diff --git a/passAutoFillExtension/Base.lproj/MainInterface.storyboard b/passAutoFillExtension/Base.lproj/MainInterface.storyboard index f5650b6..9ea07a3 100644 --- a/passAutoFillExtension/Base.lproj/MainInterface.storyboard +++ b/passAutoFillExtension/Base.lproj/MainInterface.storyboard @@ -17,13 +17,13 @@ - + - + - + diff --git a/passAutoFillExtension/Controllers/CredentialProviderViewController.swift b/passAutoFillExtension/Controllers/CredentialProviderViewController.swift index 25dad0d..e8e85a3 100644 --- a/passAutoFillExtension/Controllers/CredentialProviderViewController.swift +++ b/passAutoFillExtension/Controllers/CredentialProviderViewController.swift @@ -35,6 +35,8 @@ class CredentialProviderViewController: ASCredentialProviderViewController { override func prepareCredentialList(for serviceIdentifiers: [ASCredentialServiceIdentifier]) { let url = serviceIdentifiers.first.flatMap { URL(string: $0.identifier) } passwordsViewController.navigationItem.prompt = url?.host + let keywords = url?.host?.sanitizedDomain?.components(separatedBy: ".") ?? [] + passwordsViewController.showPasswordsWithSuggstion(keywords) } } @@ -50,3 +52,14 @@ extension CredentialProviderViewController: PasswordSelectionDelegate { } } } + +private extension String { + var sanitizedDomain: String? { + replacingOccurrences(of: ".com", with: "") + .replacingOccurrences(of: ".org", with: "") + .replacingOccurrences(of: ".edu", with: "") + .replacingOccurrences(of: ".net", with: "") + .replacingOccurrences(of: ".gov", with: "") + .replacingOccurrences(of: "www.", with: "") + } +} diff --git a/passAutoFillExtension/Controllers/PasswordsViewController.swift b/passAutoFillExtension/Controllers/PasswordsViewController.swift index 8d58212..6e17b42 100644 --- a/passAutoFillExtension/Controllers/PasswordsViewController.swift +++ b/passAutoFillExtension/Controllers/PasswordsViewController.swift @@ -27,18 +27,27 @@ class PasswordsViewController: UIViewController { return uiSearchController }() + lazy var searchBar: UISearchBar = { + self.searchController.searchBar + }() + override func viewDidLoad() { super.viewDidLoad() navigationItem.searchController = searchController navigationItem.hidesSearchBarWhenScrolling = false - searchController.searchBar.delegate = self + searchBar.delegate = self tableView.delegate = self tableView.dataSource = dataSource } + func showPasswordsWithSuggstion(_ keywords: [String]) { + dataSource.showTableEntriesWithSuggestion(matching: keywords) + tableView.reloadData() + } + @IBAction private func cancel(_: AnyObject?) { self.extensionContext?.cancelRequest(withError: NSError(domain: ASExtensionErrorDomain, code: ASExtensionError.userCanceled.rawValue)) diff --git a/passAutoFillExtension/Services/PasswordsTableDataSource.swift b/passAutoFillExtension/Services/PasswordsTableDataSource.swift index d680967..95851e2 100644 --- a/passAutoFillExtension/Services/PasswordsTableDataSource.swift +++ b/passAutoFillExtension/Services/PasswordsTableDataSource.swift @@ -12,20 +12,69 @@ import passKit class PasswordsTableDataSource: NSObject, UITableViewDataSource { var passwordTableEntries: [PasswordTableEntry] var filteredPasswordsTableEntries: [PasswordTableEntry] + var suggestedPasswordsTableEntries: [PasswordTableEntry] + var otherPasswordsTableEntries: [PasswordTableEntry] + + var showSuggestion: Bool = false init(entries: [PasswordTableEntry] = []) { passwordTableEntries = entries filteredPasswordsTableEntries = passwordTableEntries + suggestedPasswordsTableEntries = [] + otherPasswordsTableEntries = [] + } + + func numberOfSections(in tableView: UITableView) -> Int { + if !showSuggestion { + return 1 + } else { + return 2 + } } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - filteredPasswordsTableEntries.count + if !showSuggestion { + return filteredPasswordsTableEntries.count + } + + if section == 0 { + return suggestedPasswordsTableEntries.count + } else { + return otherPasswordsTableEntries.count + } + } + + func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + if suggestedPasswordsTableEntries.isEmpty { + return nil + } + + if !showSuggestion { + return "All Passwords" + } + + if section == 0 { + return "Suggested Passwords" + } else { + return "Other Passwords" + } } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "passwordTableViewCell", for: indexPath) as! PasswordTableViewCell - let entry = filteredPasswordsTableEntries[indexPath.row] + var entry: PasswordTableEntry! + if !showSuggestion { + entry = filteredPasswordsTableEntries[indexPath.row] + cell.configure(with: entry) + return cell + } + + if indexPath.section == 0 { + entry = suggestedPasswordsTableEntries[indexPath.row] + } else { + entry = otherPasswordsTableEntries[indexPath.row] + } cell.configure(with: entry) return cell @@ -34,9 +83,26 @@ class PasswordsTableDataSource: NSObject, UITableViewDataSource { func showTableEntries(matching text: String) { guard !text.isEmpty else { filteredPasswordsTableEntries = passwordTableEntries + showSuggestion = true return } filteredPasswordsTableEntries = passwordTableEntries.filter { $0.match(text) } + showSuggestion = false + } + + func showTableEntriesWithSuggestion(matching keywords: [String]) { + for entry in passwordTableEntries { + var match = false + for keyword in keywords { + match = match || entry.match(keyword) + } + if match { + suggestedPasswordsTableEntries.append(entry) + } else { + otherPasswordsTableEntries.append(entry) + } + } + showSuggestion = !suggestedPasswordsTableEntries.isEmpty } }