Fix Android header menus

This commit is contained in:
Joe Julian
2026-04-08 16:27:46 -07:00
parent 5a98fe1a75
commit d7741d14f5
+121 -9
View File
@@ -518,6 +518,10 @@ type ui struct {
deleteGroupPath []string
apiPolicyGroupScope bool
apiTokenSecret string
phoneSyncMenuAnchor image.Point
phoneMainMenuAnchor image.Point
phoneSyncMenuVisible bool
phoneMainMenuVisible bool
selectedAuditIndex int
statusExpiresAt time.Time
now func() time.Time
@@ -4132,6 +4136,8 @@ func (u *ui) layout(gtx layout.Context) layout.Dimensions {
// Clear the full frame explicitly so mobile surfaces don't start from an
// unpainted black buffer before nested background widgets run.
paint.FillShape(gtx.Ops, bgColor, clip.Rect{Max: gtx.Constraints.Max}.Op())
u.phoneSyncMenuVisible = false
u.phoneMainMenuVisible = false
u.syncHostedAPI()
u.filter()
u.processShortcuts(gtx)
@@ -4164,9 +4170,15 @@ func (u *ui) layout(gtx layout.Context) layout.Dimensions {
}
for u.toggleSyncMenu.Clicked(gtx) {
u.syncMenuOpen = !u.syncMenuOpen
if u.syncMenuOpen {
u.mainMenuOpen = false
}
}
for u.toggleMainMenu.Clicked(gtx) {
u.mainMenuOpen = !u.mainMenuOpen
if u.mainMenuOpen {
u.syncMenuOpen = false
}
}
for u.openAdvancedSync.Clicked(gtx) {
u.openAdvancedSyncDialog()
@@ -4773,6 +4785,9 @@ func (u *ui) layout(gtx layout.Context) layout.Dimensions {
}
return u.approvalDialog(gtx)
}),
layout.Stacked(func(gtx layout.Context) layout.Dimensions {
return u.phoneHeaderMenus(gtx)
}),
layout.Stacked(u.statusToast),
)
}
@@ -5502,6 +5517,29 @@ func (u *ui) header(gtx layout.Context) layout.Dimensions {
gtx.Constraints.Min.X = gtx.Constraints.Max.X
return u.headerActions(gtx)
}),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
if !u.syncMenuOpen && !u.mainMenuOpen {
return layout.Dimensions{}
}
return layout.Inset{Top: unit.Dp(6)}.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
return layout.E.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
var menu layout.Widget
if u.syncMenuOpen {
menu = u.syncMenu
} else {
menu = u.mainMenu
}
measureGTX := gtx
measureGTX.Constraints.Min = image.Point{}
macro := op.Record(gtx.Ops)
dims := menu(measureGTX)
_ = macro.Stop()
gtx.Constraints.Min.X = dims.Size.X
gtx.Constraints.Max.X = dims.Size.X
return menu(gtx)
})
})
}),
)
}
if u.shouldShowDesktopWorkingHeader() {
@@ -5575,6 +5613,20 @@ func (u *ui) headerActions(gtx layout.Context) layout.Dimensions {
rowCall.Add(gtx.Ops)
rowStack.Pop()
if u.mode == "phone" {
if u.syncMenuOpen {
u.phoneSyncMenuVisible = true
u.phoneSyncMenuAnchor = image.Pt(rowOriginX+syncDims.Size.X, rowDims.Size.Y)
}
if u.mainMenuOpen {
triggerRightX := syncDims.Size.X + spacing + lockDims.Size.X + spacing + mainDims.Size.X
u.phoneMainMenuVisible = true
u.phoneMainMenuAnchor = image.Pt(rowOriginX+triggerRightX, rowDims.Size.Y)
}
width := gtx.Constraints.Max.X
return layout.Dimensions{Size: image.Pt(width, rowDims.Size.Y)}
}
if u.syncMenuOpen {
drawMenu(u.syncMenu, syncDims.Size.X, rowDims.Size.Y)
}
@@ -5584,9 +5636,6 @@ func (u *ui) headerActions(gtx layout.Context) layout.Dimensions {
}
width := rowDims.Size.X
if u.mode == "phone" {
width = gtx.Constraints.Max.X
}
return layout.Dimensions{Size: image.Pt(width, rowDims.Size.Y)}
}
@@ -5600,7 +5649,7 @@ func (u *ui) mainMenu(gtx layout.Context) layout.Dimensions {
func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.openSecuritySettings, "Settings") },
}
rowWidth := menuActionWidth(gtx, rows)
return compactCard(gtx, func(gtx layout.Context) layout.Dimensions {
return intrinsicCompactCard(gtx, func(gtx layout.Context) layout.Dimensions {
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return rightAlignedMenuAction(gtx, rowWidth, rows[0])
@@ -5715,8 +5764,13 @@ func (u *ui) syncButtonGroup(gtx layout.Context) layout.Dimensions {
func (u *ui) syncMenuToggle(gtx layout.Context) layout.Dimensions {
btn := material.IconButton(u.theme, &u.toggleSyncMenu, u.chevronDownIcon, "More synchronize actions")
btn.Background = color.NRGBA{R: 231, G: 236, B: 232, A: 255}
btn.Color = accentColor
if u.syncMenuOpen {
btn.Background = accentColor
btn.Color = color.NRGBA{R: 255, G: 252, B: 247, A: 255}
} else {
btn.Background = color.NRGBA{R: 231, G: 236, B: 232, A: 255}
btn.Color = accentColor
}
btn.Size = unit.Dp(18)
btn.Inset = layout.UniformInset(unit.Dp(8))
if u.mode == "phone" {
@@ -5764,7 +5818,7 @@ func (u *ui) syncMenu(gtx layout.Context) layout.Dimensions {
})
}
actionWidth := menuActionWidth(gtx, actionRows)
return compactCard(gtx, func(gtx layout.Context) layout.Dimensions {
return intrinsicCompactCard(gtx, func(gtx layout.Context) layout.Dimensions {
rows := []layout.FlexChild{
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
lbl := material.Label(u.theme, unit.Sp(11), "Need another source or direction?")
@@ -5951,6 +6005,20 @@ func (u *ui) syncMenu(gtx layout.Context) layout.Dimensions {
})
}
func intrinsicCompactCard(gtx layout.Context, w layout.Widget) layout.Dimensions {
measureGTX := gtx
measureGTX.Constraints.Min = image.Point{}
macro := op.Record(gtx.Ops)
contentDims := w(measureGTX)
_ = macro.Stop()
width := contentDims.Size.X + gtx.Dp(unit.Dp(20))
if width > 0 {
gtx.Constraints.Min.X = width
gtx.Constraints.Max.X = width
}
return compactCard(gtx, w)
}
func (u *ui) sectionSpacing() unit.Dp {
if u.mode == "phone" {
if u.denseLayout {
@@ -7252,8 +7320,13 @@ func (u *ui) mainMenuButtonGroup(gtx layout.Context) layout.Dimensions {
icon = u.settingsIcon
}
btn := material.IconButton(u.theme, &u.toggleMainMenu, icon, "Menu")
btn.Background = selectedColor
btn.Color = accentColor
if u.mainMenuOpen {
btn.Background = accentColor
btn.Color = color.NRGBA{R: 255, G: 252, B: 247, A: 255}
} else {
btn.Background = selectedColor
btn.Color = accentColor
}
btn.Size = unit.Dp(18)
btn.Inset = layout.UniformInset(unit.Dp(8))
return btn.Layout(gtx)
@@ -7261,6 +7334,42 @@ func (u *ui) mainMenuButtonGroup(gtx layout.Context) layout.Dimensions {
return button(gtx)
}
func (u *ui) phoneHeaderMenus(gtx layout.Context) layout.Dimensions {
if u.mode != "phone" {
return layout.Dimensions{}
}
if !u.syncMenuVisibleOnPhone() && !u.mainMenuVisibleOnPhone() {
return layout.Dimensions{}
}
gtx.Constraints.Min = gtx.Constraints.Max
drawMenu := func(anchor image.Point, menu layout.Widget) layout.Dimensions {
_ = anchor
return layout.NE.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
return layout.Inset{
Top: unit.Dp(56),
Right: unit.Dp(16),
}.Layout(gtx, menu)
})
}
if u.syncMenuVisibleOnPhone() {
drawMenu(u.phoneSyncMenuAnchor, u.syncMenu)
}
if u.mainMenuVisibleOnPhone() {
drawMenu(u.phoneMainMenuAnchor, u.mainMenu)
}
return layout.Dimensions{Size: gtx.Constraints.Max}
}
func (u *ui) syncMenuVisibleOnPhone() bool {
return u.mode == "phone" && u.phoneSyncMenuVisible && u.syncMenuOpen
}
func (u *ui) mainMenuVisibleOnPhone() bool {
return u.mode == "phone" && u.phoneMainMenuVisible && u.mainMenuOpen
}
func (u *ui) syncMenuDropsBelowTrigger() bool {
return true
}
@@ -7510,6 +7619,9 @@ func menuActionWidth(gtx layout.Context, rows []layout.Widget) int {
}
func rightAlignedMenuAction(gtx layout.Context, width int, child layout.Widget) layout.Dimensions {
if width < gtx.Constraints.Max.X {
width = gtx.Constraints.Max.X
}
if width <= 0 {
return child(gtx)
}