mvm_core_ui/MVMCoreUI/Alerts/AlertHandler.swift
2023-05-03 12:59:12 -04:00

97 lines
3.5 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: AlertModelProtocol) -> 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.preferredStyle
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)
}
if let index = alertModel.preferredActionIndex {
alertController.preferredAction = alertModel.actions[index]
}
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
}
/** 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()
}
}