mirror of
https://github.com/nicoverbruggen/NVAppUpdater.git
synced 2025-08-07 17:50:07 +02:00
Allow changelog URL callback to be set
This commit is contained in:
@ -10,7 +10,11 @@ let package = Package(
|
||||
products: [
|
||||
.library(name: "NVAppUpdater", targets: ["NVAppUpdater"]),
|
||||
],
|
||||
dependencies: [
|
||||
.package(name: "NVAlert", path: "/Users/nicoverbruggen/Code/SwiftPM/NVAlert")
|
||||
// .package(url: "https://github.com/nicoverbruggen/NVAlert", branch: "main")
|
||||
],
|
||||
targets: [
|
||||
.target(name: "NVAppUpdater"),
|
||||
.target(name: "NVAppUpdater", dependencies: ["NVAlert"]),
|
||||
]
|
||||
)
|
||||
|
@ -5,16 +5,17 @@
|
||||
|
||||
import Foundation
|
||||
import Cocoa
|
||||
import NVAlert
|
||||
|
||||
open class UpdateCheck
|
||||
{
|
||||
let caskUrl: URL
|
||||
let promptOnFailure: Bool
|
||||
let selfUpdaterName: String
|
||||
let selfUpdaterPath: String
|
||||
|
||||
var caskFile: CaskFile!
|
||||
var newerVersion: AppVersion!
|
||||
private var releaseNotesUrlCallback: ((CaskFile) -> URL?)? = nil
|
||||
private var caskFile: CaskFile!
|
||||
private var newerVersion: AppVersion!
|
||||
|
||||
/**
|
||||
* Create a new update check instance. Once created, you should call `perform` on this instance.
|
||||
@ -28,30 +29,33 @@ open class UpdateCheck
|
||||
*
|
||||
* - Parameter caskUrl: The URL where the Cask file is expected to be located. Redirects will
|
||||
* be followed when retrieving and validating the Cask file.
|
||||
*/
|
||||
public init(
|
||||
selfUpdaterName: String,
|
||||
selfUpdaterPath: String,
|
||||
caskUrl: URL
|
||||
) {
|
||||
self.selfUpdaterName = selfUpdaterName
|
||||
self.selfUpdaterPath = selfUpdaterPath
|
||||
self.caskUrl = caskUrl
|
||||
}
|
||||
|
||||
public func resolvingReleaseNotes(with callback: @escaping (CaskFile) -> URL?) -> Self {
|
||||
self.releaseNotesUrlCallback = callback
|
||||
return self
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the check for a new version.
|
||||
*
|
||||
* - Parameter promptOnFailure: Whether user interaction is required when failing to check
|
||||
* or no new update is found. A user usually expects a prompt if they manually searched
|
||||
* for updates.
|
||||
*/
|
||||
public init(
|
||||
selfUpdaterName: String,
|
||||
selfUpdaterPath: String,
|
||||
caskUrl: URL,
|
||||
promptOnFailure: Bool
|
||||
) {
|
||||
self.selfUpdaterName = selfUpdaterName
|
||||
self.selfUpdaterPath = selfUpdaterPath
|
||||
self.caskUrl = caskUrl
|
||||
self.promptOnFailure = promptOnFailure
|
||||
}
|
||||
|
||||
/**
|
||||
Perform the check for a new version.
|
||||
*/
|
||||
public func perform() async {
|
||||
guard let caskFile = await CaskFile.from(url: caskUrl) else {
|
||||
public func perform(promptOnFailure: Bool = true) async {
|
||||
guard let caskFile = CaskFile.from(url: caskUrl) else {
|
||||
Log.text("The contents of the CaskFile at '\(caskUrl.absoluteString)' could not be retrieved.")
|
||||
return await presentCouldNotRetrieveUpdate()
|
||||
return await presentCouldNotRetrieveUpdate(promptOnFailure)
|
||||
}
|
||||
|
||||
self.caskFile = caskFile
|
||||
@ -60,7 +64,7 @@ open class UpdateCheck
|
||||
|
||||
guard let onlineVersion = AppVersion.from(caskFile.version) else {
|
||||
Log.text("The version string from the CaskFile could not be read.")
|
||||
return await presentCouldNotRetrieveUpdate()
|
||||
return await presentCouldNotRetrieveUpdate(promptOnFailure)
|
||||
}
|
||||
|
||||
self.newerVersion = onlineVersion
|
||||
@ -71,13 +75,13 @@ open class UpdateCheck
|
||||
if onlineVersion > currentVersion {
|
||||
await presentNewerVersionAvailable()
|
||||
} else if promptOnFailure {
|
||||
await presentVersionIsUpToDate()
|
||||
await presentVersionIsUpToDate(promptOnFailure)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Alerts
|
||||
|
||||
private func presentCouldNotRetrieveUpdate() async {
|
||||
private func presentCouldNotRetrieveUpdate(_ promptOnFailure: Bool) async {
|
||||
Log.text("Could not retrieve update manifest!")
|
||||
|
||||
if promptOnFailure {
|
||||
@ -88,7 +92,7 @@ open class UpdateCheck
|
||||
}
|
||||
}
|
||||
|
||||
private func presentVersionIsUpToDate() async {
|
||||
private func presentVersionIsUpToDate(_ promptOnFailure: Bool) async {
|
||||
Log.text("Version is up-to-date!")
|
||||
|
||||
if promptOnFailure {
|
||||
@ -104,22 +108,30 @@ open class UpdateCheck
|
||||
|
||||
let current = AppVersion.fromCurrentVersion()
|
||||
|
||||
let outcome = await Alert.choose(
|
||||
let alert = await NVAlert().withInformation(
|
||||
title: "An updated version of \(Executable.name) is available.",
|
||||
description: """
|
||||
Version \(newerVersion.version) is available for download.
|
||||
(This is currently version \(current.version).)
|
||||
|
||||
Do you want to download and install this updated version?
|
||||
""",
|
||||
options: [
|
||||
"Update Now",
|
||||
"Cancel"
|
||||
])
|
||||
|
||||
if outcome == .alertFirstButtonReturn {
|
||||
launchSelfUpdater()
|
||||
subtitle: "Version \(newerVersion.version) is available for download.",
|
||||
description: "Do you want to download and install this updated version?"
|
||||
)
|
||||
.withPrimary(
|
||||
text: "Install",
|
||||
action: { vc in
|
||||
vc.close(with: .OK)
|
||||
self.launchSelfUpdater()
|
||||
}
|
||||
)
|
||||
.withTertiary(text: "Dismiss", action: { vc in
|
||||
vc.close(with: .OK)
|
||||
})
|
||||
|
||||
if let callback = self.releaseNotesUrlCallback,
|
||||
let url = callback(self.caskFile) {
|
||||
await alert.withSecondary(text: "View Release Notes") { _ in
|
||||
NSWorkspace.shared.open(url)
|
||||
}
|
||||
}
|
||||
|
||||
await alert.show()
|
||||
}
|
||||
|
||||
// MARK: - Functional
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
struct CaskFile {
|
||||
public struct CaskFile {
|
||||
var properties: [String: String]
|
||||
|
||||
var name: String { return self.properties["name"]! }
|
||||
|
Reference in New Issue
Block a user