Skip to content

Commit

Permalink
Autofill change to sorting algorithm for displaying logins (duckduckg…
Browse files Browse the repository at this point in the history
…o#1513)

Task/Issue URL: https://app.asana.com/0/0/1203927830097167/f
Tech Design URL:
CC: @THISISDINOSAUR

Description:
Changes to Autofill logins management screen taking subdomains and ports into account
  • Loading branch information
amddg44 authored Mar 30, 2023
1 parent 806518b commit d7769dd
Show file tree
Hide file tree
Showing 46 changed files with 884 additions and 185 deletions.
18 changes: 17 additions & 1 deletion DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,8 @@
C1B7B52D2894469D0098FD6A /* DefaultVariantManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B7B52C2894469D0098FD6A /* DefaultVariantManager.swift */; };
C1B7B53028944E390098FD6A /* RemoteMessagingStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B7B52F28944E390098FD6A /* RemoteMessagingStoreTests.swift */; };
C1B7B53428944EFA0098FD6A /* CoreDataTestUtilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1B7B53328944EFA0098FD6A /* CoreDataTestUtilities.swift */; };
C1BF0BA529B63D7200482B73 /* AutofillLoginPromptHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1BF0BA429B63D7200482B73 /* AutofillLoginPromptHelper.swift */; };
C1BF0BA929B63E2200482B73 /* AutofillLoginPromptViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1BF0BA729B63E1A00482B73 /* AutofillLoginPromptViewModelTests.swift */; };
C1CCCBA7283E101500CF3791 /* FaviconsHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1CCCBA6283E101500CF3791 /* FaviconsHelper.swift */; };
C1D21E2D293A5965006E5A05 /* AutofillLoginSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1D21E2C293A5965006E5A05 /* AutofillLoginSession.swift */; };
C1D21E2F293A599C006E5A05 /* AutofillLoginSessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1D21E2E293A599C006E5A05 /* AutofillLoginSessionTests.swift */; };
Expand Down Expand Up @@ -1996,6 +1998,8 @@
C1B7B52C2894469D0098FD6A /* DefaultVariantManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultVariantManager.swift; sourceTree = "<group>"; };
C1B7B52F28944E390098FD6A /* RemoteMessagingStoreTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteMessagingStoreTests.swift; sourceTree = "<group>"; };
C1B7B53328944EFA0098FD6A /* CoreDataTestUtilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CoreDataTestUtilities.swift; sourceTree = "<group>"; };
C1BF0BA429B63D7200482B73 /* AutofillLoginPromptHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillLoginPromptHelper.swift; sourceTree = "<group>"; };
C1BF0BA729B63E1A00482B73 /* AutofillLoginPromptViewModelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutofillLoginPromptViewModelTests.swift; sourceTree = "<group>"; };
C1CCCBA6283E101500CF3791 /* FaviconsHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FaviconsHelper.swift; sourceTree = "<group>"; };
C1D21E2C293A5965006E5A05 /* AutofillLoginSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillLoginSession.swift; sourceTree = "<group>"; };
C1D21E2E293A599C006E5A05 /* AutofillLoginSessionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillLoginSessionTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3546,6 +3550,14 @@
name = RemoteMessaging;
sourceTree = "<group>";
};
C1BF0BA629B63E0400482B73 /* AutofillLoginUI */ = {
isa = PBXGroup;
children = (
C1BF0BA729B63E1A00482B73 /* AutofillLoginPromptViewModelTests.swift */,
);
name = AutofillLoginUI;
sourceTree = "<group>";
};
CB1AEFB6279AF6420031AE3D /* WidgetEducation */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -4305,6 +4317,7 @@
F407605328131910006B1E0B /* AutofillLoginUI */ = {
isa = PBXGroup;
children = (
C1BF0BA429B63D7200482B73 /* AutofillLoginPromptHelper.swift */,
F44D279727F331BB0037F371 /* AutofillLoginPromptView.swift */,
F44D279A27F331BB0037F371 /* AutofillLoginPromptViewController.swift */,
F44D279927F331BB0037F371 /* AutofillLoginPromptViewModel.swift */,
Expand All @@ -4326,6 +4339,7 @@
F40F843228C92B1C0081AE75 /* Autofill */ = {
isa = PBXGroup;
children = (
C1BF0BA629B63E0400482B73 /* AutofillLoginUI */,
F40F843528C938370081AE75 /* AutofillLoginListViewModelTests.swift */,
C1D21E2E293A599C006E5A05 /* AutofillLoginSessionTests.swift */,
);
Expand Down Expand Up @@ -5176,6 +5190,7 @@
4B6484F027FD1E350050A7A1 /* FontExtension.swift in Sources */,
F4F6DFB226E6AEC100ED7E12 /* AddOrEditBookmarkViewController.swift in Sources */,
F44D279F27F331BB0037F371 /* AutofillLoginPromptViewController.swift in Sources */,
C1BF0BA529B63D7200482B73 /* AutofillLoginPromptHelper.swift in Sources */,
F1F5337C1F26A9EF00D80D4F /* UserText.swift in Sources */,
1E8AD1C727BE9B2900ABA377 /* DownloadsListDataSource.swift in Sources */,
3157B43527F497F50042D3D7 /* SaveLoginViewController.swift in Sources */,
Expand Down Expand Up @@ -5531,6 +5546,7 @@
85010504292FFB080033978F /* BookmarkFaviconUpdaterTests.swift in Sources */,
F1D477C91F2139410031ED49 /* SmallOmniBarStateTests.swift in Sources */,
987130C9294AAB9F00AB05E0 /* BookmarkUtilsTests.swift in Sources */,
C1BF0BA929B63E2200482B73 /* AutofillLoginPromptViewModelTests.swift in Sources */,
987130C8294AAB9F00AB05E0 /* BookmarksTestHelpers.swift in Sources */,
F198D7981E3A45D90088DA8A /* WKWebViewConfigurationExtensionTests.swift in Sources */,
8521FDE6238D414B00A44CC3 /* FileStoreTests.swift in Sources */,
Expand Down Expand Up @@ -7414,7 +7430,7 @@
repositoryURL = "https://github.com/DuckDuckGo/BrowserServicesKit";
requirement = {
kind = exactVersion;
version = 53.0.0;
version = 53.1.0;
};
};
C14882EB27F211A000D59F0C /* XCRemoteSwiftPackageReference "SwiftSoup" */ = {
Expand Down
2 changes: 1 addition & 1 deletion DuckDuckGo/AutofillListItemTableViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ class AutofillListItemTableViewCell: UITableViewCell {
private func setupContentView(with item: AutofillLoginListItemViewModel) {
titleLabel.text = item.title
subtitleLabel.text = item.subtitle
iconImageView.loadFavicon(forDomain: item.account.domain, usingCache: .tabs)
iconImageView.loadFavicon(forDomain: item.account.domain, usingCache: .tabs, preferredFakeFaviconLetter: item.preferredFaviconLetter)
}

override func layoutSubviews() {
Expand Down
3 changes: 2 additions & 1 deletion DuckDuckGo/AutofillLoginDetailsHeaderView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ struct AutofillLoginDetailsHeaderView: View {

var body: some View {
HStack(spacing: Constants.horizontalStackSpacing) {
FaviconView(viewModel: FaviconViewModel(domain: viewModel.domain))
FaviconView(viewModel: FaviconViewModel(domain: viewModel.domain,
preferredFakeFaviconLetter: viewModel.preferredFakeFaviconLetter))
.scaledToFit()
.frame(width: Constants.imageSize, height: Constants.imageSize)
.accessibilityHidden(true)
Expand Down
6 changes: 3 additions & 3 deletions DuckDuckGo/AutofillLoginDetailsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import Combine

protocol AutofillLoginDetailsViewControllerDelegate: AnyObject {
func autofillLoginDetailsViewControllerDidSave(_ controller: AutofillLoginDetailsViewController, account: SecureVaultModels.WebsiteAccount?)
func autofillLoginDetailsViewControllerDelete(account: SecureVaultModels.WebsiteAccount)
func autofillLoginDetailsViewControllerDelete(account: SecureVaultModels.WebsiteAccount, title: String)
}

class AutofillLoginDetailsViewController: UIViewController {
Expand Down Expand Up @@ -309,8 +309,8 @@ extension AutofillLoginDetailsViewController: AutofillLoginDetailsViewModelDeleg
present(alert, animated: true)
}

func autofillLoginDetailsViewModelDelete(account: SecureVaultModels.WebsiteAccount) {
delegate?.autofillLoginDetailsViewControllerDelete(account: account)
func autofillLoginDetailsViewModelDelete(account: SecureVaultModels.WebsiteAccount, title: String) {
delegate?.autofillLoginDetailsViewControllerDelete(account: account, title: title)
navigationController?.popViewController(animated: true)
}

Expand Down
26 changes: 17 additions & 9 deletions DuckDuckGo/AutofillLoginDetailsViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import Core
protocol AutofillLoginDetailsViewModelDelegate: AnyObject {
func autofillLoginDetailsViewModelDidSave()
func autofillLoginDetailsViewModelDidAttemptToSaveDuplicateLogin()
func autofillLoginDetailsViewModelDelete(account: SecureVaultModels.WebsiteAccount)
func autofillLoginDetailsViewModelDelete(account: SecureVaultModels.WebsiteAccount, title: String)
func autofillLoginDetailsViewModelDismiss()
}

Expand All @@ -47,6 +47,8 @@ final class AutofillLoginDetailsViewModel: ObservableObject {
weak var delegate: AutofillLoginDetailsViewModelDelegate?
var account: SecureVaultModels.WebsiteAccount?
private let tld: TLD
private let autofillDomainNameUrlMatcher = AutofillDomainNameUrlMatcher()
private let autofillDomainNameUrlSort = AutofillDomainNameUrlSort()

@ObservedObject var headerViewModel: AutofillLoginDetailsHeaderViewModel
@Published var isPasswordHidden = true
Expand Down Expand Up @@ -76,7 +78,7 @@ final class AutofillLoginDetailsViewModel: ObservableObject {
case .edit:
return UserText.autofillLoginDetailsEditTitle
case .view:
return title
return title.isEmpty ? address : title
case .new:
return UserText.autofillLoginDetailsNewTitle
}
Expand Down Expand Up @@ -117,9 +119,12 @@ final class AutofillLoginDetailsViewModel: ObservableObject {
self.account = account
username = account.username
address = account.domain
title = account.name(tld: tld)
title = account.title ?? ""
notes = account.notes ?? ""
headerViewModel.updateData(with: account, tld: tld)
headerViewModel.updateData(with: account,
tld: tld,
autofillDomainNameUrlMatcher: autofillDomainNameUrlMatcher,
autofillDomainNameUrlSort: autofillDomainNameUrlSort)
setupPassword(with: account)
}

Expand Down Expand Up @@ -197,7 +202,7 @@ final class AutofillLoginDetailsViewModel: ObservableObject {
var credential = try vault.websiteCredentialsFor(accountId: accountIdInt) {
credential.account.username = username
credential.account.title = title
credential.account.domain = address
credential.account.domain = autofillDomainNameUrlMatcher.normalizeUrlForWeb(address)
credential.account.notes = notes
credential.password = passwordData

Expand All @@ -216,7 +221,8 @@ final class AutofillLoginDetailsViewModel: ObservableObject {
case .view:
break
case .new:
let account = SecureVaultModels.WebsiteAccount(title: title, username: username, domain: address, notes: notes)
let cleanAddress = autofillDomainNameUrlMatcher.normalizeUrlForWeb(address)
let account = SecureVaultModels.WebsiteAccount(title: title, username: username, domain: cleanAddress, notes: notes)
let credentials = SecureVaultModels.WebsiteCredentials(account: account, password: passwordData)

do {
Expand Down Expand Up @@ -246,7 +252,7 @@ final class AutofillLoginDetailsViewModel: ObservableObject {
assertionFailure("Trying to delete account, but the account doesn't exist")
return
}
delegate?.autofillLoginDetailsViewModelDelete(account: account)
delegate?.autofillLoginDetailsViewModelDelete(account: account, title: headerViewModel.title)
}

func openUrl() {
Expand All @@ -269,11 +275,13 @@ final class AutofillLoginDetailsHeaderViewModel: ObservableObject {
@Published var title: String = ""
@Published var subtitle: String = ""
@Published var domain: String = ""
@Published var preferredFakeFaviconLetter: String?

func updateData(with account: SecureVaultModels.WebsiteAccount, tld: TLD) {
self.title = account.name(tld: tld)
func updateData(with account: SecureVaultModels.WebsiteAccount, tld: TLD, autofillDomainNameUrlMatcher: AutofillDomainNameUrlMatcher, autofillDomainNameUrlSort: AutofillDomainNameUrlSort) {
self.title = account.name(tld: tld, autofillDomainNameUrlMatcher: autofillDomainNameUrlMatcher)
self.subtitle = UserText.autofillLoginDetailsLastUpdated(for: (dateFormatter.string(from: account.lastUpdated)))
self.domain = account.domain
self.preferredFakeFaviconLetter = account.faviconLetter(tld: tld, autofillDomainNameUrlSort: autofillDomainNameUrlSort)
}

}
16 changes: 12 additions & 4 deletions DuckDuckGo/AutofillLoginListItemViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,28 @@ final class AutofillLoginListItemViewModel: Identifiable, Hashable {
let account: SecureVaultModels.WebsiteAccount
let title: String
let subtitle: String
let preferredFaviconLetter: String?
let id = UUID()
let tld: TLD

internal init(account: SecureVaultModels.WebsiteAccount, tld: TLD) {
internal init(account: SecureVaultModels.WebsiteAccount,
tld: TLD,
autofillDomainNameUrlMatcher: AutofillDomainNameUrlMatcher,
autofillDomainNameUrlSort: AutofillDomainNameUrlSort) {
self.account = account
self.title = account.name(tld: tld)
self.tld = tld
self.title = account.name(tld: tld, autofillDomainNameUrlMatcher: autofillDomainNameUrlMatcher)
self.subtitle = account.username

self.preferredFaviconLetter = account.faviconLetter(tld: tld, autofillDomainNameUrlSort: autofillDomainNameUrlSort)

fetchImage()
}

private func fetchImage() {
FaviconsHelper.loadFaviconSync(forDomain: account.domain,
usingCache: .tabs,
useFakeFavicon: true) { image, _ in
useFakeFavicon: true,
preferredFakeFaviconLetter: preferredFaviconLetter) { image, _ in
if let image = image {
self.image = image
} else {
Expand Down
Loading

0 comments on commit d7769dd

Please sign in to comment.