diff --git a/AutoFill/Views/CredentialListView.swift b/AutoFill/Views/CredentialListView.swift new file mode 100644 index 0000000..afbb24d --- /dev/null +++ b/AutoFill/Views/CredentialListView.swift @@ -0,0 +1,62 @@ +// AutoFill/Views/CredentialListView.swift +import SwiftUI +import MyPassCore + +struct CredentialListView: View { + @ObservedObject var vm: ExtensionViewModel + @State private var searchQuery: String = "" + + private var displayedSuggested: [Entry] { + searchQuery.isEmpty ? vm.suggestedEntries : [] + } + + private var displayedAll: [Entry] { + let entries = searchQuery.isEmpty ? vm.allEntries : vm.session.allEntries() + guard !searchQuery.isEmpty else { return entries } + let q = searchQuery.lowercased() + return entries.filter { + $0.title.lowercased().contains(q) + || $0.username.lowercased().contains(q) + || $0.url.lowercased().contains(q) + } + } + + var body: some View { + List { + if !displayedSuggested.isEmpty { + Section("Suggested") { + ForEach(displayedSuggested) { entry in + CredentialRow(entry: entry) { vm.select(entry) } + } + } + } + Section(displayedSuggested.isEmpty ? "" : "All Entries") { + if displayedAll.isEmpty { + Text("No entries found").foregroundStyle(.secondary) + } else { + ForEach(displayedAll) { entry in + CredentialRow(entry: entry) { vm.select(entry) } + } + } + } + } + .searchable(text: $searchQuery, prompt: "Search…") + } +} + +private struct CredentialRow: View { + let entry: Entry + let onSelect: () -> Void + + var body: some View { + Button(action: onSelect) { + VStack(alignment: .leading, spacing: 2) { + Text(entry.title).font(.body).foregroundStyle(.primary) + Text(entry.username).font(.caption).foregroundStyle(.secondary) + if !entry.url.isEmpty { + Text(entry.url).font(.caption2).foregroundStyle(.tertiary) + } + } + } + } +}