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