Skip to content

Commit

Permalink
clean up
Browse files Browse the repository at this point in the history
  • Loading branch information
pelumy committed Jan 9, 2025
1 parent c49006f commit dd9e6b4
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 60 deletions.
33 changes: 12 additions & 21 deletions Nos/Models/CoreData/NosNotification+CoreDataClass.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,15 @@ public class NosNotification: NosManagedObject {
} else {
let notification = NosNotification(context: context)
notification.eventID = eventID
notification.user = author
notification.createdAt = date
notification.user = author
// Only set follower relationship if this is a follow event
if let event = Event.find(by: eventID, context: context) {
if event.kind == EventKind.contactList.rawValue {
notification.follower = event.author
}
}

return notification
}
}
Expand All @@ -32,7 +39,7 @@ public class NosNotification: NosManagedObject {
if let notification = try context.fetch(fetchRequest).first {
return notification
}

return nil
}

Expand All @@ -43,13 +50,13 @@ public class NosNotification: NosManagedObject {
fetchRequest.sortDescriptors = [NSSortDescriptor(keyPath: \NosNotification.eventID, ascending: false)]
return fetchRequest
}

static func unreadCount(in context: NSManagedObjectContext) throws -> Int {
let fetchRequest = NSFetchRequest<NosNotification>(entityName: String(describing: NosNotification.self))
fetchRequest.predicate = NSPredicate(format: "isRead != 1")
return try context.count(for: fetchRequest)
}

// TODO: user is unused; is this a bug?
static func markAllAsRead(in context: NSManagedObjectContext) async throws {
try await context.perform {
Expand All @@ -59,7 +66,7 @@ public class NosNotification: NosManagedObject {
for notification in unreadNotifications {
notification.isRead = true
}

try? context.saveIfNeeded()
}
}
Expand Down Expand Up @@ -99,22 +106,6 @@ public class NosNotification: NosManagedObject {
if let limit {
fetchRequest.fetchLimit = limit
}

// A notification for the user
let forUserPredicate = NSPredicate(format: "user = %@", user)
// User is being followed
let isFollowPredicate = NSPredicate(format: "follower != nil")

var predicates: [NSPredicate] = [
NSCompoundPredicate(orPredicateWithSubpredicates: [forUserPredicate, isFollowPredicate])
]

if let since {
predicates.append(NSPredicate(format: "createdAt >= %@", since as CVarArg))
}

// fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates)

return fetchRequest
}
}
78 changes: 39 additions & 39 deletions Nos/Service/PushNotificationService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import Combine
/// all new events and creates `NosNotification`s and displays them when appropriate.
@MainActor @Observable class PushNotificationService:
NSObject, NSFetchedResultsControllerDelegate, UNUserNotificationCenterDelegate {

// MARK: - Public Properties

/// The number of unread notifications that should be displayed as a badge
private(set) var badgeCount = 0

Expand All @@ -37,60 +37,60 @@ import Combine
userDefaults.set(newValue.timeIntervalSince1970, forKey: showPushNotificationsAfterKey)
}
}

// MARK: - Private Properties

@ObservationIgnored @Dependency(\.relayService) private var relayService
@ObservationIgnored @Dependency(\.persistenceController) private var persistenceController
@ObservationIgnored @Dependency(\.router) private var router
@ObservationIgnored @Dependency(\.analytics) private var analytics
@ObservationIgnored @Dependency(\.crashReporting) private var crashReporting
@ObservationIgnored @Dependency(\.userDefaults) private var userDefaults
@ObservationIgnored @Dependency(\.currentUser) private var currentUser

private var notificationWatcher: NSFetchedResultsController<Event>?
private var relaySubscription: SubscriptionCancellable?
private var currentAuthor: Author?
@ObservationIgnored private lazy var modelContext = persistenceController.newBackgroundContext()

@ObservationIgnored private lazy var registrar = PushNotificationRegistrar()

// MARK: - Setup

func listen(for user: CurrentUser) async {
relaySubscription = nil

guard let author = user.author,
let authorKey = author.hexadecimalPublicKey else {
let authorKey = author.hexadecimalPublicKey else {

Check failure on line 64 in Nos/Service/PushNotificationService.swift

View workflow job for this annotation

GitHub Actions / swift_lint

Code should be indented using one tab or 4 spaces (indentation_width)
notificationWatcher = NSFetchedResultsController(
fetchRequest: Event.emptyRequest(),
fetchRequest: Event.emptyRequest(),
managedObjectContext: modelContext,
sectionNameKeyPath: nil,
cacheName: nil
)
return
}

currentAuthor = author
notificationWatcher = NSFetchedResultsController(
fetchRequest: Event.all(notifying: author, since: showPushNotificationsAfter),
fetchRequest: Event.all(notifying: author, since: showPushNotificationsAfter),
managedObjectContext: modelContext,
sectionNameKeyPath: nil,
cacheName: nil
)
notificationWatcher?.delegate = self
await modelContext.perform { [weak self] in
do {
do {
try self?.notificationWatcher?.performFetch()
} catch {
Log.error("Error watching notifications:")
self?.crashReporting.report(error)
}
}

let userMentionsFilter = Filter(
kinds: [.text],
pTags: [authorKey],
kinds: [.text],
pTags: [authorKey],
limit: 50,
keepSubscriptionOpen: true
)
Expand All @@ -99,18 +99,18 @@ import Combine
)

await updateBadgeCount()

do {
try await registrar.register(user, context: modelContext)
} catch {
Log.optional(error, "failed to register for push notifications")
}
}

func registerForNotifications(_ user: CurrentUser, with deviceToken: Data) async throws {
try await registrar.register(user, with: deviceToken, context: modelContext)
}

// MARK: - Helpers

func requestNotificationPermissionsFromUser() {
Expand All @@ -124,7 +124,7 @@ import Combine
}
}
}

/// Recomputes the number of unread notifications for the `currentAuthor`, publishes the new value to
/// `badgeCount`, and updates the application badge icon.
func updateBadgeCount() async {
Expand All @@ -134,22 +134,22 @@ import Combine
(try? NosNotification.unreadCount(in: self.modelContext)) ?? 0
}
}

self.badgeCount = badgeCount
try? await UNUserNotificationCenter.current().setBadgeCount(badgeCount)
}

// MARK: - Internal
/// Tells the system to display a notification for the given event if it's appropriate. This will create a
/// NosNotification record in the database.
@MainActor private func showNotificationIfNecessary(for eventID: RawEventID) async {
guard let authorKey = currentAuthor?.hexadecimalPublicKey else {
return
}

let viewModel: NotificationViewModel? = await modelContext.perform { () -> NotificationViewModel? in
guard let event = Event.find(by: eventID, context: self.modelContext),
let eventCreated = event.createdAt else {
let eventCreated = event.createdAt else {

Check failure on line 152 in Nos/Service/PushNotificationService.swift

View workflow job for this annotation

GitHub Actions / swift_lint

Code should be indented using one tab or 4 spaces (indentation_width)
return nil
}

Expand All @@ -170,14 +170,14 @@ import Combine
eventCreated: eventCreated
)
}

if let viewModel {
// Leave an hour of margin on the showPushNotificationsAfter date to allow for events arriving slightly
// Leave an hour of margin on the showPushNotificationsAfter date to allow for events arriving slightly
// out of order.
guard let date = viewModel.date else { return }
showPushNotificationsAfter = date.addingTimeInterval(-60 * 60)
await viewModel.loadContent(in: self.persistenceController.backgroundViewContext)

do {
try await UNUserNotificationCenter.current().add(viewModel.notificationCenterRequest)
await updateBadgeCount()
Expand Down Expand Up @@ -244,7 +244,7 @@ import Combine

// Don't alert for old notifications or muted authors
guard eventCreated > self.showPushNotificationsAfter,
event.author?.muted == false else {
event.author?.muted == false else {

Check failure on line 247 in Nos/Service/PushNotificationService.swift

View workflow job for this annotation

GitHub Actions / swift_lint

Code should be indented using one tab or 4 spaces (indentation_width)
coreDataNotification.isRead = true
return nil
}
Expand All @@ -257,15 +257,15 @@ import Combine
}

// MARK: - UNUserNotificationCenterDelegate

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async {
if response.actionIdentifier == UNNotificationDefaultActionIdentifier {
analytics.tappedNotification()

let userInfo = response.notification.request.content.userInfo
if let eventID = userInfo["eventID"] as? String,
!eventID.isEmpty {
!eventID.isEmpty {

Check failure on line 267 in Nos/Service/PushNotificationService.swift

View workflow job for this annotation

GitHub Actions / swift_lint

Code should be indented using one tab or 4 spaces (indentation_width)

Task { @MainActor in
if let follower = try? Author.find(by: eventID, context: self.persistenceController.viewContext) {
self.router.selectedTab = .notifications
Expand All @@ -278,17 +278,17 @@ import Combine
}
}
}

func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification
) async -> UNNotificationPresentationOptions {
analytics.displayedNotification()
return [.list, .banner, .badge, .sound]
}

// MARK: - NSFetchedResultsControllerDelegate

nonisolated func controller(
_ controller: NSFetchedResultsController<NSFetchRequestResult>,
didChange anObject: Any,
Expand All @@ -299,12 +299,12 @@ import Combine
guard type == .insert else {
return
}

guard let event = anObject as? Event,
let eventID = event.identifier else {
let eventID = event.identifier else {

Check failure on line 304 in Nos/Service/PushNotificationService.swift

View workflow job for this annotation

GitHub Actions / swift_lint

Code should be indented using one tab or 4 spaces (indentation_width)
return
}

Task { await showNotificationIfNecessary(for: eventID) }
}

Expand Down

0 comments on commit dd9e6b4

Please sign in to comment.