ProHUD/ProHUD/Alert/AlertController.swift

452 lines
13 KiB
Swift
Raw Normal View History

2019-07-31 17:40:39 +08:00
//
// Alert.swift
// ProHUD
//
// Created by xaoxuu on 2019/7/23.
// Copyright © 2019 Titan Studio. All rights reserved.
//
import UIKit
import SnapKit
public extension ProHUD {
class Alert: HUDController {
2019-08-05 11:18:25 +08:00
///
2019-07-31 17:40:39 +08:00
public var contentView = BlurView()
2019-08-05 11:18:25 +08:00
/// icontextStackactionStack)
public var contentStack: StackContainer = {
2019-07-31 17:40:39 +08:00
let stack = StackContainer()
2019-08-03 17:48:37 +08:00
stack.spacing = cfg.alert.margin
2019-07-31 17:40:39 +08:00
return stack
}()
2019-08-05 11:18:25 +08:00
///
public var textStack: StackContainer = {
2019-07-31 17:40:39 +08:00
let stack = StackContainer()
2019-08-03 17:48:37 +08:00
stack.spacing = cfg.alert.margin
2019-07-31 17:40:39 +08:00
return stack
}()
2019-08-05 11:18:25 +08:00
///
public var imageView: UIImageView?
///
public var titleLabel: UILabel?
///
public var bodyLabel: UILabel?
2019-07-31 17:40:39 +08:00
///
2019-08-05 11:18:25 +08:00
public var actionStack: StackContainer = {
2019-07-31 17:40:39 +08:00
let stack = StackContainer()
stack.alignment = .fill
2019-08-03 17:48:37 +08:00
stack.spacing = cfg.alert.margin
2019-07-31 17:40:39 +08:00
return stack
}()
///
2019-08-05 11:18:25 +08:00
public var model = ViewModel()
2019-07-31 17:40:39 +08:00
2019-07-31 21:08:25 +08:00
2019-07-31 17:40:39 +08:00
// MARK:
///
/// - Parameter scene:
/// - Parameter title:
/// - Parameter message:
/// - Parameter icon:
public convenience init(scene: Scene = .default, title: String? = nil, message: String? = nil, icon: UIImage? = nil) {
self.init()
2019-08-03 17:48:37 +08:00
view.tintColor = cfg.alert.tintColor
2019-08-05 11:18:25 +08:00
model.scene = scene
model.title = title
model.message = message
model.icon = icon
2019-07-31 17:40:39 +08:00
switch scene {
case .loading:
2019-08-05 11:18:25 +08:00
model.duration = nil
2019-07-31 17:40:39 +08:00
default:
2019-08-05 11:18:25 +08:00
model.duration = 2
2019-07-31 17:40:39 +08:00
}
2019-08-01 20:22:57 +08:00
willLayoutSubviews()
2019-07-31 17:40:39 +08:00
}
2019-08-05 11:18:25 +08:00
}
}
// MARK: -
public extension ProHUD.Alert {
// MARK:
///
@discardableResult func push() -> ProHUD.Alert {
return ProHUD.push(self)
}
///
func pop() {
2019-08-05 19:14:25 +08:00
let hud = ProHUD.shared
2019-08-05 11:18:25 +08:00
let window = hud.getAlertWindow(self)
hud.removeItemFromArray(alert: self)
UIView.animateForAlertBuildOut(animations: {
self.view.alpha = 0
self.view.transform = .init(scaleX: 1.08, y: 1.08)
}) { (done) in
self.view.removeFromSuperview()
self.removeFromParent()
}
// hide window
let count = hud.alerts.count
if count == 0 && hud.alertWindow != nil {
2019-08-02 13:55:23 +08:00
UIView.animateForAlertBuildOut(animations: {
2019-08-05 11:18:25 +08:00
window.backgroundColor = window.backgroundColor?.withAlphaComponent(0)
2019-08-02 13:55:23 +08:00
}) { (done) in
2019-08-05 11:18:25 +08:00
hud.alertWindow = nil
2019-08-03 16:22:50 +08:00
}
2019-07-31 17:40:39 +08:00
}
2019-08-05 11:18:25 +08:00
}
// MARK:
///
/// - Parameter style:
/// - Parameter text:
/// - Parameter action:
2019-08-05 14:20:52 +08:00
@discardableResult func add(action style: UIAlertAction.Style, title: String?, action: (() -> Void)?) -> ProHUD.Alert {
2019-08-05 11:18:25 +08:00
if let btn = privAddButton(custom: Button.actionButton(title: title), action: action) as? Button {
btn.update(style: style)
2019-07-31 17:40:39 +08:00
}
2019-08-05 11:18:25 +08:00
return self
2019-07-31 17:40:39 +08:00
}
2019-08-05 11:18:25 +08:00
///
/// - Parameter button:
/// - Parameter action:
2019-08-05 14:20:52 +08:00
@discardableResult func add(button: UIButton, action: (() -> Void)?) -> ProHUD.Alert {
2019-08-05 11:18:25 +08:00
privAddButton(custom: button, action: action)
return self
}
///
/// - Parameter callback:
@discardableResult func didForceQuit(_ callback: (() -> Void)?) -> ProHUD.Alert {
model.forceQuitCallback = callback
return self
}
///
/// - Parameter callback:
@discardableResult func didDisappear(_ callback: (() -> Void)?) -> ProHUD.Alert {
disappearCallback = callback
return self
}
2019-08-05 14:20:52 +08:00
///
/// - Parameter duration:
@discardableResult func duration(_ duration: TimeInterval?) -> ProHUD.Alert {
model.duration = duration
willLayoutSubviews()
return self
}
///
/// - Parameter scene:
2019-08-05 11:18:25 +08:00
/// - Parameter title:
2019-08-05 14:20:52 +08:00
/// - Parameter message:
@discardableResult func update(scene: Scene, title: String?, message: String?) -> ProHUD.Alert {
model.scene = scene
2019-08-05 11:18:25 +08:00
model.title = title
model.message = message
2019-08-05 14:20:52 +08:00
cfg.alert.reloadData(self)
return self
}
///
/// - Parameter icon:
@discardableResult func update(icon: UIImage?) -> ProHUD.Alert {
2019-08-05 11:18:25 +08:00
model.icon = icon
cfg.alert.reloadData(self)
return self
}
///
/// - Parameter index:
/// - Parameter style:
/// - Parameter title:
/// - Parameter action:
2019-08-05 14:20:52 +08:00
@discardableResult func update(action index: Int, style: UIAlertAction.Style, title: String?, action: (() -> Void)?) -> ProHUD.Alert {
return update(action: index, button: { (btn) in
2019-08-05 11:18:25 +08:00
btn.setTitle(title, for: .normal)
if let b = btn as? Button {
b.update(style: style)
2019-07-31 17:40:39 +08:00
}
2019-08-05 11:18:25 +08:00
btn.layoutIfNeeded()
}, action: action)
2019-07-31 17:40:39 +08:00
}
2019-08-05 11:18:25 +08:00
///
/// - Parameter index:
/// - Parameter button:
/// - Parameter action:
2019-08-05 14:20:52 +08:00
@discardableResult func update(action index: Int, button: (UIButton) -> Void, action: (() -> Void)? = nil) -> ProHUD.Alert {
2019-08-05 11:18:25 +08:00
if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton {
button(btn)
if let ac = action {
addTouchUpAction(for: btn, action: ac)
}
2019-08-03 16:22:50 +08:00
}
UIView.animateForAlert {
self.view.layoutIfNeeded()
}
2019-08-05 11:18:25 +08:00
return self
}
///
/// - Parameter index:
2019-08-05 14:20:52 +08:00
@discardableResult func remove(action index: Int...) -> ProHUD.Alert {
2019-08-05 11:18:25 +08:00
for (i, idx) in index.enumerated() {
privRemoveAction(index: idx-i)
2019-08-03 16:22:50 +08:00
}
2019-08-05 11:18:25 +08:00
return self
2019-08-03 16:22:50 +08:00
}
2019-07-31 17:40:39 +08:00
}
2019-08-05 11:18:25 +08:00
// MARK: -
2019-07-31 17:40:39 +08:00
public extension ProHUD {
2019-08-05 11:18:25 +08:00
///
/// - Parameter alert:
@discardableResult func push(_ alert: Alert) -> Alert {
2019-07-31 17:40:39 +08:00
let window = getAlertWindow(alert)
window.makeKeyAndVisible()
window.resignKey()
window.addSubview(alert.view)
alert.view.transform = .init(scaleX: 1.2, y: 1.2)
alert.view.alpha = 0
2019-08-02 13:55:23 +08:00
UIView.animateForAlertBuildIn {
2019-07-31 17:40:39 +08:00
alert.view.transform = .identity
alert.view.alpha = 1
2019-08-02 13:55:23 +08:00
window.backgroundColor = window.backgroundColor?.withAlphaComponent(0.6)
}
2019-07-31 17:40:39 +08:00
alerts.append(alert)
2019-07-31 21:08:25 +08:00
updateAlertsLayout()
2019-08-05 11:18:25 +08:00
// setup duration
if let _ = alert.model.duration, alert.model.durationBlock == nil {
alert.duration(alert.model.duration)
2019-07-31 17:40:39 +08:00
}
return alert
}
2019-08-05 11:18:25 +08:00
///
/// - Parameter alert:
/// - Parameter title:
/// - Parameter message:
/// - Parameter icon:
2019-08-05 14:20:52 +08:00
@discardableResult func push(alert scene: Alert.Scene, title: String? = nil, message: String? = nil) -> Alert {
return push(Alert(scene: scene, title: title, message: message))
2019-07-31 17:40:39 +08:00
}
2019-08-05 11:18:25 +08:00
///
/// - Parameter identifier:
2019-08-05 19:14:25 +08:00
func alert(_ identifier: String?) -> Alert? {
2019-07-31 17:40:39 +08:00
var aa = [Alert]()
for a in alerts {
if a.identifier == identifier {
aa.append(a)
}
}
2019-08-05 19:14:25 +08:00
return aa.last
2019-07-31 17:40:39 +08:00
}
2019-08-05 11:18:25 +08:00
///
/// - Parameter alert:
2019-08-05 19:14:25 +08:00
func pop(_ alert: Alert) {
2019-07-31 17:40:39 +08:00
for a in alerts {
if a == alert {
2019-08-03 18:03:20 +08:00
a.pop()
2019-07-31 17:40:39 +08:00
}
}
}
2019-08-05 11:18:25 +08:00
///
/// - Parameter identifier:
2019-08-03 18:03:20 +08:00
func pop(alert identifier: String?) {
2019-07-31 17:40:39 +08:00
for a in alerts {
if a.identifier == identifier {
2019-08-03 18:03:20 +08:00
a.pop()
2019-07-31 17:40:39 +08:00
}
}
}
2019-08-05 14:20:52 +08:00
2019-07-31 17:40:39 +08:00
}
2019-08-05 11:18:25 +08:00
// MARK:
2019-07-31 17:40:39 +08:00
public extension ProHUD {
2019-08-05 11:18:25 +08:00
///
/// - Parameter alert:
@discardableResult class func push(_ alert: Alert) -> Alert {
2019-08-03 18:03:20 +08:00
return shared.push(alert)
2019-07-31 21:08:25 +08:00
}
2019-08-05 11:18:25 +08:00
///
/// - Parameter alert:
/// - Parameter title:
/// - Parameter message:
/// - Parameter icon:
2019-08-05 14:20:52 +08:00
@discardableResult class func push(alert: Alert.Scene, title: String? = nil, message: String? = nil) -> Alert {
return shared.push(alert: alert, title: title, message: message)
2019-07-31 17:40:39 +08:00
}
2019-08-05 11:18:25 +08:00
///
/// - Parameter identifier:
2019-08-05 19:14:25 +08:00
class func alert(_ identifier: String?) -> Alert? {
return shared.alert(identifier)
2019-07-31 17:40:39 +08:00
}
2019-08-05 11:18:25 +08:00
///
/// - Parameter alert:
2019-08-05 19:14:25 +08:00
class func pop(_ alert: Alert) {
shared.pop(alert)
2019-07-31 17:40:39 +08:00
}
2019-08-05 11:18:25 +08:00
///
/// - Parameter identifier:
2019-08-03 18:03:20 +08:00
class func pop(alert identifier: String?) {
shared.pop(alert: identifier)
2019-07-31 17:40:39 +08:00
}
}
2019-08-05 11:18:25 +08:00
// MARK: -
fileprivate extension ProHUD.Alert {
///
/// - Parameter index:
@discardableResult func privRemoveAction(index: Int) -> ProHUD.Alert {
if index < 0 {
for view in self.actionStack.arrangedSubviews {
if let btn = view as? UIButton {
btn.removeFromSuperview()
}
}
} else if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton {
btn.removeFromSuperview()
}
if self.actionStack.arrangedSubviews.count == 0 {
self.actionStack.removeFromSuperview()
}
willLayoutSubviews()
UIView.animateForAlert {
self.view.layoutIfNeeded()
}
return self
}
func willLayoutSubviews() {
2019-08-05 14:20:52 +08:00
model.setupWillLayout(duration: 0.001) { [weak self] in
2019-08-05 11:18:25 +08:00
if let a = self {
//
cfg.alert.loadSubviews(a)
cfg.alert.reloadData(a)
2019-08-05 14:20:52 +08:00
//
a.model.setupDuration(duration: a.model.duration) { [weak self] in
self?.pop()
2019-08-05 11:18:25 +08:00
}
// 退
2019-08-05 14:20:52 +08:00
a.model.setupForceQuit(duration: cfg.alert.forceQuitTimer) { [weak self] in
if let aa = self, aa.actionStack.superview == nil {
cfg.alert.loadForceQuitButton(aa)
}
2019-08-05 11:18:25 +08:00
}
}
2019-08-05 14:20:52 +08:00
}
2019-08-05 11:18:25 +08:00
}
@discardableResult func privAddButton(custom button: UIButton, action: (() -> Void)?) -> UIButton {
model.duration = nil
if actionStack.superview == nil {
contentStack.addArrangedSubview(actionStack)
}
self.view.layoutIfNeeded()
button.transform = .init(scaleX: 1, y: 0.001)
actionStack.addArrangedSubview(button)
UIView.animateForAlert {
button.transform = .identity
self.view.layoutIfNeeded()
}
addTouchUpAction(for: button) { [weak self] in
action?()
if button.tag == UIAlertAction.Style.cancel.rawValue {
self?.pop()
}
}
willLayoutSubviews()
return button
}
}
2019-08-01 20:22:57 +08:00
internal extension ProHUD {
2019-07-31 17:40:39 +08:00
2019-07-31 21:08:25 +08:00
func updateAlertsLayout() {
2019-07-31 17:40:39 +08:00
for (i, a) in alerts.reversed().enumerated() {
let scale = CGFloat(pow(0.7, CGFloat(i)))
2019-08-02 13:55:23 +08:00
UIView.animate(withDuration: 1.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: [.allowUserInteraction, .curveEaseInOut], animations: {
2019-07-31 17:40:39 +08:00
let y = -50 * CGFloat(i) * CGFloat(pow(0.8, CGFloat(i)))
a.view.transform = CGAffineTransform.init(translationX: 0, y: y).scaledBy(x: scale, y: scale)
}) { (done) in
}
}
}
2019-08-01 20:22:57 +08:00
}
2019-08-05 11:18:25 +08:00
2019-08-01 20:22:57 +08:00
fileprivate extension ProHUD {
2019-07-31 17:40:39 +08:00
func getAlertWindow(_ vc: UIViewController) -> UIWindow {
if let w = alertWindow {
return w
}
let w = UIWindow()
alertWindow = w
w.backgroundColor = UIColor.init(red: 0, green: 0, blue: 0, alpha: 0)
// alert
w.windowLevel = UIWindow.Level.alert - 1
return w
}
func removeItemFromArray(alert: Alert) {
if alerts.count > 1 {
for (i, a) in alerts.enumerated() {
if a == alert {
alerts.remove(at: i)
}
}
2019-07-31 21:08:25 +08:00
updateAlertsLayout()
2019-07-31 17:40:39 +08:00
} else if alerts.count == 1 {
alerts.removeAll()
} else {
2019-08-03 17:48:37 +08:00
debug("漏洞已经没有alert了")
2019-07-31 17:40:39 +08:00
}
}
}