ProHUD/Source/Alert/AlertConfig.swift

332 lines
12 KiB
Swift
Raw 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
import Inspire
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 loadForceQuitButton(_ callback: @escaping (ProHUD.Alert) -> Void) {
privLoadForceQuitButton = callback
}
}
}
// MARK: -
internal 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
if let imgv = vc.imageView {
imgv.image = img
} else {
let icon = UIImageView(image: img)
vc.contentStack.addArrangedSubview(icon)
icon.contentMode = .scaleAspectFit
icon.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.imageView = icon
}
vc.imageView?.layer.removeAllAnimations()
}
}()
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 privLoadForceQuitButton: (ProHUD.Alert) -> Void = {
return { (vc) in
debug(vc, "showNavButtons")
let config = cfg.alert
let btn = ProHUD.Alert.Button.forceQuitButton()
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()
// 退
vc.vm.forceQuitTimerBlock?.cancel()
if vc.buttonEvents.count == 0 {
vc.vm.forceQuitTimerBlock = DispatchWorkItem(block: { [weak vc] in
if let vc = vc {
if vc.buttonEvents.count == 0 {
privLoadForceQuitButton(vc)
}
}
})
DispatchQueue.main.asyncAfter(deadline: .now() + config.forceQuitTimer, execute: vc.vm.forceQuitTimerBlock!)
} else {
vc.vm.forceQuitTimerBlock = nil
}
}
}()