diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/ProHUD.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/ProHUD.xcscheme index 6214c27..505874b 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/ProHUD.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/ProHUD.xcscheme @@ -20,6 +20,34 @@ ReferencedContainer = "container:"> + + + + + + + + /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; - FE957B34A041E54F84E4F88C /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - CDA4E03420D3935B00CD2A0C /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - CD8BFF1823014850001E08DD /* TestToastVC.swift in Sources */, - CDA4E03E20D3935B00CD2A0C /* ViewController.swift in Sources */, - CD8BFF2023014CB5001E08DD /* EmptyVC.swift in Sources */, - CD8BFF1A2301485E001E08DD /* TestAlertVC.swift in Sources */, - CD4B40AA23017C09005111B9 /* RootVC.swift in Sources */, - CDA4E03C20D3935B00CD2A0C /* AppDelegate.swift in Sources */, - CD8BFF1C23014867001E08DD /* TestGuardVC.swift in Sources */, - CD8BFF1E230148DD001E08DD /* BaseListVC.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXVariantGroup section */ - CDA4E03F20D3935B00CD2A0C /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - CDA4E04020D3935B00CD2A0C /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - CDA4E04420D3935C00CD2A0C /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - CDA4E04520D3935C00CD2A0C /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - CDA4E04820D3935C00CD2A0C /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - CDA4E04920D3935C00CD2A0C /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_IDENTITY = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - CDA4E04B20D3935C00CD2A0C /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = CA1298266BE89D7950DE99F2 /* Pods-Example.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 34W5TB5KD2; - INFOPLIST_FILE = Example/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 2.0; - PRODUCT_BUNDLE_IDENTIFIER = com.xaoxuu.ProHUDExample; - PRODUCT_NAME = "ProHUD 老项目"; - PROVISIONING_PROFILE = "b32d51a3-c20b-408f-aebf-11d2ea3811cd"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OBJC_BRIDGING_HEADER = "Example/Example-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - CDA4E04C20D3935C00CD2A0C /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = BA1A6035F1B9A658B3BB225C /* Pods-Example.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 34W5TB5KD2; - INFOPLIST_FILE = Example/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 2.0; - PRODUCT_BUNDLE_IDENTIFIER = com.xaoxuu.ProHUDExample; - PRODUCT_NAME = "ProHUD 老项目"; - PROVISIONING_PROFILE = "b32d51a3-c20b-408f-aebf-11d2ea3811cd"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OBJC_BRIDGING_HEADER = "Example/Example-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - CDA4E03320D3935B00CD2A0C /* Build configuration list for PBXProject "Example" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CDA4E04820D3935C00CD2A0C /* Debug */, - CDA4E04920D3935C00CD2A0C /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - CDA4E04A20D3935C00CD2A0C /* Build configuration list for PBXNativeTarget "Example" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CDA4E04B20D3935C00CD2A0C /* Debug */, - CDA4E04C20D3935C00CD2A0C /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = CDA4E03020D3935B00CD2A0C /* Project object */; -} diff --git a/Example-Old/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Example-Old/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 6d2a51b..0000000 --- a/Example-Old/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Example-Old/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme b/Example-Old/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme deleted file mode 100644 index 0f716cb..0000000 --- a/Example-Old/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example-Old/Example.xcworkspace/contents.xcworkspacedata b/Example-Old/Example.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index a37cf19..0000000 --- a/Example-Old/Example.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/Example-Old/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Example-Old/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/Example-Old/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Example-Old/Example/AppDelegate.swift b/Example-Old/Example/AppDelegate.swift deleted file mode 100644 index 4d16d0b..0000000 --- a/Example-Old/Example/AppDelegate.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// AppDelegate.swift -// Example -// -// Created by xaoxuu on 2018/6/15. -// Copyright © 2018 Titan Studio. All rights reserved. -// - -import UIKit -import ProHUD - -@UIApplicationMain -class AppDelegate: UIResponder, UIApplicationDelegate { - - var window: UIWindow? - - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - // Override point for customization after application launch. - - let vc = RootVC() - window = UIWindow.init(frame: UIScreen.main.bounds) - window?.rootViewController = vc - window?.makeKeyAndVisible() - ProHUD.config { (cfg) in - // 可自动获取根控制器,如果获取失败请主动设置此值 - // cfg.rootViewController = vc - cfg.alert { (a) in -// a.titleFont = .bold(22) -// a.bodyFont = .regular(17) -// a.boldTextFont = .bold(18) -// a.buttonFont = .bold(18) - a.forceQuitTimer = 5 // 多少秒后可以强制关闭弹窗(为了方便测试,一般不要设置这么小) - } -// cfg.toast { (t) in -// t.titleFont = .bold(18) -// t.bodyFont = .regular(16) -// t.iconSize = .init(width: 42, height: 42) -// } -// cfg.guard { (g) in -// g.titleFont = .bold(22) -// g.subTitleFont = .bold(20) -// g.bodyFont = .regular(17) -// g.buttonFont = .bold(18) -// } - } - - return true - } - - func applicationWillResignActive(_ application: UIApplication) { - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. - } - - func applicationDidEnterBackground(_ application: UIApplication) { - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. - NotificationCenter.default.post(name: NSNotification.Name.init("applicationDidEnterBackground"), object: nil) - - } - - func applicationWillEnterForeground(_ application: UIApplication) { - // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. - } - - func applicationDidBecomeActive(_ application: UIApplication) { - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. - } - - func applicationWillTerminate(_ application: UIApplication) { - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. - } - - -} diff --git a/Example-Old/Example/Base.lproj/LaunchScreen.storyboard b/Example-Old/Example/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f83f6fd..0000000 --- a/Example-Old/Example/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example-Old/Example/Base.lproj/Main.storyboard b/Example-Old/Example/Base.lproj/Main.storyboard deleted file mode 100644 index 777722c..0000000 --- a/Example-Old/Example/Base.lproj/Main.storyboard +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example-Old/Example/BaseListVC.swift b/Example-Old/Example/BaseListVC.swift deleted file mode 100644 index 604aa2c..0000000 --- a/Example-Old/Example/BaseListVC.swift +++ /dev/null @@ -1,106 +0,0 @@ -// -// BaseListVC.swift -// Example -// -// Created by xaoxuu on 2019/8/12. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -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 { - - - var ts = [[String]]() - var cs = [[Callback]]() - - var vm = Table() - var secs = [Section]() - - lazy var tableView: UITableView = { - let tv: UITableView - if #available(iOS 13.0, *) { - tv = UITableView(frame: .zero, style: .insetGrouped) - } else { - // Fallback on earlier versions - tv = UITableView(frame: .zero, style: .grouped) - } - return tv - }() - - override func viewDidLoad() { - super.viewDidLoad() - - - view.addSubview(tableView) - tableView.dataSource = self - tableView.delegate = self - tableView.snp.makeConstraints { (mk) in - mk.edges.equalToSuperview() - } - } - - -} - -extension BaseListVC: UITableViewDataSource, UITableViewDelegate { - func numberOfSections(in tableView: UITableView) -> Int { - return vm.sections.count - } - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return vm.sections[section].rows.count - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell: UITableViewCell - 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.accessoryType = .disclosureIndicator - } - cell.textLabel?.text = vm.sections[indexPath.section].rows[indexPath.row].title - cell.detailTextLabel?.text = vm.sections[indexPath.section].rows[indexPath.row].subtitle - 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) { - tableView.deselectRow(at: indexPath, animated: true) - vm.sections[indexPath.section].rows[indexPath.row].callback() - } - -} - diff --git a/Example-Old/Example/EmptyVC.swift b/Example-Old/Example/EmptyVC.swift deleted file mode 100644 index e1afacb..0000000 --- a/Example-Old/Example/EmptyVC.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// EmptyVC.swift -// Example -// -// Created by xaoxuu on 2019/8/12. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit -import SnapKit -import Inspire - -class EmptyVC: UIViewController { - - - - override func viewDidLoad() { - super.viewDidLoad() - view.backgroundColor = UIColor(white: 0.95, alpha: 1) - // Do any additional setup after loading the view. - - let lb = UILabel() - lb.numberOfLines = 0 - lb.text = title - lb.font = .regular(40) - view.addSubview(lb) - lb.snp.makeConstraints { (mk) in - mk.center.equalToSuperview() - mk.leading.greaterThanOrEqualToSuperview().offset(16) - mk.trailing.lessThanOrEqualToSuperview().offset(-16) - } - - let btn = UIButton(type: .system) - btn.titleLabel?.font = .bold(20) - btn.setTitle("Dismiss", for: .normal) - btn.addTarget(self, action: #selector(didTappedDismiss(_:)), for: .touchUpInside) - view.addSubview(btn) - btn.snp.makeConstraints { (mk) in - mk.top.equalToSuperview().offset(Inspire.current.layout.safeAreaInsets(for: self).top) - mk.trailing.equalToSuperview().offset(-16) - mk.height.equalTo(44) - } - } - - @objc func didTappedDismiss(_ sender: UIButton) { - dismiss(animated: true, completion: nil) - } - -} - -extension UIViewController { - func presentEmptyVC(title: String?) { - let vc = EmptyVC() - vc.title = title - present(vc, animated: true, completion: nil) - } -} diff --git a/Example-Old/Example/Example-Bridging-Header.h b/Example-Old/Example/Example-Bridging-Header.h deleted file mode 100644 index f84fb54..0000000 --- a/Example-Old/Example/Example-Bridging-Header.h +++ /dev/null @@ -1,5 +0,0 @@ -// -// Use this file to import your target's public headers that you would like to expose to Swift. -// - - diff --git a/Example-Old/Example/Info.plist b/Example-Old/Example/Info.plist deleted file mode 100644 index 5fdbca5..0000000 --- a/Example-Old/Example/Info.plist +++ /dev/null @@ -1,54 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - $(PRODUCT_NAME) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(MARKETING_VERSION) - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UIRequiredDeviceCapabilities - - armv7 - - UIRequiresFullScreen - - UIStatusBarHidden - - UIStatusBarStyle - UIStatusBarStyleDefault - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - UIInterfaceOrientationPortraitUpsideDown - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Example-Old/Example/RootVC.swift b/Example-Old/Example/RootVC.swift deleted file mode 100644 index 580cae3..0000000 --- a/Example-Old/Example/RootVC.swift +++ /dev/null @@ -1,88 +0,0 @@ -// -// RootVC.swift -// Example -// -// Created by xaoxuu on 2019/8/12. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit -import ProHUD - -class RootVC: UIViewController { - - override func viewDidLoad() { - super.viewDidLoad() - - // Do any additional setup after loading the view. - let vc = ViewController() - let nav = UINavigationController(rootViewController: vc) - addChild(nav) - view.addSubview(nav.view) - nav.view.frame = view.bounds - if #available(iOS 11.0, *) { - nav.navigationBar.prefersLargeTitles = true - } else { - // Fallback on earlier versions - } - } - - - /* - // MARK: - Navigation - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - // Get the new view controller using segue.destination. - // Pass the selected object to the new view controller. - } - */ - -} - -extension ProHUD.Scene { - - static var delete: ProHUD.Scene { - var scene = ProHUD.Scene(identifier: "prohud.delete") - scene.image = UIImage(named: "prohud.trash") - scene.title = "确认删除" - scene.message = "此操作不可撤销" - return scene - } - - static var buy: ProHUD.Scene { - var scene = ProHUD.Scene(identifier: "buy") - scene.image = UIImage(named: "alert.buy") - scene.title = "确认付款" - scene.message = "一旦购买拒不退款" - return scene - } - - /// 重写的loading场景 - static var loading: ProHUD.Scene { - var scene = ProHUD.Scene.init(identifier: "prohud.loading.rotate") - scene.image = UIImage(named: "prohud.rainbow.circle") - scene.title = "坐和放宽" - scene.message = "正在处理一些事情" - scene.alertDuration = 0 - scene.toastDuration = 0 - return scene - } - - static var sync: ProHUD.Scene { - var scene = ProHUD.Scene.init(identifier: "sync.rotate") - scene.image = UIImage(named: "prohud.rainbow.circle") - scene.title = "正在同步" - scene.alertDuration = 0 - scene.toastDuration = 0 - return scene - } - static var sync2: ProHUD.Scene { - var scene = ProHUD.Scene.init(identifier: "sync.rotate") - scene.image = UIImage(named: "prohud.rainbow.circle") - scene.alertDuration = 0 - scene.toastDuration = 0 - return scene - } - -} diff --git a/Example-Old/Example/TestAlertVC.swift b/Example-Old/Example/TestAlertVC.swift deleted file mode 100644 index f271d08..0000000 --- a/Example-Old/Example/TestAlertVC.swift +++ /dev/null @@ -1,332 +0,0 @@ -// -// TestAlertVC.swift -// Example -// -// Created by xaoxuu on 2019/8/12. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit -import ProHUD - -// 模拟2秒后同步成功 -func loadingSuccessAfter2Seconds() { - DispatchQueue.main.asyncAfter(deadline: .now()+2) { - Alert.find("loading") { (a) in - a.update { (vm) in - vm.scene = .success - vm.title = "同步成功" - vm.message = nil - } - } - } -} - -func updateProgress(callback: @escaping (CGFloat) -> Void) { - let s = DispatchSemaphore(value: 1) - DispatchQueue.global().async { - for i in 0 ... 100 { - s.wait() - DispatchQueue.main.async { - callback(CGFloat(i)/100) - DispatchQueue.main.asyncAfter(deadline: .now()+0.03) { - s.signal() - } - } - } - } -} - -class TestAlertVC: BaseListVC { - - override func viewDidLoad() { - super.viewDidLoad() - - 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 = "这些是自带的场景,可以重写已有场景,或者扩展新的场景。" - } - - vm.addSection(title: "常用示例") { (sec) in - // MARK: 同步成功(写法1) - sec.addRow(title: "正在同步(写法1)", subtitle: "创建的时候就布局好了。") { - Alert.push("loading", scene: .sync2) { (vc) in - vc.update { (vm) in - vm.title = "正在同步" - } - } - loadingSuccessAfter2Seconds() - } - // MARK: 同步成功(写法2) - sec.addRow(title: "正在同步(写法2)", subtitle: "创建的时候没有布局完,发出去之后再更新布局。") { - Alert.push("loading", scene: .sync2) - loadingSuccessAfter2Seconds() - // 先发出去再更新(添加文字) - Alert.find("loading") { (vc) in - vc.update { (vm) in - vm.title = "正在同步" - } - } - } - // MARK: 正在同步(更新进度) - sec.addRow(title: "正在同步(有进度显示)") { - Alert.push("progress", scene: .sync) { (a) in - a.update(progress: 0) - updateProgress { (pct) in - a.update(progress: pct) - if pct >= 1 { - DispatchQueue.main.asyncAfter(deadline: .now()+0.5) { - a.update { (vm) in - vm.scene = .success - vm.title = "同步成功" - vm.message = nil - } - } - } - } - } - } - // MARK: 同步失败和重试 - sec.addRow(title: "同步失败和重试(布局变化)", subtitle: "添加、删除按钮使得窗口大小发生了变化。") { - Alert.push("loading", scene: .loading) - func loading() { - Alert.find("loading") { (a) in - a.update { (vm) in - vm.scene = .loading - vm.title = "正在同步" - vm.message = "请稍等片刻" - vm.remove(action: 0, 1) - } - a.startRotate() - DispatchQueue.main.asyncAfter(deadline: .now()+2) { - a.update { (vm) in - vm.scene = .error - vm.title = "同步失败" - vm.message = "请检查网络是否通畅" - vm.add(action: .default, title: "重试") { - loading() - } - vm.add(action: .cancel, title: "取消", handler: nil) - } - } - } - } - loading() - } - // MARK: 自定义要旋转的图片 - sec.addRow(title: "自定义要旋转的图片", subtitle: "添加了自定义视图,在更新的时候记得要视情况移除。") { - Alert.push(scene: .privacy, title: "正在授权") { (vc) in - vc.identifier = "loading" - let imgv = UIImageView(image: UIImage(named: "prohud.rainbow.circle")) - vc.imageView.addSubview(imgv) - imgv.tag = 1 - imgv.snp.makeConstraints { (mk) in - mk.center.equalToSuperview() - mk.width.height.equalTo(18) - } - vc.startRotate(imgv.layer, speed: 4) - vc.vm.duration = 0 - } - DispatchQueue.main.asyncAfter(deadline: .now() + 4) { - Alert.find("loading") { (vc) in - vc.imageView.viewWithTag(1)?.removeFromSuperview() - vc.update { (vm) in - vm.scene = .success - vm.title = "授权成功" - vm.duration = 1 - } - } - } - } - - sec.footer = "写法1和写法2动画效果略微不同" - } - - vm.addSection(title: "为了解决代码逻辑疏漏导致程序卡死、弹窗重叠等问题") { (sec) in - // MARK: 极端场景:正在同步(超时未处理) - sec.addRow(title: "极端场景:正在同步(超时未处理)", subtitle: "超时未处理的意外情况,弹窗可以手动关闭。(在config中配置所需时间)") { - Alert.push(scene: .loading, title: "坐和放宽", message: "我们正在帮你搞定一切") { (a) in - a.identifier = "loading" - a.startRotate() - a.didForceQuit { - Toast.push(scene: .default, title: "点击了强制关闭", message: "您可以处理超时事件") - } - } - } - - - // MARK: 极端场景:短时间内调用了多次同一个弹窗 - sec.addRow(title: "极端场景:短时间内调用了多次同一个弹窗", subtitle: "多次调用,页面弹窗应该是毫无变化的。(本例中,4秒内调用了6次)") { - func loading(_ index: Int = 1) { - if Alert.find("loading").count == 0 { - Alert.push("loading", scene: .loading) { (a) in - a.update { (vm) in - vm.title = "正在加载" - } - a.startRotate() - } - } - } - loading(1) - DispatchQueue.main.asyncAfter(deadline: .now()+1) { - loading(2) - } - DispatchQueue.main.asyncAfter(deadline: .now()+2) { - loading(3) - } - DispatchQueue.main.asyncAfter(deadline: .now()+3) { - loading(4) - } - DispatchQueue.main.asyncAfter(deadline: .now()+3.5) { - loading(5) - } - DispatchQueue.main.asyncAfter(deadline: .now()+4) { - loading(6) - } - DispatchQueue.main.asyncAfter(deadline: .now()+4.5) { - Alert.push("loading", scene: .success) { (a) in - a.update { (vm) in - vm.scene = .success - vm.title = "测试结束" - } - } - } - } - // MARK: 极端场景:多个不同的弹窗重叠 - sec.addRow(title: "极端场景:多个不同的弹窗重叠", subtitle: "多个弹窗不得不重叠的时候,ProHUD的景深处理可以使其看起来舒服一些。") { - func a() { - Alert.push("a", scene: .default) { (a) in - a.update { (vm) in - vm.title = "Windows 10" - vm.message = "Windows 10不是為所有人設計,而是為每個人設計" - vm.icon = UIImage(named: "prohud.windmill") - vm.duration = 0 - } - DispatchQueue.main.asyncAfter(deadline: .now()+1) { - b() - } - } - } - func b() { - Alert.push("b", scene: .warning) { (a) in - a.update { (vm) in - vm.title = "Windows 10" - vm.message = "不要说我们没有警告过你" - vm.duration = 0 - } - } - DispatchQueue.main.asyncAfter(deadline: .now()+1) { - c() - } - } - func c() { - Alert.push("c", scene: .message) { (a) in - a.update { (vm) in - vm.title = "Windows 10" - vm.message = "我们都有不顺利的时候" - vm.duration = 0 - } - } - DispatchQueue.main.asyncAfter(deadline: .now()+1) { - d() - } - } - func d() { - Alert.push("d", scene: .loading) { (a) in - a.update { (vm) in - vm.title = "Windows 10" - vm.message = "正在处理一些事情" - vm.duration = 0 - } - } - DispatchQueue.main.asyncAfter(deadline: .now()+3) { - e() - } - } - func e() { - Alert.push("e", scene: .failure) { (a) in - a.update { (vm) in - vm.title = "更新失败" - vm.message = "*回到以前的版本" - vm.add(action: .default, title: "好的") { - Alert.pop("e") - DispatchQueue.main.asyncAfter(deadline: .now()+0.3) { - Alert.pop("d") - } - DispatchQueue.main.asyncAfter(deadline: .now()+0.6) { - Alert.pop("c") - } - DispatchQueue.main.asyncAfter(deadline: .now()+0.9) { - Alert.pop("b") - } - DispatchQueue.main.asyncAfter(deadline: .now()+1.2) { - Alert.pop("a") - } - } - } - } - } - a() - - } - - - - } - - vm.addSection(title: "") { (sec) in - - // MARK: 测试较长的标题和内容 - sec.addRow(title: "测试较长的标题和内容") { - Alert.push() { (a) in - a.update { (vm) in - vm.scene = .confirm - vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过" - vm.message = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过" - vm.add(action: .default, title: "我知道了", handler: nil) - } - } - } - // MARK: 测试特别长的标题和内容 - sec.addRow(title: "测试特别长的标题和内容", subtitle: "这种情况编码阶段就可以避免,所以没有做特别处理,请控制内容长度不要过长。") { - Alert.push() { (a) in - a.update { (vm) in - vm.scene = .warning - vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过" - vm.message = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来 的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过" - vm.add(action: .default, title: "我知道了", handler: nil) - } - } - } - // MARK: 只有标题 - sec.addRow(title: "只有标题") { - Alert.push(scene: .message, title: "这是标题") - } - // MARK: 只有消息 - sec.addRow(title: "只有消息") { - Alert.push(scene: .message, message: "这是消息") - } - // MARK: 只有消息 - sec.addRow(title: "既没有标题也没有消息") { - Alert.push() - } - } - - } - - -} diff --git a/Example-Old/Example/TestGuardVC.swift b/Example-Old/Example/TestGuardVC.swift deleted file mode 100644 index dc0cc36..0000000 --- a/Example-Old/Example/TestGuardVC.swift +++ /dev/null @@ -1,188 +0,0 @@ -// -// TestGuardVC.swift -// Example -// -// Created by xaoxuu on 2019/8/12. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit -import ProHUD -import Inspire -import WebKit - -class TestGuardVC: BaseListVC { - - override func viewDidLoad() { - super.viewDidLoad() - - vm.addSection(title: "简单使用") { (sec) in - // MARK: 删除菜单 - sec.addRow(title: "示例:删除菜单") { - Guard.push("del") { (vc) in - vc.update { (vm) in - vm.add(action: .destructive, title: "删除") { [weak vc] in - Alert.push(scene: .delete) { (vc) in - vc.update { (vm) in - vm.add(action: .destructive, title: "删除") { [weak vc] in - vc?.pop() - } - vm.add(action: .cancel, title: "取消", handler: nil) - } - } - vc?.pop() - } - vm.add(action: .cancel, title: "取消", handler: nil) - } - } - DispatchQueue.main.asyncAfter(deadline: .now()+1) { - Guard.find("del") { vc in - vc.pop() - } - } - } - - // MARK: 升级至专业版 - sec.addRow(title: "示例:升级至专业版") { - // 可以通过id来避免重复 - Guard.push("pro") { (vc) in - vc.identifier = "pro" - vc.update { (vm) in - vm.add(title: "升级至专业版") - vm.add(subTitle: "解锁功能") - vm.add(message: "功能1功能2...") - vm.add(subTitle: "价格") - vm.add(message: "只需一次性付费$2999即可永久享用。") - vm.add(action: .destructive, title: "购买") { [weak vc] in - Alert.push(scene: .buy) { (vc) in - vc.identifier = "confirm" - vc.update { (vm) in - vm.add(action: .destructive, title: "购买") { [weak vc] in - vc?.update({ (vm) in - vm.scene = .loading - vm.title = "正在付款" - vm.message = "请稍等片刻" - vm.remove(action: 0, 1) - }) - vc?.startRotate() - DispatchQueue.main.asyncAfter(deadline: .now()+1) { - vc?.update({ (vm) in - vm.scene = .success - vm.title = "购买成功" - vm.message = "感谢您的支持" - vm.add(action: .default, title: "我知道了") { - vc?.pop() - } - }) - } - } - vm.add(action: .cancel, title: "取消", handler: nil) - } - } - vc?.pop() - } - vm.add(action: .cancel, title: "取消", handler: nil) - } - } - } - - } - - vm.addSection(title: "添加自定义视图") { (sec) in - // MARK: 选项切换 - sec.addRow(title: "示例:修改背景蒙版", subtitle: "很方便地添加自定义控件") { - Guard.push() { (vc) in - if #available(iOS 13.0, *) { - let imgv = UIImageView(image: UIImage(systemName: "photo.fill.on.rectangle.fill")) - vc.textStack.addArrangedSubview(imgv) - imgv.contentMode = .scaleAspectFit - imgv.snp.makeConstraints { (mk) in - mk.height.equalTo(80) - } - } else { - // Fallback on earlier versions - } - - // 添加标题 - vc.vm.add(title: "背景蒙版") - // 添加标题 - vc.vm.add(subTitle: "选择一种模糊效果") - // 添加控件 - let seg = UISegmentedControl(items: ["extraLight", "light", "dark", "none"]) - seg.selectedSegmentIndex = 1 - vc.textStack.addArrangedSubview(seg) - seg.snp.makeConstraints { (mk) in - mk.height.equalTo(40) - } - // 添加标题 - vc.vm.add(subTitle: "设置蒙版透明度") - // 添加控件 - let slider = UISlider() - slider.minimumValue = 0 - slider.maximumValue = 100 - slider.value = 100 - vc.textStack.addArrangedSubview(slider) - slider.snp.makeConstraints { (mk) in - mk.height.equalTo(40) - } - // 添加按钮 - vc.vm.add(action: .default, title: "OK") { [weak vc] in - vc?.pop() - } - } - } - - // MARK: 隐私协议页面 - sec.addRow(title: "示例:弹出隐私协议页面", subtitle: "也可以完全控制整个页面") { - Guard.push("license") { (vc) in - // 全屏 - vc.isFullScreen = true - // 添加标题 - vc.vm.add(title: "隐私协议").snp.makeConstraints { (mk) in - mk.height.equalTo(44) - } - // 添加网页 - let web = WKWebView.init(frame: .zero) - web.layer.masksToBounds = true - web.layer.cornerRadius = ProHUD.shared.config.guard.buttonCornerRadius - web.scrollView.showsHorizontalScrollIndicator = false - if let url = URL(string: "https://xaoxuu.com/wiki/prohud/") { - web.load(URLRequest(url: url)) - } - vc.textStack.addArrangedSubview(web) - web.snp.makeConstraints { (mk) in - mk.leading.trailing.equalToSuperview() - } - // 添加文本 - vc.vm.add(message: "请认真阅读以上内容,当您阅读完毕并同意协议内容时点击接受按钮。") - // 添加按钮 - vc.vm.add(action: .default, title: "接受") { [weak vc] in - vc?.pop() - } - } - } - } - - vm.addSection(title: "对比效果") { (sec) in - // MARK: 对比:原生的ActionSheet - sec.addRow(title: "对比:原生的ActionSheet") { - let ac = UIAlertController(title: "Title", message: "message", preferredStyle: .actionSheet) - let ok = UIAlertAction(title: "OK", style: .default, handler: nil) - let cancel = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) - ac.addAction(ok) - ac.addAction(cancel) - ac.popoverPresentationController?.sourceView = self.view - self.present(ac, animated: true, completion: nil) - } - // MARK: 对比:原生Present效果 - sec.addRow(title: "对比:原生Present效果") { - let vc = UIViewController() - vc.view.backgroundColor = .white - vc.title = "ceshi" - self.present(vc, animated: true, completion: nil) - } - } - } - - -} diff --git a/Example-Old/Example/TestToastVC.swift b/Example-Old/Example/TestToastVC.swift deleted file mode 100644 index 9cd9109..0000000 --- a/Example-Old/Example/TestToastVC.swift +++ /dev/null @@ -1,240 +0,0 @@ -// -// TestToastVC.swift -// Example -// -// Created by xaoxuu on 2019/8/12. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit -import ProHUD - -// 模拟15秒后同步成功 -func loadingSuccessAfter15Seconds() { - DispatchQueue.main.asyncAfter(deadline: .now() + 15) { - Toast.find("loading") { (a) in - a.update { (vm) in - vm.scene = .success - vm.title = "同步成功" - vm.message = "啊哈哈哈哈哈哈哈哈" - } - } - } -} - - -class TestToastVC: BaseListVC { - - override func viewDidLoad() { - super.viewDidLoad() - - // Do any additional setup after loading the view. - - vm.addSection(title: "简单的例子") { (sec) in - // MARK: Hello World - sec.addRow(title: "Hello World") { - Toast.push(title: "Hello World", message: "This is a test message from ProHUD.") - } - - // MARK: 场景:正在加载(没有进度显示) - sec.addRow(title: "场景:正在加载(没有进度显示)") { - Toast.push(scene: .loading).startRotate() - loadingSuccessAfter15Seconds() - } - // MARK: 场景:正在加载(有进度显示) - sec.addRow(title: "场景:正在加载(有进度显示)") { - if Toast.find("progress").count == 0 { - Toast.push("progress", scene: .loading) { (t) in - t.update { (vm) in - vm.title = "笑容正在加载" - vm.message = "这通常不会太久" - } - t.startRotate() - t.update(progress: 0) - updateProgress { (pct) in - t.update(progress: pct) - if pct >= 1 { - DispatchQueue.main.asyncAfter(deadline: .now()+0.5) { - t.update { (vm) in - vm.scene = .success - vm.icon = UIImage(named: "Feel1") - vm.title = "加载成功" - vm.message = "阿哈哈哈哈.jpg" - } - } - } - } - } - } - } - // MARK: 场景:同步成功 - sec.addRow(title: "场景:同步成功") { - let t = Toast.push(scene: .success, title: "同步成功", message: "点击查看详情") - t.didTapped { [weak self, weak t] in - self?.presentEmptyVC(title: "详情") - t?.pop() - } - } - // MARK: 场景:同步失败 - sec.addRow(title: "场景:同步失败") { - Toast.push(scene: .error, title: "同步失败", message: "请稍后重试。点击查看详情") { (vc) in - vc.update { (vm) in - vm.duration = 0 - } - vc.didTapped { [weak self, weak vc] in - self?.presentEmptyVC(title: "这是错误详情") - vc?.pop() - } - } - } - // MARK: 场景:设备电量过低 - sec.addRow(title: "场景:设备电量过低", subtitle: "这条消息正文部分显示多行") { - Toast.push(scene: .warning, title: "设备电量过低", message: "请及时对设备进行充电,以免影响使用。\n为了您的续航,我们已经为您限制了设备的峰值性能。") { (vc) in - vc.vm.duration = 0 - } - } - } - - vm.addSection(title: "实用的例子") { (sec) in - // MARK: 避免重复发布同一条信息 - sec.addRow(title: "避免重复发布同一条信息 (id=aaa)", subtitle: "为一个实例指定 identifier 可以避免重复出现。") { - Toast.push("aaa") { (vc) in - vc.update { (vm) in - vm.scene = .warning - vm.message = "这则消息不会同时出现在多条横幅中。" - vm.duration = 0 - } - vc.pulse() - } - } - // MARK: 根据 identifier 查找并修改实例 - sec.addRow(title: "根据 identifier 查找并修改实例 (id=aaa)", subtitle: "在本例中,如果找不到就不进行处理。") { - // 本例和上例唯一的区别是 push -> find - Toast.find("aaa") { (t) in - t.update { (vm) in - vm.scene = .success - vm.title = "找到了哈哈" - vm.message = "根据 identifier 查找并修改实例" - vm.duration = 0 - } - t.pulse() - } - } - // MARK: 传入指定图标 - sec.addRow(title: "传入指定图标", subtitle: "虽然您对实例具有有完全的自由,但是更建议提前在场景中设置好对应的图片。") { - Toast.push(scene: .default, title: "传入指定图标测试", message: "这是消息内容") { (vc) in - vc.update { (vm) in - if #available(iOS 13.0, *) { - vc.imageView.tintColor = .brown - vm.icon = UIImage(systemName: "icloud.and.arrow.down") - } else { - vm.icon = UIImage(named: "icloud.and.arrow.down") - } - } - } - } - // MARK: 禁止手势移除 - sec.addRow(title: "禁止手势移除", subtitle: "常用于优先级低但是必须用户处理的事件。") { - Toast.push(scene: .default, title: "禁止手势移除", message: "这条消息无法通过向上滑动移出屏幕。5秒后自动消失,每次拖拽都会刷新倒计时。") { (vc) in - vc.isRemovable = false - vc.update { (vm) in - vm.duration = 5 - } - } - } - // MARK: 组合使用示例 - sec.addRow(title: "和弹窗组合使用示例", subtitle: "如果有一个横幅消息需要用户做出选择怎么办?可以点击的时候弹出一个弹窗来。") { - Toast.push(scene: .message, title: "好友邀请", message: "你收到一条好友邀请,点击查看详情。", duration: 10) { (vc) in - vc.identifier = "xxx" - vc.didTapped { [weak vc] in - vc?.pop() - Alert.push(scene: .confirm, title: "好友邀请", message: "用户xxx想要添加你为好友,是否同意?") { (vc) in - vc.update { (vm) in - vm.add(action: .default, title: "接受") { [weak vc] in - vc?.pop() - Toast.push(scene: .success, title: "好友添加成功", message: "这是消息内容") - } - vm.add(action: .cancel, title: "拒绝") { - - } - } - } - } - } - } - - // MARK: 自定义要旋转的图片 - sec.addRow(title: "自定义要旋转的图片", subtitle: "添加了自定义视图,在更新的时候记得要视情况移除。") { - Toast.push(scene: .privacy, title: "正在授权", message: "请稍等片刻") { (t) in - t.identifier = "loading" - let imgv = UIImageView(image: UIImage(named: "prohud.rainbow.circle")) - t.imageView.addSubview(imgv) - imgv.tag = 1 - imgv.snp.makeConstraints { (mk) in - mk.center.equalToSuperview() - mk.width.height.equalTo(18) - } - t.startRotate(imgv.layer, speed: 4) - t.vm.duration = 0 - } - DispatchQueue.main.asyncAfter(deadline: .now() + 5) { - Toast.find("loading") { (a) in - a.imageView.viewWithTag(1)?.removeFromSuperview() - a.update { (vm) in - vm.scene = .success - vm.title = "授权成功" - vm.message = "啊哈哈哈哈哈哈哈哈" - } - } - } - } - - } - - - vm.addSection(title: "极端场景") { (sec) in - - // MARK: 测试较长的标题和内容 - sec.addRow(title: "测试较长的标题和内容") { - Toast.push() { (a) in - a.update { (vm) in - vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过" - vm.message = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过" - - } - } - } - // MARK: 测试特别长的标题和内容 - sec.addRow(title: "测试特别长的标题和内容", subtitle: "可以在配置中设置 titleMaxLines/bodyMaxLines 来避免出现这种情况。") { - Toast.push() { (a) in - a.update { (vm) in - vm.title = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过" - vm.message = "正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过正在同步看到了你撒地方快乐撒的肌肤轮廓啊就是;来的跨省的人格人格离开那地方离开过" - - } - } - } - // MARK: 只有标题 - sec.addRow(title: "只有标题部分的效果", subtitle: "这种情况请控制文字不要太少,否则不美观。") { - Toast.push() { (a) in - a.update { (vm) in - vm.title = "坐和放宽,我们正在帮你搞定一切,这通常不会太久。" - } - } - } - // MARK: 只有正文 - sec.addRow(title: "只有正文部分的效果", subtitle: "这种情况请控制文字不要太少,否则不美观。") { - Toast.push() { (a) in - a.update { (vm) in - vm.message = "坐和放宽,我们正在帮你搞定一切,这通常不会太久。\n不幸的是,它花费的时间比通常要长。" - } - } - } - - - } - - - } - -} diff --git a/Example-Old/Example/ViewController.swift b/Example-Old/Example/ViewController.swift deleted file mode 100644 index 772aa2a..0000000 --- a/Example-Old/Example/ViewController.swift +++ /dev/null @@ -1,91 +0,0 @@ -// -// ViewController.swift -// Example -// -// Created by xaoxuu on 2018/6/15. -// Copyright © 2018 Titan Studio. All rights reserved. -// - -import UIKit -import ProHUD -import SnapKit -import WebKit - -class ViewController: BaseListVC { - - override func viewDidLoad() { - super.viewDidLoad() - // Do any additional setup after loading the view. - title = "\(Bundle.main.infoDictionary?["CFBundleName"] ?? "ProHUD")" - - - vm.addSection(title: "测试项目") { (sec) in - sec.addRow(title: "Toast", subtitle: "横幅控件,支持图片、标题和正文。\n不支持添加按钮,但可以接受一个点击事件。") { - let vc = TestToastVC() - vc.title = "Toast" - self.navigationController?.pushViewController(vc, animated: true) - } - sec.addRow(title: "Alert", subtitle: "弹窗控件,支持图片、标题、正文和按钮。\n按钮不设置事件回调时可以自动pop。") { - let vc = TestAlertVC() - vc.title = "Alert" - self.navigationController?.pushViewController(vc, animated: true) - } - sec.addRow(title: "Guard", subtitle: "操作表控件,原生支持标题、副标题、正文和按钮,也可以添加任意视图。") { - let vc = TestGuardVC() - vc.title = "Guard" - self.navigationController?.pushViewController(vc, animated: true) - } - - } - - - vm.addSection(title: "小提示") { (sec) in - sec.addRow(title: "所有控件都是ViewController", subtitle: "可以监听进入、离开移除事件。\n推入、推出统一为 push/pop 操作。\n所有控件都可以在配置中完全自定义布局及样式。\n通过 identifier 来获取实例,方便进行多实例管理") { - } - sec.addRow(title: "基于场景的应用", subtitle: "一个场景就是一套模板,原生提供了一些常用场景,您可以覆写,也可以新建场景。\n在场景中可以指定持续时间、标题、图标、正文等数据。") { - } - sec.addRow(title: "样式与逻辑分离", subtitle: "您可以在场景中指定一些规则,也可以在配置中完全自定义布局样式。\n在使用的时候呢,只需要确定数据即可。") { - } - sec.addRow(title: "Loading图片旋转", subtitle: "可以通过调用 .startRotate() 并可传入适当参数来旋转,也可以自定义场景\n如果场景的 identifier 包含 .rotate 则会自动旋转图片") { - } - sec.addRow(title: "按钮默认行为", subtitle: "为了灵活性,default 和 destructive 按钮默认不会对实例进行 pop 操作,但是如果它们没有实现回调事件,则会自动 pop。cancel 按钮永远会自动 pop。") { - } - sec.addRow(title: "持续时间", subtitle: "设置 duration 来指定持续时间,设置为 0 可以永久持续。\n原生提供的 loading 场景持续时间为永久。\n如果弹窗添加了按钮,则持续时间会自动变成永久,除非手动设置。") { - } - sec.addRow(title: "支持深色模式", subtitle: "切换一下模式看看") { - } - } - - vm.addSection(title: "更多") { (sec) in - sec.addRow(title: "查看在线文档", subtitle: "https://xaoxuu.com/wiki/prohud/") { - Guard.push("license") { (vc) in - // 全屏 - vc.isFullScreen = true - // 添加标题 - vc.vm.add(title: "ProHUD").snp.makeConstraints { (mk) in - mk.height.equalTo(44) - } - // 添加网页 - let web = WKWebView.init(frame: .zero) - web.layer.masksToBounds = true - web.layer.cornerRadius = ProHUD.shared.config.guard.buttonCornerRadius - web.scrollView.showsHorizontalScrollIndicator = false - if let url = URL(string: "https://xaoxuu.com/wiki/prohud/") { - web.load(URLRequest(url: url)) - } - vc.textStack.addArrangedSubview(web) - web.snp.makeConstraints { (mk) in - mk.leading.trailing.equalToSuperview() - } - // 添加按钮 - vc.vm.add(action: .default, title: "关闭") { [weak vc] in - vc?.pop() - } - } - } - } - - } - -} - diff --git a/Example-Old/Podfile b/Example-Old/Podfile deleted file mode 100644 index 4b38fd5..0000000 --- a/Example-Old/Podfile +++ /dev/null @@ -1,16 +0,0 @@ -platform :ios, '10.0' -use_frameworks! - -target 'Example' do - - pod 'ProHUD', :path => '..' - - pod 'SnapKit', '5.0.0' - pod 'Inspire', :path => '../../Inspire' - -end - - - -#pod install --verbose --no-repo-update #安装命令 -#pod update --verbose --no-repo-update #更新命令 diff --git a/Example-Old/Podfile.lock b/Example-Old/Podfile.lock deleted file mode 100644 index a973bee..0000000 --- a/Example-Old/Podfile.lock +++ /dev/null @@ -1,30 +0,0 @@ -PODS: - - Inspire (2.1.0) - - ProHUD (1.0): - - Inspire - - SnapKit (= 5.0) - - SnapKit (5.0.0) - -DEPENDENCIES: - - Inspire (from `../../Inspire`) - - ProHUD (from `..`) - - SnapKit (= 5.0.0) - -SPEC REPOS: - trunk: - - SnapKit - -EXTERNAL SOURCES: - Inspire: - :path: "../../Inspire" - ProHUD: - :path: ".." - -SPEC CHECKSUMS: - Inspire: 087dce1e4ff902d26d79bd3453352af09411c172 - ProHUD: 7128b55036885ac4f8b4d0b0783ee6f8eb3a2ea9 - SnapKit: fd22d10eb9aff484d79a8724eab922c1ddf89bcf - -PODFILE CHECKSUM: 80148eec6ba2e9631b208c7b277316b6c551afc4 - -COCOAPODS: 1.10.1 diff --git a/Example-Old/README.md b/Example-Old/README.md deleted file mode 100644 index 67a6bd1..0000000 --- a/Example-Old/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# 使用 AppDelegate 的项目 - - - diff --git a/Example-Xcode11/Example-Xcode11.xcodeproj/project.pbxproj b/Example-Xcode11/Example-Xcode11.xcodeproj/project.pbxproj deleted file mode 100644 index 7ab5fd7..0000000 --- a/Example-Xcode11/Example-Xcode11.xcodeproj/project.pbxproj +++ /dev/null @@ -1,663 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 52; - objects = { - -/* Begin PBXBuildFile section */ - CDD85460249CD681004BCE22 /* TestGuardVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDD85458249CD681004BCE22 /* TestGuardVC.swift */; }; - CDD85461249CD681004BCE22 /* BaseListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDD85459249CD681004BCE22 /* BaseListVC.swift */; }; - CDD85462249CD681004BCE22 /* EmptyVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDD8545A249CD681004BCE22 /* EmptyVC.swift */; }; - CDD85463249CD681004BCE22 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CDD8545B249CD681004BCE22 /* Assets.xcassets */; }; - CDD85464249CD681004BCE22 /* RootVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDD8545C249CD681004BCE22 /* RootVC.swift */; }; - CDD85465249CD681004BCE22 /* TestToastVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDD8545D249CD681004BCE22 /* TestToastVC.swift */; }; - CDD85466249CD681004BCE22 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDD8545E249CD681004BCE22 /* ViewController.swift */; }; - CDD85467249CD681004BCE22 /* TestAlertVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDD8545F249CD681004BCE22 /* TestAlertVC.swift */; }; - CDF2C8E1249722F800C81274 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF2C8E0249722F800C81274 /* AppDelegate.swift */; }; - CDF2C8E3249722F800C81274 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF2C8E2249722F800C81274 /* SceneDelegate.swift */; }; - CDF2C8E8249722F800C81274 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CDF2C8E6249722F800C81274 /* Main.storyboard */; }; - CDF2C8ED249722F900C81274 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CDF2C8EB249722F900C81274 /* LaunchScreen.storyboard */; }; - CDF2C8F8249722F900C81274 /* Example_Xcode11Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF2C8F7249722F900C81274 /* Example_Xcode11Tests.swift */; }; - CDF2C903249722F900C81274 /* Example_Xcode11UITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF2C902249722F900C81274 /* Example_Xcode11UITests.swift */; }; - CDF2C9152497237300C81274 /* Inspire in Frameworks */ = {isa = PBXBuildFile; productRef = CDF2C9142497237300C81274 /* Inspire */; }; - CDF2C94A2497577C00C81274 /* ProHUD in Frameworks */ = {isa = PBXBuildFile; productRef = CDF2C9492497577C00C81274 /* ProHUD */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - CDF2C8F4249722F900C81274 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CDF2C8D5249722F800C81274 /* Project object */; - proxyType = 1; - remoteGlobalIDString = CDF2C8DC249722F800C81274; - remoteInfo = "Example-Xcode11"; - }; - CDF2C8FF249722F900C81274 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = CDF2C8D5249722F800C81274 /* Project object */; - proxyType = 1; - remoteGlobalIDString = CDF2C8DC249722F800C81274; - remoteInfo = "Example-Xcode11"; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - CDD85458249CD681004BCE22 /* TestGuardVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestGuardVC.swift; path = "../../Example-Old/Example/TestGuardVC.swift"; sourceTree = ""; }; - CDD85459249CD681004BCE22 /* BaseListVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BaseListVC.swift; path = "../../Example-Old/Example/BaseListVC.swift"; sourceTree = ""; }; - CDD8545A249CD681004BCE22 /* EmptyVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = EmptyVC.swift; path = "../../Example-Old/Example/EmptyVC.swift"; sourceTree = ""; }; - CDD8545B249CD681004BCE22 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = "../../Example-Old/Example/Assets.xcassets"; sourceTree = ""; }; - CDD8545C249CD681004BCE22 /* RootVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RootVC.swift; path = "../../Example-Old/Example/RootVC.swift"; sourceTree = ""; }; - CDD8545D249CD681004BCE22 /* TestToastVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestToastVC.swift; path = "../../Example-Old/Example/TestToastVC.swift"; sourceTree = ""; }; - CDD8545E249CD681004BCE22 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ViewController.swift; path = "../../Example-Old/Example/ViewController.swift"; sourceTree = ""; }; - CDD8545F249CD681004BCE22 /* TestAlertVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TestAlertVC.swift; path = "../../Example-Old/Example/TestAlertVC.swift"; sourceTree = ""; }; - CDF2C8DD249722F800C81274 /* ProHUD Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ProHUD Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - CDF2C8E0249722F800C81274 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - CDF2C8E2249722F800C81274 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - CDF2C8E7249722F800C81274 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - CDF2C8EC249722F900C81274 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - CDF2C8EE249722F900C81274 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - CDF2C8F3249722F900C81274 /* Example-Xcode11Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Example-Xcode11Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - CDF2C8F7249722F900C81274 /* Example_Xcode11Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Example_Xcode11Tests.swift; sourceTree = ""; }; - CDF2C8F9249722F900C81274 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - CDF2C8FE249722F900C81274 /* Example-Xcode11UITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Example-Xcode11UITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - CDF2C902249722F900C81274 /* Example_Xcode11UITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Example_Xcode11UITests.swift; sourceTree = ""; }; - CDF2C904249722F900C81274 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - CDF2C8DA249722F800C81274 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - CDF2C94A2497577C00C81274 /* ProHUD in Frameworks */, - CDF2C9152497237300C81274 /* Inspire in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CDF2C8F0249722F900C81274 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CDF2C8FB249722F900C81274 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - CDF2C8D4249722F800C81274 = { - isa = PBXGroup; - children = ( - CDF2C8DF249722F800C81274 /* Example-Xcode11 */, - CDF2C8F6249722F900C81274 /* Example-Xcode11Tests */, - CDF2C901249722F900C81274 /* Example-Xcode11UITests */, - CDF2C8DE249722F800C81274 /* Products */, - ); - sourceTree = ""; - }; - CDF2C8DE249722F800C81274 /* Products */ = { - isa = PBXGroup; - children = ( - CDF2C8DD249722F800C81274 /* ProHUD Demo.app */, - CDF2C8F3249722F900C81274 /* Example-Xcode11Tests.xctest */, - CDF2C8FE249722F900C81274 /* Example-Xcode11UITests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - CDF2C8DF249722F800C81274 /* Example-Xcode11 */ = { - isa = PBXGroup; - children = ( - CDF2C8E0249722F800C81274 /* AppDelegate.swift */, - CDF2C8E2249722F800C81274 /* SceneDelegate.swift */, - CDD8545B249CD681004BCE22 /* Assets.xcassets */, - CDD85459249CD681004BCE22 /* BaseListVC.swift */, - CDD8545A249CD681004BCE22 /* EmptyVC.swift */, - CDD8545C249CD681004BCE22 /* RootVC.swift */, - CDD8545F249CD681004BCE22 /* TestAlertVC.swift */, - CDD85458249CD681004BCE22 /* TestGuardVC.swift */, - CDD8545D249CD681004BCE22 /* TestToastVC.swift */, - CDD8545E249CD681004BCE22 /* ViewController.swift */, - CDF2C8E6249722F800C81274 /* Main.storyboard */, - CDF2C8EB249722F900C81274 /* LaunchScreen.storyboard */, - CDF2C8EE249722F900C81274 /* Info.plist */, - ); - path = "Example-Xcode11"; - sourceTree = ""; - }; - CDF2C8F6249722F900C81274 /* Example-Xcode11Tests */ = { - isa = PBXGroup; - children = ( - CDF2C8F7249722F900C81274 /* Example_Xcode11Tests.swift */, - CDF2C8F9249722F900C81274 /* Info.plist */, - ); - path = "Example-Xcode11Tests"; - sourceTree = ""; - }; - CDF2C901249722F900C81274 /* Example-Xcode11UITests */ = { - isa = PBXGroup; - children = ( - CDF2C902249722F900C81274 /* Example_Xcode11UITests.swift */, - CDF2C904249722F900C81274 /* Info.plist */, - ); - path = "Example-Xcode11UITests"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - CDF2C8DC249722F800C81274 /* Example-Xcode11 */ = { - isa = PBXNativeTarget; - buildConfigurationList = CDF2C907249722F900C81274 /* Build configuration list for PBXNativeTarget "Example-Xcode11" */; - buildPhases = ( - CDF2C8D9249722F800C81274 /* Sources */, - CDF2C8DA249722F800C81274 /* Frameworks */, - CDF2C8DB249722F800C81274 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "Example-Xcode11"; - packageProductDependencies = ( - CDF2C9142497237300C81274 /* Inspire */, - CDF2C9492497577C00C81274 /* ProHUD */, - ); - productName = "Example-Xcode11"; - productReference = CDF2C8DD249722F800C81274 /* ProHUD Demo.app */; - productType = "com.apple.product-type.application"; - }; - CDF2C8F2249722F900C81274 /* Example-Xcode11Tests */ = { - isa = PBXNativeTarget; - buildConfigurationList = CDF2C90A249722F900C81274 /* Build configuration list for PBXNativeTarget "Example-Xcode11Tests" */; - buildPhases = ( - CDF2C8EF249722F900C81274 /* Sources */, - CDF2C8F0249722F900C81274 /* Frameworks */, - CDF2C8F1249722F900C81274 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - CDF2C8F5249722F900C81274 /* PBXTargetDependency */, - ); - name = "Example-Xcode11Tests"; - productName = "Example-Xcode11Tests"; - productReference = CDF2C8F3249722F900C81274 /* Example-Xcode11Tests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - CDF2C8FD249722F900C81274 /* Example-Xcode11UITests */ = { - isa = PBXNativeTarget; - buildConfigurationList = CDF2C90D249722F900C81274 /* Build configuration list for PBXNativeTarget "Example-Xcode11UITests" */; - buildPhases = ( - CDF2C8FA249722F900C81274 /* Sources */, - CDF2C8FB249722F900C81274 /* Frameworks */, - CDF2C8FC249722F900C81274 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - CDF2C900249722F900C81274 /* PBXTargetDependency */, - ); - name = "Example-Xcode11UITests"; - productName = "Example-Xcode11UITests"; - productReference = CDF2C8FE249722F900C81274 /* Example-Xcode11UITests.xctest */; - productType = "com.apple.product-type.bundle.ui-testing"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - CDF2C8D5249722F800C81274 /* Project object */ = { - isa = PBXProject; - attributes = { - LastSwiftUpdateCheck = 1150; - LastUpgradeCheck = 1150; - ORGANIZATIONNAME = xaoxuu; - TargetAttributes = { - CDF2C8DC249722F800C81274 = { - CreatedOnToolsVersion = 11.5; - }; - CDF2C8F2249722F900C81274 = { - CreatedOnToolsVersion = 11.5; - TestTargetID = CDF2C8DC249722F800C81274; - }; - CDF2C8FD249722F900C81274 = { - CreatedOnToolsVersion = 11.5; - TestTargetID = CDF2C8DC249722F800C81274; - }; - }; - }; - buildConfigurationList = CDF2C8D8249722F800C81274 /* Build configuration list for PBXProject "Example-Xcode11" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = CDF2C8D4249722F800C81274; - packageReferences = ( - CDF2C9132497237300C81274 /* XCRemoteSwiftPackageReference "Inspire" */, - CDF2C9482497577C00C81274 /* XCRemoteSwiftPackageReference "ProHUD" */, - ); - productRefGroup = CDF2C8DE249722F800C81274 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - CDF2C8DC249722F800C81274 /* Example-Xcode11 */, - CDF2C8F2249722F900C81274 /* Example-Xcode11Tests */, - CDF2C8FD249722F900C81274 /* Example-Xcode11UITests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - CDF2C8DB249722F800C81274 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - CDF2C8ED249722F900C81274 /* LaunchScreen.storyboard in Resources */, - CDD85463249CD681004BCE22 /* Assets.xcassets in Resources */, - CDF2C8E8249722F800C81274 /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CDF2C8F1249722F900C81274 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CDF2C8FC249722F900C81274 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - CDF2C8D9249722F800C81274 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - CDD85464249CD681004BCE22 /* RootVC.swift in Sources */, - CDD85462249CD681004BCE22 /* EmptyVC.swift in Sources */, - CDF2C8E1249722F800C81274 /* AppDelegate.swift in Sources */, - CDD85465249CD681004BCE22 /* TestToastVC.swift in Sources */, - CDD85460249CD681004BCE22 /* TestGuardVC.swift in Sources */, - CDD85467249CD681004BCE22 /* TestAlertVC.swift in Sources */, - CDF2C8E3249722F800C81274 /* SceneDelegate.swift in Sources */, - CDD85466249CD681004BCE22 /* ViewController.swift in Sources */, - CDD85461249CD681004BCE22 /* BaseListVC.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CDF2C8EF249722F900C81274 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - CDF2C8F8249722F900C81274 /* Example_Xcode11Tests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - CDF2C8FA249722F900C81274 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - CDF2C903249722F900C81274 /* Example_Xcode11UITests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - CDF2C8F5249722F900C81274 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = CDF2C8DC249722F800C81274 /* Example-Xcode11 */; - targetProxy = CDF2C8F4249722F900C81274 /* PBXContainerItemProxy */; - }; - CDF2C900249722F900C81274 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = CDF2C8DC249722F800C81274 /* Example-Xcode11 */; - targetProxy = CDF2C8FF249722F900C81274 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - CDF2C8E6249722F800C81274 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - CDF2C8E7249722F800C81274 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - CDF2C8EB249722F900C81274 /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - CDF2C8EC249722F900C81274 /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - CDF2C905249722F900C81274 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - CDF2C906249722F900C81274 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.0; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - CDF2C908249722F900C81274 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 34W5TB5KD2; - INFOPLIST_FILE = "Example-Xcode11/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.xaoxuu.Example-Xcode11"; - PRODUCT_NAME = "ProHUD Demo"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - CDF2C909249722F900C81274 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 34W5TB5KD2; - INFOPLIST_FILE = "Example-Xcode11/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.xaoxuu.Example-Xcode11"; - PRODUCT_NAME = "ProHUD Demo"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - CDF2C90B249722F900C81274 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 34W5TB5KD2; - INFOPLIST_FILE = "Example-Xcode11Tests/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 13.5; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.xaoxuu.Example-Xcode11Tests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example-Xcode11.app/Example-Xcode11"; - }; - name = Debug; - }; - CDF2C90C249722F900C81274 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 34W5TB5KD2; - INFOPLIST_FILE = "Example-Xcode11Tests/Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 13.5; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.xaoxuu.Example-Xcode11Tests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example-Xcode11.app/Example-Xcode11"; - }; - name = Release; - }; - CDF2C90E249722F900C81274 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 34W5TB5KD2; - INFOPLIST_FILE = "Example-Xcode11UITests/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.xaoxuu.Example-Xcode11UITests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_TARGET_NAME = "Example-Xcode11"; - }; - name = Debug; - }; - CDF2C90F249722F900C81274 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 34W5TB5KD2; - INFOPLIST_FILE = "Example-Xcode11UITests/Info.plist"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.xaoxuu.Example-Xcode11UITests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - TEST_TARGET_NAME = "Example-Xcode11"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - CDF2C8D8249722F800C81274 /* Build configuration list for PBXProject "Example-Xcode11" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CDF2C905249722F900C81274 /* Debug */, - CDF2C906249722F900C81274 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - CDF2C907249722F900C81274 /* Build configuration list for PBXNativeTarget "Example-Xcode11" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CDF2C908249722F900C81274 /* Debug */, - CDF2C909249722F900C81274 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - CDF2C90A249722F900C81274 /* Build configuration list for PBXNativeTarget "Example-Xcode11Tests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CDF2C90B249722F900C81274 /* Debug */, - CDF2C90C249722F900C81274 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - CDF2C90D249722F900C81274 /* Build configuration list for PBXNativeTarget "Example-Xcode11UITests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CDF2C90E249722F900C81274 /* Debug */, - CDF2C90F249722F900C81274 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - CDF2C9132497237300C81274 /* XCRemoteSwiftPackageReference "Inspire" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/xaoxuu/Inspire"; - requirement = { - branch = master; - kind = branch; - }; - }; - CDF2C9482497577C00C81274 /* XCRemoteSwiftPackageReference "ProHUD" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/xaoxuu/ProHUD"; - requirement = { - branch = master; - kind = branch; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - CDF2C9142497237300C81274 /* Inspire */ = { - isa = XCSwiftPackageProductDependency; - package = CDF2C9132497237300C81274 /* XCRemoteSwiftPackageReference "Inspire" */; - productName = Inspire; - }; - CDF2C9492497577C00C81274 /* ProHUD */ = { - isa = XCSwiftPackageProductDependency; - package = CDF2C9482497577C00C81274 /* XCRemoteSwiftPackageReference "ProHUD" */; - productName = ProHUD; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = CDF2C8D5249722F800C81274 /* Project object */; -} diff --git a/Example-Xcode11/Example-Xcode11.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Example-Xcode11/Example-Xcode11.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/Example-Xcode11/Example-Xcode11.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/Example-Xcode11/Example-Xcode11.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Example-Xcode11/Example-Xcode11.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index 87f5c11..0000000 --- a/Example-Xcode11/Example-Xcode11.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,34 +0,0 @@ -{ - "object": { - "pins": [ - { - "package": "Inspire", - "repositoryURL": "https://github.com/xaoxuu/Inspire", - "state": { - "branch": "master", - "revision": "22c89fa2ff06bcd44b8c0500a82e64d4baf80387", - "version": null - } - }, - { - "package": "ProHUD", - "repositoryURL": "https://github.com/xaoxuu/ProHUD", - "state": { - "branch": "master", - "revision": "84b9931a8aa979d82c53376d9ff84f9e432dcc7c", - "version": null - } - }, - { - "package": "SnapKit", - "repositoryURL": "https://github.com/SnapKit/SnapKit.git", - "state": { - "branch": null, - "revision": "d458564516e5676af9c70b4f4b2a9178294f1bc6", - "version": "5.0.1" - } - } - ] - }, - "version": 1 -} diff --git a/Example-Xcode11/Example-Xcode11/Base.lproj/Main.storyboard b/Example-Xcode11/Example-Xcode11/Base.lproj/Main.storyboard deleted file mode 100644 index 25a7638..0000000 --- a/Example-Xcode11/Example-Xcode11/Base.lproj/Main.storyboard +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Example-Xcode11/Example-Xcode11/Info.plist b/Example-Xcode11/Example-Xcode11/Info.plist deleted file mode 100644 index 9592629..0000000 --- a/Example-Xcode11/Example-Xcode11/Info.plist +++ /dev/null @@ -1,62 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - LSRequiresIPhoneOS - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - UISceneStoryboardFile - Main - - - - - UILaunchStoryboardName - LaunchScreen - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Example-Xcode11/Example-Xcode11Tests/Example_Xcode11Tests.swift b/Example-Xcode11/Example-Xcode11Tests/Example_Xcode11Tests.swift deleted file mode 100644 index ddc3c9e..0000000 --- a/Example-Xcode11/Example-Xcode11Tests/Example_Xcode11Tests.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// Example_Xcode11Tests.swift -// Example-Xcode11Tests -// -// Created by xaoxuu on 2020/6/15. -// Copyright © 2020 xaoxuu. All rights reserved. -// - -import XCTest -@testable import Example_Xcode11 - -class Example_Xcode11Tests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct results. - } - - func testPerformanceExample() throws { - // This is an example of a performance test case. - self.measure { - // Put the code you want to measure the time of here. - } - } - -} diff --git a/Example-Xcode11/Example-Xcode11Tests/Info.plist b/Example-Xcode11/Example-Xcode11Tests/Info.plist deleted file mode 100644 index 64d65ca..0000000 --- a/Example-Xcode11/Example-Xcode11Tests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/Example-Xcode11/Example-Xcode11UITests/Example_Xcode11UITests.swift b/Example-Xcode11/Example-Xcode11UITests/Example_Xcode11UITests.swift deleted file mode 100644 index a7738ca..0000000 --- a/Example-Xcode11/Example-Xcode11UITests/Example_Xcode11UITests.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// Example_Xcode11UITests.swift -// Example-Xcode11UITests -// -// Created by xaoxuu on 2020/6/15. -// Copyright © 2020 xaoxuu. All rights reserved. -// - -import XCTest - -class Example_Xcode11UITests: XCTestCase { - - override func setUpWithError() throws { - // Put setup code here. This method is called before the invocation of each test method in the class. - - // In UI tests it is usually best to stop immediately when a failure occurs. - continueAfterFailure = false - - // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. - } - - override func tearDownWithError() throws { - // Put teardown code here. This method is called after the invocation of each test method in the class. - } - - func testExample() throws { - // UI tests must launch the application that they test. - let app = XCUIApplication() - app.launch() - - // Use recording to get started writing UI tests. - // Use XCTAssert and related functions to verify your tests produce the correct results. - } - - func testLaunchPerformance() throws { - if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { - // This measures how long it takes to launch your application. - measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) { - XCUIApplication().launch() - } - } - } -} diff --git a/Example-Xcode11/Example-Xcode11UITests/Info.plist b/Example-Xcode11/Example-Xcode11UITests/Info.plist deleted file mode 100644 index 64d65ca..0000000 --- a/Example-Xcode11/Example-Xcode11UITests/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/Example-Xcode11/README.md b/Example-Xcode11/README.md deleted file mode 100644 index 018d4d4..0000000 --- a/Example-Xcode11/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# 使用 SceneDelegate 的项目 - diff --git a/PHDemo/PHDemo.xcodeproj/project.pbxproj b/PHDemo/PHDemo.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d95d5aa --- /dev/null +++ b/PHDemo/PHDemo.xcodeproj/project.pbxproj @@ -0,0 +1,419 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + CD6537BF28C3311B00A5981B /* ListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6537BE28C3311B00A5981B /* ListModel.swift */; }; + CD6537C128C35E1C00A5981B /* ListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6537C028C35E1C00A5981B /* ListVC.swift */; }; + CD6537C328C35E6200A5981B /* ToastVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6537C228C35E6200A5981B /* ToastVC.swift */; }; + CD6537C528C35F2C00A5981B /* SheetVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6537C428C35F2C00A5981B /* SheetVC.swift */; }; + CD8EEF3B28BC5C7200E660EA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD8EEF3A28BC5C7200E660EA /* AppDelegate.swift */; }; + CD8EEF3D28BC5C7200E660EA /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD8EEF3C28BC5C7200E660EA /* SceneDelegate.swift */; }; + CD8EEF4228BC5C7200E660EA /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CD8EEF4028BC5C7200E660EA /* Main.storyboard */; }; + CD8EEF4428BC5C7300E660EA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD8EEF4328BC5C7300E660EA /* Assets.xcassets */; }; + CD8EEF4728BC5C7300E660EA /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CD8EEF4528BC5C7300E660EA /* LaunchScreen.storyboard */; }; + CD9C7B1E28CB8972006190CD /* Scenes.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD9C7B1D28CB8972006190CD /* Scenes.swift */; }; + CDA83DB928C601E60025F0DF /* TableHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA83DB828C601E60025F0DF /* TableHeaderView.swift */; }; + CDB6A2A228BC5F4600DEC80D /* ProHUD in Frameworks */ = {isa = PBXBuildFile; productRef = CDB6A2A128BC5F4600DEC80D /* ProHUD */; }; + CDB7A1D028C32A7400E034D8 /* AlertVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDB7A1CF28C32A7400E034D8 /* AlertVC.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + CD6537BE28C3311B00A5981B /* ListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListModel.swift; sourceTree = ""; }; + CD6537C028C35E1C00A5981B /* ListVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListVC.swift; sourceTree = ""; }; + CD6537C228C35E6200A5981B /* ToastVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastVC.swift; sourceTree = ""; }; + CD6537C428C35F2C00A5981B /* SheetVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SheetVC.swift; sourceTree = ""; }; + CD8EEF3728BC5C7200E660EA /* PHDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PHDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + CD8EEF3A28BC5C7200E660EA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + CD8EEF3C28BC5C7200E660EA /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + CD8EEF4128BC5C7200E660EA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + CD8EEF4328BC5C7300E660EA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + CD8EEF4628BC5C7300E660EA /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + CD8EEF4828BC5C7300E660EA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + CD9C7B1D28CB8972006190CD /* Scenes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scenes.swift; sourceTree = ""; }; + CDA83DB828C601E60025F0DF /* TableHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableHeaderView.swift; sourceTree = ""; }; + CDB6A29F28BC5F0F00DEC80D /* ProHUD */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = ProHUD; path = ..; sourceTree = ""; }; + CDB7A1CF28C32A7400E034D8 /* AlertVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertVC.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + CD8EEF3428BC5C7200E660EA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + CDB6A2A228BC5F4600DEC80D /* ProHUD in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + CD8EEF2E28BC5C7200E660EA = { + isa = PBXGroup; + children = ( + CDB6A29E28BC5F0F00DEC80D /* Packages */, + CD8EEF3928BC5C7200E660EA /* PHDemo */, + CD8EEF3828BC5C7200E660EA /* Products */, + CDB6A2A028BC5F4600DEC80D /* Frameworks */, + ); + sourceTree = ""; + }; + CD8EEF3828BC5C7200E660EA /* Products */ = { + isa = PBXGroup; + children = ( + CD8EEF3728BC5C7200E660EA /* PHDemo.app */, + ); + name = Products; + sourceTree = ""; + }; + CD8EEF3928BC5C7200E660EA /* PHDemo */ = { + isa = PBXGroup; + children = ( + CD8EEF3A28BC5C7200E660EA /* AppDelegate.swift */, + CD8EEF3C28BC5C7200E660EA /* SceneDelegate.swift */, + CD6537BE28C3311B00A5981B /* ListModel.swift */, + CDA83DB828C601E60025F0DF /* TableHeaderView.swift */, + CD9C7B1D28CB8972006190CD /* Scenes.swift */, + CD6537C028C35E1C00A5981B /* ListVC.swift */, + CDB7A1CF28C32A7400E034D8 /* AlertVC.swift */, + CD6537C228C35E6200A5981B /* ToastVC.swift */, + CD6537C428C35F2C00A5981B /* SheetVC.swift */, + CD8EEF4028BC5C7200E660EA /* Main.storyboard */, + CD8EEF4328BC5C7300E660EA /* Assets.xcassets */, + CD8EEF4528BC5C7300E660EA /* LaunchScreen.storyboard */, + CD8EEF4828BC5C7300E660EA /* Info.plist */, + ); + path = PHDemo; + sourceTree = ""; + }; + CDB6A29E28BC5F0F00DEC80D /* Packages */ = { + isa = PBXGroup; + children = ( + CDB6A29F28BC5F0F00DEC80D /* ProHUD */, + ); + name = Packages; + sourceTree = ""; + }; + CDB6A2A028BC5F4600DEC80D /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + CD8EEF3628BC5C7200E660EA /* PHDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = CD8EEF4B28BC5C7300E660EA /* Build configuration list for PBXNativeTarget "PHDemo" */; + buildPhases = ( + CD8EEF3328BC5C7200E660EA /* Sources */, + CD8EEF3428BC5C7200E660EA /* Frameworks */, + CD8EEF3528BC5C7200E660EA /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = PHDemo; + packageProductDependencies = ( + CDB6A2A128BC5F4600DEC80D /* ProHUD */, + ); + productName = PHDemo; + productReference = CD8EEF3728BC5C7200E660EA /* PHDemo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + CD8EEF2F28BC5C7200E660EA /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1340; + LastUpgradeCheck = 1340; + TargetAttributes = { + CD8EEF3628BC5C7200E660EA = { + CreatedOnToolsVersion = 13.4.1; + }; + }; + }; + buildConfigurationList = CD8EEF3228BC5C7200E660EA /* Build configuration list for PBXProject "PHDemo" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = CD8EEF2E28BC5C7200E660EA; + productRefGroup = CD8EEF3828BC5C7200E660EA /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + CD8EEF3628BC5C7200E660EA /* PHDemo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + CD8EEF3528BC5C7200E660EA /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CD8EEF4728BC5C7300E660EA /* LaunchScreen.storyboard in Resources */, + CD8EEF4428BC5C7300E660EA /* Assets.xcassets in Resources */, + CD8EEF4228BC5C7200E660EA /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + CD8EEF3328BC5C7200E660EA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + CDA83DB928C601E60025F0DF /* TableHeaderView.swift in Sources */, + CD6537C528C35F2C00A5981B /* SheetVC.swift in Sources */, + CD6537C328C35E6200A5981B /* ToastVC.swift in Sources */, + CDB7A1D028C32A7400E034D8 /* AlertVC.swift in Sources */, + CD6537C128C35E1C00A5981B /* ListVC.swift in Sources */, + CD8EEF3B28BC5C7200E660EA /* AppDelegate.swift in Sources */, + CD8EEF3D28BC5C7200E660EA /* SceneDelegate.swift in Sources */, + CD9C7B1E28CB8972006190CD /* Scenes.swift in Sources */, + CD6537BF28C3311B00A5981B /* ListModel.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + CD8EEF4028BC5C7200E660EA /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + CD8EEF4128BC5C7200E660EA /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + CD8EEF4528BC5C7300E660EA /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + CD8EEF4628BC5C7300E660EA /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + CD8EEF4928BC5C7300E660EA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.5; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + CD8EEF4A28BC5C7300E660EA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 15.5; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + CD8EEF4C28BC5C7300E660EA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = DASH6JFSDW; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = PHDemo/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.xaoxuu.PHDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + CD8EEF4D28BC5C7300E660EA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = DASH6JFSDW; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = PHDemo/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.xaoxuu.PHDemo; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + CD8EEF3228BC5C7200E660EA /* Build configuration list for PBXProject "PHDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CD8EEF4928BC5C7300E660EA /* Debug */, + CD8EEF4A28BC5C7300E660EA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + CD8EEF4B28BC5C7300E660EA /* Build configuration list for PBXNativeTarget "PHDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + CD8EEF4C28BC5C7300E660EA /* Debug */, + CD8EEF4D28BC5C7300E660EA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCSwiftPackageProductDependency section */ + CDB6A2A128BC5F4600DEC80D /* ProHUD */ = { + isa = XCSwiftPackageProductDependency; + productName = ProHUD; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = CD8EEF2F28BC5C7200E660EA /* Project object */; +} diff --git a/Example-Xcode11/Example-Xcode11.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/PHDemo/PHDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from Example-Xcode11/Example-Xcode11.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to PHDemo/PHDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/Example-Old/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/PHDemo/PHDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from Example-Old/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to PHDemo/PHDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/PHDemo/PHDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/PHDemo/PHDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..4a0a7cd --- /dev/null +++ b/PHDemo/PHDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,23 @@ +{ + "pins" : [ + { + "identity" : "inspire", + "kind" : "remoteSourceControl", + "location" : "https://github.com/xaoxuu/Inspire.git", + "state" : { + "revision" : "10d5a17ee24c8a66da9a3971c62c1d161d2a4cd2", + "version" : "3.0.0" + } + }, + { + "identity" : "snapkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SnapKit/SnapKit.git", + "state" : { + "revision" : "f222cbdf325885926566172f6f5f06af95473158", + "version" : "5.6.0" + } + } + ], + "version" : 2 +} diff --git a/PHDemo/PHDemo/AlertVC.swift b/PHDemo/PHDemo/AlertVC.swift new file mode 100644 index 0000000..cf3c3b2 --- /dev/null +++ b/PHDemo/PHDemo/AlertVC.swift @@ -0,0 +1,298 @@ +// +// AlertVC.swift +// PHDemo +// +// Created by xaoxuu on 2022/9/3. +// + +import UIKit +import ProHUD + +class AlertVC: ListVC { + + override func viewDidLoad() { + super.viewDidLoad() + // Uncomment the following line to preserve selection between presentations + // self.clearsSelectionOnViewWillAppear = false + + header.titleLabel.text = "ProHUD.Alert" + header.detailLabel.text = "弹窗控件,用于强阻塞性交互,用户必须做出选择或者等待结果才能进入下一步,当多个实例出现时,会以堆叠的形式显示,新的实例会在覆盖旧的实例上层。" + + Alert.Configuration.shared { config in + config.reloadData { vc in + if vc.identifier == "custom" { + return true + } + return false + } + } + + list.add(title: "纯文字") { section in + section.add(title: "只有一句话") { + Alert(.message("只有一句话").duration(2)).push() + } + section.add(title: "标题 + 正文") { + let title = "这是标题" + let message = "这是正文,文字支持自动换行,可设置最小宽度和最大宽度。这个弹窗将会持续4秒。" + Alert { alert in + alert.vm = .text(title: title, message: message) + alert.vm.duration = 4 + } + } + } + + list.add(title: "图文弹窗") { section in + section.add(title: "纯图标") { + Alert(.loading(3)).push() + } + section.add(title: "图标 + 文字") { + Alert(.loading(4).message("正在加载")) { alert in + alert.update(progress: 0) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { + alert.update(progress: 0.01) + } + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + alert.update(progress: 0.33) + } + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + alert.update(progress: 0.67) + } + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + alert.update(progress: 1) + } + } + } + section.add(title: "图标 + 标题 + 正文") { + Alert(.error) { alert in + alert.vm.title = "加载失败" + alert.vm.message = "请稍后重试" + alert.vm.duration = 3 + } + } + } + list.add(title: "文字 + 按钮") { section in + section.add(title: "只有一段文字 + 按钮") { + Alert { alert in + alert.vm.title = "只有一段文字" + alert.add(action: "取消", style: .gray) + alert.add(action: "默认按钮") + } + } + section.add(title: "标题 + 正文 + 按钮") { + Alert { alert in + alert.vm.title = "标题" + alert.vm.message = "这是一段正文,长度超出最大宽度时会自动换行" + alert.add(action: "取消", style: .gray) + alert.add(action: "删除", style: .destructive) { alert in + // 自定义了按钮事件之后,需要手动pop弹窗 + alert.pop() + } + } + } + } + list.add(title: "图标 + 文字 + 按钮") { section in + section.add(title: "图标 + 一段文字 + 自定义浅色按钮") { + Alert(.confirm) { alert in + alert.vm.title = "自定义浅色按钮" + alert.add(action: "红色", style: .light(color: .systemRed)) + alert.add(action: "蓝色", style: .light(color: .systemBlue)) + } + } + section.add(title: "图标 + 标题 + 正文 + 自定义深色按钮") { + Alert(.note) { alert in + alert.vm.title = "自定义深色按钮" + alert.vm.message = "这是一段正文,长度超出最大宽度时会自动换行" + alert.add(action: "橙色", style: .filled(color: .systemOrange)) + alert.add(action: "粉色", style: .filled(color: .systemPink)) + alert.add(action: "默认灰色", style: .gray) + } + } + } + list.add(title: "控件动态管理") { section in + section.add(title: "按钮增删") { + Alert(.note) { alert in + alert.vm.message = "可以动态增加、删除按钮" + alert.add(action: "在底部增加按钮", style: .filled(color: .systemGreen)) { alert in + alert.add(action: "哈哈1", identifier: "haha1") + } + alert.add(action: "在当前按钮下方增加", style: .filled(color: .systemIndigo), identifier: "add") { alert in + alert.insert(action: .init(identifier: "haha2", style: .light(color: .systemOrange), title: "哈哈2", handler: nil), after: "add") + } + alert.add(action: "修改当前按钮文字", identifier: "edit") { alert in + alert.update(action: "已修改", for: "edit") + } + alert.add(action: "删除「哈哈1」", style: .destructive) { alert in + alert.remove(actions: .identifiers("haha1")) + } + alert.add(action: "删除「哈哈1」和「哈哈2」", style: .destructive) { alert in + alert.remove(actions: .identifiers("haha1", "haha2")) + } + alert.add(action: "删除全部按钮", style: .destructive) { alert in + alert.remove(actions: .all) + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + alert.pop() + } + } + alert.add(action: "取消", style: .gray) + } + } + section.add(title: "更新文字") { + Alert(.note) { alert in + alert.vm.message = "可以动态增加、删除、更新文字" + alert.add(action: "增加标题") { alert in + alert.vm.title = "这是标题" + alert.reloadTextStack() + } + alert.add(action: "增加正文") { alert in + alert.vm.message = "可以动态增加、删除、更新文字" + alert.reloadTextStack() + } + alert.add(action: "删除标题", style: .destructive) { alert in + alert.vm.title = nil + alert.reloadTextStack() + } + alert.add(action: "删除正文", style: .destructive) { alert in + alert.vm.message = nil + alert.reloadTextStack() + } + alert.add(action: "取消", style: .gray) + } + } + section.add(title: "在弹出过程中增加元素") { + Alert(.loading) { alert in + alert.vm.title = "在弹出过程中增加元素" + alert.add(action: "OK", style: .gray) + alert.config.actionAxis = .vertical + } .onViewWillAppear { vc in + guard let alert = vc as? Alert else { + return + } + alert.vm.message = "这是一段后增加的文字\n动画效果会有细微差别" + alert.reloadTextStack() + } + } + } + list.add(title: "多实例管理") { section in + section.add(title: "多层级弹窗") { + func f(i: Int) { + Alert { alert in + alert.vm.title = "第\(i)次弹" + alert.vm.message = "每次都是一个新的实例覆盖在上一个弹窗上面,而背景不会叠加变深。" + alert.add(action: "取消", style: .gray) + alert.add(action: "增加一个") { alert in + f(i: i + 1) + } + } + } + f(i: 1) + } + section.add(title: "弹出loading,如果有就不重复弹") { + func f(i: Int) { + Alert.lazyPush(identifier: "haha") { alert in + if i < 2 { + alert.vm = .loading.title("第\(i)次弹") + let btn = alert.add(action: "请稍等", identifier: "btn") + btn.isEnabled = false + } else { + alert.update(progress: 1) + alert.vm = .success.title("第\(i)次弹").message("只更新内容") + alert.reloadTextStack() + alert.update(action: "完成", style: .filled(color: .systemGreen), for: "btn") + alert.button(for: "btn")?.isEnabled = true + } + } + } + f(i: 1) + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + f(i: 2) + } + } + } + list.add(title: "放在特定页面") { [weak self] section in + section.add(title: "放在特定页面") { + let vc = UIViewController() + vc.title = "页面" + vc.view.backgroundColor = .systemYellow + let alert = Alert(.loading.title("正在加载").message("这个弹窗被放在指定的容器中")) + alert.config.enableShadow = false + self?.present(vc, animated: true) + vc.view.addSubview(alert.view) + alert.view.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + } + } + list.add(title: "自定义视图") { section in + section.add(title: "自定义控件") { + Alert { alert in + alert.vm.title = "自定义控件" + // 图片 + let imgv = UIImageView(image: UIImage(named: "landscape")) + imgv.contentMode = .scaleAspectFill + imgv.clipsToBounds = true + imgv.layer.cornerRadiusWithContinuous = 12 + alert.add(subview: imgv).snp.makeConstraints { make in + make.height.equalTo(120) + } + // seg + let seg = UISegmentedControl(items: ["开发", "测试", "预发", "生产"]) + seg.selectedSegmentIndex = 0 + alert.add(subview: seg).snp.makeConstraints { make in + make.height.equalTo(40) + make.width.equalTo(400) + } + // slider + let slider = UISlider() + slider.minimumValue = 0 + slider.maximumValue = 100 + slider.value = 50 + alert.add(subview: slider) + alert.add(spacing: 24) + alert.add(action: "取消", style: .gray) + } + } + + section.add(title: "圆角半径") { + Alert { alert in + alert.title = "圆角半径" + let s1 = UISlider() + s1.minimumValue = 0 + s1.maximumValue = 40 + s1.value = Float(alert.config.cardCornerRadius ?? 16) + alert.add(subview: s1).snp.makeConstraints { make in + make.height.equalTo(50) + } + if #available(iOS 14.0, *) { + s1.addAction(.init(handler: { [unowned s1] act in + alert.config.cardCornerRadius = CGFloat(s1.value) + alert.contentView.layer.cornerRadiusWithContinuous = alert.config.cardCornerRadius ?? 16 + }), for: .valueChanged) + } else { + // Fallback on earlier versions + } + alert.config.actionAxis = .vertical + alert.add(spacing: 24) + alert.add(action: "OK", style: .gray) + } + } + + section.add(title: "完全自定义容器") { + Alert { alert in + alert.identifier = "custom" + alert.contentView.backgroundColor = .systemYellow + alert.view.addSubview(alert.contentView) + alert.contentView.layer.cornerRadiusWithContinuous = 32 + alert.contentView.snp.makeConstraints { make in + make.width.equalTo(UIScreen.main.bounds.width - 100) + make.height.equalTo(UIScreen.main.bounds.height - 200) + make.center.equalToSuperview() + } + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + alert.pop() + } + } + } + } + } + +} diff --git a/Example-Xcode11/Example-Xcode11/AppDelegate.swift b/PHDemo/PHDemo/AppDelegate.swift similarity index 82% rename from Example-Xcode11/Example-Xcode11/AppDelegate.swift rename to PHDemo/PHDemo/AppDelegate.swift index 57e1501..993afbe 100644 --- a/Example-Xcode11/Example-Xcode11/AppDelegate.swift +++ b/PHDemo/PHDemo/AppDelegate.swift @@ -1,26 +1,17 @@ // // AppDelegate.swift -// Example-Xcode11 +// PHDemo // -// Created by xaoxuu on 2020/6/15. -// Copyright © 2020 xaoxuu. All rights reserved. +// Created by xaoxuu on 2022/8/29. // import UIKit -@_exported import ProHUD -typealias ProAlert = ProHUD.Alert -typealias ProToast = ProHUD.Toast -typealias ProGuard = ProHUD.Guard - -@UIApplicationMain +@main class AppDelegate: UIResponder, UIApplicationDelegate { - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. - return true } diff --git a/PHDemo/PHDemo/Assets.xcassets/AccentColor.colorset/Contents.json b/PHDemo/PHDemo/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..9b711cb --- /dev/null +++ b/PHDemo/PHDemo/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,15 @@ +{ + "colors" : [ + { + "color" : { + "platform" : "ios", + "reference" : "systemBlueColor" + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Contents.json b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Contents.json rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-76.png b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-76.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-76.png rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-76.png diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Notification.png b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Notification.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Notification.png rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Notification.png diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Notification@2x.png b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Notification@2x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Notification@2x.png rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Notification@2x.png diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Notification@3x.png b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Notification@3x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Notification@3x.png rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Notification@3x.png diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Small.png b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Small.png rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small.png diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png diff --git a/Example-Old/Example/Assets.xcassets/AppIcon.appiconset/icon.png b/PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/icon.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/AppIcon.appiconset/icon.png rename to PHDemo/PHDemo/Assets.xcassets/AppIcon.appiconset/icon.png diff --git a/Example-Old/Example/Assets.xcassets/Contents.json b/PHDemo/PHDemo/Assets.xcassets/Contents.json similarity index 100% rename from Example-Old/Example/Assets.xcassets/Contents.json rename to PHDemo/PHDemo/Assets.xcassets/Contents.json diff --git a/Example-Old/Example/Assets.xcassets/Feel1.imageset/Contents.json b/PHDemo/PHDemo/Assets.xcassets/Feel1.imageset/Contents.json similarity index 100% rename from Example-Old/Example/Assets.xcassets/Feel1.imageset/Contents.json rename to PHDemo/PHDemo/Assets.xcassets/Feel1.imageset/Contents.json diff --git a/Example-Old/Example/Assets.xcassets/Feel1.imageset/Feel1@2x.png b/PHDemo/PHDemo/Assets.xcassets/Feel1.imageset/Feel1@2x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/Feel1.imageset/Feel1@2x.png rename to PHDemo/PHDemo/Assets.xcassets/Feel1.imageset/Feel1@2x.png diff --git a/Example-Old/Example/Assets.xcassets/Feel1.imageset/Feel1@3x.png b/PHDemo/PHDemo/Assets.xcassets/Feel1.imageset/Feel1@3x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/Feel1.imageset/Feel1@3x.png rename to PHDemo/PHDemo/Assets.xcassets/Feel1.imageset/Feel1@3x.png diff --git a/Example-Old/Example/Assets.xcassets/alert.buy.imageset/Contents.json b/PHDemo/PHDemo/Assets.xcassets/alert.buy.imageset/Contents.json similarity index 100% rename from Example-Old/Example/Assets.xcassets/alert.buy.imageset/Contents.json rename to PHDemo/PHDemo/Assets.xcassets/alert.buy.imageset/Contents.json diff --git a/Example-Old/Example/Assets.xcassets/alert.buy.imageset/ProHUDBuy@2x.png b/PHDemo/PHDemo/Assets.xcassets/alert.buy.imageset/ProHUDBuy@2x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/alert.buy.imageset/ProHUDBuy@2x.png rename to PHDemo/PHDemo/Assets.xcassets/alert.buy.imageset/ProHUDBuy@2x.png diff --git a/Example-Old/Example/Assets.xcassets/alert.buy.imageset/ProHUDBuy@3x.png b/PHDemo/PHDemo/Assets.xcassets/alert.buy.imageset/ProHUDBuy@3x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/alert.buy.imageset/ProHUDBuy@3x.png rename to PHDemo/PHDemo/Assets.xcassets/alert.buy.imageset/ProHUDBuy@3x.png diff --git a/PHDemo/PHDemo/Assets.xcassets/avatar.imageset/Contents.json b/PHDemo/PHDemo/Assets.xcassets/avatar.imageset/Contents.json new file mode 100644 index 0000000..5ab63d7 --- /dev/null +++ b/PHDemo/PHDemo/Assets.xcassets/avatar.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "avatar@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "avatar@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/PHDemo/PHDemo/Assets.xcassets/avatar.imageset/avatar@2x.png b/PHDemo/PHDemo/Assets.xcassets/avatar.imageset/avatar@2x.png new file mode 100644 index 0000000..329f94f Binary files /dev/null and b/PHDemo/PHDemo/Assets.xcassets/avatar.imageset/avatar@2x.png differ diff --git a/PHDemo/PHDemo/Assets.xcassets/avatar.imageset/avatar@3x.png b/PHDemo/PHDemo/Assets.xcassets/avatar.imageset/avatar@3x.png new file mode 100644 index 0000000..95103bb Binary files /dev/null and b/PHDemo/PHDemo/Assets.xcassets/avatar.imageset/avatar@3x.png differ diff --git a/Example-Old/Example/Assets.xcassets/icloud.and.arrow.down.imageset/Contents.json b/PHDemo/PHDemo/Assets.xcassets/icloud.and.arrow.down.imageset/Contents.json similarity index 100% rename from Example-Old/Example/Assets.xcassets/icloud.and.arrow.down.imageset/Contents.json rename to PHDemo/PHDemo/Assets.xcassets/icloud.and.arrow.down.imageset/Contents.json diff --git a/Example-Old/Example/Assets.xcassets/icloud.and.arrow.down.imageset/cloud download (2).png b/PHDemo/PHDemo/Assets.xcassets/icloud.and.arrow.down.imageset/cloud download (2).png similarity index 100% rename from Example-Old/Example/Assets.xcassets/icloud.and.arrow.down.imageset/cloud download (2).png rename to PHDemo/PHDemo/Assets.xcassets/icloud.and.arrow.down.imageset/cloud download (2).png diff --git a/Example-Old/Example/Assets.xcassets/icloud.and.arrow.down.imageset/cloud download (3).png b/PHDemo/PHDemo/Assets.xcassets/icloud.and.arrow.down.imageset/cloud download (3).png similarity index 100% rename from Example-Old/Example/Assets.xcassets/icloud.and.arrow.down.imageset/cloud download (3).png rename to PHDemo/PHDemo/Assets.xcassets/icloud.and.arrow.down.imageset/cloud download (3).png diff --git a/PHDemo/PHDemo/Assets.xcassets/landscape.imageset/Contents.json b/PHDemo/PHDemo/Assets.xcassets/landscape.imageset/Contents.json new file mode 100644 index 0000000..a4513cb --- /dev/null +++ b/PHDemo/PHDemo/Assets.xcassets/landscape.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "F462262A-3B98-4677-A4F2-75827167E067_1_105_c.jpeg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/PHDemo/PHDemo/Assets.xcassets/landscape.imageset/F462262A-3B98-4677-A4F2-75827167E067_1_105_c.jpeg b/PHDemo/PHDemo/Assets.xcassets/landscape.imageset/F462262A-3B98-4677-A4F2-75827167E067_1_105_c.jpeg new file mode 100644 index 0000000..c2c8440 Binary files /dev/null and b/PHDemo/PHDemo/Assets.xcassets/landscape.imageset/F462262A-3B98-4677-A4F2-75827167E067_1_105_c.jpeg differ diff --git a/Example-Old/Example/Assets.xcassets/prohud.rainbow.circle.imageset/Contents.json b/PHDemo/PHDemo/Assets.xcassets/prohud.rainbow.circle.imageset/Contents.json similarity index 100% rename from Example-Old/Example/Assets.xcassets/prohud.rainbow.circle.imageset/Contents.json rename to PHDemo/PHDemo/Assets.xcassets/prohud.rainbow.circle.imageset/Contents.json diff --git a/Example-Old/Example/Assets.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@2x.png b/PHDemo/PHDemo/Assets.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@2x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@2x.png rename to PHDemo/PHDemo/Assets.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@2x.png diff --git a/Example-Old/Example/Assets.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@3x.png b/PHDemo/PHDemo/Assets.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@3x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@3x.png rename to PHDemo/PHDemo/Assets.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@3x.png diff --git a/Example-Old/Example/Assets.xcassets/prohud.trash.imageset/Contents.json b/PHDemo/PHDemo/Assets.xcassets/prohud.trash.imageset/Contents.json similarity index 100% rename from Example-Old/Example/Assets.xcassets/prohud.trash.imageset/Contents.json rename to PHDemo/PHDemo/Assets.xcassets/prohud.trash.imageset/Contents.json diff --git a/Example-Old/Example/Assets.xcassets/prohud.trash.imageset/prohud.trash@2x.png b/PHDemo/PHDemo/Assets.xcassets/prohud.trash.imageset/prohud.trash@2x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/prohud.trash.imageset/prohud.trash@2x.png rename to PHDemo/PHDemo/Assets.xcassets/prohud.trash.imageset/prohud.trash@2x.png diff --git a/Example-Old/Example/Assets.xcassets/prohud.trash.imageset/prohud.trash@3x.png b/PHDemo/PHDemo/Assets.xcassets/prohud.trash.imageset/prohud.trash@3x.png similarity index 100% rename from Example-Old/Example/Assets.xcassets/prohud.trash.imageset/prohud.trash@3x.png rename to PHDemo/PHDemo/Assets.xcassets/prohud.trash.imageset/prohud.trash@3x.png diff --git a/Example-Xcode11/Example-Xcode11/Base.lproj/LaunchScreen.storyboard b/PHDemo/PHDemo/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from Example-Xcode11/Example-Xcode11/Base.lproj/LaunchScreen.storyboard rename to PHDemo/PHDemo/Base.lproj/LaunchScreen.storyboard diff --git a/PHDemo/PHDemo/Base.lproj/Main.storyboard b/PHDemo/PHDemo/Base.lproj/Main.storyboard new file mode 100644 index 0000000..0dea159 --- /dev/null +++ b/PHDemo/PHDemo/Base.lproj/Main.storyboard @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PHDemo/PHDemo/Info.plist b/PHDemo/PHDemo/Info.plist new file mode 100644 index 0000000..dd3c9af --- /dev/null +++ b/PHDemo/PHDemo/Info.plist @@ -0,0 +1,25 @@ + + + + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + + diff --git a/PHDemo/PHDemo/ListModel.swift b/PHDemo/PHDemo/ListModel.swift new file mode 100644 index 0000000..ef7b486 --- /dev/null +++ b/PHDemo/PHDemo/ListModel.swift @@ -0,0 +1,33 @@ +// +// ListModel.swift +// PHDemo +// +// Created by xaoxuu on 2022/9/3. +// + +import UIKit + +struct Row { + var title: String + var action: () -> Void +} + +struct Section { + var title: String + var rows = [Row]() + mutating func add(title: String, action: @escaping () -> Void) { + rows.append(.init(title: title, action: action)) + } +} + +struct ListModel { + + var sections = [Section]() + + mutating func add(title: String, rows: (_ section: inout Section) -> Void) { + var sec = Section(title: title) + rows(&sec) + sections.append(sec) + } + +} diff --git a/PHDemo/PHDemo/ListVC.swift b/PHDemo/PHDemo/ListVC.swift new file mode 100644 index 0000000..5b199d7 --- /dev/null +++ b/PHDemo/PHDemo/ListVC.swift @@ -0,0 +1,53 @@ +// +// ListVC.swift +// PHDemo +// +// Created by xaoxuu on 2022/9/3. +// + +import UIKit + +class ListVC: UITableViewController { + + var list = ListModel() + + lazy var header: TableHeaderView = TableHeaderView(text: "ProHUD") + + override func viewDidLoad() { + super.viewDidLoad() + + tableView.tableHeaderView = header + tableView.sectionHeaderHeight = 32 + tableView.sectionFooterHeight = 8 + + } + + + override func numberOfSections(in tableView: UITableView) -> Int { + // #warning Incomplete implementation, return the number of sections + list.sections.count + } + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + // #warning Incomplete implementation, return the number of rows + list.sections[section].rows.count + } + + override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + list.sections[section].title + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath) + cell.textLabel?.text = list.sections[indexPath.section].rows[indexPath.row].title + return cell + } + + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + list.sections[indexPath.section].rows[indexPath.row].action() + } + + +} diff --git a/Example-Xcode11/Example-Xcode11/SceneDelegate.swift b/PHDemo/PHDemo/SceneDelegate.swift similarity index 61% rename from Example-Xcode11/Example-Xcode11/SceneDelegate.swift rename to PHDemo/PHDemo/SceneDelegate.swift index a170a6c..e6191ec 100644 --- a/Example-Xcode11/Example-Xcode11/SceneDelegate.swift +++ b/PHDemo/PHDemo/SceneDelegate.swift @@ -1,9 +1,8 @@ // // SceneDelegate.swift -// Example-Xcode11 +// PHDemo // -// Created by xaoxuu on 2020/6/15. -// Copyright © 2020 xaoxuu. All rights reserved. +// Created by xaoxuu on 2022/8/29. // import UIKit @@ -17,46 +16,14 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). - guard let scene = (scene as? UIWindowScene) else { return } - - print(scene.statusBarManager?.statusBarFrame) - let rootVC = RootVC() - window?.rootViewController = rootVC - window?.makeKeyAndVisible() - print("root window \(window!)") - ProHUD.config { (cfg) in -// cfg.rootViewController = rootVC -// cfg.windowScene = scene - cfg.alert { (a) in - a.titleFont = .bold(22) - a.bodyFont = .regular(17) - a.boldTextFont = .bold(18) - a.buttonFont = .bold(18) - a.forceQuitTimer = 3 - } - cfg.toast { (t) in - t.titleFont = .bold(18) - t.bodyFont = .regular(16) - } - cfg.guard { (g) in - g.titleFont = .bold(22) - g.subTitleFont = .bold(20) - g.bodyFont = .regular(17) - g.buttonFont = .bold(18) - } - } - - let window = UIWindow() - window.makeKeyAndVisible() - window.resignKey() - + guard let _ = (scene as? UIWindowScene) else { return } } func sceneDidDisconnect(_ scene: UIScene) { // Called as the scene is being released by the system. // This occurs shortly after the scene enters the background, or when its session is discarded. // Release any resources associated with this scene that can be re-created the next time the scene connects. - // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). } func sceneDidBecomeActive(_ scene: UIScene) { diff --git a/PHDemo/PHDemo/Scenes.swift b/PHDemo/PHDemo/Scenes.swift new file mode 100644 index 0000000..eac7ca0 --- /dev/null +++ b/PHDemo/PHDemo/Scenes.swift @@ -0,0 +1,34 @@ +// +// File.swift +// PHDemo +// +// Created by xaoxuu on 2022/9/9. +// + +import UIKit +import ProHUD + +public extension ViewModel { +// static var plain: ViewModel { +// ViewModel() +// } +// static var note: ViewModel { +// ViewModel(icon: UIImage(named: "prohud.note")) +// } + static var msg: ViewModel { + ViewModel(icon: UIImage(inProHUD: "prohud.message")) + } + static func msg(_ seconds: TimeInterval) -> ViewModel { + ViewModel(icon: UIImage(inProHUD: "prohud.message"), duration: seconds) + } + static var loading: ViewModel { + let obj = ViewModel(icon: UIImage(named: "prohud.rainbow.circle")) + obj.rotation = .init(repeatCount: .infinity) + return obj + } +// static func loading(_ seconds: TimeInterval) -> ViewModel { +// let obj = ViewModel(icon: UIImage(named: "prohud.rainbow.circle"), duration: seconds) +// obj.rotation = .init(repeatCount: .infinity) +// return obj +// } +} diff --git a/PHDemo/PHDemo/SheetVC.swift b/PHDemo/PHDemo/SheetVC.swift new file mode 100644 index 0000000..66a6b20 --- /dev/null +++ b/PHDemo/PHDemo/SheetVC.swift @@ -0,0 +1,214 @@ +// +// SheetVC.swift +// PHDemo +// +// Created by xaoxuu on 2022/9/3. +// + +import UIKit +import ProHUD + +class SheetVC: ListVC { + + override func viewDidLoad() { + super.viewDidLoad() + + header.titleLabel.text = "ProHUD.Sheet" + header.detailLabel.text = "操作表控件,用于弱阻塞性交互。显示区域为从屏幕底部向上弹出的新图层,可以放置丰富的内容,自由度较高。" + + list.add(title: "默认布局") { section in + section.add(title: "标题 + 正文 + 按钮") { + Sheet { sheet in + sheet.add(title: "ProHUD") + sheet.add(subTitle: "什么是操作表控件") + sheet.add(message: "操作表控件,用于弱阻塞性交互。显示区域为从屏幕底部向上弹出的新图层,可以放置丰富的内容,自由度较高。") + sheet.add(spacing: 24) + sheet.add(action: "确认", style: .destructive) { sheet in + Alert(.confirm) { alert in + alert.vm.title = "处理点击事件" + alert.add(action: "我知道了") + } + } + sheet.add(action: "取消", style: .gray) + } + } + section.add(title: "放置自定义控件") { + Sheet { sheet in + sheet.add(title: "ProHUD") + // 图片 + let imgv = UIImageView(image: UIImage(named: "landscape")) + imgv.contentMode = .scaleAspectFill + imgv.clipsToBounds = true + imgv.layer.cornerRadiusWithContinuous = 16 + sheet.add(subview: imgv).snp.makeConstraints { make in + make.height.equalTo(200) + } + // seg + let seg = UISegmentedControl(items: ["开发", "测试", "预发", "生产"]) + seg.selectedSegmentIndex = 0 + sheet.add(subview: seg).snp.makeConstraints { make in + make.height.equalTo(40) + make.width.equalTo(400) + } + // slider + let slider = UISlider() + slider.minimumValue = 0 + slider.maximumValue = 100 + slider.value = 50 + sheet.add(subview: slider).snp.makeConstraints { make in + make.height.equalTo(50) + } + + sheet.add(spacing: 50) + } + } + + section.add(title: "全屏") { + Sheet { sheet in + sheet.config.isFullScreen = true + sheet.add(title: "ProHUD") + sheet.add(action: "OK") + } + } + + } + + list.add(title: "事件管理") { section in + section.add(title: "拦截返回事件") { + Sheet { sheet in + sheet.add(title: "ProHUD") + sheet.add(message: "点击背景将不会dismiss,必须在下方做出选择才能关掉") + sheet.add(spacing: 24) + sheet.add(action: "确认") + sheet.add(action: "取消", style: .gray) + } onTappedBackground: { sheet in + print("点击了背景") + Toast.lazyPush(identifier: "alert") { toast in + toast.vm = .note + toast.vm.title = "点击了背景" + toast.vm.message = "点击背景将不会dismiss,必须在下方做出选择才能关掉" + toast.vm.duration = 2 + } + + } + } + } + + list.add(title: "自定义样式") { section in + section.add(title: "圆角半径 & 屏幕边距") { + Sheet { sheet in + sheet.add(title: "圆角半径 & 屏幕边距") + + sheet.add(subTitle: "圆角半径") + let s1 = UISlider() + s1.minimumValue = 0 + s1.maximumValue = 40 + s1.value = Float(sheet.config.cardCornerRadius ?? 40) + sheet.add(subview: s1).snp.makeConstraints { make in + make.height.equalTo(50) + } + if #available(iOS 14.0, *) { + s1.addAction(.init(handler: { [unowned s1] act in + sheet.config.cardCornerRadius = CGFloat(s1.value) + sheet.contentView.layer.cornerRadiusWithContinuous = sheet.config.cardCornerRadius ?? 40 + }), for: .valueChanged) + } else { + // Fallback on earlier versions + } + + sheet.add(subTitle: "屏幕边距") + let s2 = UISlider() + s2.minimumValue = 0 + s2.maximumValue = 40 + s2.value = Float(sheet.config.edgeInset) + sheet.add(subview: s2).snp.makeConstraints { make in + make.height.equalTo(50) + } + if #available(iOS 14.0, *) { + s2.addAction(.init(handler: { [unowned s2] act in + sheet.config.edgeInset = CGFloat(s2.value) + sheet.reloadData() + }), for: .valueChanged) + } else { + // Fallback on earlier versions + } + + sheet.add(spacing: 24) + sheet.add(action: "OK", style: .gray) + } + } + + section.add(title: "卡片背景样式") { + Sheet { sheet in + sheet.title = "卡片背景样式" + sheet.add(action: "白色") { sheet in + sheet.contentMaskView.backgroundColor = .white + sheet.contentMaskView.effect = .none + } + sheet.add(action: "橙色") { sheet in + sheet.contentMaskView.backgroundColor = .systemOrange + sheet.contentMaskView.effect = .none + } + sheet.add(action: "毛玻璃 light") { sheet in + sheet.contentMaskView.backgroundColor = .clear + sheet.contentMaskView.effect = UIBlurEffect(style: .light) + } + sheet.add(action: "毛玻璃 dark") { sheet in + sheet.contentMaskView.backgroundColor = .clear + sheet.contentMaskView.effect = UIBlurEffect(style: .dark) + } + } + } + + + section.add(title: "自定义卡片背景") { + Sheet { sheet in + sheet.add(title: "ProHUD") + sheet.add(spacing: 24) + sheet.add(action: "OK") + sheet.config.contentViewMask { mask in + mask.effect = .none + mask.backgroundColor = .clear + } + } .onViewWillAppear { vc in + guard let sheet = vc as? Sheet else { return } + let imgv = UIImageView(image: UIImage(named: "landscape")) + imgv.contentMode = .scaleAspectFill + imgv.clipsToBounds = true + imgv.layer.cornerRadiusWithContinuous = 16 + sheet.contentView.insertSubview(imgv, at: 0) + imgv.snp.makeConstraints { make in + make.edges.equalToSuperview() + make.height.equalTo(300) + } + } + } + + + section.add(title: "透明背景") { + Sheet { sheet in + sheet.backgroundView.backgroundColor = .clear + sheet.add(title: "ProHUD") + sheet.add(spacing: 24) + sheet.add(action: "OK") + } + } + + section.add(title: "自定义布局") { + Sheet { sheet in + let imgv = UIImageView(image: UIImage(named: "landscape")) + imgv.contentMode = .scaleAspectFill + imgv.clipsToBounds = true + imgv.layer.cornerRadiusWithContinuous = 16 + sheet.set(customView: imgv).snp.makeConstraints { make in + make.edges.equalToSuperview() + make.height.equalTo(300) + } + } + } + } + + } + +} + diff --git a/PHDemo/PHDemo/TableHeaderView.swift b/PHDemo/PHDemo/TableHeaderView.swift new file mode 100644 index 0000000..8d1e482 --- /dev/null +++ b/PHDemo/PHDemo/TableHeaderView.swift @@ -0,0 +1,55 @@ +// +// TableHeaderView.swift +// PHDemo +// +// Created by xaoxuu on 2022/9/5. +// + +import UIKit + +class TableHeaderView: UIView { + + lazy var titleLabel: UILabel = { + let lb = UILabel(frame: .init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 80)) + lb.font = .systemFont(ofSize: 32, weight: .black) + lb.textAlignment = .center + lb.text = "ProHUD" + return lb + }() + + lazy var detailLabel: UILabel = { + let lb = UILabel(frame: .init(x: 0, y: 80, width: UIScreen.main.bounds.width, height: 120)) + lb.font = .systemFont(ofSize: 15, weight: .regular) + lb.textAlignment = .justified + lb.numberOfLines = 0 + lb.text = "ProHUD" + return lb + }() + + convenience init(text: String) { + self.init(frame: .init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 150)) + titleLabel.text = text + } + + override init(frame: CGRect) { + super.init(frame: frame) + + addSubview(detailLabel) + addSubview(titleLabel) + titleLabel.snp.makeConstraints { make in + make.left.right.equalToSuperview().inset(24) + make.top.equalToSuperview().offset(20) + } + detailLabel.snp.makeConstraints { make in + make.left.right.equalTo(titleLabel) + make.top.equalTo(titleLabel.snp.bottom).offset(12) + } + + } + + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} diff --git a/PHDemo/PHDemo/ToastVC.swift b/PHDemo/PHDemo/ToastVC.swift new file mode 100644 index 0000000..d3dcffc --- /dev/null +++ b/PHDemo/PHDemo/ToastVC.swift @@ -0,0 +1,224 @@ +// +// ToastVC.swift +// PHDemo +// +// Created by xaoxuu on 2022/9/3. +// + +import UIKit +import ProHUD + +class ToastVC: ListVC { + + override func viewDidLoad() { + super.viewDidLoad() + + let title = "通知条控件" + let message = "通知条控件,用于非阻塞性事件通知。显示效果如同原生通知,默认会自动消失,可以支持手势移除,有多条通知可以平铺并列显示。" + header.titleLabel.text = "ProHUD.Toast" + header.detailLabel.text = message + + list.add(title: "默认布局") { section in + section.add(title: "标题 + 正文") { + Toast(.title(title).message(message)).push() + } + section.add(title: "一段长文本") { + Toast(.message(message)).push() + } + section.add(title: "图标 + 标题 + 正文") { + let s1 = "正在加载" + let s2 = "这条通知4s后消失" + let toast = Toast(.loading(4).title(s1).message(s2)) + toast.identifier = "loading" + toast.push() + toast.update(progress: 0) + DispatchQueue.main.asyncAfter(deadline: .now() + 1) { + toast.update(progress: 0.5) + } + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + toast.update(progress: 1) + } + DispatchQueue.main.asyncAfter(deadline: .now() + 2.5) { + Toast.update(identifier: "loading") { toast in + toast.vm = .success(2).title("加载成功").message("这条通知2s后消失") + } + } + } + section.add(title: "图标 + 一段长文本") { + Toast(.note.message(message)).push() + } + } + + list.add(title: "事件管理") { section in + section.add(title: "全局点击事件") { + let title = "您收到了一条消息" + let message = "这条消息5s后消失,点击回复" + Toast(.msg(5).title(title).message(message)) { toast in + toast.onTapped { toast in + toast.pop() + testAlert() + } + } + } + section.add(title: "增加按钮") { + let title = "您收到了一条好友申请" + let message = "丹妮莉丝·坦格利安申请添加您为好友,是否同意?" + Toast(.title(title).message(message)) { toast in + toast.isRemovable = false + toast.vm.icon = UIImage(named: "avatar") + toast.imageView.layer.masksToBounds = true + toast.imageView.layer.cornerRadius = toast.config.iconSize.width / 2 + toast.add(action: "拒绝", style: .destructive) { toast in + Alert.lazyPush(identifier: "Dracarys") { alert in + alert.vm = .message("Dracarys") + alert.vm.icon = UIImage(inProHUD: "prohud.windmill") + alert.vm.rotation = .init(repeatCount: .infinity) + alert.config.enableShadow = false + alert.config.contentViewMask { mask in + mask.effect = .none + mask.backgroundColor = .clear + } + alert.config.backgroundViewMask { mask in + mask.backgroundColor = .systemRed + } + alert.config.iconSize = .init(width: 64, height: 64) + alert.config.boldTextFont = .init(name: "Papyrus", size: 40) + alert.config.dynamicTextColor = .white + } + } + toast.add(action: "同意") { toast in + Alert.find(identifier: "Dracarys")?.pop() + toast.pop() + } + } + } + + section.add(title: "禁止手势移除") { + let title = "这条消息很重要" + let message = "向上滑动将不会移除消息,您必须手动处理,用于重要但非阻塞性的事件。(通过代码处理或者在点击事件处理)" + Toast(.warning.title(title).message(message)) { toast in + toast.isRemovable = false + toast.onTapped { toast in + toast.pop() + testAlert() + } + } + } + } + + list.add(title: "自定义视图") { section in + section.add(title: "图片") { + Toast { toast in + toast.config.cardMaxHeight = 200 // 自定义视图时需手动指定高度 + let imgv = UIImageView(image: UIImage(named: "landscape")) + imgv.contentMode = .scaleAspectFill + toast.add(customView: imgv).snp.makeConstraints { make in + make.edges.equalToSuperview() + } + toast.onTapped { toast in + toast.pop() + } + } + } + + section.add(title: "其它控件") { + Toast { toast in + toast.config.cardMaxHeight = 200 // 自定义视图时需手动指定高度 + + let stack = UIStackView() + stack.axis = .vertical + stack.distribution = .fill + stack.spacing = 8 + stack.alignment = .fill + + let lb = UILabel() + lb.font = .systemFont(ofSize: 20, weight: .bold) + lb.text = "Custom Toast" + lb.textAlignment = .center + stack.addArrangedSubview(lb) + + let btn1 = ProHUD.Button(config: toast.config, action: .init(style: .gray, title: "取消")) + btn1.onTouchUpInside { action in + print("点击了取消") + testAlert() + } + let btn2 = ProHUD.Button(config: toast.config, action: .init(style: .tinted, title: "确定")) + btn2.onTouchUp { action in + print("点击了确定") + testAlert() + } + let actions = UIStackView(arrangedSubviews: [btn1, btn2]) + actions.axis = .horizontal + actions.distribution = .fillEqually + actions.spacing = 8 + actions.alignment = .fill + + stack.addArrangedSubview(actions) + actions.snp.makeConstraints { make in + make.height.equalTo(40) + } + + toast.add(customView: stack).snp.makeConstraints { make in + make.edges.equalToSuperview().inset(8) + } + toast.onTapped { toast in + toast.pop() + } + } + } + + section.add(title: "卡片背景样式") { + Toast { toast in + toast.vm.title = "卡片背景样式" + toast.add(action: "浅色毛玻璃") { toast in + toast.contentMaskView.effect = UIBlurEffect(style: .light) + toast.contentMaskView.backgroundColor = .clear + } + toast.add(action: "深色毛玻璃") { toast in + toast.contentMaskView.effect = UIBlurEffect(style: .dark) + toast.contentMaskView.backgroundColor = .clear + } + toast.add(action: "纯色") { toast in + toast.contentMaskView.effect = .none + toast.contentMaskView.backgroundColor = .red.lighten() + } + } + + } + + section.add(title: "共享配置") { + func foo() { + Toast { toast in + toast.title = "共享配置" + toast.vm.message = "建议在App启动后进行通用配置设置,所有实例都会先拉取通用配置为默认值,修改这些配置会影响到所有实例。" + toast.add(action: "默认", style: .gray) { toast in + Toast.Configuration.shared { config in + config.titleFont = .systemFont(ofSize: 19, weight: .bold) + } + toast.pop() + foo() + } + toast.add(action: "大号标题") { toast in + Toast.Configuration.shared { config in + config.titleFont = .systemFont(ofSize: 28, weight: .medium) + } + toast.pop() + foo() + } + } + } + foo() + } + + } + + } + +} + +fileprivate func testAlert() { + Alert { alert in + alert.vm.title = "处理点击事件" + alert.add(action: "我知道了", style: .destructive) + } +} diff --git a/Package.resolved b/Package.resolved index c107e87..f6ea884 100644 --- a/Package.resolved +++ b/Package.resolved @@ -6,8 +6,8 @@ "repositoryURL": "https://github.com/xaoxuu/Inspire.git", "state": { "branch": null, - "revision": "cad0c64e6995a06ee3bf3ed7c632ad27c1b8ffb1", - "version": "2.0.0" + "revision": "05bdbf23e380b7b283f9ef5c5115e1c1e1d1ad97", + "version": "2.2.0" } }, { @@ -15,8 +15,8 @@ "repositoryURL": "https://github.com/SnapKit/SnapKit.git", "state": { "branch": null, - "revision": "d458564516e5676af9c70b4f4b2a9178294f1bc6", - "version": "5.0.1" + "revision": "f222cbdf325885926566172f6f5f06af95473158", + "version": "5.6.0" } } ] diff --git a/Package.swift b/Package.swift index 4e71d83..6e629f1 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.6 import PackageDescription @@ -10,15 +10,13 @@ let package = Package( ], dependencies: [ .package(url: "https://github.com/SnapKit/SnapKit.git", "5.0.0" ..< "6.0.0"), - .package(url: "https://github.com/xaoxuu/Inspire.git", "2.1.0" ..< "3.0.0"), + .package(url: "https://github.com/xaoxuu/Inspire.git", "3.0.0" ..< "4.0.0"), ], targets: [ .target( name: "ProHUD", dependencies: ["SnapKit", "Inspire"], - path: "Source", - resources: [.process("ProHUD.xcassets")] + resources: [.process("Resources/ProHUD.xcassets")] ) - ], - swiftLanguageVersions: [.v5] + ] ) diff --git a/Podfile b/Podfile deleted file mode 100644 index bf17046..0000000 --- a/Podfile +++ /dev/null @@ -1,14 +0,0 @@ -platform :ios, '9.0' -use_frameworks! - -target 'ProHUD' do - -# pod 'SnapKit', '5.0.1' -# pod 'Inspire', '1.1.0' # :path => '../Inspire' - -end - - - -#pod install --verbose --no-repo-update #安装命令 -#pod update --verbose --no-repo-update #更新命令 diff --git a/Podfile.lock b/Podfile.lock deleted file mode 100644 index 3048d5b..0000000 --- a/Podfile.lock +++ /dev/null @@ -1,3 +0,0 @@ -PODFILE CHECKSUM: 6cebb4bc46375d38fc36a728dcb33f3b7ec0c396 - -COCOAPODS: 1.10.1 diff --git a/ProHUD.podspec b/ProHUD.podspec deleted file mode 100755 index fb3bbcc..0000000 --- a/ProHUD.podspec +++ /dev/null @@ -1,20 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'ProHUD' - s.version = "1.0" - s.license = 'MIT' - s.summary = '可完全定制化的HUD,包含顶部区域的Toast,中央区域的Alert和底部区域的ActionSheet。' - s.homepage = "http://xaoxuu.com" - s.authors = { 'xaoxuu' => 'xaoxuu@gmail.com' } - s.source = { :git => "https://github.com/xaoxuu/ProHUD.git", :tag => "#{s.version}", :submodules => false} - - s.ios.deployment_target = '10.0' - - s.source_files = 'Source/**/*.swift' - s.resource_bundles = { 'ProHUD' => ['Source/**/*.{xcassets,strings,xml,storyboard,xib,xcdatamodeld,gif,lproj}'] } - s.requires_arc = true - s.swift_version = '5.0' - - s.dependency 'SnapKit', '5.0' - s.dependency 'Inspire' - -end diff --git a/ProHUD.xcodeproj/project.pbxproj b/ProHUD.xcodeproj/project.pbxproj deleted file mode 100644 index 676381f..0000000 --- a/ProHUD.xcodeproj/project.pbxproj +++ /dev/null @@ -1,528 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 52; - objects = { - -/* Begin PBXBuildFile section */ - 36CB9DEED3C3E823FE7B1C75 /* Pods_ProHUD.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C2011798511AD590A613E54E /* Pods_ProHUD.framework */; }; - CD16490B22EF09AB0077988C /* AlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD16490A22EF09AB0077988C /* AlertModel.swift */; }; - CD16490D22EF09B40077988C /* AlertConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD16490C22EF09B40077988C /* AlertConfig.swift */; }; - CD16491222EF0D900077988C /* HUDView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD16491122EF0D900077988C /* HUDView.swift */; }; - CD16491422EF12220077988C /* ProHUD.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CD16491322EF12220077988C /* ProHUD.xcassets */; }; - CD6CD86C22F1858F00F4FD4A /* ToastModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD86B22F1858F00F4FD4A /* ToastModel.swift */; }; - CD6CD87022F185A700F4FD4A /* ToastController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD86F22F185A700F4FD4A /* ToastController.swift */; }; - CD6CD87222F185AF00F4FD4A /* ToastConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD87122F185AF00F4FD4A /* ToastConfig.swift */; }; - CD6CD87522F185C200F4FD4A /* GuardController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD87422F185C200F4FD4A /* GuardController.swift */; }; - CD6CD87922F185D000F4FD4A /* GuardConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD6CD87822F185D000F4FD4A /* GuardConfig.swift */; }; - CD95D22122E72C4C007559A3 /* ProHUD.h in Headers */ = {isa = PBXBuildFile; fileRef = CD95D21F22E72C4C007559A3 /* ProHUD.h */; settings = {ATTRIBUTES = (Public, ); }; }; - CD95D26922E72DA1007559A3 /* AlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD95D26822E72DA1007559A3 /* AlertController.swift */; }; - CD95D26B22E72DB3007559A3 /* ProHUD.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD95D26A22E72DB3007559A3 /* ProHUD.swift */; }; - CDB6A07B22EEF06500AF6CF0 /* HUDController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDB6A07A22EEF06500AF6CF0 /* HUDController.swift */; }; - CDB6A07D22EEF19D00AF6CF0 /* HUDConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDB6A07C22EEF19D00AF6CF0 /* HUDConfig.swift */; }; - CDC39CFD22FD6DDF0070E914 /* GuardModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDC39CFC22FD6DDF0070E914 /* GuardModel.swift */; }; - CDC67BE92490A19100CC6FE6 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = CDC67BE82490A19100CC6FE6 /* SnapKit */; }; - CDC67BEC2490A1D100CC6FE6 /* Inspire in Frameworks */ = {isa = PBXBuildFile; productRef = CDC67BEB2490A1D100CC6FE6 /* Inspire */; }; - CDF2C58924A0572C002ECDD5 /* HUDUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDF2C58824A0572C002ECDD5 /* HUDUtils.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 3C95FD2F17A45D13E2AB9306 /* Pods-ProHUD.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ProHUD.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ProHUD/Pods-ProHUD.debug.xcconfig"; sourceTree = ""; }; - C2011798511AD590A613E54E /* Pods_ProHUD.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ProHUD.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - CD16490A22EF09AB0077988C /* AlertModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertModel.swift; sourceTree = ""; }; - CD16490C22EF09B40077988C /* AlertConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertConfig.swift; sourceTree = ""; }; - CD16491122EF0D900077988C /* HUDView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HUDView.swift; sourceTree = ""; }; - CD16491322EF12220077988C /* ProHUD.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = ProHUD.xcassets; sourceTree = ""; }; - CD6CD86B22F1858F00F4FD4A /* ToastModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastModel.swift; sourceTree = ""; }; - CD6CD86F22F185A700F4FD4A /* ToastController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastController.swift; sourceTree = ""; }; - CD6CD87122F185AF00F4FD4A /* ToastConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastConfig.swift; sourceTree = ""; }; - CD6CD87422F185C200F4FD4A /* GuardController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuardController.swift; sourceTree = ""; }; - CD6CD87822F185D000F4FD4A /* GuardConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuardConfig.swift; sourceTree = ""; }; - CD95D21C22E72C4C007559A3 /* ProHUD.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ProHUD.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - CD95D21F22E72C4C007559A3 /* ProHUD.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProHUD.h; sourceTree = ""; }; - CD95D22022E72C4C007559A3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - CD95D26722E72D68007559A3 /* ProHUD.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = ProHUD.podspec; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; - CD95D26822E72DA1007559A3 /* AlertController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertController.swift; sourceTree = ""; }; - CD95D26A22E72DB3007559A3 /* ProHUD.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProHUD.swift; sourceTree = ""; }; - CDB6A07A22EEF06500AF6CF0 /* HUDController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HUDController.swift; sourceTree = ""; }; - CDB6A07C22EEF19D00AF6CF0 /* HUDConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HUDConfig.swift; sourceTree = ""; }; - CDC39CFC22FD6DDF0070E914 /* GuardModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GuardModel.swift; sourceTree = ""; }; - CDF2C58824A0572C002ECDD5 /* HUDUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HUDUtils.swift; sourceTree = ""; }; - DC31EBFAC56868D6096A233A /* Pods-ProHUD.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ProHUD.release.xcconfig"; path = "Pods/Target Support Files/Pods-ProHUD/Pods-ProHUD.release.xcconfig"; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - CD95D21922E72C4C007559A3 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - CDC67BEC2490A1D100CC6FE6 /* Inspire in Frameworks */, - CDC67BE92490A19100CC6FE6 /* SnapKit in Frameworks */, - 36CB9DEED3C3E823FE7B1C75 /* Pods_ProHUD.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 33E080A4BE17176DF10FFA89 /* Pods */ = { - isa = PBXGroup; - children = ( - 3C95FD2F17A45D13E2AB9306 /* Pods-ProHUD.debug.xcconfig */, - DC31EBFAC56868D6096A233A /* Pods-ProHUD.release.xcconfig */, - ); - name = Pods; - sourceTree = ""; - }; - BA9A12AB2B7D4F5C9A8C773C /* Frameworks */ = { - isa = PBXGroup; - children = ( - C2011798511AD590A613E54E /* Pods_ProHUD.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - CD16491022EF0A4B0077988C /* Alert */ = { - isa = PBXGroup; - children = ( - CD95D26822E72DA1007559A3 /* AlertController.swift */, - CD16490A22EF09AB0077988C /* AlertModel.swift */, - CD16490C22EF09B40077988C /* AlertConfig.swift */, - ); - path = Alert; - sourceTree = ""; - }; - CD6CD87322F185B400F4FD4A /* Toast */ = { - isa = PBXGroup; - children = ( - CD6CD86B22F1858F00F4FD4A /* ToastModel.swift */, - CD6CD86F22F185A700F4FD4A /* ToastController.swift */, - CD6CD87122F185AF00F4FD4A /* ToastConfig.swift */, - ); - path = Toast; - sourceTree = ""; - }; - CD6CD87C22F185DA00F4FD4A /* Guard */ = { - isa = PBXGroup; - children = ( - CD6CD87422F185C200F4FD4A /* GuardController.swift */, - CD6CD87822F185D000F4FD4A /* GuardConfig.swift */, - CDC39CFC22FD6DDF0070E914 /* GuardModel.swift */, - ); - path = Guard; - sourceTree = ""; - }; - CD95D21222E72C4C007559A3 = { - isa = PBXGroup; - children = ( - CD95D26722E72D68007559A3 /* ProHUD.podspec */, - CDC67BED2490A28500CC6FE6 /* Source */, - CD95D21E22E72C4C007559A3 /* ProHUD */, - CD95D21D22E72C4C007559A3 /* Products */, - 33E080A4BE17176DF10FFA89 /* Pods */, - BA9A12AB2B7D4F5C9A8C773C /* Frameworks */, - ); - sourceTree = ""; - }; - CD95D21D22E72C4C007559A3 /* Products */ = { - isa = PBXGroup; - children = ( - CD95D21C22E72C4C007559A3 /* ProHUD.framework */, - ); - name = Products; - sourceTree = ""; - }; - CD95D21E22E72C4C007559A3 /* ProHUD */ = { - isa = PBXGroup; - children = ( - CD95D22022E72C4C007559A3 /* Info.plist */, - ); - path = ProHUD; - sourceTree = ""; - }; - CDC67BED2490A28500CC6FE6 /* Source */ = { - isa = PBXGroup; - children = ( - CD95D21F22E72C4C007559A3 /* ProHUD.h */, - CD16491322EF12220077988C /* ProHUD.xcassets */, - CD95D26A22E72DB3007559A3 /* ProHUD.swift */, - CDB6A07C22EEF19D00AF6CF0 /* HUDConfig.swift */, - CDB6A07A22EEF06500AF6CF0 /* HUDController.swift */, - CD16491122EF0D900077988C /* HUDView.swift */, - CDF2C58824A0572C002ECDD5 /* HUDUtils.swift */, - CD6CD87322F185B400F4FD4A /* Toast */, - CD16491022EF0A4B0077988C /* Alert */, - CD6CD87C22F185DA00F4FD4A /* Guard */, - ); - path = Source; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - CD95D21722E72C4C007559A3 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - CD95D22122E72C4C007559A3 /* ProHUD.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - CD95D21B22E72C4C007559A3 /* ProHUD */ = { - isa = PBXNativeTarget; - buildConfigurationList = CD95D22422E72C4C007559A3 /* Build configuration list for PBXNativeTarget "ProHUD" */; - buildPhases = ( - A54F2DB69A2889EF6E75A3EC /* [CP] Check Pods Manifest.lock */, - CD95D21722E72C4C007559A3 /* Headers */, - CD95D21822E72C4C007559A3 /* Sources */, - CD95D21922E72C4C007559A3 /* Frameworks */, - CD95D21A22E72C4C007559A3 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = ProHUD; - packageProductDependencies = ( - CDC67BE82490A19100CC6FE6 /* SnapKit */, - CDC67BEB2490A1D100CC6FE6 /* Inspire */, - ); - productName = ProHUD; - productReference = CD95D21C22E72C4C007559A3 /* ProHUD.framework */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - CD95D21322E72C4C007559A3 /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 1100; - ORGANIZATIONNAME = "Titan Studio"; - TargetAttributes = { - CD95D21B22E72C4C007559A3 = { - CreatedOnToolsVersion = 11.0; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = CD95D21622E72C4C007559A3 /* Build configuration list for PBXProject "ProHUD" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = CD95D21222E72C4C007559A3; - packageReferences = ( - CDC67BE72490A19100CC6FE6 /* XCRemoteSwiftPackageReference "SnapKit" */, - CDC67BEA2490A1D100CC6FE6 /* XCRemoteSwiftPackageReference "Inspire" */, - ); - productRefGroup = CD95D21D22E72C4C007559A3 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - CD95D21B22E72C4C007559A3 /* ProHUD */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - CD95D21A22E72C4C007559A3 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - CD16491422EF12220077988C /* ProHUD.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - A54F2DB69A2889EF6E75A3EC /* [CP] Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-ProHUD-checkManifestLockResult.txt", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; - showEnvVarsInLog = 0; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - CD95D21822E72C4C007559A3 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - CD95D26922E72DA1007559A3 /* AlertController.swift in Sources */, - CD6CD87922F185D000F4FD4A /* GuardConfig.swift in Sources */, - CDB6A07D22EEF19D00AF6CF0 /* HUDConfig.swift in Sources */, - CD6CD87222F185AF00F4FD4A /* ToastConfig.swift in Sources */, - CD6CD87522F185C200F4FD4A /* GuardController.swift in Sources */, - CD6CD87022F185A700F4FD4A /* ToastController.swift in Sources */, - CD95D26B22E72DB3007559A3 /* ProHUD.swift in Sources */, - CD16490D22EF09B40077988C /* AlertConfig.swift in Sources */, - CD6CD86C22F1858F00F4FD4A /* ToastModel.swift in Sources */, - CD16490B22EF09AB0077988C /* AlertModel.swift in Sources */, - CD16491222EF0D900077988C /* HUDView.swift in Sources */, - CDF2C58924A0572C002ECDD5 /* HUDUtils.swift in Sources */, - CDB6A07B22EEF06500AF6CF0 /* HUDController.swift in Sources */, - CDC39CFD22FD6DDF0070E914 /* GuardModel.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - CD95D22222E72C4C007559A3 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - CD95D22322E72C4C007559A3 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 10.0; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - CD95D22522E72C4C007559A3 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 3C95FD2F17A45D13E2AB9306 /* Pods-ProHUD.debug.xcconfig */; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 34W5TB5KD2; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = ProHUD/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.xaoxuu.ProHUD; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTS_MACCATALYST = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - CD95D22622E72C4C007559A3 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = DC31EBFAC56868D6096A233A /* Pods-ProHUD.release.xcconfig */; - buildSettings = { - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = 34W5TB5KD2; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - INFOPLIST_FILE = ProHUD/Info.plist; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.xaoxuu.ProHUD; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTS_MACCATALYST = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - CD95D21622E72C4C007559A3 /* Build configuration list for PBXProject "ProHUD" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CD95D22222E72C4C007559A3 /* Debug */, - CD95D22322E72C4C007559A3 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - CD95D22422E72C4C007559A3 /* Build configuration list for PBXNativeTarget "ProHUD" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - CD95D22522E72C4C007559A3 /* Debug */, - CD95D22622E72C4C007559A3 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - CDC67BE72490A19100CC6FE6 /* XCRemoteSwiftPackageReference "SnapKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/SnapKit/SnapKit"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 5.0.1; - }; - }; - CDC67BEA2490A1D100CC6FE6 /* XCRemoteSwiftPackageReference "Inspire" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/xaoxuu/Inspire"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.1.0; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - CDC67BE82490A19100CC6FE6 /* SnapKit */ = { - isa = XCSwiftPackageProductDependency; - package = CDC67BE72490A19100CC6FE6 /* XCRemoteSwiftPackageReference "SnapKit" */; - productName = SnapKit; - }; - CDC67BEB2490A1D100CC6FE6 /* Inspire */ = { - isa = XCSwiftPackageProductDependency; - package = CDC67BEA2490A1D100CC6FE6 /* XCRemoteSwiftPackageReference "Inspire" */; - productName = Inspire; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = CD95D21322E72C4C007559A3 /* Project object */; -} diff --git a/ProHUD.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ProHUD.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a..0000000 --- a/ProHUD.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/ProHUD.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ProHUD.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/ProHUD.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/ProHUD.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ProHUD.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index c867fdc..0000000 --- a/ProHUD.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,25 +0,0 @@ -{ - "object": { - "pins": [ - { - "package": "Inspire", - "repositoryURL": "https://github.com/xaoxuu/Inspire", - "state": { - "branch": null, - "revision": "fed13e3530ca38f884d190ea5c7b12b8f3b2a41b", - "version": "2.0.0" - } - }, - { - "package": "SnapKit", - "repositoryURL": "https://github.com/SnapKit/SnapKit", - "state": { - "branch": null, - "revision": "d458564516e5676af9c70b4f4b2a9178294f1bc6", - "version": "5.0.1" - } - } - ] - }, - "version": 1 -} diff --git a/ProHUD.xcworkspace/contents.xcworkspacedata b/ProHUD.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index aabe091..0000000 --- a/ProHUD.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - diff --git a/ProHUD.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ProHUD.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d9810..0000000 --- a/ProHUD.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/ProHUD.xcworkspace/xcshareddata/swiftpm/Package.resolved b/ProHUD.xcworkspace/xcshareddata/swiftpm/Package.resolved deleted file mode 100644 index 38ef67a..0000000 --- a/ProHUD.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ /dev/null @@ -1,25 +0,0 @@ -{ - "object": { - "pins": [ - { - "package": "Inspire", - "repositoryURL": "https://github.com/xaoxuu/Inspire", - "state": { - "branch": null, - "revision": "cad0c64e6995a06ee3bf3ed7c632ad27c1b8ffb1", - "version": "2.0.0" - } - }, - { - "package": "SnapKit", - "repositoryURL": "https://github.com/SnapKit/SnapKit", - "state": { - "branch": null, - "revision": "d458564516e5676af9c70b4f4b2a9178294f1bc6", - "version": "5.0.1" - } - } - ] - }, - "version": 1 -} diff --git a/ProHUD/Info.plist b/ProHUD/Info.plist deleted file mode 100644 index 9bcb244..0000000 --- a/ProHUD/Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - - diff --git a/README.md b/README.md index d06df4d..58f4057 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ Toast.push(scene: .warning, title: "设备电量过低", message: "请及时对 toast.isRemovable = false // 监听点击事件 toast.didTapped { - debugPrint("点击了这条横幅") + print("点击了这条横幅") } } ``` @@ -351,4 +351,4 @@ ProHUD.config { (cfg) in ## 文档 - \ No newline at end of file + diff --git a/Source/Alert/AlertConfig.swift b/Source/Alert/AlertConfig.swift deleted file mode 100644 index 8874f4a..0000000 --- a/Source/Alert/AlertConfig.swift +++ /dev/null @@ -1,340 +0,0 @@ -// -// 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 - } - - } -}() diff --git a/Source/Alert/AlertController.swift b/Source/Alert/AlertController.swift deleted file mode 100644 index ce5cf37..0000000 --- a/Source/Alert/AlertController.swift +++ /dev/null @@ -1,355 +0,0 @@ -// -// Alert.swift -// ProHUD -// -// Created by xaoxuu on 2019/7/23. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit -import SnapKit - -public typealias Alert = ProHUD.Alert - -public extension ProHUD { - class Alert: HUDController { - - static var alerts = [Alert]() - - static var alertWindow: UIWindow? - - /// 内容视图 - public var contentView = createBlurView() - - /// 内容容器(包括icon、textStack、actionStack) - public var contentStack: StackContainer = { - let stack = StackContainer() - stack.spacing = cfg.alert.margin - return stack - }() - - /// 文本区容器 - public var textStack: StackContainer = { - let stack = StackContainer() - stack.spacing = cfg.alert.margin - return stack - }() - - /// 图片 - public var imageView = UIImageView() - - /// 标题 - public var titleLabel: UILabel? - - /// 正文 - public var bodyLabel: UILabel? - - /// 操作区域 - public var actionStack: StackContainer = { - let stack = StackContainer() - stack.alignment = .fill - stack.spacing = cfg.alert.margin - return stack - }() - - /// 视图模型 - public var vm = ViewModel() - - // MARK: 生命周期 - private var isLoadFinished = false - - /// 实例化 - /// - Parameter scene: 场景 - /// - Parameter title: 标题 - /// - Parameter message: 内容 - /// - Parameter icon: 图标 - public convenience init(scene: Scene?, title: String? = nil, message: String? = nil, actions: ((Alert) -> Void)? = nil) { - self.init() - vm.vc = self - vm.scene = scene ?? .default - vm.title = title - vm.message = message - actions?(self) - } - - public override func viewDidLoad() { - super.viewDidLoad() - view.tintColor = cfg.alert.tintColor - cfg.alert.reloadData(self) - isLoadFinished = true - } - - } - -} - -// MARK: - 实例函数 - -public extension Alert { - - /// 推入屏幕 - @discardableResult func push() -> Alert { - if Alert.alerts.contains(self) == false { - willAppearCallback?() - let window = Alert.privGetAlertWindow(self) - window.makeKeyAndVisible() - window.resignKey() - window.addSubview(view) - if #available(iOS 13.0, *) { - window.windowScene = cfg.windowScene ?? .currentWindowScene - } - view.transform = .init(scaleX: 1.2, y: 1.2) - view.alpha = 0 - UIView.animateForAlertBuildIn { - self.view.transform = .identity - self.view.alpha = 1 - window.backgroundColor = window.backgroundColor?.withAlphaComponent(0.6) - } - Alert.alerts.append(self) - didAppearCallback?() - } - Alert.privUpdateAlertsLayout() - return self - } - - /// 弹出屏幕 - func pop() { - willDisappearCallback?() - let window = Alert.privGetAlertWindow(self) - Alert.privRemoveItemFromArray(alert: self) - UIView.animateForAlertBuildOut(animations: { - self.view.alpha = 0 - self.view.transform = .init(scaleX: 1.08, y: 1.08) - }) { (done) in - self.view.removeFromSuperview() - self.removeFromParent() - self.didDisappearCallback?() - } - // hide window - let count = Alert.alerts.count - if count == 0 && Alert.alertWindow != nil { - UIView.animateForAlertBuildOut(animations: { - window.backgroundColor = window.backgroundColor?.withAlphaComponent(0) - }) { (done) in - if Alert.alerts.count == 0 { - Alert.alertWindow = nil - } - } - } - } - - /// 更新 - /// - Parameter callback: 回调 - func update(_ callback: ((inout ViewModel) -> Void)? = nil) { - callback?(&vm) - cfg.alert.reloadData(self) - } - - - /// 强制关闭弹窗的事件 - /// - Parameter callback: 事件回调 - func didForceQuit(_ callback: (() -> Void)?) { - vm.forceQuitCallback = callback - } - -} - - -// MARK: 支持加载动画 -extension Alert: LoadingRotateAnimation {} - -// MARK: - 实例管理器 -public extension Alert { - - /// 推入屏幕 - /// - Parameter alert: 场景 - /// - Parameter title: 标题 - /// - Parameter message: 正文 - /// - Parameter actions: 更多操作 - @discardableResult class func push(scene: ProHUD.Scene = .default, title: String? = nil, message: String? = nil, _ actions: ((Alert) -> Void)? = nil) -> Alert { - return Alert(scene: scene, title: title, message: message, actions: actions).push() - } - - /// 创建实例并推入屏幕 - /// - Parameters: - /// - identifier: 唯一标识 - /// - toast: 实例对象 - /// - Returns: 回调 - @discardableResult class func push(_ identifier: String, scene: ProHUD.Scene? = nil, instance: ((Alert) -> Void)? = nil) -> Alert { - if let a = find(identifier).last { - if let s = scene, s != a.vm.scene { - a.update { (vm) in - vm.scene = s - } - } - instance?(a) - return a - } else { - return Alert(scene: scene) { (aa) in - aa.identifier = identifier - instance?(aa) - }.push() - } - } - - /// 查找指定的实例 - /// - Parameter identifier: 指定实例的标识 - class func find(_ identifier: String) -> [Alert] { - var aa = [Alert]() - for a in Alert.alerts { - if a.identifier == identifier { - aa.append(a) - } - } - return aa - } - - /// 查找指定的实例 - /// - Parameter identifier: 标识 - /// - Parameter last: 已经存在(获取最后一个) - /// - Parameter none: 不存在 - class func find(_ identifier: String, last: @escaping (Alert) -> Void) { - if let t = find(identifier).last { - last(t) - } - } - - /// 弹出屏幕 - /// - Parameter alert: 实例 - class func pop(_ alert: Alert) { - alert.pop() - } - - /// 弹出屏幕 - /// - Parameter identifier: 指定实例的标识 - class func pop(_ identifier: String) { - for a in find(identifier) { - a.pop() - } - } - -} - - -// MARK: - 创建和设置 -extension Alert { - - /// 插入一个按钮 - /// - Parameter style: 样式 - /// - Parameter title: 标题 - /// - Parameter action: 事件 - @discardableResult func insert(action index: Int?, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton { - let btn = Button.createActionButton(title: title) - if let idx = index, idx < actionStack.arrangedSubviews.count { - actionStack.insertArrangedSubview(btn, at: idx) - } else { - actionStack.addArrangedSubview(btn) - } - btn.update(style: style) - if actionStack.superview == nil { - contentStack.addArrangedSubview(actionStack) - contentStack.layoutIfNeeded() - } - addTouchUpAction(for: btn) { [weak self] in - handler?() - if btn.tag == UIAlertAction.Style.cancel.rawValue || handler == nil { - self?.pop() - } - } - if isLoadFinished { - actionStack.layoutIfNeeded() - UIView.animateForAlert { - self.view.layoutIfNeeded() - } - } - return btn - } - - /// 更新按钮 - /// - Parameter index: 索引 - /// - Parameter style: 样式 - /// - Parameter title: 标题 - /// - Parameter handler: 事件 - func update(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) { - if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton { - btn.setTitle(title, for: .normal) - if let b = btn as? Button { - b.update(style: style) - } - if let _ = buttonEvents[btn] { - buttonEvents.removeValue(forKey: btn) - } - addTouchUpAction(for: btn) { [weak self] in - handler?() - if btn.tag == UIAlertAction.Style.cancel.rawValue { - self?.pop() - } - } - } - } - - /// 移除按钮 - /// - Parameter index: 索引 - @discardableResult func remove(action index: Int) -> Alert { - if index < 0 { - for view in self.actionStack.arrangedSubviews { - if let btn = view as? UIButton { - btn.removeFromSuperview() - if let _ = buttonEvents[btn] { - buttonEvents.removeValue(forKey: btn) - } - } - } - } else if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton { - btn.removeFromSuperview() - if let _ = buttonEvents[btn] { - buttonEvents.removeValue(forKey: btn) - } - } - if self.actionStack.arrangedSubviews.count == 0 { - self.actionStack.removeFromSuperview() - } - UIView.animateForAlert { - self.view.layoutIfNeeded() - } - return self - } -} - -fileprivate extension Alert { - class func privUpdateAlertsLayout() { - for (i, a) in alerts.reversed().enumerated() { - let scale = CGFloat(pow(0.7, CGFloat(i))) - UIView.animate(withDuration: 1.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: [.allowUserInteraction, .curveEaseInOut], animations: { - let y = -50 * CGFloat(i) * CGFloat(pow(0.8, CGFloat(i))) - a.view.transform = CGAffineTransform.init(translationX: 0, y: y).scaledBy(x: scale, y: scale) - }) { (done) in - - } - } - } - class func privGetAlertWindow(_ vc: UIViewController) -> UIWindow { - if let w = alertWindow { - return w - } - let w = UIWindow() - alertWindow = w - w.backgroundColor = UIColor.init(red: 0, green: 0, blue: 0, alpha: 0) - // 比原生alert层级低一点 - w.windowLevel = .alertForProHUD - return w - } - - class func privRemoveItemFromArray(alert: Alert) { - if alerts.count > 1 { - alerts.removeAll { $0 == alert } - privUpdateAlertsLayout() - } else if alerts.count == 1 { - alerts.removeAll() - } else { - debug("‼️代码漏洞:已经没有alert了") - } - } - -} - diff --git a/Source/Alert/AlertModel.swift b/Source/Alert/AlertModel.swift deleted file mode 100644 index 2b4ce60..0000000 --- a/Source/Alert/AlertModel.swift +++ /dev/null @@ -1,115 +0,0 @@ -// -// AlertModel.swift -// ProHUD -// -// Created by xaoxuu on 2019/7/29. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit - -public extension Alert { - class ViewModel { - - /// 使用场景 - public var scene = ProHUD.Scene.default - - /// 标题 - public var title: String? { - didSet { - vc?.titleLabel?.text = title - } - } - - /// 正文 - public var message: String? { - didSet { - vc?.bodyLabel?.text = message - } - } - - /// 图标 - public var icon: UIImage? { - didSet { - vc?.imageView.image = icon - } - } - - /// 持续时间(为空代表根据场景不同的默认配置,为0代表无穷大) - public var duration: TimeInterval? { - didSet { - updateDuration() - } - } - - public weak var vc: Alert? - - // MARK: 私有 - - /// 持续时间 - var durationBlock: DispatchWorkItem? - - /// 强制退出按钮 - var hideTimerBlock: DispatchWorkItem? - - /// 强制退出代码 - var forceQuitCallback: (() -> Void)? - - func updateDuration() { - durationBlock?.cancel() - if let t = duration ?? scene.alertDuration, t > 0 { - durationBlock = DispatchWorkItem(block: { [weak self] in - if let vc = self?.vc { - if vc.buttonEvents.count == 0 { - vc.pop() - } - } - }) - DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: durationBlock!) - } else { - durationBlock = nil - } - } - - } - -} - -public extension Alert.ViewModel { - - /// 添加按钮 - /// - Parameter style: 样式 - /// - Parameter text: 标题 - /// - Parameter handler: 事件处理 - @discardableResult func add(action style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton { - return vc!.insert(action: nil, style: style, title: title, handler: handler) - } - - /// 插入按钮 - /// - Parameter index: 索引 - /// - Parameter style: 样式 - /// - Parameter title: 标题 - /// - Parameter handler: 事件处理 - @discardableResult func insert(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton { - return vc!.insert(action: index, style: style, title: title, handler: handler) - } - - /// 更新按钮 - /// - Parameter index: 索引 - /// - Parameter style: 样式 - /// - Parameter title: 标题 - /// - Parameter handler: 事件处理 - func update(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) { - vc?.update(action: index, style: style, title: title, handler: handler) - } - - /// 移除按钮 - /// - Parameter index: 索引 - func remove(action index: Int...) { - for (i, idx) in index.enumerated() { - vc?.remove(action: idx-i) - } - } - - -} diff --git a/Source/Guard/GuardConfig.swift b/Source/Guard/GuardConfig.swift deleted file mode 100644 index 6ae652f..0000000 --- a/Source/Guard/GuardConfig.swift +++ /dev/null @@ -1,141 +0,0 @@ -// -// cfg.guard.swift -// ProHUD -// -// Created by xaoxuu on 2019/7/31. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit -import SnapKit - -public extension ProHUD.Configuration { - struct Guard { - // MARK: 卡片样式 - /// 最大宽度(用于优化横屏或者iPad显示) - public var cardMaxWidth = CGFloat(460) - /// 圆角半径(手机竖屏时为0) - public var cardCornerRadius = CGFloat(16) - - /// 余量:元素与元素之间的距离 - public var margin = CGFloat(8) - /// 填充:元素内部控件距离元素边界的距离 - public var padding = CGFloat(16) - - /// 颜色 - public var tintColor: UIColor? - - // MARK: 文本样式 - /// 标题字体 - public var titleFont = UIFont.boldSystemFont(ofSize: 22) - /// 副标题字体 - public var subTitleFont = UIFont.boldSystemFont(ofSize: 20) - /// 正文字体 - public var bodyFont = UIFont.systemFont(ofSize: 18) - - // MARK: 按钮样式 - /// 按钮字体 - public var buttonFont = UIFont.boldSystemFont(ofSize: 18) - - /// 按钮圆角半径 - public var buttonCornerRadius = CGFloat(12) - - /// 更新视图 - /// - Parameter callback: 回调代码 - public mutating func reloadData(_ callback: @escaping (ProHUD.Guard) -> Void) { - privReloadData = callback - } - - } -} - - -// MARK: - 内部调用 -extension ProHUD.Configuration.Guard { - - var reloadData: (ProHUD.Guard) -> Void { - return privReloadData - } - - var reloadStack: (ProHUD.Guard) -> Void { - return { (vc) in - if vc.textStack.arrangedSubviews.count > 0 { - vc.contentStack.addArrangedSubview(vc.textStack) - } else { - vc.textStack.removeFromSuperview() - } - if vc.actionStack.arrangedSubviews.count > 0 { - vc.contentStack.addArrangedSubview(vc.actionStack) - } else { - vc.actionStack.removeFromSuperview() - } - } - } - -} - -// MARK: - 默认实现 -fileprivate var privReloadData: (ProHUD.Guard) -> Void = { - return { (vc) in - debug(vc, "reloadData") - let config = cfg.guard - // background - vc.view.tintColor = config.tintColor - vc.view.backgroundColor = UIColor(white: 0, alpha: 0) - vc.view.addSubview(vc.contentView) - vc.contentView.contentView.addSubview(vc.contentStack) - // 更新布局 - var width = UIScreen.main.bounds.width - if width > config.cardMaxWidth { - // 横屏或者iPad - width = config.cardMaxWidth - vc.contentView.layer.masksToBounds = true - vc.contentView.layer.cornerRadius = config.cardCornerRadius - } else { - vc.contentView.layer.shadowRadius = 4 - vc.contentView.layer.shadowOffset = .init(width: 0, height: 2) - vc.contentView.layer.shadowOpacity = 0.12 - } - vc.contentView.snp.makeConstraints { (mk) in - if isPortrait && vc.isFullScreen { - mk.top.equalToSuperview() - } - mk.centerX.equalToSuperview() - if UIDevice.current.userInterfaceIdiom == .phone { - if width < config.cardMaxWidth { - mk.bottom.equalToSuperview() - } else { - mk.bottom.equalToSuperview().offset(-ProHUD.safeAreaInsets.bottom) - } - } else if UIDevice.current.userInterfaceIdiom == .pad { - mk.centerY.equalToSuperview() - } - mk.width.equalTo(width) - } - // stack - vc.contentStack.snp.makeConstraints { (mk) in - if isPortrait && vc.isFullScreen { - mk.top.equalToSuperview().offset(ProHUD.safeAreaInsets.top) - } else { - mk.top.equalToSuperview().offset(config.padding) - } - mk.centerX.equalToSuperview() - if width < config.cardMaxWidth { - let bottom = ProHUD.safeAreaInsets.bottom - if bottom == 0 { - mk.bottom.equalToSuperview().offset(-config.padding) - } else { - mk.bottom.equalToSuperview().offset(-config.padding/2 - bottom) - } - } else { - mk.bottom.equalToSuperview().offset(-config.padding) - } - if isPortrait { - mk.width.equalToSuperview().offset(-config.padding * 2) - } else { - mk.width.equalToSuperview().offset(-config.padding * 4) - } - } - config.reloadStack(vc) - } -}() diff --git a/Source/Guard/GuardController.swift b/Source/Guard/GuardController.swift deleted file mode 100644 index b379656..0000000 --- a/Source/Guard/GuardController.swift +++ /dev/null @@ -1,383 +0,0 @@ -// -// GuardController.swift -// ProHUD -// -// Created by xaoxuu on 2019/7/31. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit -import SnapKit - -public typealias Guard = ProHUD.Guard - -public extension ProHUD { - - class Guard: HUDController { - - /// 内容视图 - public var contentView = createBlurView() - - /// 内容容器(包括textStack、actionStack,可以自己插入需要的控件) - public var contentStack: StackContainer = { - let stack = StackContainer() - stack.spacing = cfg.guard.padding + cfg.guard.margin - stack.alignment = .fill - return stack - }() - - /// 文本区容器 - public var textStack: StackContainer = { - let stack = StackContainer() - stack.spacing = cfg.guard.margin - stack.alignment = .fill - return stack - }() - - /// 操作区容器 - public var actionStack: StackContainer = { - let stack = StackContainer() - stack.alignment = .fill - stack.spacing = cfg.guard.margin - return stack - }() - - /// 是否是强制性的(点击空白处是否可以消失) - public var isForce = false - - /// 是否是全屏的(仅手机竖屏有效) - public var isFullScreen = false - - /// 是否正在显示 - private var isDisplaying = false - - /// 背景颜色 - public var backgroundColor: UIColor? = UIColor(white: 0, alpha: 0.4) - - public var vm = ViewModel() - - // MARK: 生命周期 - private var isLoadFinished = false - - /// 实例化 - /// - Parameter title: 标题 - /// - Parameter message: 内容 - /// - Parameter actions: 更多操作 - public convenience init(title: String? = nil, message: String? = nil, actions: ((Guard) -> Void)? = nil) { - self.init() - vm.vc = self - if let _ = title { - add(title: title) - } - if let _ = message { - add(message: message) - } - actions?(self) - - // 点击空白处 - let tap = UITapGestureRecognizer(target: self, action: #selector(privDidTapped(_:))) - view.addGestureRecognizer(tap) - - } - - - public override func viewDidLoad() { - super.viewDidLoad() - view.tintColor = cfg.guard.tintColor - cfg.guard.reloadData(self) - isLoadFinished = true - } - - } - -} - -// MARK: - 实例函数 -public extension Guard { - - /// 推入某个视图控制器 - /// - Parameter viewController: 视图控制器 - @discardableResult func push(to viewController: UIViewController? = nil) -> Guard { - func f(_ vc: UIViewController) -> Guard { - willAppearCallback?() - view.layoutIfNeeded() - vc.addChild(self) - vc.view.addSubview(view) - view.isUserInteractionEnabled = true - view.snp.makeConstraints { (mk) in - mk.edges.equalToSuperview() - } - if isDisplaying == false { - privTranslateOut() - } - isDisplaying = true - UIView.animateForGuard { - self.privTranslateIn() - } - didAppearCallback?() - return self - } - if let vc = viewController ?? cfg.rootViewController { - return f(vc) - } else if let vc = UIViewController.currentRootViewController { - return f(vc) - debug("⚠️自动获取根控制器失败,请设置根控制器或者传入需要push到的控制器") - } - return self - } - - /// 从父视图控制器弹出 - func pop() { - if isDisplaying { - debug("pop") - willDisappearCallback?() - isDisplaying = false - view.isUserInteractionEnabled = false - self.removeFromParent() - UIView.animateForGuard(animations: { - self.privTranslateOut() - }) { (done) in - if self.isDisplaying == false { - self.view.removeFromSuperview() - self.didDisappearCallback?() - } - } - } - } - - /// 更新 - /// - Parameter callback: 回调 - func update(_ callback: ((inout ViewModel) -> Void)? = nil) { - callback?(&vm) - cfg.guard.reloadData(self) - } - - -} - -// MARK: - 实例管理器 -public extension Guard { - - /// 推入屏幕 - /// - Parameter alert: 场景 - /// - Parameter title: 标题 - /// - Parameter message: 正文 - /// - Parameter icon: 图标 - @discardableResult class func push(to viewController: UIViewController? = nil, _ actions: ((Guard) -> Void)? = nil) -> Guard { - return Guard(actions: actions).push(to: viewController) - } - - /// 创建实例并推入屏幕 - /// - Parameters: - /// - identifier: 唯一标识 - /// - toast: 实例对象 - /// - Returns: 回调 - @discardableResult class func push(_ identifier: String, to viewController: UIViewController? = nil, _ instance: ( (Guard) -> Void)? = nil) -> Guard { - if let g = find(identifier).last { - instance?(g) - return g - } else { - return Guard() { (gg) in - gg.identifier = identifier - instance?(gg) - }.push(to: viewController) - } - } - - /// 查找指定的实例 - /// - Parameter identifier: 指定实例的标识 - class func find(_ identifier: String?, from viewController: UIViewController? = nil) -> [Guard] { - guard let vc = viewController ?? cfg.rootViewController ?? UIViewController.currentRootViewController else { return [] } - return vc.children.compactMap { (child) -> Guard? in - guard let child = child as? Guard else { return nil } - if let id = identifier, child.identifier == id { - return child - } else { - return child - } - } - } - - /// 查找指定的实例 - /// - Parameter identifier: 标识 - /// - Parameter last: 已经存在(获取最后一个) - /// - Parameter none: 不存在 - class func find(_ identifier: String?, from viewController: UIViewController? = nil, last: @escaping (Guard) -> Void) { - if let t = find(identifier, from: viewController).last { - last(t) - } - } - - - /// 弹出屏幕 - /// - Parameter alert: 实例 - class func pop(_ guard: Guard) { - `guard`.pop() - } - - /// 弹出所有实例 - /// - Parameter identifier: 指定实例的标识 - class func pop(_ identifier: String?, from viewController: UIViewController?) { - for g in find(identifier, from: viewController) { - g.pop() - } - } - -} - - - -// MARK: - 创建和设置 -extension Guard { - - /// 加载一个标题 - /// - Parameter text: 文本 - @discardableResult func add(title: String?) -> UILabel { - let lb = UILabel() - lb.font = cfg.guard.titleFont - lb.textColor = cfg.primaryLabelColor - lb.numberOfLines = 0 - lb.textAlignment = .center - lb.text = title - textStack.addArrangedSubview(lb) - if #available(iOS 11.0, *) { - let count = textStack.arrangedSubviews.count - if count > 1 { - textStack.setCustomSpacing(cfg.guard.margin * 3, after: textStack.arrangedSubviews[count-2]) - textStack.setCustomSpacing(cfg.guard.margin * 1.5, after: textStack.arrangedSubviews[count-1]) - } - } else { - // Fallback on earlier versions - } - cfg.guard.reloadStack(self) - return lb - } - - /// 加载一个副标题 - /// - Parameter text: 文本 - @discardableResult func add(subTitle: String?) -> UILabel { - let lb = add(title: subTitle) - lb.font = cfg.guard.subTitleFont - lb.textAlignment = .justified - return lb - } - - /// 加载一段正文 - /// - Parameter text: 文本 - @discardableResult func add(message: String?) -> UILabel { - let lb = UILabel() - lb.font = cfg.guard.bodyFont - lb.textColor = cfg.secondaryLabelColor - lb.numberOfLines = 0 - lb.textAlignment = .justified - lb.text = message - textStack.addArrangedSubview(lb) - cfg.guard.reloadStack(self) - return lb - } - - /// 插入一个按钮 - /// - Parameter index: 索引 - /// - Parameter style: 样式 - /// - Parameter title: 标题 - /// - Parameter action: 事件 - @discardableResult func insert(action index: Int?, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton { - let btn = Button.createActionButton(title: title) - btn.titleLabel?.font = cfg.guard.buttonFont - if let idx = index, idx < actionStack.arrangedSubviews.count { - actionStack.insertArrangedSubview(btn, at: idx) - } else { - actionStack.addArrangedSubview(btn) - } - btn.update(style: style) - cfg.guard.reloadStack(self) - addTouchUpAction(for: btn) { [weak self] in - handler?() - if btn.tag == UIAlertAction.Style.cancel.rawValue { - self?.pop() - } - } - if isLoadFinished { - UIView.animateForGuard { - self.view.layoutIfNeeded() - } - } - return btn - } - - /// 更新按钮 - /// - Parameter index: 索引 - /// - Parameter style: 样式 - /// - Parameter title: 标题 - /// - Parameter handler: 事件 - func update(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) { - if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton { - btn.setTitle(title, for: .normal) - if let b = btn as? Button { - b.update(style: style) - } - if let _ = buttonEvents[btn] { - buttonEvents.removeValue(forKey: btn) - } - addTouchUpAction(for: btn) { [weak self] in - handler?() - if btn.tag == UIAlertAction.Style.cancel.rawValue { - self?.pop() - } - } - } - } - - /// 移除按钮 - /// - Parameter index: 索引 - @discardableResult func remove(index: Int) -> Guard { - if index < 0 { - for view in self.actionStack.arrangedSubviews { - if let btn = view as? UIButton { - btn.removeFromSuperview() - if let _ = buttonEvents[btn] { - buttonEvents.removeValue(forKey: btn) - } - } - } - } else if index < self.actionStack.arrangedSubviews.count, let btn = self.actionStack.arrangedSubviews[index] as? UIButton { - btn.removeFromSuperview() - if let _ = buttonEvents[btn] { - buttonEvents.removeValue(forKey: btn) - } - } - cfg.guard.reloadStack(self) - UIView.animateForAlert { - self.view.layoutIfNeeded() - } - return self - } - -} - -fileprivate extension Guard { - - /// 点击事件 - /// - Parameter sender: 手势 - @objc func privDidTapped(_ sender: UITapGestureRecognizer) { - let point = sender.location(in: contentView) - if point.x < 0 || point.y < 0 { - if isForce == false { - // 点击到操作区域外部 - pop() - } - } - - } - - func privTranslateIn() { - view.backgroundColor = backgroundColor - contentView.transform = .identity - } - - func privTranslateOut() { - view.backgroundColor = UIColor(white: 0, alpha: 0) - contentView.transform = .init(translationX: 0, y: view.frame.size.height - contentView.frame.minY + cfg.guard.margin) - } - -} diff --git a/Source/Guard/GuardModel.swift b/Source/Guard/GuardModel.swift deleted file mode 100644 index 65f7cce..0000000 --- a/Source/Guard/GuardModel.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// GuardModel.swift -// ProHUD -// -// Created by xaoxuu on 2019/8/9. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit - -public extension Guard { - - struct ViewModel { - - weak var vc: Guard? - - } - -} - -public extension Guard.ViewModel { - - /// 加载一个标题 - /// - Parameter text: 文本 - @discardableResult func add(title: String?) -> UILabel { - return vc!.add(title: title) - } - - /// 加载一个副标题 - /// - Parameter text: 文本 - @discardableResult func add(subTitle: String?) -> UILabel { - return vc!.add(subTitle: subTitle) - } - - /// 加载一段正文 - /// - Parameter text: 文本 - @discardableResult func add(message: String?) -> UILabel { - return vc!.add(message: message) - } - - /// 加载一个按钮 - /// - Parameter style: 样式 - /// - Parameter title: 标题 - /// - Parameter action: 事件 - @discardableResult func add(action style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton { - return vc!.insert(action: nil, style: style, title: title, handler: handler) - } - - /// 插入一个按钮 - /// - Parameter index: 索引 - /// - Parameter style: 样式 - /// - Parameter title: 标题 - /// - Parameter handler: 事件处理 - @discardableResult func insert(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) -> UIButton { - return vc!.insert(action: index, style: style, title: title, handler: handler) - } - - /// 更新按钮 - /// - Parameter index: 索引 - /// - Parameter style: 样式 - /// - Parameter title: 标题 - /// - Parameter handler: 事件处理 - func update(action index: Int, style: UIAlertAction.Style, title: String?, handler: (() -> Void)?) { - vc?.update(action: index, style: style, title: title, handler: handler) - } - - /// 移除按钮 - /// - Parameter index: 索引 - func remove(action index: Int...) { - for (i, idx) in index.enumerated() { - vc?.remove(index: idx-i) - } - } - - -} diff --git a/Source/HUDConfig.swift b/Source/HUDConfig.swift deleted file mode 100644 index f0a3df1..0000000 --- a/Source/HUDConfig.swift +++ /dev/null @@ -1,109 +0,0 @@ -// -// HUDConfig.swift -// ProHUD -// -// Created by xaoxuu on 2019/7/29. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit - -@available(iOS 13.0, *) fileprivate var sharedWindowScene: UIWindowScene? - -/// HUD配置 -public extension ProHUD { - struct Configuration { - - /// 是否允许log输出 - public var enablePrint = true - - /// 根控制器,默认可以自动获取,如果获取失败请主动设置 - public var rootViewController: UIViewController? - - /// iOS13必须设置此值,默认可以自动获取,如果获取失败请主动设置 - @available(iOS 13.0, *) - public var windowScene: UIWindowScene? { - set { sharedWindowScene = newValue } - get { sharedWindowScene } - } - - /// 动态颜色 - public lazy var dynamicColor: UIColor = { - if #available(iOS 13.0, *) { - let color = UIColor { (traitCollection: UITraitCollection) -> UIColor in - if traitCollection.userInterfaceStyle == .dark { - return .init(white: 1, alpha: 1) - } else { - return .init(white: 0.1, alpha: 1) - } - } - return color - } else { - // Fallback on earlier versions - } - return .init(white: 0.1, alpha: 1) - }() - - /// 主标签文本颜色 - public lazy var primaryLabelColor: UIColor = { - return dynamicColor.withAlphaComponent(0.8) - }() - - /// 次级标签文本颜色 - public lazy var secondaryLabelColor: UIColor = { - return dynamicColor.withAlphaComponent(0.66) - }() - - public func blurView(_ callback: @escaping () -> UIVisualEffectView) { - createBlurView = callback - } - - - public var toast = Toast() - public var alert = Alert() - public var `guard` = Guard() - - /// Toast的配置 - /// - Parameter callback: 回调 - public mutating func toast(_ callback: @escaping (inout Toast) -> Void) { - callback(&toast) - } - - /// Alert的配置 - /// - Parameter callback: 回调 - public mutating func alert(_ callback: @escaping (inout Alert) -> Void) { - callback(&alert) - } - - /// Guard的配置 - /// - Parameter callback: 回调 - public mutating func `guard`(_ callback: @escaping (inout Guard) -> Void) { - callback(&`guard`) - } - - } -} - -/// 配置 -internal var cfg = ProHUD.Configuration() - -public extension ProHUD { - static func config(_ config: (inout Configuration) -> Void) { - config(&cfg) - } -} - -internal var createBlurView: () -> UIVisualEffectView = { - return { - let vev = UIVisualEffectView() - if #available(iOS 13.0, *) { - vev.effect = UIBlurEffect(style: .systemMaterial) - } else if #available(iOS 11.0, *) { - vev.effect = UIBlurEffect(style: .extraLight) - } else { - vev.effect = .none - vev.backgroundColor = .white - } - return vev - } -}() diff --git a/Source/HUDController.swift b/Source/HUDController.swift deleted file mode 100644 index 6d244a3..0000000 --- a/Source/HUDController.swift +++ /dev/null @@ -1,173 +0,0 @@ -// -// HUDController.swift -// ProHUD -// -// Created by xaoxuu on 2019/7/29. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit - -public class HUDController: UIViewController { - - /// ID标识 - public var identifier = String(Date().timeIntervalSince1970) - - internal var willAppearCallback: (() -> Void)? - internal var didAppearCallback: (() -> Void)? - internal var willDisappearCallback: (() -> Void)? - internal var didDisappearCallback: (() -> Void)? - - /// 执行动画的图层 - internal var animateLayer: CALayer? - internal var animation: CAAnimation? - - internal var progressView: ProHUD.ProgressView? - - /// 按钮事件 - internal var buttonEvents = [UIButton:() -> Void]() - - init() { - super.init(nibName: nil, bundle: nil) - debug(self, "init") - } - - required public init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - deinit { - debug("👌", self, "deinit") - } - - - override public func viewDidLoad() { - super.viewDidLoad() - - // Do any additional setup after loading the view. - } - - public override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - willAppearCallback?() - } - public override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - didAppearCallback?() - } - public override func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - didDisappearCallback?() - } - - public func viewWillAppear(_ callback: (() -> Void)?) { - willAppearCallback = callback - } - public func viewDidAppear(_ callback: (() -> Void)?) { - didAppearCallback = callback - } - - public func viewWillDisappear(_ callback: (() -> Void)?) { - willDisappearCallback = callback - } - public func viewDidDisappear(_ callback: (() -> Void)?) { - didDisappearCallback = callback - } - -} - -// MARK: - 事件 -internal extension HUDController { - - func addTouchUpAction(for button: UIButton, action: @escaping () -> Void) { - button.addTarget(self, action: #selector(didTappedButton(_:)), for: .touchUpInside) - buttonEvents[button] = action - } - - @objc func didTappedButton(_ sender: UIButton) { - buttonEvents[sender]?() - } - -} - -// MARK: - 动画 - -/// 图片动画 -public protocol LoadingAnimationView: HUDController { - var imageView: UIImageView { get } -} -public extension LoadingAnimationView { - - /// 更新进度(如果需要显示进度,需要先调用一次 updateProgress(0) 来初始化) - /// - Parameter progress: 进度(0~1) - func update(progress: CGFloat) { - if let spv = imageView.superview { - if progressView == nil { - let v = ProHUD.ProgressView() - spv.addSubview(v) - v.snp.makeConstraints { (mk) in - mk.center.equalTo(imageView) - mk.width.height.equalTo(28) - } - progressView = v - } - if let v = progressView { - v.updateProgress(progress: progress) - } - } - } - -} -/// 旋转动画 -public protocol LoadingRotateAnimation: LoadingAnimationView {} -public extension LoadingRotateAnimation { - - /// 旋转动画 - /// - Parameters: - /// - layer: 图层 - /// - direction: 方向 - /// - speed: 速度 - func startRotate(_ layer: CALayer? = nil, direction: ProHUD.RotateDirection = .clockwise, speed: CFTimeInterval = 2) { - DispatchQueue.main.async { - let l = layer ?? self.imageView.layer - self.animateLayer = l - l.startRotate(direction: direction, speed: speed) - NotificationCenter.default.addObserver(self, selector: #selector(self.didEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(self.willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil) - } - } - - /// 停止旋转 - /// - Parameter layer: 图层 - func stopRotate(_ layer: CALayer? = nil) { - DispatchQueue.main.async { - self.animateLayer = nil - (layer ?? self.imageView.layer)?.stopRotate() - NotificationCenter.default.removeObserver(self, name: UIApplication.didEnterBackgroundNotification, object: nil) - NotificationCenter.default.removeObserver(self, name: UIApplication.willEnterForegroundNotification, object: nil) - } - } - -} - -/// 动画扩展 -extension HUDController { - @objc func didEnterBackground() { - if let layer = animateLayer { - animation = layer.animation(forKey: .rotateKey) - layer.timeOffset = layer.convertTime(CACurrentMediaTime(), from: nil) - layer.speed = 0 - } - } - @objc func willEnterForeground() { - if let layer = animateLayer, let ani = animation, layer.speed == 0 { - let pauseTime = layer.timeOffset - layer.timeOffset = 0 - let beginTime = layer.convertTime(CACurrentMediaTime(), from: nil) - pauseTime - layer.beginTime = beginTime - layer.speed = 1 - layer.add(ani, forKey: .rotateKey) - } - } -} - diff --git a/Source/HUDUtils.swift b/Source/HUDUtils.swift deleted file mode 100644 index a9516ff..0000000 --- a/Source/HUDUtils.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// HUDUtils.swift -// ProHUD -// -// Created by xaoxuu on 2020/6/22. -// Copyright © 2020 Titan Studio. All rights reserved. -// - -import UIKit -import Inspire - -extension String { - static let rotateKey = "rotationAnimation" -} - -extension ProHUD { - static var safeAreaInsets: UIEdgeInsets { - Inspire.shared.screen.safeAreaInsets - } -} - - -func == (left: ProHUD.Scene, right: ProHUD.Scene) -> Bool { - left.identifier == right.identifier -} - - -func != (left: ProHUD.Scene, right: ProHUD.Scene) -> Bool { - left.identifier != right.identifier -} diff --git a/Source/HUDView.swift b/Source/HUDView.swift deleted file mode 100644 index 1597b75..0000000 --- a/Source/HUDView.swift +++ /dev/null @@ -1,253 +0,0 @@ -// -// HUDView.swift -// ProHUD -// -// Created by xaoxuu on 2019/7/29. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit - -// MARK: - public - -public extension ProHUD { - - /// 堆栈视图容器 - class StackContainer: UIStackView { - - public override init(frame: CGRect) { - super.init(frame: frame) - spacing = cfg.alert.margin - distribution = .fill - alignment = .center - axis = .vertical - - } - - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - } - - /// 旋转方向 - enum RotateDirection: Double { - /// 顺时针 - case clockwise = 1 - /// 逆时针 - case counterclockwise = -1 - } - - - /// 进度指示器 - class ProgressView: UIView { - - var progressLayer = CAShapeLayer() - - override init(frame: CGRect) { - // 容器宽度 - let maxSize = CGFloat(28) - super.init(frame: .init(x: 0, y: 0, width: maxSize, height: maxSize)) - layer.cornerRadius = maxSize / 2 - layer.masksToBounds = true - // 进度圆半径 - let radius = maxSize / 2 - 4 - backgroundColor = .white - - let path = UIBezierPath(arcCenter: CGPoint(x: 14, y: 14), radius: radius/2, startAngle: -CGFloat.pi*0.5, endAngle: CGFloat.pi * 1.5, clockwise: true) - - progressLayer.fillColor = UIColor.clear.cgColor - progressLayer.path = path.cgPath - - progressLayer.strokeColor = tintColor.cgColor - progressLayer.lineWidth = radius - progressLayer.strokeStart = 0 - progressLayer.strokeEnd = 0 - layer.addSublayer(progressLayer) - - } - - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func updateProgress(progress: CGFloat) { - if progress <= 1 { - // 初始化 - if progressLayer.superlayer == nil { - progressLayer.strokeEnd = 0 - layer.addSublayer(progressLayer) - } - progressLayer.strokeEnd = progress - } - } - - } - -} - -// MARK: - internal - -// MARK: 弹窗 -internal extension Alert { - - /// 弹窗的按钮 - class Button: UIButton { - - /// 创建操作按钮 - /// - Parameter title: 标题 - /// - Returns: 按钮 - static func createActionButton(title: String?) -> Button { - let btn = Button(type: .system) - btn.setTitle(title, for: .normal) - btn.layer.cornerRadius = cfg.alert.cornerRadius / 2 - btn.titleLabel?.font = cfg.alert.buttonFont - return btn - } - - /// 更新按钮 - /// - Parameter style: 样式 - func update(style: UIAlertAction.Style) { - let pd = CGFloat(8) - if style != .cancel { - backgroundColor = cfg.dynamicColor.withAlphaComponent(0.04) - contentEdgeInsets = .init(top: pd*1.5, left: pd*1.5, bottom: pd*1.5, right: pd*1.5) - } else { - backgroundColor = .clear - contentEdgeInsets = .init(top: pd*1, left: pd*1.5, bottom: pd*1, right: pd*1.5) - } - switch style { - case .default: - setTitleColor(tintColor, for: .normal) - case .destructive: - setTitleColor(.init(red: 244/255, green: 67/255, blue: 54/255, alpha: 1), for: .normal) - case .cancel: - setTitleColor(cfg.secondaryLabelColor, for: .normal) - @unknown default: - break - } - tag = style.rawValue - } - - /// 创建隐藏按钮 - /// - Returns: 按钮 - static func createHideButton() -> UIButton { - let btn = Button(type: .system) - let pd = cfg.alert.padding/2 - btn.contentEdgeInsets = .init(top: pd*1.5, left: pd*1.5, bottom: pd*1.5, right: pd*1.5) - btn.imageEdgeInsets.right = pd*1.5 - btn.setTitleColor(UIColor(red:1.00, green:0.55, blue:0.21, alpha:1.00), for: .normal) - btn.titleLabel?.font = cfg.alert.buttonFont - return btn - } - - } - -} - -// MARK: 操作表 -internal extension Guard { - - /// 操作表的按钮 - class Button: UIButton { - - /// 创建操作按钮 - /// - Parameter title: 标题 - /// - Returns: 按钮 - static func createActionButton(title: String?) -> Button { - let btn = Button(type: .system) - btn.setTitle(title, for: .normal) - btn.layer.cornerRadius = cfg.guard.buttonCornerRadius - btn.titleLabel?.font = cfg.guard.buttonFont - return btn - } - - func update(style: UIAlertAction.Style) { - let pd = CGFloat(8) - if style != .cancel { - contentEdgeInsets = .init(top: pd*1.5+2, left: pd*1.5, bottom: pd*1.5+2, right: pd*1.5) - } else { - contentEdgeInsets = .init(top: pd*1+2, left: pd*1.5, bottom: pd*1+2, right: pd*1.5) - } - switch style { - case .default: - backgroundColor = tintColor - setTitleColor(.white, for: .normal) - case .destructive: - backgroundColor = .init(red: 244/255, green: 67/255, blue: 54/255, alpha: 1) - setTitleColor(.white, for: .normal) - case .cancel: - backgroundColor = .clear - setTitleColor(cfg.secondaryLabelColor, for: .normal) - @unknown default: - break - } - tag = style.rawValue - } - - } -} - -// MARK: - 动画 - -internal extension UIView { - - private class func animateEaseOut(duration: TimeInterval = 1, delay: TimeInterval = 0, animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) { - animate(withDuration: duration, delay: delay, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [.allowUserInteraction, .curveEaseOut], animations: animations, completion: completion) - } - - class func animateForAlertBuildIn(animations: @escaping () -> Void) { - animateEaseOut(duration: 0.8, delay: 0, animations: animations, completion: nil) - } - class func animateForAlertBuildOut(animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) { - animateEaseOut(duration: 0.38, delay: 0, animations: animations, completion: completion) - } - - class func animateForAlert(animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) { - animateEaseOut(duration: 1, delay: 0, animations: animations, completion: completion) - } - class func animateForAlert(animations: @escaping () -> Void) { - animateForAlert(animations: animations, completion: nil) - } - - class func animateForToast(animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) { - animateEaseOut(duration: 1.2, delay: 0, animations: animations, completion: completion) - } - class func animateForToast(animations: @escaping () -> Void) { - animateForToast(animations: animations, completion: nil) - } - - class func animateForGuard(animations: @escaping () -> Void, completion: ((Bool) -> Void)? = nil) { - animateEaseOut(duration: 0.45, delay: 0, animations: animations, completion: completion) - } - class func animateForGuard(animations: @escaping () -> Void) { - animateForGuard(animations: animations, completion: nil) - } - -} - - -extension CALayer { - - /// 开始旋转 - /// - Parameters: - /// - direction: 方向 - /// - speed: 速度 - func startRotate(direction: ProHUD.RotateDirection, speed: CFTimeInterval) { - if animation(forKey: .rotateKey) == nil { - let ani = CABasicAnimation(keyPath: "transform.rotation.z") - ani.toValue = direction.rawValue * Double.pi * 2.0 - if speed > 0 { - ani.duration = 2 / speed - } - ani.repeatDuration = .infinity - add(ani, forKey: .rotateKey) - } - } - - /// 停止旋转 - func stopRotate() { - removeAnimation(forKey: .rotateKey) - } - -} diff --git a/Source/ProHUD.h b/Source/ProHUD.h deleted file mode 100644 index 57853f8..0000000 --- a/Source/ProHUD.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// ProHUD.h -// ProHUD -// -// Created by xaoxuu on 2019/7/23. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -#import - -//! Project version number for ProHUD. -FOUNDATION_EXPORT double ProHUDVersionNumber; - -//! Project version string for ProHUD. -FOUNDATION_EXPORT const unsigned char ProHUDVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Source/ProHUD.swift b/Source/ProHUD.swift deleted file mode 100644 index 07a981b..0000000 --- a/Source/ProHUD.swift +++ /dev/null @@ -1,159 +0,0 @@ -// -// ProHUD.swift -// ProHUD -// -// Created by xaoxuu on 2019/7/23. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit - -public class ProHUD { - - public static let shared = ProHUD() - - public var config: Configuration { cfg } - - -} - -// MARK: - Scene -public extension ProHUD { - - struct Scene { - public let identifier: String - public var image: UIImage? - public var alertDuration: TimeInterval? - public var toastDuration: TimeInterval? = 3 - public var title: String? - public var message: String? - public init(identifier: String) { - self.identifier = identifier - } - } - -} - -// 默认场景,可直接在项目工程中覆写场景参数 -public extension ProHUD.Scene { - static var `default`: ProHUD.Scene { - var scene = ProHUD.Scene.init(identifier: "prohud.default") - scene.image = ProHUD.image(named: "prohud.note") - return scene - } - static var message: ProHUD.Scene { - var scene = ProHUD.Scene.init(identifier: "prohud.message") - scene.image = ProHUD.image(named: "prohud.message") - scene.alertDuration = 2 - scene.toastDuration = 5 - return scene - } - static var loading: ProHUD.Scene { - var scene = ProHUD.Scene.init(identifier: "prohud.loading.rotate") - scene.image = ProHUD.image(named: "prohud.rainbow.circle") - scene.title = "Loading" - scene.alertDuration = 0 - scene.toastDuration = 0 - return scene - } - static var success: ProHUD.Scene { - var scene = ProHUD.Scene.init(identifier: "prohud.success") - scene.image = ProHUD.image(named: "prohud.checkmark") - scene.title = "Success" - scene.alertDuration = 2 - return scene - } - static var warning: ProHUD.Scene { - var scene = ProHUD.Scene.init(identifier: "prohud.warning") - scene.image = ProHUD.image(named: "prohud.exclamationmark") - scene.title = "Warning" - scene.message = "Something happened." - scene.alertDuration = 2 - scene.toastDuration = 5 - return scene - } - static var error: ProHUD.Scene { - var scene = ProHUD.Scene.init(identifier: "prohud.error") - scene.image = ProHUD.image(named: "prohud.xmark") - scene.title = "Error" - scene.message = "Please try again later." - scene.alertDuration = 2 - scene.toastDuration = 5 - return scene - } - static var failure: ProHUD.Scene { - var scene = ProHUD.Scene.init(identifier: "prohud.failure") - scene.image = ProHUD.image(named: "prohud.xmark") - scene.title = "Failure" - scene.message = "Please try again later." - scene.alertDuration = 2 - scene.toastDuration = 5 - return scene - } - static var confirm: ProHUD.Scene { - var scene = ProHUD.Scene.init(identifier: "prohud.confirm") - scene.image = ProHUD.image(named: "prohud.questionmark") - scene.alertDuration = 2 - scene.toastDuration = 5 - return scene - } - static var privacy: ProHUD.Scene { - var scene = ProHUD.Scene.init(identifier: "prohud.privacy") - scene.image = ProHUD.image(named: "prohud.privacy") - scene.alertDuration = 2 - scene.toastDuration = 5 - return scene - } - static var delete: ProHUD.Scene { - var scene = ProHUD.Scene.init(identifier: "prohud.delete") - scene.image = ProHUD.image(named: "prohud.trash") - scene.alertDuration = 2 - scene.toastDuration = 5 - return scene - } - - -} - - -// MARK: - Utilities - -internal extension ProHUD { - - /// 获取Bundle - static var bundle: Bundle { - let path = Bundle(for: HUDController.self).path(forResource: "ProHUD", ofType: "bundle") - return Bundle(path: path ?? "") ?? Bundle.main - } - - /// 获取Image - static func image(named: String) -> UIImage? { - return UIImage(named: named) ?? UIImage(named: named, in: bundle, compatibleWith: nil) - } - - -} - - -/// 是否是手机竖屏模式 -internal var isPortrait: Bool { - if UIDevice.current.userInterfaceIdiom == .phone { - if UIApplication.shared.statusBarOrientation.isPortrait { - debug("当前是手机竖屏模式") - return true - } else { - debug("当前是手机横屏模式") - } - } else { - debug("非手机设备(unspecified、iPad、tv、carPlay)") - } - return false -} - -/// 可控Debug输出 -internal func debug(_ items: Any..., separator: String = " ", terminator: String = "\n") { - if cfg.enablePrint { - print(items, separator: separator, terminator: terminator) - } -} - diff --git a/Source/Toast/ToastConfig.swift b/Source/Toast/ToastConfig.swift deleted file mode 100644 index 0b3616b..0000000 --- a/Source/Toast/ToastConfig.swift +++ /dev/null @@ -1,134 +0,0 @@ -// -// cfg.toast.swift -// ProHUD -// -// Created by xaoxuu on 2019/7/31. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit -import SnapKit - -public extension UIWindow.Level { - static let proToast = UIWindow.Level.alert + 1000 -} - -public extension ProHUD.Configuration { - struct Toast { - // MARK: 卡片样式 - /// 最大宽度(用于优化横屏或者iPad显示) - public var maxWidth = CGFloat(556) - /// 圆角半径 - public var cornerRadius = CGFloat(12) - /// 余量:元素与元素之间的距离 - public var margin = CGFloat(8) - /// 填充:元素内部控件距离元素边界的距离 - public var padding = CGFloat(16) - /// 行间距 - public var lineSpace = CGFloat(4) - // MARK: 图标样式 - /// 图标尺寸 - public var iconSize = CGSize(width: 44, height: 44) - - // MARK: 文本样式 - /// 标题字体 - public var titleFont = UIFont.boldSystemFont(ofSize: 18) - /// 标题最多行数 - public var titleMaxLines = Int(5) - - /// 正文字体 - public var bodyFont = UIFont.systemFont(ofSize: 16) - /// 正文最多行数 - public var bodyMaxLines = Int(20) - - /// 更新视图 - /// - Parameter callback: 回调代码 - public mutating func reloadData(_ callback: @escaping (ProHUD.Toast) -> Void) { - privReloadData = callback - } - - - } -} - - -// MARK: - 内部调用 -extension ProHUD.Configuration.Toast { - - var reloadData: (ProHUD.Toast) -> Void { - return privReloadData - } - - -} - -// MARK: - 默认实现 -fileprivate var privReloadData: (ProHUD.Toast) -> Void = { - return { (vc) in - debug(vc, "reloadData") - let config = cfg.toast - let scene = vc.vm.scene - if vc.imageView.superview == nil { - vc.view.addSubview(vc.imageView) - } - if vc.textStack.superview == nil { - vc.view.addSubview(vc.textStack) - vc.textStack.addArrangedSubview(vc.titleLabel) - vc.textStack.addArrangedSubview(vc.bodyLabel) - } - - // 设置数据 - vc.imageView.image = vc.vm.icon ?? vc.vm.scene.image - vc.imageView.layer.removeAllAnimations() - vc.titleLabel.textColor = cfg.primaryLabelColor - vc.titleLabel.text = vc.vm.title ?? vc.vm.scene.title - vc.bodyLabel.textColor = cfg.secondaryLabelColor - vc.bodyLabel.text = vc.vm.message ?? vc.vm.scene.message - - if let count = vc.titleLabel.text?.count, count > 0 { - vc.textStack.insertArrangedSubview(vc.titleLabel, at: 0) - } else { - vc.titleLabel.removeFromSuperview() - } - if let count = vc.bodyLabel.text?.count, count > 0 { - vc.textStack.addArrangedSubview(vc.bodyLabel) - } else { - vc.bodyLabel.removeFromSuperview() - } - - // 更新布局 - vc.imageView.snp.makeConstraints { (mk) in - mk.top.equalToSuperview().offset(config.padding) - mk.leading.equalToSuperview().offset(config.padding) - mk.bottom.lessThanOrEqualToSuperview().offset(-config.padding) - mk.width.height.equalTo(config.iconSize) - } - vc.textStack.snp.makeConstraints { (mk) in - mk.top.equalToSuperview().offset(config.padding) - mk.leading.equalTo(vc.imageView.snp.trailing).offset(config.padding - 4) - mk.leading.greaterThanOrEqualToSuperview().offset(config.padding) - mk.trailing.equalToSuperview().offset(-config.padding) - mk.bottom.lessThanOrEqualToSuperview().offset(-config.padding) - } - - vc.view.layoutIfNeeded() - - // 设置持续时间 - vc.vm.updateDuration() - - // 移除动画 - vc.stopRotate(vc.animateLayer) - vc.animateLayer = nil - vc.animation = nil - - // 移除进度 - vc.progressView?.removeFromSuperview() - - // id 包含 .rotate 的会自动旋转 - if vc.vm.scene.identifier.contains(".rotate") { - vc.startRotate() - } - - } - -}() diff --git a/Source/Toast/ToastController.swift b/Source/Toast/ToastController.swift deleted file mode 100644 index ea288ab..0000000 --- a/Source/Toast/ToastController.swift +++ /dev/null @@ -1,367 +0,0 @@ -// -// ToastController.swift -// ProHUD -// -// Created by xaoxuu on 2019/7/31. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit - -public typealias Toast = ProHUD.Toast - -public extension ProHUD { - class Toast: HUDController { - - static var toasts = [Toast]() - - public var window: UIWindow? - - /// 图标 - public lazy var imageView: UIImageView = { - let imgv = UIImageView() - imgv.contentMode = .scaleAspectFit - return imgv - }() - - /// 文本区容器 - public var textStack: StackContainer = { - let stack = StackContainer() - stack.spacing = cfg.toast.lineSpace - stack.alignment = .fill - return stack - }() - - /// 标题 - public lazy var titleLabel: UILabel = { - let lb = UILabel() - lb.textColor = cfg.primaryLabelColor - lb.font = cfg.toast.titleFont - lb.textAlignment = .justified - lb.numberOfLines = cfg.toast.titleMaxLines - return lb - }() - - /// 正文 - public lazy var bodyLabel: UILabel = { - let lb = UILabel() - lb.textColor = cfg.secondaryLabelColor - lb.font = cfg.toast.bodyFont - lb.textAlignment = .justified - lb.numberOfLines = cfg.toast.bodyMaxLines - return lb - }() - - /// 背景层 - public var backgroundView: UIVisualEffectView = { - let vev = createBlurView() - vev.layer.masksToBounds = true - vev.layer.cornerRadius = cfg.toast.cornerRadius - return vev - }() - - /// 是否可以通过手势移除(向上滑出屏幕) - public var isRemovable = true - - /// 视图模型 - public var vm = ViewModel() - - var maxY = CGFloat(0) - - // MARK: 生命周期 - - /// 实例化 - /// - Parameter scene: 场景 - /// - Parameter title: 标题 - /// - Parameter message: 内容 - /// - Parameter icon: 图标 - public convenience init(scene: Scene?, title: String? = nil, message: String? = nil, icon: UIImage? = nil, duration: TimeInterval? = nil, actions: ((Toast) -> Void)? = nil) { - self.init() - vm.vc = self - - vm.scene = scene ?? .default - vm.title = title - vm.message = message - vm.icon = icon - vm.duration = duration - actions?(self) - - // 点击 - let tap = UITapGestureRecognizer(target: self, action: #selector(privDidTapped(_:))) - view.addGestureRecognizer(tap) - // 拖动 - let pan = UIPanGestureRecognizer(target: self, action: #selector(privDidPan(_:))) - view.addGestureRecognizer(pan) - - } - - - public override func viewDidLoad() { - super.viewDidLoad() - - cfg.toast.reloadData(self) - - } - - - } - -} - -// MARK: - 实例函数 -public extension Toast { - - /// 推入屏幕 - @discardableResult func push() -> Toast { - let config = cfg.toast - let isNew: Bool - if self.window == nil { - willAppearCallback?() - let window = UIWindow(frame: .zero) - self.window = window - if #available(iOS 13.0, *) { - window.windowScene = cfg.windowScene ?? .currentWindowScene - } - window.windowLevel = .proToast - window.backgroundColor = .clear - window.layer.shadowRadius = 8 - window.layer.shadowOffset = .init(width: 0, height: 5) - window.layer.shadowOpacity = 0.2 - window.isHidden = false - isNew = true - } else { - isNew = false - } - - let window = self.window! - // background & frame - // 设定正确的宽度,更新子视图 - let width = CGFloat.minimum(UIScreen.main.bounds.width - 2*config.margin, config.maxWidth) - view.frame.size = CGSize(width: width, height: 800) - titleLabel.sizeToFit() - bodyLabel.sizeToFit() - view.layoutIfNeeded() - // 更新子视图之后获取正确的高度 - var height = CGFloat(0) - for v in self.view.subviews { - height = CGFloat.maximum(v.frame.maxY, height) - } - height += config.padding - // 应用到frame - window.frame = CGRect(x: (UIScreen.main.bounds.width - width) / 2, y: 0, width: width, height: height) - backgroundView.frame.size = window.frame.size - window.insertSubview(backgroundView, at: 0) - window.rootViewController = self // 此时toast.view.frame.size会自动更新为window.frame.size - // 根据在屏幕中的顺序,确定y坐标 - if Toast.toasts.contains(self) == false { - Toast.toasts.append(self) - } - Toast.privUpdateToastsLayout() - if isNew { - window.transform = .init(translationX: 0, y: -window.frame.maxY) - UIView.animateForToast { - window.transform = .identity - } - } else { - view.layoutIfNeeded() - } - didAppearCallback?() - return self - } - - /// 弹出屏幕 - func pop() { - Toast.pop(self) - } - - - /// 更新 - /// - Parameter callback: 回调 - func update(_ callback: ((inout ViewModel) -> Void)? = nil) { - callback?(&vm) - cfg.toast.reloadData(self) - } - - /// 点击事件 - /// - Parameter callback: 事件回调 - func didTapped(_ callback: (() -> Void)?) { - vm.tapCallback = callback - } - - /// 脉冲效果 - func pulse() { - DispatchQueue.main.async { - UIView.animate(withDuration: 0.2, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [.allowUserInteraction, .curveEaseOut], animations: { - self.window?.transform = .init(scaleX: 1.04, y: 1.04) - }) { (done) in - UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 1, options: [.allowUserInteraction, .curveEaseIn], animations: { - self.window?.transform = .identity - }) { (done) in - - } - } - } - } - -} - -// MARK: 支持加载动画 -extension Toast: LoadingRotateAnimation {} - -// MARK: - 实例管理器 -public extension Toast { - - /// 创建实例并推入屏幕 - /// - Parameter toast: 场景 - /// - Parameter title: 标题 - /// - Parameter message: 内容 - /// - Parameter actions: 更多操作 - @discardableResult class func push(scene: ProHUD.Scene = .default, title: String? = nil, message: String? = nil, duration: TimeInterval? = nil, _ actions: ((Toast) -> Void)? = nil) -> Toast { - return Toast(scene: scene, title: title, message: message, duration: duration, actions: actions).push() - } - - /// 创建实例并推入屏幕 - /// - Parameters: - /// - identifier: 唯一标识 - /// - toast: 实例对象 - /// - Returns: 回调 - @discardableResult class func push(_ identifier: String, scene: ProHUD.Scene? = nil, instance: ((Toast) -> Void)? = nil) -> Toast { - if let t = find(identifier).last { - if let s = scene, s != t.vm.scene { - t.update { (vm) in - vm.scene = s - } - } - instance?(t) - return t - } else { - return Toast(scene: scene) { (tt) in - tt.identifier = identifier - instance?(tt) - }.push() - } - } - - /// 查找指定的实例 - /// - Parameter identifier: 标识 - class func find(_ identifier: String) -> [Toast] { - var tt = [Toast]() - for t in toasts { - if t.identifier == identifier { - tt.append(t) - } - } - return tt - } - - /// 查找指定的实例 - /// - Parameter identifier: 标识 - /// - Parameter last: 已经存在(获取最后一个) - class func find(_ identifier: String, last: @escaping (Toast) -> Void) { - if let t = find(identifier).last { - last(t) - } - } - - /// 弹出屏幕 - /// - Parameter toast: 实例 - class func pop(_ toast: Toast) { - toast.willDisappearCallback?() - if toasts.count > 1 { - toasts.removeAll { $0 == toast } - privUpdateToastsLayout() - } else if toasts.count == 1 { - toasts.removeAll() - } else { - debug("‼️代码漏洞:已经没有toast了") - } - UIView.animateForToast(animations: { - toast.window?.transform = .init(translationX: 0, y: -20-toast.maxY) - }) { (done) in - toast.view.removeFromSuperview() - toast.removeFromParent() - toast.window = nil - toast.didDisappearCallback?() - } - } - - /// 弹出屏幕 - /// - Parameter identifier: 指定实例的标识 - class func pop(_ identifier: String) { - for t in find(identifier) { - t.pop() - } - } - -} - -// MARK: - 创建和设置 -fileprivate var willprivUpdateToastsLayout: DispatchWorkItem? - -fileprivate extension Toast { - - /// 点击事件 - /// - Parameter sender: 手势 - @objc func privDidTapped(_ sender: UITapGestureRecognizer) { - if let cb = vm.tapCallback { - cb() - } else { - pulse() - } - } - - /// 拖拽事件 - /// - Parameter sender: 手势 - @objc func privDidPan(_ sender: UIPanGestureRecognizer) { - vm.durationBlock?.cancel() - let point = sender.translation(in: sender.view) - window?.transform = .init(translationX: 0, y: point.y) - if sender.state == .recognized { - let v = sender.velocity(in: sender.view) - if isRemovable == true && (((window?.frame.origin.y ?? 0) < 0 && v.y < 0) || v.y < -1200) { - // 移除 - self.pop() - } else { - UIView.animateForToast(animations: { - self.window?.transform = .identity - }) { (done) in - let d = self.vm.duration - self.vm.duration = d - } - } - } - } - - class func privUpdateToastsLayout() { - func f() { - let top = ProHUD.safeAreaInsets.top - for (i, e) in toasts.enumerated() { - let config = cfg.toast - if let window = e.window { - var y = window.frame.origin.y - if i == 0 { - if isPortrait { - y = top - } else { - y = config.margin - } - } else { - let lastY = toasts[i-1].window?.frame.maxY ?? .zero - y = lastY + config.margin - } - e.maxY = y + window.frame.size.height - UIView.animateForToast { - window.frame.origin.y = y - } - } - } - } - willprivUpdateToastsLayout?.cancel() - willprivUpdateToastsLayout = DispatchWorkItem(block: { - f() - }) - DispatchQueue.main.asyncAfter(deadline: .now()+0.001, execute: willprivUpdateToastsLayout!) - } - -} - diff --git a/Source/Toast/ToastModel.swift b/Source/Toast/ToastModel.swift deleted file mode 100644 index c1cd993..0000000 --- a/Source/Toast/ToastModel.swift +++ /dev/null @@ -1,72 +0,0 @@ -// -// ToastModel.swift -// ProHUD -// -// Created by xaoxuu on 2019/7/31. -// Copyright © 2019 Titan Studio. All rights reserved. -// - -import UIKit - -public extension Toast { - class ViewModel { - - /// 使用场景 - public var scene = ProHUD.Scene.default - - /// 标题 - public var title: String? { - didSet { - vc?.titleLabel.text = title - } - } - - /// 正文 - public var message: String? { - didSet { - vc?.bodyLabel.text = message - } - } - - /// 图标 - public var icon: UIImage? { - didSet { - vc?.imageView.image = icon - } - } - - /// 持续时间 - public var duration: TimeInterval? { - didSet { - updateDuration() - } - } - - public weak var vc: Toast? - - // MARK: 私有 - - /// 持续时间 - var durationBlock: DispatchWorkItem? - - /// 点击事件回调 - var tapCallback: (() -> Void)? - - func updateDuration() { - durationBlock?.cancel() - if let t = duration ?? scene.toastDuration, t > 0 { - durationBlock = DispatchWorkItem(block: { [weak self] in - if let vc = self?.vc { - if vc.buttonEvents.count == 0 { - vc.pop() - } - } - }) - DispatchQueue.main.asyncAfter(deadline: .now()+t, execute: durationBlock!) - } else { - durationBlock = nil - } - } - - } -} diff --git a/Sources/ProHUD/Alert/Alert.swift b/Sources/ProHUD/Alert/Alert.swift new file mode 100644 index 0000000..5a035bb --- /dev/null +++ b/Sources/ProHUD/Alert/Alert.swift @@ -0,0 +1,109 @@ +// +// Alert.swift +// +// +// Created by xaoxuu on 2022/8/29. +// + +import UIKit + +public class Alert: ProHUD.Controller { + + public lazy var config: Configuration = { + var cfg = Configuration() + Configuration.customShared?(cfg) + return cfg + }() + + public var progressView: ProgressView? + + /// 内容容器(包括icon、textStack、actionStack) + public lazy var contentStack: StackView = { + let stack = StackView(axis: .vertical) + stack.spacing = config.margin + stack.alignment = .center + return stack + }() + + /// 文本区容器 + public lazy var textStack: StackView = { + let stack = StackView(axis: .vertical) + stack.spacing = config.margin + stack.alignment = .center + return stack + }() + + /// 图片 + public var imageView = UIImageView() + + /// 标题 + public lazy var titleLabel: UILabel = { + let lb = UILabel() + lb.textColor = config.primaryLabelColor + lb.font = config.titleFontByDefault + lb.textAlignment = .justified + lb.numberOfLines = config.titleMaxLines + return lb + }() + + /// 正文 + public lazy var bodyLabel: UILabel = { + let lb = UILabel() + lb.textColor = config.primaryLabelColor + lb.font = config.bodyFontByDefault + lb.textAlignment = .justified + lb.numberOfLines = config.bodyMaxLines + return lb + }() + + /// 操作区域 + public lazy var actionStack: StackView = { + let stack = StackView() + stack.alignment = .fill + stack.distribution = .fill + stack.spacing = config.margin + return stack + }() + + /// 视图模型 + public var vm = ViewModel() + + public override var title: String? { + didSet { + vm.title = title + } + } + + @discardableResult public init(_ vm: ViewModel?, callback: ((_ alert: Alert) -> Void)? = nil) { + super.init() + if let vm = vm { + self.vm = vm + } + callback?(self) + DispatchQueue.main.async { + if callback != nil { + self.setDefaultAxis() + self.push() + } + } + } + + @discardableResult public convenience init(callback: ((_ alert: Alert) -> Void)?) { + self.init(nil, callback: callback) + } + + public override func viewDidLoad() { + super.viewDidLoad() + view.tintColor = config.tintColor + reloadData() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + +} + +// MARK: 动画扩展 +extension Alert: LoadingAnimation {} diff --git a/Sources/ProHUD/Alert/AlertConfiguration.swift b/Sources/ProHUD/Alert/AlertConfiguration.swift new file mode 100644 index 0000000..a041f3a --- /dev/null +++ b/Sources/ProHUD/Alert/AlertConfiguration.swift @@ -0,0 +1,44 @@ +// +// File.swift +// +// +// Created by xaoxuu on 2022/8/29. +// + +import UIKit + +public extension Alert { + + class Configuration: ProHUD.Configuration { + + /// 指定排列方向(默认两个按钮水平排列,超过时垂直排列) + public var actionAxis: NSLayoutConstraint.Axis? + + /// 堆叠深度 + public var stackDepth: CGFloat = 30 + + public var enableShadow: Bool = true + + static var customShared: ((_ config: Configuration) -> Void)? + + /// 共享配置(只能设置一次,影响所有实例) + /// - Parameter callback: 配置代码 + public static func shared(_ callback: @escaping (_ config: Configuration) -> Void) { + customShared = callback + } + + var customBackgroundViewMask: ((_ mask: UIView) -> Void)? + + /// 设置背景蒙版 + /// - Parameter callback: 自定义内容卡片蒙版代码 + public func backgroundViewMask(_ callback: @escaping (_ mask: UIView) -> Void) { + customBackgroundViewMask = callback + } + + override var animateDurationForBuildInByDefault: CGFloat { + animateDurationForBuildIn ?? 0.6 + } + + } + +} diff --git a/Sources/ProHUD/Alert/AlertConvenienceLayout.swift b/Sources/ProHUD/Alert/AlertConvenienceLayout.swift new file mode 100644 index 0000000..fd4ec4e --- /dev/null +++ b/Sources/ProHUD/Alert/AlertConvenienceLayout.swift @@ -0,0 +1,159 @@ +// +// AlertConvenienceLayout.swift +// +// +// Created by xaoxuu on 2022/9/8. +// + +import UIKit + +extension Alert: InternalConvenienceLayout { + + // MARK: 增加 + @discardableResult public func add(action: Action) -> Button { + insert(action: action, at: actionStack.arrangedSubviews.count) + } + public func insert(action: Action, at index: Int) -> Button { + let btn = Button(config: config, action: action) + if index < actionStack.arrangedSubviews.count { + actionStack.insertArrangedSubview(btn, at: index) + } else { + actionStack.addArrangedSubview(btn) + } + if actionStack.superview == nil { + reloadActionStack() + contentStack.layoutIfNeeded() + } + addTouchUpAction(for: btn) { [weak self] in + if let self = self { + action.handler?(self) + } + if action.handler == nil { + self?.pop() + } + } + if isViewLoaded { + self.actionStack.layoutIfNeeded() + UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) { + self.view.layoutIfNeeded() + } + } + return btn + } + + // MARK: 查找 + public func button(for identifier: String) -> Button? { + if let index = actionIndex(for: identifier) { + return actionStack.arrangedSubviews[index] as? Button + } + return nil + } + + // MARK: 更新 + public func update(action title: String, style: Action.Style? = nil, for identifier: String) { + if let btn = button(for: identifier), let act = btn.action { + act.title = title + if let style = style { + act.style = style + } + btn.update(config: config, action: act) + } + } + + // MARK: 删除 + public func remove(actions finder: Action.Filter) { + if finder.ids.count > 0 { + for identifier in finder.ids { + while let index = actionIndex(for: identifier), index < actionStack.arrangedSubviews.count { + let view = actionStack.arrangedSubviews[index] + actionStack.removeArrangedSubview(view) + view.removeFromSuperview() + buttonEvents[view] = nil + } + } + } else { + for view in actionStack.arrangedSubviews { + actionStack.removeArrangedSubview(view) + view.removeFromSuperview() + buttonEvents[view] = nil + } + } + if isViewLoaded { + UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) { + self.actionStack.layoutIfNeeded() + self.view.layoutIfNeeded() + } + } + } + + // MARK: 自定义控件 + + @discardableResult public func add(subview: UIView) -> UIView { + actionStack.addArrangedSubview(subview) + return subview + } + + + // MARK: 布局工具 + + public func add(spacing: CGFloat) { + if #available(iOS 11.0, *) { + if let last = actionStack.arrangedSubviews.last { + actionStack.setCustomSpacing(spacing, after: last) + } + } + } + + // MARK: 完全自定义布局 + + public func set(customView: UIView) -> UIView { + self.customView = customView + contentView.subviews.forEach({ $0.removeFromSuperview() }) + contentView.addSubview(customView) + return customView + } + + // MARK: internal + func actionIndex(for identifier: String) -> Int? { + let arr = actionStack.arrangedSubviews.compactMap({ $0 as? Button }) + for i in 0 ..< arr.count { + if arr[i].action?.identifier == identifier { + return i + } + } + return nil + } + +} + +// MARK: more +public extension Alert { + + /// 增加一个按钮 + /// - Parameters: + /// - title: 标题 + /// - style: 样式 + /// - identifier: 唯一标识符 + /// - handler: 点击事件 + /// - Returns: 按钮实例 + @discardableResult func add(action title: String, style: Action.Style = .tinted, identifier: String? = nil, handler: ((_ alert: Alert) -> Void)? = nil) -> Button { + if let handler = handler { + let action = Action(identifier: identifier, style: style, title: title) { vc in + if let vc = vc as? Alert { + handler(vc) + } + } + return add(action: action) + } else { + return add(action: .init(identifier: identifier, style: style, title: title, handler: nil)) + } + } + + func reloadTextStack() { + setupTextStack() + UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) { + self.view.layoutIfNeeded() + } + } + +} diff --git a/Sources/ProHUD/Alert/AlertDefaultLayout.swift b/Sources/ProHUD/Alert/AlertDefaultLayout.swift new file mode 100644 index 0000000..b4b506b --- /dev/null +++ b/Sources/ProHUD/Alert/AlertDefaultLayout.swift @@ -0,0 +1,247 @@ +// +// AlertDefaultLayout.swift +// +// +// Created by xaoxuu on 2022/9/9. +// + +import UIKit + +extension Alert: DefaultLayout { + + var cfg: ProHUD.Configuration { + return config + } + + func reloadDataByDefault() { + let isFirstLayout: Bool + if contentView.superview == nil { + isFirstLayout = true + // 布局主容器视图 + loadContentViewIfNeeded() + } else { + isFirstLayout = false + } + // 更新时间 + updateTimeoutDuration() + // custom layout + guard customView == nil else { + return + } + // default layout + // 更新图片 + setupImageView() + + // 更新文本容器 + setupTextStack() + + // 更新操作容器 + reloadActionStack() + contentStack.layoutIfNeeded() + contentView.layoutIfNeeded() + + // 动画 + if isFirstLayout { + view.layoutIfNeeded() + imageView.transform = .init(scaleX: 0.7, y: 0.7) + UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) { + self.view.layoutIfNeeded() + self.imageView.transform = .identity + } + } else { + UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) { + self.view.layoutIfNeeded() + } + } + // id 包含 .rotate 的会自动旋转 + if let rotation = vm.rotation { + startRotate(rotation) + } + // 设置持续时间 + vm.timeoutHandler = DispatchWorkItem(block: { [weak self] in + self?.pop() + }) + + } + + func loadContentViewIfNeeded() { + contentView.layer.cornerRadiusWithContinuous = config.cardCornerRadiusByDefault + if contentView.superview != view { + view.insertSubview(contentView, at: 0) + } + if config.enableShadow { + contentView.clipsToBounds = false + contentView.layer.shadowRadius = 4 + contentView.layer.shadowOpacity = 0.08 + } + // custom layout + guard customView == nil else { + contentView.snp.remakeConstraints { make in + make.center.equalToSuperview() + } + return + } + // default layout + contentView.snp.remakeConstraints { make in + make.center.equalToSuperview() + if customView == nil { + make.width.greaterThanOrEqualTo(config.cardMinWidth).priority(.low) + make.width.lessThanOrEqualTo(config.cardMaxWidthByDefault) + make.height.greaterThanOrEqualTo(config.cardMinHeight).priority(.low) + make.height.lessThanOrEqualTo(config.cardMaxHeightByDefault) + } + } + if contentStack.superview == nil { + contentView.addSubview(contentStack) + contentStack.spacing = config.margin + config.padding + contentStack.snp.remakeConstraints { make in + make.edges.equalTo(contentView).inset(config.padding) + } + } + // card background + if let mask = config.customContentViewMask { + mask(contentMaskView) + contentView.insertSubview(contentMaskView, at: 0) + contentMaskView.snp.remakeConstraints { make in + make.edges.equalToSuperview() + } + } else { + contentView.backgroundColor = config.dynamicBackgroundColor + } + + } + + func setDefaultAxis() { + guard isViewDisplayed == false && config.actionAxis == nil else { return } + let count = actionStack.arrangedSubviews.count + guard count < 4 else { return } + if isPortrait && count < 3 || !isPortrait { + actionStack.axis = .horizontal + actionStack.distribution = .fillEqually + } + } + + func updateTimeoutDuration() { + // 设置持续时间 + vm.timeoutHandler = DispatchWorkItem(block: { [weak self] in + self?.pop() + }) + } + +} + +extension Alert { + + func setupImageView() { + guard let icon = vm.icon else { return } + imageView.image = icon + contentStack.insertArrangedSubview(imageView, at: 0) + imageView.contentMode = .scaleAspectFit + imageView.snp.remakeConstraints { (mk) in + mk.top.left.greaterThanOrEqualTo(contentView).inset(config.padding*2.25) + mk.right.bottom.lessThanOrEqualTo(contentView).inset(config.padding*2.25) + mk.width.equalTo(config.iconSize.width) + mk.height.equalTo(config.iconSize.height) + } + // 移除动画 + stopRotate(animateLayer) + animateLayer = nil + animation = nil + + // 移除进度 + progressView?.removeFromSuperview() + } + func setupTextStack() { + let titleCount = vm.title?.count ?? 0 + let bodyCount = vm.message?.count ?? 0 + if titleCount > 0 || bodyCount > 0 { + if textStack.superview != contentStack { + if let index = contentStack.arrangedSubviews.firstIndex(of: imageView) { + contentStack.insertArrangedSubview(textStack, at: index + 1) + } else { + contentStack.insertArrangedSubview(textStack, at: 0) + } + textStack.snp.remakeConstraints { (mk) in + mk.top.greaterThanOrEqualTo(contentView).inset(config.padding*1.75) + mk.bottom.lessThanOrEqualTo(contentView).inset(config.padding*1.75) + if UIScreen.main.bounds.width < 414 { + mk.left.greaterThanOrEqualTo(contentView).inset(config.padding*1.5) + mk.right.lessThanOrEqualTo(contentView).inset(config.padding*1.5) + } else { + mk.left.greaterThanOrEqualTo(contentView).inset(config.padding*2) + mk.right.lessThanOrEqualTo(contentView).inset(config.padding*2) + } + } + } + if titleCount > 0 { + titleLabel.text = vm.title + if titleLabel.superview != textStack { + textStack.insertArrangedSubview(titleLabel, at: 0) + } + if bodyCount > 0 { + // 有message + titleLabel.font = config.titleFontByDefault + } else { + // 没有message + titleLabel.font = config.boldTextFontByDefault + } + } else { + if textStack.arrangedSubviews.contains(titleLabel) { + textStack.removeArrangedSubview(titleLabel) + } + titleLabel.removeFromSuperview() + } + if bodyCount > 0 { + bodyLabel.text = vm.message + if bodyLabel.superview != textStack { + textStack.addArrangedSubview(bodyLabel) + } + if titleCount > 0 { + // 有title + bodyLabel.font = config.bodyFontByDefault + } else { + // 没有title + bodyLabel.font = config.boldTextFontByDefault + } + } else { + if textStack.arrangedSubviews.contains(bodyLabel) { + textStack.removeArrangedSubview(bodyLabel) + } + bodyLabel.removeFromSuperview() + } + } else { + textStack.removeFromSuperview() + } + textStack.layoutIfNeeded() + } + + func reloadActionStack() { + if actionStack.arrangedSubviews.count > 0 { + if actionStack.superview == nil { + contentStack.addArrangedSubview(actionStack) + actionStack.snp.remakeConstraints { (mk) in + mk.width.greaterThanOrEqualTo(180) + mk.left.right.equalToSuperview() + } + } + if let axis = config.actionAxis { + actionStack.axis = axis + } + } else { + // 无按钮 + for v in actionStack.arrangedSubviews { + v.removeFromSuperview() + } + actionStack.removeFromSuperview() + } + actionStack.layoutIfNeeded() + } + + public override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + if config.enableShadow { + contentView.layer.shadowPath = UIBezierPath.init(rect: contentView.bounds).cgPath + } + } + +} diff --git a/Sources/ProHUD/Alert/AlertManager.swift b/Sources/ProHUD/Alert/AlertManager.swift new file mode 100644 index 0000000..14c74ca --- /dev/null +++ b/Sources/ProHUD/Alert/AlertManager.swift @@ -0,0 +1,151 @@ +// +// AlertManager.swift +// +// +// Created by xaoxuu on 2022/8/31. +// + +import UIKit + +extension Alert: HUD { + + public func push() { + guard AlertWindow.alerts.contains(self) == false else { + return + } + let window = attachedWindow + view.transform = .init(scaleX: 1.2, y: 1.2) + view.alpha = 0 + navEvents[.onViewWillAppear]?(self) + window.vc.addChild(self) + window.vc.view.addSubview(view) + view.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + UIView.animateEaseOut(duration: config.animateDurationForBuildIn ?? config.animateDurationForBuildInByDefault) { + self.view.transform = .identity + self.view.alpha = 1 + if let f = self.config.customBackgroundViewMask { + f(window.backgroundView) + } + window.backgroundView.alpha = 1 + } completion: { done in + self.navEvents[.onViewDidAppear]?(self) + } + AlertWindow.alerts.append(self) + Alert.updateAlertsLayout() + } + + public func pop() { + navEvents[.onViewWillDisappear]?(self) + let window = attachedWindow + Alert.removeAlert(alert: self) + let duration = config.animateDurationForBuildOut ?? config.animateDurationForBuildOutByDefault + UIView.animateEaseOut(duration: duration) { + self.view.alpha = 0 + self.view.transform = .init(scaleX: 1.08, y: 1.08) + } completion: { done in + self.view.removeFromSuperview() + self.removeFromParent() + self.navEvents[.onViewDidDisappear]?(self) + } + // hide window + let count = AlertWindow.alerts.count + if count == 0 && AlertWindow.current != nil { + UIView.animateEaseOut(duration: duration) { + window.backgroundView.alpha = 0 + } completion: { done in + if AlertWindow.alerts.count == 0 { + AlertWindow.current = nil + } + } + } + } + +} + +extension Alert { + + /// 如果不存在就创建并弹出一个HUD实例,如果存在就更新实例 + /// - Parameters: + /// - identifier: 实例唯一标识符(如果为空,则以代码位置为唯一标识符) + /// - callback: 实例创建代码 + public static func lazyPush(identifier: String? = nil, file: String = #file, line: Int = #line, callback: @escaping (_ alert: Alert) -> Void) { + let id = identifier ?? (file + "#\(line)") + if let vc = AlertWindow.alerts.last(where: { $0.identifier == id }) { + callback(vc) + vc.reloadData() + } else { + Alert { hud in + hud.identifier = id + callback(hud) + }.push() + } + } + + /// 更新HUD实例 + /// - Parameter callback: 实例更新代码 + public func update(callback: @escaping (_ alert: Alert) -> Void) { + callback(self) + } + + /// 更新HUD实例 + /// - Parameters: + /// - identifier: 唯一标识符 + /// - callback: 实例更新代码 + public static func update(identifier: String, callback: @escaping (_ alert: Alert) -> Void) { + guard let vc = AlertWindow.alerts.last(where: { $0.identifier == identifier }) else { + return + } + callback(vc) + vc.reloadData() + } + + /// 查找HUD实例 + /// - Parameter identifier: 唯一标识符 + /// - Returns: HUD实例 + public static func find(identifier: String) -> Alert? { + guard let vc = AlertWindow.alerts.last(where: { $0.identifier == identifier }) else { + return nil + } + return vc + } + +} + +fileprivate extension Alert { + static func updateAlertsLayout() { + for (i, a) in AlertWindow.alerts.reversed().enumerated() { + let scale = CGFloat(pow(0.9, CGFloat(i))) + UIView.animate(withDuration: 1.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.5, options: [.allowUserInteraction, .curveEaseInOut], animations: { + let y = 0 - a.config.stackDepth * CGFloat(i) * CGFloat(pow(0.85, CGFloat(i))) + a.view.transform = CGAffineTransform.init(translationX: 0, y: y).scaledBy(x: scale, y: scale) + }) { (done) in + + } + } + } + + var attachedWindow: AlertWindow { + AlertWindow.attachedWindow(config: config) + } + + static func removeAlert(alert: Alert) { + if AlertWindow.alerts.count > 1 { + for (i, a) in AlertWindow.alerts.enumerated() { + if a == alert { + if i < AlertWindow.alerts.count { + AlertWindow.alerts.remove(at: i) + } + } + } + updateAlertsLayout() + } else if AlertWindow.alerts.count == 1 { + AlertWindow.alerts.removeAll() + } else { + print("‼️代码漏洞:已经没有alert了") + } + } + +} + diff --git a/Sources/ProHUD/Alert/AlertWindow.swift b/Sources/ProHUD/Alert/AlertWindow.swift new file mode 100644 index 0000000..ffcba43 --- /dev/null +++ b/Sources/ProHUD/Alert/AlertWindow.swift @@ -0,0 +1,38 @@ +// +// AlertWindow.swift +// +// +// Created by xaoxuu on 2022/9/8. +// + +import UIKit + +class AlertWindow: Window { + + static var current: AlertWindow? + + static var alerts = [Alert]() + + override var usingBackground: Bool { true } + + static func attachedWindow(config: Configuration) -> AlertWindow { + if let w = AlertWindow.current { + return w + } + let w: AlertWindow + if #available(iOS 13.0, *) { + if let scene = config.windowScene ?? UIApplication.shared.windows.last?.windowScene { + w = .init(windowScene: scene) + } else { + w = .init(frame: UIScreen.main.bounds) + } + } else { + w = .init(frame: UIScreen.main.bounds) + } + AlertWindow.current = w + // 比原生alert层级低一点 + w.windowLevel = .init(rawValue: UIWindow.Level.alert.rawValue - 1) + return w + } + +} diff --git a/Sources/ProHUD/Core/Controllers/Controller.swift b/Sources/ProHUD/Core/Controllers/Controller.swift new file mode 100644 index 0000000..3a8c4a2 --- /dev/null +++ b/Sources/ProHUD/Core/Controllers/Controller.swift @@ -0,0 +1,106 @@ +// +// Controller.swift +// +// +// Created by xaoxuu on 2022/8/29. +// + +import UIKit + +open class Controller: UIViewController { + + /// ID标识 + public var identifier = String(Date().timeIntervalSince1970) + + /// 执行动画的图层 + var animateLayer: CALayer? + var animation: CAAnimation? + + open lazy var contentView: ContentView = ContentView() + + open lazy var contentMaskView: UIVisualEffectView = UIVisualEffectView() + + open var customView: UIView? + + public internal(set) var isViewDisplayed = false + /// 按钮事件 + var buttonEvents = [UIView: () -> Void]() + + public init() { + super.init(nibName: nil, bundle: nil) + consolePrint(self, "init") + } + + required public init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + deinit { + consolePrint("👌", self, "init") + } + + override public func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + // will appear + + enum NavEvent: String { + case onViewDidLoad = "onViewDidLoad" + case onViewWillAppear = "onViewWillAppear" + case onViewDidAppear = "onViewDidAppear" + case onViewWillDisappear = "onViewWillDisappear" + case onViewDidDisappear = "onViewDidDisappear" + case onTappedBackground = "onTappedBackground" + } + + var navEvents = [NavEvent: ((Controller) -> Void)]() + + @discardableResult public func onViewWillAppear(_ callback: ((_ vc: Controller) -> Void)?) -> Controller { + navEvents[.onViewWillAppear] = callback + return self + } + + @discardableResult public func onViewDidAppear(_ callback: ((_ vc: Controller) -> Void)?) -> Controller { + navEvents[.onViewDidAppear] = callback + return self + } + + @discardableResult public func onViewWillDisappear(_ callback: ((_ vc: Controller) -> Void)?) -> Controller { + navEvents[.onViewWillDisappear] = callback + return self + } + + @discardableResult public func onViewDidDisappear(_ callback: ((_ vc: Controller) -> Void)?) -> Controller { + navEvents[.onViewDidDisappear] = callback + return self + } + + open override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + isViewDisplayed = true + } + +} + +// MARK: - 事件 +extension Controller { + + func addTouchUpAction(for button: UIButton, action: @escaping () -> Void) { + button.addTarget(self, action: #selector(didTappedButton(_:)), for: .touchUpInside) + buttonEvents[button] = action + } + + @objc func didTappedButton(_ sender: UIButton) { + if let ac = buttonEvents[sender] { + ac() + } + } + + func removeTouchUpAction(for button: UIButton) { + buttonEvents[button] = nil + } + +} diff --git a/Sources/ProHUD/Core/Models/Action.swift b/Sources/ProHUD/Core/Models/Action.swift new file mode 100644 index 0000000..ebb1cc6 --- /dev/null +++ b/Sources/ProHUD/Core/Models/Action.swift @@ -0,0 +1,55 @@ +// +// Action.swift +// +// +// Created by xaoxuu on 2022/8/29. +// + +import UIKit + +open class Action: NSObject { + + /// 筛选过滤 + public struct Filter { + public static var all: Filter { .init() } + var ids = [String]() + init(identifiers: [String] = []) { + self.ids = identifiers + } + public static func identifiers(_ ids: String...) -> Filter { + .init(identifiers: ids) + } + } + + /// 按钮样式 + public enum Style { + case tinted // default, background with tintColor + case gray // cancel button + case destructive // red button, background with systemRed + case filled(color: UIColor) // background with custom color + case light(color: UIColor) // light background with custom color, text with custom color + } + + public private(set) var identifier: String? + + open var style: Style = .tinted + + open var title: String? + + open var handler: ((_ vc: HUD) -> Void)? + + public init(identifier: String? = nil, style: Style = .tinted, title: String?, handler: ((_ vc: HUD) -> Void)? = nil) { + self.identifier = identifier + self.style = style + self.title = title + self.handler = handler + } + +} + +extension Action.Filter: ExpressibleByStringLiteral { + public typealias StringLiteralType = String + public init(stringLiteral value: String) { + self.init(identifiers: [value]) + } +} diff --git a/Sources/ProHUD/Core/Models/Configuration.swift b/Sources/ProHUD/Core/Models/Configuration.swift new file mode 100644 index 0000000..7afaac3 --- /dev/null +++ b/Sources/ProHUD/Core/Models/Configuration.swift @@ -0,0 +1,169 @@ +// +// Configuration.swift +// +// +// Created by xaoxuu on 2022/8/29. +// + +import UIKit + +public class Configuration: NSObject { + + /// 是否允许log输出 + public static var enablePrint = true + + /// 根控制器,默认可以自动获取,如果获取失败请主动设置 + public var rootViewController: UIViewController? + + /// iOS13必须设置此值,默认可以自动获取,如果获取失败请主动设置 + @available(iOS 13.0, *) + private static var sharedWindowScene: UIWindowScene? + + /// iOS13必须设置此值,默认可以自动获取,如果获取失败请主动设置 + @available(iOS 13.0, *) + public var windowScene: UIWindowScene? { + set { + Self.sharedWindowScene = newValue + } + get { + return Self.sharedWindowScene + } + } + + public lazy var dynamicBackgroundColor: UIColor = { + if #available(iOS 13.0, *) { + let color = UIColor { (traitCollection: UITraitCollection) -> UIColor in + if traitCollection.userInterfaceStyle == .dark { + return .init(white: 0.15, alpha: 1) + } else { + return .init(white: 1, alpha: 1) + } + } + return color + } else { + // Fallback on earlier versions + } + return .init(white: 1, alpha: 1) + }() + + /// 动态颜色(适配iOS13) + public lazy var dynamicTextColor: UIColor = { + if #available(iOS 13.0, *) { + let color = UIColor { (traitCollection: UITraitCollection) -> UIColor in + if traitCollection.userInterfaceStyle == .dark { + return .init(white: 1, alpha: 1) + } else { + return .init(white: 0.1, alpha: 1) + } + } + return color + } else { + // Fallback on earlier versions + } + return .init(white: 0.1, alpha: 1) + }() + + /// 主标签文本颜色 + public lazy var primaryLabelColor: UIColor = { + dynamicTextColor.withAlphaComponent(0.9) + }() + + /// 次级标签文本颜色 + public lazy var secondaryLabelColor: UIColor = { + return dynamicTextColor.withAlphaComponent(0.8) + }() + + + // MARK: 卡片样式 + /// 最大宽度(用于优化横屏或者iPad显示) + public var cardMaxWidth: CGFloat? + var cardMaxWidthByDefault: CGFloat { + cardMaxWidth ?? .minimum(UIScreen.main.bounds.width * 0.72, 400) + } + + public var cardMaxHeight: CGFloat? + var cardMaxHeightByDefault: CGFloat { + cardMaxHeight ?? (UIScreen.main.bounds.height - 100) + } + /// 最小宽度 + public var cardMinWidth = CGFloat(32) + /// 最小高度 + public var cardMinHeight = CGFloat(32) + + /// 卡片圆角 + public var cardCornerRadius: CGFloat? + var cardCornerRadiusByDefault: CGFloat { cardCornerRadius ?? 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? + var titleFontByDefault: UIFont { titleFont ?? .boldSystemFont(ofSize: 20) } + + /// 标题最多行数 + public var titleMaxLines = Int(5) + + /// 加粗字体(如果只有标题或者只有正文,则显示这种字体) + public var boldTextFont: UIFont? + var boldTextFontByDefault: UIFont { boldTextFont ?? .boldSystemFont(ofSize: 18) } + + /// 正文字体 + public var bodyFont: UIFont? + var bodyFontByDefault: UIFont { bodyFont ?? .systemFont(ofSize: 17) } + + /// 正文最多行数 + public var bodyMaxLines = Int(20) + + // MARK: 按钮样式 + /// 按钮字体 + public var buttonFont: UIFont? + var buttonFontByDefault: UIFont { buttonFont ?? .boldSystemFont(ofSize: 15) } + + /// 按钮圆角 + public var buttonCornerRadius: CGFloat? + var buttonCornerRadiusByDefault: CGFloat { buttonCornerRadius ?? 8 } + + // MARK: 动画 + + public var animateDurationForBuildIn: TimeInterval? + var animateDurationForBuildInByDefault: CGFloat { animateDurationForBuildIn ?? 0.5 } + + public var animateDurationForBuildOut: TimeInterval? + var animateDurationForBuildOutByDefault: CGFloat { animateDurationForBuildOut ?? 0.38 } + + public var animateDurationForReload: TimeInterval? + var animateDurationForReloadByDefault: CGFloat { animateDurationForReload ?? 0.8 } + + + // MARK: 自定义 + + var customReloadData: ((_ vc: Controller) -> Bool)? + + /// 自定义刷新规则( ⚠️ 自定义此函数之后,整个容器将不再走默认布局规则,可实现完全自定义) + /// - Parameter callback: 自定义刷新规则代码 + public func reloadData(_ callback: @escaping (_ vc: Controller) -> Bool) { + customReloadData = callback + } + + /// 自定义内容卡片蒙版 + var customContentViewMask: ((_ mask: UIVisualEffectView) -> Void)? + + /// 设置内容卡片蒙版 + /// - Parameter callback: 自定义内容卡片蒙版代码 + public func contentViewMask(_ callback: @escaping (_ mask: UIVisualEffectView) -> Void) { + customContentViewMask = callback + } + +} + diff --git a/Sources/ProHUD/Core/Models/Rotation.swift b/Sources/ProHUD/Core/Models/Rotation.swift new file mode 100644 index 0000000..d791af4 --- /dev/null +++ b/Sources/ProHUD/Core/Models/Rotation.swift @@ -0,0 +1,32 @@ +// +// Rotation.swift +// +// +// Created by xaoxuu on 2022/8/31. +// + +import Foundation + +public struct Rotation { + + /// 旋转方向 + public enum Direction: Double { + /// 顺时针 + case clockwise = 1 + /// 逆时针 + case counterclockwise = -1 + } + + public var direction: Direction = .clockwise + + public var speed: CFTimeInterval = 2 + + public var repeatCount: Float = .infinity + + public init(direction: Direction = .clockwise, speed: CFTimeInterval = 2, repeatCount: Float = .infinity) { + self.direction = direction + self.speed = speed + self.repeatCount = repeatCount + } + +} diff --git a/Sources/ProHUD/Core/Models/ViewModel.swift b/Sources/ProHUD/Core/Models/ViewModel.swift new file mode 100644 index 0000000..53e3b75 --- /dev/null +++ b/Sources/ProHUD/Core/Models/ViewModel.swift @@ -0,0 +1,159 @@ +// +// ViewModel.swift +// +// +// Created by xaoxuu on 2022/8/29. +// + +import UIKit + +/// 数据模型 +open class ViewModel: NSObject { + + /// 图标 + open var icon: UIImage? + + /// 图标旋转动画 + open var rotation: Rotation? + + /// 标题 + open var title: String? + + /// 消息正文 + open var message: String? + + /// 持续时间(为空代表根据场景不同的默认配置,为0代表无穷大) + open var duration: TimeInterval? { + didSet { + resetTimeoutHandler() + } + } + + public convenience init(icon: UIImage? = nil, duration: TimeInterval? = nil) { + self.init() + self.icon = icon + self.duration = duration + } + + /// 超时处理 + var timeoutHandler: DispatchWorkItem? { + didSet { + resetTimeoutHandler() + } + } + + var timeoutTimer: Timer? + + func resetTimeoutHandler() { + timeoutTimer?.invalidate() + timeoutTimer = nil + if let t = duration, t > 0 { + let timer = Timer(timeInterval: t, repeats: false, block: { [weak self] t in + self?.timeoutHandler?.perform() + }) + RunLoop.main.add(timer, forMode: .common) + timeoutTimer = timer + } + } + +} + +// MARK: - convenience func +public extension ViewModel { + + func icon(_ image: UIImage?) -> ViewModel { + self.icon = image + return self + } + + func title(_ text: String?) -> ViewModel { + self.title = text + return self + } + + func message(_ text: String?) -> ViewModel { + self.message = text + return self + } + + func duration(_ seconds: TimeInterval?) -> ViewModel { + self.duration = seconds + return self + } + +} + +// MARK: - example scenes +public extension ViewModel { + + // MARK: plain + static func title(_ text: String?) -> ViewModel { + let obj = ViewModel() + obj.title = text + return obj + } + static func message(_ text: String?) -> ViewModel { + let obj = ViewModel() + obj.message = text + return obj + } + + static func text(title: String?, message: String?) -> ViewModel { + let obj = ViewModel() + obj.title = title + obj.message = message + return obj + } + + // MARK: note + static var note: ViewModel { + .init(icon: UIImage(inProHUD: "prohud.note")) + } + static func note(_ seconds: TimeInterval) -> ViewModel { + .init(icon: UIImage(inProHUD: "prohud.note"), duration: seconds) + } + // MARK: loading + static var loading: ViewModel { + let obj = ViewModel(icon: UIImage(inProHUD: "prohud.rainbow.circle")) + obj.rotation = .init(repeatCount: .infinity) + return obj + } + static func loading(_ seconds: TimeInterval) -> ViewModel { + let obj = ViewModel(icon: UIImage(inProHUD: "prohud.rainbow.circle"), duration: seconds) + obj.rotation = .init(repeatCount: .infinity) + return obj + } + // MARK: success + static var success: ViewModel { + .init(icon: UIImage(inProHUD: "prohud.checkmark")) + } + static func success(_ seconds: TimeInterval) -> ViewModel { + .init(icon: UIImage(inProHUD: "prohud.checkmark"), duration: seconds) + } + // MARK: warning + static var warning: ViewModel { + .init(icon: UIImage(inProHUD: "prohud.exclamationmark")) + } + static func warning(_ seconds: TimeInterval) -> ViewModel { + .init(icon: UIImage(inProHUD: "prohud.exclamationmark"), duration: seconds) + } + // MARK: error + static var error: ViewModel { + .init(icon: UIImage(inProHUD: "prohud.xmark")) + } + static func error(_ seconds: TimeInterval) -> ViewModel { + .init(icon: UIImage(inProHUD: "prohud.xmark"), duration: seconds) + } + // MARK: failure + static var failure: ViewModel { error } + static func failure(_ seconds: TimeInterval) -> ViewModel { error(seconds) } + + // MARK: confirm + static var confirm: ViewModel { + .init(icon: UIImage(inProHUD: "prohud.questionmark")) + } + static func confirm(_ seconds: TimeInterval) -> ViewModel { + .init(icon: UIImage(inProHUD: "prohud.questionmark"), duration: seconds) + } + +} diff --git a/Sources/ProHUD/Core/Protocols/CommonLayout.swift b/Sources/ProHUD/Core/Protocols/CommonLayout.swift new file mode 100644 index 0000000..b14808a --- /dev/null +++ b/Sources/ProHUD/Core/Protocols/CommonLayout.swift @@ -0,0 +1,30 @@ +// +// CommonLayout.swift +// +// +// Created by xaoxuu on 2022/9/9. +// + +import Foundation + +public protocol CommonLayout: Controller { + func reloadData() +} + +public extension CommonLayout { + + func reloadData() { + guard let self = self as? DefaultLayout else { + return + } + if self.cfg.customReloadData?(self) == true { + return + } + self.reloadDataByDefault() + } + +} + +extension CommonLayout { + +} diff --git a/Sources/ProHUD/Core/Protocols/ConvenienceLayout.swift b/Sources/ProHUD/Core/Protocols/ConvenienceLayout.swift new file mode 100644 index 0000000..8145205 --- /dev/null +++ b/Sources/ProHUD/Core/Protocols/ConvenienceLayout.swift @@ -0,0 +1,94 @@ +// +// LayoutProtocol.swift +// +// +// Created by xaoxuu on 2022/8/29. +// + +import UIKit + +public protocol ConvenienceLayout { + + // MARK: 增加 + + /// 增加按钮 + /// - Parameter action: 按钮模型 + /// - Returns: 按钮实例 + @discardableResult func add(action: Action) -> Button + + /// 插入按钮 + /// - Parameters: + /// - action: 按钮模型 + /// - index: 位置 + /// - Returns: 按钮实例 + @discardableResult func insert(action: Action, at index: Int) -> Button + + // MARK: 查找 + + /// 查找某个按钮实例 + /// - Parameter identifier: 按钮唯一标识符 + /// - Returns: 按钮实例 + func button(for identifier: String) -> Button? + + // MARK: 更新 + + /// 更新按钮 + /// - Parameters: + /// - title: 标题 + /// - style: 样式 + /// - identifier: 按钮唯一标识符 + func update(action title: String, style: Action.Style?, for identifier: String) + + // MARK: 删除 + + /// 删除按钮 + /// - Parameter finder: 按钮查找器 + func remove(actions finder: Action.Filter) + + // MARK: 自定义控件 + + /// 增加自定义视图(无法通过唯一标识符管理) + /// - Parameter subview: 自定义子视图 + /// - Returns: 自定义子视图 + @discardableResult func add(subview: UIView) -> UIView + + // MARK: 布局工具 + + /// 增加空隙(仅iOS11以上可用) + /// - Parameter spacing: 自定义空隙 + func add(spacing: CGFloat) + + // MARK: 自定义布局 + + /// 设置自定义视图,调用此func之后标题、正文以及其它actions设置将失效 + /// - Parameter customView: 自定义视图 + @discardableResult func set(customView: UIView) -> UIView + +} + +public extension ConvenienceLayout { + + func insert(action: Action, after id: String) { + guard let self = self as? InternalConvenienceLayout, let index = self.actionIndex(for: id) else { + return + } + insert(action: action, at: index + 1) + } + + func insert(action: Action, before id: String) { + guard let self = self as? InternalConvenienceLayout, let index = self.actionIndex(for: id) else { + return + } + insert(action: action, at: index) + } + +} + +protocol InternalConvenienceLayout: ConvenienceLayout { + + /// 查找某个按钮索引 + /// - Parameter identifier: 按钮唯一标识符 + /// - Returns: 按钮索引 + func actionIndex(for identifier: String) -> Int? + +} diff --git a/Sources/ProHUD/Core/Protocols/DefaultLayout.swift b/Sources/ProHUD/Core/Protocols/DefaultLayout.swift new file mode 100644 index 0000000..723a721 --- /dev/null +++ b/Sources/ProHUD/Core/Protocols/DefaultLayout.swift @@ -0,0 +1,38 @@ +// +// DefaultLayout.swift +// +// +// Created by xaoxuu on 2022/9/9. +// + +import UIKit + +protocol DefaultLayout: CommonLayout { + + var cfg: Configuration { get } + + func reloadDataByDefault() + + func loadContentViewIfNeeded() + +} + +extension DefaultLayout { + func loadContentMaskViewIfNeeded() { + guard contentMaskView.superview != contentView else { + return + } + if let mask = cfg.customContentViewMask { + mask(contentMaskView) + } else { + contentMaskView.effect = .none + contentMaskView.backgroundColor = cfg.dynamicBackgroundColor + } + contentView.insertSubview(contentMaskView, at: 0) + contentView.backgroundColor = .clear + contentMaskView.snp.remakeConstraints { make in + make.edges.equalToSuperview() + } + } +} + diff --git a/Sources/ProHUD/Core/Protocols/HUD.swift b/Sources/ProHUD/Core/Protocols/HUD.swift new file mode 100644 index 0000000..ba50838 --- /dev/null +++ b/Sources/ProHUD/Core/Protocols/HUD.swift @@ -0,0 +1,13 @@ +// +// ProHUD.swift +// +// +// Created by xaoxuu on 2022/8/29. +// + +import Foundation + +public protocol HUD { + func push() + func pop() +} diff --git a/Sources/ProHUD/Core/Protocols/LoadingAnimation.swift b/Sources/ProHUD/Core/Protocols/LoadingAnimation.swift new file mode 100644 index 0000000..1a08e02 --- /dev/null +++ b/Sources/ProHUD/Core/Protocols/LoadingAnimation.swift @@ -0,0 +1,20 @@ +// +// LoadingAnimation.swift +// +// +// Created by xaoxuu on 2022/9/1. +// + +import UIKit + +/// 加载动画 +public protocol LoadingAnimation: Controller { + + var imageView: UIImageView { get } + var progressView: ProgressView? { get set } + + /// 更新进度 + /// - Parameter progress: 进度百分比(0~1) + func update(progress: CGFloat) + +} diff --git a/Sources/ProHUD/Core/Utils/ConsolePrint.swift b/Sources/ProHUD/Core/Utils/ConsolePrint.swift new file mode 100644 index 0000000..089b29f --- /dev/null +++ b/Sources/ProHUD/Core/Utils/ConsolePrint.swift @@ -0,0 +1,15 @@ +// +// ConsolePrint.swift +// +// +// Created by xaoxuu on 2022/8/31. +// + +import Foundation + +func consolePrint(_ items: Any...) { + #if DEBUG + guard Configuration.enablePrint else { return } + print(">> ProHUD: ", items) + #endif +} diff --git a/Sources/ProHUD/Core/Utils/LayerExts.swift b/Sources/ProHUD/Core/Utils/LayerExts.swift new file mode 100644 index 0000000..9cf4a54 --- /dev/null +++ b/Sources/ProHUD/Core/Utils/LayerExts.swift @@ -0,0 +1,55 @@ +// +// LayerExts.swift +// +// +// Created by xaoxuu on 2022/8/31. +// + +import UIKit + +// MARK: 圆角 + +extension CALayer { + var cornerRadiusWithContinuous: CGFloat { + set { + cornerRadius = newValue + if #available(iOS 13.0, *) { + cornerCurve = .continuous + } else { + // Fallback on earlier versions + } + } + get { cornerRadius } + } +} + +// MARK: - 旋转动画 + +extension String { + static let rotateKey = "rotationAnimation" +} + +extension CALayer { + + /// 开始旋转 + /// - Parameters: + /// - direction: 方向 + /// - speed: 速度 + func startRotate(_ rotate: Rotation) { + if animation(forKey: .rotateKey) == nil { + let ani = CABasicAnimation(keyPath: "transform.rotation.z") + ani.toValue = rotate.direction.rawValue * Double.pi * 2.0 + if speed > 0 { + ani.duration = 2 / rotate.speed + } + ani.repeatCount = rotate.repeatCount + add(ani, forKey: .rotateKey) + } + } + + /// 停止旋转 + func stopRotate() { + removeAnimation(forKey: .rotateKey) + } + +} diff --git a/Sources/ProHUD/Core/Utils/RotateAnimation.swift b/Sources/ProHUD/Core/Utils/RotateAnimation.swift new file mode 100644 index 0000000..2f13d88 --- /dev/null +++ b/Sources/ProHUD/Core/Utils/RotateAnimation.swift @@ -0,0 +1,78 @@ +// +// File.swift +// +// +// Created by xaoxuu on 2022/8/29. +// + +import UIKit + +extension LoadingAnimation { + + /// 更新进度(如果需要显示进度,需要先调用一次 updateProgress(0) 来初始化) + /// - Parameter progress: 进度(0~1) + public func update(progress: CGFloat) { + guard let superview = imageView.superview else { return } + if progressView == nil { + let v = ProgressView() + superview.addSubview(v) + v.snp.remakeConstraints { (mk) in + mk.center.equalTo(imageView) + mk.width.height.equalTo(28) + } + progressView = v + } + if let v = progressView { + v.updateProgress(progress: progress) + } + } + + /// 旋转动画 + /// - Parameters: + /// - layer: 图层 + /// - direction: 方向 + /// - speed: 速度 + func startRotate(_ rotate: Rotation, at layer: CALayer? = nil) { + DispatchQueue.main.async { + let l = layer ?? self.imageView.layer + self.animateLayer = l + l.startRotate(rotate) + NotificationCenter.default.addObserver(self, selector: #selector(self.pauseLoadingAnimation), name: UIApplication.didEnterBackgroundNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(self.resumeLoadingAnimation), name: UIApplication.willEnterForegroundNotification, object: nil) + } + } + + /// 停止旋转 + /// - Parameter layer: 图层 + func stopRotate(_ layer: CALayer? = nil) { + DispatchQueue.main.async { + self.animateLayer = nil + (layer ?? self.imageView.layer)?.stopRotate() + NotificationCenter.default.removeObserver(self, name: UIApplication.didEnterBackgroundNotification, object: nil) + NotificationCenter.default.removeObserver(self, name: UIApplication.willEnterForegroundNotification, object: nil) + } + } + +} + +/// 动画扩展 +extension Controller { + @objc func pauseLoadingAnimation() { + if let layer = animateLayer { + animation = layer.animation(forKey: .rotateKey) + layer.timeOffset = layer.convertTime(CACurrentMediaTime(), from: nil) + layer.speed = 0 + } + } + @objc func resumeLoadingAnimation() { + if let layer = animateLayer, let ani = animation, layer.speed == 0 { + let pauseTime = layer.timeOffset + layer.timeOffset = 0 + let beginTime = layer.convertTime(CACurrentMediaTime(), from: nil) - pauseTime + layer.beginTime = beginTime + layer.speed = 1 + layer.add(ani, forKey: .rotateKey) + } + } +} + diff --git a/Sources/ProHUD/Core/Utils/Utils.swift b/Sources/ProHUD/Core/Utils/Utils.swift new file mode 100644 index 0000000..e91467d --- /dev/null +++ b/Sources/ProHUD/Core/Utils/Utils.swift @@ -0,0 +1,34 @@ +// +// File.swift +// +// +// Created by xaoxuu on 2022/8/29. +// + +import UIKit +import Inspire + +var screenSafeAreaInsets: UIEdgeInsets { + Inspire.shared.screen.safeAreaInsets +} + +extension UIImage { + public convenience init?(inProHUD named: String) { + if #available(iOS 13.0, *) { + self.init(named: named, in: .module, with: .none) + } else { + self.init(named: named) + } + } +} + + +/// 是否是手机竖屏模式 +internal var isPortrait: Bool { + if UIDevice.current.userInterfaceIdiom == .phone { + if UIApplication.shared.statusBarOrientation.isPortrait { + return true + } + } + return false +} diff --git a/Sources/ProHUD/Core/Utils/ViewExts.swift b/Sources/ProHUD/Core/Utils/ViewExts.swift new file mode 100644 index 0000000..59a5300 --- /dev/null +++ b/Sources/ProHUD/Core/Utils/ViewExts.swift @@ -0,0 +1,16 @@ +// +// ViewExts.swift +// +// +// Created by xaoxuu on 2022/8/31. +// + +import UIKit + +extension UIView { + + static func animateEaseOut(duration: TimeInterval, animations: @escaping () -> Void, completion: ((_ done: Bool) -> Void)? = nil) { + animate(withDuration: duration, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [.allowUserInteraction, .curveEaseOut], animations: animations, completion: completion) + } + +} diff --git a/Sources/ProHUD/Core/Views/Button.swift b/Sources/ProHUD/Core/Views/Button.swift new file mode 100644 index 0000000..030bbb1 --- /dev/null +++ b/Sources/ProHUD/Core/Views/Button.swift @@ -0,0 +1,109 @@ +// +// Button.swift +// +// +// Created by xaoxuu on 2022/8/29. +// + +import UIKit + +/// 弹窗的按钮 + +open class Button: UIButton { + + public internal(set) var action: Action? + + var edgeInset: CGFloat { 8 * 1.5 } + + public override init(frame: CGRect) { + super.init(frame: frame) + let padding = edgeInset + contentEdgeInsets = .init(top: padding, left: padding * 2, bottom: padding, right: padding * 2) + addTarget(self, action: #selector(self._onTouchUp(_:)), for: [.touchUpInside, .touchUpOutside]) + addTarget(self, action: #selector(self._onTouchDown(_:)), for: .touchDown) + addTarget(self, action: #selector(self._onTouchUpInside(_:)), for: .touchUpInside) + } + + required public init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public convenience init(config: ProHUD.Configuration, action: Action) { + self.init(frame: .zero) + self.update(config: config, action: action) + } + + /// 更新按钮 + /// - Parameter style: 样式 + open func update(config: ProHUD.Configuration, action: Action) { + titleLabel?.font = config.buttonFontByDefault + layer.cornerRadiusWithContinuous = config.buttonCornerRadiusByDefault + self.action = action + setTitle(action.title, for: .normal) + switch action.style { + case .tinted: + setTitleColor(config.dynamicBackgroundColor, for: .normal) + backgroundColor = config.tintColor ?? tintColor ?? .systemBlue + case .destructive: + setTitleColor(config.dynamicBackgroundColor, for: .normal) + backgroundColor = .systemRed + case .gray: + setTitleColor(config.secondaryLabelColor, for: .normal) + backgroundColor = config.secondaryLabelColor.withAlphaComponent(0.08) + case .filled(let color): + setTitleColor(config.dynamicBackgroundColor, for: .normal) + backgroundColor = color + case .light(let color): + setTitleColor(color, for: .normal) + backgroundColor = color.withAlphaComponent(0.15) + } + } + + var onTouchDown: ((_ action: Button) -> Void)? + public func onTouchDown(handler: @escaping (_ action: Button) -> Void) { + onTouchDown = handler + } + + var onTouchUp: ((_ action: Button) -> Void)? + public func onTouchUp(handler: @escaping (_ action: Button) -> Void) { + onTouchUp = handler + } + + var onTouchUpInside: ((_ action: Button) -> Void)? + public func onTouchUpInside(handler: @escaping (_ action: Button) -> Void) { + onTouchUpInside = handler + } + +} + +extension Button { + @objc func _onTouchDown(_ sender: Button) { + onTouchDown?(sender) + } + @objc func _onTouchUp(_ sender: Button) { + onTouchUp?(sender) + } + @objc func _onTouchUpInside(_ sender: Button) { + onTouchUpInside?(sender) + } + open override var isHighlighted: Bool { + didSet { + UIView.animate(withDuration: 0.1, delay: 0, options: .allowUserInteraction) { + if self.isEnabled { + self.alpha = self.isHighlighted ? 0.6 : 1 + } + } completion: { done in + + } + } + } + open override var isEnabled: Bool { + didSet { + UIView.animate(withDuration: 0.1, delay: 0, options: .allowUserInteraction) { + self.alpha = self.isEnabled ? 1 : 0.2 + } completion: { done in + + } + } + } +} diff --git a/Sources/ProHUD/Core/Views/ContentView.swift b/Sources/ProHUD/Core/Views/ContentView.swift new file mode 100644 index 0000000..080dda4 --- /dev/null +++ b/Sources/ProHUD/Core/Views/ContentView.swift @@ -0,0 +1,21 @@ +// +// ContentView.swift +// +// +// Created by xaoxuu on 2022/9/3. +// + +import UIKit + +public class ContentView: UIView { + + public override init(frame: CGRect) { + super.init(frame: frame) + layer.masksToBounds = true + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} diff --git a/Sources/ProHUD/Core/Views/ProgressView.swift b/Sources/ProHUD/Core/Views/ProgressView.swift new file mode 100644 index 0000000..184c919 --- /dev/null +++ b/Sources/ProHUD/Core/Views/ProgressView.swift @@ -0,0 +1,53 @@ +// +// ProgressView.swift +// +// +// Created by xaoxuu on 2022/8/29. +// + +import UIKit + +/// 进度指示器 +public class ProgressView: UIView { + + var progressLayer = CAShapeLayer() + + override init(frame: CGRect) { + // 容器宽度 + let maxSize = CGFloat(28) + super.init(frame: .init(x: 0, y: 0, width: maxSize, height: maxSize)) + layer.cornerRadius = maxSize / 2 + layer.masksToBounds = true + // 进度圆半径 + let radius = maxSize / 2 - 4 + backgroundColor = .white + + let path = UIBezierPath(arcCenter: CGPoint(x: 14, y: 14), radius: radius/2, startAngle: -CGFloat.pi*0.5, endAngle: CGFloat.pi * 1.5, clockwise: true) + + progressLayer.fillColor = UIColor.clear.cgColor + progressLayer.path = path.cgPath + + progressLayer.strokeColor = tintColor.cgColor + progressLayer.lineWidth = radius + progressLayer.strokeStart = 0 + progressLayer.strokeEnd = 0 + layer.addSublayer(progressLayer) + + } + + required init(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func updateProgress(progress: CGFloat) { + if progress <= 1 { + // 初始化 + if progressLayer.superlayer == nil { + progressLayer.strokeEnd = 0 + layer.addSublayer(progressLayer) + } + progressLayer.strokeEnd = progress + } + } + +} diff --git a/Sources/ProHUD/Core/Views/StackView.swift b/Sources/ProHUD/Core/Views/StackView.swift new file mode 100644 index 0000000..bbb0f01 --- /dev/null +++ b/Sources/ProHUD/Core/Views/StackView.swift @@ -0,0 +1,29 @@ +// +// StackView.swift +// +// +// Created by xaoxuu on 2022/8/29. +// + +import UIKit + +open class StackView: UIStackView { + + public override init(frame: CGRect) { + super.init(frame: frame) + distribution = .fill + alignment = .fill + axis = .vertical + spacing = 8 + } + + required public init(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + convenience init(axis: NSLayoutConstraint.Axis) { + self.init(frame: .zero) + self.axis = axis + } + +} diff --git a/Sources/ProHUD/Core/Views/Window.swift b/Sources/ProHUD/Core/Views/Window.swift new file mode 100644 index 0000000..12da8c8 --- /dev/null +++ b/Sources/ProHUD/Core/Views/Window.swift @@ -0,0 +1,54 @@ +// +// Window.swift +// +// +// Created by xaoxuu on 2022/9/1. +// + +import UIKit +import SnapKit + +class Window: UIWindow { + + lazy var backgroundView: UIView = { + let v = UIView() + v.backgroundColor = .black.withAlphaComponent(0.6) + v.alpha = 0 + return v + }() + + var usingBackground: Bool { false } + + override init(frame: CGRect) { + super.init(frame: frame) + setup() + } + + lazy var vc: UIViewController = { + UIViewController() + }() + + func setup() { + makeKeyAndVisible() + resignKey() + backgroundColor = .clear + if usingBackground { + insertSubview(backgroundView, at: 0) + backgroundView.snp.remakeConstraints { make in + make.edges.equalToSuperview() + } + } + rootViewController = vc + } + + @available(iOS 13.0, *) + override init(windowScene: UIWindowScene) { + super.init(windowScene: windowScene) + setup() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} diff --git a/Source/ProHUD.xcassets/Contents.json b/Sources/ProHUD/Resources/ProHUD.xcassets/Contents.json similarity index 100% rename from Source/ProHUD.xcassets/Contents.json rename to Sources/ProHUD/Resources/ProHUD.xcassets/Contents.json diff --git a/Source/ProHUD.xcassets/prohud.checkmark.imageset/Contents.json b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.checkmark.imageset/Contents.json similarity index 100% rename from Source/ProHUD.xcassets/prohud.checkmark.imageset/Contents.json rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.checkmark.imageset/Contents.json diff --git a/Source/ProHUD.xcassets/prohud.checkmark.imageset/prohud.checkmark@2x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.checkmark.imageset/prohud.checkmark@2x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.checkmark.imageset/prohud.checkmark@2x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.checkmark.imageset/prohud.checkmark@2x.png diff --git a/Source/ProHUD.xcassets/prohud.checkmark.imageset/prohud.checkmark@3x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.checkmark.imageset/prohud.checkmark@3x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.checkmark.imageset/prohud.checkmark@3x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.checkmark.imageset/prohud.checkmark@3x.png diff --git a/Source/ProHUD.xcassets/prohud.exclamationmark.imageset/Contents.json b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.exclamationmark.imageset/Contents.json similarity index 100% rename from Source/ProHUD.xcassets/prohud.exclamationmark.imageset/Contents.json rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.exclamationmark.imageset/Contents.json diff --git a/Source/ProHUD.xcassets/prohud.exclamationmark.imageset/prohud.exclamationmark@2x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.exclamationmark.imageset/prohud.exclamationmark@2x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.exclamationmark.imageset/prohud.exclamationmark@2x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.exclamationmark.imageset/prohud.exclamationmark@2x.png diff --git a/Source/ProHUD.xcassets/prohud.exclamationmark.imageset/prohud.exclamationmark@3x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.exclamationmark.imageset/prohud.exclamationmark@3x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.exclamationmark.imageset/prohud.exclamationmark@3x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.exclamationmark.imageset/prohud.exclamationmark@3x.png diff --git a/Source/ProHUD.xcassets/prohud.message.imageset/Contents.json b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.message.imageset/Contents.json similarity index 100% rename from Source/ProHUD.xcassets/prohud.message.imageset/Contents.json rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.message.imageset/Contents.json diff --git a/Source/ProHUD.xcassets/prohud.message.imageset/prohud.message@2x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.message.imageset/prohud.message@2x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.message.imageset/prohud.message@2x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.message.imageset/prohud.message@2x.png diff --git a/Source/ProHUD.xcassets/prohud.message.imageset/prohud.message@3x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.message.imageset/prohud.message@3x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.message.imageset/prohud.message@3x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.message.imageset/prohud.message@3x.png diff --git a/Source/ProHUD.xcassets/prohud.note.imageset/Contents.json b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.note.imageset/Contents.json similarity index 100% rename from Source/ProHUD.xcassets/prohud.note.imageset/Contents.json rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.note.imageset/Contents.json diff --git a/Source/ProHUD.xcassets/prohud.note.imageset/prohud.note@2x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.note.imageset/prohud.note@2x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.note.imageset/prohud.note@2x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.note.imageset/prohud.note@2x.png diff --git a/Source/ProHUD.xcassets/prohud.note.imageset/prohud.note@3x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.note.imageset/prohud.note@3x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.note.imageset/prohud.note@3x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.note.imageset/prohud.note@3x.png diff --git a/Source/ProHUD.xcassets/prohud.privacy.imageset/Contents.json b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.privacy.imageset/Contents.json similarity index 100% rename from Source/ProHUD.xcassets/prohud.privacy.imageset/Contents.json rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.privacy.imageset/Contents.json diff --git a/Source/ProHUD.xcassets/prohud.privacy.imageset/prohud.privacy@2x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.privacy.imageset/prohud.privacy@2x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.privacy.imageset/prohud.privacy@2x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.privacy.imageset/prohud.privacy@2x.png diff --git a/Source/ProHUD.xcassets/prohud.privacy.imageset/prohud.privacy@3x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.privacy.imageset/prohud.privacy@3x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.privacy.imageset/prohud.privacy@3x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.privacy.imageset/prohud.privacy@3x.png diff --git a/Source/ProHUD.xcassets/prohud.questionmark.imageset/Contents.json b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.questionmark.imageset/Contents.json similarity index 100% rename from Source/ProHUD.xcassets/prohud.questionmark.imageset/Contents.json rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.questionmark.imageset/Contents.json diff --git a/Source/ProHUD.xcassets/prohud.questionmark.imageset/prohud.questionmark@2x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.questionmark.imageset/prohud.questionmark@2x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.questionmark.imageset/prohud.questionmark@2x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.questionmark.imageset/prohud.questionmark@2x.png diff --git a/Source/ProHUD.xcassets/prohud.questionmark.imageset/prohud.questionmark@3x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.questionmark.imageset/prohud.questionmark@3x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.questionmark.imageset/prohud.questionmark@3x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.questionmark.imageset/prohud.questionmark@3x.png diff --git a/Source/ProHUD.xcassets/prohud.rainbow.circle.imageset/Contents.json b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.rainbow.circle.imageset/Contents.json similarity index 100% rename from Source/ProHUD.xcassets/prohud.rainbow.circle.imageset/Contents.json rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.rainbow.circle.imageset/Contents.json diff --git a/Source/ProHUD.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@2x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@2x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@2x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@2x.png diff --git a/Source/ProHUD.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@3x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@3x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@3x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@3x.png diff --git a/Source/ProHUD.xcassets/prohud.trash.imageset/Contents.json b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.trash.imageset/Contents.json similarity index 100% rename from Source/ProHUD.xcassets/prohud.trash.imageset/Contents.json rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.trash.imageset/Contents.json diff --git a/Source/ProHUD.xcassets/prohud.trash.imageset/prohud.trash@2x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.trash.imageset/prohud.trash@2x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.trash.imageset/prohud.trash@2x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.trash.imageset/prohud.trash@2x.png diff --git a/Source/ProHUD.xcassets/prohud.trash.imageset/prohud.trash@3x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.trash.imageset/prohud.trash@3x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.trash.imageset/prohud.trash@3x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.trash.imageset/prohud.trash@3x.png diff --git a/Source/ProHUD.xcassets/prohud.windmill.imageset/Contents.json b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.windmill.imageset/Contents.json similarity index 100% rename from Source/ProHUD.xcassets/prohud.windmill.imageset/Contents.json rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.windmill.imageset/Contents.json diff --git a/Source/ProHUD.xcassets/prohud.windmill.imageset/prohud.windmill@2x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.windmill.imageset/prohud.windmill@2x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.windmill.imageset/prohud.windmill@2x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.windmill.imageset/prohud.windmill@2x.png diff --git a/Source/ProHUD.xcassets/prohud.windmill.imageset/prohud.windmill@3x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.windmill.imageset/prohud.windmill@3x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.windmill.imageset/prohud.windmill@3x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.windmill.imageset/prohud.windmill@3x.png diff --git a/Source/ProHUD.xcassets/prohud.xmark.imageset/Contents.json b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.xmark.imageset/Contents.json similarity index 100% rename from Source/ProHUD.xcassets/prohud.xmark.imageset/Contents.json rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.xmark.imageset/Contents.json diff --git a/Source/ProHUD.xcassets/prohud.xmark.imageset/prohud.xmark@2x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.xmark.imageset/prohud.xmark@2x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.xmark.imageset/prohud.xmark@2x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.xmark.imageset/prohud.xmark@2x.png diff --git a/Source/ProHUD.xcassets/prohud.xmark.imageset/prohud.xmark@3x.png b/Sources/ProHUD/Resources/ProHUD.xcassets/prohud.xmark.imageset/prohud.xmark@3x.png similarity index 100% rename from Source/ProHUD.xcassets/prohud.xmark.imageset/prohud.xmark@3x.png rename to Sources/ProHUD/Resources/ProHUD.xcassets/prohud.xmark.imageset/prohud.xmark@3x.png diff --git a/Sources/ProHUD/Sheet/Sheet.swift b/Sources/ProHUD/Sheet/Sheet.swift new file mode 100644 index 0000000..bfe02d0 --- /dev/null +++ b/Sources/ProHUD/Sheet/Sheet.swift @@ -0,0 +1,106 @@ +// +// Sheet.swift +// +// +// Created by xaoxuu on 2022/9/8. +// + +import UIKit + +public class Sheet: Controller { + + weak var window: SheetWindow? + + public lazy var config: Configuration = { + var cfg = Configuration() + Configuration.customShared?(cfg) + return cfg + }() + + public lazy var backgroundView: UIView = { + let v = UIView() + v.backgroundColor = .init(white: 0, alpha: 0.5) + v.alpha = 0 + return v + }() + + /// 内容容器(包括icon、textStack、actionStack) + public lazy var contentStack: StackView = { + let stack = StackView() + stack.spacing = config.margin + stack.alignment = .fill + return stack + }() + + private var onTappedBackground: ((_ sheet: Sheet) -> Void)? + + public override var title: String? { + didSet { + add(title: title) + } + } + + @discardableResult public init(callback: @escaping (_ sheet: Sheet) -> Void, onTappedBackground action: ((_ sheet: Sheet) -> Void)? = nil) { + super.init() + + onTappedBackground = action + callback(self) + + DispatchQueue.main.async { + SheetWindow.push(sheet: self) + } + + } + + required public init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public override func viewDidLoad() { + super.viewDidLoad() + view.tintColor = config.tintColor + + // 点击 + let tap = UITapGestureRecognizer(target: self, action: #selector(_onTappedBackground(_:))) + backgroundView.addGestureRecognizer(tap) + + reloadData() + + _translateOut() + + } + +} + +extension Sheet { + func translateIn(completion: (() -> Void)?) { + UIView.animateEaseOut(duration: config.animateDurationForBuildInByDefault) { + self._translateIn() + } completion: { done in + completion?() + } + } + func translateOut(completion: (() -> Void)?) { + UIView.animateEaseOut(duration: config.animateDurationForBuildOutByDefault) { + self._translateOut() + } completion: { done in + completion?() + } + } + + func _translateIn() { + backgroundView.alpha = 1 + contentView.transform = .identity + } + func _translateOut() { + backgroundView.alpha = 0 + contentView.transform = .init(translationX: 0, y: view.frame.size.height - contentView.frame.minY + config.margin) + } + @objc func _onTappedBackground(_ sender: UITapGestureRecognizer) { + if let act = onTappedBackground { + act(self) + } else { + SheetWindow.pop(sheet: self) + } + } +} diff --git a/Sources/ProHUD/Sheet/SheetButton.swift b/Sources/ProHUD/Sheet/SheetButton.swift new file mode 100644 index 0000000..87ec9cc --- /dev/null +++ b/Sources/ProHUD/Sheet/SheetButton.swift @@ -0,0 +1,12 @@ +// +// SheetButton.swift +// +// +// Created by xaoxuu on 2022/9/9. +// + +import UIKit + +public class SheetButton: Button { + override var edgeInset: CGFloat { 8 * 1.75 } +} diff --git a/Sources/ProHUD/Sheet/SheetConfiguration.swift b/Sources/ProHUD/Sheet/SheetConfiguration.swift new file mode 100644 index 0000000..c236644 --- /dev/null +++ b/Sources/ProHUD/Sheet/SheetConfiguration.swift @@ -0,0 +1,69 @@ +// +// SheetConfiguration.swift +// +// +// Created by xaoxuu on 2022/9/8. +// + +import UIKit + +public extension Sheet { + + class Configuration: ProHUD.Configuration { + + /// 卡片距离屏幕的间距 + public var edgeInset: CGFloat = 4 + + /// 是否是全屏的页面 + public var isFullScreen = false + + /// 副标题字体 + public var subTitleFont: UIFont? + var subTitleFontByDefault: UIFont { + subTitleFont ?? .systemFont(ofSize: 20, weight: .bold) + } + + static var customShared: ((_ config: Configuration) -> Void)? + + /// 共享配置(只能设置一次,影响所有实例) + /// - Parameter callback: 配置代码 + public static func shared(_ callback: @escaping (_ config: Configuration) -> Void) { + customShared = callback + } + + var customBackgroundViewMask: ((_ mask: UIView) -> Void)? + + /// 设置背景蒙版 + /// - Parameter callback: 自定义内容卡片蒙版代码 + public func backgroundViewMask(_ callback: @escaping (_ mask: UIView) -> Void) { + customBackgroundViewMask = callback + } + + override var cardMaxWidthByDefault: CGFloat { cardMaxWidth ?? 500 } + + override var titleFontByDefault: UIFont { + titleFont ?? .systemFont(ofSize: 24, weight: .bold) + } + + override var bodyFontByDefault: UIFont { + bodyFont ?? .systemFont(ofSize: 16, weight: .regular) + } + + override var buttonFontByDefault: UIFont { + buttonFont ?? .systemFont(ofSize: 18, weight: .bold) + } + override var buttonCornerRadiusByDefault: CGFloat { buttonCornerRadius ?? 12 } + + override var animateDurationForBuildInByDefault: CGFloat { + animateDurationForBuildIn ?? 0.5 + } + + override var animateDurationForBuildOutByDefault: CGFloat { + animateDurationForBuildOut ?? 0.5 + } + + override var cardCornerRadiusByDefault: CGFloat { cardCornerRadius ?? 40 } + + } + +} diff --git a/Sources/ProHUD/Sheet/SheetConvenienceLayout.swift b/Sources/ProHUD/Sheet/SheetConvenienceLayout.swift new file mode 100644 index 0000000..64c59d4 --- /dev/null +++ b/Sources/ProHUD/Sheet/SheetConvenienceLayout.swift @@ -0,0 +1,192 @@ +// +// SheetConvenienceLayout.swift +// +// +// Created by xaoxuu on 2022/9/8. +// + +import UIKit + +extension Sheet: ConvenienceLayout { + + // MARK: 增加 + @discardableResult public func add(action: Action) -> Button { + insert(action: action, at: contentStack.arrangedSubviews.count) + } + public func insert(action: Action, at index: Int) -> Button { + let btn = SheetButton(config: config, action: action) + if index < contentStack.arrangedSubviews.count { + contentStack.insertArrangedSubview(btn, at: index) + } else { + contentStack.addArrangedSubview(btn) + } + addTouchUpAction(for: btn) { [weak self] in + if let self = self { + action.handler?(self) + } + if action.handler == nil { + self?.pop() + } + } + if isViewLoaded { + self.contentStack.layoutIfNeeded() + UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) { + self.view.layoutIfNeeded() + } + } + return btn + } + + // MARK: 查找 + public func button(for identifier: String) -> Button? { + if let index = actionIndex(for: identifier) { + return contentStack.arrangedSubviews[index] as? Button + } + return nil + } + + // MARK: 更新 + public func update(action title: String, style: Action.Style? = nil, for identifier: String) { + if let btn = button(for: identifier), let act = btn.action { + act.title = title + if let style = style { + act.style = style + } + btn.update(config: config, action: act) + } + } + + // MARK: 删除 + public func remove(actions finder: Action.Filter) { + if finder.ids.count > 0 { + for identifier in finder.ids { + while let index = actionIndex(for: identifier), index < contentStack.arrangedSubviews.count { + let view = contentStack.arrangedSubviews[index] + contentStack.removeArrangedSubview(view) + view.removeFromSuperview() + buttonEvents[view] = nil + } + } + } else { + for view in contentStack.arrangedSubviews { + contentStack.removeArrangedSubview(view) + view.removeFromSuperview() + buttonEvents[view] = nil + } + } + if isViewLoaded { + UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) { + self.contentStack.layoutIfNeeded() + self.view.layoutIfNeeded() + } + } + } + + // MARK: 自定义控件 + + @discardableResult public func add(subview: UIView) -> UIView { + contentStack.addArrangedSubview(subview) + return subview + } + + + // MARK: 布局工具 + + public func add(spacing: CGFloat) { + if #available(iOS 11.0, *) { + if let last = contentStack.arrangedSubviews.last { + contentStack.setCustomSpacing(spacing, after: last) + } + } + } + + // MARK: 完全自定义布局 + + public func set(customView: UIView) -> UIView { + self.customView = customView + contentView.addSubview(customView) + return customView + } + + // MARK: internal + func actionIndex(for identifier: String) -> Int? { + let arr = contentStack.arrangedSubviews.compactMap({ $0 as? Button }) + for i in 0 ..< arr.count { + if arr[i].action?.identifier == identifier { + return i + } + } + return nil + } + +} + +// MARK: more +public extension Sheet { + + /// 增加一个标题 + /// - Parameter text: 文本 + @discardableResult func add(title text: String?) -> UILabel { + let lb = add(subTitle: text) + lb.font = config.titleFontByDefault + lb.textAlignment = .center + return lb + } + + /// 增加一个副标题 + /// - Parameter text: 文本 + @discardableResult func add(subTitle text: String?) -> UILabel { + let lb = UILabel() + lb.font = config.subTitleFontByDefault + lb.textColor = config.primaryLabelColor + lb.numberOfLines = 0 + lb.textAlignment = .justified + lb.text = text + contentStack.addArrangedSubview(lb) + if #available(iOS 11.0, *) { + let count = contentStack.arrangedSubviews.count + if count > 1 { + contentStack.setCustomSpacing(config.margin * 3, after: contentStack.arrangedSubviews[count-2]) + contentStack.setCustomSpacing(config.margin * 1.5, after: contentStack.arrangedSubviews[count-1]) + } + } else { + // Fallback on earlier versions + } + return lb + } + + /// 增加一段正文 + /// - Parameter text: 文本 + @discardableResult func add(message text: String?) -> UILabel { + let lb = UILabel() + lb.font = config.bodyFontByDefault + lb.textColor = config.primaryLabelColor + lb.numberOfLines = 0 + lb.textAlignment = .justified + lb.text = text + contentStack.addArrangedSubview(lb) + return lb + } + + /// 增加一个按钮 + /// - Parameters: + /// - title: 标题 + /// - style: 样式 + /// - identifier: 唯一标识符 + /// - handler: 点击事件 + /// - Returns: 按钮实例 + @discardableResult func add(action title: String, style: Action.Style = .tinted, identifier: String? = nil, handler: ((_ sheet: Sheet) -> Void)? = nil) -> Button { + if let handler = handler { + let action = Action(identifier: identifier, style: style, title: title) { vc in + if let vc = vc as? Sheet { + handler(vc) + } + } + return add(action: action) + } else { + return add(action: .init(identifier: identifier, style: style, title: title, handler: nil)) + } + } + + +} diff --git a/Sources/ProHUD/Sheet/SheetDefaultLayout.swift b/Sources/ProHUD/Sheet/SheetDefaultLayout.swift new file mode 100644 index 0000000..04317e7 --- /dev/null +++ b/Sources/ProHUD/Sheet/SheetDefaultLayout.swift @@ -0,0 +1,105 @@ +// +// SheetDefaultLayout.swift +// +// +// Created by xaoxuu on 2022/9/9. +// + +import UIKit + +extension Sheet: DefaultLayout { + + var cfg: ProHUD.Configuration { + return config + } + + func reloadDataByDefault() { + // background + if backgroundView.superview == nil { + view.insertSubview(backgroundView, at: 0) + backgroundView.snp.remakeConstraints { make in + make.edges.equalToSuperview() + } + config.customBackgroundViewMask?(backgroundView) + } + // content + loadContentViewIfNeeded() + + if isViewDisplayed { + UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) { + self.view.layoutIfNeeded() + } + } + + } + + func loadContentViewIfNeeded() { + contentView.layer.cornerRadiusWithContinuous = config.cardCornerRadiusByDefault + if contentView.superview != view { + view.insertSubview(contentView, aboveSubview: backgroundView) + } + // mask + loadContentMaskViewIfNeeded() + // layout + let maxWidth = config.cardMaxWidthByDefault + var width = UIScreen.main.bounds.width - config.edgeInset * 2 + if width > maxWidth { + // landscape iPhone or iPad + width = maxWidth + } + contentView.snp.remakeConstraints { make in + if config.isFullScreen { + make.edges.equalToSuperview() + } else { + make.centerX.equalToSuperview() + if UIDevice.current.userInterfaceIdiom == .phone { + if width < maxWidth { + make.bottom.equalToSuperview().inset(config.edgeInset) + } else { + make.bottom.equalToSuperview().inset(screenSafeAreaInsets.bottom) + } + } else if UIDevice.current.userInterfaceIdiom == .pad { + make.centerY.equalToSuperview() + } + make.width.equalTo(width) + make.height.greaterThanOrEqualTo(config.cardCornerRadiusByDefault * 2) + make.height.lessThanOrEqualTo(config.cardMaxHeightByDefault) + } + } + guard customView == nil else { + if contentStack.superview != nil { + contentStack.removeFromSuperview() + } + return + } + // stack + if contentStack.superview == nil { + contentView.addSubview(contentStack) + contentStack.snp.remakeConstraints { make in + if config.isFullScreen { + make.top.equalToSuperview().offset(screenSafeAreaInsets.top) + } else { + make.top.equalToSuperview().offset(config.padding * 2) + } + if width < maxWidth { + let bottom = screenSafeAreaInsets.bottom + if bottom == 0 { + make.bottom.equalToSuperview().inset(config.padding * 2) + } else { + make.bottom.equalToSuperview().inset(bottom - config.padding / 2) + } + } else { + make.bottom.equalToSuperview().inset(config.padding * 2) + } + if isPortrait { + make.left.right.equalToSuperview().inset(config.padding) + } else { + make.left.right.equalToSuperview().inset(config.padding * 2) + } + } + } + + } + + +} diff --git a/Sources/ProHUD/Sheet/SheetManager.swift b/Sources/ProHUD/Sheet/SheetManager.swift new file mode 100644 index 0000000..b2f761b --- /dev/null +++ b/Sources/ProHUD/Sheet/SheetManager.swift @@ -0,0 +1,20 @@ +// +// SheetManager.swift +// +// +// Created by xaoxuu on 2022/9/8. +// + +import UIKit + +extension Sheet: HUD { + + public func push() { + SheetWindow.push(sheet: self) + } + + public func pop() { + SheetWindow.pop(sheet: self) + } + +} diff --git a/Sources/ProHUD/Sheet/SheetWindow.swift b/Sources/ProHUD/Sheet/SheetWindow.swift new file mode 100644 index 0000000..942e741 --- /dev/null +++ b/Sources/ProHUD/Sheet/SheetWindow.swift @@ -0,0 +1,75 @@ +// +// File.swift +// +// +// Created by xaoxuu on 2022/9/8. +// + +import UIKit + +class SheetWindow: Window { + + static var windows = [SheetWindow]() + + var sheet: Sheet + + init(sheet: Sheet) { + self.sheet = sheet + super.init(frame: .zero) + if #available(iOS 13.0, *) { + windowScene = sheet.config.windowScene ?? UIApplication.shared.windows.last?.windowScene + } + sheet.window = self + windowLevel = .init(rawValue: UIWindow.Level.alert.rawValue - 2) + isHidden = false + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + static func push(sheet: Sheet) { + let isNew: Bool + let window: SheetWindow + if let w = windows.first(where: { $0.sheet == sheet }) { + isNew = false + window = w + } else { + window = SheetWindow(sheet: sheet) + isNew = true + } + window.rootViewController = sheet // 此时toast.view.frame.size会自动更新为window.frame.size + if windows.contains(window) == false { + windows.append(window) + } + if isNew { + sheet.navEvents[.onViewWillAppear]?(sheet) + window.sheet.translateIn { + sheet.navEvents[.onViewDidAppear]?(sheet) + } + } else { + sheet.view.layoutIfNeeded() + } + } + + static func pop(sheet: Sheet) { + guard let window = windows.first(where: { $0.sheet == sheet }) else { + return + } + sheet.navEvents[.onViewWillDisappear]?(sheet) + window.sheet.translateOut { [weak window] in + if let win = window { + win.sheet.navEvents[.onViewDidDisappear]?(win.sheet) + if windows.count > 1 { + windows.removeAll { $0 == win } + } else if windows.count == 1 { + windows.removeAll() + } else { + consolePrint("‼️代码漏洞:已经没有sheet了") + } + } + } + } + + +} diff --git a/Sources/ProHUD/Toast/Toast.swift b/Sources/ProHUD/Toast/Toast.swift new file mode 100644 index 0000000..1ac94d1 --- /dev/null +++ b/Sources/ProHUD/Toast/Toast.swift @@ -0,0 +1,170 @@ +// +// Toast.swift +// +// +// Created by xaoxuu on 2022/9/3. +// + +import UIKit + +public class Toast: Controller { + + weak var window: ToastWindow? + + public lazy var config: Configuration = { + var cfg = Configuration() + Configuration.customShared?(cfg) + return cfg + }() + + public var progressView: ProgressView? + + /// 内容容器(包括icon、textStack、actionStack) + public lazy var contentStack: StackView = { + let stack = StackView(axis: .vertical) + stack.spacing = config.margin * 2 + return stack + }() + + /// 信息容器(image+text) + public lazy var infoStack: StackView = { + let stack = StackView(axis: .horizontal) + stack.spacing = config.margin + stack.alignment = .top + return stack + }() + + /// 文本容器 + public lazy var textStack: StackView = { + let stack = StackView(axis: .vertical) + stack.spacing = config.lineSpace + stack.distribution = .equalSpacing + return stack + }() + + /// 按钮容器 + public lazy var actionStack: StackView = { + let stack = StackView(axis: .horizontal) + stack.spacing = config.margin + return stack + }() + + /// 图标 + public lazy var imageView: UIImageView = { + let imgv = UIImageView() + imgv.contentMode = .scaleAspectFit + return imgv + }() + + /// 标题 + public lazy var titleLabel: UILabel = { + let lb = UILabel() + lb.textColor = config.primaryLabelColor + lb.font = config.titleFontByDefault + lb.textAlignment = .justified + lb.numberOfLines = config.titleMaxLines + return lb + }() + + /// 正文 + public lazy var bodyLabel: UILabel = { + let lb = UILabel() + lb.textColor = config.primaryLabelColor + lb.font = config.bodyFontByDefault + lb.textAlignment = .justified + lb.numberOfLines = config.bodyMaxLines + return lb + }() + + /// 是否可以通过手势移除(向上滑出屏幕) + public var isRemovable = true + + /// 视图模型 + public var vm = ViewModel() + + private var tapActionCallback: ((_ toast: Toast) -> Void)? + + + public override var title: String? { + didSet { + vm.title = title + } + } + + + @discardableResult public init(_ vm: ViewModel?, callback: ((_ toast: Toast) -> Void)? = nil) { + super.init() + if let vm = vm { + self.vm = vm + } + callback?(self) + DispatchQueue.main.async { + if callback != nil { + ToastWindow.push(toast: self) + } + } + } + + @discardableResult public convenience init(callback: ((_ toast: Toast) -> Void)?) { + self.init(nil, callback: callback) + } + + required public init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + public override func viewDidLoad() { + super.viewDidLoad() + view.tintColor = config.tintColor + + // 点击 + let tap = UITapGestureRecognizer(target: self, action: #selector(_onTappedGesture(_:))) + view.addGestureRecognizer(tap) + // 拖动 + let pan = UIPanGestureRecognizer(target: self, action: #selector(_onPanGesture(_:))) + view.addGestureRecognizer(pan) + + reloadData() + } + + public func onTapped(action: @escaping (_ toast: Toast) -> Void) { + self.tapActionCallback = action + } + +} + +fileprivate extension Toast { + + /// 点击事件 + /// - Parameter sender: 手势 + @objc func _onTappedGesture(_ sender: UITapGestureRecognizer) { + tapActionCallback?(self) + } + + /// 拖拽事件 + /// - Parameter sender: 手势 + @objc func _onPanGesture(_ sender: UIPanGestureRecognizer) { + vm.timeoutTimer?.invalidate() + let point = sender.translation(in: sender.view) + window?.transform = .init(translationX: 0, y: point.y) + if sender.state == .recognized { + let v = sender.velocity(in: sender.view) + if isRemovable { + // 可以移除 + if ((window?.frame.origin.y ?? 0) < 0 && v.y < 0) || v.y < -1200 { + // 达到移除的速度 + return pop() + } + } + UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) { + self.window?.transform = .identity + } completion: { done in + let d = self.vm.duration + self.vm.duration = d + } + } + } + +} + +extension Toast: LoadingAnimation { } diff --git a/Sources/ProHUD/Toast/ToastButton.swift b/Sources/ProHUD/Toast/ToastButton.swift new file mode 100644 index 0000000..732ba64 --- /dev/null +++ b/Sources/ProHUD/Toast/ToastButton.swift @@ -0,0 +1,13 @@ +// +// ToastButton.swift +// +// +// Created by xaoxuu on 2022/9/9. +// + +import UIKit + +public class ToastButton: Button { + override var edgeInset: CGFloat { 8 * 1.25 } +} + diff --git a/Sources/ProHUD/Toast/ToastConfiguration.swift b/Sources/ProHUD/Toast/ToastConfiguration.swift new file mode 100644 index 0000000..77326f0 --- /dev/null +++ b/Sources/ProHUD/Toast/ToastConfiguration.swift @@ -0,0 +1,56 @@ +// +// ToastConfiguration.swift +// +// +// Created by xaoxuu on 2022/9/3. +// + +import UIKit + +public extension Toast { + + class Configuration: ProHUD.Configuration { + + /// 行间距 + public var lineSpace = CGFloat(4) + + static var customShared: ((_ config: Configuration) -> Void)? + + /// 共享配置(只能设置一次,影响所有实例) + /// - Parameter callback: 配置代码 + public static func shared(_ callback: @escaping (_ config: Configuration) -> Void) { + customShared = callback + } + + override var cardMaxWidthByDefault: CGFloat { + cardMaxWidth ?? 500 + } + + override var cardMaxHeightByDefault: CGFloat { + cardMaxHeight ?? (UIScreen.main.bounds.height / 3) + } + + override var titleFontByDefault: UIFont { + titleFont ?? .systemFont(ofSize: 19, weight: .bold) + } + + override var boldTextFontByDefault: UIFont { + boldTextFont ?? .systemFont(ofSize: 17, weight: .bold) + } + + override var bodyFontByDefault: UIFont { + bodyFont ?? .systemFont(ofSize: 17, weight: .regular) + } + + override var animateDurationForBuildInByDefault: CGFloat { + animateDurationForBuildIn ?? 0.8 + } + + override var animateDurationForBuildOutByDefault: CGFloat { + animateDurationForBuildIn ?? 0.8 + } + + } + +} + diff --git a/Sources/ProHUD/Toast/ToastConvenienceLayout.swift b/Sources/ProHUD/Toast/ToastConvenienceLayout.swift new file mode 100644 index 0000000..534bc23 --- /dev/null +++ b/Sources/ProHUD/Toast/ToastConvenienceLayout.swift @@ -0,0 +1,81 @@ +// +// ToastConvenienceLayout.swift +// +// +// Created by xaoxuu on 2022/9/8. +// + +import UIKit + +public extension Toast { + + @discardableResult func add(customView: UIView) -> UIView { + if contentStack.superview != nil { + contentStack.removeFromSuperview() + } + contentView.addSubview(customView) + return customView + } + + @discardableResult func add(action: Action) -> Button { + insert(action: action, at: actionStack.arrangedSubviews.count) + } + + func insert(action: Action, at index: Int) -> Button { + let btn = ToastButton(config: config, action: action) + if index < actionStack.arrangedSubviews.count { + actionStack.insertArrangedSubview(btn, at: index) + } else { + actionStack.addArrangedSubview(btn) + } + loadActionStackIfNeeded() + addTouchUpAction(for: btn) { [weak self] in + if let self = self { + action.handler?(self) + } + if action.handler == nil { + self?.pop() + } + } + if isViewLoaded { + self.actionStack.layoutIfNeeded() + UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) { + self.view.layoutIfNeeded() + } + } + return btn + } + + // MARK: 布局工具 + + func add(spacing: CGFloat) { + if #available(iOS 11.0, *) { + if let last = contentStack.arrangedSubviews.last { + contentStack.setCustomSpacing(spacing, after: last) + } + } + } + + /// 增加一个按钮 + /// - Parameters: + /// - title: 标题 + /// - style: 样式 + /// - identifier: 唯一标识符 + /// - handler: 点击事件 + /// - Returns: 按钮实例 + @discardableResult func add(action title: String, style: Action.Style = .tinted, identifier: String? = nil, handler: ((_ toast: Toast) -> Void)? = nil) -> Button { + if let handler = handler { + let action = Action(identifier: identifier, style: style, title: title) { vc in + if let vc = vc as? Toast { + handler(vc) + } + } + return add(action: action) + } else { + return add(action: .init(identifier: identifier, style: style, title: title, handler: nil)) + } + } + + +} + diff --git a/Sources/ProHUD/Toast/ToastDefaultLayout.swift b/Sources/ProHUD/Toast/ToastDefaultLayout.swift new file mode 100644 index 0000000..98df8ed --- /dev/null +++ b/Sources/ProHUD/Toast/ToastDefaultLayout.swift @@ -0,0 +1,129 @@ +// +// ToastDefaultLayout.swift +// +// +// Created by xaoxuu on 2022/9/9. +// + +import UIKit + +extension Toast: DefaultLayout { + + var cfg: ProHUD.Configuration { + return config + } + + func reloadDataByDefault() { + loadContentViewIfNeeded() + loadContentMaskViewIfNeeded() + guard customView == nil else { + if contentStack.superview != nil { + contentStack.removeFromSuperview() + } + return + } + if vm.icon != nil { + if imageView.superview == nil { + infoStack.insertArrangedSubview(imageView, at: 0) + imageView.snp.makeConstraints { make in + make.width.height.equalTo(config.iconSize) + } + } + } else { + if infoStack.arrangedSubviews.contains(imageView) { + infoStack.removeArrangedSubview(imageView) + } + imageView.removeFromSuperview() + } + if textStack.superview == nil { + infoStack.addArrangedSubview(textStack) + } + let titleCount = vm.title?.count ?? 0 + let bodyCount = vm.message?.count ?? 0 + if titleCount > 0 { + textStack.insertArrangedSubview(titleLabel, at: 0) + if bodyCount == 0 { + titleLabel.font = config.boldTextFontByDefault + } else { + titleLabel.font = config.titleFontByDefault + } + } else { + if textStack.arrangedSubviews.contains(titleLabel) { + textStack.removeArrangedSubview(titleLabel) + } + titleLabel.removeFromSuperview() + } + if bodyCount > 0 { + textStack.addArrangedSubview(bodyLabel) + if titleCount == 0 { + bodyLabel.font = config.boldTextFontByDefault + } else { + bodyLabel.font = config.bodyFontByDefault + } + } else { + if textStack.arrangedSubviews.contains(bodyLabel) { + textStack.removeArrangedSubview(bodyLabel) + } + bodyLabel.removeFromSuperview() + } + // 设置数据 + imageView.image = vm.icon + titleLabel.text = vm.title + bodyLabel.text = vm.message + view.layoutIfNeeded() + + // 设置持续时间 + vm.timeoutHandler = DispatchWorkItem(block: { [weak self] in + self?.pop() + }) + + // 移除动画 + stopRotate(animateLayer) + animateLayer = nil + animation = nil + + // 移除进度 + progressView?.removeFromSuperview() + // 开始动画 + if let rotation = vm.rotation { + startRotate(rotation) + } + + } + + func loadContentViewIfNeeded() { + contentView.layer.cornerRadiusWithContinuous = config.cardCornerRadiusByDefault + guard contentView.superview != view else { + return + } + view.addSubview(contentView) + contentView.snp.remakeConstraints { make in + make.edges.equalToSuperview() + } + // stacks + if contentStack.superview != contentView { + contentView.addSubview(contentStack) + contentStack.snp.remakeConstraints { (mk) in + mk.edges.equalToSuperview().inset(config.padding) + } + } + contentStack.insertArrangedSubview(infoStack, at: 0) + + } + +} + +extension Toast { + func loadActionStackIfNeeded() { + guard actionStack.arrangedSubviews.count > 0 else { + actionStack.removeFromSuperview() + return + } + if actionStack.superview == nil { + let sup = StackView() + sup.alignment = .trailing + sup.addArrangedSubview(actionStack) + contentStack.addArrangedSubview(sup) + } + } +} diff --git a/Sources/ProHUD/Toast/ToastManager.swift b/Sources/ProHUD/Toast/ToastManager.swift new file mode 100644 index 0000000..a223de2 --- /dev/null +++ b/Sources/ProHUD/Toast/ToastManager.swift @@ -0,0 +1,69 @@ +// +// ToastManager.swift +// +// +// Created by xaoxuu on 2022/9/3. +// + +import UIKit + +extension Toast: HUD { + + public func push() { + ToastWindow.push(toast: self) + } + + public func pop() { + ToastWindow.pop(toast: self) + } + +} + +extension Toast { + + /// 如果不存在就创建并弹出一个HUD实例,如果存在就更新实例 + /// - Parameters: + /// - identifier: 实例唯一标识符(如果为空,则以代码位置为唯一标识符) + /// - callback: 实例创建代码 + public static func lazyPush(identifier: String? = nil, file: String = #file, line: Int = #line, callback: @escaping (_ toast: Toast) -> Void) { + let id = identifier ?? (file + "#\(line)") + if let vc = ToastWindow.windows.last(where: { $0.toast.identifier == id })?.toast { + callback(vc) + vc.reloadData() + } else { + Toast { hud in + hud.identifier = id + callback(hud) + }.push() + } + } + + /// 更新HUD实例 + /// - Parameter callback: 实例更新代码 + public func update(callback: @escaping (_ toast: Toast) -> Void) { + callback(self) + } + + /// 更新HUD实例 + /// - Parameters: + /// - identifier: 唯一标识符 + /// - callback: 实例更新代码 + public static func update(identifier: String, callback: @escaping (_ toast: Toast) -> Void) { + guard let vc = ToastWindow.windows.last(where: { $0.toast.identifier == identifier })?.toast else { + return + } + callback(vc) + vc.reloadData() + } + + /// 查找HUD实例 + /// - Parameter identifier: 唯一标识符 + /// - Returns: HUD实例 + public static func find(identifier: String) -> Toast? { + guard let vc = ToastWindow.windows.last(where: { $0.toast.identifier == identifier })?.toast else { + return nil + } + return vc + } + +} diff --git a/Sources/ProHUD/Toast/ToastWindow.swift b/Sources/ProHUD/Toast/ToastWindow.swift new file mode 100644 index 0000000..04ed34c --- /dev/null +++ b/Sources/ProHUD/Toast/ToastWindow.swift @@ -0,0 +1,170 @@ +// +// ToastWindow.swift +// +// +// Created by xaoxuu on 2022/9/3. +// + +import UIKit + +class ToastWindow: Window { + + static var windows = [ToastWindow]() + + var toast: Toast + + var maxY = CGFloat(0) + + init(toast: Toast) { + self.toast = toast + super.init(frame: .zero) + if #available(iOS 13.0, *) { + windowScene = toast.config.windowScene ?? UIApplication.shared.windows.last?.windowScene + } + toast.window = self + windowLevel = .init(rawValue: UIWindow.Level.alert.rawValue + 1000) + layer.shadowRadius = 8 + layer.shadowOffset = .init(width: 0, height: 5) + layer.shadowOpacity = 0.2 + isHidden = false + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func layoutSubviews() { + super.layoutSubviews() + layer.shadowPath = UIBezierPath.init(rect: bounds).cgPath + } + + static func push(toast: Toast) { + let isNew: Bool + let window: ToastWindow + if let w = windows.first(where: { $0.toast == toast }) { + isNew = false + window = w + } else { + window = ToastWindow(toast: toast) + isNew = true + } + let config = toast.config + // frame + let width = CGFloat.minimum(UIScreen.main.bounds.width - 2*config.margin, config.cardMaxWidthByDefault) + toast.view.frame.size = CGSize(width: width, height: config.cardMaxHeightByDefault) + toast.titleLabel.sizeToFit() + toast.bodyLabel.sizeToFit() + toast.view.layoutIfNeeded() + // 更新子视图之后获取正确的高度 + let height = toast.calcHeight() + toast.view.frame.size = CGSize(width: width, height: height) + // 应用到frame + window.frame = CGRect(x: (UIScreen.main.bounds.width - width) / 2, y: 0, width: width, height: height) + window.rootViewController = toast // 此时toast.view.frame.size会自动更新为window.frame.size + if windows.contains(window) == false { + windows.append(window) + } + updateToastWindowsLayout() + if isNew { + window.transform = .init(translationX: 0, y: -window.frame.maxY) + UIView.animateEaseOut(duration: config.animateDurationForBuildInByDefault) { + window.transform = .identity + } completion: { done in + toast.navEvents[.onViewDidAppear]?(toast) + } + } else { + toast.view.layoutIfNeeded() + toast.navEvents[.onViewDidAppear]?(toast) + } + } + + static func pop(toast: Toast) { + guard let window = windows.first(where: { $0.toast == toast }) else { + return + } + if windows.count > 1 { + windows.removeAll { $0 == window } + updateToastWindowsLayout() + } else if windows.count == 1 { + windows.removeAll() + } else { + consolePrint("‼️代码漏洞:已经没有toast了") + } + toast.vm.duration = nil + UIView.animateEaseOut(duration: toast.config.animateDurationForBuildOutByDefault) { + window.transform = .init(translationX: 0, y: 0-20-window.maxY) + } completion: { done in + window.toast.view.removeFromSuperview() + window.toast.removeFromParent() + window.toast.navEvents[.onViewDidDisappear]?(window.toast) + } + } + + +} + +fileprivate var updateToastsLayoutWorkItem: DispatchWorkItem? + +fileprivate extension ToastWindow { + + static func setToastWindowsLayout() { + let top = screenSafeAreaInsets.top + for (i, window) in windows.enumerated() { + let config = window.toast.config + var y = window.frame.origin.y + if i == 0 { + if isPortrait { + y = top + } else { + y = config.margin + } + } else { + if i - 1 < windows.count && i > 0 { + y = config.margin + windows[i-1].frame.maxY + } else { + y = config.margin + } + } + window.maxY = y + window.frame.size.height + UIView.animateEaseOut(duration: config.animateDurationForReloadByDefault) { + window.frame.origin.y = y + } + } + } + + static func updateToastWindowsLayout() { + updateToastsLayoutWorkItem?.cancel() + updateToastsLayoutWorkItem = DispatchWorkItem { + setToastWindowsLayout() + } + DispatchQueue.main.asyncAfter(deadline: .now()+0.001, execute: updateToastsLayoutWorkItem!) + } + +} + +fileprivate extension Toast { + func calcHeight() -> CGFloat { + var height = CGFloat(0) + for v in infoStack.arrangedSubviews { + // 图片或者文本最大高度 + height = CGFloat.maximum(v.frame.maxY, height) + } + if actionStack.arrangedSubviews.count > 0 { + height += actionStack.frame.height + contentStack.spacing + } + contentView.subviews.filter { v in + if v == contentMaskView { + return false + } + if v == contentStack { + return false + } + return true + } .forEach { v in + height = CGFloat.maximum(v.frame.maxY, height) + } + // 上下边间距 + height += 2 * config.padding + return height + } +} diff --git a/podspec.sh b/podspec.sh deleted file mode 100755 index c1e406b..0000000 --- a/podspec.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash -# 如果目录下有一个podspec文件,直接询问版本号,然后打包验证、发布 -# 如果目录下有多个podspec文件,遍历每一个podspec文件,询问版本号,然后打包验证、发布 - -PARAM1=$1 - -function cmd_push(){ - # 输入版本号 - while : - do - if [ "$PARAM1" == "" ];then - read -p "请输入${FILENAME}版本号: " PARAM1 - else - break - fi - done - - # 更新podspec - sed -i "" "s/s.version\([ ]\{1,\}\)=\([ ]\{1,\}\)\([\'|\"]\)\([^\"]\{1,\}\([\'|\"]\)\)/s.version = \"${PARAM1}\"/g" ${FILENAME} - - # 打包验证 - git add --all - git commit -am "update podspec" - git push origin - git tag ${PARAM1} - git push --tags - pod lib lint - - # 发布 - read -p "现在要发布${FILENAME}吗? y/n: " pushnow - if [ "$pushnow" == "y" ];then - echo "> pod trunk push ${FILENAME}" - pod trunk push ${FILENAME} - fi - - -} - -function cmd_checkfile(){ - count=$(ls *.podspec | wc -l) - - # 遍历每一个podspec文件 - for FILENAME in *.podspec - do - if [ $count -gt 1 ]; then - read -p "检测到了${FILENAME},是否是您要发布的podspec? y/n: " yn - if [ "$yn" == "y" ];then - cmd_push - fi - elif [ $count == 1 ]; then - cmd_push - else - echo -e "> \\033[0;31m没有找到podspec。\\033[0;39m" - fi - done -} - -case $PARAM1 in - 'docs'|'help') open https://xaoxuu.com/wiki/podspec.sh/ ;; - *) cmd_checkfile ;; -esac