Files
attendi/Packages/Features/Sources/Notifying/View Models/Notifier.swift
T

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 }
}
}
}