Rearrange how UIAlertActions are generated by splitting out the legacy model and using a protocol to drive.
This commit is contained in:
parent
14117c84a6
commit
cc9a39e599
@ -44,10 +44,10 @@ public class AlertHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
public func createAlertController(with alertModel: AlertModel) -> AlertController {
|
public func createAlertController(with alertModel: AlertModelProtocol, additionalData: [AnyHashable: Any]? = nil, delegateObject: DelegateObject? = nil) -> 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.
|
// 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.
|
// TODO: Find a way to support this.
|
||||||
var alertStyle = alertModel.style
|
var alertStyle = alertModel.preferredStyle
|
||||||
if alertStyle == .actionSheet, UIDevice.current.userInterfaceIdiom != .phone {
|
if alertStyle == .actionSheet, UIDevice.current.userInterfaceIdiom != .phone {
|
||||||
alertStyle = .alert
|
alertStyle = .alert
|
||||||
}
|
}
|
||||||
@ -57,12 +57,15 @@ public class AlertHandler {
|
|||||||
for action in alertModel.actions {
|
for action in alertModel.actions {
|
||||||
alertController.addAction(action)
|
alertController.addAction(action)
|
||||||
}
|
}
|
||||||
|
if let index = alertModel.preferredActionIndex {
|
||||||
|
alertController.preferredAction = alertModel.actions[index]
|
||||||
|
}
|
||||||
return alertController
|
return alertController
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shows an alert using the alert object.
|
/// Shows an alert using the alert object.
|
||||||
@MainActor
|
@MainActor
|
||||||
public func queueAlertToShow(with alertObject: AlertObject) -> UIAlertController {
|
public func queueAlertToShow(with alertObject: AlertObject, additionalData: [AnyHashable: Any]? = nil, delegateObject: DelegateObject? = nil) -> UIAlertController {
|
||||||
|
|
||||||
// It's a greedy alert! Clear all alerts that are queued up and the one that is showing
|
// It's a greedy alert! Clear all alerts that are queued up and the one that is showing
|
||||||
if alertObject.isGreedy {
|
if alertObject.isGreedy {
|
||||||
@ -75,15 +78,6 @@ public class AlertHandler {
|
|||||||
return alertController
|
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.
|
/** 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.
|
* @param predicate The predicate block to decide whether to cancel an alert.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -8,6 +8,14 @@
|
|||||||
|
|
||||||
import MVMCore
|
import MVMCore
|
||||||
|
|
||||||
|
public protocol AlertModelProtocol {
|
||||||
|
var title: String? { get }
|
||||||
|
var message: String? { get }
|
||||||
|
var actions: [UIAlertAction] { get }
|
||||||
|
var preferredActionIndex: Int? { get }
|
||||||
|
var preferredStyle: UIAlertController.Style { get }
|
||||||
|
}
|
||||||
|
|
||||||
/// An object with properties for managing the alert.
|
/// An object with properties for managing the alert.
|
||||||
public struct AlertObject {
|
public struct AlertObject {
|
||||||
|
|
||||||
@ -15,11 +23,11 @@ public struct AlertObject {
|
|||||||
public var isGreedy = false
|
public var isGreedy = false
|
||||||
|
|
||||||
/// The alert model for the alert to show.
|
/// The alert model for the alert to show.
|
||||||
public var alertModel: AlertModel
|
public var alertModel: AlertModelProtocol
|
||||||
|
|
||||||
public weak var alertDelegate: AlertDelegateProtocol?
|
public weak var alertDelegate: AlertDelegateProtocol?
|
||||||
|
|
||||||
public init(alertModel: AlertModel, isGreedy: Bool = false, alertDelegate: AlertDelegateProtocol? = nil) {
|
public init(alertModel: AlertModelProtocol, isGreedy: Bool = false, alertDelegate: AlertDelegateProtocol? = nil) {
|
||||||
self.alertModel = alertModel
|
self.alertModel = alertModel
|
||||||
self.isGreedy = isGreedy
|
self.isGreedy = isGreedy
|
||||||
self.alertDelegate = alertDelegate
|
self.alertDelegate = alertDelegate
|
||||||
|
|||||||
@ -17,6 +17,7 @@ public struct AlertButtonModel: Codable {
|
|||||||
public var title: String
|
public var title: String
|
||||||
public var action: ActionModelProtocol
|
public var action: ActionModelProtocol
|
||||||
public var style: UIAlertAction.Style = .default
|
public var style: UIAlertAction.Style = .default
|
||||||
|
public var preferred: Bool = false
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Initializer
|
// MARK: - Initializer
|
||||||
@ -36,6 +37,7 @@ public struct AlertButtonModel: Codable {
|
|||||||
case title
|
case title
|
||||||
case action
|
case action
|
||||||
case style
|
case style
|
||||||
|
case preferred
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -50,6 +52,7 @@ public struct AlertButtonModel: Codable {
|
|||||||
self.style = UIAlertAction.Style(rawValue: style)
|
self.style = UIAlertAction.Style(rawValue: style)
|
||||||
}
|
}
|
||||||
action = try typeContainer.decodeModel(codingKey: .action)
|
action = try typeContainer.decodeModel(codingKey: .action)
|
||||||
|
preferred = try typeContainer.decodeIfPresent(Bool.self, forKey: .preferred) ?? false
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
@ -57,42 +60,51 @@ public struct AlertButtonModel: Codable {
|
|||||||
try container.encode(title, forKey: .title)
|
try container.encode(title, forKey: .title)
|
||||||
try container.encode(style.rawValueString, forKey: .style)
|
try container.encode(style.rawValueString, forKey: .style)
|
||||||
try container.encodeModel(action, forKey: .action)
|
try container.encodeModel(action, forKey: .action)
|
||||||
|
try container.encodeIfPresent(preferred, forKey: .preferred)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct AlertModel: Codable, Identifiable {
|
public struct AlertModel: Codable, Identifiable, AlertModelProtocol {
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public var title: String
|
public var title: String?
|
||||||
public var message: String
|
public var message: String?
|
||||||
public var style: UIAlertController.Style = .alert
|
public var preferredStyle: UIAlertController.Style = .alert
|
||||||
public var actions: [UIAlertAction]
|
public var buttonModels: [AlertButtonModel]
|
||||||
public var buttonModels: [AlertButtonModel]?
|
|
||||||
public var analyticsData: JSONValueDictionary?
|
public var analyticsData: JSONValueDictionary?
|
||||||
public var id: String
|
public var id: String
|
||||||
|
|
||||||
|
public var delegateObject: DelegateObject?
|
||||||
|
|
||||||
|
public var actions: [UIAlertAction] {
|
||||||
|
get {
|
||||||
|
buttonModels.map({ alertButtonModel in
|
||||||
|
return alertButtonModel.generateAction(delegateObject: delegateObject)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public var preferredActionIndex: Int? {
|
||||||
|
get {
|
||||||
|
buttonModels.firstIndex(where: { alertButtonModel in
|
||||||
|
return alertButtonModel.preferred
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Init
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public init(title: String, message: String, actions: [UIAlertAction], style: UIAlertController.Style = .alert, id: String = UUID().uuidString) {
|
|
||||||
self.title = title
|
|
||||||
self.message = message
|
|
||||||
self.actions = actions
|
|
||||||
self.style = style
|
|
||||||
self.id = id
|
|
||||||
}
|
|
||||||
|
|
||||||
public init(title: String, message: String, buttonModels: [AlertButtonModel], style: UIAlertController.Style = .alert, delegateObject: DelegateObject?, id: String = UUID().uuidString) {
|
public init(title: String, message: String, buttonModels: [AlertButtonModel], style: UIAlertController.Style = .alert, delegateObject: DelegateObject?, id: String = UUID().uuidString) {
|
||||||
self.title = title
|
self.title = title
|
||||||
self.message = message
|
self.message = message
|
||||||
self.buttonModels = buttonModels
|
self.buttonModels = buttonModels
|
||||||
actions = buttonModels.map({ alertButtonModel in
|
self.preferredStyle = style
|
||||||
return alertButtonModel.generateAction(delegateObject: delegateObject)
|
|
||||||
})
|
|
||||||
self.style = style
|
|
||||||
self.id = id
|
self.id = id
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,17 +127,14 @@ public struct AlertModel: Codable, Identifiable {
|
|||||||
|
|
||||||
public init(from decoder: Decoder) throws {
|
public init(from decoder: Decoder) throws {
|
||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
let delegateObject = try decoder.get()
|
delegateObject = try decoder.get()
|
||||||
title = try typeContainer.decode(String.self, forKey: .title)
|
title = try typeContainer.decode(String.self, forKey: .title)
|
||||||
message = try typeContainer.decode(String.self, forKey: .message)
|
message = try typeContainer.decode(String.self, forKey: .message)
|
||||||
buttonModels = try typeContainer.decode([AlertButtonModel].self, forKey: .alertActions)
|
buttonModels = try typeContainer.decode([AlertButtonModel].self, forKey: .alertActions)
|
||||||
actions = buttonModels!.map({ alertButtonModel in
|
|
||||||
return alertButtonModel.generateAction(delegateObject: delegateObject)
|
|
||||||
})
|
|
||||||
analyticsData = try typeContainer.decodeIfPresent(JSONValueDictionary.self, forKey: .analyticsData)
|
analyticsData = try typeContainer.decodeIfPresent(JSONValueDictionary.self, forKey: .analyticsData)
|
||||||
|
|
||||||
if let style = try typeContainer.decodeIfPresent(String.self, forKey: .style) {
|
if let style = try typeContainer.decodeIfPresent(String.self, forKey: .style) {
|
||||||
self.style = UIAlertController.Style(rawValue: style)
|
self.preferredStyle = UIAlertController.Style(rawValue: style)
|
||||||
}
|
}
|
||||||
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
|
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
|
||||||
}
|
}
|
||||||
@ -135,7 +144,7 @@ public struct AlertModel: Codable, Identifiable {
|
|||||||
try container.encode(title, forKey: .title)
|
try container.encode(title, forKey: .title)
|
||||||
try container.encode(message, forKey: .message)
|
try container.encode(message, forKey: .message)
|
||||||
try container.encodeIfPresent(buttonModels, forKey: .alertActions)
|
try container.encodeIfPresent(buttonModels, forKey: .alertActions)
|
||||||
try container.encode(style.rawValueString, forKey: .style)
|
try container.encode(preferredStyle.rawValueString, forKey: .style)
|
||||||
try container.encodeIfPresent(analyticsData, forKey: .analyticsData)
|
try container.encodeIfPresent(analyticsData, forKey: .analyticsData)
|
||||||
try container.encode(id, forKey: .id)
|
try container.encode(id, forKey: .id)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user