66 lines
1.9 KiB
Swift
66 lines
1.9 KiB
Swift
import Accessibility
|
|
import Foundation
|
|
import Observation
|
|
|
|
/// The observable model that owns the lifecycle of the transient in-app notifications.
|
|
///
|
|
/// Posting a notification appends it to ``notifications``, announces its message to assistive technologies — since the visual
|
|
/// banners are transient — and schedules its automatic dismissal a few seconds later, which is the only way a notification is
|
|
/// dismissed.
|
|
@MainActor
|
|
@Observable
|
|
public final class Notifier {
|
|
|
|
// MARK: Properties
|
|
|
|
/// The notifications currently presented, in post order.
|
|
public private(set) var notifications: [AppNotification] = []
|
|
|
|
/// The time a posted notification stays visible before its automatic dismissal.
|
|
@ObservationIgnored
|
|
private let delayDismissal: Duration
|
|
|
|
// MARK: Initializers
|
|
|
|
/// Creates a notifier.
|
|
///
|
|
/// - Parameter delayDismissal: The time a posted notification stays visible before its automatic dismissal.
|
|
/// Defaults to four seconds.
|
|
public init(
|
|
delayDismissal: Duration = .seconds(4)
|
|
) {
|
|
self.delayDismissal = delayDismissal
|
|
}
|
|
|
|
// MARK: Methods
|
|
|
|
/// Posts a notification, announcing its message to assistive technologies and scheduling its automatic dismissal.
|
|
///
|
|
/// - Parameters:
|
|
/// - kind: The kind of the notification.
|
|
/// - message: The localized message of the notification.
|
|
/// - symbol: The system symbol of the notification's icon.
|
|
public func post(
|
|
_ kind: AppNotification.Kind,
|
|
message: String,
|
|
symbol: String
|
|
) {
|
|
let notification = AppNotification(
|
|
kind: kind,
|
|
message: message,
|
|
symbol: symbol
|
|
)
|
|
|
|
notifications.append(notification)
|
|
|
|
AccessibilityNotification.Announcement(message).post()
|
|
|
|
Task {
|
|
try? await Task.sleep(for: delayDismissal)
|
|
|
|
notifications.removeAll { $0.id == notification.id }
|
|
}
|
|
}
|
|
|
|
}
|