diff --git a/main.go b/main.go index cda10e5..b120a85 100644 --- a/main.go +++ b/main.go @@ -5667,25 +5667,36 @@ func (u *ui) syncButtonGroup(gtx layout.Context) layout.Dimensions { if u.mode == "phone" { spacing = unit.Dp(3) } - return layout.Flex{Axis: layout.Vertical}.Layout(gtx, - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return layout.Flex{Alignment: layout.Middle}.Layout(gtx, - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return syncPrimaryButton(gtx, u.theme, &u.synchronizeVault, label, u.mode == "phone") - }), - layout.Rigid(layout.Spacer{Width: spacing}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return u.syncMenuToggle(gtx) - }), - ) - }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if !u.syncMenuOpen { - return layout.Dimensions{} - } - return layout.Inset{Top: unit.Dp(6)}.Layout(gtx, u.syncMenu) - }), - ) + row := func(gtx layout.Context) layout.Dimensions { + return layout.Flex{Alignment: layout.Middle}.Layout(gtx, + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return syncPrimaryButton(gtx, u.theme, &u.synchronizeVault, label, u.mode == "phone") + }), + layout.Rigid(layout.Spacer{Width: spacing}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return u.syncMenuToggle(gtx) + }), + ) + } + rowDims := row(gtx) + if !u.syncMenuOpen { + return rowDims + } + + menuGTX := gtx + menuGTX.Constraints.Min = image.Point{} + menuOps := op.Record(gtx.Ops) + menuDims := layout.Inset{Top: unit.Dp(6)}.Layout(menuGTX, u.syncMenu) + menuCall := menuOps.Stop() + + menuX := rowDims.Size.X - menuDims.Size.X + if menuX < 0 { + menuX = 0 + } + stack := op.Offset(image.Pt(menuX, rowDims.Size.Y)).Push(gtx.Ops) + menuCall.Add(gtx.Ops) + stack.Pop() + return rowDims } func (u *ui) syncMenuToggle(gtx layout.Context) layout.Dimensions { @@ -7196,6 +7207,14 @@ func (u *ui) topRightActionOrder() []string { return []string{"Sync", "Lock", "Menu"} } +func (u *ui) syncMenuDropsBelowTrigger() bool { + return true +} + +func (u *ui) syncMenuRightAlignsToTrigger() bool { + return true +} + func detailLine(th *material.Theme, label, value string) layout.Widget { return func(gtx layout.Context) layout.Dimensions { valueSize := unit.Sp(16) diff --git a/main_test.go b/main_test.go index 4d83059..064e72f 100644 --- a/main_test.go +++ b/main_test.go @@ -324,6 +324,22 @@ func TestUITopRightActionOrderMatchesAcrossModes(t *testing.T) { } } +func TestUISyncMenuAnchorsMatchAcrossModes(t *testing.T) { + t.Parallel() + + desktop := newUIWithSession("desktop", summarySession{hasVault: true}) + desktop.state.Section = appstate.SectionEntries + phone := newUIWithSession("phone", summarySession{hasVault: true}) + phone.state.Section = appstate.SectionEntries + + if !desktop.syncMenuDropsBelowTrigger() || !phone.syncMenuDropsBelowTrigger() { + t.Fatal("sync menu should drop below trigger across desktop and phone") + } + if !desktop.syncMenuRightAlignsToTrigger() || !phone.syncMenuRightAlignsToTrigger() { + t.Fatal("sync menu should right-align to trigger across desktop and phone") + } +} + func TestUICurrentVaultSummary(t *testing.T) { t.Parallel()