diff --git a/main_test.go b/main_test.go index fa09fb6..80ffeb8 100644 --- a/main_test.go +++ b/main_test.go @@ -746,6 +746,20 @@ func TestUILifecycleControlsWithSelectedRecentVaultDoesNotPanic(t *testing.T) { _ = u.lifecycleControls(gtx) } +func TestUIShouldPrioritizeLifecyclePrimaryActionsOnPhone(t *testing.T) { + t.Parallel() + + phone := newUIWithSession("phone", &session.Manager{}) + if !phone.shouldPrioritizeLifecyclePrimaryActions() { + t.Fatal("phone.shouldPrioritizeLifecyclePrimaryActions() = false, want true") + } + + desktop := newUIWithSession("desktop", &session.Manager{}) + if desktop.shouldPrioritizeLifecyclePrimaryActions() { + t.Fatal("desktop.shouldPrioritizeLifecyclePrimaryActions() = true, want false") + } +} + func TestUIRecentVaultListWithSelectedRecentVaultDoesNotPanic(t *testing.T) { t.Parallel() @@ -6040,7 +6054,13 @@ func TestUIRemoteSyncSetupShortcutLabelUsesClearLanguage(t *testing.T) { func TestUILifecycleRemoteSyncActionLabelUsesSetupLanguageWithoutSavedBinding(t *testing.T) { t.Parallel() - u := newUIWithSession("desktop", &session.Manager{}) + dir := t.TempDir() + u := newUIWithSession("desktop", &session.Manager{}, statePaths{ + DefaultSaveAsPath: filepath.Join(dir, "vault.kdbx"), + RecentVaultsPath: filepath.Join(dir, "recent-vaults.json"), + RecentRemotesPath: filepath.Join(dir, "recent-remotes.json"), + UIPreferencesPath: filepath.Join(dir, "ui-prefs.json"), + }) u.vaultPath.SetText("/vaults/bellagio.kdbx") if !u.shouldShowLifecycleRemoteSyncAction() { diff --git a/ui_forms.go b/ui_forms.go index 57438c1..94bdd52 100644 --- a/ui_forms.go +++ b/ui_forms.go @@ -22,6 +22,92 @@ func (u *ui) lifecycleControls(gtx layout.Context) layout.Dimensions { busy := u.lifecycleBusy() showLocalChooser := u.showLocalVaultChooser() selectedLocalPath := strings.TrimSpace(u.vaultPath.Text()) + advancedSection := func(gtx layout.Context) layout.Dimensions { + if busy { + return layout.Dimensions{} + } + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Rigid(u.lifecycleAdvancedDisclosure), + layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + if u.lifecycleAdvancedHidden { + return layout.Dimensions{} + } + if u.lifecycleMode == "remote" { + return layout.Dimensions{} + } + return compactCard(gtx, func(gtx layout.Context) layout.Dimensions { + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + lbl := material.Label(u.theme, unit.Sp(13), "Vault settings") + lbl.Color = accentColor + return lbl.Layout(gtx) + }), + layout.Rigid(layout.Spacer{Height: unit.Dp(4)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + lbl := material.Label(u.theme, unit.Sp(12), u.lifecycleSecuritySettingsSummary()) + lbl.Color = mutedColor + return lbl.Layout(gtx) + }), + layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return tonedButton(gtx, u.theme, &u.openSecuritySettings, "Open Vault Settings") + }), + ) + }) + }), + ) + } + primaryActionsSection := func(gtx layout.Context) layout.Dimensions { + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + label := "Open Vault" + if busy { + label = "Opening Vault..." + } + if busy { + return passiveTonedButton(gtx, u.theme, label) + } + return tonedButton(gtx, u.theme, &u.openVault, label) + }), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + if busy || !u.shouldShowLifecycleRemoteSyncAction() { + return layout.Dimensions{} + } + return layout.Spacer{Height: unit.Dp(6)}.Layout(gtx) + }), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + if busy || !u.shouldShowLifecycleRemoteSyncAction() { + return layout.Dimensions{} + } + return tonedButton(gtx, u.theme, &u.lifecycleRemoteSyncAction, u.lifecycleRemoteSyncActionLabel()) + }), + layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + lbl := material.Label(u.theme, unit.Sp(11), "Need a fresh database instead?") + lbl.Color = mutedColor + return lbl.Layout(gtx) + }), + layout.Rigid(layout.Spacer{Height: unit.Dp(4)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + if busy { + return passiveSectionTab(gtx, u.theme, "Create New Vault", false) + } + return sectionTabButton(gtx, u.theme, &u.createVault, "Create New Vault", false) + }), + ) + } + selectedVaultSection := func(gtx layout.Context) layout.Dimensions { + if busy || selectedLocalPath == "" { + return layout.Dimensions{} + } + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout), + layout.Rigid(func(gtx layout.Context) layout.Dimensions { + return u.selectedLocalVaultCard(gtx, selectedLocalPath) + }), + ) + } return layout.Flex{Axis: layout.Vertical}.Layout(gtx, layout.Rigid(func(gtx layout.Context) layout.Dimensions { lbl := material.Label(u.theme, unit.Sp(12), "OPEN A VAULT") @@ -119,106 +205,30 @@ func (u *ui) lifecycleControls(gtx layout.Context) layout.Dimensions { } return keyFileSelector(u.theme, &u.keyFilePath, &u.pickKeyFile)(gtx) }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if busy { - return layout.Dimensions{} - } - return layout.Spacer{Height: unit.Dp(8)}.Layout(gtx) - }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if busy { - return layout.Dimensions{} - } - return u.lifecycleAdvancedDisclosure(gtx) - }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if busy { - return layout.Dimensions{} - } - return layout.Spacer{Height: unit.Dp(6)}.Layout(gtx) - }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if busy || u.lifecycleAdvancedHidden { - return layout.Dimensions{} - } - if u.lifecycleMode == "remote" { - return layout.Dimensions{} - } - return compactCard(gtx, func(gtx layout.Context) layout.Dimensions { - return layout.Flex{Axis: layout.Vertical}.Layout(gtx, - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - lbl := material.Label(u.theme, unit.Sp(13), "Vault settings") - lbl.Color = accentColor - return lbl.Layout(gtx) - }), - layout.Rigid(layout.Spacer{Height: unit.Dp(4)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - lbl := material.Label(u.theme, unit.Sp(12), u.lifecycleSecuritySettingsSummary()) - lbl.Color = mutedColor - return lbl.Layout(gtx) - }), - layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return tonedButton(gtx, u.theme, &u.openSecuritySettings, "Open Vault Settings") - }), - ) - }) - }), layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout), layout.Rigid(func(gtx layout.Context) layout.Dimensions { + if u.shouldPrioritizeLifecyclePrimaryActions() { + return layout.Flex{Axis: layout.Vertical}.Layout(gtx, + layout.Rigid(primaryActionsSection), + layout.Rigid(selectedVaultSection), + layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout), + layout.Rigid(advancedSection), + ) + } return layout.Flex{Axis: layout.Vertical}.Layout(gtx, - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - label := "Open Vault" - if busy { - label = "Opening Vault..." - } - if busy { - return passiveTonedButton(gtx, u.theme, label) - } - return tonedButton(gtx, u.theme, &u.openVault, label) - }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if busy || !u.shouldShowLifecycleRemoteSyncAction() { - return layout.Dimensions{} - } - return layout.Spacer{Height: unit.Dp(6)}.Layout(gtx) - }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if busy || !u.shouldShowLifecycleRemoteSyncAction() { - return layout.Dimensions{} - } - return tonedButton(gtx, u.theme, &u.lifecycleRemoteSyncAction, u.lifecycleRemoteSyncActionLabel()) - }), - layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - lbl := material.Label(u.theme, unit.Sp(11), "Need a fresh database instead?") - lbl.Color = mutedColor - return lbl.Layout(gtx) - }), - layout.Rigid(layout.Spacer{Height: unit.Dp(4)}.Layout), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if busy { - return passiveSectionTab(gtx, u.theme, "Create New Vault", false) - } - return sectionTabButton(gtx, u.theme, &u.createVault, "Create New Vault", false) - }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if busy || selectedLocalPath == "" { - return layout.Dimensions{} - } - return layout.Spacer{Height: unit.Dp(8)}.Layout(gtx) - }), - layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if busy || selectedLocalPath == "" { - return layout.Dimensions{} - } - return u.selectedLocalVaultCard(gtx, selectedLocalPath) - }), + layout.Rigid(advancedSection), + layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout), + layout.Rigid(primaryActionsSection), + layout.Rigid(selectedVaultSection), ) }), ) } +func (u *ui) shouldPrioritizeLifecyclePrimaryActions() bool { + return u.mode == "phone" +} + func (u *ui) selectedRemoteConnectionCard(gtx layout.Context) layout.Dimensions { heading := u.selectedRemoteCardHeading() primary := u.selectedRemoteCardPrimaryText()