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: [
|
products: [
|
||||||
.library(name: "NVAppUpdater", targets: ["NVAppUpdater"]),
|
.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: [
|
targets: [
|
||||||
.target(name: "NVAppUpdater"),
|
.target(name: "NVAppUpdater", dependencies: ["NVAlert"]),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
@ -5,16 +5,17 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
import NVAlert
|
||||||
|
|
||||||
open class UpdateCheck
|
open class UpdateCheck
|
||||||
{
|
{
|
||||||
let caskUrl: URL
|
let caskUrl: URL
|
||||||
let promptOnFailure: Bool
|
|
||||||
let selfUpdaterName: String
|
let selfUpdaterName: String
|
||||||
let selfUpdaterPath: String
|
let selfUpdaterPath: String
|
||||||
|
|
||||||
var caskFile: CaskFile!
|
private var releaseNotesUrlCallback: ((CaskFile) -> URL?)? = nil
|
||||||
var newerVersion: AppVersion!
|
private var caskFile: CaskFile!
|
||||||
|
private var newerVersion: AppVersion!
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new update check instance. Once created, you should call `perform` on this instance.
|
* 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
|
* - Parameter caskUrl: The URL where the Cask file is expected to be located. Redirects will
|
||||||
* be followed when retrieving and validating the Cask file.
|
* be followed when retrieving and validating the Cask file.
|
||||||
*
|
|
||||||
* - 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(
|
public init(
|
||||||
selfUpdaterName: String,
|
selfUpdaterName: String,
|
||||||
selfUpdaterPath: String,
|
selfUpdaterPath: String,
|
||||||
caskUrl: URL,
|
caskUrl: URL
|
||||||
promptOnFailure: Bool
|
|
||||||
) {
|
) {
|
||||||
self.selfUpdaterName = selfUpdaterName
|
self.selfUpdaterName = selfUpdaterName
|
||||||
self.selfUpdaterPath = selfUpdaterPath
|
self.selfUpdaterPath = selfUpdaterPath
|
||||||
self.caskUrl = caskUrl
|
self.caskUrl = caskUrl
|
||||||
self.promptOnFailure = promptOnFailure
|
}
|
||||||
|
|
||||||
|
public func resolvingReleaseNotes(with callback: @escaping (CaskFile) -> URL?) -> Self {
|
||||||
|
self.releaseNotesUrlCallback = callback
|
||||||
|
return self
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Perform the check for a new version.
|
* 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 func perform() async {
|
public func perform(promptOnFailure: Bool = true) async {
|
||||||
guard let caskFile = await CaskFile.from(url: caskUrl) else {
|
guard let caskFile = CaskFile.from(url: caskUrl) else {
|
||||||
Log.text("The contents of the CaskFile at '\(caskUrl.absoluteString)' could not be retrieved.")
|
Log.text("The contents of the CaskFile at '\(caskUrl.absoluteString)' could not be retrieved.")
|
||||||
return await presentCouldNotRetrieveUpdate()
|
return await presentCouldNotRetrieveUpdate(promptOnFailure)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.caskFile = caskFile
|
self.caskFile = caskFile
|
||||||
@ -60,7 +64,7 @@ open class UpdateCheck
|
|||||||
|
|
||||||
guard let onlineVersion = AppVersion.from(caskFile.version) else {
|
guard let onlineVersion = AppVersion.from(caskFile.version) else {
|
||||||
Log.text("The version string from the CaskFile could not be read.")
|
Log.text("The version string from the CaskFile could not be read.")
|
||||||
return await presentCouldNotRetrieveUpdate()
|
return await presentCouldNotRetrieveUpdate(promptOnFailure)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.newerVersion = onlineVersion
|
self.newerVersion = onlineVersion
|
||||||
@ -71,13 +75,13 @@ open class UpdateCheck
|
|||||||
if onlineVersion > currentVersion {
|
if onlineVersion > currentVersion {
|
||||||
await presentNewerVersionAvailable()
|
await presentNewerVersionAvailable()
|
||||||
} else if promptOnFailure {
|
} else if promptOnFailure {
|
||||||
await presentVersionIsUpToDate()
|
await presentVersionIsUpToDate(promptOnFailure)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Alerts
|
// MARK: - Alerts
|
||||||
|
|
||||||
private func presentCouldNotRetrieveUpdate() async {
|
private func presentCouldNotRetrieveUpdate(_ promptOnFailure: Bool) async {
|
||||||
Log.text("Could not retrieve update manifest!")
|
Log.text("Could not retrieve update manifest!")
|
||||||
|
|
||||||
if promptOnFailure {
|
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!")
|
Log.text("Version is up-to-date!")
|
||||||
|
|
||||||
if promptOnFailure {
|
if promptOnFailure {
|
||||||
@ -104,22 +108,30 @@ open class UpdateCheck
|
|||||||
|
|
||||||
let current = AppVersion.fromCurrentVersion()
|
let current = AppVersion.fromCurrentVersion()
|
||||||
|
|
||||||
let outcome = await Alert.choose(
|
let alert = await NVAlert().withInformation(
|
||||||
title: "An updated version of \(Executable.name) is available.",
|
title: "An updated version of \(Executable.name) is available.",
|
||||||
description: """
|
subtitle: "Version \(newerVersion.version) is available for download.",
|
||||||
Version \(newerVersion.version) is available for download.
|
description: "Do you want to download and install this updated version?"
|
||||||
(This is currently version \(current.version).)
|
)
|
||||||
|
.withPrimary(
|
||||||
|
text: "Install",
|
||||||
|
action: { vc in
|
||||||
|
vc.close(with: .OK)
|
||||||
|
self.launchSelfUpdater()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.withTertiary(text: "Dismiss", action: { vc in
|
||||||
|
vc.close(with: .OK)
|
||||||
|
})
|
||||||
|
|
||||||
Do you want to download and install this updated version?
|
if let callback = self.releaseNotesUrlCallback,
|
||||||
""",
|
let url = callback(self.caskFile) {
|
||||||
options: [
|
await alert.withSecondary(text: "View Release Notes") { _ in
|
||||||
"Update Now",
|
NSWorkspace.shared.open(url)
|
||||||
"Cancel"
|
}
|
||||||
])
|
|
||||||
|
|
||||||
if outcome == .alertFirstButtonReturn {
|
|
||||||
launchSelfUpdater()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await alert.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Functional
|
// MARK: - Functional
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct CaskFile {
|
public struct CaskFile {
|
||||||
var properties: [String: String]
|
var properties: [String: String]
|
||||||
|
|
||||||
var name: String { return self.properties["name"]! }
|
var name: String { return self.properties["name"]! }
|
||||||
|
Reference in New Issue
Block a user