代码重构

This commit is contained in:
xaoxuu 2023-08-18 20:55:57 +08:00
parent 6eee00880b
commit 32f9af1ae6
52 changed files with 823 additions and 682 deletions

View File

@ -18,7 +18,7 @@ class AlertVC: ListVC {
title = "Alert" title = "Alert"
header.detailLabel.text = "弹窗控件,用于强阻塞性交互,用户必须做出选择或者等待结果才能进入下一步,当多个实例出现时,会以堆叠的形式显示,新的实例会在覆盖旧的实例上层。" header.detailLabel.text = "弹窗控件,用于强阻塞性交互,用户必须做出选择或者等待结果才能进入下一步,当多个实例出现时,会以堆叠的形式显示,新的实例会在覆盖旧的实例上层。"
Alert.Configuration.shared { config in AlertConfiguration.global { config in
config.reloadData { vc in config.reloadData { vc in
if vc.identifier == "custom" { if vc.identifier == "custom" {
return true return true
@ -29,7 +29,7 @@ class AlertVC: ListVC {
list.add(title: "纯文字") { section in list.add(title: "纯文字") { section in
section.add(title: "只有一句话") { section.add(title: "只有一句话") {
Alert(.message("只有一句话").duration(2)).push() Alert(.message("只有一句话").duration(2))
} }
section.add(title: "标题 + 正文") { section.add(title: "标题 + 正文") {
let title = "这是标题" let title = "这是标题"
@ -43,7 +43,7 @@ class AlertVC: ListVC {
list.add(title: "图文弹窗") { section in list.add(title: "图文弹窗") { section in
section.add(title: "纯图标") { section.add(title: "纯图标") {
Alert(.loading(3)).push() Alert(.loading(3))
} }
section.add(title: "图标 + 文字") { section.add(title: "图标 + 文字") {
Alert(.loading.message("正在加载")) { alert in Alert(.loading.message("正在加载")) { alert in
@ -82,8 +82,8 @@ class AlertVC: ListVC {
button.titleLabel?.font = .systemFont(ofSize: 15) button.titleLabel?.font = .systemFont(ofSize: 15)
} }
alert.vm.title = "你正在使用移动网络观看" alert.vm.title = "你正在使用移动网络观看"
} .onViewDidLoad { vc in alert.onViewDidLoad { vc in
guard let alert = vc as? Alert else { guard let alert = vc as? AlertTarget else {
return return
} }
alert.add(contentSpacing: 30) alert.add(contentSpacing: 30)
@ -98,6 +98,7 @@ class AlertVC: ListVC {
} }
} }
}
section.add(title: "只有一段文字 + 无背景色按钮") { section.add(title: "只有一段文字 + 无背景色按钮") {
Alert { alert in Alert { alert in
alert.config.cardMinWidth = 270 alert.config.cardMinWidth = 270
@ -111,8 +112,8 @@ class AlertVC: ListVC {
button.titleLabel?.font = .systemFont(ofSize: 15) button.titleLabel?.font = .systemFont(ofSize: 15)
} }
alert.vm.message = "为了维护社区氛围,上麦用户需进行主播认证" alert.vm.message = "为了维护社区氛围,上麦用户需进行主播认证"
} .onViewDidLoad { vc in alert.onViewDidLoad { vc in
guard let alert = vc as? Alert else { guard let alert = vc as? AlertTarget else {
return return
} }
alert.add(contentSpacing: 30) alert.add(contentSpacing: 30)
@ -127,6 +128,7 @@ class AlertVC: ListVC {
alert.add(action: "确定", style: .plain(textColor: UIColor("#14cccc"))) alert.add(action: "确定", style: .plain(textColor: UIColor("#14cccc")))
} }
} }
}
section.add(title: "只有一段文字 + 3个无背景色按钮") { section.add(title: "只有一段文字 + 3个无背景色按钮") {
Alert { alert in Alert { alert in
alert.config.cardMinWidth = 270 alert.config.cardMinWidth = 270
@ -144,8 +146,8 @@ class AlertVC: ListVC {
stack.spacing = 0 stack.spacing = 0
stack.axis = .vertical // stack.axis = .vertical //
} }
} .onViewDidLoad { vc in alert.onViewDidLoad { vc in
guard let alert = vc as? Alert else { guard let alert = vc as? AlertTarget else {
return return
} }
func createLine() -> UIView { func createLine() -> UIView {
@ -181,6 +183,7 @@ class AlertVC: ListVC {
} }
} }
}
section.add(title: "只有一段文字 + 按钮") { section.add(title: "只有一段文字 + 按钮") {
Alert { alert in Alert { alert in
@ -203,7 +206,7 @@ class AlertVC: ListVC {
} }
list.add(title: "图标 + 文字 + 按钮") { section in list.add(title: "图标 + 文字 + 按钮") { section in
section.add(title: "操作成功") { section.add(title: "操作成功") {
Alert(.success(3).title("操作成功").message("这条消息将在3s后消失")).push() Alert(.success(3).title("操作成功").message("这条消息将在3s后消失"))
} }
section.add(title: "操作失败") { section.add(title: "操作失败") {
Alert { alert in Alert { alert in
@ -287,8 +290,8 @@ class AlertVC: ListVC {
Alert(.loading) { alert in Alert(.loading) { alert in
alert.vm.title = "在弹出过程中增加元素" alert.vm.title = "在弹出过程中增加元素"
alert.add(action: "OK", style: .gray) alert.add(action: "OK", style: .gray)
} .onViewWillAppear { vc in alert.onViewWillAppear { vc in
guard let alert = vc as? Alert else { guard let alert = vc as? AlertTarget else {
return return
} }
alert.vm.message = "这是一段后增加的文字\n动画效果会有细微差别" alert.vm.message = "这是一段后增加的文字\n动画效果会有细微差别"
@ -296,6 +299,7 @@ class AlertVC: ListVC {
} }
} }
} }
}
list.add(title: "实例管理") { section in list.add(title: "实例管理") { section in
section.add(title: "多层级弹窗") { section.add(title: "多层级弹窗") {
func f(i: Int) { func f(i: Int) {
@ -337,7 +341,7 @@ class AlertVC: ListVC {
let vc = UIViewController() let vc = UIViewController()
vc.title = "页面" vc.title = "页面"
vc.view.backgroundColor = .systemYellow vc.view.backgroundColor = .systemYellow
let alert = Alert(.loading.title("正在加载").message("这个弹窗被放在指定容器中")) let alert = Alert(.loading.title("正在加载").message("这个弹窗被放在指定容器中")).target
alert.add(action: "返回上一页") { alert in alert.add(action: "返回上一页") { alert in
vc.dismiss(animated: true) vc.dismiss(animated: true)
} }

View File

@ -16,20 +16,30 @@ class CapsuleVC: ListVC {
title = "Capsule" title = "Capsule"
header.detailLabel.text = "状态胶囊控件,用于状态显示,一个主程序窗口每个位置(上中下)各自最多只有一个状态胶囊实例。" header.detailLabel.text = "状态胶囊控件,用于状态显示,一个主程序窗口每个位置(上中下)各自最多只有一个状态胶囊实例。"
Capsule.Configuration.shared { config in CapsuleConfiguration.global { config in
// config.cardCornerRadius = .infinity // // config.cardCornerRadius = .infinity //
} }
list.add(title: "默认布局:纯文字") { section in list.add(title: "默认布局:纯文字") { section in
section.add(title: "一条简短的消息") { section.add(title: "一条简短的消息") {
Capsule(.message("一条简短的消息")).push() // vmhandlerpushvm
Capsule(.message("一条简短消息"))
} }
section.add(title: "一条稍微长一点的消息") { section.add(title: "一条稍微长一点的消息") {
Capsule(.message("一条稍微长一点的消息")).push() // vmhandlerpushhandler
Capsule { capsule in
// handler
capsule.vm = .message("一条稍微长一点的消息")
}
} }
section.add(title: "(默认)状态胶囊控件,用于状态显示,一个主程序窗口只有一个状态胶囊实例。") { section.add(title: "(默认)状态胶囊控件,用于状态显示,一个主程序窗口只有一个状态胶囊实例。") {
Capsule(.message("状态胶囊控件,用于状态显示,一个主程序窗口只有一个状态胶囊实例。")).push() // push
let obj = Capsule().target
obj.vm = .message("状态胶囊控件,用于状态显示,一个主程序窗口只有一个状态胶囊实例。")
// ... push
obj.push()
} }
section.add(title: "限制1行状态胶囊控件用于状态显示一个主程序窗口只有一个状态胶囊实例。") { section.add(title: "限制1行状态胶囊控件用于状态显示一个主程序窗口只有一个状态胶囊实例。") {
// vmhandler
Capsule(.message("状态胶囊控件,用于状态显示,一个主程序窗口只有一个状态胶囊实例。")) { capsule in Capsule(.message("状态胶囊控件,用于状态显示,一个主程序窗口只有一个状态胶囊实例。")) { capsule in
capsule.config.customTextLabel { label in capsule.config.customTextLabel { label in
label.numberOfLines = 1 label.numberOfLines = 1
@ -39,14 +49,27 @@ class CapsuleVC: ListVC {
} }
list.add(title: "默认布局:图文") { section in list.add(title: "默认布局:图文") { section in
section.add(title: "一条简短的消息") { section.add(title: "下载进度") {
Capsule(.info("一条简短的消息")).push() let capsule = Capsule().target
capsule.vm = .message("正在下载").icon(.init(systemName: "arrow.down.circle.fill")).duration(.infinity)
capsule.update(progress: 0)
capsule.push()
updateProgress(in: 4) { percent in
capsule.update(progress: percent)
} completion: {
capsule.update { toast in
toast.vm = .message("下载成功")
.icon(.init(systemName: "checkmark.circle.fill"))
.duration(5)
.tintColor(.systemGreen)
} }
section.add(title: "一条稍微长一点的消息") { }
Capsule(.systemError.title("500").message("一条稍微长一点的消息")).push() }
section.add(title: "接口报错提示") {
Capsule(.systemError.title("[500]").message("服务端错误"))
} }
section.add(title: "(默认)状态胶囊控件,用于状态显示,一个主程序窗口只有一个状态胶囊实例。") { section.add(title: "(默认)状态胶囊控件,用于状态显示,一个主程序窗口只有一个状态胶囊实例。") {
Capsule(.info("状态胶囊控件,用于状态显示,一个主程序窗口只有一个状态胶囊实例。")).push() Capsule(.info("状态胶囊控件,用于状态显示,一个主程序窗口只有一个状态胶囊实例。"))
} }
section.add(title: "限制1行状态胶囊控件用于状态显示一个主程序窗口只有一个状态胶囊实例。") { section.add(title: "限制1行状态胶囊控件用于状态显示一个主程序窗口只有一个状态胶囊实例。") {
Capsule(.info("状态胶囊控件,用于状态显示,一个主程序窗口只有一个状态胶囊实例。")) { capsule in Capsule(.info("状态胶囊控件,用于状态显示,一个主程序窗口只有一个状态胶囊实例。")) { capsule in
@ -59,14 +82,10 @@ class CapsuleVC: ListVC {
list.add(title: "不同位置、不同动画") { section in list.add(title: "不同位置、不同动画") { section in
section.add(title: "顶部,默认滑入") { section.add(title: "顶部,默认滑入") {
Capsule(.info("一条简短的消息")) { capsule in Capsule(.info("一条简短的消息"))
}
} }
section.add(title: "中间,默认缩放") { section.add(title: "中间,默认缩放") {
Capsule(.middle.info("一条简短的消息")) { capsule in Capsule(.middle.info("一条简短的消息"))
}
} }
section.add(title: "中间,黑底白字,透明渐变") { section.add(title: "中间,黑底白字,透明渐变") {
Capsule(.middle.info("一条简短的消息")) { capsule in Capsule(.middle.info("一条简短的消息")) { capsule in
@ -98,7 +117,7 @@ class CapsuleVC: ListVC {
section.add(title: "底部,渐变背景,默认回弹滑入") { section.add(title: "底部,渐变背景,默认回弹滑入") {
Capsule(.bottom.enter("点击进入")) { capsule in Capsule(.bottom.enter("点击进入")) { capsule in
capsule.config.tintColor = .white capsule.config.tintColor = .white
capsule.config.cardEdgeInsets = .init(top: 16, left: 24, bottom: 16, right: 24) capsule.config.cardEdgeInsets = .init(top: 12, left: 20, bottom: 12, right: 20)
capsule.config.customTextLabel { label in capsule.config.customTextLabel { label in
label.textColor = .white label.textColor = .white
label.font = .boldSystemFont(ofSize: 16) label.font = .boldSystemFont(ofSize: 16)
@ -116,17 +135,18 @@ class CapsuleVC: ListVC {
mask.layer.insertSublayer(gradientLayer, at: 0) mask.layer.insertSublayer(gradientLayer, at: 0)
} }
capsule.config.cardCornerRadius = .infinity capsule.config.cardCornerRadius = .infinity
}.onTapped { capsule in capsule.onTapped { capsule in
Alert(.message("收到点击事件").duration(1)).push() Alert(.message("收到点击事件").duration(1))
capsule.pop() capsule.pop()
} }
} }
} }
} }
}
} }
extension Capsule.ViewModel { extension CapsuleTarget.ViewModel {
static func info(_ text: String?) -> Self { static func info(_ text: String?) -> Self {
.init() .init()

View File

@ -73,7 +73,7 @@ class SheetVC: ListVC {
sheet.add(spacing: 24) sheet.add(spacing: 24)
sheet.add(action: "确认") sheet.add(action: "确认")
sheet.add(action: "取消", style: .gray) sheet.add(action: "取消", style: .gray)
} onTappedBackground: { sheet in sheet.onTappedBackground { sheet in
print("点击了背景") print("点击了背景")
Toast.lazyPush(identifier: "alert") { toast in Toast.lazyPush(identifier: "alert") { toast in
toast.vm = .error toast.vm = .error
@ -84,6 +84,7 @@ class SheetVC: ListVC {
} }
} }
} }
}
list.add(title: "自定义样式") { section in list.add(title: "自定义样式") { section in
section.add(title: "堆叠样式") { section.add(title: "堆叠样式") {
@ -180,8 +181,8 @@ class SheetVC: ListVC {
mask.effect = .none mask.effect = .none
mask.backgroundColor = .clear mask.backgroundColor = .clear
} }
} .onViewWillAppear { vc in sheet.onViewWillAppear { vc in
guard let sheet = vc as? Sheet else { return } guard let sheet = vc as? SheetTarget else { return }
let imgv = UIImageView(image: UIImage(named: "landscape")) let imgv = UIImageView(image: UIImage(named: "landscape"))
imgv.contentMode = .scaleAspectFill imgv.contentMode = .scaleAspectFill
imgv.clipsToBounds = true imgv.clipsToBounds = true
@ -193,6 +194,7 @@ class SheetVC: ListVC {
} }
} }
} }
}
section.add(title: "透明背景") { section.add(title: "透明背景") {

View File

@ -32,15 +32,14 @@ func updateProgress(in duration: TimeInterval, callback: @escaping (_ percent: C
let isTesting: Bool = true let isTesting: Bool = true
class TestToast: Toast { class TestToastTarget: ToastTarget {
override func push() { override func push() {
guard isTesting else { guard isTesting else { return }
return
}
super.push() super.push()
} }
} }
typealias TestToast = HUDProvider<ToastViewModel, TestToastTarget>
class ToastVC: ListVC { class ToastVC: ListVC {
@ -54,7 +53,7 @@ class ToastVC: ListVC {
header.detailLabel.text = message header.detailLabel.text = message
Toast.Configuration.shared { config in ToastConfiguration.global { config in
config.contentViewMask { mask in config.contentViewMask { mask in
mask.backgroundColor = .clear mask.backgroundColor = .clear
mask.effect = UIBlurEffect(style: .systemChromeMaterial) mask.effect = UIBlurEffect(style: .systemChromeMaterial)
@ -66,15 +65,15 @@ class ToastVC: ListVC {
list.add(title: "默认布局") { section in list.add(title: "默认布局") { section in
section.add(title: "标题 + 正文") { section.add(title: "标题 + 正文") {
TestToast(.title(title).message(message)).push() TestToast(.title(title).message(message))
} }
section.add(title: "一段长文本") { section.add(title: "一段长文本") {
Toast(.message(message)).push() Toast(.message(message))
} }
section.add(title: "图标 + 标题 + 正文") { section.add(title: "图标 + 标题 + 正文") {
let s1 = "笑容正在加载" let s1 = "笑容正在加载"
let s2 = "这通常不会太久" let s2 = "这通常不会太久"
let toast = Toast(.loading.title(s1).message(s2)) let toast = Toast(.loading.title(s1).message(s2)).target
toast.push() toast.push()
toast.update(progress: 0) toast.update(progress: 0)
updateProgress(in: 4) { percent in updateProgress(in: 4) { percent in
@ -99,10 +98,10 @@ class ToastVC: ListVC {
} }
} }
section.add(title: "图标 + 一段长文本") { section.add(title: "图标 + 一段长文本") {
Toast(.note.message(message)).push() Toast(.note.message(message))
} }
section.add(title: "网络图标 + 一段文本") { section.add(title: "网络图标 + 一段文本") {
Toast(.message("这是网络图标").icon(.init(string: "https://xaoxuu.com/assets/xaoxuu/avatar/rect-256@2x.png"))).push() Toast(.message("这是网络图标").icon(.init(string: "https://xaoxuu.com/assets/xaoxuu/avatar/rect-256@2x.png")))
} }
} }
@ -113,7 +112,7 @@ class ToastVC: ListVC {
Toast(.msg.title(title).message(message)) { toast in Toast(.msg.title(title).message(message)) { toast in
toast.onTapped { toast in toast.onTapped { toast in
toast.pop() toast.pop()
Alert(.success(1).message("操作成功")).push() Alert(.success(1).message("操作成功"))
} }
} }
} }
@ -150,7 +149,7 @@ class ToastVC: ListVC {
alert.pop() alert.pop()
}) })
toast.pop() toast.pop()
Alert(.success(1).message("Good choice!")).push() Alert(.success(1).message("Good choice!"))
} }
Toast.find(identifier: "loading") { toast in Toast.find(identifier: "loading") { toast in
toast.vm = .success(2).message("加载成功") toast.vm = .success(2).message("加载成功")
@ -227,28 +226,28 @@ class ToastVC: ListVC {
Toast { toast in Toast { toast in
toast.vm = .title("圆角半径").message("可以在共享配置中设置,则全局生效") toast.vm = .title("圆角半径").message("可以在共享配置中设置,则全局生效")
toast.add(action: "8", style: .gray) { toast in toast.add(action: "8", style: .gray) { toast in
Toast.Configuration.shared { config in ToastConfiguration.global { config in
config.cardCornerRadius = 8 config.cardCornerRadius = 8
} }
toast.pop() toast.pop()
foo() foo()
} }
toast.add(action: "16", style: .gray) { toast in toast.add(action: "16", style: .gray) { toast in
Toast.Configuration.shared { config in ToastConfiguration.global { config in
config.cardCornerRadius = 16 config.cardCornerRadius = 16
} }
toast.pop() toast.pop()
foo() foo()
} }
toast.add(action: "24", style: .gray) { toast in toast.add(action: "24", style: .gray) { toast in
Toast.Configuration.shared { config in ToastConfiguration.global { config in
config.cardCornerRadius = 24 config.cardCornerRadius = 24
} }
toast.pop() toast.pop()
foo() foo()
} }
toast.add(action: "32", style: .gray) { toast in toast.add(action: "32", style: .gray) { toast in
Toast.Configuration.shared { config in ToastConfiguration.global { config in
config.cardCornerRadius = 32 config.cardCornerRadius = 32
} }
toast.pop() toast.pop()
@ -330,7 +329,7 @@ class ToastVC: ListVC {
toast.title = "共享配置" toast.title = "共享配置"
toast.vm.message = "建议在App启动后进行通用配置设置所有实例都会先拉取通用配置为默认值修改这些配置会影响到所有实例。" toast.vm.message = "建议在App启动后进行通用配置设置所有实例都会先拉取通用配置为默认值修改这些配置会影响到所有实例。"
toast.add(action: "默认", style: .gray) { toast in toast.add(action: "默认", style: .gray) { toast in
Toast.Configuration.shared { config in ToastConfiguration.global { config in
config.customTitleLabel { titleLabel in config.customTitleLabel { titleLabel in
titleLabel.font = .systemFont(ofSize: 19, weight: .bold) titleLabel.font = .systemFont(ofSize: 19, weight: .bold)
} }
@ -339,7 +338,7 @@ class ToastVC: ListVC {
foo() foo()
} }
toast.add(action: "大号标题") { toast in toast.add(action: "大号标题") { toast in
Toast.Configuration.shared { config in ToastConfiguration.global { config in
config.customTitleLabel { titleLabel in config.customTitleLabel { titleLabel in
titleLabel.font = .systemFont(ofSize: 28, weight: .medium) titleLabel.font = .systemFont(ofSize: 28, weight: .medium)
} }

View File

@ -13,7 +13,7 @@ public class AlertButton: Button {
.init(top: 12, left: 24, bottom: 12, right: 24) .init(top: 12, left: 24, bottom: 12, right: 24)
} }
public override func update(config: ProHUD.Configuration, action: Action) { public override func update(config: CommonConfiguration, action: Action) {
titleLabel?.font = .boldSystemFont(ofSize: 15) titleLabel?.font = .boldSystemFont(ofSize: 15)
layer.cornerRadiusWithContinuous = 8 layer.cornerRadiusWithContinuous = 8
super.update(config: config, action: action) super.update(config: config, action: action)

View File

@ -7,21 +7,19 @@
import UIKit import UIKit
public extension Alert { public class AlertConfiguration: CommonConfiguration {
class Configuration: ProHUD.Configuration {
/// ///
public var stackDepth: CGFloat = 30 public var stackDepth: CGFloat = 30
public var enableShadow: Bool = true public var enableShadow: Bool = true
static var customShared: ((_ config: Configuration) -> Void)? static var customGlobalConfig: ((_ config: AlertConfiguration) -> Void)?
/// ///
/// - Parameter callback: /// - Parameter callback:
public static func shared(_ callback: @escaping (_ config: Configuration) -> Void) { public static func global(_ callback: @escaping (_ config: AlertConfiguration) -> Void) {
customShared = callback customGlobalConfig = callback
} }
var customBackgroundViewMask: ((_ mask: UIView) -> Void)? var customBackgroundViewMask: ((_ mask: UIView) -> Void)?
@ -36,6 +34,4 @@ public extension Alert {
animateDurationForBuildIn ?? 0.6 animateDurationForBuildIn ?? 0.6
} }
}
} }

View File

@ -7,7 +7,7 @@
import UIKit import UIKit
extension Alert: InternalConvenienceLayout { extension AlertTarget: InternalConvenienceLayout {
// MARK: // MARK:
@discardableResult public func add(action: Action) -> Button { @discardableResult public func add(action: Action) -> Button {
@ -155,7 +155,7 @@ extension Alert: InternalConvenienceLayout {
} }
// MARK: more // MARK: more
public extension Alert { public extension AlertTarget {
/// ///
/// - Parameters: /// - Parameters:
@ -164,10 +164,10 @@ public extension Alert {
/// - identifier: /// - identifier:
/// - handler: /// - handler:
/// - Returns: /// - Returns:
@discardableResult func add(action title: String, style: Action.Style = .tinted, identifier: String? = nil, handler: ((_ alert: Alert) -> Void)? = nil) -> Button { @discardableResult func add(action title: String, style: Action.Style = .tinted, identifier: String? = nil, handler: ((_ alert: AlertTarget) -> Void)? = nil) -> Button {
if let handler = handler { if let handler = handler {
let action = Action(identifier: identifier, style: style, title: title) { vc in let action = Action(identifier: identifier, style: style, title: title) { vc in
if let vc = vc as? Alert { if let vc = vc as? AlertTarget {
handler(vc) handler(vc)
} }
} }

View File

@ -7,9 +7,9 @@
import UIKit import UIKit
extension Alert: DefaultLayout { extension AlertTarget: DefaultLayout {
var cfg: ProHUD.Configuration { var cfg: CommonConfiguration {
return config return config
} }
@ -17,6 +17,7 @@ extension Alert: DefaultLayout {
if self.cfg.customReloadData?(self) == true { if self.cfg.customReloadData?(self) == true {
return return
} }
view.tintColor = vm.tintColor ?? config.tintColor
let isFirstLayout: Bool let isFirstLayout: Bool
if contentView.superview == nil { if contentView.superview == nil {
isFirstLayout = animated isFirstLayout = animated
@ -132,7 +133,7 @@ extension Alert: DefaultLayout {
} }
extension Alert { extension AlertTarget {
func setupImageView() { func setupImageView() {
// //

View File

@ -7,14 +7,15 @@
import UIKit import UIKit
extension Alert: HUD { extension AlertTarget {
@objc open func push() { @objc open func push() {
guard Configuration.isEnabled else { return } guard AlertConfiguration.isEnabled else { return }
let window = createAttachedWindowIfNotExists() let window = createAttachedWindowIfNotExists()
guard window.alerts.contains(self) == false else { guard window.alerts.contains(self) == false else {
return return
} }
setDefaultAxis()
view.transform = .init(scaleX: 1.2, y: 1.2) view.transform = .init(scaleX: 1.2, y: 1.2)
view.alpha = 0 view.alpha = 0
navEvents[.onViewWillAppear]?(self) navEvents[.onViewWillAppear]?(self)
@ -34,12 +35,12 @@ extension Alert: HUD {
self.navEvents[.onViewDidAppear]?(self) self.navEvents[.onViewDidAppear]?(self)
} }
window.alerts.append(self) window.alerts.append(self)
Alert.updateAlertsLayout(alerts: window.alerts) AlertTarget.updateAlertsLayout(alerts: window.alerts)
} }
@objc open func pop() { @objc open func pop() {
navEvents[.onViewWillDisappear]?(self) navEvents[.onViewWillDisappear]?(self)
Alert.removeAlert(alert: self) AlertTarget.removeAlert(alert: self)
let duration = config.animateDurationForBuildOut ?? config.animateDurationForBuildOutByDefault let duration = config.animateDurationForBuildOut ?? config.animateDurationForBuildOutByDefault
UIView.animateEaseOut(duration: duration) { UIView.animateEaseOut(duration: duration) {
self.view.alpha = 0 self.view.alpha = 0
@ -63,29 +64,9 @@ extension Alert: HUD {
} }
} }
}
public extension Alert {
/// HUD
/// - Parameters:
/// - identifier:
/// - handler:
static func lazyPush(identifier: String? = nil, file: String = #file, line: Int = #line, handler: @escaping (_ alert: Alert) -> Void, onExists: ((_ alert: Alert) -> Void)? = nil) {
let id = identifier ?? (file + "#\(line)")
if let vc = find(identifier: id).last {
vc.update(handler: onExists ?? handler)
} else {
Alert { alert in
alert.identifier = id
handler(alert)
}
}
}
/// HUD /// HUD
/// - Parameter callback: /// - Parameter callback:
func update(handler: @escaping (_ alert: Alert) -> Void) { @objc open func update(handler: @escaping (_ alert: AlertTarget) -> Void) {
handler(self) handler(self)
reloadData() reloadData()
UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) { UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) {
@ -93,23 +74,12 @@ public extension Alert {
} }
} }
/// HUD
/// - Parameter identifier:
/// - Returns: HUD
@discardableResult static func find(identifier: String, update handler: ((_ alert: Alert) -> Void)? = nil) -> [Alert] {
let arr = AppContext.alertWindow.values.flatMap({ $0.alerts }).filter({ $0.identifier == identifier })
if let handler = handler {
arr.forEach({ $0.update(handler: handler) })
}
return arr
}
} }
// MARK: - layout // MARK: - layout
fileprivate extension Alert { fileprivate extension AlertTarget {
static func updateAlertsLayout(alerts: [Alert]) { static func updateAlertsLayout(alerts: [AlertTarget]) {
for (i, a) in alerts.reversed().enumerated() { for (i, a) in alerts.reversed().enumerated() {
let scale = CGFloat(pow(0.9, CGFloat(i))) let scale = CGFloat(pow(0.9, CGFloat(i)))
UIView.animate(withDuration: 1.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: [.allowUserInteraction, .curveEaseInOut], animations: { UIView.animate(withDuration: 1.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: [.allowUserInteraction, .curveEaseInOut], animations: {
@ -125,7 +95,7 @@ fileprivate extension Alert {
AlertWindow.createAttachedWindowIfNotExists(config: config) AlertWindow.createAttachedWindowIfNotExists(config: config)
} }
static func removeAlert(alert: Alert) { static func removeAlert(alert: AlertTarget) {
guard var alerts = alert.attachedWindow?.alerts else { guard var alerts = alert.attachedWindow?.alerts else {
return return
} }

View File

@ -0,0 +1,48 @@
//
// AlertProvider.swift
//
//
// Created by xaoxuu on 2023/8/18.
//
import UIKit
open class AlertProvider: HUDProvider<AlertViewModel, AlertTarget> {
@discardableResult public required init(_ vm: ViewModel?, initializer: ((_ alert: Target) -> Void)?) {
super.init(vm, initializer: initializer)
}
@discardableResult public required convenience init(initializer: ((_ alert: Target) -> Void)?) {
self.init(nil, initializer: initializer)
}
/// HUD
/// - Parameters:
/// - identifier:
/// - handler:
public static func lazyPush(identifier: String? = nil, file: String = #file, line: Int = #line, handler: @escaping (_ alert: AlertTarget) -> Void, onExists: ((_ alert: AlertTarget) -> Void)? = nil) {
let id = identifier ?? (file + "#\(line)")
if let vc = find(identifier: id).last {
vc.update(handler: onExists ?? handler)
} else {
Self.init { alert in
alert.identifier = id
handler(alert)
}
}
}
/// HUD
/// - Parameter identifier:
/// - Returns: HUD
@discardableResult public static func find(identifier: String, update handler: ((_ alert: AlertTarget) -> Void)? = nil) -> [AlertTarget] {
let arr = AppContext.alertWindow.values.flatMap({ $0.alerts }).filter({ $0.identifier == identifier })
if let handler = handler {
arr.forEach({ $0.update(handler: handler) })
}
return arr
}
}
public typealias Alert = AlertProvider

View File

@ -7,11 +7,11 @@
import UIKit import UIKit
open class Alert: ProHUD.Controller { open class AlertTarget: BaseController, HUDTargetType {
public lazy var config: Configuration = { public lazy var config: AlertConfiguration = {
var cfg = Configuration() var cfg = AlertConfiguration()
Configuration.customShared?(cfg) AlertConfiguration.customGlobalConfig?(cfg)
return cfg return cfg
}() }()
@ -73,10 +73,8 @@ open class Alert: ProHUD.Controller {
return stack return stack
}() }()
@objc(AlertViewModel) open class ViewModel: BaseViewModel {}
/// ///
@objc public var vm = ViewModel() @objc public var vm: AlertViewModel = .init()
public override var title: String? { public override var title: String? {
didSet { didSet {
@ -84,35 +82,22 @@ open class Alert: ProHUD.Controller {
} }
} }
@discardableResult @objc public init(_ vm: ViewModel, handler: ((_ alert: Alert) -> Void)? = nil) { required public override init() {
super.init() super.init()
self.vm = vm
handler?(self)
DispatchQueue.main.async {
if handler != nil {
self.setDefaultAxis()
self.push()
}
}
}
@discardableResult @objc public convenience init(handler: ((_ alert: Alert) -> Void)?) {
self.init(.init(), handler: handler)
}
public override func viewDidLoad() {
super.viewDidLoad()
view.tintColor = config.tintColor
reloadData(animated: false)
navEvents[.onViewDidLoad]?(self)
} }
required public init?(coder: NSCoder) { required public init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
public override func viewDidLoad() {
super.viewDidLoad()
reloadData(animated: false)
navEvents[.onViewDidLoad]?(self)
}
} }
// MARK: // MARK:
extension Alert: LoadingAnimation {} extension AlertTarget: LoadingAnimation {}

View File

@ -0,0 +1,10 @@
//
// AlertViewModel.swift
//
//
// Created by xaoxuu on 2023/8/18.
//
import UIKit
@objc open class AlertViewModel: BaseViewModel {}

View File

@ -9,11 +9,11 @@ import UIKit
class AlertWindow: Window { class AlertWindow: Window {
var alerts: [Alert] = [] var alerts: [AlertTarget] = []
override var usingBackground: Bool { true } override var usingBackground: Bool { true }
static func createAttachedWindowIfNotExists(config: Configuration) -> AlertWindow { static func createAttachedWindowIfNotExists(config: AlertConfiguration) -> AlertWindow {
let windowScene = AppContext.windowScene let windowScene = AppContext.windowScene
if let windowScene = windowScene, let w = AppContext.alertWindow[windowScene] { if let windowScene = windowScene, let w = AppContext.alertWindow[windowScene] {
return w return w
@ -34,7 +34,7 @@ class AlertWindow: Window {
} }
extension Alert { extension AlertTarget {
var attachedWindow: AlertWindow? { var attachedWindow: AlertWindow? {
view.window as? AlertWindow view.window as? AlertWindow
} }

View File

@ -7,18 +7,16 @@
import UIKit import UIKit
public extension Capsule { public class CapsuleConfiguration: CommonConfiguration {
typealias CustomAnimateHandler = ((_ window: UIWindow, _ completion: @escaping () -> Void) -> Void) public typealias CustomAnimateHandler = ((_ window: UIWindow, _ completion: @escaping () -> Void) -> Void)
class Configuration: ProHUD.Configuration { static var customGlobalConfig: ((_ config: CapsuleConfiguration) -> Void)?
static var customShared: ((_ config: Configuration) -> Void)? ///
///
/// - Parameter callback: /// - Parameter callback:
public static func shared(_ callback: @escaping (_ config: Configuration) -> Void) { public static func global(_ callback: @escaping (_ config: CapsuleConfiguration) -> Void) {
customShared = callback customGlobalConfig = callback
} }
override var cardCornerRadiusByDefault: CGFloat { override var cardCornerRadiusByDefault: CGFloat {
@ -52,6 +50,4 @@ public extension Capsule {
} }
}
} }

View File

@ -7,9 +7,9 @@
import UIKit import UIKit
extension Capsule: DefaultLayout { extension CapsuleTarget: DefaultLayout {
var cfg: ProHUD.Configuration { var cfg: CommonConfiguration {
return config return config
} }
@ -18,18 +18,14 @@ extension Capsule: DefaultLayout {
return return
} }
view.tintColor = vm.tintColor ?? config.tintColor
// content // content
loadContentViewIfNeeded() loadContentViewIfNeeded()
loadContentMaskViewIfNeeded() loadContentMaskViewIfNeeded()
// image // image
imageView.removeFromSuperview() setupImageView()
if let icon = vm.icon {
contentStack.insertArrangedSubview(imageView, at: 0)
imageView.image = icon
} else {
contentStack.removeArrangedSubview(imageView)
}
// text // text
textLabel.removeFromSuperview() textLabel.removeFromSuperview()
@ -94,4 +90,27 @@ extension Capsule: DefaultLayout {
}) })
} }
private func setupImageView() {
//
stopRotate(animateLayer)
animateLayer = nil
animation = nil
//
progressView?.removeFromSuperview()
if vm.icon == nil && vm.iconURL == nil {
contentStack.removeArrangedSubview(imageView)
} else {
contentStack.insertArrangedSubview(imageView, at: 0)
}
imageView.image = vm.icon
if let iconURL = vm.iconURL {
config.customWebImage?(imageView, iconURL)
}
if let rotation = vm.rotation {
startRotate(rotation)
}
}
} }

View File

@ -7,10 +7,10 @@
import UIKit import UIKit
extension Capsule: HUD { extension CapsuleTarget {
@objc open func push() { @objc open func push() {
guard Configuration.isEnabled else { return } guard CapsuleConfiguration.isEnabled else { return }
let isNew: Bool let isNew: Bool
let window: CapsuleWindow let window: CapsuleWindow
let position = vm.position let position = vm.position
@ -156,78 +156,15 @@ extension Capsule: HUD {
} }
} }
}
public extension Capsule {
/// HUD
/// - Parameters:
/// - identifier:
/// - handler:
static func lazyPush(identifier: String? = nil, file: String = #file, line: Int = #line, handler: @escaping (_ capsule: Capsule) -> Void, onExists: ((_ capsule: Capsule) -> Void)? = nil) {
let id = identifier ?? (file + "#\(line)")
if let vc = find(identifier: id).last {
vc.update(handler: onExists ?? handler)
} else {
Capsule { capsule in
capsule.identifier = id
handler(capsule)
}
}
}
/// HUD /// HUD
/// - Parameter handler: /// - Parameter handler:
func update(handler: @escaping (_ capsule: Capsule) -> Void) { @objc open func update(handler: @escaping (_ capsule: CapsuleTarget) -> Void) {
handler(self) handler(self)
reloadData() reloadData()
UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) { UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) {
self.view.layoutIfNeeded() self.view.layoutIfNeeded()
} }
} }
/// HUD
/// - Parameter identifier:
/// - Returns: HUD
@discardableResult static func find(identifier: String, update handler: ((_ capsule: Capsule) -> Void)? = nil) -> [Capsule] {
let arr = AppContext.capsuleWindows.values.flatMap({ $0.values }).compactMap({ $0.capsule }).filter({ $0.identifier == identifier })
if let handler = handler {
arr.forEach({ $0.update(handler: handler) })
}
return arr
}
} }
//extension Capsule {
//
// func translateIn(completion: (() -> Void)?) {
// UIView.animateEaseOut(duration: config.animateDurationForBuildInByDefault) {
// if self.config.stackDepthEffect {
// if isPhonePortrait {
// AppContext.appWindow?.transform = .init(translationX: 0, y: 8).scaledBy(x: 0.9, y: 0.9)
// } else {
// AppContext.appWindow?.transform = .init(scaleX: 0.92, y: 0.92)
// }
// AppContext.appWindow?.layer.cornerRadiusWithContinuous = 16
// AppContext.appWindow?.layer.masksToBounds = true
// }
// } completion: { done in
// completion?()
// }
// }
//
// func translateOut(completion: (() -> Void)?) {
// UIView.animateEaseOut(duration: config.animateDurationForBuildOutByDefault) {
// if self.config.stackDepthEffect {
// AppContext.appWindow?.transform = .identity
// AppContext.appWindow?.layer.cornerRadius = 0
// }
// } completion: { done in
// completion?()
// }
// }
//
//}

View File

@ -0,0 +1,53 @@
//
// CapsuleProvider.swift
//
//
// Created by xaoxuu on 2023/8/18.
//
import UIKit
open class CapsuleProvider: HUDProvider<CapsuleTarget.ViewModel, CapsuleTarget> {
/// ViewModelTarget
/// - Parameters:
/// - vm:
/// - initializer:
@discardableResult public required init(_ vm: ViewModel?, initializer: ((_ capsule: Target) -> Void)?) {
super.init(vm, initializer: initializer)
}
@discardableResult public required convenience init(initializer: ((_ capsule: Target) -> Void)?) {
self.init(nil, initializer: initializer)
}
/// HUD
/// - Parameters:
/// - identifier:
/// - handler:
public static func lazyPush(identifier: String? = nil, file: String = #file, line: Int = #line, handler: @escaping (_ capsule: CapsuleTarget) -> Void, onExists: ((_ capsule: CapsuleTarget) -> Void)? = nil) {
let id = identifier ?? (file + "#\(line)")
if let vc = find(identifier: id).last {
vc.update(handler: onExists ?? handler)
} else {
Self.init { capsule in
capsule.identifier = id
handler(capsule)
}
}
}
/// HUD
/// - Parameter identifier:
/// - Returns: HUD
@discardableResult public static func find(identifier: String, update handler: ((_ capsule: CapsuleTarget) -> Void)? = nil) -> [CapsuleTarget] {
let arr = AppContext.capsuleWindows.values.flatMap({ $0.values }).compactMap({ $0.capsule }).filter({ $0.identifier == identifier })
if let handler = handler {
arr.forEach({ $0.update(handler: handler) })
}
return arr
}
}
public typealias Capsule = CapsuleProvider

View File

@ -7,11 +7,11 @@
import UIKit import UIKit
open class Capsule: Controller { open class CapsuleTarget: BaseController, HUDTargetType {
public lazy var config: Configuration = { public lazy var config: CapsuleConfiguration = {
var cfg = Configuration() var cfg = CapsuleConfiguration()
Configuration.customShared?(cfg) CapsuleConfiguration.customGlobalConfig?(cfg)
return cfg return cfg
}() }()
@ -33,6 +33,8 @@ open class Capsule: Controller {
return imgv return imgv
}() }()
public var progressView: ProgressView?
/// ///
public lazy var textLabel: UILabel = { public lazy var textLabel: UILabel = {
let lb = UILabel() let lb = UILabel()
@ -44,56 +46,12 @@ open class Capsule: Controller {
return lb return lb
}() }()
@objc(CapsuleViewModel) open class ViewModel: BaseViewModel { public var vm: CapsuleViewModel = .init()
@objc public enum Position: Int { private var tapActionCallback: ((_ capsule: CapsuleTarget) -> Void)?
case top
case middle
case bottom
}
@objc public var position: Position = .top required public override init() {
public func position(position: Position) -> Self {
self.position = position
return self
}
public static var top: Self {
let obj = Self.init()
obj.position = .top
return obj
}
public static var middle: Self {
let obj = Self.init()
obj.position = .middle
return obj
}
public static var bottom: Self {
let obj = Self.init()
obj.position = .bottom
return obj
}
}
///
@objc public var vm = ViewModel()
private var tapActionCallback: ((_ capsule: Capsule) -> Void)?
@discardableResult @objc public init(_ vm: ViewModel, handler: ((_ capsule: Capsule) -> Void)? = nil) {
super.init() super.init()
self.vm = vm
handler?(self)
DispatchQueue.main.async {
if handler != nil {
self.push()
}
}
}
@discardableResult @objc public convenience init(handler: ((_ capsule: Capsule) -> Void)?) {
self.init(.init(), handler: handler)
} }
required public init?(coder: NSCoder) { required public init?(coder: NSCoder) {
@ -102,7 +60,6 @@ open class Capsule: Controller {
public override func viewDidLoad() { public override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
view.tintColor = vm.tintColor ?? config.tintColor
view.layer.shadowRadius = 8 view.layer.shadowRadius = 8
view.layer.shadowOffset = .init(width: 0, height: 5) view.layer.shadowOffset = .init(width: 0, height: 5)
view.layer.shadowOpacity = 0.1 view.layer.shadowOpacity = 0.1
@ -117,13 +74,13 @@ open class Capsule: Controller {
} }
public func onTapped(action: @escaping (_ capsule: Capsule) -> Void) { public func onTapped(action: @escaping (_ capsule: CapsuleTarget) -> Void) {
self.tapActionCallback = action self.tapActionCallback = action
} }
} }
fileprivate extension Capsule { fileprivate extension CapsuleTarget {
/// ///
/// - Parameter sender: /// - Parameter sender:
@ -132,3 +89,6 @@ fileprivate extension Capsule {
} }
} }
extension CapsuleTarget: LoadingAnimation { }

View File

@ -0,0 +1,40 @@
//
// CapsuleViewModel.swift
//
//
// Created by xaoxuu on 2023/8/18.
//
import UIKit
@objc open class CapsuleViewModel: BaseViewModel {
@objc public enum Position: Int {
case top
case middle
case bottom
}
@objc public var position: Position = .top
public func position(position: Position) -> Self {
self.position = position
return self
}
public static var top: Self {
let obj = Self.init()
obj.position = .top
return obj
}
public static var middle: Self {
let obj = Self.init()
obj.position = .middle
return obj
}
public static var bottom: Self {
let obj = Self.init()
obj.position = .bottom
return obj
}
}

View File

@ -9,9 +9,9 @@ import UIKit
class CapsuleWindow: Window { class CapsuleWindow: Window {
var capsule: Capsule var capsule: CapsuleTarget
init(capsule: Capsule) { init(capsule: CapsuleTarget) {
self.capsule = capsule self.capsule = capsule
super.init(frame: .zero) super.init(frame: .zero)
windowScene = AppContext.windowScene windowScene = AppContext.windowScene
@ -36,7 +36,7 @@ class CapsuleWindow: Window {
} }
extension Capsule { extension CapsuleTarget {
var attachedWindow: CapsuleWindow? { var attachedWindow: CapsuleWindow? {
view.window as? CapsuleWindow view.window as? CapsuleWindow
} }

View File

@ -1,5 +1,5 @@
// //
// Controller.swift // BaseController.swift
// //
// //
// Created by xaoxuu on 2022/8/29. // Created by xaoxuu on 2022/8/29.
@ -7,7 +7,7 @@
import UIKit import UIKit
open class Controller: UIViewController { open class BaseController: UIViewController {
/// ID /// ID
public var identifier = String(Date().timeIntervalSince1970) public var identifier = String(Date().timeIntervalSince1970)
@ -56,29 +56,29 @@ open class Controller: UIViewController {
case onTappedBackground = "onTappedBackground" case onTappedBackground = "onTappedBackground"
} }
var navEvents = [NavEvent: ((Controller) -> Void)]() var navEvents = [NavEvent: ((BaseController) -> Void)]()
@discardableResult public func onViewDidLoad(_ callback: ((_ vc: Controller) -> Void)?) -> Controller { @discardableResult public func onViewDidLoad(_ callback: ((_ vc: BaseController) -> Void)?) -> BaseController {
navEvents[.onViewDidLoad] = callback navEvents[.onViewDidLoad] = callback
return self return self
} }
@discardableResult public func onViewWillAppear(_ callback: ((_ vc: Controller) -> Void)?) -> Controller { @discardableResult public func onViewWillAppear(_ callback: ((_ vc: BaseController) -> Void)?) -> BaseController {
navEvents[.onViewWillAppear] = callback navEvents[.onViewWillAppear] = callback
return self return self
} }
@discardableResult public func onViewDidAppear(_ callback: ((_ vc: Controller) -> Void)?) -> Controller { @discardableResult public func onViewDidAppear(_ callback: ((_ vc: BaseController) -> Void)?) -> BaseController {
navEvents[.onViewDidAppear] = callback navEvents[.onViewDidAppear] = callback
return self return self
} }
@discardableResult public func onViewWillDisappear(_ callback: ((_ vc: Controller) -> Void)?) -> Controller { @discardableResult public func onViewWillDisappear(_ callback: ((_ vc: BaseController) -> Void)?) -> BaseController {
navEvents[.onViewWillDisappear] = callback navEvents[.onViewWillDisappear] = callback
return self return self
} }
@discardableResult public func onViewDidDisappear(_ callback: ((_ vc: Controller) -> Void)?) -> Controller { @discardableResult public func onViewDidDisappear(_ callback: ((_ vc: BaseController) -> Void)?) -> BaseController {
navEvents[.onViewDidDisappear] = callback navEvents[.onViewDidDisappear] = callback
return self return self
} }
@ -91,7 +91,7 @@ open class Controller: UIViewController {
} }
// MARK: - // MARK: -
extension Controller { extension BaseController {
func addTouchUpAction(for button: UIButton, action: @escaping () -> Void) { func addTouchUpAction(for button: UIButton, action: @escaping () -> Void) {
button.addTarget(self, action: #selector(didTappedButton(_:)), for: .touchUpInside) button.addTarget(self, action: #selector(didTappedButton(_:)), for: .touchUpInside)

View File

@ -37,9 +37,9 @@ open class Action: NSObject {
open var title: String? open var title: String?
open var handler: ((_ vc: HUD) -> Void)? open var handler: ((_ vc: HUDControllerType) -> Void)?
public init(identifier: String? = nil, style: Style = .tinted, title: String?, handler: ((_ vc: HUD) -> Void)? = nil) { public init(identifier: String? = nil, style: Style = .tinted, title: String?, handler: ((_ vc: HUDControllerType) -> Void)? = nil) {
self.identifier = identifier self.identifier = identifier
self.style = style self.style = style
self.title = title self.title = title

View File

@ -7,8 +7,10 @@
import UIKit import UIKit
public protocol HUDViewModelType {}
/// ///
open class BaseViewModel: NSObject { open class BaseViewModel: NSObject, HUDViewModelType {
/// ///
@objc open var icon: UIImage? @objc open var icon: UIImage?

View File

@ -7,7 +7,7 @@
import UIKit import UIKit
public class Configuration: NSObject { open class CommonConfiguration: NSObject {
/// ///
public static var isEnabled: Bool = true public static var isEnabled: Bool = true
@ -171,11 +171,11 @@ public class Configuration: NSObject {
customWebImage = handler customWebImage = handler
} }
var customReloadData: ((_ vc: Controller) -> Bool)? var customReloadData: ((_ vc: BaseController) -> Bool)?
/// ///
/// - Parameter callback: /// - Parameter callback:
public func reloadData(_ callback: @escaping (_ vc: Controller) -> Bool) { public func reloadData(_ callback: @escaping (_ vc: BaseController) -> Bool) {
customReloadData = callback customReloadData = callback
} }
@ -188,5 +188,9 @@ public class Configuration: NSObject {
customContentViewMask = callback customContentViewMask = callback
} }
override init() {
}
} }

View File

@ -7,7 +7,7 @@
import Foundation import Foundation
public protocol CommonLayout: Controller { public protocol CommonLayout: BaseController {
func reloadData() func reloadData()
} }

View File

@ -9,7 +9,7 @@ import UIKit
protocol DefaultLayout: CommonLayout { protocol DefaultLayout: CommonLayout {
var cfg: Configuration { get } var cfg: CommonConfiguration { get }
func reloadData(animated: Bool) func reloadData(animated: Bool)

View File

@ -1,20 +0,0 @@
//
// ProHUD.swift
//
//
// Created by xaoxuu on 2022/8/29.
//
import UIKit
@objc public protocol HUD {
@objc func push()
@objc func pop()
}
//public extension HUD {
// func push(workspace: Workspace?) {
// AppContext.workspace = workspace
// push()
// }
//}

View File

@ -8,7 +8,7 @@
import UIKit import UIKit
/// ///
public protocol LoadingAnimation: Controller { public protocol LoadingAnimation: BaseController {
var imageView: UIImageView { get } var imageView: UIImageView { get }
var progressView: ProgressView? { get set } var progressView: ProgressView? { get set }

View File

@ -0,0 +1,64 @@
//
// Provider.swift
//
//
// Created by xaoxuu on 2023/8/18.
//
import UIKit
public protocol HUDProviderType {
associatedtype ViewModel = HUDViewModelType
associatedtype Target = HUDTargetType
/// ViewModelTarget
/// - Parameters:
/// - vm:
/// - initializer:
@discardableResult init(_ vm: ViewModel?, initializer: ((_ target: Target) -> Void)?)
}
open class HUDProvider<ViewModel: HUDViewModelType, Target: HUDTargetType>: HUDProviderType {
/// HUD
public var target: Target
/// ViewModelTarget
/// - Parameters:
/// - vm:
/// - initializer:
@discardableResult public required init(_ vm: ViewModel?, initializer: ((_ target: Target) -> Void)?) {
var t = Target()
if let vm = vm as? Target.ViewModel {
t.vm = vm
}
initializer?(t)
self.target = t
if (vm == nil && initializer == nil) == false {
DispatchQueue.main.async {
t.push()
}
}
}
/// Target
/// - Parameter initializer:
@discardableResult public convenience init(initializer: ((_ target: Target) -> Void)?) {
self.init(nil, initializer: initializer)
}
/// ViewModelTarget
/// - Parameter vm:
@discardableResult public convenience init(_ vm: ViewModel?) {
self.init(vm, initializer: nil)
}
/// target.push()
@discardableResult public convenience init() {
self.init(nil, initializer: nil)
}
}

View File

@ -0,0 +1,19 @@
//
// Target.swift
//
//
// Created by xaoxuu on 2023/8/18.
//
import UIKit
@objc public protocol HUDControllerType {
@objc func push()
@objc func pop()
}
public protocol HUDTargetType: HUDControllerType {
associatedtype ViewModel = HUDViewModelType
var vm: ViewModel { get set }
init()
}

View File

@ -36,7 +36,7 @@ public struct AppContext {
static var toastWindows: [UIWindowScene: [ToastWindow]] = [:] static var toastWindows: [UIWindowScene: [ToastWindow]] = [:]
static var alertWindow: [UIWindowScene: AlertWindow] = [:] static var alertWindow: [UIWindowScene: AlertWindow] = [:]
static var sheetWindows: [UIWindowScene: [SheetWindow]] = [:] static var sheetWindows: [UIWindowScene: [SheetWindow]] = [:]
static var capsuleWindows: [UIWindowScene: [Capsule.ViewModel.Position: CapsuleWindow]] = [:] static var capsuleWindows: [UIWindowScene: [CapsuleTarget.ViewModel.Position: CapsuleWindow]] = [:]
static var current: AppContext? { static var current: AppContext? {
guard let windowScene = windowScene else { return nil } guard let windowScene = windowScene else { return nil }
@ -120,7 +120,7 @@ extension AppContext {
var toastWindows: [ToastWindow] { var toastWindows: [ToastWindow] {
Self.toastWindows[windowScene] ?? [] Self.toastWindows[windowScene] ?? []
} }
var capsuleWindows: [Capsule.ViewModel.Position: CapsuleWindow] { var capsuleWindows: [CapsuleTarget.ViewModel.Position: CapsuleWindow] {
Self.capsuleWindows[windowScene] ?? [:] Self.capsuleWindows[windowScene] ?? [:]
} }
} }

View File

@ -9,7 +9,7 @@ import Foundation
func consolePrint(_ items: Any...) { func consolePrint(_ items: Any...) {
#if DEBUG #if DEBUG
guard Configuration.enablePrint else { return } guard CommonConfiguration.enablePrint else { return }
print(">> ProHUD:", items) print(">> ProHUD:", items)
#endif #endif
} }

View File

@ -59,7 +59,7 @@ extension LoadingAnimation {
} }
/// ///
extension Controller { extension BaseController {
@objc func pauseLoadingAnimation() { @objc func pauseLoadingAnimation() {
if let layer = animateLayer { if let layer = animateLayer {
animation = layer.animation(forKey: .rotateKey) animation = layer.animation(forKey: .rotateKey)

View File

@ -29,7 +29,7 @@ open class Button: UIButton {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
public convenience init(config: ProHUD.Configuration, action: Action) { public convenience init(config: CommonConfiguration, action: Action) {
self.init(frame: .zero) self.init(frame: .zero)
layer.cornerRadiusWithContinuous = 8 layer.cornerRadiusWithContinuous = 8
self.update(config: config, action: action) self.update(config: config, action: action)
@ -37,7 +37,7 @@ open class Button: UIButton {
/// ///
/// - Parameter style: /// - Parameter style:
open func update(config: ProHUD.Configuration, action: Action) { open func update(config: CommonConfiguration, action: Action) {
self.action = action self.action = action
setTitle(action.title, for: .normal) setTitle(action.title, for: .normal)
switch action.style { switch action.style {

View File

@ -13,7 +13,7 @@ public class SheetButton: Button {
.init(top: 14, left: 28, bottom: 14, right: 28) .init(top: 14, left: 28, bottom: 14, right: 28)
} }
public override func update(config: ProHUD.Configuration, action: Action) { public override func update(config: CommonConfiguration, action: Action) {
titleLabel?.font = .boldSystemFont(ofSize: 18) titleLabel?.font = .boldSystemFont(ofSize: 18)
layer.cornerRadiusWithContinuous = 12 layer.cornerRadiusWithContinuous = 12
super.update(config: config, action: action) super.update(config: config, action: action)

View File

@ -7,9 +7,7 @@
import UIKit import UIKit
public extension Sheet { public class SheetConfiguration: CommonConfiguration {
class Configuration: ProHUD.Configuration {
/// ///
public var stackDepthEffect: Bool = false public var stackDepthEffect: Bool = false
@ -28,12 +26,12 @@ public extension Sheet {
customSubtitleLabel = handler customSubtitleLabel = handler
} }
static var customShared: ((_ config: Configuration) -> Void)? static var customGlobalConfig: ((_ config: SheetConfiguration) -> Void)?
/// ///
/// - Parameter callback: /// - Parameter callback:
public static func shared(_ callback: @escaping (_ config: Configuration) -> Void) { public static func global(_ callback: @escaping (_ config: SheetConfiguration) -> Void) {
customShared = callback customGlobalConfig = callback
} }
var customBackgroundViewMask: ((_ mask: UIView) -> Void)? var customBackgroundViewMask: ((_ mask: UIView) -> Void)?
@ -62,6 +60,4 @@ public extension Sheet {
override var cardCornerRadiusByDefault: CGFloat { cardCornerRadius ?? 32 } override var cardCornerRadiusByDefault: CGFloat { cardCornerRadius ?? 32 }
}
} }

View File

@ -7,7 +7,7 @@
import UIKit import UIKit
extension Sheet: ConvenienceLayout { extension SheetTarget: ConvenienceLayout {
// MARK: // MARK:
@discardableResult public func add(action: Action) -> Button { @discardableResult public func add(action: Action) -> Button {
@ -126,7 +126,7 @@ extension Sheet: ConvenienceLayout {
} }
// MARK: more // MARK: more
public extension Sheet { public extension SheetTarget {
/// ///
/// - Parameter text: /// - Parameter text:
@ -185,10 +185,10 @@ public extension Sheet {
/// - identifier: /// - identifier:
/// - handler: /// - handler:
/// - Returns: /// - Returns:
@discardableResult func add(action title: String, style: Action.Style = .tinted, identifier: String? = nil, handler: ((_ sheet: Sheet) -> Void)? = nil) -> Button { @discardableResult func add(action title: String, style: Action.Style = .tinted, identifier: String? = nil, handler: ((_ sheet: SheetTarget) -> Void)? = nil) -> Button {
if let handler = handler { if let handler = handler {
let action = Action(identifier: identifier, style: style, title: title) { vc in let action = Action(identifier: identifier, style: style, title: title) { vc in
if let vc = vc as? Sheet { if let vc = vc as? SheetTarget {
handler(vc) handler(vc)
} }
} }

View File

@ -7,9 +7,9 @@
import UIKit import UIKit
extension Sheet: DefaultLayout { extension SheetTarget: DefaultLayout {
var cfg: ProHUD.Configuration { var cfg: CommonConfiguration {
return config return config
} }
@ -17,6 +17,7 @@ extension Sheet: DefaultLayout {
if self.cfg.customReloadData?(self) == true { if self.cfg.customReloadData?(self) == true {
return return
} }
view.tintColor = vm.tintColor ?? config.tintColor
// background // background
if backgroundView.superview == nil { if backgroundView.superview == nil {
view.insertSubview(backgroundView, at: 0) view.insertSubview(backgroundView, at: 0)

View File

@ -7,10 +7,10 @@
import UIKit import UIKit
extension Sheet: HUD { extension SheetTarget {
@objc open func push() { @objc open func push() {
guard Configuration.isEnabled else { return } guard SheetConfiguration.isEnabled else { return }
let isNew: Bool let isNew: Bool
let window: SheetWindow let window: SheetWindow
var windows = AppContext.current?.sheetWindows ?? [] var windows = AppContext.current?.sheetWindows ?? []
@ -57,29 +57,9 @@ extension Sheet: HUD {
} }
} }
}
public extension Sheet {
/// HUD
/// - Parameters:
/// - identifier:
/// - handler:
static func lazyPush(identifier: String? = nil, file: String = #file, line: Int = #line, handler: @escaping (_ sheet: Sheet) -> Void, onExists: ((_ sheet: Sheet) -> Void)? = nil) {
let id = identifier ?? (file + "#\(line)")
if let vc = find(identifier: id).last {
vc.update(handler: onExists ?? handler)
} else {
Sheet { sheet in
sheet.identifier = id
handler(sheet)
}
}
}
/// HUD /// HUD
/// - Parameter handler: /// - Parameter handler:
func update(handler: @escaping (_ sheet: Sheet) -> Void) { @objc open func update(handler: @escaping (_ sheet: SheetTarget) -> Void) {
handler(self) handler(self)
reloadData() reloadData()
UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) { UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) {
@ -87,21 +67,9 @@ public extension Sheet {
} }
} }
/// HUD
/// - Parameter identifier:
/// - Returns: HUD
@discardableResult static func find(identifier: String, update handler: ((_ sheet: Sheet) -> Void)? = nil) -> [Sheet] {
let arr = AppContext.sheetWindows.values.flatMap({ $0 }).compactMap({ $0.sheet }).filter({ $0.identifier == identifier })
if let handler = handler {
arr.forEach({ $0.update(handler: handler) })
}
return arr
}
} }
extension SheetTarget {
extension Sheet {
func translateIn(completion: (() -> Void)?) { func translateIn(completion: (() -> Void)?) {
UIView.animateEaseOut(duration: config.animateDurationForBuildInByDefault) { UIView.animateEaseOut(duration: config.animateDurationForBuildInByDefault) {

View File

@ -0,0 +1,48 @@
//
// SheetProvider.swift
//
//
// Created by xaoxuu on 2023/8/18.
//
import UIKit
open class SheetProvider: HUDProvider<SheetViewModel, SheetTarget> {
@discardableResult public required init(_ vm: ViewModel?, initializer: ((_ sheet: Target) -> Void)?) {
super.init(vm, initializer: initializer)
}
@discardableResult public required convenience init(initializer: ((_ sheet: Target) -> Void)?) {
self.init(nil, initializer: initializer)
}
/// HUD
/// - Parameters:
/// - identifier:
/// - handler:
public static func lazyPush(identifier: String? = nil, file: String = #file, line: Int = #line, handler: @escaping (_ sheet: SheetTarget) -> Void, onExists: ((_ sheet: SheetTarget) -> Void)? = nil) {
let id = identifier ?? (file + "#\(line)")
if let vc = find(identifier: id).last {
vc.update(handler: onExists ?? handler)
} else {
Self.init { sheet in
sheet.identifier = id
handler(sheet)
}
}
}
/// HUD
/// - Parameter identifier:
/// - Returns: HUD
@discardableResult public static func find(identifier: String, update handler: ((_ sheet: SheetTarget) -> Void)? = nil) -> [SheetTarget] {
let arr = AppContext.sheetWindows.values.flatMap({ $0 }).compactMap({ $0.sheet }).filter({ $0.identifier == identifier })
if let handler = handler {
arr.forEach({ $0.update(handler: handler) })
}
return arr
}
}
public typealias Sheet = SheetProvider

View File

@ -7,13 +7,13 @@
import UIKit import UIKit
open class Sheet: Controller { open class SheetTarget: BaseController, HUDTargetType {
weak var window: SheetWindow? weak var window: SheetWindow?
public lazy var config: Configuration = { public lazy var config: SheetConfiguration = {
var cfg = Configuration() var cfg = SheetConfiguration()
Configuration.customShared?(cfg) SheetConfiguration.customGlobalConfig?(cfg)
return cfg return cfg
}() }()
@ -33,7 +33,7 @@ open class Sheet: Controller {
return stack return stack
}() }()
private var onTappedBackground: ((_ sheet: Sheet) -> Void)? private var tapActionCallback: ((_ sheet: SheetTarget) -> Void)?
public override var title: String? { public override var title: String? {
didSet { didSet {
@ -41,16 +41,10 @@ open class Sheet: Controller {
} }
} }
@discardableResult @objc public init(handler: @escaping (_ sheet: Sheet) -> Void, onTappedBackground action: ((_ sheet: Sheet) -> Void)? = nil) { public var vm: SheetViewModel = .init()
required public override init() {
super.init() super.init()
onTappedBackground = action
handler(self)
DispatchQueue.main.async {
self.push()
}
} }
required public init?(coder: NSCoder) { required public init?(coder: NSCoder) {
@ -59,7 +53,6 @@ open class Sheet: Controller {
public override func viewDidLoad() { public override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
view.tintColor = config.tintColor
// //
let tap = UITapGestureRecognizer(target: self, action: #selector(_onTappedBackground(_:))) let tap = UITapGestureRecognizer(target: self, action: #selector(_onTappedBackground(_:)))
@ -73,11 +66,15 @@ open class Sheet: Controller {
} }
public func onTappedBackground(action: @escaping (_ sheet: SheetTarget) -> Void) {
self.tapActionCallback = action
}
} }
extension Sheet { extension SheetTarget {
@objc func _onTappedBackground(_ sender: UITapGestureRecognizer) { @objc func _onTappedBackground(_ sender: UITapGestureRecognizer) {
if let act = onTappedBackground { if let act = tapActionCallback {
act(self) act(self)
} else { } else {
self.pop() self.pop()

View File

@ -0,0 +1,10 @@
//
// SheetViewModel.swift
//
//
// Created by xaoxuu on 2023/8/18.
//
import UIKit
@objc open class SheetViewModel: BaseViewModel {}

View File

@ -9,9 +9,9 @@ import UIKit
class SheetWindow: Window { class SheetWindow: Window {
var sheet: Sheet var sheet: SheetTarget
init(sheet: Sheet) { init(sheet: SheetTarget) {
self.sheet = sheet self.sheet = sheet
if let scene = AppContext.windowScene { if let scene = AppContext.windowScene {
super.init(windowScene: scene) super.init(windowScene: scene)
@ -29,7 +29,7 @@ class SheetWindow: Window {
} }
extension Sheet { extension SheetTarget {
func getContextWindows() -> [SheetWindow] { func getContextWindows() -> [SheetWindow] {
guard let windowScene = windowScene else { guard let windowScene = windowScene else {
return [] return []

View File

@ -13,7 +13,7 @@ public class ToastButton: Button {
.init(top: 10, left: 24, bottom: 10, right: 24) .init(top: 10, left: 24, bottom: 10, right: 24)
} }
public override func update(config: ProHUD.Configuration, action: Action) { public override func update(config: CommonConfiguration, action: Action) {
titleLabel?.font = .boldSystemFont(ofSize: 15) titleLabel?.font = .boldSystemFont(ofSize: 15)
layer.cornerRadiusWithContinuous = 8 layer.cornerRadiusWithContinuous = 8
super.update(config: config, action: action) super.update(config: config, action: action)

View File

@ -7,9 +7,7 @@
import UIKit import UIKit
public extension Toast { public class ToastConfiguration: CommonConfiguration {
class Configuration: ProHUD.Configuration {
/// ///
public var margin = CGFloat(8) public var margin = CGFloat(8)
@ -21,12 +19,12 @@ public extension Toast {
/// ///
public var lineSpace = CGFloat(4) public var lineSpace = CGFloat(4)
static var customShared: ((_ config: Configuration) -> Void)? static var customGlobalConfig: ((_ config: ToastConfiguration) -> Void)?
/// ///
/// - Parameter callback: /// - Parameter callback:
public static func shared(_ callback: @escaping (_ config: Configuration) -> Void) { public static func global(_ callback: @escaping (_ config: ToastConfiguration) -> Void) {
customShared = callback customGlobalConfig = callback
} }
/// ///
@ -51,7 +49,4 @@ public extension Toast {
animateDurationForBuildIn ?? 0.8 animateDurationForBuildIn ?? 0.8
} }
}
} }

View File

@ -7,7 +7,7 @@
import UIKit import UIKit
extension Toast: ConvenienceLayout { extension ToastTarget: ConvenienceLayout {
// MARK: // MARK:
@ -18,10 +18,10 @@ extension Toast: ConvenienceLayout {
/// - identifier: /// - identifier:
/// - handler: /// - handler:
/// - Returns: /// - Returns:
@discardableResult public func add(action title: String, style: Action.Style = .tinted, identifier: String? = nil, handler: ((_ toast: Toast) -> Void)? = nil) -> Button { @discardableResult public func add(action title: String, style: Action.Style = .tinted, identifier: String? = nil, handler: ((_ toast: ToastTarget) -> Void)? = nil) -> Button {
if let handler = handler { if let handler = handler {
let action = Action(identifier: identifier, style: style, title: title) { vc in let action = Action(identifier: identifier, style: style, title: title) { vc in
if let vc = vc as? Toast { if let vc = vc as? ToastTarget {
handler(vc) handler(vc)
} }
} }

View File

@ -7,9 +7,9 @@
import UIKit import UIKit
extension Toast: DefaultLayout { extension ToastTarget: DefaultLayout {
var cfg: ProHUD.Configuration { var cfg: CommonConfiguration {
return config return config
} }
@ -17,6 +17,7 @@ extension Toast: DefaultLayout {
if self.cfg.customReloadData?(self) == true { if self.cfg.customReloadData?(self) == true {
return return
} }
view.tintColor = vm.tintColor ?? config.tintColor
loadContentViewIfNeeded() loadContentViewIfNeeded()
loadContentMaskViewIfNeeded() loadContentMaskViewIfNeeded()
guard customView == nil else { guard customView == nil else {
@ -117,7 +118,7 @@ extension Toast: DefaultLayout {
} }
extension Toast { extension ToastTarget {
func loadActionStackIfNeeded() { func loadActionStackIfNeeded() {
guard actionStack.arrangedSubviews.count > 0 else { guard actionStack.arrangedSubviews.count > 0 else {
actionStack.removeFromSuperview() actionStack.removeFromSuperview()
@ -149,4 +150,5 @@ extension Toast {
} }
} }
} }

View File

@ -7,7 +7,7 @@
import UIKit import UIKit
extension Toast: HUD { extension ToastTarget {
private func calcHeight() -> CGFloat { private func calcHeight() -> CGFloat {
var height = CGFloat(0) var height = CGFloat(0)
@ -34,8 +34,9 @@ extension Toast: HUD {
height += cardEdgeInsets.top + cardEdgeInsets.bottom height += cardEdgeInsets.top + cardEdgeInsets.bottom
return height return height
} }
@objc open func push() { @objc open func push() {
guard Configuration.isEnabled else { return } guard ToastConfiguration.isEnabled else { return }
let isNew: Bool let isNew: Bool
let window: ToastWindow let window: ToastWindow
var windows = AppContext.current?.toastWindows ?? [] var windows = AppContext.current?.toastWindows ?? []
@ -104,29 +105,9 @@ extension Toast: HUD {
} }
} }
}
public extension Toast {
/// HUD
/// - Parameters:
/// - identifier:
/// - handler:
static func lazyPush(identifier: String? = nil, file: String = #file, line: Int = #line, handler: @escaping (_ toast: Toast) -> Void, onExists: ((_ toast: Toast) -> Void)? = nil) {
let id = identifier ?? (file + "#\(line)")
if let vc = find(identifier: id).last {
vc.update(handler: onExists ?? handler)
} else {
Toast { toast in
toast.identifier = id
handler(toast)
}
}
}
/// HUD /// HUD
/// - Parameter handler: /// - Parameter handler:
func update(handler: @escaping (_ toast: Toast) -> Void) { @objc open func update(handler: @escaping (_ toast: ToastTarget) -> Void) {
handler(self) handler(self)
reloadData() reloadData()
UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) { UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) {
@ -134,17 +115,6 @@ public extension Toast {
} }
} }
/// HUD
/// - Parameter identifier:
/// - Returns: HUD
@discardableResult static func find(identifier: String, update handler: ((_ toast: Toast) -> Void)? = nil) -> [Toast] {
let arr = AppContext.toastWindows.values.flatMap({ $0 }).compactMap({ $0.toast }).filter({ $0.identifier == identifier })
if let handler = handler {
arr.forEach({ $0.update(handler: handler) })
}
return arr
}
} }
// MARK: - layout // MARK: - layout

View File

@ -0,0 +1,48 @@
//
// ToastProvider.swift
//
//
// Created by xaoxuu on 2023/8/18.
//
import UIKit
open class ToastProvider: HUDProvider<ToastViewModel, ToastTarget> {
@discardableResult public required init(_ vm: ViewModel?, initializer: ((_ toast: Target) -> Void)?) {
super.init(vm, initializer: initializer)
}
@discardableResult public required convenience init(initializer: ((_ toast: Target) -> Void)?) {
self.init(nil, initializer: initializer)
}
/// HUD
/// - Parameters:
/// - identifier:
/// - handler:
public static func lazyPush(identifier: String? = nil, file: String = #file, line: Int = #line, handler: @escaping (_ toast: ToastTarget) -> Void, onExists: ((_ toast: ToastTarget) -> Void)? = nil) {
let id = identifier ?? (file + "#\(line)")
if let vc = find(identifier: id).last {
vc.update(handler: onExists ?? handler)
} else {
Self.init { toast in
toast.identifier = id
handler(toast)
}
}
}
/// HUD
/// - Parameter identifier:
/// - Returns: HUD
@discardableResult public static func find(identifier: String, update handler: ((_ toast: ToastTarget) -> Void)? = nil) -> [ToastTarget] {
let arr = AppContext.toastWindows.values.flatMap({ $0 }).compactMap({ $0.toast }).filter({ $0.identifier == identifier })
if let handler = handler {
arr.forEach({ $0.update(handler: handler) })
}
return arr
}
}
public typealias Toast = ToastProvider

View File

@ -7,13 +7,13 @@
import UIKit import UIKit
open class Toast: Controller { open class ToastTarget: BaseController, HUDTargetType {
weak var window: ToastWindow? weak var window: ToastWindow?
public lazy var config: Configuration = { public lazy var config: ToastConfiguration = {
var cfg = Configuration() var cfg = ToastConfiguration()
Configuration.customShared?(cfg) ToastConfiguration.customGlobalConfig?(cfg)
return cfg return cfg
}() }()
@ -83,12 +83,10 @@ open class Toast: Controller {
/// ///
public var isRemovable = true public var isRemovable = true
@objc(ToastViewModel) open class ViewModel: BaseViewModel {}
/// ///
@objc public var vm = ViewModel() @objc public var vm = ToastViewModel()
private var tapActionCallback: ((_ toast: Toast) -> Void)? private var tapActionCallback: ((_ toast: ToastTarget) -> Void)?
public override var title: String? { public override var title: String? {
@ -97,20 +95,8 @@ open class Toast: Controller {
} }
} }
required public override init() {
@discardableResult @objc public init(_ vm: ViewModel, handler: ((_ toast: Toast) -> Void)? = nil) {
super.init() super.init()
self.vm = vm
handler?(self)
DispatchQueue.main.async {
if handler != nil {
self.push()
}
}
}
@discardableResult @objc public convenience init(handler: ((_ toast: Toast) -> Void)?) {
self.init(.init(), handler: handler)
} }
required public init?(coder: NSCoder) { required public init?(coder: NSCoder) {
@ -119,7 +105,6 @@ open class Toast: Controller {
public override func viewDidLoad() { public override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
view.tintColor = config.tintColor
// //
let tap = UITapGestureRecognizer(target: self, action: #selector(_onTappedGesture(_:))) let tap = UITapGestureRecognizer(target: self, action: #selector(_onTappedGesture(_:)))
@ -133,13 +118,13 @@ open class Toast: Controller {
} }
public func onTapped(action: @escaping (_ toast: Toast) -> Void) { public func onTapped(action: @escaping (_ toast: ToastTarget) -> Void) {
self.tapActionCallback = action self.tapActionCallback = action
} }
} }
fileprivate extension Toast { fileprivate extension ToastTarget {
/// ///
/// - Parameter sender: /// - Parameter sender:
@ -173,4 +158,4 @@ fileprivate extension Toast {
} }
extension Toast: LoadingAnimation { } extension ToastTarget: LoadingAnimation { }

View File

@ -0,0 +1,12 @@
//
// ToastViewModel.swift
//
//
// Created by xaoxuu on 2023/8/18.
//
import UIKit
@objc open class ToastViewModel: BaseViewModel {
}

View File

@ -9,11 +9,11 @@ import UIKit
class ToastWindow: Window { class ToastWindow: Window {
var toast: Toast var toast: ToastTarget
var maxY = CGFloat(0) var maxY = CGFloat(0)
init(toast: Toast) { init(toast: ToastTarget) {
self.toast = toast self.toast = toast
super.init(frame: .zero) super.init(frame: .zero)
windowScene = AppContext.windowScene windowScene = AppContext.windowScene
@ -36,7 +36,7 @@ class ToastWindow: Window {
} }
extension Toast { extension ToastTarget {
func getContextWindows() -> [ToastWindow] { func getContextWindows() -> [ToastWindow] {
guard let windowScene = windowScene else { guard let windowScene = windowScene else {
return [] return []