This commit is contained in:
xaoxuu 2019-08-09 18:02:41 +08:00
parent 6596e6c971
commit 26d7aa0049
12 changed files with 531 additions and 363 deletions

View File

@ -18,8 +18,15 @@ class ViewController: UIViewController {
ProHUD.config { (cfg) in ProHUD.config { (cfg) in
cfg.alert { (a) in cfg.alert { (a) in
a.forceQuitTimer = 2 a.duration = 1
a.forceQuitTimer = 3
// a.iconSize = .init(width: 20, height: 80) // a.iconSize = .init(width: 20, height: 80)
// a.reloadData
// a.iconSize = .init(width: 20, height: 80)
a.iconForScene { (s) -> UIImage? in
return UIImage(named: "icon_download")
}
} }
cfg.toast { (t) in cfg.toast { (t) in
// t.iconSize = .init(width: 300, height: 30) // t.iconSize = .init(width: 300, height: 30)
@ -30,43 +37,134 @@ class ViewController: UIViewController {
@IBAction func test(_ sender: UIButton) { @IBAction func test(_ sender: UIButton) {
// testAlert()
testToast()
// testUpdateAction() // testUpdateAction()
testGuard() // testGuard()
// fastGuard() // fastGuard()
} }
func testAlert() {
let a = Alert.push(scene: .loading) { (a) in
// a.update()
}
a.update { (vm) in
vm.add(action: .default, title: "OK", handler: nil)
}
// a.update()
// Alert.push(scene: .loading, title: "Loading") { (a) in
// a.animate(rotate: true)
// DispatchQueue.main.asyncAfter(deadline: .now()+1) {
// a.update { (vm) in
// vm.message = ""
// }
// a.animate(rotate: true)
// }
// DispatchQueue.main.asyncAfter(deadline: .now()+2) {
// a.update { (vm) in
// vm.message = ""
// }
// a.animate(rotate: true)
// }
// DispatchQueue.main.asyncAfter(deadline: .now()+3) {
// a.update { (vm) in
// vm.scene = .success
// vm.add(action: .default, title: "OK") { [weak a] in
// a?.pop()
// }
// }
// }
// DispatchQueue.main.asyncAfter(deadline: .now()+4) {
// a.update { (vm) in
// vm.update(action: 0, style: .cancel, title: "Cancel", handler: nil)
// }
// }
// }
// Alert.push(scene: .delete, title: "", message: "") { (a) in
// a.identifier = ""
// DispatchQueue.main.asyncAfter(deadline: .now()+1) {
// a.update { (vm) in
// vm.add(action: .destructive, title: "") { [weak a] in
// a?.update({ (vm) in
// vm.message = " "
// vm.remove(action: 1)
// vm.update(action: 0, style: .destructive, title: "", handler: {
// a?.pop()
// })
// })
// }
// vm.add(action: .cancel, title: "", handler: nil)
// }
// }
//
// }
}
func testDelete() { func testDelete() {
let a = ProHUD.push(alert: .delete, title: "确认删除", message: "此操作不可撤销") let a = Alert.push(scene: .delete, title: "确认删除", message: "此操作不可撤销")
a.add(action: .destructive, title: "确认", action: { [weak a] in a.update { (vm) in
a?.remove(action: 0, 1) vm.add(action: .destructive, title: "确认", handler: { [weak a] in
a?.update(scene: .loading, title: "正在删除", message: "请稍后片刻") a?.update { (vm) in
DispatchQueue.main.asyncAfter(deadline: .now()+1) { vm.scene = .loading
a?.update(scene: .success, title: "删除成功", message: "啊哈哈哈哈").duration(2) vm.title = "正在删除"
ProHUD.push(toast: .success, title: "删除成功", message: "aaa") vm.message = "请稍后片刻"
} vm.remove(action: 0, 1)
}).add(action: .cancel, title: "取消", action: nil) }
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
a?.update { (vm) in
vm.scene = .success
vm.title = "删除成功"
vm.message = "啊哈哈哈哈"
vm.duration = 2
}
Toast.push(scene: .success, title: "删除成功", message: "aaa")
}
})
vm.add(action: .cancel, title: "取消", handler: nil)
}
} }
func testToast() { func testToast() {
let t = ProHUD.Toast(scene: .loading, title: "正在加载", message: "请稍候片刻") let t = Toast(scene: .loading, title: "正在加载", message: "请稍候片刻")
let a = ProHUD.push(alert : .loading, title: "正在加载", message: "请稍候片刻") let a = Alert.push(scene : .loading, title: "正在加载", message: "请稍候片刻")
a.didForceQuit { a.didForceQuit {
hud.push(t) t.push()
} }
t.didTapped { [weak t] in t.didTapped { [weak t] in
t?.pop() t?.pop()
let a2 = ProHUD.push(alert: .loading, title: "正在加载", message: "马上就要成功了") Alert.push(scene: .loading, title: "正在加载", message: "马上就要成功了")
DispatchQueue.main.asyncAfter(deadline: .now()+1) { DispatchQueue.main.asyncAfter(deadline: .now()+1) {
let a3 = ProHUD.push(alert: .error, title: "加载失败", message: "点击充实") Alert.push(scene: .error, title: "加载失败", message: "点击充实") { (vm) in
a3.add(action: .default, title: "重新加载") { [weak a3] in vm.duration = 0
a3?.update(scene: .success, title: "加载成功", message: "马上就要成功了") vm.identifier = "hehe"
a3?.update(action: 0, style: .default, title: "OK", action: { [weak a3] in let a = vm.vc!
a3?.pop() vm.add(action: .default, title: "重新加载") {
}).remove(action: 1, 2) a.vm.scene = .success
}.add(action: .destructive, title: "终止", action: nil).add(action: .cancel, title: "取消", action: nil) a.vm.title = "加载成功"
a.vm.message = "马上就要成功了aaaa"
a.vm.remove(action: 1, 2)
a.vm.update(action: 0, style: .default, title: "OK") { [weak a] in
a?.pop()
}
}
vm.add(action: .destructive, title: "终止", handler: nil)
vm.add(action: .cancel, title: "取消", handler: nil)
}
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
if let a = Alert.alerts("hehe").last {
a.update { (vm) in
vm.add(action: .cancel, title: "CANCEL", handler: nil)
}
}
}
} }
@ -80,37 +178,47 @@ class ViewController: UIViewController {
g.add(title: "呵呵") g.add(title: "呵呵")
g.add(message: "请打开相机权限开关,否则无法进行测量。请打开相机权限开关,否则无法进行测量。") g.add(message: "请打开相机权限开关,否则无法进行测量。请打开相机权限开关,否则无法进行测量。")
g.add(action: .default, title: "测试弹窗", action: { [weak self] in g.add(action: .default, title: "测试弹窗", handler: { [weak self] in
self?.testToast() self?.testToast()
}) })
g.add(action: .destructive, title: "测试删除弹窗", action: { [weak self] in g.add(action: .destructive, title: "测试删除弹窗", handler: { [weak self] in
self?.testDelete() self?.testDelete()
}) })
g.add(action: .cancel, title: "我知道了", action: nil) g.add(action: .cancel, title: "我知道了", handler: nil)
g.push(to: self) g.push(to: self)
debugPrint("test: ", g) debugPrint("test: ", g)
} }
func testUpdateAction() { func testUpdateAction() {
let a = ProHUD.push(alert: .confirm, title: "确认删除", message: "此操作无法撤销") let a = Alert.push(scene: .confirm, title: "确认删除", message: "此操作无法撤销")
a.add(action: .destructive, title: "删除") { a.update { (vm) in
a.remove(action: 0, 1).update(scene: .loading, title: "正在删除", message: "请稍后片刻") vm.add(action: .destructive, title: "删除") {
}.add(action: .cancel, title: "取消", action: nil) a.update { (vm) in
vm.remove(action: 0, 1)
vm.scene = .loading
vm.title = "正在删除"
vm.message = "请稍后片刻"
}
}
vm.add(action: .cancel, title: "取消", handler: nil)
}
} }
func fastGuard() { func fastGuard() {
let g = ProHUD.push(guard: self, title: "测试", message: "测试测试") Guard.push(to: self) { (vm) in
g.add(action: .default, title: "默认按钮", action: { vm.add(title: "测试")
vm.add(message: "测试测试")
vm.add(action: .default, title: "默认按钮", handler: {
}) })
g.add(action: .cancel, title: "取消", action: nil) vm.add(action: .cancel, title: "取消", handler: nil)
g.view.backgroundColor = .clear vm.vc?.view.backgroundColor = .clear
}
// g.contentView.backgroundColor = UIColor.white
} }
@ -120,37 +228,6 @@ class ViewController: UIViewController {
//
// ProHUD.show(alert: .loading, title: "", message: "").timeout(nil)
//
// ProHUD.show(alert: .confirm, title: "", message: "").timeout(3)
//
// a.addAction(style: .destructive, title: "") { [weak a] in
// a?.updateContent(scene: .success, title: "", message: "xxx")
// a?.updateAction(index: 0, style: .default, title: "", action: {
// a?.remove()
// }).removeAction(index: 1)
//// a?.updateContent(scene: .success, title: "").removeAction(index: -1).timeout(2)
// }.addAction(style: .cancel, title: "", action: nil).didDisappear {
// debugPrint("didDisappear")
// }
//
// ProHUD.show(alert: .delete, title: "", message: "").addAction(style: .destructive, title: "") {
//
// }.addAction(style: .cancel, title: "", action: nil).didDisappear {
// debugPrint("didDisappear")
// }.addAction(style: .cancel, title: nil) {
//
// }
// ProHUD.show(toast: .loading, title: "", message: "")
// ProHUD.show(toast: .loading, title: "", message: "")
} }
} }

View File

@ -25,6 +25,7 @@
CD95D26B22E72DB3007559A3 /* ProHUD.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD95D26A22E72DB3007559A3 /* ProHUD.swift */; }; CD95D26B22E72DB3007559A3 /* ProHUD.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD95D26A22E72DB3007559A3 /* ProHUD.swift */; };
CDB6A07B22EEF06500AF6CF0 /* HUDController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDB6A07A22EEF06500AF6CF0 /* HUDController.swift */; }; CDB6A07B22EEF06500AF6CF0 /* HUDController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDB6A07A22EEF06500AF6CF0 /* HUDController.swift */; };
CDB6A07D22EEF19D00AF6CF0 /* HUDConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDB6A07C22EEF19D00AF6CF0 /* HUDConfig.swift */; }; CDB6A07D22EEF19D00AF6CF0 /* HUDConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDB6A07C22EEF19D00AF6CF0 /* HUDConfig.swift */; };
CDC39CFD22FD6DDF0070E914 /* GuardModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC39CFC22FD6DDF0070E914 /* GuardModel.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
@ -50,6 +51,7 @@
CD95D26A22E72DB3007559A3 /* ProHUD.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProHUD.swift; sourceTree = "<group>"; }; CD95D26A22E72DB3007559A3 /* ProHUD.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProHUD.swift; sourceTree = "<group>"; };
CDB6A07A22EEF06500AF6CF0 /* HUDController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HUDController.swift; sourceTree = "<group>"; }; CDB6A07A22EEF06500AF6CF0 /* HUDController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HUDController.swift; sourceTree = "<group>"; };
CDB6A07C22EEF19D00AF6CF0 /* HUDConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HUDConfig.swift; sourceTree = "<group>"; }; CDB6A07C22EEF19D00AF6CF0 /* HUDConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HUDConfig.swift; sourceTree = "<group>"; };
CDC39CFC22FD6DDF0070E914 /* GuardModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuardModel.swift; sourceTree = "<group>"; };
DC31EBFAC56868D6096A233A /* Pods-ProHUD.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ProHUD.release.xcconfig"; path = "Pods/Target Support Files/Pods-ProHUD/Pods-ProHUD.release.xcconfig"; sourceTree = "<group>"; }; DC31EBFAC56868D6096A233A /* Pods-ProHUD.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ProHUD.release.xcconfig"; path = "Pods/Target Support Files/Pods-ProHUD/Pods-ProHUD.release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@ -110,6 +112,7 @@
CD6CD87422F185C200F4FD4A /* GuardController.swift */, CD6CD87422F185C200F4FD4A /* GuardController.swift */,
CD6CD87822F185D000F4FD4A /* GuardConfig.swift */, CD6CD87822F185D000F4FD4A /* GuardConfig.swift */,
CD6CD87A22F185D600F4FD4A /* GuardView.swift */, CD6CD87A22F185D600F4FD4A /* GuardView.swift */,
CDC39CFC22FD6DDF0070E914 /* GuardModel.swift */,
); );
path = Guard; path = Guard;
sourceTree = "<group>"; sourceTree = "<group>";
@ -292,6 +295,7 @@
CD16490B22EF09AB0077988C /* AlertModel.swift in Sources */, CD16490B22EF09AB0077988C /* AlertModel.swift in Sources */,
CD16491222EF0D900077988C /* HUDView.swift in Sources */, CD16491222EF0D900077988C /* HUDView.swift in Sources */,
CDB6A07B22EEF06500AF6CF0 /* HUDController.swift in Sources */, CDB6A07B22EEF06500AF6CF0 /* HUDController.swift in Sources */,
CDC39CFD22FD6DDF0070E914 /* GuardModel.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

View File

@ -11,7 +11,7 @@ import SnapKit
import Inspire import Inspire
public extension ProHUD.Configuration { public extension ProHUD.Configuration {
struct Alert { class Alert {
// MARK: // MARK:
/// iPad /// iPad
public var maxWidth = CGFloat(400) public var maxWidth = CGFloat(400)
@ -28,6 +28,10 @@ public extension ProHUD.Configuration {
/// ///
public var iconSize = CGSize(width: 48, height: 48) public var iconSize = CGSize(width: 48, height: 48)
public func iconForScene(_ callback: @escaping (ProHUD.Alert.Scene) -> UIImage?) {
privIconForScene = callback
}
// MARK: // MARK:
/// ///
public var titleFont = UIFont.boldSystemFont(ofSize: 22) public var titleFont = UIFont.boldSystemFont(ofSize: 22)
@ -48,18 +52,14 @@ public extension ProHUD.Configuration {
// MARK: // MARK:
/// ///
/// - Parameter callback: public func reloadData(_ callback: @escaping (ProHUD.Alert) -> Void) {
public mutating func loadSubviews(_ callback: @escaping (ProHUD.Alert) -> Void) {
privLoadSubviews = callback
}
///
/// - Parameter callback:
public mutating func reloadData(_ callback: @escaping (ProHUD.Alert) -> Void) {
privReloadData = callback privReloadData = callback
} }
/// Loading
public var duration = TimeInterval(2)
/// 退 /// 退
public var forceQuitTimer = TimeInterval(30) public var forceQuitTimer = TimeInterval(30)
@ -68,77 +68,41 @@ public extension ProHUD.Configuration {
/// 退 /// 退
/// - Parameter callback: /// - Parameter callback:
public mutating func loadForceQuitButton(_ callback: @escaping (ProHUD.Alert) -> Void) { public func loadForceQuitButton(_ callback: @escaping (ProHUD.Alert) -> Void) {
privLoadForceQuitButton = callback privLoadForceQuitButton = callback
} }
}
}
// MARK: -
internal extension ProHUD.Configuration.Alert {
var reloadData: (ProHUD.Alert) -> Void {
return privReloadData
} }
} }
// MARK: - // MARK: -
internal extension ProHUD.Configuration.Alert { fileprivate var privLayoutContentView: (ProHUD.Alert) -> Void = {
var loadSubviews: (ProHUD.Alert) -> Void {
return privLoadSubviews
}
var reloadData: (ProHUD.Alert) -> Void {
return privReloadData
}
var loadForceQuitButton: (ProHUD.Alert) -> Void {
return privLoadForceQuitButton
}
var setupDefaultDuration: (ProHUD.Alert) -> Void {
return { (vc) in
//
if let t = vc.model.duration, t > 0 {
if vc.buttonEvents.count > 0 {
vc.duration(nil)
}
} else if vc.model.duration == nil && vc.model.scene != .loading {
//
vc.duration(2)
}
}
}
var reloadStack: (ProHUD.Alert) -> Void {
return { (vc) in
if vc.textStack.arrangedSubviews.count > 0 {
vc.contentStack.addArrangedSubview(vc.textStack)
} else {
vc.textStack.removeFromSuperview()
}
if vc.actionStack.arrangedSubviews.count > 0 {
vc.contentStack.addArrangedSubview(vc.actionStack)
} else {
vc.actionStack.removeFromSuperview()
}
}
}
}
fileprivate var privLoadSubviews: (ProHUD.Alert) -> Void = {
return { (vc) in return { (vc) in
debug(vc, "loadSubviews")
let config = cfg.alert
if vc.contentView.superview == nil { if vc.contentView.superview == nil {
vc.view.addSubview(vc.contentView) vc.view.addSubview(vc.contentView)
vc.contentView.contentView.addSubview(vc.contentStack)
vc.contentStack.spacing = cfg.alert.margin + cfg.alert.padding
vc.contentView.layer.masksToBounds = true vc.contentView.layer.masksToBounds = true
vc.contentView.layer.cornerRadius = cfg.alert.cornerRadius vc.contentView.layer.cornerRadius = cfg.alert.cornerRadius
let maxWidth = CGFloat.maximum(CGFloat.minimum(UIScreen.main.bounds.width * 0.68, cfg.alert.maxWidth), 268) let maxWidth = CGFloat.maximum(CGFloat.minimum(UIScreen.main.bounds.width * 0.68, cfg.alert.maxWidth), 268)
vc.contentView.snp.makeConstraints { (mk) in vc.contentView.snp.makeConstraints { (mk) in
mk.center.equalToSuperview() mk.center.equalToSuperview()
mk.width.lessThanOrEqualTo(maxWidth) mk.width.lessThanOrEqualTo(maxWidth)
} }
}
if vc.contentStack.superview == nil {
vc.contentView.contentView.addSubview(vc.contentStack)
vc.contentStack.spacing = cfg.alert.margin + cfg.alert.padding
vc.contentStack.snp.makeConstraints { (mk) in vc.contentStack.snp.makeConstraints { (mk) in
mk.centerX.equalToSuperview() mk.centerX.equalToSuperview()
mk.top.equalToSuperview().offset(cfg.alert.padding) mk.top.equalToSuperview().offset(cfg.alert.padding)
@ -147,23 +111,13 @@ fileprivate var privLoadSubviews: (ProHUD.Alert) -> Void = {
mk.trailing.equalToSuperview().offset(-cfg.alert.padding) mk.trailing.equalToSuperview().offset(-cfg.alert.padding)
} }
} }
} }
}() }()
fileprivate var privReloadData: (ProHUD.Alert) -> Void = { fileprivate var privIconForScene: (ProHUD.Alert.Scene) -> UIImage? = {
return { (vc) in return { (scene) in
debug(vc, "reloadData")
let config = cfg.alert
let isFirstLayout: Bool
// layout
if vc.textStack.superview == nil && vc.imageView?.superview == nil {
isFirstLayout = true
} else {
isFirstLayout = false
}
let imgStr: String let imgStr: String
switch vc.model.scene { switch scene {
case .success: case .success:
imgStr = "ProHUDSuccess" imgStr = "ProHUDSuccess"
case .warning: case .warning:
@ -179,7 +133,14 @@ fileprivate var privReloadData: (ProHUD.Alert) -> Void = {
default: default:
imgStr = "ProHUDMessage" imgStr = "ProHUDMessage"
} }
let img = vc.model.icon ?? ProHUD.image(named: imgStr) return ProHUD.image(named: imgStr)
}
}()
fileprivate var privUpdateImage: (ProHUD.Alert) -> Void = {
return { (vc) in
let config = cfg.alert
let img = vc.vm.icon ?? privIconForScene(vc.vm.scene)
if let imgv = vc.imageView { if let imgv = vc.imageView {
imgv.image = img imgv.image = img
} else { } else {
@ -197,9 +158,13 @@ fileprivate var privReloadData: (ProHUD.Alert) -> Void = {
vc.imageView = icon vc.imageView = icon
} }
vc.imageView?.layer.removeAllAnimations() vc.imageView?.layer.removeAllAnimations()
}
}()
// text fileprivate var privUpdateTextStack: (ProHUD.Alert) -> Void = {
if vc.model.title?.count ?? 0 > 0 || vc.model.message?.count ?? 0 > 0 { return { (vc) in
let config = cfg.alert
if vc.vm.title?.count ?? 0 > 0 || vc.vm.message?.count ?? 0 > 0 {
vc.contentStack.addArrangedSubview(vc.textStack) vc.contentStack.addArrangedSubview(vc.textStack)
vc.textStack.snp.makeConstraints { (mk) in vc.textStack.snp.makeConstraints { (mk) in
mk.top.greaterThanOrEqualTo(vc.contentView).offset(config.padding*1.75) mk.top.greaterThanOrEqualTo(vc.contentView).offset(config.padding*1.75)
@ -212,19 +177,19 @@ fileprivate var privReloadData: (ProHUD.Alert) -> Void = {
mk.trailing.lessThanOrEqualTo(vc.contentView).offset(-config.padding*2) mk.trailing.lessThanOrEqualTo(vc.contentView).offset(-config.padding*2)
} }
} }
if vc.model.title?.count ?? 0 > 0 { if vc.vm.title?.count ?? 0 > 0 {
if let lb = vc.titleLabel { if let lb = vc.titleLabel {
lb.text = vc.model.title lb.text = vc.vm.title
} else { } else {
let title = UILabel() let title = UILabel()
title.textAlignment = .center title.textAlignment = .center
title.numberOfLines = config.titleMaxLines title.numberOfLines = config.titleMaxLines
title.textColor = cfg.primaryLabelColor title.textColor = cfg.primaryLabelColor
title.text = vc.model.title title.text = vc.vm.title
vc.textStack.addArrangedSubview(title) vc.textStack.addArrangedSubview(title)
vc.titleLabel = title vc.titleLabel = title
} }
if vc.model.message?.count ?? 0 > 0 { if vc.vm.message?.count ?? 0 > 0 {
// message // message
vc.titleLabel?.font = config.titleFont vc.titleLabel?.font = config.titleFont
} else { } else {
@ -234,20 +199,20 @@ fileprivate var privReloadData: (ProHUD.Alert) -> Void = {
} else { } else {
vc.titleLabel?.removeFromSuperview() vc.titleLabel?.removeFromSuperview()
} }
if vc.model.message?.count ?? 0 > 0 { if vc.vm.message?.count ?? 0 > 0 {
if let lb = vc.bodyLabel { if let lb = vc.bodyLabel {
lb.text = vc.model.message lb.text = vc.vm.message
} else { } else {
let body = UILabel() let body = UILabel()
body.textAlignment = .center body.textAlignment = .center
body.font = config.bodyFont body.font = config.bodyFont
body.numberOfLines = config.bodyMaxLines body.numberOfLines = config.bodyMaxLines
body.textColor = cfg.secondaryLabelColor body.textColor = cfg.secondaryLabelColor
body.text = vc.model.message body.text = vc.vm.message
vc.textStack.addArrangedSubview(body) vc.textStack.addArrangedSubview(body)
vc.bodyLabel = body vc.bodyLabel = body
} }
if vc.model.title?.count ?? 0 > 0 { if vc.vm.title?.count ?? 0 > 0 {
// title // title
vc.bodyLabel?.font = config.bodyFont vc.bodyLabel?.font = config.bodyFont
} else { } else {
@ -260,48 +225,35 @@ fileprivate var privReloadData: (ProHUD.Alert) -> Void = {
} else { } else {
vc.textStack.removeFromSuperview() vc.textStack.removeFromSuperview()
} }
if vc.actionStack.superview != nil { vc.textStack.layoutIfNeeded()
if isFirstLayout { }
vc.contentStack.addArrangedSubview(vc.actionStack) }()
} else {
vc.actionStack.transform = .init(scaleX: 1, y: 0.001)
UIView.animateForAlert { fileprivate var privUpdateActionStack: (ProHUD.Alert) -> Void = {
vc.contentStack.addArrangedSubview(vc.actionStack) return { (vc) in
vc.view.layoutIfNeeded() let config = cfg.alert
} if vc.buttonEvents.count > 0 {
} //
vc.contentStack.addArrangedSubview(vc.actionStack)
// iPad // iPad
if isPortrait == false { if isPortrait == false && vc.buttonEvents.count < 4 {
vc.actionStack.axis = .horizontal vc.actionStack.axis = .horizontal
vc.actionStack.alignment = .fill vc.actionStack.alignment = .fill
vc.actionStack.distribution = .fillEqually vc.actionStack.distribution = .fillEqually
} }
vc.actionStack.snp.makeConstraints { (mk) in vc.actionStack.snp.makeConstraints { (mk) in
mk.width.greaterThanOrEqualTo(200) mk.width.greaterThanOrEqualTo(200)
mk.leading.trailing.equalToSuperview() mk.leading.trailing.equalToSuperview()
} }
if isFirstLayout == false {
UIView.animateForAlert {
vc.actionStack.transform = .identity
}
}
}
if isFirstLayout {
vc.view.layoutIfNeeded()
vc.imageView?.transform = .init(scaleX: 0.75, y: 0.75)
UIView.animateForAlert {
vc.imageView?.transform = .identity
vc.view.layoutIfNeeded()
}
} else { } else {
UIView.animateForAlert { //
vc.view.layoutIfNeeded() for v in vc.actionStack.arrangedSubviews {
v.removeFromSuperview()
} }
vc.actionStack.removeFromSuperview()
} }
vc.actionStack.layoutIfNeeded()
} }
}() }()
@ -335,12 +287,74 @@ fileprivate var privLoadForceQuitButton: (ProHUD.Alert) -> Void = {
bg.transform = .identity bg.transform = .identity
} }
vc.addTouchUpAction(for: btn) { [weak vc] in vc.addTouchUpAction(for: btn) { [weak vc] in
debug("点击了隐藏") debug("点击了\(config.forceQuitTitle)")
vc?.model.forceQuitCallback?() vc?.vm.forceQuitCallback?()
vc?.pop() vc?.pop()
} }
} }
}() }()
///
fileprivate var privReloadData: (ProHUD.Alert) -> Void = {
return { (vc) in
debug(vc, "reloadData")
let config = cfg.alert
let isFirstLayout: Bool
if vc.contentView.superview == nil {
isFirstLayout = true
//
privLayoutContentView(vc)
} else {
isFirstLayout = false
}
//
privUpdateImage(vc)
//
privUpdateTextStack(vc)
//
privUpdateActionStack(vc)
vc.contentStack.layoutIfNeeded()
vc.contentView.layoutIfNeeded()
//
if isFirstLayout {
vc.view.layoutIfNeeded()
vc.imageView?.transform = .init(scaleX: 0.75, y: 0.75)
UIView.animateForAlert {
vc.view.layoutIfNeeded()
vc.imageView?.transform = .identity
}
} else {
UIView.animateForAlert {
vc.view.layoutIfNeeded()
}
}
//
if vc.vm.duration == nil {
if vc.vm.scene == .loading {
vc.vm.duration = 0
} else {
vc.vm.duration = config.duration
}
}
// 退
vc.vm.forceQuitTimerBlock?.cancel()
if vc.buttonEvents.count == 0 {
vc.vm.forceQuitTimerBlock = DispatchWorkItem(block: { [weak vc] in
if let vc = vc {
if vc.buttonEvents.count == 0 {
privLoadForceQuitButton(vc)
}
}
})
DispatchQueue.main.asyncAfter(deadline: .now() + config.forceQuitTimer, execute: vc.vm.forceQuitTimerBlock!)
} else {
vc.vm.forceQuitTimerBlock = nil
}
}
}()

View File

@ -53,28 +53,32 @@ public extension ProHUD {
}() }()
/// ///
public var model = ViewModel() public var vm = ViewModel()
// MARK: // MARK:
internal var isLoadFinished = false
/// ///
/// - Parameter scene: /// - Parameter scene:
/// - Parameter title: /// - Parameter title:
/// - Parameter message: /// - Parameter message:
/// - Parameter icon: /// - Parameter icon:
public convenience init(scene: Scene = .default, title: String? = nil, message: String? = nil, icon: UIImage? = nil, actions: ((Alert) -> Void)? = nil) { public convenience init(scene: Scene = .default, title: String? = nil, message: String? = nil, icon: UIImage? = nil, actions: ((inout ViewModel) -> Void)? = nil) {
self.init() self.init()
view.tintColor = cfg.alert.tintColor vm.vc = self
model.scene = scene vm.scene = scene
model.title = title vm.title = title
model.message = message vm.message = message
model.icon = icon vm.icon = icon
actions?(self) actions?(&vm)
willLayoutSubviews()
} }
public override func viewDidLoad() {
super.viewDidLoad()
view.tintColor = cfg.alert.tintColor
cfg.alert.reloadData(self)
isLoadFinished = true
}
} }
@ -88,7 +92,6 @@ public extension Alert {
/// ///
@discardableResult func push() -> Alert { @discardableResult func push() -> Alert {
let hud = ProHUD.shared
if Alert.alerts.contains(self) == false { if Alert.alerts.contains(self) == false {
let window = Alert.getAlertWindow(self) let window = Alert.getAlertWindow(self)
window.makeKeyAndVisible() window.makeKeyAndVisible()
@ -104,11 +107,6 @@ public extension Alert {
Alert.alerts.append(self) Alert.alerts.append(self)
} }
Alert.updateAlertsLayout() Alert.updateAlertsLayout()
// setup duration
if let _ = model.duration, model.durationBlock == nil {
duration(model.duration)
}
return self return self
} }
@ -137,22 +135,11 @@ public extension Alert {
// MARK: // MARK:
///
/// - Parameter style:
/// - Parameter text:
/// - Parameter handler:
@discardableResult func add(action style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton {
let btn = privAddButton(custom: Button.actionButton(title: title), action: handler)
if let b = btn as? Button {
b.update(style: style)
}
return btn
}
/// ///
/// - Parameter callback: /// - Parameter callback:
@discardableResult func didForceQuit(_ callback: (() -> Void)?) -> Alert { @discardableResult func didForceQuit(_ callback: (() -> Void)?) -> Alert {
model.forceQuitCallback = callback vm.forceQuitCallback = callback
return self return self
} }
@ -163,77 +150,29 @@ public extension Alert {
return self return self
} }
///
/// - Parameter duration:
@discardableResult func duration(_ duration: TimeInterval?) -> Alert {
model.setupDuration(duration: duration) { [weak self] in
self?.pop()
}
return self
}
/// ///
/// - Parameter scene: /// - Parameter callback:
/// - Parameter title: func update(_ callback: ((inout Alert.ViewModel) -> Void)? = nil) {
/// - Parameter message: callback?(&vm)
@discardableResult func update(scene: Scene, title: String?, message: String?) -> Alert {
model.scene = scene
model.title = title
model.message = message
willLayoutSubviews()
return self
}
///
/// - Parameter icon:
@discardableResult func update(icon: UIImage?) -> Alert {
model.icon = icon
cfg.alert.reloadData(self) cfg.alert.reloadData(self)
return self
} }
@discardableResult func animate(rotate: Bool) -> Alert { func animate(rotate: Bool) {
if rotate { if rotate {
DispatchQueue.main.async { DispatchQueue.main.async {
let ani = CABasicAnimation(keyPath: "transform.rotation.z") let ani = CABasicAnimation(keyPath: "transform.rotation.z")
ani.toValue = M_PI*2.0 ani.toValue = Double.pi * 2.0
ani.duration = 2 ani.duration = 3
ani.repeatCount = 10000 ani.repeatCount = 10000
self.imageView?.layer.add(ani, forKey: "rotationAnimation") self.imageView?.layer.add(ani, forKey: "rotationAnimation")
} }
} else { } else {
imageView?.layer.removeAllAnimations() imageView?.layer.removeAllAnimations()
} }
return self
} }
///
/// - Parameter index:
/// - Parameter style:
/// - Parameter title:
/// - Parameter action:
@discardableResult func update(action index: Int, style: UIAlertAction.Style, title: String?, action: (() -> Void)?) -> Alert {
if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton {
btn.setTitle(title, for: .normal)
if let b = btn as? Button {
b.update(style: style)
}
btn.layoutIfNeeded()
if let ac = action {
addTouchUpAction(for: btn, action: ac)
}
}
return self
}
///
/// - Parameter index:
@discardableResult func remove(action index: Int...) -> Alert {
for (i, idx) in index.enumerated() {
privRemoveAction(index: idx-i)
}
return self
}
} }
@ -247,7 +186,7 @@ public extension Alert {
/// - Parameter title: /// - Parameter title:
/// - Parameter message: /// - Parameter message:
/// - Parameter actions: /// - Parameter actions:
@discardableResult class func push(alert scene: Alert.Scene, title: String? = nil, message: String? = nil, actions: ((Alert) -> Void)? = nil) -> Alert { @discardableResult class func push(scene: Alert.Scene, title: String? = nil, message: String? = nil, actions: ((inout Alert.ViewModel) -> Void)? = nil) -> Alert {
return Alert(scene: scene, title: title, message: message, actions: actions).push() return Alert(scene: scene, title: title, message: message, actions: actions).push()
} }
@ -256,7 +195,7 @@ public extension Alert {
class func alerts(_ identifier: String?) -> [Alert] { class func alerts(_ identifier: String?) -> [Alert] {
var aa = [Alert]() var aa = [Alert]()
for a in Alert.alerts { for a in Alert.alerts {
if a.identifier == identifier { if a.vm.identifier == identifier {
aa.append(a) aa.append(a)
} }
} }
@ -281,7 +220,7 @@ public extension Alert {
// MARK: - // MARK: -
fileprivate extension Alert { internal extension Alert {
/// ///
/// - Parameter index: /// - Parameter index:
@ -298,52 +237,56 @@ fileprivate extension Alert {
if self.actionStack.arrangedSubviews.count == 0 { if self.actionStack.arrangedSubviews.count == 0 {
self.actionStack.removeFromSuperview() self.actionStack.removeFromSuperview()
} }
willLayoutSubviews()
UIView.animateForAlert { UIView.animateForAlert {
self.view.layoutIfNeeded() self.view.layoutIfNeeded()
} }
return self return self
} }
func willLayoutSubviews() { @discardableResult func privAddButton(custom button: UIButton, at index: Int? = nil, handler: (() -> Void)?) -> UIButton {
model.setupWillLayout(duration: 0.001) { [weak self] in
if let a = self {
//
cfg.alert.loadSubviews(a)
cfg.alert.reloadData(a)
cfg.alert.setupDefaultDuration(a)
// 退
a.model.setupForceQuit(duration: cfg.alert.forceQuitTimer) { [weak self] in
if let aa = self, aa.actionStack.superview == nil {
cfg.alert.loadForceQuitButton(aa)
}
}
}
}
}
@discardableResult func privAddButton(custom button: UIButton, action: (() -> Void)?) -> UIButton {
model.duration = nil
if actionStack.superview == nil { if actionStack.superview == nil {
contentStack.addArrangedSubview(actionStack) contentStack.addArrangedSubview(actionStack)
contentStack.layoutIfNeeded()
} }
self.view.layoutIfNeeded() if let idx = index, idx < actionStack.arrangedSubviews.count {
button.transform = .init(scaleX: 1, y: 0.001) actionStack.insertArrangedSubview(button, at: idx)
actionStack.addArrangedSubview(button) } else {
UIView.animateForAlert { actionStack.addArrangedSubview(button)
button.transform = .identity
self.view.layoutIfNeeded()
} }
addTouchUpAction(for: button) { [weak self] in addTouchUpAction(for: button) { [weak self] in
action?() handler?()
if button.tag == UIAlertAction.Style.cancel.rawValue { if button.tag == UIAlertAction.Style.cancel.rawValue {
self?.pop() self?.pop()
} }
} }
willLayoutSubviews() if isLoadFinished {
actionStack.layoutIfNeeded()
UIView.animateForAlert {
self.view.layoutIfNeeded()
}
}
return button return button
} }
func privUpdateButton(action index: Int, style: UIAlertAction.Style, title: String?, _ handler: (() -> Void)?) {
if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton {
btn.setTitle(title, for: .normal)
if let b = btn as? Button {
b.update(style: style)
}
if let _ = buttonEvents[btn] {
buttonEvents.removeValue(forKey: btn)
}
addTouchUpAction(for: btn) { [weak self] in
handler?()
if btn.tag == UIAlertAction.Style.cancel.rawValue {
self?.pop()
}
}
}
}
} }
fileprivate extension Alert { fileprivate extension Alert {

View File

@ -35,20 +35,50 @@ public extension Alert {
struct ViewModel { struct ViewModel {
/// ID
public var identifier = String(Date().timeIntervalSince1970)
/// 使 /// 使
public var scene = Scene.default public var scene = Scene.default
/// ///
public var title: String? public var title: String? {
didSet {
vc?.titleLabel?.text = title
}
}
/// ///
public var message: String? public var message: String? {
didSet {
vc?.bodyLabel?.text = message
}
}
/// ///
public var icon: UIImage? public var icon: UIImage? {
didSet {
vc?.imageView?.image = icon
}
}
/// /// 0
internal var duration: TimeInterval? public var duration: TimeInterval? {
didSet {
durationBlock?.cancel()
if let t = duration, t > 0 {
let v = vc
durationBlock = DispatchWorkItem(block: {
v?.pop()
})
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: durationBlock!)
} else {
durationBlock = nil
}
}
}
public weak var vc: Alert?
/// ///
internal var durationBlock: DispatchWorkItem? internal var durationBlock: DispatchWorkItem?
@ -59,40 +89,56 @@ public extension Alert {
/// 退 /// 退
internal var forceQuitCallback: (() -> Void)? internal var forceQuitCallback: (() -> Void)?
internal var willLayoutBlock: DispatchWorkItem?
internal mutating func setupDuration(duration: TimeInterval?, callback: @escaping () -> Void) {
self.duration = duration
durationBlock?.cancel()
if let t = duration, t > 0 {
durationBlock = DispatchWorkItem(block: callback)
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: durationBlock!)
} else {
durationBlock = nil
}
}
internal mutating func setupForceQuit(duration: TimeInterval?, callback: @escaping () -> Void) {
forceQuitTimerBlock?.cancel()
if let t = duration, t > 0 {
forceQuitTimerBlock = DispatchWorkItem(block: callback)
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: forceQuitTimerBlock!)
} else {
forceQuitTimerBlock = nil
}
}
internal mutating func setupWillLayout(duration: TimeInterval?, callback: @escaping () -> Void) {
willLayoutBlock?.cancel()
if let t = duration, t > 0 {
willLayoutBlock = DispatchWorkItem(block: callback)
DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: willLayoutBlock!)
} else {
willLayoutBlock = nil
}
}
} }
} }
public extension Alert.ViewModel {
///
/// - Parameter style:
/// - Parameter text:
/// - Parameter handler:
@discardableResult mutating func add(action style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton {
duration = 0
let btn = vc?.privAddButton(custom: Alert.Button.actionButton(title: title), handler: handler)
if let b = btn as? Alert.Button {
b.update(style: style)
}
return btn!
}
///
/// - Parameter index:
/// - Parameter style:
/// - Parameter title:
/// - Parameter handler:
@discardableResult mutating func insert(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton {
duration = 0
let btn = vc?.privAddButton(custom: Alert.Button.actionButton(title: title), at: index, handler: handler)
if let b = btn as? Alert.Button {
b.update(style: style)
}
return btn!
}
///
/// - Parameter index:
/// - Parameter style:
/// - Parameter title:
/// - Parameter handler:
mutating func update(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) {
vc?.privUpdateButton(action: index, style: style, title: title, handler)
}
///
/// - Parameter index:
mutating func remove(action index: Int...) {
guard let alert = self.vc else { return }
for (i, idx) in index.enumerated() {
alert.privRemoveAction(index: idx-i)
}
}
}

View File

@ -24,6 +24,7 @@ internal extension Alert {
backgroundColor = cfg.dynamicColor.withAlphaComponent(0.04) backgroundColor = cfg.dynamicColor.withAlphaComponent(0.04)
contentEdgeInsets = .init(top: pd*1.5, left: pd*1.5, bottom: pd*1.5, right: pd*1.5) contentEdgeInsets = .init(top: pd*1.5, left: pd*1.5, bottom: pd*1.5, right: pd*1.5)
} else { } else {
backgroundColor = .clear
contentEdgeInsets = .init(top: pd*0.5, left: pd*1.5, bottom: pd*0.5, right: pd*1.5) contentEdgeInsets = .init(top: pd*0.5, left: pd*1.5, bottom: pd*0.5, right: pd*1.5)
} }
switch style { switch style {

View File

@ -86,11 +86,7 @@ fileprivate var privLoadSubviews: (ProHUD.Guard) -> Void = {
return { (vc) in return { (vc) in
debug(vc, "loadSubviews") debug(vc, "loadSubviews")
let config = cfg.guard let config = cfg.guard
// background
vc.view.tintColor = config.tintColor
vc.view.backgroundColor = UIColor(white: 0, alpha: 0)
vc.view.addSubview(vc.contentView)
vc.contentView.contentView.addSubview(vc.contentStack)
} }
}() }()
@ -98,6 +94,11 @@ fileprivate var privReloadData: (ProHUD.Guard) -> Void = {
return { (vc) in return { (vc) in
debug(vc, "reloadData") debug(vc, "reloadData")
let config = cfg.guard let config = cfg.guard
// background
vc.view.tintColor = config.tintColor
vc.view.backgroundColor = UIColor(white: 0, alpha: 0)
vc.view.addSubview(vc.contentView)
vc.contentView.contentView.addSubview(vc.contentStack)
// //
var width = UIScreen.main.bounds.width var width = UIScreen.main.bounds.width
if width > config.cardMaxWidth { if width > config.cardMaxWidth {

View File

@ -50,23 +50,26 @@ public extension ProHUD {
/// ///
public var backgroundColor: UIColor? = UIColor(white: 0, alpha: 0.5) public var backgroundColor: UIColor? = UIColor(white: 0, alpha: 0.5)
public var vm = ViewModel()
// MARK: // MARK:
/// ///
/// - Parameter title: /// - Parameter title:
/// - Parameter message: /// - Parameter message:
/// - Parameter actions: /// - Parameter actions:
public convenience init(title: String? = nil, message: String? = nil, actions: ((Guard) -> Void)? = nil) { public convenience init(title: String? = nil, message: String? = nil, actions: ((inout ViewModel) -> Void)? = nil) {
self.init() self.init()
vm.vc = self
view.tintColor = cfg.guard.tintColor
if let _ = title { if let _ = title {
add(title: title) add(title: title)
} }
if let _ = message { if let _ = message {
add(message: message) add(message: message)
} }
actions?(self) actions?(&vm)
view.tintColor = cfg.guard.tintColor
cfg.guard.loadSubviews(self) cfg.guard.loadSubviews(self)
cfg.guard.reloadData(self) cfg.guard.reloadData(self)
cfg.guard.reloadStack(self) cfg.guard.reloadStack(self)
@ -91,7 +94,7 @@ public extension Guard {
/// ///
/// - Parameter viewController: /// - Parameter viewController:
func push(to viewController: UIViewController? = nil) -> Guard { @discardableResult func push(to viewController: UIViewController? = nil) -> Guard {
func f(_ vc: UIViewController) { func f(_ vc: UIViewController) {
view.layoutIfNeeded() view.layoutIfNeeded()
vc.addChild(self) vc.addChild(self)
@ -226,7 +229,7 @@ public extension Guard {
/// - Parameter title: /// - Parameter title:
/// - Parameter message: /// - Parameter message:
/// - Parameter icon: /// - Parameter icon:
@discardableResult class func push(to viewController: UIViewController? = nil, actions: ((Guard) -> Void)? = nil) -> Guard { @discardableResult class func push(to viewController: UIViewController? = nil, actions: ((inout ViewModel) -> Void)? = nil) -> Guard {
return Guard(actions: actions).push(to: viewController) return Guard(actions: actions).push(to: viewController)
} }
@ -239,7 +242,7 @@ public extension Guard {
if child.isKind(of: Guard.self) { if child.isKind(of: Guard.self) {
if let g = child as? Guard { if let g = child as? Guard {
if let id = identifier { if let id = identifier {
if g.identifier == id { if g.vm.identifier == id {
gg.append(g) gg.append(g)
} }
} else { } else {
@ -272,7 +275,7 @@ public extension Guard {
// MARK: - // MARK: -
fileprivate extension Guard { internal extension Guard {
/// ///
/// - Parameter sender: /// - Parameter sender:
@ -317,6 +320,5 @@ fileprivate extension Guard {
} }
} }

View File

@ -0,0 +1,80 @@
//
// GuardModel.swift
// ProHUD
//
// Created by xaoxuu on 2019/8/9.
// Copyright © 2019 Titan Studio. All rights reserved.
//
import UIKit
public extension Guard {
struct ViewModel {
/// ID
public var identifier = String(Date().timeIntervalSince1970)
public weak var vc: Guard?
}
}
public extension Guard.ViewModel {
///
/// - Parameter text:
@discardableResult func add(title: String?) -> UILabel {
return vc!.add(title: title)
}
///
/// - Parameter text:
@discardableResult func add(subTitle: String?) -> UILabel {
return vc!.add(subTitle: subTitle)
}
///
/// - Parameter text:
@discardableResult func add(message: String?) -> UILabel {
return vc!.add(message: message)
}
///
/// - Parameter style:
/// - Parameter title:
/// - Parameter action:
@discardableResult func add(action style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton {
return vc!.add(action: style, title: title, handler: handler)
}
///
/// - Parameter index:
/// - Parameter style:
/// - Parameter title:
/// - Parameter handler:
@discardableResult mutating func insert(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton {
return UIButton()
}
///
/// - Parameter index:
/// - Parameter style:
/// - Parameter title:
/// - Parameter handler:
mutating func update(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) {
// vc?.privUpdateButton(action: index, style: style, title: title, handler)
}
///
/// - Parameter index:
func remove(action index: Int...) {
for (i, idx) in index.enumerated() {
vc!.privRemoveAction(index: idx-i)
}
}
}

View File

@ -10,9 +10,6 @@ import UIKit
public class HUDController: UIViewController { public class HUDController: UIViewController {
/// ID
public var identifier = String(Date().timeIntervalSince1970)
/// ///
internal var disappearCallback: (() -> Void)? internal var disappearCallback: (() -> Void)?

View File

@ -243,7 +243,7 @@ public extension Toast {
/// - Parameter title: /// - Parameter title:
/// - Parameter message: /// - Parameter message:
/// - Parameter actions: /// - Parameter actions:
@discardableResult class func push(toast scene: Toast.Scene, title: String? = nil, message: String? = nil, actions: ((Toast) -> Void)? = nil) -> Toast { @discardableResult class func push(scene: Toast.Scene, title: String? = nil, message: String? = nil, actions: ((Toast) -> Void)? = nil) -> Toast {
return Toast(scene: scene, title: title, message: message, actions: actions).push() return Toast(scene: scene, title: title, message: message, actions: actions).push()
} }
@ -252,7 +252,7 @@ public extension Toast {
class func toasts(_ identifier: String?) -> [Toast] { class func toasts(_ identifier: String?) -> [Toast] {
var tt = [Toast]() var tt = [Toast]()
for t in toasts { for t in toasts {
if t.identifier == identifier { if t.model.identifier == identifier {
tt.append(t) tt.append(t)
} }
} }

View File

@ -35,6 +35,9 @@ public extension Toast {
struct ViewModel { struct ViewModel {
/// ID
public var identifier = String(Date().timeIntervalSince1970)
/// 使 /// 使
public var scene = Scene.default public var scene = Scene.default