diff --git a/.gitignore b/.gitignore index 5564ee6..c7b1e68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ build/ *.apk keepassgo +android/keepassgo-android.jar packaging/archlinux/keepassgo-git/*.pkg.tar.zst packaging/archlinux/keepassgo-git/PKGBUILD packaging/archlinux/keepassgo-git/pkg/ diff --git a/android/keepassgo-android.jar b/android/keepassgo-android.jar deleted file mode 100644 index 556c6a8..0000000 Binary files a/android/keepassgo-android.jar and /dev/null differ diff --git a/main.go b/main.go index bed5e88..b2743ed 100644 --- a/main.go +++ b/main.go @@ -1559,6 +1559,44 @@ func (u *ui) startChooseSyncLocalSourceAction() { }) } +func pickedDocumentName(file io.ReadCloser, fallback string) string { + if named, ok := file.(interface{ Name() string }); ok { + if base := filepath.Base(strings.TrimSpace(named.Name())); base != "" && base != "." && base != string(filepath.Separator) { + return base + } + } + fallback = filepath.Base(strings.TrimSpace(fallback)) + if fallback == "" || fallback == "." || fallback == string(filepath.Separator) { + return "selected-vault.kdbx" + } + return fallback +} + +func (u *ui) startChooseVaultPathAction() { + if runtime.GOOS != "android" || u.fileExplorer == nil { + u.runAction("choose vault path", func() error { return u.chooseExistingFileAction(&u.vaultPath) }) + return + } + u.runBackgroundAction("choose vault file", func() (func() error, error) { + file, err := u.fileExplorer.ChooseFile(".kdbx") + if err != nil { + if errors.Is(err, explorer.ErrUserDecline) { + return func() error { return nil }, nil + } + return nil, err + } + defer file.Close() + content, err := io.ReadAll(file) + if err != nil { + return nil, err + } + name := pickedDocumentName(file, "selected-vault.kdbx") + return func() error { + return u.importSharedVaultBytesAction(name, content) + }, nil + }) +} + func (u *ui) startImportSharedVaultAction() { if !supportsSharedVaultImport(runtime.GOOS) || u.fileExplorer == nil { return @@ -4386,7 +4424,7 @@ func (u *ui) layout(gtx layout.Context) layout.Dimensions { if u.lifecycleBusy() { continue } - u.runAction("choose vault path", func() error { return u.chooseExistingFileAction(&u.vaultPath) }) + u.startChooseVaultPathAction() } for u.importSharedVault.Clicked(gtx) { if u.lifecycleBusy() { diff --git a/main_test.go b/main_test.go index 80ffeb8..1e58c8c 100644 --- a/main_test.go +++ b/main_test.go @@ -159,6 +159,42 @@ func TestUIMasterPasswordUsesPasswordInputHint(t *testing.T) { } } +func TestLocalVaultPathHelpForAndroidUsesChooserLanguage(t *testing.T) { + t.Parallel() + + if got := localVaultPathHelpForRuntime("android"); got != "Choose the existing .kdbx file to open." { + t.Fatalf("localVaultPathHelpForRuntime(android) = %q, want chooser guidance", got) + } +} + +func TestPickedDocumentNameUsesFileBaseName(t *testing.T) { + t.Parallel() + + dir := t.TempDir() + path := filepath.Join(dir, "mint-ledger.kdbx") + if err := os.WriteFile(path, []byte("mint"), 0o600); err != nil { + t.Fatalf("WriteFile(%q) error = %v", path, err) + } + file, err := os.Open(path) + if err != nil { + t.Fatalf("Open(%q) error = %v", path, err) + } + t.Cleanup(func() { _ = file.Close() }) + + if got := pickedDocumentName(file, "selected-vault.kdbx"); got != "mint-ledger.kdbx" { + t.Fatalf("pickedDocumentName(file, fallback) = %q, want mint-ledger.kdbx", got) + } +} + +func TestPickedDocumentNameFallsBackWhenUnnamed(t *testing.T) { + t.Parallel() + + reader := io.NopCloser(strings.NewReader("mint")) + if got := pickedDocumentName(reader, "crew-ledger.kdbx"); got != "crew-ledger.kdbx" { + t.Fatalf("pickedDocumentName(reader, fallback) = %q, want crew-ledger.kdbx", got) + } +} + func TestUISearchBehaviorIsConsistentAcrossDesktopAndPhoneLayouts(t *testing.T) { t.Parallel() diff --git a/ui_forms.go b/ui_forms.go index 94bdd52..28be39e 100644 --- a/ui_forms.go +++ b/ui_forms.go @@ -1140,13 +1140,17 @@ 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) { +func localVaultPathHelpForRuntime(goos string) string { + if supportsDesktopFilePicker(goos) || supportsSharedVaultImport(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 localVaultPathHelp() string { + return localVaultPathHelpForRuntime(runtime.GOOS) +} + func keyFileHelp() string { if supportsDesktopFilePicker(runtime.GOOS) { return "Optional path to a KeePass-compatible key file." @@ -1155,7 +1159,7 @@ func keyFileHelp() string { } func localPathSelector(th *material.Theme, editor *widget.Editor, click *widget.Clickable) layout.Widget { - if supportsDesktopFilePicker(runtime.GOOS) { + if supportsDesktopFilePicker(runtime.GOOS) || supportsSharedVaultImport(runtime.GOOS) { return selectorEditorHelp(th, "Vault Path", localVaultPathHelp(), editor, click, "Choose File", false) } return labeledEditorHelp(th, "Vault Path", localVaultPathHelp(), editor, false)