parent
86825d667f
commit
6ebaedd641
@ -0,0 +1,35 @@ |
||||
// |
||||
// AppDelegate.swift |
||||
// LeCountdown |
||||
// |
||||
// Created by Laurent Morvillier on 24/01/2023. |
||||
// |
||||
|
||||
import Foundation |
||||
import UIKit |
||||
|
||||
class AppDelegate : NSObject, UIApplicationDelegate { |
||||
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { |
||||
|
||||
UNUserNotificationCenter.current().delegate = self |
||||
|
||||
return true |
||||
} |
||||
|
||||
} |
||||
|
||||
extension AppDelegate: UNUserNotificationCenterDelegate { |
||||
|
||||
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async { |
||||
print("didReceive response") |
||||
} |
||||
|
||||
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { |
||||
print("willPresent notification") |
||||
completionHandler([.banner, .sound]) |
||||
AppEnvironment.sun.clearNotificationDate() |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,95 @@ |
||||
// |
||||
// CountdownScheduler.swift |
||||
// Countdown |
||||
// |
||||
// Created by Laurent Morvillier on 15/01/2023. |
||||
// |
||||
|
||||
import Foundation |
||||
import UserNotifications |
||||
|
||||
class CountdownScheduler { |
||||
|
||||
static let master = CountdownScheduler() |
||||
|
||||
func scheduleIfPossible(duration: Double, handler: @escaping (Result<Date?, Error>) -> Void) { |
||||
|
||||
UNUserNotificationCenter.current().getPendingNotificationRequests { requests in |
||||
self.cancel() |
||||
self._scheduleCountdownNotification(duration: duration, handler: handler) |
||||
} |
||||
|
||||
} |
||||
|
||||
func cancel() { |
||||
UNUserNotificationCenter.current().removeAllPendingNotificationRequests() |
||||
AppEnvironment.sun.clearNotificationDate() |
||||
} |
||||
|
||||
fileprivate func _scheduleCountdownNotification(duration: Double, handler: @escaping (Result<Date?, Error>) -> Void) { |
||||
let content = UNMutableNotificationContent() |
||||
content.title = NSLocalizedString("It's time!", comment: "") |
||||
|
||||
let minutes = duration / 60.0 |
||||
|
||||
let minutesLabel = minutes > 1 ? NSLocalizedString("minutes", comment: "") : NSLocalizedString("minute", comment: "") |
||||
let isOrAre = minutes > 1 ? NSLocalizedString("are", comment: "") : NSLocalizedString("is", comment: "") |
||||
|
||||
content.body = NSLocalizedString("The \(minutes) \(minutesLabel) \(isOrAre) over!", comment: "") |
||||
content.sound = UNNotificationSound.defaultCritical |
||||
|
||||
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: duration, repeats: false) |
||||
let request = UNNotificationRequest(identifier: "com.staxriver.countdown", content: content, trigger: trigger) |
||||
UNUserNotificationCenter.current().add(request) { error in |
||||
if let error { |
||||
handler(.failure(error)) |
||||
print("Scheduling error = \(error)") |
||||
} else { |
||||
if let date = trigger.nextTriggerDate() { |
||||
AppEnvironment.sun.saveNotificationDate(date) |
||||
handler(.success(trigger.nextTriggerDate())) |
||||
} else { |
||||
let backupDate = Date().addingTimeInterval(duration) |
||||
AppEnvironment.sun.saveNotificationDate(backupDate) |
||||
} |
||||
} |
||||
} |
||||
|
||||
print("SCHEDULED @ \(Date())") |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
class AppEnvironment : ObservableObject { |
||||
|
||||
static let sun: AppEnvironment = AppEnvironment() |
||||
|
||||
init() { |
||||
self.notificationDate = UserDefaults.standard.value(forKey: Key.date.rawValue) as? Date |
||||
} |
||||
|
||||
@Published var notificationDate: Date? = nil { |
||||
didSet { |
||||
UserDefaults.standard.set(notificationDate, forKey: Key.date.rawValue) |
||||
} |
||||
} |
||||
|
||||
enum Key : String { |
||||
case date |
||||
} |
||||
|
||||
var hasNotificationDate: Bool { |
||||
return self.notificationDate != nil |
||||
} |
||||
|
||||
func saveNotificationDate(_ date: Date) { |
||||
self.notificationDate = date |
||||
} |
||||
|
||||
func clearNotificationDate() { |
||||
self.notificationDate = nil |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,27 @@ |
||||
// |
||||
// NSManagedContext+Extensions.swift |
||||
// LeCountdown |
||||
// |
||||
// Created by Laurent Morvillier on 24/01/2023. |
||||
// |
||||
|
||||
import Foundation |
||||
import CoreData |
||||
|
||||
extension NSManagedObjectContext { |
||||
|
||||
func object(stringId: String) -> NSManagedObject? { |
||||
guard let url = URL(string: stringId) else { return nil } |
||||
guard let objectId = PersistenceController.shared.container.persistentStoreCoordinator.managedObjectID(forURIRepresentation: url) else { return nil } |
||||
return self.object(with: objectId) |
||||
} |
||||
|
||||
} |
||||
|
||||
extension NSManagedObject { |
||||
|
||||
var isTemporary: Bool { |
||||
return self.objectID.isTemporaryID |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue