From cdf0c0c2c7e5c3ce10d19d4255e87194a850a456 Mon Sep 17 00:00:00 2001 From: Joe Julian Date: Thu, 9 Apr 2026 06:58:05 -0700 Subject: [PATCH] Extract app UI action models --- internal/appui/actions/sync_menu.go | 95 +++++++++++++++++ internal/appui/app.go | 28 ++--- internal/appui/main_test.go | 62 +++++------ internal/appui/ui_layout_header.go | 56 +++++----- internal/appui/ui_sync_menu_actions.go | 51 +++++++++ internal/appui/ui_sync_menu_model.go | 142 ------------------------- 6 files changed, 219 insertions(+), 215 deletions(-) create mode 100644 internal/appui/actions/sync_menu.go create mode 100644 internal/appui/ui_sync_menu_actions.go delete mode 100644 internal/appui/ui_sync_menu_model.go diff --git a/internal/appui/actions/sync_menu.go b/internal/appui/actions/sync_menu.go new file mode 100644 index 0000000..15a56e0 --- /dev/null +++ b/internal/appui/actions/sync_menu.go @@ -0,0 +1,95 @@ +package actions + +import "git.julianfamily.org/keepassgo/internal/appstate" + +type SyncMenuModel struct { + HasOpenVault bool + HasSelectedBinding bool + ShowSelectors bool + ShowShare bool + ShowSaveCurrentBinding bool + SavedBindingSummary SyncMenuBindingSummary + RemoteBaseURL string + RemotePath string + RemoteUsername string + RemotePassword string + SelectedVaultSyncMode appstate.SyncMode +} + +type SyncMenuBindingSummary struct { + ProfileLabel string + CredentialLabel string + SyncLabel string + OK bool +} + +func (m SyncMenuModel) SavedBindingHeading() string { + if !m.ShowSelectors { + return "Use this vault's saved remote sync target" + } + return "Use a saved remote profile from this vault" +} + +func (m SyncMenuModel) OpenSelectedButtonLabel() string { + if !m.ShowSelectors { + return "Use Remote Sync" + } + return "Open Saved Remote" +} + +func (m SyncMenuModel) ShowDirectRemoteSyncShortcut() bool { + return m.HasOpenVault && m.HasSelectedBinding +} + +func (m SyncMenuModel) DirectRemoteSyncShortcutLabel() string { + return "Use Remote Sync" +} + +func (m SyncMenuModel) ShowRemoteSyncSettingsShortcut() bool { + return m.HasOpenVault && m.HasSelectedBinding +} + +func (m SyncMenuModel) RemoteSyncSettingsShortcutLabel() string { + return "Remote Sync Settings" +} + +func (m SyncMenuModel) ShowRemoveRemoteSyncShortcut() bool { + return m.ShowRemoteSyncSettingsShortcut() +} + +func (m SyncMenuModel) RemoveRemoteSyncShortcutLabel() string { + return "Stop Using Remote Sync" +} + +func (m SyncMenuModel) ShowRemoteSyncSetupShortcut() bool { + return m.HasOpenVault && !m.HasSelectedBinding +} + +func (m SyncMenuModel) RemoteSyncSetupShortcutLabel() string { + return "Set Up Remote Sync" +} + +func (m SyncMenuModel) ActionLabels() []string { + labels := []string{"Open Advanced Sync"} + if m.ShowRemoteSyncSetupShortcut() { + labels = append(labels, m.RemoteSyncSetupShortcutLabel()) + } + if m.ShowDirectRemoteSyncShortcut() { + labels = append(labels, m.DirectRemoteSyncShortcutLabel()) + } + if m.ShowRemoteSyncSettingsShortcut() { + labels = append(labels, m.RemoteSyncSettingsShortcutLabel()) + } + if m.ShowRemoveRemoteSyncShortcut() { + labels = append(labels, m.RemoveRemoteSyncShortcutLabel()) + } + return labels +} + +func (m SyncMenuModel) SaveCurrentRemoteBindingHeading() string { + return "Bind this local vault to the current remote target" +} + +func (m SyncMenuModel) SaveCurrentRemoteBindingButtonLabel() string { + return "Save Remote In Vault" +} diff --git a/internal/appui/app.go b/internal/appui/app.go index 6be8cf9..b9a57bf 100644 --- a/internal/appui/app.go +++ b/internal/appui/app.go @@ -2740,60 +2740,60 @@ func (u *ui) shouldShowSavedRemoteBindingSelectors() bool { func (u *ui) savedRemoteBindingSummary() (profileLabel, credentialLabel, syncLabel string, ok bool) { summary := u.computeSavedRemoteBindingSummary() - return summary.profileLabel, summary.credentialLabel, summary.syncLabel, summary.ok + return summary.ProfileLabel, summary.CredentialLabel, summary.SyncLabel, summary.OK } func (u *ui) savedRemoteBindingHeading() string { - return u.buildSyncMenuModel().savedBindingHeading() + return u.buildSyncMenuModel().SavedBindingHeading() } func (u *ui) openSelectedVaultRemoteButtonLabel() string { - return u.buildSyncMenuModel().openSelectedButtonLabel() + return u.buildSyncMenuModel().OpenSelectedButtonLabel() } func (u *ui) shouldShowDirectRemoteSyncShortcut() bool { if !u.hasOpenVault() || u.isVaultLocked() || u.state.Section != appstate.SectionEntries { return false } - return u.buildSyncMenuModel().showDirectRemoteSyncShortcut() + return u.buildSyncMenuModel().ShowDirectRemoteSyncShortcut() } func (u *ui) directRemoteSyncShortcutLabel() string { - return u.buildSyncMenuModel().directRemoteSyncShortcutLabel() + return u.buildSyncMenuModel().DirectRemoteSyncShortcutLabel() } func (u *ui) shouldShowRemoteSyncSettingsShortcut() bool { if !u.hasOpenVault() || u.isVaultLocked() || u.state.Section != appstate.SectionEntries { return false } - return u.buildSyncMenuModel().showRemoteSyncSettingsShortcut() + return u.buildSyncMenuModel().ShowRemoteSyncSettingsShortcut() } func (u *ui) remoteSyncSettingsShortcutLabel() string { - return u.buildSyncMenuModel().remoteSyncSettingsShortcutLabel() + return u.buildSyncMenuModel().RemoteSyncSettingsShortcutLabel() } func (u *ui) shouldShowRemoveRemoteSyncShortcut() bool { - return u.buildSyncMenuModel().showRemoveRemoteSyncShortcut() + return u.buildSyncMenuModel().ShowRemoveRemoteSyncShortcut() } func (u *ui) removeRemoteSyncShortcutLabel() string { - return u.buildSyncMenuModel().removeRemoteSyncShortcutLabel() + return u.buildSyncMenuModel().RemoveRemoteSyncShortcutLabel() } func (u *ui) shouldShowRemoteSyncSetupShortcut() bool { if !u.hasOpenVault() || u.isVaultLocked() || u.state.Section != appstate.SectionEntries { return false } - return u.buildSyncMenuModel().showRemoteSyncSetupShortcut() + return u.buildSyncMenuModel().ShowRemoteSyncSetupShortcut() } func (u *ui) remoteSyncSetupShortcutLabel() string { - return u.buildSyncMenuModel().remoteSyncSetupShortcutLabel() + return u.buildSyncMenuModel().RemoteSyncSetupShortcutLabel() } func (u *ui) syncMenuActionLabels() []string { - return u.buildSyncMenuModel().actionLabels() + return u.buildSyncMenuModel().ActionLabels() } func remoteBindingSuffix(baseURL, path, username string) string { @@ -2901,11 +2901,11 @@ func (u *ui) removeSelectedRemoteBindingAction() error { } func (u *ui) saveCurrentRemoteBindingHeading() string { - return u.buildSyncMenuModel().saveCurrentRemoteBindingHeading() + return u.buildSyncMenuModel().SaveCurrentRemoteBindingHeading() } func (u *ui) saveCurrentRemoteBindingButtonLabel() string { - return u.buildSyncMenuModel().saveCurrentRemoteBindingButtonLabel() + return u.buildSyncMenuModel().SaveCurrentRemoteBindingButtonLabel() } func (u *ui) materializeCurrentRemoteCache() error { diff --git a/internal/appui/main_test.go b/internal/appui/main_test.go index 34a1b82..cf09378 100644 --- a/internal/appui/main_test.go +++ b/internal/appui/main_test.go @@ -439,14 +439,14 @@ func TestBuildSyncMenuModelForUnboundVault(t *testing.T) { u.state.Section = appstate.SectionEntries model := u.buildSyncMenuModel() - if !model.showRemoteSyncSetupShortcut() { - t.Fatal("model.showRemoteSyncSetupShortcut() = false, want true for an unbound open vault") + if !model.ShowRemoteSyncSetupShortcut() { + t.Fatal("model.ShowRemoteSyncSetupShortcut() = false, want true for an unbound open vault") } - if model.showDirectRemoteSyncShortcut() { - t.Fatal("model.showDirectRemoteSyncShortcut() = true, want false without a saved binding") + if model.ShowDirectRemoteSyncShortcut() { + t.Fatal("model.ShowDirectRemoteSyncShortcut() = true, want false without a saved binding") } - if got := model.actionLabels(); !slices.Equal(got, []string{"Open Advanced Sync", "Set Up Remote Sync"}) { - t.Fatalf("model.actionLabels() = %v, want [Open Advanced Sync Set Up Remote Sync]", got) + if got := model.ActionLabels(); !slices.Equal(got, []string{"Open Advanced Sync", "Set Up Remote Sync"}) { + t.Fatalf("model.ActionLabels() = %v, want [Open Advanced Sync Set Up Remote Sync]", got) } } @@ -477,30 +477,30 @@ func TestBuildSyncMenuModelForBoundVault(t *testing.T) { u.selectedVaultRemoteSyncMode = appstate.SyncModeAutomaticOnOpenSave model := u.buildSyncMenuModel() - if model.showRemoteSyncSetupShortcut() { - t.Fatal("model.showRemoteSyncSetupShortcut() = true, want false for a bound vault") + if model.ShowRemoteSyncSetupShortcut() { + t.Fatal("model.ShowRemoteSyncSetupShortcut() = true, want false for a bound vault") } - if !model.showDirectRemoteSyncShortcut() { - t.Fatal("model.showDirectRemoteSyncShortcut() = false, want true for a bound vault") + if !model.ShowDirectRemoteSyncShortcut() { + t.Fatal("model.ShowDirectRemoteSyncShortcut() = false, want true for a bound vault") } - if !model.showRemoteSyncSettingsShortcut() { - t.Fatal("model.showRemoteSyncSettingsShortcut() = false, want true for a bound vault") + if !model.ShowRemoteSyncSettingsShortcut() { + t.Fatal("model.ShowRemoteSyncSettingsShortcut() = false, want true for a bound vault") } - if !model.showRemoveRemoteSyncShortcut() { - t.Fatal("model.showRemoveRemoteSyncShortcut() = false, want true for a bound vault") + if !model.ShowRemoveRemoteSyncShortcut() { + t.Fatal("model.ShowRemoveRemoteSyncShortcut() = false, want true for a bound vault") } - summary := model.savedBindingSummary - if !summary.ok { - t.Fatal("model.savedBindingSummary.ok = false, want true") + summary := model.SavedBindingSummary + if !summary.OK { + t.Fatal("model.SavedBindingSummary.OK = false, want true") } - if summary.profileLabel != "Downtown Mint" { - t.Fatalf("model.savedBindingSummary.profileLabel = %q, want Downtown Mint", summary.profileLabel) + if summary.ProfileLabel != "Downtown Mint" { + t.Fatalf("model.SavedBindingSummary.ProfileLabel = %q, want Downtown Mint", summary.ProfileLabel) } - if summary.credentialLabel != "Mint Credentials · verbal-kint" { - t.Fatalf("model.savedBindingSummary.credentialLabel = %q, want Mint Credentials · verbal-kint", summary.credentialLabel) + if summary.CredentialLabel != "Mint Credentials · verbal-kint" { + t.Fatalf("model.SavedBindingSummary.CredentialLabel = %q, want Mint Credentials · verbal-kint", summary.CredentialLabel) } - if summary.syncLabel != "Syncs automatically on open and save." { - t.Fatalf("model.savedBindingSummary.syncLabel = %q, want automatic-sync summary", summary.syncLabel) + if summary.SyncLabel != "Syncs automatically on open and save." { + t.Fatalf("model.SavedBindingSummary.SyncLabel = %q, want automatic-sync summary", summary.SyncLabel) } } @@ -515,8 +515,8 @@ func TestBuildSyncMenuModelShowsSaveCurrentBindingOnlyWithCompleteRemoteInput(t u.state.Section = appstate.SectionEntries model := u.buildSyncMenuModel() - if model.showSaveCurrentBinding { - t.Fatal("model.showSaveCurrentBinding = true, want false without remote input") + if model.ShowSaveCurrentBinding { + t.Fatal("model.ShowSaveCurrentBinding = true, want false without remote input") } u.remoteBaseURL.SetText("https://mint.example.invalid/remote.php/dav") @@ -525,14 +525,14 @@ func TestBuildSyncMenuModelShowsSaveCurrentBindingOnlyWithCompleteRemoteInput(t u.remotePassword.SetText("kobayashi") model = u.buildSyncMenuModel() - if !model.showSaveCurrentBinding { - t.Fatal("model.showSaveCurrentBinding = false, want true with complete remote input") + if !model.ShowSaveCurrentBinding { + t.Fatal("model.ShowSaveCurrentBinding = false, want true with complete remote input") } - if got := model.saveCurrentRemoteBindingHeading(); got != "Bind this local vault to the current remote target" { - t.Fatalf("model.saveCurrentRemoteBindingHeading() = %q, want vault binding guidance", got) + if got := model.SaveCurrentRemoteBindingHeading(); got != "Bind this local vault to the current remote target" { + t.Fatalf("model.SaveCurrentRemoteBindingHeading() = %q, want vault binding guidance", got) } - if got := model.saveCurrentRemoteBindingButtonLabel(); got != "Save Remote In Vault" { - t.Fatalf("model.saveCurrentRemoteBindingButtonLabel() = %q, want Save Remote In Vault", got) + if got := model.SaveCurrentRemoteBindingButtonLabel(); got != "Save Remote In Vault" { + t.Fatalf("model.SaveCurrentRemoteBindingButtonLabel() = %q, want Save Remote In Vault", got) } } diff --git a/internal/appui/ui_layout_header.go b/internal/appui/ui_layout_header.go index 8d078ba..8e7a75b 100644 --- a/internal/appui/ui_layout_header.go +++ b/internal/appui/ui_layout_header.go @@ -206,29 +206,29 @@ func (u *ui) syncMenu(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.openAdvancedSync, "Open Advanced Sync") }, } - if model.showShare { + if model.ShowShare { actionRows = append(actionRows, func(gtx layout.Context) layout.Dimensions { return tonedButton(gtx, u.theme, &u.shareCurrentVault, "Share Vault") }) } - if model.showRemoteSyncSetupShortcut() { + if model.ShowRemoteSyncSetupShortcut() { actionRows = append(actionRows, func(gtx layout.Context) layout.Dimensions { - return tonedButton(gtx, u.theme, &u.useSavedAdvancedSyncRemote, model.remoteSyncSetupShortcutLabel()) + return tonedButton(gtx, u.theme, &u.useSavedAdvancedSyncRemote, model.RemoteSyncSetupShortcutLabel()) }) } - if model.showDirectRemoteSyncShortcut() { + if model.ShowDirectRemoteSyncShortcut() { actionRows = append(actionRows, func(gtx layout.Context) layout.Dimensions { - return tonedButton(gtx, u.theme, &u.openSelectedVaultRemote, model.directRemoteSyncShortcutLabel()) + return tonedButton(gtx, u.theme, &u.openSelectedVaultRemote, model.DirectRemoteSyncShortcutLabel()) }) } - if model.showRemoteSyncSettingsShortcut() { + if model.ShowRemoteSyncSettingsShortcut() { actionRows = append(actionRows, func(gtx layout.Context) layout.Dimensions { - return tonedButton(gtx, u.theme, &u.useSavedAdvancedSyncRemote, model.remoteSyncSettingsShortcutLabel()) + return tonedButton(gtx, u.theme, &u.useSavedAdvancedSyncRemote, model.RemoteSyncSettingsShortcutLabel()) }) } - if model.showRemoveRemoteSyncShortcut() { + if model.ShowRemoveRemoteSyncShortcut() { actionRows = append(actionRows, func(gtx layout.Context) layout.Dimensions { - return tonedButton(gtx, u.theme, &u.removeSelectedRemoteBinding, model.removeRemoteSyncShortcutLabel()) + return tonedButton(gtx, u.theme, &u.removeSelectedRemoteBinding, model.RemoveRemoteSyncShortcutLabel()) }) } actionWidth := menuActionWidth(gtx, actionRows) @@ -241,7 +241,7 @@ func (u *ui) syncMenu(gtx layout.Context) layout.Dimensions { }), layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), layout.Rigid(func(gtx layout.Context) layout.Dimensions { - if !model.showShare { + if !model.ShowShare { return layout.Dimensions{} } return layout.Flex{Axis: layout.Vertical}.Layout(gtx, @@ -259,42 +259,42 @@ func (u *ui) syncMenu(gtx layout.Context) layout.Dimensions { }) }), } - if model.showRemoteSyncSetupShortcut() { + if model.ShowRemoteSyncSetupShortcut() { rows = append(rows, layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), layout.Rigid(func(gtx layout.Context) layout.Dimensions { return rightAlignedMenuAction(gtx, actionWidth, func(gtx layout.Context) layout.Dimensions { - return tonedButton(gtx, u.theme, &u.useSavedAdvancedSyncRemote, model.remoteSyncSetupShortcutLabel()) + return tonedButton(gtx, u.theme, &u.useSavedAdvancedSyncRemote, model.RemoteSyncSetupShortcutLabel()) }) }), ) } - if model.showDirectRemoteSyncShortcut() { + if model.ShowDirectRemoteSyncShortcut() { rows = append(rows, layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), layout.Rigid(func(gtx layout.Context) layout.Dimensions { return rightAlignedMenuAction(gtx, actionWidth, func(gtx layout.Context) layout.Dimensions { - return tonedButton(gtx, u.theme, &u.openSelectedVaultRemote, model.directRemoteSyncShortcutLabel()) + return tonedButton(gtx, u.theme, &u.openSelectedVaultRemote, model.DirectRemoteSyncShortcutLabel()) }) }), ) } - if model.showRemoteSyncSettingsShortcut() { + if model.ShowRemoteSyncSettingsShortcut() { rows = append(rows, layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), layout.Rigid(func(gtx layout.Context) layout.Dimensions { return rightAlignedMenuAction(gtx, actionWidth, func(gtx layout.Context) layout.Dimensions { - return tonedButton(gtx, u.theme, &u.useSavedAdvancedSyncRemote, model.remoteSyncSettingsShortcutLabel()) + return tonedButton(gtx, u.theme, &u.useSavedAdvancedSyncRemote, model.RemoteSyncSettingsShortcutLabel()) }) }), ) } - if model.showRemoveRemoteSyncShortcut() { + if model.ShowRemoveRemoteSyncShortcut() { rows = append(rows, layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), layout.Rigid(func(gtx layout.Context) layout.Dimensions { return rightAlignedMenuAction(gtx, actionWidth, func(gtx layout.Context) layout.Dimensions { - return tonedButton(gtx, u.theme, &u.removeSelectedRemoteBinding, model.removeRemoteSyncShortcutLabel()) + return tonedButton(gtx, u.theme, &u.removeSelectedRemoteBinding, model.RemoveRemoteSyncShortcutLabel()) }) }), ) @@ -303,36 +303,36 @@ func (u *ui) syncMenu(gtx layout.Context) layout.Dimensions { rows = append(rows, layout.Rigid(layout.Spacer{Height: unit.Dp(10)}.Layout), layout.Rigid(func(gtx layout.Context) layout.Dimensions { - lbl := material.Label(u.theme, unit.Sp(11), model.savedBindingHeading()) + lbl := material.Label(u.theme, unit.Sp(11), model.SavedBindingHeading()) lbl.Color = mutedColor return lbl.Layout(gtx) }), layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), ) - if !model.showSelectors { + if !model.ShowSelectors { rows = append(rows, layout.Rigid(func(gtx layout.Context) layout.Dimensions { - summary := model.savedBindingSummary - if !summary.ok { + summary := model.SavedBindingSummary + if !summary.OK { return layout.Dimensions{} } return layout.Background{}.Layout(gtx, fill(color.NRGBA{R: 242, G: 245, B: 240, A: 255}), func(gtx layout.Context) layout.Dimensions { return layout.UniformInset(unit.Dp(10)).Layout(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), summary.profileLabel) + lbl := material.Label(u.theme, unit.Sp(13), summary.ProfileLabel) lbl.Color = accentColor return lbl.Layout(gtx) }), layout.Rigid(layout.Spacer{Height: unit.Dp(2)}.Layout), layout.Rigid(func(gtx layout.Context) layout.Dimensions { - lbl := material.Label(u.theme, unit.Sp(12), "Credential: "+summary.credentialLabel) + lbl := material.Label(u.theme, unit.Sp(12), "Credential: "+summary.CredentialLabel) lbl.Color = mutedColor return lbl.Layout(gtx) }), layout.Rigid(layout.Spacer{Height: unit.Dp(2)}.Layout), layout.Rigid(func(gtx layout.Context) layout.Dimensions { - lbl := material.Label(u.theme, unit.Sp(12), summary.syncLabel) + lbl := material.Label(u.theme, unit.Sp(12), summary.SyncLabel) lbl.Color = mutedColor return lbl.Layout(gtx) }), @@ -395,17 +395,17 @@ func (u *ui) syncMenu(gtx layout.Context) layout.Dimensions { } } } - if model.showSaveCurrentBinding { + if model.ShowSaveCurrentBinding { rows = append(rows, layout.Rigid(layout.Spacer{Height: unit.Dp(10)}.Layout), layout.Rigid(func(gtx layout.Context) layout.Dimensions { - lbl := material.Label(u.theme, unit.Sp(11), model.saveCurrentRemoteBindingHeading()) + lbl := material.Label(u.theme, unit.Sp(11), model.SaveCurrentRemoteBindingHeading()) lbl.Color = mutedColor return lbl.Layout(gtx) }), layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout), layout.Rigid(func(gtx layout.Context) layout.Dimensions { - return tonedButton(gtx, u.theme, &u.saveCurrentRemoteBinding, model.saveCurrentRemoteBindingButtonLabel()) + return tonedButton(gtx, u.theme, &u.saveCurrentRemoteBinding, model.SaveCurrentRemoteBindingButtonLabel()) }), ) } diff --git a/internal/appui/ui_sync_menu_actions.go b/internal/appui/ui_sync_menu_actions.go new file mode 100644 index 0000000..edc3bce --- /dev/null +++ b/internal/appui/ui_sync_menu_actions.go @@ -0,0 +1,51 @@ +package appui + +import ( + "runtime" + "strings" + + "git.julianfamily.org/keepassgo/internal/appstate" + appuiactions "git.julianfamily.org/keepassgo/internal/appui/actions" +) + +func (u *ui) buildSyncMenuModel() appuiactions.SyncMenuModel { + model := appuiactions.SyncMenuModel{ + HasOpenVault: u.hasOpenVault(), + ShowSelectors: u.shouldShowSavedRemoteBindingSelectors(), + ShowShare: supportsVaultShare(runtime.GOOS) && u.vaultSharer != nil && strings.TrimSpace(u.currentShareableVaultPath()) != "", + RemoteBaseURL: strings.TrimSpace(u.remoteBaseURL.Text()), + RemotePath: strings.TrimSpace(u.remotePath.Text()), + RemoteUsername: strings.TrimSpace(u.remoteUsername.Text()), + RemotePassword: u.remotePassword.Text(), + SelectedVaultSyncMode: normalizeUISyncMode(u.selectedVaultRemoteSyncMode), + } + _, model.HasSelectedBinding = u.selectedVaultRemoteBinding() + model.SavedBindingSummary = u.computeSavedRemoteBindingSummary() + model.ShowSaveCurrentBinding = model.HasOpenVault && model.RemoteBaseURL != "" && model.RemotePath != "" && model.RemoteUsername != "" && model.RemotePassword != "" + return model +} + +func (u *ui) computeSavedRemoteBindingSummary() appuiactions.SyncMenuBindingSummary { + profile, ok := u.selectedVaultRemoteProfile() + if !ok { + return appuiactions.SyncMenuBindingSummary{} + } + entry, ok := u.selectedVaultRemoteCredentialEntry() + if !ok { + return appuiactions.SyncMenuBindingSummary{} + } + credentialLabel := entry.Title + if strings.TrimSpace(entry.Username) != "" { + credentialLabel += " · " + strings.TrimSpace(entry.Username) + } + syncLabel := "Sync manually when you choose Use Remote Sync." + if normalizeUISyncMode(u.selectedVaultRemoteSyncMode) == appstate.SyncModeAutomaticOnOpenSave { + syncLabel = "Syncs automatically on open and save." + } + return appuiactions.SyncMenuBindingSummary{ + ProfileLabel: profile.Name, + CredentialLabel: credentialLabel, + SyncLabel: syncLabel, + OK: true, + } +} diff --git a/internal/appui/ui_sync_menu_model.go b/internal/appui/ui_sync_menu_model.go deleted file mode 100644 index eca8d6f..0000000 --- a/internal/appui/ui_sync_menu_model.go +++ /dev/null @@ -1,142 +0,0 @@ -package appui - -import ( - "runtime" - "strings" - - "git.julianfamily.org/keepassgo/internal/appstate" -) - -type syncMenuModel struct { - hasOpenVault bool - hasSelectedBinding bool - showSelectors bool - showShare bool - showSaveCurrentBinding bool - savedBindingSummary syncMenuBindingSummary - remoteBaseURL string - remotePath string - remoteUsername string - remotePassword string - selectedVaultSyncMode appstate.SyncMode -} - -type syncMenuBindingSummary struct { - profileLabel string - credentialLabel string - syncLabel string - ok bool -} - -func (u *ui) buildSyncMenuModel() syncMenuModel { - model := syncMenuModel{ - hasOpenVault: u.hasOpenVault(), - showSelectors: u.shouldShowSavedRemoteBindingSelectors(), - showShare: supportsVaultShare(runtime.GOOS) && u.vaultSharer != nil && strings.TrimSpace(u.currentShareableVaultPath()) != "", - remoteBaseURL: strings.TrimSpace(u.remoteBaseURL.Text()), - remotePath: strings.TrimSpace(u.remotePath.Text()), - remoteUsername: strings.TrimSpace(u.remoteUsername.Text()), - remotePassword: u.remotePassword.Text(), - selectedVaultSyncMode: normalizeUISyncMode(u.selectedVaultRemoteSyncMode), - } - _, model.hasSelectedBinding = u.selectedVaultRemoteBinding() - model.savedBindingSummary = u.computeSavedRemoteBindingSummary() - model.showSaveCurrentBinding = model.hasOpenVault && model.remoteBaseURL != "" && model.remotePath != "" && model.remoteUsername != "" && model.remotePassword != "" - return model -} - -func (u *ui) computeSavedRemoteBindingSummary() syncMenuBindingSummary { - profile, ok := u.selectedVaultRemoteProfile() - if !ok { - return syncMenuBindingSummary{} - } - entry, ok := u.selectedVaultRemoteCredentialEntry() - if !ok { - return syncMenuBindingSummary{} - } - credentialLabel := entry.Title - if strings.TrimSpace(entry.Username) != "" { - credentialLabel += " · " + strings.TrimSpace(entry.Username) - } - syncLabel := "Sync manually when you choose Use Remote Sync." - if normalizeUISyncMode(u.selectedVaultRemoteSyncMode) == appstate.SyncModeAutomaticOnOpenSave { - syncLabel = "Syncs automatically on open and save." - } - return syncMenuBindingSummary{ - profileLabel: profile.Name, - credentialLabel: credentialLabel, - syncLabel: syncLabel, - ok: true, - } -} - -func (m syncMenuModel) savedBindingHeading() string { - if !m.showSelectors { - return "Use this vault's saved remote sync target" - } - return "Use a saved remote profile from this vault" -} - -func (m syncMenuModel) openSelectedButtonLabel() string { - if !m.showSelectors { - return "Use Remote Sync" - } - return "Open Saved Remote" -} - -func (m syncMenuModel) showDirectRemoteSyncShortcut() bool { - return m.hasOpenVault && m.hasSelectedBinding -} - -func (m syncMenuModel) directRemoteSyncShortcutLabel() string { - return "Use Remote Sync" -} - -func (m syncMenuModel) showRemoteSyncSettingsShortcut() bool { - return m.hasOpenVault && m.hasSelectedBinding -} - -func (m syncMenuModel) remoteSyncSettingsShortcutLabel() string { - return "Remote Sync Settings" -} - -func (m syncMenuModel) showRemoveRemoteSyncShortcut() bool { - return m.showRemoteSyncSettingsShortcut() -} - -func (m syncMenuModel) removeRemoteSyncShortcutLabel() string { - return "Stop Using Remote Sync" -} - -func (m syncMenuModel) showRemoteSyncSetupShortcut() bool { - return m.hasOpenVault && !m.hasSelectedBinding -} - -func (m syncMenuModel) remoteSyncSetupShortcutLabel() string { - return "Set Up Remote Sync" -} - -func (m syncMenuModel) actionLabels() []string { - labels := []string{"Open Advanced Sync"} - if m.showRemoteSyncSetupShortcut() { - labels = append(labels, m.remoteSyncSetupShortcutLabel()) - } - if m.showDirectRemoteSyncShortcut() { - labels = append(labels, m.directRemoteSyncShortcutLabel()) - } - if m.showRemoteSyncSettingsShortcut() { - labels = append(labels, m.remoteSyncSettingsShortcutLabel()) - } - if m.showRemoveRemoteSyncShortcut() { - labels = append(labels, m.removeRemoteSyncShortcutLabel()) - } - return labels -} - -func (m syncMenuModel) saveCurrentRemoteBindingHeading() string { - return "Bind this local vault to the current remote target" -} - -func (m syncMenuModel) saveCurrentRemoteBindingButtonLabel() string { - return "Save Remote In Vault" -}