diff --git a/apps/mobile-app/ios/Autofill/CredentialProviderViewController+Passkey.swift b/apps/mobile-app/ios/Autofill/CredentialProviderViewController+Passkey.swift index 6c8730c15..904f99bfe 100644 --- a/apps/mobile-app/ios/Autofill/CredentialProviderViewController+Passkey.swift +++ b/apps/mobile-app/ios/Autofill/CredentialProviderViewController+Passkey.swift @@ -370,10 +370,11 @@ extension CredentialProviderViewController: PasskeyProviderDelegate { try vaultStore.beginTransaction() // Store credential with passkey and logo in database + // Use viewModel.displayName as the title (Service.name) _ = try vaultStore.createCredentialWithPasskey( rpId: rpId, userName: userName, - userDisplayName: userDisplayName, + displayName: viewModel.displayName, passkey: passkey, logo: logo ) diff --git a/apps/mobile-app/ios/VaultStoreKit/VaultStore+Passkey.swift b/apps/mobile-app/ios/VaultStoreKit/VaultStore+Passkey.swift index adef1a2cc..f47785e1e 100644 --- a/apps/mobile-app/ios/VaultStoreKit/VaultStore+Passkey.swift +++ b/apps/mobile-app/ios/VaultStoreKit/VaultStore+Passkey.swift @@ -391,7 +391,7 @@ extension VaultStore { public func createCredentialWithPasskey( rpId: String, userName: String?, - userDisplayName: String?, + displayName: String, passkey: Passkey, logo: Data? = nil ) throws -> Credential { @@ -414,7 +414,7 @@ extension VaultStore { let serviceInsert = serviceTable.insert( Expression("Id") <- serviceId.uuidString, - Expression("Name") <- rpId, + Expression("Name") <- displayName, // Use displayName as the service name (title) Expression("Url") <- "https://\(rpId)", Expression("Logo") <- logoBlob, Expression("CreatedAt") <- timestamp, @@ -430,7 +430,7 @@ extension VaultStore { Expression("ServiceId") <- serviceId.uuidString, Expression("AliasId") <- nil, Expression("Username") <- userName, - Expression("Notes") <- "Passkey for \(rpId)", + Expression("Notes") <- nil, Expression("CreatedAt") <- timestamp, Expression("UpdatedAt") <- timestamp, Expression("IsDeleted") <- 0 diff --git a/apps/mobile-app/ios/VaultUI/Views/PasskeyRegistrationView.swift b/apps/mobile-app/ios/VaultUI/Views/PasskeyRegistrationView.swift index 07afa4de5..126515b5a 100644 --- a/apps/mobile-app/ios/VaultUI/Views/PasskeyRegistrationView.swift +++ b/apps/mobile-app/ios/VaultUI/Views/PasskeyRegistrationView.swift @@ -8,6 +8,7 @@ public struct PasskeyRegistrationView: View { @ObservedObject public var viewModel: PasskeyRegistrationViewModel @Environment(\.colorScheme) private var colorScheme + @FocusState private var isTitleFocused: Bool public init(viewModel: PasskeyRegistrationViewModel) { self._viewModel = ObservedObject(wrappedValue: viewModel) @@ -43,16 +44,37 @@ public struct PasskeyRegistrationView: View { } .padding(.bottom, 20) - // Request details - VStack(spacing: 16) { - InfoRow( + // Editable title field + VStack(alignment: .leading, spacing: 8) { + Text(String(localized: "title", bundle: locBundle)) + .font(.caption) + .foregroundColor(colorScheme == .dark ? ColorConstants.Dark.textMuted : ColorConstants.Light.textMuted) + .padding(.horizontal) + + TextField("", text: $viewModel.displayName) + .textFieldStyle(PlainTextFieldStyle()) + .font(.body) + .foregroundColor(colorScheme == .dark ? ColorConstants.Dark.text : ColorConstants.Light.text) + .padding() + .background( + (colorScheme == .dark ? ColorConstants.Dark.accentBackground : ColorConstants.Light.accentBackground) + ) + .cornerRadius(8) + .padding(.horizontal) + .focused($isTitleFocused) + } + .padding(.bottom, 8) + + // Request details (compact, read-only) + VStack(spacing: 8) { + CompactInfoRow( label: String(localized: "website", bundle: locBundle), value: viewModel.rpId, icon: "globe" ) if let userName = viewModel.userName { - InfoRow( + CompactInfoRow( label: String(localized: "username", bundle: locBundle), value: userName, icon: "person.fill" @@ -101,6 +123,10 @@ public struct PasskeyRegistrationView: View { } } .navigationBarHidden(true) + .onAppear { + // Auto-focus the title field + isTitleFocused = true + } } } } @@ -191,8 +217,8 @@ private struct LoadingOverlayView: View { } } -/// Info row component for displaying passkey registration details -private struct InfoRow: View { +/// Compact info row component for displaying read-only passkey details +private struct CompactInfoRow: View { let label: String let value: String let icon: String @@ -200,28 +226,23 @@ private struct InfoRow: View { @Environment(\.colorScheme) private var colorScheme var body: some View { - HStack(alignment: .top, spacing: 12) { + HStack(spacing: 8) { Image(systemName: icon) .foregroundColor(ColorConstants.Light.primary) .frame(width: 24) - VStack(alignment: .leading, spacing: 4) { - Text(label) - .font(.caption) - .foregroundColor(colorScheme == .dark ? ColorConstants.Dark.textMuted : ColorConstants.Light.textMuted) + Text(label + ":") + .font(.subheadline) + .foregroundColor(colorScheme == .dark ? ColorConstants.Dark.textMuted : ColorConstants.Light.textMuted) - Text(value) - .font(.body) - .foregroundColor(colorScheme == .dark ? ColorConstants.Dark.text : ColorConstants.Light.text) - } + Text(value) + .font(.subheadline) + .foregroundColor(colorScheme == .dark ? ColorConstants.Dark.text : ColorConstants.Light.text) Spacer() } - .padding() - .background( - (colorScheme == .dark ? ColorConstants.Dark.accentBackground : ColorConstants.Light.accentBackground) - ) - .cornerRadius(8) + .padding(.vertical, 4) + .padding(.horizontal, 8) } } @@ -232,6 +253,7 @@ public class PasskeyRegistrationViewModel: ObservableObject { @Published public var origin: String @Published public var userName: String? @Published public var userDisplayName: String? + @Published public var displayName: String // Editable title that defaults to rpId @Published public var isLoading: Bool = false @Published public var loadingMessage: String = "" @@ -252,6 +274,8 @@ public class PasskeyRegistrationViewModel: ObservableObject { self.origin = origin self.userName = userName self.userDisplayName = userDisplayName + // Initialize displayName to rpId by default + self.displayName = rpId self.completionHandler = completionHandler self.cancelHandler = cancelHandler } diff --git a/apps/mobile-app/ios/VaultUI/en.lproj/Localizable.strings b/apps/mobile-app/ios/VaultUI/en.lproj/Localizable.strings index 90285ab66..2a23e9d10 100644 Binary files a/apps/mobile-app/ios/VaultUI/en.lproj/Localizable.strings and b/apps/mobile-app/ios/VaultUI/en.lproj/Localizable.strings differ