Fix Android local open flow
This commit is contained in:
@@ -577,7 +577,6 @@ func newUIWithState(mode string, sess appstate.CurrentSession, paths statePaths)
|
||||
apiPolicyGroupScope: true,
|
||||
autofillNoticePreference: autofillNoticeAll,
|
||||
backgroundResults: make(chan backgroundActionResult, 8),
|
||||
requestMasterPassFocus: true,
|
||||
}
|
||||
u.apiPolicyAllow.Value = true
|
||||
u.apiPolicyGroupScopeW.Value = true
|
||||
@@ -598,10 +597,12 @@ func newUIWithState(mode string, sess appstate.CurrentSession, paths statePaths)
|
||||
u.loadRecentVaults()
|
||||
u.loadRecentRemotes()
|
||||
u.restoreStartupLifecycleTarget()
|
||||
u.requestMasterPassFocus = u.hasSelectedLifecycleTarget()
|
||||
u.loadUIPreferences()
|
||||
u.loadSettings()
|
||||
u.loadSettingsFormFromPreferences()
|
||||
u.loadSettingsDraft()
|
||||
u.requestMasterPassFocus = u.hasSelectedLifecycleTarget()
|
||||
u.filter()
|
||||
u.syncAutofillCache()
|
||||
return u
|
||||
@@ -663,6 +664,10 @@ func shouldUsePreviewWindowSize(mode, goos string) bool {
|
||||
return !strings.EqualFold(strings.TrimSpace(goos), "android")
|
||||
}
|
||||
|
||||
func supportsDesktopFilePicker(goos string) bool {
|
||||
return !strings.EqualFold(strings.TrimSpace(goos), "android")
|
||||
}
|
||||
|
||||
func (u *ui) selectedAttachmentItems() []attachmentItem {
|
||||
item, ok := u.selectedEntry()
|
||||
if !ok || len(item.Attachments) == 0 {
|
||||
@@ -1594,6 +1599,15 @@ func (u *ui) restoreStartupLifecycleTarget() {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *ui) hasSelectedLifecycleTarget() bool {
|
||||
switch strings.TrimSpace(u.lifecycleMode) {
|
||||
case "remote":
|
||||
return strings.TrimSpace(u.remoteBaseURL.Text()) != "" && strings.TrimSpace(u.remotePath.Text()) != ""
|
||||
default:
|
||||
return strings.TrimSpace(u.vaultPath.Text()) != ""
|
||||
}
|
||||
}
|
||||
|
||||
func (u *ui) latestRecentVault() (string, time.Time) {
|
||||
for _, path := range u.recentVaults {
|
||||
if strings.TrimSpace(path) == "" {
|
||||
@@ -3699,7 +3713,10 @@ func (u *ui) syncDialogContent(gtx layout.Context) layout.Dimensions {
|
||||
}),
|
||||
)
|
||||
}
|
||||
return selectorEditorHelp(u.theme, "Local Vault Path", "Choose the other local .kdbx file to synchronize with.", &u.syncLocalPath, &u.pickSyncLocalPath, "Choose File", false)(gtx)
|
||||
if supportsDesktopFilePicker(runtime.GOOS) {
|
||||
return selectorEditorHelp(u.theme, "Local Vault Path", "Choose the other local .kdbx file to synchronize with.", &u.syncLocalPath, &u.pickSyncLocalPath, "Choose File", false)(gtx)
|
||||
}
|
||||
return labeledEditorHelp(u.theme, "Local Vault Path", "Enter the shared-storage path to the other local .kdbx file to synchronize with.", &u.syncLocalPath, false)(gtx)
|
||||
}),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(14)}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
|
||||
@@ -3519,6 +3519,50 @@ func TestUIStartupPreselectsNewestTargetAcrossLocalAndRemote(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIStartupDoesNotRequestMasterPasswordFocusWithoutSelectedTarget(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dir := t.TempDir()
|
||||
u := newUIWithSession("phone", &session.Manager{}, statePaths{
|
||||
DefaultSaveAsPath: filepath.Join(dir, "vault.kdbx"),
|
||||
RecentVaultsPath: filepath.Join(dir, "recent-vaults.json"),
|
||||
RecentRemotesPath: filepath.Join(dir, "recent-remotes.json"),
|
||||
SettingsPath: filepath.Join(dir, "settings.json"),
|
||||
UIPreferencesPath: filepath.Join(dir, "ui-prefs.json"),
|
||||
AutofillCachePath: filepath.Join(dir, "autofill-cache.json"),
|
||||
})
|
||||
|
||||
if u.requestMasterPassFocus {
|
||||
t.Fatal("requestMasterPassFocus = true without a selected startup target, want false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIStartupRequestsMasterPasswordFocusForSelectedRecentVault(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dir := t.TempDir()
|
||||
paths := statePaths{
|
||||
DefaultSaveAsPath: filepath.Join(dir, "vault.kdbx"),
|
||||
RecentVaultsPath: filepath.Join(dir, "recent-vaults.json"),
|
||||
RecentRemotesPath: filepath.Join(dir, "recent-remotes.json"),
|
||||
SettingsPath: filepath.Join(dir, "settings.json"),
|
||||
UIPreferencesPath: filepath.Join(dir, "ui-prefs.json"),
|
||||
AutofillCachePath: filepath.Join(dir, "autofill-cache.json"),
|
||||
}
|
||||
|
||||
first := newUIWithSession("phone", &session.Manager{}, paths)
|
||||
first.noteRecentVault("/tmp/demo.kdbx")
|
||||
|
||||
reopened := newUIWithSession("phone", &session.Manager{}, paths)
|
||||
|
||||
if got := reopened.vaultPath.Text(); got != "/tmp/demo.kdbx" {
|
||||
t.Fatalf("vaultPath = %q, want /tmp/demo.kdbx", got)
|
||||
}
|
||||
if !reopened.requestMasterPassFocus {
|
||||
t.Fatal("requestMasterPassFocus = false with a selected startup vault, want true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIGroupToolsDisclosureStatePersists(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -4311,6 +4355,17 @@ func TestShouldUsePreviewWindowSizeSkipsAndroid(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSupportsDesktopFilePicker(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
if got := supportsDesktopFilePicker("android"); got {
|
||||
t.Fatal("supportsDesktopFilePicker(android) = true, want false")
|
||||
}
|
||||
if got := supportsDesktopFilePicker("linux"); !got {
|
||||
t.Fatal("supportsDesktopFilePicker(linux) = false, want true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnterOnLocalLifecycleScreenDefaultsToOpenVault(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
+35
-6
@@ -6,6 +6,7 @@ import (
|
||||
"image/color"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"gioui.org/layout"
|
||||
@@ -27,7 +28,7 @@ func (u *ui) lifecycleControls(gtx layout.Context) layout.Dimensions {
|
||||
}),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(4)}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
message := "Choose a recent vault or pick a `.kdbx` file, then unlock it."
|
||||
message := "Choose a recent vault or enter a .kdbx path, then unlock it."
|
||||
if u.lifecycleMode == "remote" {
|
||||
message = "Connect to a remote vault, then unlock it with the KeePass master key."
|
||||
}
|
||||
@@ -182,9 +183,9 @@ func (u *ui) lifecycleControls(gtx layout.Context) layout.Dimensions {
|
||||
selectedPath := strings.TrimSpace(u.vaultPath.Text())
|
||||
switch {
|
||||
case busy:
|
||||
return labeledEditorHelp(u.theme, "Vault Path", "Choose the existing .kdbx file to open.", &u.vaultPath, false)(gtx)
|
||||
return labeledEditorHelp(u.theme, "Vault Path", localVaultPathHelp(), &u.vaultPath, false)(gtx)
|
||||
case selectedPath == "":
|
||||
return selectorEditorHelp(u.theme, "Vault Path", "Choose the existing .kdbx file to open.", &u.vaultPath, &u.pickVaultPath, "Choose File", false)(gtx)
|
||||
return localPathSelector(u.theme, &u.vaultPath, &u.pickVaultPath)(gtx)
|
||||
default:
|
||||
lastGroup := u.recentVaultGroup(selectedPath)
|
||||
return compactCard(gtx, func(gtx layout.Context) layout.Dimensions {
|
||||
@@ -242,9 +243,9 @@ func (u *ui) lifecycleControls(gtx layout.Context) layout.Dimensions {
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
if busy {
|
||||
return labeledEditorHelp(u.theme, "Key File", "Optional path to a KeePass-compatible key file.", &u.keyFilePath, false)(gtx)
|
||||
return labeledEditorHelp(u.theme, "Key File", keyFileHelp(), &u.keyFilePath, false)(gtx)
|
||||
}
|
||||
return selectorEditorHelp(u.theme, "Key File", "Optional path to a KeePass-compatible key file.", &u.keyFilePath, &u.pickKeyFile, "Choose File", false)(gtx)
|
||||
return keyFileSelector(u.theme, &u.keyFilePath, &u.pickKeyFile)(gtx)
|
||||
}),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
if busy {
|
||||
@@ -1149,6 +1150,34 @@ func labeledEditorHelp(th *material.Theme, label, help string, editor *widget.Ed
|
||||
return labeledEditorHelpFocus(th, defaultAccessibilityPreferences(), label, help, editor, sensitive, false)
|
||||
}
|
||||
|
||||
func localVaultPathHelp() string {
|
||||
if supportsDesktopFilePicker(runtime.GOOS) {
|
||||
return "Choose the existing .kdbx file to open."
|
||||
}
|
||||
return "Enter the shared-storage path to the existing .kdbx file, for example /sdcard/Download/vault.kdbx."
|
||||
}
|
||||
|
||||
func keyFileHelp() string {
|
||||
if supportsDesktopFilePicker(runtime.GOOS) {
|
||||
return "Optional path to a KeePass-compatible key file."
|
||||
}
|
||||
return "Optional shared-storage path to a KeePass-compatible key file."
|
||||
}
|
||||
|
||||
func localPathSelector(th *material.Theme, editor *widget.Editor, click *widget.Clickable) layout.Widget {
|
||||
if supportsDesktopFilePicker(runtime.GOOS) {
|
||||
return selectorEditorHelp(th, "Vault Path", localVaultPathHelp(), editor, click, "Choose File", false)
|
||||
}
|
||||
return labeledEditorHelp(th, "Vault Path", localVaultPathHelp(), editor, false)
|
||||
}
|
||||
|
||||
func keyFileSelector(th *material.Theme, editor *widget.Editor, click *widget.Clickable) layout.Widget {
|
||||
if supportsDesktopFilePicker(runtime.GOOS) {
|
||||
return selectorEditorHelp(th, "Key File", keyFileHelp(), editor, click, "Choose File", false)
|
||||
}
|
||||
return labeledEditorHelp(th, "Key File", keyFileHelp(), editor, false)
|
||||
}
|
||||
|
||||
func labeledEditorHelpFocus(th *material.Theme, prefs accessibilityPreferences, label, help string, editor *widget.Editor, sensitive bool, focused bool) layout.Widget {
|
||||
return func(gtx layout.Context) layout.Dimensions {
|
||||
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
|
||||
@@ -1252,7 +1281,7 @@ func (u *ui) unlockPanel(gtx layout.Context) layout.Dimensions {
|
||||
return u.masterPasswordField(gtx, "Used alone or together with a key file to unlock the vault.")
|
||||
}),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(6)}.Layout),
|
||||
layout.Rigid(selectorEditorHelp(u.theme, "Key File", "Optional path to a KeePass-compatible key file.", &u.keyFilePath, &u.pickKeyFile, "Choose File", false)),
|
||||
layout.Rigid(keyFileSelector(u.theme, &u.keyFilePath, &u.pickKeyFile)),
|
||||
layout.Rigid(layout.Spacer{Height: unit.Dp(8)}.Layout),
|
||||
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
|
||||
return tonedButton(gtx, u.theme, &u.unlockVault, "Unlock")
|
||||
|
||||
Reference in New Issue
Block a user