summaryrefslogtreecommitdiffstats
path: root/app/src/main
AgeCommit message (Collapse)AuthorFilesLines
23 hoursfix(app): point the rebase conflict error at the current settings pathDanilo M.10-11/+10
The detached HEAD error sent users to "Settings > Git utils", a screen the Compose settings no longer have. Every locale now names Settings > Repository > Local Git config & utilities, and the English quotes are escaped so they show. The git configuration screen's title reuses that translated row label instead of an untranslatable English string. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
24 hoursfix(app): name the pushed conflict branch after abort rebaseDanilo M.1-6/+7
The success dialog showed a literal conflicting-<branch>-... instead of the branch BreakOutOfDetached pushed. It now reads the newest local conflicting-<branch>-<millis> ref, which is the one just created. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
24 hoursfix(i18n): name HardenedPass in every localeDanilo M.8-22/+22
0.1.4 renamed the app in the English and Italian autofill and biometric texts only; German, French, Galician, Korean, Polish, Brazilian Portuguese, Russian and Chinese still said Password Store in 22 strings. 20 now name HardenedPass; the two German messages where it meant the store itself say Repository, as the rest of that translation does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
24 hoursrefactor(app): lay out the git credential prompt without ConstraintLayoutDanilo M.1-10/+5
The prompt was ConstraintLayout's last user: a vertical LinearLayout holds the same field and checkbox, so the dependency goes. Ids, input type and the remember box's default are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
24 hoursbuild(app): drop the View-era dependencies and view bindingDanilo M.4-43/+0
Nothing uses preference, recyclerview, recyclerview-selection, fastscroll or modernandroidpreferences since the Compose screens replaced the Views, nor view binding. fragment-ktx stays as the pin that keeps androidx.fragment at 1.8.4. The preference widget override, the multiselect attribute, the toolbar and bottom sheet styles and the lint ignores for deleted layouts go. Lint checks unused ids again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
24 hoursrefactor(app): fold BasePGPActivity into the autofill decryptionDanilo M.7-78/+59
AutofillDecryptActivity was its last subclass: it now sets FLAG_SECURE and injects the settings, crypto repository and dispatchers itself. The path and clipboard helpers move to CryptoExtensions.kt as top-level functions (a test pins the path helpers), and the FILE_PATH extra key moves, unchanged, to LaunchActivity. An invalid or short .gpg-id ID is reported with a toast: the snackbar never showed in the autofill decryption, which closes its window at once. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
24 hoursrefactor(app): drop dead Fragment, view and navigation stack helpersDanilo M.10-274/+14
The Compose screens use no Fragments or view binding, so FragmentExtensions (with its four slide animators) and FragmentViewBindingDelegate have no users, nor do resolveAttribute, isPermissionGranted, launchActivity and the unused Modifier.conditional. SearchableRepositoryViewModel keeps one navigateTo: the Compose list owns the back stack, so the RecyclerView-era navigation stack, stableId, isFiltered and the unused DirectoriesOnly mode go. PasswordItem loses the parent overloads, @JvmStatic and the unread NAME extra, and the leftover sentry.properties goes too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
29 hoursfix(app): show the autofill switch off right after turning it offDanilo M.1-1/+2
hasEnabledAutofillServices() still answers true right after disableAutofillServices(), so the switch stayed on and the next tap turned autofill off again instead of opening the instructions dialog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
30 hoursfix(app): guard the autofill picker against overlaysDanilo M.3-2/+7
The picker decides which entry fills the requesting app, so it drops touches under another app's overlay, as the publisher warning does. The entry view now uses cachesPassphrase too, so the cache rule lives in one place, and the publisher warning's app name gets its closing quote. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
30 hoursdocs: record the autofill activities' Compose UI in the specDanilo M.1-2/+3
The autofill activities cannot join MainActivity's graph, so they keep opening the PGP key import through the setup intent; the spec and the ponytail note no longer promise otherwise. The spec gains an Autofill section. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
30 hoursfix(app): cache only a typed autofill passphrase, close on a bad .gpg-idDanilo M.1-5/+17
Autofill re-cached the passphrase it had just read from the cache, and cached an empty one for keys without a passphrase. Like the entry view, it now caches only what the user typed into the passphrase dialog. An unreadable .gpg-id left the transparent window up with a snackbar no one could see; the activity now finishes and fills nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
30 hoursfeat(app): move the autofill decryption prompts to ComposeDanilo M.8-262/+148
AutofillDecryptActivity shows the no keys dialog and the entry view's passphrase dialog in Compose over its transparent FLAG_SECURE window. The flow starts once, on the first window focus, instead of on every onStart: Android 14 evicts a screen lock prompt shown before the activity is on top, and a restart showed a second passphrase dialog. After a key import it restarts on the next focus. Dismissing the no keys dialog now finishes instead of leaving an invisible window. Rotation and resizing no longer recreate the activity; other recreations cancel the fill. The passphrase is now cached only after a successful screen lock prompt, as the entry view does: a passphrase typed after a cancelled or unavailable prompt was cached whenever the cache feature was on. PasswordDialog, its layout, dimens.xml and requireKeysExist lose their last user and go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
30 hoursfix(app): keep a double tap from re-enabling autofillDanilo M.1-6/+10
The Re-enable button replaced Advanced information in place, so a quick double tap re-enabled autofill for an app with a changed publisher (upstream had the same flaw). The package and certificate details now come first and push Re-enable below them. The title is marked as a heading and the footer's ponytail note sits on the footer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
30 hoursfix(app): address the autofill picker reviewDanilo M.3-5/+12
- Run the first search during composition with the saved query and strict switch, so a recreated picker no longer flashes the results for the initial query under the restored text. - Scroll the result list back to the top on every new result, as the old picker did. - Fall back to the file name when a row has neither identifier nor account part, instead of an empty label. DirectoryStructure never returns both null today, so no test can reach it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
30 hoursfeat(app): move the publisher warning to ComposeDanilo M.4-236/+175
AutofillPublisherChangedActivity draws the warning with the shared theme. Keep Autofill disabled is now the primary button, and the Possible phishing attempt title replaces the logo. Re-enabling still takes two taps (Advanced information first) and still clears the app's matches before returning the prepared fill response; every other way out fills nothing. Touches that reach the warning through another app's window are now dropped (filterTouchesWhenObscured on the decor view), so an overlay cannot trick the user into re-enabling. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
30 hoursfeat(app): move the autofill picker to ComposeDanilo M.10-488/+215
AutofillFilterView draws the picker with the shared theme: origin header, search field, entry rows in a grouped surface and the three switches, over the same SearchableRepositoryViewModel search. Rows name the origin identifier and show the account and folders below it. The first tap wins, so a double tap no longer starts two decryptions. PasswordViewHolder, the RecyclerView adapter, the two layouts, their drawables, the multiselect color and their lint baseline entries go. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
30 hoursfeat(app): add the autofill picker's row modelDanilo M.1-0/+38
autofillRows turns the picker's search results into list rows: the origin identifier, the part that must match the site or app, becomes the row's name, and the account part and the folders above it the subtitle, as the old picker's bold title and subtitle showed them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
46 hoursfix(app): make the app lock work on Android 14Danilo M.2-3/+12
LaunchActivity showed the screen lock prompt from onCreate, before the activity was on top. Android 14's SystemUI evicts a prompt whose app is not the top activity ("Evicting client due to top activity is not ..."), so the prompt closed at once with ERROR_CANCELED and the app quit. This is upstream issue 2802, which upstream worked around by disabling the setting on Android 14. The prompt now opens on the first window focus. LaunchActivity also used a translucent theme, so after unlocking the home screen showed through until MainActivity drew. It now uses the app's opaque theme. Verified on an Android 14 tablet with a PIN-only screen lock: unlock opens the app without a flash of the home screen, cancel closes it, and turning the lock off asks for the PIN. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
47 hoursfix(app): validate the proxy fully and keep its password out of propertiesDanilo M.2-11/+10
- A host with an empty port was saved, but ProxySelector treats port -1 as no proxy, so git silently connected directly. The port is now required while a host is set. - Patterns.WEB_URL accepted "http://proxy.example.org:3128/" as a host, which then broke every HTTPS operation. The host must be a numeric address or a plain domain name, without scheme, port or path. - setDefaultProxy copied the proxy password into the process-wide http.proxyPassword system property. The Authenticator already supplies the credentials, so the properties are only cleared now. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
47 hoursrefactor(app): remove the legacy settings screensDanilo M.35-1783/+4
The Compose settings, git config, commit log and proxy screens replace SettingsActivity with its six preference providers, GitConfigActivity with TextInputDialog, GitLogActivity with its adapter and GitLogModel, and ProxySelectorActivity, with their layouts and manifest entries. The dead OpenKeystore key ID row goes with its string, the Android 14 platform bug summary and normal_margin lose their last users, and the setup intent loses the two starts only Settings used. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
47 hoursfeat(app): run Settings in MainActivityDanilo M.4-9/+99
The list and the welcome screen open the Compose settings; their rows open the git server, SSH key, key generation, PGP keys, proxy and git config screens within the graph. Deleting the repository returns to the welcome screen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
47 hoursfix(git): stop SSH auth hanging after a closed screen lock promptDanilo M.1-7/+3
executeAfterAuthentication waited for another result whenever the prompt reported Failure, on the assumption that Failure meant a failed attempt with the prompt still open. Failure comes from error callbacks (lockout, timeout, unable to process), which always close the prompt, so the operation hung forever. Only Retry keeps the prompt open; every other result now ends the wait, and Failure and CanceledBySystem fail the operation with the generic screen lock error, like the other non-success results. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
47 hoursfix(app): end the screen lock prompt on sensor errorsDanilo M.4-12/+21
BiometricAuthenticator mapped onAuthenticationError(ERROR_UNABLE_TO_PROCESS) to Retry, but an error callback always closes the prompt. The settings screen keeps its one-prompt-at-a-time guard set on Retry, so the gated switches stayed locked until the section was left. The error now maps to Failure; Retry comes only from onAuthenticationFailed, while the prompt is still open. Once the device screen lock is removed, the biometric app lock could not be turned off: the prompt returns HardwareUnavailableOrDisabled and nothing was written. Turning it off without a usable screen lock now writes the value directly, as the passphrase cache row already does. The settings category rows and PreferenceAction rows get Role.Button for accessibility services. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
47 hoursfeat(app): add the Compose git config and commit log screensDanilo M.7-3/+541
Author name and email, HEAD status, commit log, abort rebase, hard reset and gc. The hard reset now warns and prefills the current branch; a finished reset or gc stays on the screen with a snackbar, and a failed operation keeps the screen too. The commit log is read off the main thread. BreakOutOfDetached's not-rebasing dialog no longer finishes the calling activity. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
47 hoursfeat(app): add the Compose proxy screenDanilo M.4-0/+259
Host, port, user name and password. An invalid host or port blocks the save, an emptied port is cleared, the proxy applies at once, and the screen is FLAG_SECURE while the saved password is on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
47 hoursfeat(app): add the Compose settings screensDanilo M.4-0/+655
The categories and one screen per category, with the old rows over the same keys. Screen lock gated switches store their value only after a successful prompt. Clearing a saved HTTPS password or SSH passphrase, which never removed anything, now asks and removes it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
47 hoursfeat(app): add Compose preference rows and the settings stateDanilo M.2-0/+442
Switch, single choice, text and action rows over the existing preference keys, and a ViewModel that reads every displayed value, follows preference changes, deletes the store without following symlinks, and clears saved credentials and the passphrase cache. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
47 hoursfeat(app): drop two sort orders, fix the proxy user nameDanilo M.16-42/+106
The Compose list shows folders and entries in separate groups, so the files first and type independent sort orders did nothing visible. They are removed; a stored one migrates to folders first, and any unknown value reads as folders first instead of throwing. The OpenKeychain SSH key ID, which nothing reads any more, is removed once. GitSettings wrote the proxy user name to the proxy preferences but read it from the main settings, so ProxyUtils never authenticated. Adds the pure parts of the settings port: proxy port parsing, HEAD status and the commit log. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfix(app): address the step 5 review and emulator findingsDanilo M.6-10/+40
- A store a cancelled attempt already made for the chosen key (its .gpg-id names exactly that key) no longer counts as occupied: choosing the key again commits and moves on instead of refusing. - SSH key import reads at most 100 kB whatever the provider reports, like the PGP import, instead of reading the stream whole. - PGPKeyManager replaces a key through a temporary file moved over it atomically, so a failed write keeps the old key; listings only read .key files, so a stray temporary file is never taken for a key. - "View generated public SSH key" goes through the settings result launcher, so the preference visibility refreshes afterwards. - A plain start from LaunchActivity replaces the task: an open MainActivity (e.g. one whose store vanished) is no longer left below the new one, and one back leaves the app. - The PGP keys screen's import FAB carries its content description itself; M3 cleared the icon's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysrefactor(app): remove the legacy setup screensDanilo M.35-1997/+0
The Compose welcome, git server, SSH key, key generation and PGP keys screens replace OnboardingActivity with its fragments, GitServerConfigActivity with BasicBottomSheet, SshKeyImportActivity, SshKeyGenActivity, ShowSshKeyFragment, PGPKeyImportActivity and PGPKeyListActivity with KeyList and PGPKeyListViewModel, their layouts and manifest entries, and ui:compose's APSAppBar. Resources only they used are removed too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfix(app): localize the occupied store refusalDanilo M.4-5/+7
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfix(app): guard store creation and tidy the setup screensDanilo M.4-5/+9
- createStore refuses a non-empty store folder (only .git allowed), so a restored, cloned store keeps its .gpg-id - failed store creation cleans up with deleteWithoutFollowingLinks, which also removes a fresh .git - PGP keys screen: Later goes through the guarded leave path - Import SSH key row launches via the result launcher so the public key row refreshes - GitServerViewModel.changeUrl always refits the auth mode, also for an empty URL Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfeat(app): run setup in MainActivityDanilo M.9-49/+185
The welcome screen starts the app without a store, the list sends a vanished store back to it, and its clone prompt opens the git server screen. A clone asks for the store's PGP key when none matches it. Settings, the entry view, autofill decryption and git operations open the setup screens through MainActivity.setupIntent. The No SSH key dialog's Cancel and the unusable screen lock prompt no longer finish the calling activity, which is now the app's main screen. KeysMode is a route argument, so it is kept from minification (lint MissingKeepAnnotation). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfeat(app): add the Compose PGP keys screenDanilo M.3-0/+337
One screen for managing keys, choosing the key of a new local store and importing the key a store needs. Rows show user ID and key ID; the import keeps the old success, replace and failure dialogs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfeat(app): add the Compose SSH key and key generation screensDanilo M.3-0/+381
The SSH key screen shows the key's state and, for a generated key, the public key with copy and share, and imports a key file after the old replace confirmation. The generation screen ports the old one; the key is generated in the ViewModel after the screen lock prompt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfeat(app): add the Compose welcome and git server screensDanilo M.4-0/+452
The welcome screen merges the old welcome and repository type screens. The git server screen serves clone and edit: the old URL checks as dialogs, authentication mode buttons, the SSH key's state with Manage, the host key reset, and a clone that keeps the screen on failure. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfix(app): harden the setup key importsDanilo M.7-48/+126
- PGP key import reads at most 1 MiB (bounded read, buffer zeroed) and refuses larger files with a new message. - SshKeyViewModel catches any Exception from import and generation (CancellationException rethrown) instead of a short list, so an unexpected provider or sshj error no longer crashes the app. - Pending PGP key bytes are zeroed in a finally block, also on cancellation during addKey after a replace, and an earlier pending pick is zeroed before a new one takes its place. - PGPKeyManager never replaces a stored secret key with a public-only key of the same ID, with or without replace (KeyDowngradeException); the setup ViewModel shows a localized message for it. Unit test added. - storeRecipients strips '#' comments and a trailing '!' as pass reads .gpg-id; tests added. - GitServerViewModel.clearStore returns the failure when the store folder cannot be emptied, so the clone does not start; the plan's Task 3 call site reports it. - readGpgId opens the file with NOFOLLOW_LINKS and reads at most 64 KiB + 1 bytes, refusing more. - SshKey.import writes the new private key to a temp file and moves it over atomically before dropping the old key's Keystore entry, public key and passphrase, so an I/O error keeps the old key. - KeyUtils.isSecretKey notes (ponytail) that GnuPG stub and smartcard keyrings count as secret. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfeat(app): add the setup ViewModelsDanilo M.5-0/+505
Git server (URL, mode, clone state, the after-clone key check), SSH key (import and generation off the main thread, outcome kept across recreation) and PGP keys (rows with key IDs, import with the replace question, delete by key ID, creation of a local store). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfeat(app): add the setup model and stricter key checksDanilo M.2-10/+127
URL checks and fixes, authentication modes per URL, the clone target, the store's recipients, a size- and symlink-checked .gpg-id read and the .gpg-id text for a new store (uppercase long key IDs), as pure functions for the Compose setup screens. The SSH key import now also requires a format sshj recognizes (an OpenPGP private key block matched the old marker check and was imported as the SSH key) and no longer crashes on an empty size cursor. KeyUtils tells secret keys apart and no longer throws on a key without user ID. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfix(git): get sshj's Ed25519 keys from Bouncy CastleDanilo M.1-0/+18
Recent Conscrypt (Android 14 mainline updates) registers a KeyFactory for Ed25519. With sshj leaving provider selection to the JCA, its Ed25519KeyFactory now gets Conscrypt's key class, whose algorithm name sshj does not map to ssh-ed25519: KeyType.fromKey returns UNKNOWN and every Ed25519 host key fails with "Don't know how to encode key", so clone and sync over SSH break. 0.1.4 is affected since the sshj 0.41.2 update. Register a provider at position 1 that serves only KeyFactory.Ed25519 from Bouncy Castle (kept by the existing R8 rule). Everything else, including signatures with Android Keystore keys, still goes through normal JCA provider selection. Verified on an Android 14 tablet: clone over SSH failed before and works with the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit ad3c63f665e6264ed1db42d6ae2dfc0947e33393)
2 daysfix(app): pick editor recipients and folder from resolved pathsDanilo M.3-6/+5
- Look up the .gpg-id from the normalized target's folder, so a prefilled folder such as a/../b cannot pick a/'s recipients. - Derive the edited entry's folder from its canonical parent, so a store path spelled differently does not show as ../../data/...; the file name still comes from the link. - Drop the REPO_PATH shortcut extra nothing reads any more. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysrefactor(app): remove the legacy editor, generators and folder pickerDanilo M.34-1825/+2
The Compose editor, generator sheet, OTP dialog and folder picker replace PasswordCreationActivity, the generator and manual OTP dialog fragments, SelectFolderActivity with its fragment and adapter, their layouts and menus, and upstream's unused EditPasswordScreen with the PasswordField it used. flowbinding and swiperefreshlayout had no other users. BasePGPActivity keeps what autofill decryption still needs. Also drops two stale SshKey baseline entries, the snackbar FAB anchor whose view is gone, and resources only the deleted files used. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfeat(app): host the Compose editor in the autofill save flowDanilo M.2-54/+75
AutofillSaveActivity shows the editor itself, prefilled from the form and FLAG_SECURE, instead of starting the legacy editor for a result. The autofill match and the generated-password fill work as before: the username and password are read back from the saved content, as the old editor did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfix(app): finish an editor save after recreationDanilo M.3-35/+65
A successful save left saving set while the destination committed in the activity's lifecycleScope. An activity recreated then (theme, locale, split-screen resize) cancelled that scope: onSaved never ran, and the surviving ViewModel kept Save disabled and back swallowed. The ViewModel now keeps the success in a memory-only saved state, set inside the NonCancellable write so a cancelled caller cannot lose it. A LaunchedEffect on it runs the commit and onSaved, so a recreated editor finishes the job; "Save and copy" and the stale-original notice run once only, and left() clears it before onSaved navigates. Editing a symlinked entry derived its folder from the canonical path but its name from the link, saving a new entry next to the target. The folder is now relative to the non-canonical repository directory; the save still checks the target is inside the store. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfeat(app): open the Compose editor from the list and entry viewDanilo M.4-55/+359
EditRoute replaces the legacy editor for new entries and edits. An edit copies its plaintext from the entry view's ViewModel below it, never through the route or saved state. Saving returns to the list, closing returns to where the editor was opened. FLAG_SECURE is now counted in MainActivity, so moving between the entry view and the editor never clears it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfeat(app): add the Compose editor screen and generator sheetDanilo M.4-0/+534
Stateless editor: name, folder breadcrumbs with Change, password with reveal and generator, username, extra content and the OTP actions. The generator sheet has random and diceware tabs with the old options; the manual OTP dialog and the sheet are FLAG_SECURE. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfix(app): harden the editor save path and the pickerDanilo M.6-8/+35
- Run the save's write, original delete, autofill and history updates under NonCancellable so a recreated activity cannot leave a half done rename. - fsync the temporary file before the atomic move. - Move dialog: refuse targets outside the store (symlinks) and moving a folder into itself or a descendant, with a toast. - Folder picker: do not navigate into a new folder whose mkdirs failed; show a toast (new string, en and it). - Normalize entryFile so "./" and "a/../b" give the same keys as the list; covered in EditorModelTest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfeat(app): add the editor ViewModelDanilo M.3-8/+259
Holds the form in memory only, generates passwords with the stored generator options, decodes QR images and saves off the main thread: nothing is written when the target would replace another entry or when encryption fails, the file is written through a temporary file, and a renamed or moved entry takes its autofill matches and recently-used time along. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfeat(app): add the Compose folder picker for movesDanilo M.4-29/+161
A dialog with breadcrumbs, subfolder rows and New folder replaces the legacy folder picker activity for the list's move action; the editor will share it. New folder reuses the list's name dialog and checks. A second tap on Select no longer moves twice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 daysfeat(app): add the editor model and the picker's folder listingDanilo M.2-0/+156
Pure functions for the Compose editor: the form and the pass file it writes, validation, the target file, the overwrite check, an atomic write, OTP URI building and the random generator's options. The folder picker lists subfolders with the list's hidden filter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>