mirror of https://github.com/xaoxuu/ProHUD
example
This commit is contained in:
parent
539ad04623
commit
ad3576cf6f
|
@ -30,7 +30,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
// a.bodyFont = .regular(17)
|
// a.bodyFont = .regular(17)
|
||||||
// a.boldTextFont = .bold(18)
|
// a.boldTextFont = .bold(18)
|
||||||
// a.buttonFont = .bold(18)
|
// a.buttonFont = .bold(18)
|
||||||
a.forceQuitTimer = 3
|
a.forceQuitTimer = 5 // 多少秒后可以强制关闭弹窗(为了方便测试,一般不要设置这么小)
|
||||||
}
|
}
|
||||||
// cfg.toast { (t) in
|
// cfg.toast { (t) in
|
||||||
// t.titleFont = .bold(18)
|
// t.titleFont = .bold(18)
|
||||||
|
@ -78,7 +78,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||||
extension ProHUD.Scene {
|
extension ProHUD.Scene {
|
||||||
|
|
||||||
static var delete: ProHUD.Scene {
|
static var delete: ProHUD.Scene {
|
||||||
var scene = ProHUD.Scene(identifier: "delete")
|
var scene = ProHUD.Scene(identifier: "prohud.delete")
|
||||||
scene.image = UIImage(named: "prohud.trash")
|
scene.image = UIImage(named: "prohud.trash")
|
||||||
scene.title = "确认删除"
|
scene.title = "确认删除"
|
||||||
scene.message = "此操作不可撤销"
|
scene.message = "此操作不可撤销"
|
||||||
|
|
|
@ -8,18 +8,46 @@
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
typealias Callback = () -> Void
|
||||||
|
|
||||||
|
struct Table {
|
||||||
|
var sections = [Section]()
|
||||||
|
mutating func addSection(title: String, callback: @escaping (inout Section) -> Void) {
|
||||||
|
var sec = Section()
|
||||||
|
sec.header = title
|
||||||
|
callback(&sec)
|
||||||
|
sections.append(sec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct Section {
|
||||||
|
var header = ""
|
||||||
|
var footer = ""
|
||||||
|
var rows = [Row]()
|
||||||
|
mutating func addRow(title: String, subtitle: String? = nil, callback: @escaping Callback) {
|
||||||
|
rows.append(Row(title: title, subtitle: subtitle, callback: callback))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct Row {
|
||||||
|
var title: String
|
||||||
|
var subtitle: String?
|
||||||
|
var callback: Callback
|
||||||
|
}
|
||||||
|
|
||||||
class BaseListVC: UIViewController {
|
class BaseListVC: UIViewController {
|
||||||
|
|
||||||
|
|
||||||
|
var ts = [[String]]()
|
||||||
|
var cs = [[Callback]]()
|
||||||
|
|
||||||
|
var vm = Table()
|
||||||
|
var secs = [Section]()
|
||||||
|
|
||||||
lazy var tableView: UITableView = {
|
lazy var tableView: UITableView = {
|
||||||
let tv = UITableView()
|
let tv = UITableView(frame: .zero, style: .grouped)
|
||||||
|
|
||||||
return tv
|
return tv
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var titles: [String] {
|
|
||||||
return ["Toast", "Alert", "Guard"]
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
@ -27,29 +55,47 @@ class BaseListVC: UIViewController {
|
||||||
view.addSubview(tableView)
|
view.addSubview(tableView)
|
||||||
tableView.dataSource = self
|
tableView.dataSource = self
|
||||||
tableView.delegate = self
|
tableView.delegate = self
|
||||||
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
|
|
||||||
tableView.snp.makeConstraints { (mk) in
|
tableView.snp.makeConstraints { (mk) in
|
||||||
mk.edges.equalToSuperview()
|
mk.edges.equalToSuperview()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension BaseListVC: UITableViewDataSource, UITableViewDelegate {
|
extension BaseListVC: UITableViewDataSource, UITableViewDelegate {
|
||||||
|
func numberOfSections(in tableView: UITableView) -> Int {
|
||||||
|
return vm.sections.count
|
||||||
|
}
|
||||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||||
return titles.count
|
return vm.sections[section].rows.count
|
||||||
}
|
}
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
|
let cell: UITableViewCell
|
||||||
cell.textLabel?.text = titles[indexPath.row]
|
if let c = tableView.dequeueReusableCell(withIdentifier: "cell") {
|
||||||
|
cell = c
|
||||||
|
} else {
|
||||||
|
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cell")
|
||||||
|
cell.textLabel?.numberOfLines = 0
|
||||||
|
cell.detailTextLabel?.textColor = .gray
|
||||||
|
cell.detailTextLabel?.numberOfLines = 0
|
||||||
|
|
||||||
|
}
|
||||||
|
cell.textLabel?.text = vm.sections[indexPath.section].rows[indexPath.row].title
|
||||||
|
cell.detailTextLabel?.text = vm.sections[indexPath.section].rows[indexPath.row].subtitle
|
||||||
return cell
|
return cell
|
||||||
}
|
}
|
||||||
|
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||||
|
return vm.sections[section].header
|
||||||
|
}
|
||||||
|
func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
|
||||||
|
return vm.sections[section].footer
|
||||||
|
}
|
||||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
tableView.deselectRow(at: indexPath, animated: true)
|
tableView.deselectRow(at: indexPath, animated: true)
|
||||||
|
vm.sections[indexPath.section].rows[indexPath.row].callback()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,91 +9,109 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import ProHUD
|
import ProHUD
|
||||||
|
|
||||||
|
// 模拟2秒后同步成功
|
||||||
|
func loadingSuccessAfter2Seconds() {
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now()+2) {
|
||||||
|
Alert.find("loading", last: { (a) in
|
||||||
|
a.update { (vm) in
|
||||||
|
vm.scene = .success
|
||||||
|
vm.title = "同步成功"
|
||||||
|
vm.message = nil
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class TestAlertVC: BaseListVC {
|
class TestAlertVC: BaseListVC {
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
// Do any additional setup after loading the view.
|
vm.addSection(title: "最简单的写法") { (sec) in
|
||||||
|
sec.addRow(title: "Alert.push(scene: .loading)") {
|
||||||
|
Alert.push(scene: .loading)
|
||||||
|
}
|
||||||
|
sec.addRow(title: "Alert.push(scene: .success)") {
|
||||||
|
Alert.push(scene: .success)
|
||||||
|
}
|
||||||
|
sec.addRow(title: "Alert.push(scene: .warning)") {
|
||||||
|
Alert.push(scene: .warning)
|
||||||
|
}
|
||||||
|
sec.addRow(title: "Alert.push(scene: .error)") {
|
||||||
|
Alert.push(scene: .error)
|
||||||
|
}
|
||||||
|
sec.addRow(title: "Alert.push(scene: .failure)") {
|
||||||
|
Alert.push(scene: .failure)
|
||||||
|
}
|
||||||
|
sec.footer = "这些是自带的场景,可以重写已有场景,或者扩展新的场景。"
|
||||||
}
|
}
|
||||||
|
|
||||||
override var titles: [String] {
|
vm.addSection(title: "常用场景示例") { (sec) in
|
||||||
return ["极端场景:正在同步(超时未处理)",
|
// MARK: 场景:同步成功(写法1)
|
||||||
"场景:同步成功(写法1)",
|
sec.addRow(title: "场景:同步成功(写法1)") {
|
||||||
"场景:同步成功(写法2)",
|
Alert.push("loading") { (a) in
|
||||||
"场景:同步失败和重试",
|
|
||||||
"极端场景:短时间内调用了多次同一个弹窗",
|
|
||||||
"极端场景:多个不同的弹窗重叠",
|
|
||||||
"测试较长的标题和内容",
|
|
||||||
"测试特别长的标题和内容",
|
|
||||||
"场景:正在同步(更新进度)"]
|
|
||||||
}
|
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
||||||
tableView.deselectRow(at: indexPath, animated: true)
|
|
||||||
let row = indexPath.row
|
|
||||||
if row == 0 {
|
|
||||||
func f() {
|
|
||||||
Alert.push(scene: .loading, title: "正在同步", message: "请稍等片刻") { (a) in
|
|
||||||
a.identifier = "loading"
|
|
||||||
a.startRotate()
|
|
||||||
a.didForceQuit {
|
|
||||||
let t = Toast.push(scene: .loading, title: "正在同步", message: "请稍等片刻(点击展开为Alert)") { (vm) in
|
|
||||||
vm.identifier = "loading"
|
|
||||||
}
|
|
||||||
t.startRotate()
|
|
||||||
t.didTapped { [weak t] in
|
|
||||||
t?.pop()
|
|
||||||
f()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
f()
|
|
||||||
} else if row == 1 {
|
|
||||||
Alert.push() { (a) in
|
|
||||||
a.identifier = "loading"
|
|
||||||
a.startRotate()
|
|
||||||
a.update { (vm) in
|
a.update { (vm) in
|
||||||
vm.scene = .loading
|
vm.scene = .loading
|
||||||
vm.title = "正在同步"
|
vm.title = "正在同步"
|
||||||
vm.message = "请稍等片刻"
|
vm.message = "请稍等片刻"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now()+2) {
|
|
||||||
Alert.find("loading", last: { (a) in
|
|
||||||
a.update { (vm) in
|
|
||||||
vm.scene = .success
|
|
||||||
vm.title = "同步成功"
|
|
||||||
vm.message = nil
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else if row == 2 {
|
|
||||||
let a = Alert.push() { (a) in
|
|
||||||
a.identifier = "loading"
|
|
||||||
}
|
|
||||||
a.startRotate()
|
a.startRotate()
|
||||||
|
}
|
||||||
|
loadingSuccessAfter2Seconds()
|
||||||
|
}
|
||||||
|
// MARK: 场景:同步成功(写法2)
|
||||||
|
sec.addRow(title: "场景:同步成功(写法2)") {
|
||||||
|
let a = Alert.push("loading") { (a) in
|
||||||
|
a.startRotate()
|
||||||
|
}
|
||||||
a.update { (vm) in
|
a.update { (vm) in
|
||||||
vm.scene = .loading
|
vm.scene = .loading
|
||||||
vm.title = "正在同步"
|
vm.title = "正在同步"
|
||||||
vm.message = "请稍等片刻"
|
vm.message = "请稍等片刻"
|
||||||
}
|
}
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now()+2) {
|
loadingSuccessAfter2Seconds()
|
||||||
Alert.find("loading", last: { (a) in
|
}
|
||||||
|
// MARK: 场景:正在同步(更新进度)
|
||||||
|
sec.addRow(title: "场景:正在同步(更新进度)") {
|
||||||
|
Alert.push("progress") { (a) in
|
||||||
|
a.update { (vm) in
|
||||||
|
vm.scene = .loading
|
||||||
|
vm.title = "正在同步"
|
||||||
|
vm.message = "请稍等片刻"
|
||||||
|
}
|
||||||
|
a.startRotate()
|
||||||
|
a.update(progress: 0)
|
||||||
|
let s = DispatchSemaphore(value: 1)
|
||||||
|
DispatchQueue.global().async {
|
||||||
|
for i in 0 ... 100 {
|
||||||
|
s.wait()
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
Alert.find("progress", last: { (a) in
|
||||||
|
a.update(progress: CGFloat(i)/100)
|
||||||
|
print("\(CGFloat(i)/100)")
|
||||||
|
if i == 100 {
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now()+0.5) {
|
||||||
a.update { (vm) in
|
a.update { (vm) in
|
||||||
vm.scene = .success
|
vm.scene = .success
|
||||||
vm.title = "同步成功"
|
vm.title = "同步成功"
|
||||||
vm.message = nil
|
vm.message = nil
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now()+0.03) {
|
||||||
|
s.signal()
|
||||||
}
|
}
|
||||||
} else if row == 3 {
|
|
||||||
Alert.push() { (a) in
|
|
||||||
a.identifier = "loading"
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// MARK: 场景:同步失败和重试
|
||||||
|
sec.addRow(title: "场景:同步失败和重试(布局变化)") {
|
||||||
|
Alert.push("loading", scene: .loading)
|
||||||
func loading() {
|
func loading() {
|
||||||
Alert.find("loading", last: { (a) in
|
Alert.find("loading") { (a) in
|
||||||
a.update { (vm) in
|
a.update { (vm) in
|
||||||
vm.scene = .loading
|
vm.scene = .loading
|
||||||
vm.title = "正在同步"
|
vm.title = "正在同步"
|
||||||
|
@ -112,22 +130,42 @@ class TestAlertVC: BaseListVC {
|
||||||
vm.add(action: .cancel, title: "取消", handler: nil)
|
vm.add(action: .cancel, title: "取消", handler: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
loading()
|
loading()
|
||||||
} else if row == 4 {
|
}
|
||||||
|
sec.footer = "两种写法1和写法2动画效果略微不同"
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.addSection(title: "为了解决代码逻辑疏漏导致程序卡死、弹窗重叠等问题") { (sec) in
|
||||||
|
// MARK: 极端场景:正在同步(超时未处理)
|
||||||
|
sec.addRow(title: "极端场景:正在同步(超时未处理)", subtitle: "超时未处理的意外情况,弹窗可以手动关闭。(在config中配置所需时间)") {
|
||||||
|
func f() {
|
||||||
|
Alert.push(scene: .loading, title: "正在同步", message: "请稍等片刻") { (a) in
|
||||||
|
a.identifier = "loading"
|
||||||
|
a.startRotate()
|
||||||
|
a.didForceQuit {
|
||||||
|
let t = Toast.push(scene: .loading, title: "正在同步", message: "请稍等片刻(点击展开为Alert)") { (vm) in
|
||||||
|
vm.identifier = "loading"
|
||||||
|
}
|
||||||
|
t.startRotate()
|
||||||
|
t.didTapped { [weak t] in
|
||||||
|
t?.pop()
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: 极端场景:短时间内调用了多次同一个弹窗
|
||||||
|
sec.addRow(title: "极端场景:短时间内调用了多次同一个弹窗", subtitle: "多次调用,页面弹窗应该是毫无变化的。(本例中,4秒内调用了6次)") {
|
||||||
func loading(_ index: Int = 1) {
|
func loading(_ index: Int = 1) {
|
||||||
if let _ = Alert.find("loading").last {
|
if Alert.find("loading").count == 0 {
|
||||||
Toast.push("loading-tip") { (t) in
|
Alert.push("loading", scene: .loading) { (a) in
|
||||||
t.update { (vm) in
|
|
||||||
vm.title = "此时又调用了一次相同的弹窗 x\(index)"
|
|
||||||
}
|
|
||||||
t.pulse()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Alert.push("loading") { (a) in
|
|
||||||
a.update { (vm) in
|
a.update { (vm) in
|
||||||
vm.scene = .loading
|
|
||||||
vm.title = "正在加载"
|
vm.title = "正在加载"
|
||||||
}
|
}
|
||||||
a.startRotate()
|
a.startRotate()
|
||||||
|
@ -150,7 +188,9 @@ class TestAlertVC: BaseListVC {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now()+4) {
|
DispatchQueue.main.asyncAfter(deadline: .now()+4) {
|
||||||
loading(6)
|
loading(6)
|
||||||
}
|
}
|
||||||
} else if row == 5 {
|
}
|
||||||
|
// MARK: 极端场景:多个不同的弹窗重叠
|
||||||
|
sec.addRow(title: "极端场景:多个不同的弹窗重叠", subtitle: "多个弹窗不得不重叠的时候,ProHUD的景深处理可以使其看起来舒服一些。") {
|
||||||
func f(_ i: Int) {
|
func f(_ i: Int) {
|
||||||
Alert.push() { (a) in
|
Alert.push() { (a) in
|
||||||
a.startRotate()
|
a.startRotate()
|
||||||
|
@ -171,7 +211,16 @@ class TestAlertVC: BaseListVC {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
||||||
f(4)
|
f(4)
|
||||||
}
|
}
|
||||||
} else if row == 6 {
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.addSection(title: "") { (sec) in
|
||||||
|
|
||||||
|
// MARK: 测试较长的标题和内容
|
||||||
|
sec.addRow(title: "测试较长的标题和内容") {
|
||||||
Alert.push() { (a) in
|
Alert.push() { (a) in
|
||||||
a.update { (vm) in
|
a.update { (vm) in
|
||||||
vm.scene = .confirm
|
vm.scene = .confirm
|
||||||
|
@ -180,7 +229,9 @@ class TestAlertVC: BaseListVC {
|
||||||
vm.add(action: .default, title: "我知道了", handler: nil)
|
vm.add(action: .default, title: "我知道了", handler: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if row == 7 {
|
}
|
||||||
|
// MARK: 测试特别长的标题和内容
|
||||||
|
sec.addRow(title: "测试特别长的标题和内容", subtitle: "这种情况编码阶段就可以避免,所以没有做特别处理,请控制内容长度不要过长。") {
|
||||||
Alert.push() { (a) in
|
Alert.push() { (a) in
|
||||||
a.update { (vm) in
|
a.update { (vm) in
|
||||||
vm.scene = .warning
|
vm.scene = .warning
|
||||||
|
@ -189,39 +240,21 @@ class TestAlertVC: BaseListVC {
|
||||||
vm.add(action: .default, title: "我知道了", handler: nil)
|
vm.add(action: .default, title: "我知道了", handler: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if row == 8 {
|
|
||||||
Alert.push("progress") { (a) in
|
|
||||||
a.update { (vm) in
|
|
||||||
vm.scene = .loading
|
|
||||||
vm.title = "正在同步"
|
|
||||||
vm.message = "请稍等片刻"
|
|
||||||
}
|
|
||||||
a.startRotate()
|
|
||||||
a.update(progress: 0)
|
|
||||||
let s = DispatchSemaphore(value: 1)
|
|
||||||
DispatchQueue.global().async {
|
|
||||||
for i in 0 ... 5 {
|
|
||||||
s.wait()
|
|
||||||
DispatchQueue.main.async {
|
|
||||||
Alert.find("progress", last: { (a) in
|
|
||||||
a.update(progress: CGFloat(i)/5)
|
|
||||||
print("\(CGFloat(i)/5)")
|
|
||||||
if i == 5 {
|
|
||||||
a.update { (vm) in
|
|
||||||
vm.scene = .success
|
|
||||||
vm.title = "同步成功"
|
|
||||||
vm.message = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
|
|
||||||
s.signal()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// MARK: 只有标题
|
||||||
|
sec.addRow(title: "只有标题") {
|
||||||
|
Alert.push(scene: .default, title: "标题")
|
||||||
|
}
|
||||||
|
// MARK: 只有消息
|
||||||
|
sec.addRow(title: "只有消息") {
|
||||||
|
Alert.push(scene: .default, message: "这是消息")
|
||||||
|
}
|
||||||
|
// MARK: 只有消息
|
||||||
|
sec.addRow(title: "既没有标题也没有消息") {
|
||||||
|
Alert.push("a")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func simulateSync() {
|
func simulateSync() {
|
||||||
|
|
|
@ -15,17 +15,9 @@ class TestGuardVC: BaseListVC {
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
// Do any additional setup after loading the view.
|
vm.addSection(title: "") { (sec) in
|
||||||
}
|
// MARK: 场景:删除菜单
|
||||||
|
sec.addRow(title: "场景:删除菜单") {
|
||||||
override var titles: [String] {
|
|
||||||
return ["场景:删除菜单", "场景:升级至专业版", "场景:隐私协议页面", "对比:原生的ActionSheet", "对比:原生Present效果"]
|
|
||||||
}
|
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
||||||
tableView.deselectRow(at: indexPath, animated: true)
|
|
||||||
let row = indexPath.row
|
|
||||||
if row == 0 {
|
|
||||||
Guard.push("del") { (vc) in
|
Guard.push("del") { (vc) in
|
||||||
vc.update { (vm) in
|
vc.update { (vm) in
|
||||||
vm.add(action: .destructive, title: "删除") { [weak vc] in
|
vm.add(action: .destructive, title: "删除") { [weak vc] in
|
||||||
|
@ -42,7 +34,10 @@ class TestGuardVC: BaseListVC {
|
||||||
vm.add(action: .cancel, title: "取消", handler: nil)
|
vm.add(action: .cancel, title: "取消", handler: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if row == 1 {
|
}
|
||||||
|
|
||||||
|
// MARK: 场景:升级至专业版
|
||||||
|
sec.addRow(title: "场景:升级至专业版") {
|
||||||
// 可以通过id来避免重复
|
// 可以通过id来避免重复
|
||||||
Guard.push("pro") { (vc) in
|
Guard.push("pro") { (vc) in
|
||||||
vc.identifier = "pro"
|
vc.identifier = "pro"
|
||||||
|
@ -84,7 +79,10 @@ class TestGuardVC: BaseListVC {
|
||||||
vm.add(action: .cancel, title: "取消", handler: nil)
|
vm.add(action: .cancel, title: "取消", handler: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if row == 2 {
|
}
|
||||||
|
|
||||||
|
// MARK: 场景:隐私协议页面
|
||||||
|
sec.addRow(title: "场景:隐私协议页面") {
|
||||||
Guard.push("license") { (vc) in
|
Guard.push("license") { (vc) in
|
||||||
vc.isFullScreen = true
|
vc.isFullScreen = true
|
||||||
vc.update { (vm) in
|
vc.update { (vm) in
|
||||||
|
@ -104,20 +102,27 @@ class TestGuardVC: BaseListVC {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if row == 3 {
|
}
|
||||||
|
|
||||||
|
// MARK: 对比:原生的ActionSheet
|
||||||
|
sec.addRow(title: "对比:原生的ActionSheet") {
|
||||||
let ac = UIAlertController(title: "Title", message: "message", preferredStyle: .actionSheet)
|
let ac = UIAlertController(title: "Title", message: "message", preferredStyle: .actionSheet)
|
||||||
let ok = UIAlertAction(title: "OK", style: .default, handler: nil)
|
let ok = UIAlertAction(title: "OK", style: .default, handler: nil)
|
||||||
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
|
let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
|
||||||
ac.addAction(ok)
|
ac.addAction(ok)
|
||||||
ac.addAction(cancel)
|
ac.addAction(cancel)
|
||||||
ac.popoverPresentationController?.sourceView = tableView.cellForRow(at: indexPath)
|
ac.popoverPresentationController?.sourceView = self.view
|
||||||
self.present(ac, animated: true, completion: nil)
|
self.present(ac, animated: true, completion: nil)
|
||||||
} else if row == 4 {
|
}
|
||||||
|
// MARK: 对比:原生Present效果
|
||||||
|
sec.addRow(title: "对比:原生Present效果") {
|
||||||
let vc = UIViewController()
|
let vc = UIViewController()
|
||||||
vc.view.backgroundColor = .white
|
vc.view.backgroundColor = .white
|
||||||
vc.title = "ceshi"
|
vc.title = "ceshi"
|
||||||
present(vc, animated: true, completion: nil)
|
self.present(vc, animated: true, completion: nil)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,44 +9,25 @@
|
||||||
import UIKit
|
import UIKit
|
||||||
import ProHUD
|
import ProHUD
|
||||||
|
|
||||||
|
typealias Callback2 = (String) -> Void
|
||||||
class TestToastVC: BaseListVC {
|
class TestToastVC: BaseListVC {
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
// Do any additional setup after loading the view.
|
// Do any additional setup after loading the view.
|
||||||
}
|
|
||||||
|
|
||||||
override var titles: [String] {
|
vm.addSection(title: "基本场景") { (sec) in
|
||||||
return ["场景:正在同步",
|
// MARK: 场景:正在同步
|
||||||
"场景:正在同步(更新进度)",
|
sec.addRow(title: "场景:正在同步") {
|
||||||
"场景:同步成功",
|
|
||||||
"场景:同步失败",
|
|
||||||
"场景:设备电量过低",
|
|
||||||
"传入指定图标",
|
|
||||||
"禁止手势移除",
|
|
||||||
"组合使用示例",
|
|
||||||
"避免重复发布同一条信息",
|
|
||||||
"根据id查找并修改实例",
|
|
||||||
"测试较长的标题和内容",
|
|
||||||
"测试特别长的标题和内容",
|
|
||||||
"测试只有title",
|
|
||||||
"测试只有message",
|
|
||||||
"自定义旋转的图片"]
|
|
||||||
}
|
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
||||||
tableView.deselectRow(at: indexPath, animated: true)
|
|
||||||
let row = indexPath.row
|
|
||||||
if row == 0 {
|
|
||||||
Toast.push(scene: .loading, title: "正在同步", message: "请稍等片刻") { (vm) in
|
Toast.push(scene: .loading, title: "正在同步", message: "请稍等片刻") { (vm) in
|
||||||
vm.identifier = "loading"
|
vm.identifier = "loading"
|
||||||
}.startRotate()
|
}.startRotate()
|
||||||
simulateSync()
|
self.simulateSync()
|
||||||
} else if row == 1 {
|
}
|
||||||
if let _ = Toast.find("progress").last {
|
// MARK: 场景:正在同步(更新进度)
|
||||||
|
sec.addRow(title: "场景:正在同步(更新进度)") {
|
||||||
} else {
|
if Toast.find("progress").count == 0 {
|
||||||
Toast.push("progress") { (t) in
|
Toast.push("progress") { (t) in
|
||||||
t.update { (vm) in
|
t.update { (vm) in
|
||||||
vm.scene = .loading
|
vm.scene = .loading
|
||||||
|
@ -79,14 +60,17 @@ class TestToastVC: BaseListVC {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else if row == 2 {
|
// MARK: 场景:同步成功
|
||||||
|
sec.addRow(title: "场景:同步成功") {
|
||||||
let t = Toast.push(scene: .success, title: "同步成功", message: "点击查看详情")
|
let t = Toast.push(scene: .success, title: "同步成功", message: "点击查看详情")
|
||||||
t.didTapped { [weak self, weak t] in
|
t.didTapped { [weak self, weak t] in
|
||||||
self?.presentEmptyVC(title: "详情")
|
self?.presentEmptyVC(title: "详情")
|
||||||
t?.pop()
|
t?.pop()
|
||||||
}
|
}
|
||||||
} else if row == 3 {
|
}
|
||||||
|
// MARK: 场景:同步失败
|
||||||
|
sec.addRow(title: "场景:同步失败") {
|
||||||
Toast.push(scene: .error, title: "同步失败", message: "请稍后重试。点击查看详情") { (vc) in
|
Toast.push(scene: .error, title: "同步失败", message: "请稍后重试。点击查看详情") { (vc) in
|
||||||
vc.update { (vm) in
|
vc.update { (vm) in
|
||||||
vm.duration = 0
|
vm.duration = 0
|
||||||
|
@ -96,10 +80,9 @@ class TestToastVC: BaseListVC {
|
||||||
vc?.pop()
|
vc?.pop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if row == 4 {
|
}
|
||||||
Toast.push(scene: .warning, title: "设备电量过低", message: "请及时对设备进行充电,以免影响使用。")
|
// MARK: 场景:设备电量过低
|
||||||
|
sec.addRow(title: "场景:设备电量过低") {
|
||||||
} else if row == 5 {
|
|
||||||
Toast.push(scene: .default, title: "传入指定图标测试", message: "这是消息内容") { (vc) in
|
Toast.push(scene: .default, title: "传入指定图标测试", message: "这是消息内容") { (vc) in
|
||||||
vc.update { (vm) in
|
vc.update { (vm) in
|
||||||
if #available(iOS 13.0, *) {
|
if #available(iOS 13.0, *) {
|
||||||
|
@ -110,14 +93,25 @@ class TestToastVC: BaseListVC {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if row == 6 {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.addSection(title: "") { (sec) in
|
||||||
|
// MARK: 传入指定图标
|
||||||
|
sec.addRow(title: "传入指定图标") {
|
||||||
|
Toast.push(scene: .warning, title: "设备电量过低", message: "请及时对设备进行充电,以免影响使用。")
|
||||||
|
}
|
||||||
|
// MARK: 禁止手势移除
|
||||||
|
sec.addRow(title: "禁止手势移除") {
|
||||||
Toast.push(scene: .default, title: "禁止手势移除", message: "这条消息无法通过向上滑动移出屏幕。5秒后自动消失,每次拖拽都会刷新倒计时。") { (vc) in
|
Toast.push(scene: .default, title: "禁止手势移除", message: "这条消息无法通过向上滑动移出屏幕。5秒后自动消失,每次拖拽都会刷新倒计时。") { (vc) in
|
||||||
vc.isRemovable = false
|
vc.isRemovable = false
|
||||||
vc.update { (vm) in
|
vc.update { (vm) in
|
||||||
vm.duration = 5
|
vm.duration = 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if row == 7 {
|
}
|
||||||
|
// MARK: 组合使用示例
|
||||||
|
sec.addRow(title: "组合使用示例") {
|
||||||
Toast.push(scene: .message, title: "好友邀请", message: "你收到一条好友邀请,点击查看详情。", duration: 10) { (vc) in
|
Toast.push(scene: .message, title: "好友邀请", message: "你收到一条好友邀请,点击查看详情。", duration: 10) { (vc) in
|
||||||
vc.identifier = "xxx"
|
vc.identifier = "xxx"
|
||||||
vc.didTapped { [weak vc] in
|
vc.didTapped { [weak vc] in
|
||||||
|
@ -135,7 +129,9 @@ class TestToastVC: BaseListVC {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if row == 8 {
|
}
|
||||||
|
// MARK: 避免重复发布同一条信息
|
||||||
|
sec.addRow(title: "避免重复发布同一条信息") {
|
||||||
if let t = Toast.find("aaa").last {
|
if let t = Toast.find("aaa").last {
|
||||||
t.pulse()
|
t.pulse()
|
||||||
t.update() { (vm) in
|
t.update() { (vm) in
|
||||||
|
@ -150,7 +146,9 @@ class TestToastVC: BaseListVC {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if row == 9 {
|
}
|
||||||
|
// MARK: 根据id查找并修改实例
|
||||||
|
sec.addRow(title: "根据id查找并修改实例") {
|
||||||
Toast.push("aaa") { (t) in
|
Toast.push("aaa") { (t) in
|
||||||
t.update { (vm) in
|
t.update { (vm) in
|
||||||
vm.scene = .success
|
vm.scene = .success
|
||||||
|
@ -159,7 +157,9 @@ class TestToastVC: BaseListVC {
|
||||||
}
|
}
|
||||||
t.pulse()
|
t.pulse()
|
||||||
}
|
}
|
||||||
} else if row == 10 {
|
}
|
||||||
|
// MARK: 测试较长的标题和内容
|
||||||
|
sec.addRow(title: "测试较长的标题和内容") {
|
||||||
Toast.push() { (a) in
|
Toast.push() { (a) in
|
||||||
a.update { (vm) in
|
a.update { (vm) in
|
||||||
vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
|
vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
|
||||||
|
@ -167,7 +167,9 @@ class TestToastVC: BaseListVC {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if row == 11 {
|
}
|
||||||
|
// MARK: 测试特别长的标题和内容
|
||||||
|
sec.addRow(title: "测试特别长的标题和内容") {
|
||||||
Toast.push() { (a) in
|
Toast.push() { (a) in
|
||||||
a.update { (vm) in
|
a.update { (vm) in
|
||||||
vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
|
vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过"
|
||||||
|
@ -175,7 +177,9 @@ class TestToastVC: BaseListVC {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if row == 12 {
|
}
|
||||||
|
// MARK: 测试只有title
|
||||||
|
sec.addRow(title: "测试只有title") {
|
||||||
Toast.push() { (a) in
|
Toast.push() { (a) in
|
||||||
a.update { (vm) in
|
a.update { (vm) in
|
||||||
vm.scene = .warning
|
vm.scene = .warning
|
||||||
|
@ -183,7 +187,9 @@ class TestToastVC: BaseListVC {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if row == 13 {
|
}
|
||||||
|
// MARK: 测试只有message
|
||||||
|
sec.addRow(title: "测试只有message") {
|
||||||
Toast.push() { (a) in
|
Toast.push() { (a) in
|
||||||
a.update { (vm) in
|
a.update { (vm) in
|
||||||
vm.scene = .warning
|
vm.scene = .warning
|
||||||
|
@ -191,8 +197,9 @@ class TestToastVC: BaseListVC {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if row == 14 {
|
}
|
||||||
|
// MARK: 自定义旋转的图片
|
||||||
|
sec.addRow(title: "自定义旋转的图片") {
|
||||||
Toast.push(scene: .privacy, title: "正在授权", message: "请稍等片刻") { (t) in
|
Toast.push(scene: .privacy, title: "正在授权", message: "请稍等片刻") { (t) in
|
||||||
t.identifier = "loading"
|
t.identifier = "loading"
|
||||||
let imgv = UIImageView(image: UIImage(named: "prohud.rainbow.circle"))
|
let imgv = UIImageView(image: UIImage(named: "prohud.rainbow.circle"))
|
||||||
|
@ -203,14 +210,17 @@ class TestToastVC: BaseListVC {
|
||||||
}
|
}
|
||||||
t.startRotate(imgv.layer, speed: 4)
|
t.startRotate(imgv.layer, speed: 4)
|
||||||
}
|
}
|
||||||
simulateSync()
|
self.simulateSync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
func simulateSync() {
|
func simulateSync() {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + 15) {
|
||||||
Toast.find("loading", last: { (t) in
|
Toast.find("loading", last: { (a) in
|
||||||
t.update { (vm) in
|
a.update { (vm) in
|
||||||
vm.scene = .success
|
vm.scene = .success
|
||||||
vm.title = "同步成功"
|
vm.title = "同步成功"
|
||||||
vm.message = "啊哈哈哈哈哈哈哈哈"
|
vm.message = "啊哈哈哈哈哈哈哈哈"
|
||||||
|
|
|
@ -16,28 +16,26 @@ class ViewController: BaseListVC {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
// Do any additional setup after loading the view.
|
// Do any additional setup after loading the view.
|
||||||
title = "\(Bundle.main.infoDictionary?["CFBundleName"] ?? "ProHUD")"
|
title = "\(Bundle.main.infoDictionary?["CFBundleName"] ?? "ProHUD")"
|
||||||
}
|
|
||||||
|
|
||||||
override var titles: [String] {
|
vm.addSection(title: "") { (sec) in
|
||||||
return ["Toast", "Alert", "Guard"]
|
sec.addRow(title: "Toast") {
|
||||||
}
|
|
||||||
|
|
||||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
|
||||||
tableView.deselectRow(at: indexPath, animated: true)
|
|
||||||
if indexPath.row == 0 {
|
|
||||||
let vc = TestToastVC()
|
let vc = TestToastVC()
|
||||||
vc.title = titles[indexPath.row]
|
vc.title = "Toast"
|
||||||
navigationController?.pushViewController(vc, animated: true)
|
self.navigationController?.pushViewController(vc, animated: true)
|
||||||
} else if indexPath.row == 1 {
|
}
|
||||||
|
sec.addRow(title: "Alert") {
|
||||||
let vc = TestAlertVC()
|
let vc = TestAlertVC()
|
||||||
vc.title = titles[indexPath.row]
|
vc.title = "Alert"
|
||||||
navigationController?.pushViewController(vc, animated: true)
|
self.navigationController?.pushViewController(vc, animated: true)
|
||||||
} else {
|
}
|
||||||
|
sec.addRow(title: "Guard") {
|
||||||
let vc = TestGuardVC()
|
let vc = TestGuardVC()
|
||||||
vc.title = titles[indexPath.row]
|
vc.title = "Guard"
|
||||||
navigationController?.pushViewController(vc, animated: true)
|
self.navigationController?.pushViewController(vc, animated: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,10 +63,10 @@ public extension ProHUD {
|
||||||
/// - Parameter title: 标题
|
/// - Parameter title: 标题
|
||||||
/// - Parameter message: 内容
|
/// - Parameter message: 内容
|
||||||
/// - Parameter icon: 图标
|
/// - Parameter icon: 图标
|
||||||
public convenience init(scene: Scene = .default, title: String? = nil, message: String? = nil, actions: ((Alert) -> Void)? = nil) {
|
public convenience init(scene: Scene?, title: String? = nil, message: String? = nil, actions: ((Alert) -> Void)? = nil) {
|
||||||
self.init()
|
self.init()
|
||||||
vm.vc = self
|
vm.vc = self
|
||||||
vm.scene = scene
|
vm.scene = scene ?? .default
|
||||||
vm.title = title
|
vm.title = title
|
||||||
vm.message = message
|
vm.message = message
|
||||||
actions?(self)
|
actions?(self)
|
||||||
|
@ -148,7 +148,7 @@ public extension Alert {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// 最小化事件
|
/// 强制关闭弹窗的事件
|
||||||
/// - Parameter callback: 事件回调
|
/// - Parameter callback: 事件回调
|
||||||
func didForceQuit(_ callback: (() -> Void)?) {
|
func didForceQuit(_ callback: (() -> Void)?) {
|
||||||
vm.forceQuitCallback = callback
|
vm.forceQuitCallback = callback
|
||||||
|
@ -177,14 +177,19 @@ public extension Alert {
|
||||||
/// - identifier: 唯一标识
|
/// - identifier: 唯一标识
|
||||||
/// - toast: 实例对象
|
/// - toast: 实例对象
|
||||||
/// - Returns: 回调
|
/// - Returns: 回调
|
||||||
@discardableResult class func push(_ identifier: String, instance: @escaping (Alert) -> Void) -> Alert {
|
@discardableResult class func push(_ identifier: String, scene: ProHUD.Scene? = nil, instance: ((Alert) -> Void)? = nil) -> Alert {
|
||||||
if let a = find(identifier).last {
|
if let a = find(identifier).last {
|
||||||
instance(a)
|
if let s = scene, s != a.vm.scene {
|
||||||
|
a.update { (vm) in
|
||||||
|
vm.scene = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instance?(a)
|
||||||
return a
|
return a
|
||||||
} else {
|
} else {
|
||||||
return Alert() { (aa) in
|
return Alert(scene: scene) { (aa) in
|
||||||
aa.identifier = identifier
|
aa.identifier = identifier
|
||||||
instance(aa)
|
instance?(aa)
|
||||||
}.push()
|
}.push()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,11 +75,11 @@ public extension ProHUD {
|
||||||
/// - 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, duration: TimeInterval? = nil, actions: ((Toast) -> Void)? = nil) {
|
public convenience init(scene: Scene?, title: String? = nil, message: String? = nil, icon: UIImage? = nil, duration: TimeInterval? = nil, actions: ((Toast) -> Void)? = nil) {
|
||||||
self.init()
|
self.init()
|
||||||
vm.vc = self
|
vm.vc = self
|
||||||
|
|
||||||
vm.scene = scene
|
vm.scene = scene ?? .default
|
||||||
vm.title = title
|
vm.title = title
|
||||||
vm.message = message
|
vm.message = message
|
||||||
vm.icon = icon
|
vm.icon = icon
|
||||||
|
@ -227,14 +227,19 @@ public extension Toast {
|
||||||
/// - identifier: 唯一标识
|
/// - identifier: 唯一标识
|
||||||
/// - toast: 实例对象
|
/// - toast: 实例对象
|
||||||
/// - Returns: 回调
|
/// - Returns: 回调
|
||||||
@discardableResult class func push(_ identifier: String, instance: @escaping (Toast) -> Void) -> Toast {
|
@discardableResult class func push(_ identifier: String, scene: ProHUD.Scene? = nil, instance: ((Toast) -> Void)? = nil) -> Toast {
|
||||||
if let t = find(identifier).last {
|
if let t = find(identifier).last {
|
||||||
instance(t)
|
if let s = scene, s != t.vm.scene {
|
||||||
|
t.update { (vm) in
|
||||||
|
vm.scene = s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
instance?(t)
|
||||||
return t
|
return t
|
||||||
} else {
|
} else {
|
||||||
return Toast() { (tt) in
|
return Toast(scene: scene) { (tt) in
|
||||||
tt.identifier = identifier
|
tt.identifier = identifier
|
||||||
instance(tt)
|
instance?(tt)
|
||||||
}.push()
|
}.push()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue