Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor automatic update flow to use custom Sparkle user driver #3274

Open
wants to merge 45 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
574ab13
Revert "Resolving automatic update edge cases (#3142)"
quanganhdo Sep 3, 2024
a5ecfce
UpdateUserDriver draft
quanganhdo Sep 3, 2024
af16a18
Refactor UpdateState to show progress
quanganhdo Sep 3, 2024
7bce020
Fix wrong deferInstallation param
quanganhdo Sep 4, 2024
b227375
Show update progress
quanganhdo Sep 4, 2024
7da7531
Add manual restart
quanganhdo Sep 4, 2024
dfe308b
Rename delegate methods
quanganhdo Sep 4, 2024
21c5778
Remove AppRestarter
quanganhdo Sep 4, 2024
c060a2e
Fix updateCycleDone state
quanganhdo Sep 4, 2024
0e46de1
Remove shouldShowManualUpdateDialog
quanganhdo Sep 4, 2024
a778118
Simplify the states (double check needed)
quanganhdo Sep 4, 2024
50a2616
Add more logging, tweak last check date
quanganhdo Sep 4, 2024
4222672
Refactor updateCycleDone state
quanganhdo Sep 4, 2024
6d0ec52
Move from delegate method to Combine
quanganhdo Sep 4, 2024
18ea656
Put popup on hold till update cycle is done
quanganhdo Sep 4, 2024
8ec4a4b
Reconfigure updater whenever setting changes
quanganhdo Sep 4, 2024
1adf8b3
Refactor updateProgress
quanganhdo Sep 5, 2024
73c4daf
Minor refactoring
quanganhdo Sep 5, 2024
21a9710
Reintroduce cached result
quanganhdo Sep 5, 2024
9943227
Refactor new version check for UI
quanganhdo Sep 5, 2024
6bd72d6
Fix overaggressive updater reconfiguration
quanganhdo Sep 5, 2024
7b09024
Fix release note tab state
quanganhdo Sep 5, 2024
479b28d
Different checkpoints for different update options
quanganhdo Sep 6, 2024
9a4d060
Remove unnecessary code
quanganhdo Sep 6, 2024
aaa2304
Disable update mode switching if session is in progress
quanganhdo Sep 9, 2024
8dd0c50
Rename isNewVersionAvailable to hasPendingUpdate and fix edge case wh…
quanganhdo Sep 9, 2024
2d49b14
Fix stuck hasPendingStatus
quanganhdo Sep 9, 2024
2ddb68f
Check for update upon starting the app
quanganhdo Sep 9, 2024
f28f4e3
Simplify user driver
quanganhdo Sep 9, 2024
eae15e8
Dot goes away when menu opens
quanganhdo Sep 10, 2024
3da45e5
Add setNeedsDisplay
quanganhdo Sep 10, 2024
adc04d5
Add shouldShowUpdateNotification logic
quanganhdo Sep 10, 2024
1f3c6ff
Check for update when release note / about page is loaded and when it…
quanganhdo Sep 10, 2024
049d829
Fix stuck state when switching between modes
quanganhdo Sep 11, 2024
9061ba3
Add DEBUG check
quanganhdo Sep 11, 2024
1a52a17
Avoid overlapping popup
quanganhdo Sep 12, 2024
81e001d
Code cleanup
quanganhdo Sep 12, 2024
2a15a3c
Update copy
quanganhdo Sep 13, 2024
077add9
Fix last checked date showing - when idling
quanganhdo Sep 13, 2024
655b53e
Revert "Increase build number (to be reverted)" and update appcast2 U…
quanganhdo Sep 13, 2024
0ba11ed
Oops, wrong URL
quanganhdo Sep 13, 2024
a950d14
Revert browserRestart behaviour and undo debug changes
quanganhdo Sep 13, 2024
67cb390
Fix swiftlint
quanganhdo Sep 13, 2024
78e08d0
Add missing SPARKLE checks
quanganhdo Sep 16, 2024
bdc7a75
Design improvements to automatic update flow (#3344)
quanganhdo Oct 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 4 additions & 14 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@
1D01A3D92B88DF8B00FE8150 /* PreferencesSyncView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D01A3D72B88DF8B00FE8150 /* PreferencesSyncView.swift */; };
1D02633628D8A9A9005CBB41 /* BWEncryption.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D02633528D8A9A9005CBB41 /* BWEncryption.m */; settings = {COMPILER_FLAGS = "-Wno-deprecated -Wno-strict-prototypes"; }; };
1D074B272909A433006E4AC3 /* PasswordManagerCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D074B262909A433006E4AC3 /* PasswordManagerCoordinator.swift */; };
1D0DE93E2C3BA9840037ABC2 /* AppRestarter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D0DE93D2C3BA9840037ABC2 /* AppRestarter.swift */; };
1D0DE93F2C3BA9840037ABC2 /* AppRestarter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D0DE93D2C3BA9840037ABC2 /* AppRestarter.swift */; };
1D0DE9412C3BB9CC0037ABC2 /* ReleaseNotesParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D0DE9402C3BB9CC0037ABC2 /* ReleaseNotesParser.swift */; };
1D0DE9422C3BB9CC0037ABC2 /* ReleaseNotesParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D0DE9402C3BB9CC0037ABC2 /* ReleaseNotesParser.swift */; };
1D12F2E2298BC660009A65FD /* InternalUserDeciderStoreMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D12F2E1298BC660009A65FD /* InternalUserDeciderStoreMock.swift */; };
Expand All @@ -69,8 +67,6 @@
1D220BF92B86192200F8BBC6 /* PreferencesEmailProtectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D220BF72B86192200F8BBC6 /* PreferencesEmailProtectionView.swift */; };
1D220BFC2B87AACF00F8BBC6 /* PrivacyProtectionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D220BFB2B87AACF00F8BBC6 /* PrivacyProtectionStatus.swift */; };
1D220BFD2B87AACF00F8BBC6 /* PrivacyProtectionStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D220BFB2B87AACF00F8BBC6 /* PrivacyProtectionStatus.swift */; };
1D232E942C7860DA0043840D /* BinaryOwnershipChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D232E932C7860DA0043840D /* BinaryOwnershipChecker.swift */; };
1D232E992C7870D90043840D /* BinaryOwnershipCheckerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D232E962C786E7D0043840D /* BinaryOwnershipCheckerTests.swift */; };
1D26EBAC2B74BECB0002A93F /* NSImageSendable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D26EBAB2B74BECB0002A93F /* NSImageSendable.swift */; };
1D26EBAD2B74BECB0002A93F /* NSImageSendable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D26EBAB2B74BECB0002A93F /* NSImageSendable.swift */; };
1D26EBB02B74DB600002A93F /* TabSnapshotCleanupService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D26EBAF2B74DB600002A93F /* TabSnapshotCleanupService.swift */; };
Expand Down Expand Up @@ -2718,6 +2714,7 @@
BD384ACA2BBC821A00EF3735 /* vpn-light-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = BD384AC72BBC821100EF3735 /* vpn-light-mode.json */; };
BD384ACB2BBC821B00EF3735 /* vpn-dark-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = BD384AC82BBC821100EF3735 /* vpn-dark-mode.json */; };
BD384ACC2BBC821B00EF3735 /* vpn-light-mode.json in Resources */ = {isa = PBXBuildFile; fileRef = BD384AC72BBC821100EF3735 /* vpn-light-mode.json */; };
BD6367252C877BE1009DE7A8 /* UpdateUserDriver.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD6367242C877BE1009DE7A8 /* UpdateUserDriver.swift */; };
BD7090CF2C5182FB009EED82 /* UnifiedFeedbackFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD7090CE2C5182FB009EED82 /* UnifiedFeedbackFormView.swift */; };
BD7090D02C5182FB009EED82 /* UnifiedFeedbackFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD7090CE2C5182FB009EED82 /* UnifiedFeedbackFormView.swift */; };
BD7090D22C52ECFE009EED82 /* UnifiedMetadataCollector.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD7090D12C52ECFE009EED82 /* UnifiedMetadataCollector.swift */; };
Expand Down Expand Up @@ -3214,16 +3211,13 @@
1D02633428D8A9A9005CBB41 /* BWEncryption.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BWEncryption.h; sourceTree = "<group>"; };
1D02633528D8A9A9005CBB41 /* BWEncryption.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BWEncryption.m; sourceTree = "<group>"; };
1D074B262909A433006E4AC3 /* PasswordManagerCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordManagerCoordinator.swift; sourceTree = "<group>"; };
1D0DE93D2C3BA9840037ABC2 /* AppRestarter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppRestarter.swift; sourceTree = "<group>"; };
1D0DE9402C3BB9CC0037ABC2 /* ReleaseNotesParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReleaseNotesParser.swift; sourceTree = "<group>"; };
1D12F2E1298BC660009A65FD /* InternalUserDeciderStoreMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternalUserDeciderStoreMock.swift; sourceTree = "<group>"; };
1D1A33482A6FEB170080ACED /* BurnerMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BurnerMode.swift; sourceTree = "<group>"; };
1D1C36E229FAE8DA001FA40C /* FaviconManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FaviconManagerTests.swift; sourceTree = "<group>"; };
1D1C36E529FB019C001FA40C /* HistoryTabExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryTabExtensionTests.swift; sourceTree = "<group>"; };
1D220BF72B86192200F8BBC6 /* PreferencesEmailProtectionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreferencesEmailProtectionView.swift; sourceTree = "<group>"; };
1D220BFB2B87AACF00F8BBC6 /* PrivacyProtectionStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyProtectionStatus.swift; sourceTree = "<group>"; };
1D232E932C7860DA0043840D /* BinaryOwnershipChecker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinaryOwnershipChecker.swift; sourceTree = "<group>"; };
1D232E962C786E7D0043840D /* BinaryOwnershipCheckerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BinaryOwnershipCheckerTests.swift; sourceTree = "<group>"; };
1D26EBAB2B74BECB0002A93F /* NSImageSendable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSImageSendable.swift; sourceTree = "<group>"; };
1D26EBAF2B74DB600002A93F /* TabSnapshotCleanupService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabSnapshotCleanupService.swift; sourceTree = "<group>"; };
1D36E657298AA3BA00AA485D /* InternalUserDeciderStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternalUserDeciderStore.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4556,6 +4550,7 @@
BBFF355C2C4AF26200DA3289 /* BookmarksSortModeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BookmarksSortModeTests.swift; sourceTree = "<group>"; };
BD384AC72BBC821100EF3735 /* vpn-light-mode.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "vpn-light-mode.json"; sourceTree = "<group>"; };
BD384AC82BBC821100EF3735 /* vpn-dark-mode.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "vpn-dark-mode.json"; sourceTree = "<group>"; };
BD6367242C877BE1009DE7A8 /* UpdateUserDriver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateUserDriver.swift; sourceTree = "<group>"; };
BD7090CE2C5182FB009EED82 /* UnifiedFeedbackFormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnifiedFeedbackFormView.swift; sourceTree = "<group>"; };
BD7090D12C52ECFE009EED82 /* UnifiedMetadataCollector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnifiedMetadataCollector.swift; sourceTree = "<group>"; };
BD7090D52C540D5D009EED82 /* EmptyMetadataCollector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmptyMetadataCollector.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -5107,12 +5102,11 @@
1DA84D312C119AE70011C80F /* UpdateMenuItemFactory.swift */,
1D72D59B2BFF61B200AEDE36 /* UpdateNotificationPresenter.swift */,
1D9297BE2C1B062900A38521 /* ApplicationUpdateDetector.swift */,
1D0DE93D2C3BA9840037ABC2 /* AppRestarter.swift */,
1D232E932C7860DA0043840D /* BinaryOwnershipChecker.swift */,
1D39E5762C2BFD5700757339 /* ReleaseNotesTabExtension.swift */,
1D39E5792C2C0F3700757339 /* ReleaseNotesUserScript.swift */,
1D0DE9402C3BB9CC0037ABC2 /* ReleaseNotesParser.swift */,
1D710F4A2C48F1F200C3975F /* UpdateDialogHelper.swift */,
BD6367242C877BE1009DE7A8 /* UpdateUserDriver.swift */,
);
path = Updates;
sourceTree = "<group>";
Expand Down Expand Up @@ -5149,7 +5143,6 @@
children = (
1D838A312C44F0180078373F /* ReleaseNotesParserTests.swift */,
1D638D602C44F2BA00530DD5 /* ApplicationUpdateDetectorTests.swift */,
1D232E962C786E7D0043840D /* BinaryOwnershipCheckerTests.swift */,
);
path = Updates;
sourceTree = "<group>";
Expand Down Expand Up @@ -11443,7 +11436,6 @@
3707C71E294B5D2900682A9F /* URLRequestExtension.swift in Sources */,
3706FCA3293F65D500E42796 /* WKProcessPool+GeolocationProvider.swift in Sources */,
372A0FED2B2379310033BF7F /* SyncMetricsEventsHandler.swift in Sources */,
1D0DE93F2C3BA9840037ABC2 /* AppRestarter.swift in Sources */,
3706FCA4293F65D500E42796 /* RecentlyClosedMenu.swift in Sources */,
8400DC4C2C6E26AE006509D2 /* ItemCachingCollectionView.swift in Sources */,
4B9DB02D2A983B24000927DB /* WaitlistKeychainStorage.swift in Sources */,
Expand Down Expand Up @@ -12337,7 +12329,6 @@
B6BF5D8929470BC4006742B1 /* HTTPSUpgradeTabExtension.swift in Sources */,
1D36E65B298ACD2900AA485D /* AppIconChanger.swift in Sources */,
4B4D60E22A0C883A00BCD287 /* AppMain.swift in Sources */,
1D0DE93E2C3BA9840037ABC2 /* AppRestarter.swift in Sources */,
7BCB90C22C18626E008E3543 /* VPNControllerXPCClient+ConvenienceInitializers.swift in Sources */,
4B9DB0202A983B24000927DB /* ProductWaitlistRequest.swift in Sources */,
7B60B0022C5145EC008E32A3 /* VPNUIActionHandler.swift in Sources */,
Expand Down Expand Up @@ -12847,7 +12838,6 @@
37BF3F21286F0A7A00BD9014 /* PinnedTabsViewModel.swift in Sources */,
EEC4A6692B2C87D300F7C0AA /* VPNLocationView.swift in Sources */,
AAC5E4D225D6A709007F5990 /* BookmarkList.swift in Sources */,
1D232E942C7860DA0043840D /* BinaryOwnershipChecker.swift in Sources */,
B602E81D2A1E25B1006D261F /* NEOnDemandRuleExtension.swift in Sources */,
56A0543E2C215FB3007D8FAB /* OnboardingUserScript.swift in Sources */,
C1372EF42BBC5BAD003F8793 /* SecureTextField.swift in Sources */,
Expand All @@ -12874,6 +12864,7 @@
AAC82C60258B6CB5009B6B42 /* TabPreviewWindowController.swift in Sources */,
AAC5E4E425D6BA9C007F5990 /* NSSizeExtension.swift in Sources */,
AA6820EB25503D6A005ED0D5 /* Fire.swift in Sources */,
BD6367252C877BE1009DE7A8 /* UpdateUserDriver.swift in Sources */,
3158B1492B0BF73000AF130C /* DBPHomeViewController.swift in Sources */,
9F56CFA92B82DC4300BB7F11 /* AddEditBookmarkFolderView.swift in Sources */,
37445F9C2A1569F00029F789 /* SyncBookmarksAdapter.swift in Sources */,
Expand Down Expand Up @@ -13183,7 +13174,6 @@
567A23E12C89B1EE0010F66C /* BrowserTabViewControllerOnboardingTests.swift in Sources */,
986189E62A7CFB3E001B4519 /* LocalBookmarkStoreSavingTests.swift in Sources */,
AA652CD325DDA6E9009059CC /* LocalBookmarkManagerTests.swift in Sources */,
1D232E992C7870D90043840D /* BinaryOwnershipCheckerTests.swift in Sources */,
CBDD5DE329A67F2700832877 /* MockConfigurationStore.swift in Sources */,
9F3910692B68D87B00CB5112 /* ProgressExtensionTests.swift in Sources */,
B63ED0DC26AE7B1E00A9DAD1 /* WebViewMock.swift in Sources */,
Expand Down
10 changes: 7 additions & 3 deletions DuckDuckGo/Common/Localizables/UserText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1221,21 +1221,25 @@ struct UserText {
static let downloadsOpenDownloadsFolder = NSLocalizedString("downloads.open-downloads-folder", value: "Open Downloads Folder", comment: "Button in the downloads manager that allows the user to open the downloads folder")

// MARK: Updates
static let updateAvailableMenuItem = NSLocalizedString("update.available.menu.item", value: "Update Available - Restart Now", comment: "Title of the menu item that informs user that a new update is available. Clicking on the menu item restarts the app and installs the update")
static let updateAvailableMenuItem = NSLocalizedString("update.available.menu.item", value: "Update Available - Install Now", comment: "Title of the menu item that informs user that a new update is available. Clicking on the menu item installs the update")
static let releaseNotesMenuItem = NSLocalizedString("release.notes.menu.item", value: "Release Notes", comment: "Title of the dialog menu item that opens release notes")
static let whatsNewMenuItem = NSLocalizedString("whats.new.menu.item", value: "What's New", comment: "Title of the dialog menu item that opens the 'What's New' page")
static let browserUpdatesTitle = NSLocalizedString("settings.browser.updates.title", value: "Browser Updates", comment: "Title of the section in Settings where people set up automatic vs manual updates")
static let automaticUpdates = NSLocalizedString("settings.automatic.updates", value: "Automatically install updates (recommended)", comment: "Title of the checkbox item to set up automatic updates of the browser")
static let manualUpdates = NSLocalizedString("settings.manual.updates", value: "Check for updates but let you choose to install them", comment: "Title of the checkbox item to set up manual updates of the browser")
static let checkingForUpdate = NSLocalizedString("settings.checking.for.update", value: "Checking for update", comment: "Label informing users the app is currently checking for new update")
static let downloadingUpdate = NSLocalizedString("settings.downloading.update", value: "Downloading update %@", comment: "Label informing users the app is currently downloading the update. This will contain a percentage")
static let preparingUpdate = NSLocalizedString("settings.preparing.update", value: "Preparing update", comment: "Label informing users the app is preparing to update.")
static let updateFailed = NSLocalizedString("settings.update.failed", value: "Update failed", comment: "Label informing users the app is unable to update.")
static let upToDate = NSLocalizedString("settings.up.to.date", value: "DuckDuckGo is up to date", comment: "Label informing users the app is currently up to date and no update is required.")
static let newerVersionAvailable = NSLocalizedString("settings.newer.version.available", value: "Newer version available", comment: "Label informing users the newer version of the app is available to install.")
static let lastChecked = NSLocalizedString("settings.last.checked", value: "Last checked", comment: "Label informing users what is the last time the app checked for the update.")
static let restartToUpdate = NSLocalizedString("settings.restart.to.update", value: "Restart to Update", comment: "Button label trigering restart and update of the application.")
static let runUpdate = NSLocalizedString("settings.restart.to.update", value: "Update DuckDuckGo", comment: "Button label triggering restart and update of the application.")
static let retryUpdate = NSLocalizedString("settings.retry.update", value: "Retry Update", comment: "Button label triggering a retry of the update.")
static let browserUpdatedNotification = NSLocalizedString("notification.browser.updated", value: "Browser Updated", comment: "Notification informing user the app has been updated")
static let browserDowngradedNotification = NSLocalizedString("notification.browser.downgraded", value: "Browser Downgraded", comment: "Notification informing user the app has been downgraded")
static let criticalUpdateNotification = NSLocalizedString("notification.critical.update", value: "Critical update required. Restart to update.", comment: "Notification informing user a critical update is required.")
static let updateAvailableNotification = NSLocalizedString("notification.update.available", value: "New version available. Restart to update.", comment: "Notification informing user the a version of app is available")
static let updateAvailableNotification = NSLocalizedString("notification.update.available", value: "New version available. Click here to update.", comment: "Notification informing user the a version of app is available")
static let viewDetails = NSLocalizedString("view.details.button", value: "View Details", comment: "Button title to open more details about the update")

enum Bookmarks {
Expand Down
1 change: 1 addition & 0 deletions DuckDuckGo/Common/Utilities/UserDefaultsWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ public struct UserDefaultsWrapper<T> {

// Updates
case automaticUpdates = "updates.automatic"
case pendingUpdateShown = "pending.update.shown"

// Experiments
case pixelExperimentInstalled = "pixel.experiment.installed"
Expand Down
Loading
Loading