Commit Graph
21 Commits
Author SHA1 Message Date
krissandClaude Sonnet 5 da5ad145b0 fix: make search bar always visible instead of toggle-behind-icon
Removed the magnifying-glass toolbar button and the isSearching state
it drove -- .searchable() now shows the search field unconditionally,
which is simpler and was requested after hands-on use showed the extra
tap added no value. Updated the spec to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 19:08:36 +02:00
krissandClaude Sonnet 5 e6136a3f63 fix: use sheet-presented group filter on iOS instead of NavigationSplitView
Confirmed by hands-on testing: NavigationSplitView's compact-width
collapse only pushes into the detail column when the sidebar drives
navigation via row selection. GroupFilterView is a multi-select filter,
not a picker, so on iPhone it showed only the sidebar with no way to
reach the entry list at all -- exactly the risk the final whole-branch
review flagged as unverified.

iOS now uses a plain NavigationStack with EntryListView as the root and
GroupFilterView presented as a sheet via the hamburger button. macOS
keeps the persistent NavigationSplitView sidebar, which does work
correctly at regular width.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 17:31:46 +02:00
krissandClaude Sonnet 5 f454b4594a fix: correct add-entry default group and clear search on hide
- GroupFilterViewModel now tracks lastToggledGroupId (the single group
  most recently toggled to a non-empty selection), since toggling a
  group with subgroups expands selectedGroupIds to include the whole
  subtree, breaking the previous count==1 check used to infer the
  active filter group.
- VaultViewModel exposes lastToggledGroupId, forwarded from
  GroupFilterViewModel by VaultRootView (ContentView.swift), and
  EntryListView.defaultGroupId now reads it instead of the broken
  selectedGroupIds.count == 1 check, so the add-entry sheet defaults
  new entries into the group actually being filtered by, not silently
  back to root.
- EntryListView's search toggle button now clears vm.searchQuery when
  hiding the search bar, so a hidden bar can no longer keep filtering
  the list invisibly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 17:25:06 +02:00
krissandClaude Sonnet 5 05bd34208b fix: VaultViewModel forwards session objectWillChange explicitly
Prevents EntryListView refresh from relying on an implicit SwiftUI
re-render cascade through ContentView; now vaultVM itself publishes
when session.database changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 17:17:38 +02:00
krissandClaude Sonnet 5 b7bdd6f1f6 feat: unify iOS/macOS navigation as NavigationSplitView, fix VM lifecycle
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 17:13:34 +02:00
krissandClaude Sonnet 5 171ce1eea7 feat: add EntryListView, remove GroupBrowserView and SearchView
Replaces group-drilling navigation with a flat, filterable/searchable
entry list backed by VaultViewModel.displayedEntries. SearchView's
role is fully absorbed by EntryListView's .searchable() modifier.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 17:11:02 +02:00
krissandClaude Haiku 4.5 bf93b75bdf feat: add GroupFilterViewModel and GroupFilterView sidebar
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 17:07:44 +02:00
krissandClaude Haiku 4.5 e653071f80 feat: add group + search filtering to VaultViewModel
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 17:04:52 +02:00
krissandClaude Sonnet 5 1ec0d02e44 feat: require groupId in EntryEditViewModel, add group picker to EntryEditView
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 17:02:03 +02:00
krissandClaude Sonnet 5 ee350c4c02 feat: add password reveal toggle, friendlier KDBX4 wrong-password message
Adds an eye-icon toggle to the master password field (UnlockView) so
users can verify what they typed before submitting.

Also maps KDBX4's ERROR_HEADER_HASH_VERIFICATION_FAILED -- surfaced
via the header HMAC check, which is password-derived -- to
KDBXError.invalidPassword alongside the existing
passwordAndOrKeyfileWrong check. KeePassKit uses this same error code
for both a wrong password/keyfile and genuine file corruption (it
doesn't distinguish the two), so the message hedges: "Incorrect
password, or this vault file is corrupted." Found while testing
against a real KDBX4 vault, which was surfacing this as a raw,
unreadable NSError string before the previous commit's LocalizedError
fix, and as *no* friendly message at all before this one (the error
code wasn't in the recognized set yet).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 16:17:17 +02:00
krissandClaude Sonnet 5 82cc800415 fix: don't attempt unlock with an empty password on first file pick
UnlockViewModel.openFile(url:) called unlockWithPassword() immediately
after saving the bookmark, but the first-open UI (openFileSection) has
no password field yet -- password is still "" at that point, so every
first file pick failed before the user could type anything. Picking a
file now only saves the bookmark; the view naturally switches to the
password-entry state for the user to unlock explicitly.

Also makes KDBXError conform to LocalizedError with readable messages
per case, so any error path that reaches the generic catch clause
shows something useful instead of the default
"The operation couldn't be completed (MyPassCore.KDBXError error N)".

Found while testing the Phase 4 UI against a real KDBX file in the
simulator.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 16:14:10 +02:00
krissandClaude Sonnet 5 ed6e4ab9ab feat: wire ContentView router, macOS 3-column layout, scene lifecycle lock
Completes Phase 4 (Task 17) -- ContentView now routes between UnlockView
and the vault UI (NavigationStack on iOS, 3-column NavigationSplitView on
macOS) instead of the leftover SwiftData template, finally resolving the
long-standing "cannot find type Item" build break. Vault locks on
scene-background (iOS) / resign-active (macOS).

Fixes two more real bugs surfaced now that everything actually links
together: EntryEditViewModel.save's dismiss closure needed @escaping
(used inside Task {}), and UnlockView's UTType(filenameExtension:)
needed `import UniformTypeIdentifiers`.

Also restores MyPass.entitlements, which had regressed to an empty
App Group array with Keychain Sharing missing entirely since the
"wire up AutoFill extension target" commit -- likely clobbered by
Xcode reconciling capabilities at some point without a rebuild in
between to catch it. Verified clean `xcodebuild` on both iOS Simulator
and macOS destinations, and `swift test` still passes all 18 tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 16:02:23 +02:00
krissandClaude Sonnet 5 1f7ee90882 feat: add SearchView
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 16:00:53 +02:00
krissandClaude Sonnet 5 a48e8baf7a feat: add EntryEditView for add/edit entries
Also fixes real bugs found while making Phase 4 build clean on both
platforms:
- FileBookmarkService used .withSecurityScope unconditionally, but
  that bookmark option is macOS-only -- iOS grants scoped access
  automatically once the user picks a file. Now conditional per platform.
- EntryEditViewModel's groupId was non-optional with no default, but
  EntryDetailView's edit-sheet call site (Task 14) has no group
  reference to pass -- only the "add new entry" path actually needs
  it, so groupId is now optional and validated at save time instead.
- Missing `import Combine` in EntryDetailView (Timer.publish/autoconnect)
  and UnlockViewModel/VaultViewModel/EntryEditViewModel (@Published).
- GroupBrowserView's `group: Group` property collided with SwiftUI's
  own Group view type -- qualified as MyPassCore.Group.
- EntryEditView's .keyboardType(.URL) and .navigationBarTitleDisplayMode
  are iOS-only APIs, guarded with #if os(iOS) for the macOS build.

Verified clean (aside from the known, expected ContentView.swift/Item
breakage) on both iOS Simulator and macOS destinations.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 16:00:37 +02:00
krissandClaude Sonnet 5 347f9a99c4 feat: add EntryDetailView with TOTP countdown
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 15:59:07 +02:00
krissandClaude Sonnet 5 66a01b3c80 feat: add GroupBrowserView with search and group navigation
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 15:58:41 +02:00
krissandClaude Sonnet 5 543a063528 feat: add UnlockView with biometric and password unlock
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 15:58:15 +02:00
krissandClaude Sonnet 5 ef52cb9804 feat: add FileBookmarkService, BiometricAuthService, ClipboardService
Phase 3 (Tasks 10-11) app services: FileBookmarkService persists a
security-scoped bookmark for the KDBX file in the shared App Group;
BiometricAuthService wraps LAContext for Face ID/Touch ID; ClipboardService
copies text with an expiring clipboard entry on iOS/macOS.

Also fixes a real build issue found while verifying: the AutoFill
extension (iOS-only) was being embedded/signed unconditionally,
breaking macOS builds of the MyPass scheme with a bogus provisioning
error. Added platformFilters = (ios) to both the embed build file and
the target dependency so macOS builds skip it. Verified both iOS
Simulator and macOS builds now fail only on the known, expected
ContentView.swift/Item SwiftData breakage.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 15:52:16 +02:00
krissandClaude Sonnet 5 6279488416 chore: wire up AutoFill extension target and rebrand bundle prefix
Adds the AutoFill Credential Provider Extension target (App Group +
Keychain Sharing capabilities, autofill-credential-provider
entitlement), removes the leftover SwiftData bootstrap from
MyPassApp.swift now that Item.swift is gone, and switches the bundle
ID / App Group / Keychain group prefix from com.christophevila to
org.antiloop222 to match the project's existing identifier.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WYqycDFsynHH9VnnK7LNSf
2026-09-19 15:33:23 +02:00
krissandClaude Sonnet 4.6 32c37c6f30 feat: scaffold MyPassCore Swift Package
- Add MyPassCore local Swift Package with directory structure for
  Models, KDBX, TOTP, Keychain, AutoFill, and Session modules
- Add KeePassKit as git submodule (Vendor/KeePassKit) with SPM wrapper
  Package.swift since upstream has no native SPM support
- Delete SwiftData boilerplate Item.swift from main app target

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-22 12:19:36 +02:00
kriss 2c4138ddb3 Initial Commit 2026-05-21 22:04:13 +02:00