~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/atirc-ios-client

0
1
main
72 lines · 2.5 KB Raw History
//
//  AskNotifier.swift
//  AT-IRC
//
//  Local notifications for owner questions. True APNs remote push needs a
//  server-side sender and provisioning; polling while the app runs plus a
//  local notification is the shipping scope.
//

import Foundation
import OSLog
import UserNotifications

final class AskNotifier: NSObject, UNUserNotificationCenterDelegate {
    static let shared = AskNotifier()

    private var prepared = false
    private let log = Logger(subsystem: "com.fedfork.irc.AT-IRC", category: "notify")

    private override init() {
        super.init()
        UNUserNotificationCenter.current().delegate = self
    }

    /// Ask once for alert/sound permission; a denial only leaves the in-app
    /// badge and question list. Scripted UI tests set
    /// ATIRC_SKIP_NOTIFICATION_PROMPT=1 so the system alert does not keep the
    /// app from becoming active.
    func prepare() {
        guard !prepared else { return }
        prepared = true
        #if DEBUG
        let skip = ProcessInfo.processInfo.environment["ATIRC_SKIP_NOTIFICATION_PROMPT"] == "1"
        log.notice("prepare skip=\(skip, privacy: .public)")
        if skip {
            return
        }
        #endif
        Task {
            _ = try? await UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge])
        }
    }

    func announce(_ ask: AskQuestion) {
        let content = UNMutableNotificationContent()
        content.title = "Question from \(ask.asker)"
        content.body = ask.question
        content.sound = .default
        content.userInfo = ["askID": ask.id]
        let request = UNNotificationRequest(
            identifier: "atirc.ask.\(ask.id)",
            content: content,
            trigger: nil
        )
        UNUserNotificationCenter.current().add(request)
    }

    /// Drop the notification once the question has been answered or decided.
    func clear(_ askID: String) {
        let identifier = "atirc.ask.\(askID)"
        UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [identifier])
        UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [identifier])
    }

    nonisolated func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        willPresent notification: UNNotification,
        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
    ) {
        completionHandler([.banner, .sound, .list])
    }
}