import Foundation
import ThreemaMacros
public final class UIAlertTemplate: NSObject {
@objc public static func showOKAlert(
owner: UIViewController,
title: String?,
message: String?,
actionOk: ((UIAlertAction) -> Void)? = nil
) {
showOKAlert(owner: owner, title: title, message: message, titleOk: nil, actionOk: actionO k)
}
@objc public static func showOKAlert(
owner: UIViewController,
title: String?,
message: String?,
titleOk: String? = nil,
actionOk: ((UIAlertAction) -> Void)? = nil
) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let ok = titleOk ?? #localize("ok")
alert
.addAction(UIAlertAction(
title: ok,
style: .default,
handler: actionOk
))
owner.present(alert, animated: true)
}
@objc public static func showAlert(
owner: UIViewController,
title: String?,
message: String?,
titleOk: String,
actionOk: ((UIAlertAction) -> Void)? = nil,
titleCancel: String? = nil,
actionCancel: ((UIAlertAction) -> Void)? = nil
) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: titleOk, style: .default, handler: actionOk))
let cancelTitle = resolveCancelTitle(with: titleCancel)
alert.addAction(UIAlertAction(title: cancelTitle, style: .cancel, handler: actionCancel))
owner.present(alert, animated: true)
}
public static func showDestructiveAlert(
owner: UIViewController,
title: String?,
message: String?,
titleDestructive: String,
actionDestructive: @escaping ((UIAlertAction) -> Void),
titleCancel: String? = nil,
actionCancel: ((UIAlertAction) -> Void)? = nil
) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let cancelTitle = resolveCancelTitle(with: titleCancel)
alert.addAction(UIAlertAction(title: cancelTitle, style: .cancel, handler: actionCancel))
alert.addAction(UIAlertAction(title: titleDestructive, style: .destructive, handler: actionDestructive))
owner.present(alert, animated: true)
}
public static func showConfirm(
owner: UIViewController,
popOverSource: UIView,
title: String,
message: String?,
titleOk: String,
actionOk: ((UIAlertAction) -> Void)? = nil,
titleCancel: String,
actionCancel: ((UIAlertAction) -> Void)? = nil
) {
let confirm = UIAlertController(
title: title,
message: message,
preferredStyle: UIAlertController.Style.actionSheet
)
confirm.addAction(UIAlertAction(title: titleCancel, style: .cancel, handler: actionCancel))
confirm.addAction(UIAlertAction(title: titleOk, style: .destructive, handler: actionOk))
let popOver = confirm.popoverPresentationController
popOver?.sourceView = popOverSource
popOver?.permittedArrowDirections = .any
owner.present(confirm, animated: true)
}
public static func showConfirm(
title: String,
message: String? = nil,
titleOk: String,
on viewController: UIViewController,
action: @escaping () -> Void
) {
guard let view = viewController.view else {
return
}
showConfirm(
owner: viewController,
popOverSource: view,
title: title,
message: message,
titleOk: titleOk,
actionOk: { _ in
action()
},
titleCancel: #localize("cancel")
)
}
/// Show an action sheet
///
/// See HIG for guidance: <https://developer.apple.com/design/human-interface-guidelines/ios/views/action-sheets/>
///
/// - Parameters:
/// - owner: View Controller to present sheet on
/// - popOverSource: Origin view of sheet (i.e. table view cell, ...)
/// - title: Optional title shown in sheet
/// - message: Optional message shown in sheet
/// - actions: Actions shown in this order (put destructive actions at the beginning)
/// - cancelTitle: Custom title for cancel button (normally not needed)
/// - cancelAction: Custom action for cancel button
public static func showSheet(
owner: UIViewController,
popOverSource: UIView,
title: String? = nil,
message: String? = nil,
actions: [UIAlertAction],
cancelTitle: String? = nil,
cancelAction: ((UIAlertAction) -> Void)? = nil
) {
// Because a title without a message gets formatted as a message, but a message without a
// title like a title we switch them if we have no message.
var title = title
var message = message
if message == nil {
message = title
title = nil
}
let actionSheet = UIAlertController(title: title, message: message, preferredStyle: .actionSheet)
actionSheet.popoverPresentationController?.sourceView = popOverSource
actionSheet.popoverPresentationController?.sourceRect = popOverSource.bounds
show(
actionSheet: actionSheet,
owner: owner,
actions: actions,
cancelTitle: cancelTitle,
cancelAction: cancelAction
)
}
/// Show an action sheet
///
/// See HIG for guidance: <https://developer.apple.com/design/human-interface-guidelines/ios/views/action-sheets/>
///
/// - Parameters:
/// - owner: View Controller to present sheet on
/// - popOverSource: Origin `UIBarButtonItem` of sheet
/// - title: Optional title shown in sheet
/// - message: Optional message shown in sheet
/// - actions: Actions shown in this order (put destructive actions at the beginning)
/// - cancelTitle: Custom title for cancel button (normally not needed)
/// - cancelAction: Custom action for cancel button
public static func showSheet(
owner: UIViewController,
popOverSource: UIBarButtonItem,
title: String? = nil,
message: String? = nil,
actions: [UIAlertAction],
cancelTitle: String? = nil,
cancelAction: ((UIAlertAction) -> Void)? = nil
) {
// Because a title without a message gets formatted as a message, but a message without a
// title like a title we switch them if we have no message.
var title = title
var message = message
if message == nil {
message = title
title = nil
}
let actionSheet = UIAlertController(title: title, message: message, preferredStyle: .actionSheet)
actionSheet.popoverPresentationController?.barButtonItem = popOverSource
show(
actionSheet: actionSheet,
owner: owner,
actions: actions,
cancelTitle: cancelTitle,
cancelAction: cancelAction
)
}
/// Show a custom alert with three actions
///
/// See HIG for guidance: <https://developer.apple.com/design/human-interface-guidelines/ios/views/alerts/>
///
/// - Warning: Try to not use it. Use two action alerts whenever possible.
///
/// - Parameters:
/// - owner: View controller to present alert on
/// - title: Tile shown in alert
/// - message: Optional message shown in alert
/// - action1: First action
/// - action2: Second action
/// - cancelTitle: Custom title for cancel button (normally not needed)
/// - cancelAction: Custom action for cancel button
public static func showAlert(
owner: UIViewController,
title: String,
message: String? = nil,
action1: UIAlertAction,
action2: UIAlertAction,
cancelTitle: String? = nil,
cancelAction: ((UIAlertAction) -> Void)? = nil
) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(action1)
alert.addAction(action2)
let cancelTitle = resolveCancelTitle(with: cancelTitle)
alert.addAction(UIAlertAction(title: cancelTitle, style: .cancel, handler: cancelAction))
owner.present(alert, animated: true)
}
/// Show a custom alert with two actions, that become enabled after a certain time
///
/// See HIG for guidance: <https://developer.apple.com/design/human-interface-guidelines/ios/views/alerts/>
///
/// - Warning: Try to not use it. Use two action alerts whenever possible.
///
/// - Parameters:
/// - owner: View controller to present alert on
/// - title: Tile shown in alert
/// - message: Optional message shown in alert
/// - action1: First action
/// - action2: Second action
/// - enableActionsAfter: Seconds before the actions are enabled
public static func showTimedAlert(
owner: UIViewController,
title: String,
message: String,
action1: UIAlertAction,
action2: UIAlertAction,
enableActionsAfter seconds: Int
) {
let initialMessage =
"\(message) \n\n \(String.localizedStringWithFormat(#localize("alert_enable_actions"), seconds))"
let alert = UIAlertController(title: title, message: initialMessage, preferredStyle: .alert)
alert.addAction(action1)
action1.isEnabled = false
alert.addAction(action2)
action2.isEnabled = false
var secondsPassed = 0
owner.present(alert, animated: true) {
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { timer in
secondsPassed += 1
if secondsPassed == seconds {
action1.isEnabled = true
action2.isEnabled = true
alert.message = message
timer.invalidate()
}
else {
alert
.message =
"\(message) \n\n \(String.localizedStringWithFormat(#localize("alert_enable_actions"), seconds - secondsPassed))"
}
}
}
}
}
extension UIAlertTemplate {
private static func resolveCancelTitle(with optionalTitle: String?) -> String {
optionalTitle ?? #localize("cancel")
}
// Internal helper for shared code
private static func show(
actionSheet: UIAlertController,
owner: UIViewController,
actions: [UIAlertAction],
cancelTitle: String?,
cancelAction: ((UIAlertAction) -> Void)?
) {
for action in actions {
actionSheet.addAction(action)
}
let cancelTitle = resolveCancelTitle(with: cancelTitle)
actionSheet.addAction(UIAlertAction(title: cancelTitle, style: .cancel, handler: cancelAction))
owner.present(actionSheet, animated: true)
}
}
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet am 2026-11-04)
¤
*© Formatika GbR, Deutschland
|
|