ProHUD/Source/Alert/AlertConfig.swift

341 lines
12 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// cfg.alert.swift
// ProHUD
//
// Created by xaoxuu on 2019/7/29.
// Copyright © 2019 Titan Studio. All rights reserved.
//
import UIKit
import SnapKit
public extension UIWindow.Level {
static let alertForProHUD = UIWindow.Level.alert - 1
}
public extension ProHUD.Configuration {
struct Alert {
// MARK:
/// iPad
public var maxWidth = CGFloat(400)
///
public var cornerRadius = CGFloat(16)
///
public var margin = CGFloat(8)
///
public var padding = CGFloat(16)
///
public var tintColor: UIColor?
// MARK:
///
public var iconSize = CGSize(width: 48, height: 48)
// MARK:
///
public var titleFont = UIFont.boldSystemFont(ofSize: 22)
///
public var titleMaxLines = Int(5)
///
public var boldTextFont = UIFont.boldSystemFont(ofSize: 18)
///
public var bodyFont = UIFont.systemFont(ofSize: 17)
///
public var bodyMaxLines = Int(20)
// MARK:
///
public var buttonFont = UIFont.boldSystemFont(ofSize: 18)
// MARK:
///
public func reloadData(_ callback: @escaping (ProHUD.Alert) -> Void) {
privReloadData = callback
}
/// 退
public var forceQuitTimer = TimeInterval(30)
/// 退
public var forceQuitTitle = "隐藏窗口"
/// 退
/// - Parameter callback:
public func loadHideButton(_ callback: @escaping (ProHUD.Alert) -> Void) {
privLoadHideButton = callback
}
}
}
// MARK: -
extension ProHUD.Configuration.Alert {
var reloadData: (ProHUD.Alert) -> Void {
return privReloadData
}
}
// MARK: -
fileprivate var privLayoutContentView: (ProHUD.Alert) -> Void = {
return { (vc) in
if vc.contentView.superview == nil {
vc.view.addSubview(vc.contentView)
vc.contentView.layer.masksToBounds = true
vc.contentView.layer.cornerRadius = cfg.alert.cornerRadius
let maxWidth = CGFloat.maximum(CGFloat.minimum(UIScreen.main.bounds.width * 0.68, cfg.alert.maxWidth), 268)
vc.contentView.snp.makeConstraints { (mk) in
mk.center.equalToSuperview()
mk.width.lessThanOrEqualTo(maxWidth)
}
}
if vc.contentStack.superview == nil {
vc.contentView.contentView.addSubview(vc.contentStack)
vc.contentStack.spacing = cfg.alert.margin + cfg.alert.padding
vc.contentStack.snp.makeConstraints { (mk) in
mk.centerX.equalToSuperview()
mk.top.equalToSuperview().offset(cfg.alert.padding)
mk.bottom.equalToSuperview().offset(-cfg.alert.padding)
mk.leading.equalToSuperview().offset(cfg.alert.padding)
mk.trailing.equalToSuperview().offset(-cfg.alert.padding)
}
}
}
}()
fileprivate var privUpdateImage: (ProHUD.Alert) -> Void = {
return { (vc) in
let config = cfg.alert
let img = vc.vm.icon ?? vc.vm.scene.image
vc.imageView.image = img
vc.contentStack.addArrangedSubview(vc.imageView)
vc.imageView.contentMode = .scaleAspectFit
vc.imageView.snp.makeConstraints { (mk) in
mk.top.greaterThanOrEqualTo(vc.contentView).offset(config.padding*2.25)
mk.bottom.lessThanOrEqualTo(vc.contentView).offset(-config.padding*2.25)
mk.leading.greaterThanOrEqualTo(vc.contentView).offset(config.padding*4)
mk.trailing.lessThanOrEqualTo(vc.contentView).offset(-config.padding*4)
mk.width.equalTo(config.iconSize.width)
mk.height.equalTo(config.iconSize.height)
}
//
vc.stopRotate(vc.animateLayer)
vc.animateLayer = nil
vc.animation = nil
//
vc.progressView?.removeFromSuperview()
}
}()
fileprivate var privUpdateTextStack: (ProHUD.Alert) -> Void = {
return { (vc) in
let config = cfg.alert
if vc.vm.title == nil {
vc.vm.title = vc.vm.scene.title
}
if vc.vm.message == nil {
vc.vm.message = vc.vm.scene.message
}
if vc.vm.title?.count ?? 0 > 0 || vc.vm.message?.count ?? 0 > 0 {
vc.contentStack.addArrangedSubview(vc.textStack)
vc.textStack.snp.makeConstraints { (mk) in
mk.top.greaterThanOrEqualTo(vc.contentView).offset(config.padding*1.75)
mk.bottom.lessThanOrEqualTo(vc.contentView).offset(-config.padding*1.75)
if UIScreen.main.bounds.width < 414 {
mk.leading.greaterThanOrEqualTo(vc.contentView).offset(config.padding*1.5)
mk.trailing.lessThanOrEqualTo(vc.contentView).offset(-config.padding*1.5)
} else {
mk.leading.greaterThanOrEqualTo(vc.contentView).offset(config.padding*2)
mk.trailing.lessThanOrEqualTo(vc.contentView).offset(-config.padding*2)
}
}
if vc.vm.title?.count ?? 0 > 0 {
if let lb = vc.titleLabel {
lb.text = vc.vm.title
} else {
let title = UILabel()
title.textAlignment = .center
title.numberOfLines = config.titleMaxLines
title.textColor = cfg.primaryLabelColor
title.text = vc.vm.title
vc.textStack.addArrangedSubview(title)
vc.titleLabel = title
}
if vc.vm.message?.count ?? 0 > 0 {
// message
vc.titleLabel?.font = config.titleFont
} else {
// message
vc.titleLabel?.font = config.boldTextFont
}
} else {
vc.titleLabel?.removeFromSuperview()
}
if vc.vm.message?.count ?? 0 > 0 {
if let lb = vc.bodyLabel {
lb.text = vc.vm.message
} else {
let body = UILabel()
body.textAlignment = .center
body.font = config.bodyFont
body.numberOfLines = config.bodyMaxLines
body.textColor = cfg.secondaryLabelColor
body.text = vc.vm.message
vc.textStack.addArrangedSubview(body)
vc.bodyLabel = body
}
if vc.vm.title?.count ?? 0 > 0 {
// title
vc.bodyLabel?.font = config.bodyFont
} else {
// title
vc.bodyLabel?.font = config.boldTextFont
}
} else {
vc.bodyLabel?.removeFromSuperview()
}
} else {
vc.textStack.removeFromSuperview()
}
vc.textStack.layoutIfNeeded()
}
}()
fileprivate var privUpdateActionStack: (ProHUD.Alert) -> Void = {
return { (vc) in
let config = cfg.alert
if vc.actionStack.arrangedSubviews.count > 0 {
//
vc.contentStack.addArrangedSubview(vc.actionStack)
// iPad
if isPortrait == false && vc.actionStack.arrangedSubviews.count < 4 {
vc.actionStack.axis = .horizontal
vc.actionStack.alignment = .fill
vc.actionStack.distribution = .fillEqually
}
vc.actionStack.snp.makeConstraints { (mk) in
mk.width.greaterThanOrEqualTo(200)
mk.leading.trailing.equalToSuperview()
}
} else {
//
for v in vc.actionStack.arrangedSubviews {
v.removeFromSuperview()
}
vc.actionStack.removeFromSuperview()
}
vc.actionStack.layoutIfNeeded()
}
}()
fileprivate var privLoadHideButton: (ProHUD.Alert) -> Void = {
return { (vc) in
debug(vc, "showNavButtons")
let config = cfg.alert
let btn = ProHUD.Alert.Button.createHideButton()
btn.setTitle(cfg.alert.forceQuitTitle, for: .normal)
let bg = createBlurView()
bg.layer.masksToBounds = true
bg.layer.cornerRadius = config.cornerRadius
if let last = vc.view.subviews.last {
vc.view.insertSubview(bg, belowSubview: last)
} else {
vc.view.addSubview(bg)
}
bg.snp.makeConstraints { (mk) in
mk.leading.trailing.equalTo(vc.contentView)
mk.top.equalTo(vc.contentView.snp.bottom).offset(config.margin)
}
bg.contentView.addSubview(btn)
btn.snp.makeConstraints { (mk) in
mk.edges.equalToSuperview()
}
bg.alpha = 0
bg.layoutIfNeeded()
bg.transform = .init(translationX: 0, y: -2*(config.margin+bg.frame.size.height))
UIView.animateForAlert {
bg.alpha = 1
bg.transform = .identity
}
vc.addTouchUpAction(for: btn) { [weak vc] in
debug("点击了【\(config.forceQuitTitle)")
vc?.vm.forceQuitCallback?()
vc?.pop()
}
}
}()
///
fileprivate var privReloadData: (ProHUD.Alert) -> Void = {
return { (vc) in
debug(vc, "reloadData")
let config = cfg.alert
let isFirstLayout: Bool
if vc.contentView.superview == nil {
isFirstLayout = true
//
privLayoutContentView(vc)
} else {
isFirstLayout = false
}
//
privUpdateImage(vc)
//
privUpdateTextStack(vc)
//
privUpdateActionStack(vc)
vc.contentStack.layoutIfNeeded()
vc.contentView.layoutIfNeeded()
//
if isFirstLayout {
vc.view.layoutIfNeeded()
vc.imageView.transform = .init(scaleX: 0.75, y: 0.75)
UIView.animateForAlert {
vc.view.layoutIfNeeded()
vc.imageView.transform = .identity
}
} else {
UIView.animateForAlert {
vc.view.layoutIfNeeded()
}
}
//
vc.vm.updateDuration()
// id .rotate
if vc.vm.scene.identifier.contains(".rotate") {
vc.startRotate()
}
//
vc.vm.hideTimerBlock?.cancel()
if vc.buttonEvents.count == 0 {
vc.vm.hideTimerBlock = DispatchWorkItem(block: { [weak vc] in
if let vc = vc {
if vc.buttonEvents.count == 0 {
privLoadHideButton(vc)
}
}
})
DispatchQueue.main.asyncAfter(deadline: .now() + config.forceQuitTimer, execute: vc.vm.hideTimerBlock!)
} else {
vc.vm.hideTimerBlock = nil
}
}
}()