Persist and maybe sometimes but sadly not always update the UI

This commit is contained in:
Philipp Heckel 2022-05-18 21:06:16 -04:00
parent 2520ccef65
commit 066be631ec
5 changed files with 39 additions and 87 deletions

View file

@ -4,54 +4,6 @@
type = "1"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "75468F65-9E01-4DF5-A169-07217AF6D1B2"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "ntfyNSE/NotificationService.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "25"
endingLineNumber = "25"
landmarkName = "didReceive(_:withContentHandler:)"
landmarkType = "7">
<Locations>
<Location
uuid = "75468F65-9E01-4DF5-A169-07217AF6D1B2 - 427a5e501e23ebe0"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
symbolName = "ntfyNSE.NotificationService.didReceive(_: __C.UNNotificationRequest, withContentHandler: (__C.UNNotificationContent) -&gt; ()) -&gt; ()"
moduleName = "ntfyNSE"
usesParentBreakpointCondition = "Yes"
urlString = "file:///Users/pheckel/Code/ntfy/ntfyNSE/NotificationService.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "25"
endingLineNumber = "25"
offsetFromSymbolStart = "516">
</Location>
<Location
uuid = "75468F65-9E01-4DF5-A169-07217AF6D1B2 - 427a5e501e23ebe0"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
symbolName = "ntfyNSE.NotificationService.didReceive(_: __C.UNNotificationRequest, withContentHandler: (__C.UNNotificationContent) -&gt; ()) -&gt; ()"
moduleName = "ntfyNSE"
usesParentBreakpointCondition = "Yes"
urlString = "file:///Users/pheckel/Code/ntfy/ntfyNSE/NotificationService.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "25"
endingLineNumber = "25"
offsetFromSymbolStart = "560">
</Location>
</Locations>
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
@ -62,8 +14,8 @@
filePath = "ntfyNSE/NotificationService.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "32"
endingLineNumber = "32"
startingLineNumber = "25"
endingLineNumber = "25"
landmarkName = "didReceive(_:withContentHandler:)"
landmarkType = "7">
</BreakpointContent>

View file

@ -10,6 +10,8 @@ import Firebase
@main
struct AppMain: App {
let tag = "main"
@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate: AppDelegate
@StateObject private var store = Store.shared
@ -21,6 +23,13 @@ struct AppMain: App {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, store.container.viewContext)
.onReceive(NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)) { _ in
// Use this hook instead of applicationDidBecomeActive, see https://stackoverflow.com/a/68888509/1440785
// That post also explains how to start SwiftUI from AppDelegate if that's ever needed.
Log.d(tag, "App became active, refreshing objects")
store.context.refreshAllObjects()
}
}
}
}

View file

@ -1,17 +1,10 @@
//
// DataController.swift
// ntfy
//
// Created by Philipp Heckel on 5/14/22.
//
import Foundation
import CoreData
class Store: ObservableObject {
static let shared = Store()
static let tag = "Store"
let tag = "Store"
let container: NSPersistentContainer
var context: NSManagedObjectContext
@ -19,13 +12,13 @@ class Store: ObservableObject {
let directory = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.io.heckel.ntfy")!
let storeUrl = directory.appendingPathComponent("ntfy.sqlite")
let description = NSPersistentStoreDescription(url: storeUrl)
// Set up container and observe changes from app extension
container = NSPersistentContainer(name: "Model")
container.persistentStoreDescriptions = [description]
container.loadPersistentStores { description, error in
if let error = error {
print("Core Data failed to load: \(error.localizedDescription)")
Log.e(Store.tag, "Core Data failed to load: \(error.localizedDescription)", error)
}
}
@ -56,11 +49,11 @@ class Store: ObservableObject {
let time = userInfo["time"] as? String,
let timeInt = Int64(time),
let message = userInfo["message"] as? String else {
print("Unknown or irrelevant message", userInfo)
Log.d(Store.tag, "Unknown or irrelevant message", userInfo)
return
}
guard let subscription = getSubscription(baseUrl: appBaseUrl, topic: topic) else {
print("Subscription for topic \(topic) unknown")
Log.d(Store.tag, "Subscription for topic \(topic) unknown")
return
}
@ -73,8 +66,8 @@ class Store: ObservableObject {
subscription.addToNotifications(notification)
try context.save()
} catch let error {
Log.w(tag, "Cannot store notification", error)
context.rollback()
Log.w(Store.tag, "Cannot store notification (fromUserInfo)", error)
rollbackAndRefresh()
}
}
@ -88,8 +81,17 @@ class Store: ObservableObject {
subscription.addToNotifications(notification)
try context.save()
} catch let error {
print(error)
context.rollback()
Log.w(Store.tag, "Cannot store notification (fromMessage)", error)
rollbackAndRefresh()
}
}
func rollbackAndRefresh() {
// Hack: We refresh all objects, since failing to store a notification usually means
// that the app extension stored the notification first. This is a way to update the
// UI properly when it is in the foreground and the app extension stores a notification.
context.rollback()
context.refreshAllObjects()
}
}

View file

@ -1,10 +1,3 @@
//
// Subscription.swift
// ntfy
//
// Created by Philipp Heckel on 5/15/22.
//
import Foundation
extension Subscription {
@ -25,6 +18,9 @@ extension Subscription {
}
func notificationsSorted() -> [Notification] {
return notifications!.sortedArray(using: [NSSortDescriptor(key: "time", ascending: false)]) as! [Notification]
if let notifications = notifications {
return notifications.sortedArray(using: [NSSortDescriptor(key: "time", ascending: false)]) as! [Notification]
}
return []
}
}

View file

@ -1,16 +1,11 @@
//
// NotificationService.swift
// ntfyNSE
//
// Created by Philipp Heckel on 5/13/22.
//
import UserNotifications
import CoreData
// https://debashishdas3100.medium.com/save-push-notifications-to-coredata-userdefaults-ios-swift-5-ea074390b57
class NotificationService: UNNotificationServiceExtension {
let tag = "NotificationService"
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
@ -20,15 +15,13 @@ class NotificationService: UNNotificationServiceExtension {
) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
print("NotificationService didReceive")
Log.d(tag, "Notification received (in service)") // Logs from extensions are not printed in Xcode!
if let bestAttemptContent = bestAttemptContent {
bestAttemptContent.title = "\(bestAttemptContent.title) [modified]"
// bestAttemptContent.title = "\(bestAttemptContent.title) [modified]"
let userInfo = bestAttemptContent.userInfo
let store = Store.shared
store.saveNotification(fromUserInfo: userInfo)
Store.shared.saveNotification(fromUserInfo: userInfo)
contentHandler(bestAttemptContent)
}