Use NVAlert 2.0 with urgency

This commit is contained in:
2025-11-27 13:31:21 +01:00
parent bfe441fb2f
commit aa9658754d
4 changed files with 37 additions and 31 deletions

View File

@@ -1,13 +1,13 @@
{
"originHash" : "0b9d136f905253e9368420218eda771d18cfa528b15553cb08a34c9e5ecdfea7",
"originHash" : "699c69d1c5c91fc14af71a7c0e846526c570ff854487f4866cea7b5caa49b7fe",
"pins" : [
{
"identity" : "nvalert",
"kind" : "remoteSourceControl",
"location" : "https://github.com/nicoverbruggen/NVAlert",
"state" : {
"revision" : "2d649465067e3fc053bc64beed0e2ffea7e1cbe2",
"version" : "1.0.0"
"revision" : "1bbaad37697e4ad4c047eec2a8fc9834c2b5d98a",
"version" : "2.0.0"
}
}
],

View File

@@ -10,7 +10,7 @@ let package = Package(
.library(name: "NVAppUpdater", targets: ["NVAppUpdater"]),
],
dependencies: [
.package(url: "https://github.com/nicoverbruggen/NVAlert", from: "1.0.0")
.package(url: "https://github.com/nicoverbruggen/NVAlert", from: "2.0.0")
],
targets: [
.target(name: "NVAppUpdater", dependencies: ["NVAlert"]),

View File

@@ -68,7 +68,8 @@ await UpdateCheck(
selfUpdaterName: "MyApp Self-Updater.app",
selfUpdaterPath: "~/.config/com.example.my-app/updater",
caskUrl: URL(string: "https://my-app.test/latest/build.rb")!,
).perform(promptOnFailure: true)
isInteractive: true,
).perform()
```
You can also specify what callback needs to be used to determine the correct URL for the release notes. You may need to get some information from the CaskFile, which you are free to source. For example:
@@ -80,11 +81,12 @@ await UpdateCheck(
selfUpdaterName: "MyApp Self-Updater.app",
selfUpdaterPath: "~/.config/com.example.my-app/updater",
caskUrl: URL(string: "https://my-app.test/latest/build.rb")!,
isInteractive: true,
)
.resolvingReleaseNotes(with: { caskFile in
return URL(string: "https://my-app.com/release-notes/\(caskFile.version)")!
})
.perform(promptOnFailure: true)
.perform()
```
## Self-Updater

View File

@@ -42,6 +42,7 @@ open class UpdateCheck
let caskUrl: URL
let selfUpdaterName: String
let selfUpdaterPath: String
let isInteractive: Bool
private var releaseNotesUrlCallback: ((NVCaskFile) -> URL?)? = nil
private var caskFile: NVCaskFile!
@@ -59,15 +60,21 @@ 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.
*
* - Parameter isInteractive: 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
caskUrl: URL,
isInteractive: Bool
) {
self.selfUpdaterName = selfUpdaterName
self.selfUpdaterPath = selfUpdaterPath
self.caskUrl = caskUrl
self.isInteractive = isInteractive
}
/**
@@ -82,15 +89,11 @@ open class UpdateCheck
/**
* 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(promptOnFailure: Bool = true) async {
public func perform() async {
guard let caskFile = NVCaskFile.from(url: caskUrl) else {
Log.text("The contents of the CaskFile at '\(caskUrl.absoluteString)' could not be retrieved.")
return await presentCouldNotRetrieveUpdate(promptOnFailure)
return await presentCouldNotRetrieveUpdate()
}
self.caskFile = caskFile
@@ -99,7 +102,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(promptOnFailure)
return await presentCouldNotRetrieveUpdate()
}
self.newerVersion = onlineVersion
@@ -108,29 +111,19 @@ open class UpdateCheck
Log.text("The current version is v\(currentVersion.computerReadable).")
if onlineVersion > currentVersion {
// A newer version is available
await presentNewerVersionAvailable()
} else if promptOnFailure {
await presentVersionIsUpToDate(promptOnFailure)
} else {
await presentVersionUpToDate()
}
}
// MARK: - Alerts
private func presentCouldNotRetrieveUpdate(_ promptOnFailure: Bool) async {
Log.text("Could not retrieve update manifest!")
private func presentVersionUpToDate() async {
Log.text("Application is up-to-date!")
if promptOnFailure {
await Alert.confirm(
title: translations.couldNotRetrieveUpdateTitle,
description: translations.couldNotRetrieveUpdateDescription
)
}
}
private func presentVersionIsUpToDate(_ promptOnFailure: Bool) async {
Log.text("Version is up-to-date!")
if promptOnFailure {
if isInteractive {
await Alert.confirm(
title: translations.appIsUpToDateTitle
.replacingOccurrences(of: "%@", with: Executable.name),
@@ -139,6 +132,17 @@ open class UpdateCheck
}
}
private func presentCouldNotRetrieveUpdate() async {
Log.text("Could not retrieve update manifest!")
if isInteractive {
await Alert.confirm(
title: translations.couldNotRetrieveUpdateTitle,
description: translations.couldNotRetrieveUpdateDescription
)
}
}
private func presentNewerVersionAvailable() async {
Log.text("A newer version is available!")
@@ -167,7 +171,7 @@ open class UpdateCheck
}
}
await alert.show()
await alert.show(urgency: isInteractive ? .bringToFront : .urgentRequestAttention)
}
// MARK: - Functional