Files
yingmeng-ios-switf/yinmeng-ios/HttpRequest/LevelStatusBarWindowController.swift
2024-02-21 21:30:13 +08:00

191 lines
5.4 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.

//
// LevelStatusBarWindowController.swift
// yinmeng-ios
//
// Created by MaiMang on 2024/2/2.
//
import Foundation
public protocol LevelStatusBarWindowShowUpable {
///
/// - Parameter superview:
func makeOpenedStatusConstraint(superview: UIView)
///
func refreshBeforeShow()
///
/// - Parameters:
/// - animated:
/// - animation:
/// - completion:
func show(animated: Bool, animation: (() -> Void)?, completion: ((Bool) -> Void)?)
///
/// - Parameters:
/// - animated:
/// - animation:
/// - completion:
func close(animated: Bool, animation: (() -> Void)?, completion: ((Bool) -> Void)?)
}
///
open class LevelStatusBarWindowController: UIViewController {
private var isCalledClose = false
private var canNotBeCanceled = false
private var loadingCount: Int = 0
private lazy var lock = NSLock()
private lazy var overlay: UIView = {
let view = UIView(frame: self.view.bounds)
view.backgroundColor = overlayBackgroundColor
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(overlayTap)))
view.isUserInteractionEnabled = true
return view
}()
public var key: String?
public var showUpView: LevelStatusBarWindowShowUpable?
///
public var canCloseWhenTapOutSize: Bool = true
/// `showUpView`
public var addedShowUpView: Bool = false
public var overlayBackgroundColor: UIColor = UIColor.black.withAlphaComponent(0.2) {
didSet {
self.overlay.backgroundColor = overlayBackgroundColor
}
}
public func addedLoadingCount() {
self.lock.lock()
self.loadingCount += 1
self.lock.unlock()
}
public func subtractLoadingCount() -> Int {
self.lock.lock()
defer { self.lock.unlock() }
self.loadingCount -= 1
return self.loadingCount
}
open override var prefersStatusBarHidden: Bool {
if let controller = YMRequestX.topViewController() {
return controller.prefersStatusBarHidden
}
return true
}
open override var preferredStatusBarStyle: UIStatusBarStyle {
if let controller = YMRequestX.topViewController() {
return controller.preferredStatusBarStyle
}
return .default
}
open override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.clear
self.view.addSubview(self.overlay)
if self.addedShowUpView {
if let alertView = self.showUpView as? UIView {
self.view.bringSubviewToFront(alertView)
}
} else if let alertView = self.showUpView as? UIView {
self.view.addSubview(alertView)
}
self.showUpView?.makeOpenedStatusConstraint(superview: self.view)
}
private var overlayTapCloseBlock: ((LevelStatusBarWindowController) -> Void)?
public func setOverlayTapCloseBlock(block: @escaping (LevelStatusBarWindowController) -> Void) {
self.overlayTapCloseBlock = block
}
public func show(completion: ((Bool) -> Void)? = nil) {
Self.controllers.removeAll { $0 == self }
if let rootViewController = Self.window.rootViewController as? Self, !rootViewController.isCalledClose {
Self.controllers.append(rootViewController)
Self.window.rootViewController = nil
}
self.showUpView?.refreshBeforeShow()
if Self.lastKeyWindow != Self.window {
Self.lastKeyWindow = YMRequestX.keyWindow()
}
Self.window.isHidden = false
Self.window.windowLevel = UIWindow.Level.statusBar
Self.window.rootViewController = self
Self.window.makeKeyAndVisible()
self.overlay.alpha = 0
self.showUpView?.show(animated: true, animation: { [weak self] in
self?.overlay.alpha = 1.0
self?.overlay.backgroundColor = self?.overlayBackgroundColor
}, completion: completion)
}
public func close(animated: Bool = true) {
self.isCalledClose = true
self.showUpView?.close(animated: animated, animation: { [weak self] in
self?.overlay.alpha = 0
}, completion: self.closeCompleted)
}
private func closeCompleted(_: Bool) {
guard Self.window.rootViewController == self else {
return
}
if let lastKeyWindow = Self.lastKeyWindow {
if lastKeyWindow.rootViewController != nil {
lastKeyWindow.makeKeyAndVisible()
}
Self.lastKeyWindow = nil
} else if let window = UIApplication.shared.delegate?.window, window != nil {
window?.makeKeyAndVisible()
}
Self.window.rootViewController = nil
Self.window.isHidden = true
if Self.controllers.count < 10 {
while let rootViewController = Self.controllers.last {
if rootViewController.isCalledClose {
Self.controllers.removeLast()
continue
}
rootViewController.show()
break
}
} else {
Self.controllers.removeAll()
}
}
@objc private func overlayTap() {
if canCloseWhenTapOutSize {
close()
overlayTapCloseBlock?(self)
}
}
}
extension LevelStatusBarWindowController {
private static let window = UIWindow(frame: UIScreen.main.bounds)
private static var lastKeyWindow: UIWindow?
private static var controllers = [LevelStatusBarWindowController]()
public static func cancelAllBackgroundControllersShow() {
Self.controllers = Self.controllers.filter({ $0.canNotBeCanceled })
}
public static func forcecancelAllControllers() {
if let controller = Self.window.rootViewController as? LevelStatusBarWindowController, !controller.canNotBeCanceled {
Self.window.rootViewController = nil
Self.window.isHidden = true
}
cancelAllBackgroundControllersShow()
}
}