Skip to content

Commit

Permalink
Connect refactored update flow to the new release notes page
Browse files Browse the repository at this point in the history
  • Loading branch information
quanganhdo committed Oct 16, 2024
1 parent b898112 commit 5b29d1c
Show file tree
Hide file tree
Showing 7 changed files with 109 additions and 48 deletions.
3 changes: 2 additions & 1 deletion DuckDuckGo/Common/Localizables/UserText.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1222,7 +1222,8 @@ struct UserText {
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 runUpdate = NSLocalizedString("settings.restart.to.update", value: "Update DuckDuckGo", comment: "Button label triggering restart and update of the application.")
static let restartToUpdate = NSLocalizedString("settings.restart.to.update", value: "Restart to Update", comment: "Button label triggering restart and update of the application.")
static let runUpdate = NSLocalizedString("settings.run.update", value: "Update DuckDuckGo", comment: "Button label triggering 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")
Expand Down
14 changes: 13 additions & 1 deletion DuckDuckGo/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -55457,7 +55457,7 @@
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "Update DuckDuckGo"
"value" : "Restart to Update"
}
},
"es" : {
Expand Down Expand Up @@ -55516,6 +55516,18 @@
}
}
},
"settings.run.update" : {
"comment" : "Button label triggering update of the application.",
"extractionState" : "extracted_with_value",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "new",
"value" : "Update DuckDuckGo"
}
}
}
},
"settings.up.to.date" : {
"comment" : "Label informing users the app is currently up to date and no update is required.",
"extractionState" : "extracted_with_value",
Expand Down
18 changes: 0 additions & 18 deletions DuckDuckGo/Preferences/Model/AboutPreferences.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,11 @@ final class AboutPreferences: ObservableObject, PreferencesTabOpening {
static let shared = AboutPreferences()

#if SPARKLE
enum UpdateState {

case upToDate
case updateCycle(UpdateCycleProgress)

init(from update: Update?, progress: UpdateCycleProgress) {
if let update, !update.isInstalled {
self = .updateCycle(progress)
} else if progress.isFailed {
self = .updateCycle(progress)
} else {
self = .upToDate
}
}
}

@Published var updateState = UpdateState.upToDate

#if SPARKLE
var updateController: UpdateControllerProtocol? {
return Application.appDelegate.updateController
}
#endif

var areAutomaticUpdatesEnabled: Bool {
get {
Expand Down
2 changes: 1 addition & 1 deletion DuckDuckGo/Preferences/View/PreferencesAboutView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ extension Preferences {
.buttonStyle(UpdateButtonStyle(enabled: true))
case .updateCycle(let progress):
if hasPendingUpdate {
Button(UserText.runUpdate) {
Button(model.areAutomaticUpdatesEnabled ? UserText.restartToUpdate : UserText.runUpdate) {
model.runUpdate()
}
.buttonStyle(UpdateButtonStyle(enabled: true))
Expand Down
93 changes: 67 additions & 26 deletions DuckDuckGo/Updates/ReleaseNotesTabExtension.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ protocol ReleaseNotesUserScriptProvider {
extension UserScripts: ReleaseNotesUserScriptProvider {}

public struct ReleaseNotesValues: Codable {
enum Status: String {
case loaded
case loading
case updateReady
case updateDownloading
case updatePreparing
case updateError
}

let status: String
let currentVersion: String
Expand All @@ -40,7 +48,7 @@ public struct ReleaseNotesValues: Codable {
let releaseTitle: String?
let releaseNotes: [String]?
let releaseNotesPrivacyPro: [String]?

let downloadProgress: Double?
}

final class ReleaseNotesTabExtension: NavigationResponder {
Expand Down Expand Up @@ -115,49 +123,82 @@ extension TabExtensions {

extension ReleaseNotesValues {

init(status: String,
init(status: Status,
currentVersion: String,
lastUpdate: UInt) {
self.init(status: status,
currentVersion: currentVersion,
latestVersion: nil,
lastUpdate: lastUpdate,
releaseTitle: nil,
releaseNotes: nil,
releaseNotesPrivacyPro: nil)
latestVersion: String? = nil,
lastUpdate: UInt,
releaseTitle: String? = nil,
releaseNotes: [String]? = nil,
releaseNotesPrivacyPro: [String]? = nil,
downloadProgress: Double? = nil) {
self.status = status.rawValue
self.currentVersion = currentVersion
self.latestVersion = latestVersion
self.lastUpdate = lastUpdate
self.releaseTitle = releaseTitle
self.releaseNotes = releaseNotes
self.releaseNotesPrivacyPro = releaseNotesPrivacyPro
self.downloadProgress = downloadProgress
}

init(from updateController: UpdateController?) {
let currentVersion = "\(AppVersion().versionNumber) (\(AppVersion().buildNumber))"
let lastUpdate = UInt((updateController?.lastUpdateCheckDate ?? Date()).timeIntervalSince1970)
let status: String
let latestVersion: String

guard let updateController, updateController.updateProgress.isIdle else {
self.init(status: "loading",
guard let updateController else {
self.init(status: .loaded,
currentVersion: currentVersion,
lastUpdate: lastUpdate)
return
}

if let latestUpdate = updateController.latestUpdate {
status = latestUpdate.isInstalled ? "loaded" : "updateReady"
latestVersion = "\(latestUpdate.version) (\(latestUpdate.build))"
self.init(status: status,
currentVersion: currentVersion,
latestVersion: latestVersion,
lastUpdate: lastUpdate,
releaseTitle: latestUpdate.title,
releaseNotes: latestUpdate.releaseNotes,
releaseNotesPrivacyPro: latestUpdate.releaseNotesPrivacyPro)
return
} else {
self.init(status: "loaded",
let updateState = UpdateState(from: updateController.latestUpdate, progress: updateController.updateProgress)
let hasPendingUpdate = updateController.hasPendingUpdate

switch updateState {
case .upToDate:
self.init(status: .loaded,
currentVersion: currentVersion,
lastUpdate: lastUpdate)
case .updateCycle(let progress):
if let latestUpdate = updateController.latestUpdate {
latestVersion = "\(latestUpdate.version) (\(latestUpdate.build))"
let status = hasPendingUpdate ? .updateReady : progress.toStatus
self.init(status: status,
currentVersion: currentVersion,
latestVersion: latestVersion,
lastUpdate: lastUpdate,
releaseTitle: latestUpdate.title,
releaseNotes: latestUpdate.releaseNotes,
releaseNotesPrivacyPro: latestUpdate.releaseNotesPrivacyPro,
downloadProgress: progress.toDownloadProgress)
} else {
self.init(status: .loaded,
currentVersion: currentVersion,
lastUpdate: lastUpdate)
}
}
}
}

private extension UpdateCycleProgress {
var toStatus: ReleaseNotesValues.Status {
switch self {
case .updateCycleDidStart: return .loading
case .downloadDidStart, .downloading: return .updateDownloading
case .extractionDidStart, .extracting, .readyToInstallAndRelaunch, .installationDidStart, .installing: return .updatePreparing
case .updaterError: return .updateError
case .updateCycleNotStarted, .updateCycleDone: return .updateReady
}
}

var toDownloadProgress: Double? {
guard case .downloading(let percentage) = self else {
return nil
}
return percentage
}
}

#else
Expand Down
12 changes: 11 additions & 1 deletion DuckDuckGo/Updates/ReleaseNotesUserScript.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ final class ReleaseNotesUserScript: NSObject, Subfeature {
case reportPageException
case reportInitException
case browserRestart
case retryUpdate
}

override init() {
Expand All @@ -57,7 +58,8 @@ final class ReleaseNotesUserScript: NSObject, Subfeature {
.initialSetup: initialSetup,
.reportPageException: reportPageException,
.reportInitException: reportInitException,
.browserRestart: browserRestart
.browserRestart: browserRestart,
.retryUpdate: retryUpdate,
]

@MainActor
Expand Down Expand Up @@ -108,6 +110,14 @@ extension ReleaseNotesUserScript {
return InitialSetupResult(env: env, locale: Locale.current.identifier)
}

@MainActor
private func retryUpdate(params: Any, original: WKScriptMessage) async throws -> Encodable? {
DispatchQueue.main.async { [weak self] in
self?.updateController.checkForUpdateIfNeeded()
}
return nil
}

struct InitialSetupResult: Encodable {
let env: String
let locale: String
Expand Down
15 changes: 15 additions & 0 deletions DuckDuckGo/Updates/UpdateUserDriver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,21 @@ import os.log

#if SPARKLE

enum UpdateState {
case upToDate
case updateCycle(UpdateCycleProgress)

init(from update: Update?, progress: UpdateCycleProgress) {
if let update, !update.isInstalled {
self = .updateCycle(progress)
} else if progress.isFailed {
self = .updateCycle(progress)
} else {
self = .upToDate
}
}
}

enum UpdateCycleProgress {
case updateCycleNotStarted
case updateCycleDidStart
Expand Down

0 comments on commit 5b29d1c

Please sign in to comment.