diff --git a/Calendr/Assets/Generated/Strings.generated.swift b/Calendr/Assets/Generated/Strings.generated.swift
index d4b119c9..21ec8029 100644
--- a/Calendr/Assets/Generated/Strings.generated.swift
+++ b/Calendr/Assets/Generated/Strings.generated.swift
@@ -10,6 +10,10 @@ import Foundation
// swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
internal enum Strings {
+ /// New version available: %@
+ internal static func newVersion(_ p1: Any) -> String {
+ return Strings.tr("Localizable", "new_version", String(describing: p1), fallback: "New version available: %@")
+ }
/// Localizable.strings
/// Calendr
///
diff --git a/Calendr/Assets/de.lproj/Localizable.strings b/Calendr/Assets/de.lproj/Localizable.strings
index 89a94cab..d20a7693 100644
--- a/Calendr/Assets/de.lproj/Localizable.strings
+++ b/Calendr/Assets/de.lproj/Localizable.strings
@@ -7,6 +7,7 @@
"quit" = "Programm beenden";
"search" = "Suchen";
+"new_version" = "Neue Version verfügbar: %@";
"settings.title" = "Einstellungen";
"settings.tab.general" = "Allgemein";
diff --git a/Calendr/Assets/en.lproj/Localizable.strings b/Calendr/Assets/en.lproj/Localizable.strings
index 1f9045cd..1b50ba3f 100644
--- a/Calendr/Assets/en.lproj/Localizable.strings
+++ b/Calendr/Assets/en.lproj/Localizable.strings
@@ -7,6 +7,7 @@
"quit" = "Quit";
"search" = "Search";
+"new_version" = "New version available: %@";
"settings.title" = "Preferences";
"settings.tab.general" = "General";
diff --git a/Calendr/Assets/es.lproj/Localizable.strings b/Calendr/Assets/es.lproj/Localizable.strings
index 502e1050..180285ec 100644
--- a/Calendr/Assets/es.lproj/Localizable.strings
+++ b/Calendr/Assets/es.lproj/Localizable.strings
@@ -7,6 +7,7 @@
"quit" = "Salir";
"search" = "Buscar";
+"new_version" = "Nueva versión disponible: %@";
"settings.title" = "Preferencias";
"settings.tab.general" = "General";
diff --git a/Calendr/Assets/fr.lproj/Localizable.strings b/Calendr/Assets/fr.lproj/Localizable.strings
index 2433e2fc..1f21fbd0 100644
--- a/Calendr/Assets/fr.lproj/Localizable.strings
+++ b/Calendr/Assets/fr.lproj/Localizable.strings
@@ -7,6 +7,7 @@
"quit" = "Quitter";
"search" = "Rechercher";
+"new_version" = "Nouvelle version disponible: %@";
"settings.title" = "Préférences";
"settings.tab.general" = "Général";
diff --git a/Calendr/Assets/it.lproj/Localizable.strings b/Calendr/Assets/it.lproj/Localizable.strings
index 5251c000..64d5e7ee 100644
--- a/Calendr/Assets/it.lproj/Localizable.strings
+++ b/Calendr/Assets/it.lproj/Localizable.strings
@@ -7,6 +7,7 @@
"quit" = "Esci";
"search" = "Cerca";
+"new_version" = "Nuova versione disponibile: %@";
"settings.title" = "Preferenze";
"settings.tab.general" = "Generali";
diff --git a/Calendr/Assets/pt.lproj/Localizable.strings b/Calendr/Assets/pt.lproj/Localizable.strings
index 7fb93514..eb9d852a 100644
--- a/Calendr/Assets/pt.lproj/Localizable.strings
+++ b/Calendr/Assets/pt.lproj/Localizable.strings
@@ -7,6 +7,7 @@
"quit" = "Sair";
"search" = "Buscar";
+"new_version" = "Nova versão disponível: %@";
"settings.title" = "Preferências";
"settings.tab.general" = "Geral";
diff --git a/Calendr/Config/Calendr.entitlements b/Calendr/Config/Calendr.entitlements
index d9120b5a..498d6171 100644
--- a/Calendr/Config/Calendr.entitlements
+++ b/Calendr/Config/Calendr.entitlements
@@ -6,6 +6,8 @@
com.apple.security.files.user-selected.read-only
+ com.apple.security.network.client
+
com.apple.security.personal-information.calendars
com.apple.security.temporary-exception.apple-events
diff --git a/Calendr/Settings/AboutViewController.swift b/Calendr/Settings/AboutViewController.swift
index 435c2d00..3ef80f8f 100644
--- a/Calendr/Settings/AboutViewController.swift
+++ b/Calendr/Settings/AboutViewController.swift
@@ -6,11 +6,14 @@
//
import Cocoa
+import UserNotifications
-class AboutViewController: NSViewController {
+class AboutViewController: NSViewController, UNUserNotificationCenterDelegate {
private let quitButton: NSButton
private let linkView: NSTextView
+ private let newVersionButton: NSButton
+ private let appVersion = "v\(BuildConfig.appVersion)"
init() {
quitButton = NSButton(title: Strings.quit, target: NSApp, action: #selector(NSApp.terminate))
@@ -26,23 +29,38 @@ class AboutViewController: NSViewController {
linkView.alignment = .center
linkView.height(equalTo: 15)
+ newVersionButton = NSButton()
+
super.init(nibName: nil, bundle: nil)
+ newVersionButton.target = self
+ newVersionButton.action = #selector(openReleasePage)
+ newVersionButton.refusesFirstResponder = true
+ newVersionButton.bezelStyle = .roundRect
+
setUpAccessibility()
+ setUpReleaseCheck()
}
override func loadView() {
+ if let version = UserDefaults.standard.string(forKey: Prefs.lastCheckedVersion), version != appVersion {
+ showNewVersionButton(Strings.newVersion(version))
+ } else {
+ newVersionButton.isHidden = true
+ }
+
view = NSStackView(views: [
Label(text: "Calendr", font: .systemFont(ofSize: 16, weight: .semibold), align: .center),
.spacer(height: 0),
- Label(text: "v\(BuildConfig.appVersion)", font: .systemFont(ofSize: 13), align: .center),
+ Label(text: appVersion, font: .systemFont(ofSize: 13), align: .center),
Label(text: "\(BuildConfig.date) - \(BuildConfig.time)", color: .secondaryLabelColor, align: .center),
.spacer(height: 4),
Label(text: #"¯\_(ツ)_/¯"#, font: .systemFont(ofSize: 16), align: .center),
.spacer(height: 4),
Label(text: "© 2020 - \(BuildConfig.date.suffix(4)) Carlos Enumo", align: .center),
linkView,
+ newVersionButton,
.spacer(height: 4),
quitButton
])
@@ -50,7 +68,7 @@ class AboutViewController: NSViewController {
.with(orientation: .vertical)
}
- func setUpAccessibility() {
+ private func setUpAccessibility() {
guard BuildConfig.isUITesting else { return }
@@ -62,6 +80,84 @@ class AboutViewController: NSViewController {
quitButton.setAccessibilityIdentifier(Accessibility.Settings.About.quitBtn)
}
+ private func setUpReleaseCheck() {
+ UNUserNotificationCenter.current().delegate = self
+ UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { (granted, error) in
+ guard granted else { return }
+ self.checkRelease()
+ DispatchQueue.main.async {
+ Timer.scheduledTimer(
+ withTimeInterval: 60 * 60,
+ repeats: true
+ ) { _ in
+ DispatchQueue.global().async {
+ self.checkRelease()
+ }
+ }
+ }
+ }
+ }
+
+ private func showNewVersionButton(_ title: String) {
+ newVersionButton.title = title
+ newVersionButton.isHidden = false
+ }
+
+ private func checkRelease() {
+ do {
+ let url = "https://api.github.com/repos/pakerwreah/Calendr/releases/latest"
+ let data = try Data(contentsOf: URL(string: url)!)
+ guard
+ let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
+ let version = json["name"] as? String
+ else { return }
+
+ guard version != appVersion else {
+ DispatchQueue.main.async {
+ self.newVersionButton.isHidden = true
+ }
+ UserDefaults.standard.set(version, forKey: Prefs.lastCheckedVersion)
+ return
+ }
+
+ guard version != UserDefaults.standard.string(forKey: Prefs.lastCheckedVersion) else { return }
+
+ let message = Strings.newVersion(version)
+
+ DispatchQueue.main.async {
+ self.showNewVersionButton(message)
+ }
+
+ let content = UNMutableNotificationContent()
+ content.title = message
+ content.sound = .default
+
+ UNUserNotificationCenter.current().add(
+ UNNotificationRequest(
+ identifier: UUID().uuidString,
+ content: content,
+ trigger: nil
+ )
+ ) { error in
+ if let error {
+ print(error.localizedDescription)
+ return
+ }
+ UserDefaults.standard.set(version, forKey: Prefs.lastCheckedVersion)
+ }
+ } catch {
+ print(error.localizedDescription)
+ }
+ }
+
+ @objc private func openReleasePage() {
+ NSWorkspace.shared.open(URL(string: "https://github.com/pakerwreah/Calendr/releases/latest")!)
+ }
+
+ func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async {
+ openReleasePage()
+ }
+
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
diff --git a/Calendr/Settings/Prefs+UserDefaults.swift b/Calendr/Settings/Prefs+UserDefaults.swift
index 45231812..6e2eea09 100644
--- a/Calendr/Settings/Prefs+UserDefaults.swift
+++ b/Calendr/Settings/Prefs+UserDefaults.swift
@@ -26,6 +26,7 @@ enum Prefs {
static let transparencyLevel = "transparency_level"
static let calendarScaling = "calendar_scaling"
static let highlightedWeekdays = "highlighted_weekdays"
+ static let lastCheckedVersion = "last_checked_version"
}
extension UserDefaults {