- Custom copper AccentColor and warm VaultBackground color assets (light/dark), applied to both the main app and the AutoFill extension (which needed its own copy of the asset catalog plus ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME and an explicit .tint() modifier, since extensions don't pick up the app-wide accent color the same way a full SwiftUI App/Scene does). - GroupFilterView no longer uses DisclosureGroup for subgroups -- the whole tree renders always-expanded (indented per depth) so active filters are visible at a glance instead of requiring tap-to-expand. - Added a placeholder app icon (padlock glyph, light/dark/tinted variants plus macOS sizes) -- previously the icon slot existed but had no actual images, which blocks App Store/TestFlight archive validation. - Added ITSAppUsesNonExemptEncryption = NO (standard encryption only, via KeePassKit) to skip the export-compliance prompt on each upload. - Renamed the app from MyPass to KeeVault throughout: Xcode project/targets/ schemes, the MyPassCore package (now KeeVaultCore) and every import site, folder and file names, bundle identifiers (org.antiloop222.keevault) and their App Group/Keychain-group entitlements, and remaining UI/string references -- MyPass was already taken as an App Store app name.
84 lines
2.8 KiB
Swift
84 lines
2.8 KiB
Swift
// KeeVault/ViewModels/EntryEditViewModel.swift
|
|
import Foundation
|
|
import Combine
|
|
import SwiftUI
|
|
import KeeVaultCore
|
|
|
|
@MainActor
|
|
final class EntryEditViewModel: ObservableObject {
|
|
@Published var title: String
|
|
@Published var username: String
|
|
@Published var password: String
|
|
@Published var url: String
|
|
@Published var notes: String
|
|
@Published var customFields: [CustomField]
|
|
@Published var groupId: UUID
|
|
@Published var errorMessage: String?
|
|
@Published var isSaving: Bool = false
|
|
|
|
let session: VaultSession
|
|
private let existingEntry: Entry?
|
|
|
|
/// `groupId` is the target group for a new entry, or the entry's current group when
|
|
/// editing (shown read-only in that case -- KeeVault doesn't support re-parenting an
|
|
/// existing entry to a different group yet).
|
|
init(session: VaultSession, groupId: UUID, existing: Entry? = nil) {
|
|
self.session = session
|
|
self.groupId = groupId
|
|
self.existingEntry = existing
|
|
title = existing?.title ?? ""
|
|
username = existing?.username ?? ""
|
|
password = existing?.password.reveal() ?? ""
|
|
url = existing?.url ?? ""
|
|
notes = existing?.notes ?? ""
|
|
customFields = existing?.customFields ?? []
|
|
}
|
|
|
|
var isEditing: Bool { existingEntry != nil }
|
|
|
|
var flatGroups: [FlatGroup] {
|
|
guard let root = session.database?.root else { return [] }
|
|
return flattenGroups(in: root)
|
|
}
|
|
|
|
func save(dismiss: @escaping () -> Void) {
|
|
Task {
|
|
isSaving = true
|
|
errorMessage = nil
|
|
do {
|
|
if var entry = existingEntry {
|
|
entry.title = title
|
|
entry.username = username
|
|
entry.password = ProtectedString(password, isProtected: true)
|
|
entry.url = url
|
|
entry.notes = notes
|
|
entry.customFields = customFields
|
|
try session.updateEntry(entry)
|
|
} else {
|
|
let entry = Entry(
|
|
title: title,
|
|
username: username,
|
|
password: ProtectedString(password, isProtected: true),
|
|
url: url,
|
|
notes: notes,
|
|
customFields: customFields
|
|
)
|
|
try session.addEntry(entry, toGroupId: groupId)
|
|
}
|
|
dismiss()
|
|
} catch {
|
|
errorMessage = error.localizedDescription
|
|
}
|
|
isSaving = false
|
|
}
|
|
}
|
|
|
|
func addCustomField() {
|
|
customFields.append(CustomField(key: "", value: ProtectedString("", isProtected: false)))
|
|
}
|
|
|
|
func removeCustomField(at offsets: IndexSet) {
|
|
customFields.remove(atOffsets: offsets)
|
|
}
|
|
}
|