Fixignoring bugs

This commit is contained in:
Max Goedjen 2020-11-12 23:48:56 -08:00
parent 8bbf489146
commit cd0a1b0a68
No known key found for this signature in database
GPG Key ID: E58C21DD77B9B8E8
5 changed files with 74 additions and 23 deletions

View File

@ -4,7 +4,8 @@ import Combine
public protocol UpdaterProtocol: ObservableObject { public protocol UpdaterProtocol: ObservableObject {
var update: Release? { get } var update: Release? { get }
func ignore(release: Release)
} }
public class Updater: ObservableObject, UpdaterProtocol { public class Updater: ObservableObject, UpdaterProtocol {
@ -41,26 +42,15 @@ extension Updater {
func evaluate(release: Release) { func evaluate(release: Release) {
guard !userIgnored(release: release) else { return } guard !userIgnored(release: release) else { return }
let latestVersion = semVer(from: release.name) let latestVersion = SemVer(release.name)
let currentVersion = semVer(from: Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String) let currentVersion = SemVer(Bundle.main.infoDictionary!["CFBundleShortVersionString"] as! String)
for (latest, current) in zip(latestVersion, currentVersion) { if latestVersion > currentVersion {
if latest > current { DispatchQueue.main.async {
DispatchQueue.main.async { self.update = release
self.update = release
}
return
} }
} }
} }
func semVer(from stringVersion: String) -> [Int] {
var split = stringVersion.split(separator: ".").compactMap { Int($0) }
while split.count < 3 {
split.append(0)
}
return split
}
func userIgnored(release: Release) -> Bool { func userIgnored(release: Release) -> Bool {
guard !release.critical else { return false } guard !release.critical else { return false }
return defaults.bool(forKey: release.name) return defaults.bool(forKey: release.name)
@ -71,6 +61,38 @@ extension Updater {
} }
} }
struct SemVer {
let versionNumbers: [Int]
init(_ version: String) {
// Betas have the format 1.2.3_beta1
let strippedBeta = version.split(separator: "_").first!
var split = strippedBeta.split(separator: ".").compactMap { Int($0) }
while split.count < 3 {
split.append(0)
}
versionNumbers = split
}
}
extension SemVer: Comparable {
static func < (lhs: SemVer, rhs: SemVer) -> Bool {
for (latest, current) in zip(lhs.versionNumbers, rhs.versionNumbers) {
if latest < current {
return true
} else if latest > current {
return false
}
}
return false
}
}
extension Updater { extension Updater {
enum Constants { enum Constants {
@ -93,11 +115,18 @@ public struct Release: Codable {
} }
extension Release: Identifiable {
public var id: String {
html_url.absoluteString
}
}
extension Release { extension Release {
public var critical: Bool { public var critical: Bool {
return body.contains(Constants.securityContent) body.contains(Constants.securityContent)
} }
} }

View File

@ -13,7 +13,7 @@ class Notifier {
let updateAction = UNNotificationAction(identifier: Constants.updateActionIdentitifier, title: "Update", options: []) let updateAction = UNNotificationAction(identifier: Constants.updateActionIdentitifier, title: "Update", options: [])
let ignoreAction = UNNotificationAction(identifier: Constants.ignoreActionIdentitifier, title: "Ignore", options: []) let ignoreAction = UNNotificationAction(identifier: Constants.ignoreActionIdentitifier, title: "Ignore", options: [])
let updateCategory = UNNotificationCategory(identifier: Constants.updateCategoryIdentitifier, actions: [updateAction, ignoreAction], intentIdentifiers: [], options: []) let updateCategory = UNNotificationCategory(identifier: Constants.updateCategoryIdentitifier, actions: [updateAction, ignoreAction], intentIdentifiers: [], options: [])
let criticalUpdateCategory = UNNotificationCategory(identifier: Constants.updateCategoryIdentitifier, actions: [updateAction], intentIdentifiers: [], options: []) let criticalUpdateCategory = UNNotificationCategory(identifier: Constants.criticalUpdateCategoryIdentitifier, actions: [updateAction], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([updateCategory, criticalUpdateCategory]) UNUserNotificationCenter.current().setNotificationCategories([updateCategory, criticalUpdateCategory])
UNUserNotificationCenter.current().delegate = notificationDelegate UNUserNotificationCenter.current().delegate = notificationDelegate
} }

View File

@ -16,7 +16,9 @@ class PreviewUpdater: UpdaterProtocol {
self.update = Release(name: "10.10.10", html_url: URL(string: "https://example.com")!, body: "Critical Security Update") self.update = Release(name: "10.10.10", html_url: URL(string: "https://example.com")!, body: "Critical Security Update")
} }
} }
func ignore(release: Release) {
}
} }
extension PreviewUpdater { extension PreviewUpdater {

View File

@ -87,9 +87,13 @@ struct ContentView<UpdaterType: UpdaterProtocol, AgentStatusCheckerType: AgentSt
severity = .advisory severity = .advisory
text = "Update Available" text = "Update Available"
} }
return AnyView(NoticeView(text: text, severity: severity, actionTitle: "Update") { let action = {
NSWorkspace.shared.open(update.html_url) _ = NSWorkspace.shared.open(update.html_url)
}) }
let ignoreAction = {
updater.ignore(release: update)
}
return AnyView(NoticeView(text: text, severity: severity, actionTitle: "Update", action: action, secondaryActionTitle: "Ignore", secondaryAction: ignoreAction))
} }
func agentNotice() -> some View { func agentNotice() -> some View {

View File

@ -7,12 +7,28 @@ struct NoticeView: View {
let severity: Severity let severity: Severity
let actionTitle: String? let actionTitle: String?
let action: (() -> Void)? let action: (() -> Void)?
let secondaryActionTitle: String?
let secondaryAction: (() -> Void)?
public init(text: String, severity: NoticeView.Severity, actionTitle: String?, action: (() -> Void)?, secondaryActionTitle: String? = nil, secondaryAction: (() -> Void)? = nil) {
self.text = text
self.severity = severity
self.actionTitle = actionTitle
self.action = action
self.secondaryActionTitle = secondaryActionTitle
self.secondaryAction = secondaryAction
}
var body: some View { var body: some View {
HStack { HStack {
Text(text).bold() Text(text).bold()
Spacer() Spacer()
if action != nil { if action != nil {
if secondaryAction != nil {
Button(action: secondaryAction!) {
Text(secondaryActionTitle!)
}
}
Button(action: action!) { Button(action: action!) {
Text(actionTitle!) Text(actionTitle!)
} }