AzureCommunicationUI/sdk/AzureCommunicationUICalling/Sources/Presentation/SwiftUI/ViewComponents/ToastNotification/BottomToastViewModel.swift (82 lines of code) (raw):
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
import Foundation
final class BottomToastViewModel: ObservableObject, Identifiable {
// The time a bottom toast should be presented for before
// automatically being dismissed.
private static let bottomToastBannerDismissInterval: TimeInterval = 4.0
@Published private(set) var visible = false
@Published private(set) var text: String = ""
@Published private(set) var icon: CompositeIcon?
private let dispatch: ActionDispatch
private var bottomToastDismissTimer: Timer!
private let localizationProvider: LocalizationProviderProtocol
private let accessibilityProvider: AccessibilityProviderProtocol
init(dispatchAction: @escaping ActionDispatch,
localizationProvider: LocalizationProviderProtocol,
accessibilityProvider: AccessibilityProviderProtocol,
toastNotificationState: ToastNotificationState) {
self.dispatch = dispatchAction
self.localizationProvider = localizationProvider
self.accessibilityProvider = accessibilityProvider
update(toastNotificationState: toastNotificationState)
}
func update(toastNotificationState: ToastNotificationState) {
guard let state = toastNotificationState.status else {
dismiss()
return
}
switch state {
case .networkReceiveQuality, .networkSendQuality:
displayNotification(localizationKey: .callDiagnosticsNetworkQualityLow,
icon: .wifiWarning,
isPersistent: false)
case .networkReconnectionQuality:
displayNotification(localizationKey: .callDiagnosticsNetworkReconnect,
icon: .wifiWarning,
isPersistent: true)
case .networkUnavailable, .networkRelaysUnreachable:
displayNotification(localizationKey: .callDiagnosticsNetworkLost,
icon: .wifiWarning,
isPersistent: false)
case .speakingWhileMicrophoneIsMuted:
displayNotification(localizationKey: .callDiagnosticsUserMuted,
icon: .micOff,
isPersistent: false)
case .cameraStartFailed, .cameraStartTimedOut:
displayNotification(localizationKey: .callDiagnosticsCameraNotWorking,
icon: .videoOffRegular,
isPersistent: false)
case .someFeaturesLost:
displayNotification(localizationKey: .callingViewToastFeaturesLost,
icon: .warning,
isPersistent: false)
case .someFeaturesGained:
displayNotification(localizationKey: .callingViewToastFeaturesGained,
icon: .warning,
isPersistent: false)
}
}
private func displayNotification(localizationKey: LocalizationKey,
icon: CompositeIcon,
isPersistent: Bool) {
if !isPersistent {
bottomToastDismissTimer =
Timer.scheduledTimer(withTimeInterval: BottomToastViewModel.bottomToastBannerDismissInterval,
repeats: false) { [weak self] _ in
self?.dismiss()
self?.dispatch(.toastNotificationAction(.dismissNotification))
}
} else {
invalidateTimer()
}
self.visible = true
self.text = localizationProvider.getLocalizedString(localizationKey)
self.icon = icon
// Announce accessibility text when toast appear.
accessibilityProvider.postQueuedAnnouncement(text)
}
private func dismiss() {
visible = false
invalidateTimer()
}
private func invalidateTimer() {
bottomToastDismissTimer?.invalidate()
bottomToastDismissTimer = nil
}
}