Skip to content

Commit

Permalink
Autofill Settings - Import passwords via sync (#2756)
Browse files Browse the repository at this point in the history
Task/Issue URL: https://app.asana.com/0/72649045549333/1206531758082871/f
Tech Design URL:
CC:

Description:
Gives users a path to import passwords via importing on desktop and enabling sync
  • Loading branch information
amddg44 committed Apr 29, 2024
1 parent 612de01 commit a845df9
Show file tree
Hide file tree
Showing 56 changed files with 3,143 additions and 285 deletions.
4 changes: 4 additions & 0 deletions Core/DateExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ extension Date {
guard let otherDate = otherDate else { return false }
return Calendar.current.isDate(self, inSameDayAs: otherDate)
}

public func isLessThan48HoursAgo() -> Bool {
self > Date().addingTimeInterval(-48 * 60 * 60)
}
}
22 changes: 22 additions & 0 deletions Core/PixelEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,17 @@ extension Pixel {
case autofillLoginsLaunchWidgetLock
case autofillLoginsLaunchAppShortcut

case autofillLoginsImport
case autofillLoginsImportNoPasswords
case autofillLoginsImportGetDesktop
case autofillLoginsImportSync
case autofillLoginsImportNoAction
case autofillLoginsImportSuccess
case autofillLoginsImportFailure

case getDesktopCopy
case getDesktopShare

case autofillJSPixelFired(_ pixel: AutofillUserScript.JSPixel)

case secureVaultError
Expand Down Expand Up @@ -904,6 +915,17 @@ extension Pixel.Event {
case .autofillLoginsLaunchWidgetLock: return "m_autofill_logins_launch_widget_lock"
case .autofillLoginsLaunchAppShortcut: return "m_autofill_logins_launch_app_shortcut"

case .autofillLoginsImport: return "m_autofill_logins_import"
case .autofillLoginsImportNoPasswords: return "m_autofill_logins_import_no_passwords"
case .autofillLoginsImportGetDesktop: return "m_autofill_logins_import_get_desktop"
case .autofillLoginsImportSync: return "m_autofill_logins_import_sync"
case .autofillLoginsImportNoAction: return "m_autofill_logins_import_no-action"
case .autofillLoginsImportSuccess: return "m_autofill_logins_import_success"
case .autofillLoginsImportFailure: return "m_autofill_logins_import_failure"

case .getDesktopCopy: return "m_get_desktop_copy"
case .getDesktopShare: return "m_get_desktop_share"

case .autofillJSPixelFired(let pixel):
return "m_ios_\(pixel.pixelName)"

Expand Down
1 change: 1 addition & 0 deletions Core/UserDefaultsPropertyWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public struct UserDefaultsWrapper<T> {
case autofillCredentialsSavePromptShowAtLeastOnce = "com.duckduckgo.ios.autofillCredentialsSavePromptShowAtLeastOnce"
case autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary =
"com.duckduckgo.ios.autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary"
case autofillImportViaSyncStart = "com.duckduckgo.ios.autofillImportViaSyncStart"

// .v2 suffix added to fix https://app.asana.com/0/547792610048271/1206524375402369/f
case featureFlaggingDidVerifyInternalUser = "com.duckduckgo.app.featureFlaggingDidVerifyInternalUser.v2"
Expand Down
44 changes: 40 additions & 4 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -664,9 +664,15 @@
C158AC7B297AB5DC0008723A /* MockSecureVault.swift in Sources */ = {isa = PBXBuildFile; fileRef = C158AC7A297AB5DC0008723A /* MockSecureVault.swift */; };
C159DF072A430B60007834BB /* EmailSignupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C159DF062A430B60007834BB /* EmailSignupViewController.swift */; };
C160544129D6044D00B715A1 /* AutofillInterfaceUsernameTruncator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C160544029D6044D00B715A1 /* AutofillInterfaceUsernameTruncator.swift */; };
C1641EAF2BC2F5140012607A /* ImportPasswordsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1641EAE2BC2F5140012607A /* ImportPasswordsViewController.swift */; };
C1641EB12BC2F52B0012607A /* ImportPasswordsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1641EB02BC2F52B0012607A /* ImportPasswordsView.swift */; };
C1641EB32BC2F53C0012607A /* ImportPasswordsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1641EB22BC2F53C0012607A /* ImportPasswordsViewModel.swift */; };
C174CE602BD6A6CE00AED2EA /* MockDDGSyncing.swift in Sources */ = {isa = PBXBuildFile; fileRef = C185ED652BD43A5500BAE9DC /* MockDDGSyncing.swift */; };
C17B59592A03AAD30055F2D1 /* PasswordGenerationPromptViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17B59562A03AAD30055F2D1 /* PasswordGenerationPromptViewModel.swift */; };
C17B595A2A03AAD30055F2D1 /* PasswordGenerationPromptViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17B59572A03AAD30055F2D1 /* PasswordGenerationPromptViewController.swift */; };
C17B595B2A03AAD30055F2D1 /* PasswordGenerationPromptView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C17B59582A03AAD30055F2D1 /* PasswordGenerationPromptView.swift */; };
C185ED612BD4329700BAE9DC /* ImportPasswordsStatusHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = C185ED602BD4329700BAE9DC /* ImportPasswordsStatusHandler.swift */; };
C185ED672BD43DA100BAE9DC /* ImportPasswordsStatusHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C185ED632BD438AF00BAE9DC /* ImportPasswordsStatusHandlerTests.swift */; };
C18ED43A2AB6F77600BF3805 /* AutofillSettingsEnableFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18ED4392AB6F77600BF3805 /* AutofillSettingsEnableFooterView.swift */; };
C18ED43C2AB8364400BF3805 /* FileTextPreviewDebugViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C18ED43B2AB8364400BF3805 /* FileTextPreviewDebugViewController.swift */; };
C1963863283794A000298D4D /* BookmarksCachingSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1963862283794A000298D4D /* BookmarksCachingSearch.swift */; };
Expand Down Expand Up @@ -760,7 +766,6 @@
D6D95CE32B6D9F8800960317 /* AsyncHeadlessWebViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6D95CE22B6D9F8800960317 /* AsyncHeadlessWebViewModel.swift */; };
D6E0C1832B7A2B1E00D5E1E9 /* DesktopDownloadView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E0C1822B7A2B1E00D5E1E9 /* DesktopDownloadView.swift */; };
D6E0C1852B7A2B9400D5E1E9 /* DesktopDownloadPlatformConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E0C1842B7A2B9400D5E1E9 /* DesktopDownloadPlatformConstants.swift */; };
D6E0C1872B7A2D0700D5E1E9 /* DesktopDownloadViewButtonStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E0C1862B7A2D0700D5E1E9 /* DesktopDownloadViewButtonStyle.swift */; };
D6E0C1892B7A2E0D00D5E1E9 /* DesktopDownloadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E0C1882B7A2E0D00D5E1E9 /* DesktopDownloadViewModel.swift */; };
D6E83C122B1E6AB3006C8AFB /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E83C112B1E6AB3006C8AFB /* SettingsView.swift */; };
D6E83C2E2B1EA06E006C8AFB /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E83C2D2B1EA06E006C8AFB /* SettingsViewModel.swift */; };
Expand Down Expand Up @@ -2267,9 +2272,15 @@
C158AC7A297AB5DC0008723A /* MockSecureVault.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockSecureVault.swift; sourceTree = "<group>"; };
C159DF062A430B60007834BB /* EmailSignupViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailSignupViewController.swift; sourceTree = "<group>"; };
C160544029D6044D00B715A1 /* AutofillInterfaceUsernameTruncator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillInterfaceUsernameTruncator.swift; sourceTree = "<group>"; };
C1641EAE2BC2F5140012607A /* ImportPasswordsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportPasswordsViewController.swift; sourceTree = "<group>"; };
C1641EB02BC2F52B0012607A /* ImportPasswordsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportPasswordsView.swift; sourceTree = "<group>"; };
C1641EB22BC2F53C0012607A /* ImportPasswordsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportPasswordsViewModel.swift; sourceTree = "<group>"; };
C17B59562A03AAD30055F2D1 /* PasswordGenerationPromptViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordGenerationPromptViewModel.swift; sourceTree = "<group>"; };
C17B59572A03AAD30055F2D1 /* PasswordGenerationPromptViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordGenerationPromptViewController.swift; sourceTree = "<group>"; };
C17B59582A03AAD30055F2D1 /* PasswordGenerationPromptView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordGenerationPromptView.swift; sourceTree = "<group>"; };
C185ED602BD4329700BAE9DC /* ImportPasswordsStatusHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportPasswordsStatusHandler.swift; sourceTree = "<group>"; };
C185ED632BD438AF00BAE9DC /* ImportPasswordsStatusHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportPasswordsStatusHandlerTests.swift; sourceTree = "<group>"; };
C185ED652BD43A5500BAE9DC /* MockDDGSyncing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDDGSyncing.swift; sourceTree = "<group>"; };
C18ED4392AB6F77600BF3805 /* AutofillSettingsEnableFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutofillSettingsEnableFooterView.swift; sourceTree = "<group>"; };
C18ED43B2AB8364400BF3805 /* FileTextPreviewDebugViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileTextPreviewDebugViewController.swift; sourceTree = "<group>"; };
C1963862283794A000298D4D /* BookmarksCachingSearch.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarksCachingSearch.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2378,7 +2389,6 @@
D6D95CE22B6D9F8800960317 /* AsyncHeadlessWebViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncHeadlessWebViewModel.swift; sourceTree = "<group>"; };
D6E0C1822B7A2B1E00D5E1E9 /* DesktopDownloadView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DesktopDownloadView.swift; sourceTree = "<group>"; };
D6E0C1842B7A2B9400D5E1E9 /* DesktopDownloadPlatformConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DesktopDownloadPlatformConstants.swift; sourceTree = "<group>"; };
D6E0C1862B7A2D0700D5E1E9 /* DesktopDownloadViewButtonStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DesktopDownloadViewButtonStyle.swift; sourceTree = "<group>"; };
D6E0C1882B7A2E0D00D5E1E9 /* DesktopDownloadViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DesktopDownloadViewModel.swift; sourceTree = "<group>"; };
D6E83C112B1E6AB3006C8AFB /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
D6E83C2D2B1EA06E006C8AFB /* SettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4166,6 +4176,17 @@
name = EmailProtection;
sourceTree = "<group>";
};
C1641EAD2BC2F46C0012607A /* Import */ = {
isa = PBXGroup;
children = (
C1641EAE2BC2F5140012607A /* ImportPasswordsViewController.swift */,
C1641EB02BC2F52B0012607A /* ImportPasswordsView.swift */,
C1641EB22BC2F53C0012607A /* ImportPasswordsViewModel.swift */,
C185ED602BD4329700BAE9DC /* ImportPasswordsStatusHandler.swift */,
);
name = Import;
sourceTree = "<group>";
};
C17B59552A03AAC40055F2D1 /* PasswordGeneration */ = {
isa = PBXGroup;
children = (
Expand All @@ -4176,6 +4197,14 @@
name = PasswordGeneration;
sourceTree = "<group>";
};
C185ED622BD4388F00BAE9DC /* Import */ = {
isa = PBXGroup;
children = (
C185ED632BD438AF00BAE9DC /* ImportPasswordsStatusHandlerTests.swift */,
);
name = Import;
sourceTree = "<group>";
};
C1AFFC4B2B8773060060448E /* AuthConfirmation */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -4384,7 +4413,6 @@
children = (
D6E0C1822B7A2B1E00D5E1E9 /* DesktopDownloadView.swift */,
D6E0C1842B7A2B9400D5E1E9 /* DesktopDownloadPlatformConstants.swift */,
D6E0C1862B7A2D0700D5E1E9 /* DesktopDownloadViewButtonStyle.swift */,
D6E0C1882B7A2E0D00D5E1E9 /* DesktopDownloadViewModel.swift */,
);
name = DesktopDownloads;
Expand Down Expand Up @@ -4943,6 +4971,7 @@
31C7D71B27515A6300A95D0A /* MockVoiceSearchHelper.swift */,
CBDD5DE029A6741300832877 /* MockBundle.swift */,
C1B0F6412AB08BE9001EAF05 /* MockPrivacyConfiguration.swift */,
C185ED652BD43A5500BAE9DC /* MockDDGSyncing.swift */,
);
name = Mocks;
sourceTree = "<group>";
Expand Down Expand Up @@ -5279,6 +5308,7 @@
F40F843228C92B1C0081AE75 /* Autofill */ = {
isa = PBXGroup;
children = (
C185ED622BD4388F00BAE9DC /* Import */,
C1BF0BA629B63E0400482B73 /* AutofillLoginUI */,
F40F843528C938370081AE75 /* AutofillLoginListViewModelTests.swift */,
C1D21E2E293A599C006E5A05 /* AutofillLoginSessionTests.swift */,
Expand All @@ -5290,6 +5320,7 @@
F44D279327F331930037F371 /* Autofill */ = {
isa = PBXGroup;
children = (
C1641EAD2BC2F46C0012607A /* Import */,
D63657182A7BAE7C001AF19D /* EmailManagerRequestDelegate.swift */,
F4147353283BF834004AA7A5 /* AutofillContentScopeFeatureToggles.swift */,
C1D21E2C293A5965006E5A05 /* AutofillLoginSession.swift */,
Expand Down Expand Up @@ -6319,6 +6350,7 @@
310ECFDD282A8BB0005029B3 /* EnableAutofillSettingsTableViewCell.swift in Sources */,
1E908BF329827C480008C8F3 /* AutoconsentManagement.swift in Sources */,
D6D95CE32B6D9F8800960317 /* AsyncHeadlessWebViewModel.swift in Sources */,
C185ED612BD4329700BAE9DC /* ImportPasswordsStatusHandler.swift in Sources */,
CB9B8739278C8E72001F4906 /* WidgetEducationViewController.swift in Sources */,
F4D9C4FA25117A0F00814B71 /* HomeMessageStorage.swift in Sources */,
D69FBF762B28BE3600B505F1 /* SettingsSubscriptionView.swift in Sources */,
Expand All @@ -6341,6 +6373,7 @@
986DA94A24884B18004A7E39 /* WebViewTransition.swift in Sources */,
31B524572715BB23002225AB /* WebJSAlert.swift in Sources */,
CB48D3322B90CE9F00631D8B /* UserBehaviorEvent.swift in Sources */,
C1641EB32BC2F53C0012607A /* ImportPasswordsViewModel.swift in Sources */,
8536A1FD2ACF114B003AC5BA /* Theme+DesignSystem.swift in Sources */,
F114C55B1E66EB020018F95F /* NibLoading.swift in Sources */,
D6BFCB612B7525160051FF81 /* SubscriptionPIRViewModel.swift in Sources */,
Expand Down Expand Up @@ -6377,6 +6410,7 @@
83BE9BC3215D69C1009844D9 /* AppConfigurationFetch.swift in Sources */,
37CF91622BB474AA00BADCAE /* CrashCollectionOnboardingView.swift in Sources */,
1EEC460627A9499600E75FCB /* DownloadsList.swift in Sources */,
C1641EAF2BC2F5140012607A /* ImportPasswordsViewController.swift in Sources */,
D6E83C5A2B2213ED006C8AFB /* SettingsPrivacyView.swift in Sources */,
85B9CB8921AEBDD5009001F1 /* FavoriteHomeCell.swift in Sources */,
98999D5922FDA41500CBBE1B /* BasicAuthenticationAlert.swift in Sources */,
Expand Down Expand Up @@ -6443,6 +6477,7 @@
EE0153EF2A70021E002A8B26 /* NetworkProtectionInviteView.swift in Sources */,
9888F77B2224980500C46159 /* FeedbackViewController.swift in Sources */,
D6E83C662B23936F006C8AFB /* SettingsDebugView.swift in Sources */,
C1641EB12BC2F52B0012607A /* ImportPasswordsView.swift in Sources */,
CBFCB30E2B2CD47800253E9E /* ConfigurationURLDebugViewController.swift in Sources */,
982686AD2600C0850011A8D6 /* ActionMessageView.swift in Sources */,
F446B9B5251150AC00324016 /* HomeMessageViewSectionRenderer.swift in Sources */,
Expand Down Expand Up @@ -6534,7 +6569,6 @@
311BD1B12836C0CA00AEF6C1 /* AutofillLoginListAuthenticator.swift in Sources */,
4BBBBA902B031B4200D965DA /* VPNWaitlist.swift in Sources */,
B652DF13287C373A00C12A9C /* ScriptSourceProviding.swift in Sources */,
D6E0C1872B7A2D0700D5E1E9 /* DesktopDownloadViewButtonStyle.swift in Sources */,
854A012B2A54412600FCC628 /* ActivityViewController.swift in Sources */,
F1CA3C391F045885005FADB3 /* PrivacyUserDefaults.swift in Sources */,
6F655BE22BAB289E00AC3597 /* DefaultTheme.swift in Sources */,
Expand Down Expand Up @@ -6762,8 +6796,10 @@
4BCD146D2B05DB09000B1E4C /* NetworkProtectionAccessControllerTests.swift in Sources */,
EE3B226B29DE0F110082298A /* MockInternalUserStoring.swift in Sources */,
987130C8294AAB9F00AB05E0 /* BookmarksTestHelpers.swift in Sources */,
C185ED672BD43DA100BAE9DC /* ImportPasswordsStatusHandlerTests.swift in Sources */,
F198D7981E3A45D90088DA8A /* WKWebViewConfigurationExtensionTests.swift in Sources */,
C14E2F7729DE14EA002AC515 /* AutofillInterfaceUsernameTruncatorTests.swift in Sources */,
C174CE602BD6A6CE00AED2EA /* MockDDGSyncing.swift in Sources */,
8521FDE6238D414B00A44CC3 /* FileStoreTests.swift in Sources */,
F14E491F1E391CE900DC037C /* URLExtensionTests.swift in Sources */,
85D2187424BF25CD004373D2 /* FaviconsTests.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion DuckDuckGo/AppDelegate+AppDeepLinks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ extension AppDelegate {
}
if let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
let queryItems = components.queryItems,
let lsItem = queryItems.first(where: { $0.name == "ls" }) {
queryItems.first(where: { $0.name == "ls" }) != nil {
Pixel.fire(pixel: .autofillLoginsLaunchWidgetLock)
} else {
Pixel.fire(pixel: .autofillLoginsLaunchWidgetHome)
Expand Down
3 changes: 3 additions & 0 deletions DuckDuckGo/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
#endif

updateSubscriptionStatus()

let importPasswordsStatusHandler = ImportPasswordsStatusHandler(syncService: syncService)
importPasswordsStatusHandler.checkSyncSuccessStatus()
}

private func stopTunnelAndShowThankYouMessagingIfNeeded() {
Expand Down
3 changes: 3 additions & 0 deletions DuckDuckGo/AppSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
//

import Bookmarks
import Foundation

enum AddressBarPosition: String, CaseIterable, CustomStringConvertible {
case top
Expand Down Expand Up @@ -67,6 +68,8 @@ protocol AppSettings: AnyObject {
var autofillCredentialsHasBeenEnabledAutomaticallyIfNecessary: Bool { get set }
var autofillIsNewInstallForOnByDefault: Bool? { get set }
func setAutofillIsNewInstallForOnByDefault()
var autofillImportViaSyncStart: Date? { get set }
func clearAutofillImportViaSyncStart()

var voiceSearchEnabled: Bool { get set }

Expand Down
7 changes: 7 additions & 0 deletions DuckDuckGo/AppUserDefaults.swift
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,13 @@ public class AppUserDefaults: AppSettings {
autofillIsNewInstallForOnByDefault = StatisticsUserDefaults().installDate == nil
}

@UserDefaultsWrapper(key: .autofillImportViaSyncStart, defaultValue: nil)
var autofillImportViaSyncStart: Date?

func clearAutofillImportViaSyncStart() {
autofillImportViaSyncStart = nil
}

@UserDefaultsWrapper(key: .voiceSearchEnabled, defaultValue: false)
var voiceSearchEnabled: Bool

Expand Down

0 comments on commit a845df9

Please sign in to comment.