mvm_core_ui/MVMCoreUI/Alerts/AlertHandler.swift
Scott Pfeil 67a0ccfbac revert
2023-04-19 16:44:39 -04:00

103 lines
3.6 KiB
Swift

//
// AlertHandler.swift
// MVMCore
//
// Created by Scott Pfeil on 4/10/23.
// Copyright © 2023 myverizon. All rights reserved.
//
import MVMCore
public class AlertHandler {
/// Returns the handler stored in the CoreUIObject
public static func shared() -> Self {
return MVMCoreActionUtility.fatalClassCheck(object: CoreUIObject.sharedInstance()?.alertHandler)
}
/// The operation queue of alert operations.
private var queue = {
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
return queue
}()
public init() {}
/// Returns if an alert is currently showing in the hierarchy, even if it is not the top presented view.
public func isAlertShowing() -> Bool {
return queue.operations.contains(where: { operation in
return !operation.isCancelled &&
!operation.isFinished &&
operation.isExecuting
})
}
/// Returns if a greedy alert is currently showing in the hierarchy, even if it is not the top presented view.
public func isGreedyAlertShowing() -> Bool {
return queue.operations.contains(where: { operation in
return !operation.isCancelled &&
!operation.isFinished &&
operation.isExecuting &&
(operation as? AlertOperation)?.alertObject.isGreedy ?? false
})
}
@MainActor
public func createAlertController(with alertModel: AlertModel) -> AlertController {
// ActionSheets are not supported on iPad interfaces without a source rect (i.e. a source element) which isn't currently supported for our generic handling.
// TODO: Find a way to support this.
var alertStyle = alertModel.style
if alertStyle == .actionSheet, UIDevice.current.userInterfaceIdiom != .phone {
alertStyle = .alert
}
// Create the alert. Adds the actions one by one.
let alertController = AlertController(title: alertModel.title, message: alertModel.message, preferredStyle: alertStyle)
for action in alertModel.actions {
alertController.addAction(action)
}
return alertController
}
/// Shows an alert using the alert object.
@MainActor
public func queueAlertToShow(with alertObject: AlertObject) -> UIAlertController {
// It's a greedy alert! Clear all alerts that are queued up and the one that is showing
if alertObject.isGreedy {
removeAllAlertViews()
}
let alertController = createAlertController(with: alertObject.alertModel)
let alertOperation = AlertOperation(with: alertController, alertObject: alertObject)
queue.addOperation(alertOperation)
return alertController
}
/// Cancel Alert with ID.
public func cancelAlert(with id: String) {
queue.operations.first { operation in
guard let operation = operation as? AlertOperation,
operation.alertObject.alertModel.id == id else { return false }
return true
}?.cancel()
}
/** Iterates through all scheduled alerts and cancels any that match the provided predicate.
* @param predicate The predicate block to decide whether to cancel an alert.
*/
public func cancelAlert(using predicate: ((AlertObject) -> Bool)) {
for case let operation as AlertOperation in queue.operations {
if predicate(operation.alertObject) {
operation.cancel()
}
}
}
/// Cancels all current alerts
public func removeAllAlertViews() {
queue.cancelAllOperations()
}
}