From f028cceee906c962271af47eca03667038c39b2e Mon Sep 17 00:00:00 2001 From: xaoxuu Date: Sat, 10 Sep 2022 02:54:25 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xcshareddata/xcschemes/ProHUD.xcscheme | 28 + Assets/Icons.sketch | Bin 68647 -> 0 bytes Example-Old/Example.xcodeproj/project.pbxproj | 445 ------------ .../contents.xcworkspacedata | 7 - .../xcshareddata/xcschemes/Example.xcscheme | 78 --- .../contents.xcworkspacedata | 10 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - Example-Old/Example/AppDelegate.swift | 76 -- .../Base.lproj/LaunchScreen.storyboard | 25 - .../Example/Base.lproj/Main.storyboard | 46 -- Example-Old/Example/BaseListVC.swift | 106 --- Example-Old/Example/EmptyVC.swift | 57 -- Example-Old/Example/Example-Bridging-Header.h | 5 - Example-Old/Example/Info.plist | 54 -- Example-Old/Example/RootVC.swift | 88 --- Example-Old/Example/TestAlertVC.swift | 332 --------- Example-Old/Example/TestGuardVC.swift | 188 ----- Example-Old/Example/TestToastVC.swift | 240 ------- Example-Old/Example/ViewController.swift | 91 --- Example-Old/Podfile | 16 - Example-Old/Podfile.lock | 30 - Example-Old/README.md | 4 - .../Example-Xcode11.xcodeproj/project.pbxproj | 663 ------------------ .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/swiftpm/Package.resolved | 34 - .../Base.lproj/Main.storyboard | 24 - Example-Xcode11/Example-Xcode11/Info.plist | 62 -- .../Example_Xcode11Tests.swift | 34 - .../Example-Xcode11Tests/Info.plist | 22 - .../Example_Xcode11UITests.swift | 43 -- .../Example-Xcode11UITests/Info.plist | 22 - Example-Xcode11/README.md | 2 - PHDemo/PHDemo.xcodeproj/project.pbxproj | 419 +++++++++++ .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/swiftpm/Package.resolved | 23 + PHDemo/PHDemo/AlertVC.swift | 298 ++++++++ .../PHDemo}/AppDelegate.swift | 15 +- .../AccentColor.colorset/Contents.json | 15 + .../AppIcon.appiconset/Contents.json | 0 .../AppIcon.appiconset/Icon-60@2x.png | Bin .../AppIcon.appiconset/Icon-60@3x.png | Bin .../AppIcon.appiconset/Icon-76.png | Bin .../AppIcon.appiconset/Icon-76@2x.png | Bin .../AppIcon.appiconset/Icon-83.5@2x.png | Bin .../AppIcon.appiconset/Icon-Notification.png | Bin .../Icon-Notification@2x.png | Bin .../Icon-Notification@3x.png | Bin .../AppIcon.appiconset/Icon-Small-40.png | Bin .../AppIcon.appiconset/Icon-Small-40@2x.png | Bin .../AppIcon.appiconset/Icon-Small-40@3x.png | Bin .../AppIcon.appiconset/Icon-Small.png | Bin .../AppIcon.appiconset/Icon-Small@2x.png | Bin .../AppIcon.appiconset/Icon-Small@3x.png | Bin .../AppIcon.appiconset/icon.png | Bin .../PHDemo}/Assets.xcassets/Contents.json | 0 .../Feel1.imageset/Contents.json | 0 .../Feel1.imageset/Feel1@2x.png | Bin .../Feel1.imageset/Feel1@3x.png | Bin .../alert.buy.imageset/Contents.json | 0 .../alert.buy.imageset/ProHUDBuy@2x.png | Bin .../alert.buy.imageset/ProHUDBuy@3x.png | Bin .../avatar.imageset/Contents.json | 22 + .../avatar.imageset/avatar@2x.png | Bin 0 -> 26793 bytes .../avatar.imageset/avatar@3x.png | Bin 0 -> 54072 bytes .../Contents.json | 0 .../cloud download (2).png | Bin .../cloud download (3).png | Bin .../landscape.imageset/Contents.json | 21 + ...A-3B98-4677-A4F2-75827167E067_1_105_c.jpeg | Bin 0 -> 96309 bytes .../Contents.json | 0 .../prohud.rainbow.circle@2x.png | Bin .../prohud.rainbow.circle@3x.png | Bin .../prohud.trash.imageset/Contents.json | 0 .../prohud.trash.imageset/prohud.trash@2x.png | Bin .../prohud.trash.imageset/prohud.trash@3x.png | Bin .../Base.lproj/LaunchScreen.storyboard | 0 PHDemo/PHDemo/Base.lproj/Main.storyboard | 131 ++++ PHDemo/PHDemo/Info.plist | 25 + PHDemo/PHDemo/ListModel.swift | 33 + PHDemo/PHDemo/ListVC.swift | 53 ++ .../PHDemo}/SceneDelegate.swift | 41 +- PHDemo/PHDemo/Scenes.swift | 34 + PHDemo/PHDemo/SheetVC.swift | 214 ++++++ PHDemo/PHDemo/TableHeaderView.swift | 55 ++ PHDemo/PHDemo/ToastVC.swift | 224 ++++++ Package.resolved | 8 +- Package.swift | 10 +- Podfile | 14 - Podfile.lock | 3 - ProHUD.podspec | 20 - ProHUD.xcodeproj/project.pbxproj | 528 -------------- .../contents.xcworkspacedata | 7 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/swiftpm/Package.resolved | 25 - ProHUD.xcworkspace/contents.xcworkspacedata | 10 - .../xcshareddata/IDEWorkspaceChecks.plist | 8 - .../xcshareddata/swiftpm/Package.resolved | 25 - ProHUD/Info.plist | 22 - README.md | 4 +- Source/Alert/AlertConfig.swift | 340 --------- Source/Alert/AlertController.swift | 355 ---------- Source/Alert/AlertModel.swift | 115 --- Source/Guard/GuardConfig.swift | 141 ---- Source/Guard/GuardController.swift | 383 ---------- Source/Guard/GuardModel.swift | 76 -- Source/HUDConfig.swift | 109 --- Source/HUDController.swift | 173 ----- Source/HUDUtils.swift | 30 - Source/HUDView.swift | 253 ------- Source/ProHUD.h | 19 - Source/ProHUD.swift | 159 ----- Source/Toast/ToastConfig.swift | 134 ---- Source/Toast/ToastController.swift | 367 ---------- Source/Toast/ToastModel.swift | 72 -- Sources/ProHUD/Alert/Alert.swift | 109 +++ Sources/ProHUD/Alert/AlertConfiguration.swift | 44 ++ .../ProHUD/Alert/AlertConvenienceLayout.swift | 159 +++++ Sources/ProHUD/Alert/AlertDefaultLayout.swift | 247 +++++++ Sources/ProHUD/Alert/AlertManager.swift | 151 ++++ Sources/ProHUD/Alert/AlertWindow.swift | 38 + .../ProHUD/Core/Controllers/Controller.swift | 106 +++ Sources/ProHUD/Core/Models/Action.swift | 55 ++ .../ProHUD/Core/Models/Configuration.swift | 169 +++++ Sources/ProHUD/Core/Models/Rotation.swift | 32 + Sources/ProHUD/Core/Models/ViewModel.swift | 159 +++++ .../ProHUD/Core/Protocols/CommonLayout.swift | 30 + .../Core/Protocols/ConvenienceLayout.swift | 94 +++ .../ProHUD/Core/Protocols/DefaultLayout.swift | 38 + Sources/ProHUD/Core/Protocols/HUD.swift | 13 + .../Core/Protocols/LoadingAnimation.swift | 20 + Sources/ProHUD/Core/Utils/ConsolePrint.swift | 15 + Sources/ProHUD/Core/Utils/LayerExts.swift | 55 ++ .../ProHUD/Core/Utils/RotateAnimation.swift | 78 +++ Sources/ProHUD/Core/Utils/Utils.swift | 34 + Sources/ProHUD/Core/Utils/ViewExts.swift | 16 + Sources/ProHUD/Core/Views/Button.swift | 109 +++ Sources/ProHUD/Core/Views/ContentView.swift | 21 + Sources/ProHUD/Core/Views/ProgressView.swift | 53 ++ Sources/ProHUD/Core/Views/StackView.swift | 29 + Sources/ProHUD/Core/Views/Window.swift | 54 ++ .../Resources}/ProHUD.xcassets/Contents.json | 0 .../prohud.checkmark.imageset/Contents.json | 0 .../prohud.checkmark@2x.png | Bin .../prohud.checkmark@3x.png | Bin .../Contents.json | 0 .../prohud.exclamationmark@2x.png | Bin .../prohud.exclamationmark@3x.png | Bin .../prohud.message.imageset/Contents.json | 0 .../prohud.message@2x.png | Bin .../prohud.message@3x.png | Bin .../prohud.note.imageset/Contents.json | 0 .../prohud.note.imageset/prohud.note@2x.png | Bin .../prohud.note.imageset/prohud.note@3x.png | Bin .../prohud.privacy.imageset/Contents.json | 0 .../prohud.privacy@2x.png | Bin .../prohud.privacy@3x.png | Bin .../Contents.json | 0 .../prohud.questionmark@2x.png | Bin .../prohud.questionmark@3x.png | Bin .../Contents.json | 0 .../prohud.rainbow.circle@2x.png | Bin .../prohud.rainbow.circle@3x.png | Bin .../prohud.trash.imageset/Contents.json | 0 .../prohud.trash.imageset/prohud.trash@2x.png | Bin .../prohud.trash.imageset/prohud.trash@3x.png | Bin .../prohud.windmill.imageset/Contents.json | 0 .../prohud.windmill@2x.png | Bin .../prohud.windmill@3x.png | Bin .../prohud.xmark.imageset/Contents.json | 0 .../prohud.xmark.imageset/prohud.xmark@2x.png | Bin .../prohud.xmark.imageset/prohud.xmark@3x.png | Bin Sources/ProHUD/Sheet/Sheet.swift | 106 +++ Sources/ProHUD/Sheet/SheetButton.swift | 12 + Sources/ProHUD/Sheet/SheetConfiguration.swift | 69 ++ .../ProHUD/Sheet/SheetConvenienceLayout.swift | 192 +++++ Sources/ProHUD/Sheet/SheetDefaultLayout.swift | 105 +++ Sources/ProHUD/Sheet/SheetManager.swift | 20 + Sources/ProHUD/Sheet/SheetWindow.swift | 75 ++ Sources/ProHUD/Toast/Toast.swift | 170 +++++ Sources/ProHUD/Toast/ToastButton.swift | 13 + Sources/ProHUD/Toast/ToastConfiguration.swift | 56 ++ .../ProHUD/Toast/ToastConvenienceLayout.swift | 81 +++ Sources/ProHUD/Toast/ToastDefaultLayout.swift | 129 ++++ Sources/ProHUD/Toast/ToastManager.swift | 69 ++ Sources/ProHUD/Toast/ToastWindow.swift | 170 +++++ podspec.sh | 61 -- 187 files changed, 4807 insertions(+), 6338 deletions(-) delete mode 100644 Assets/Icons.sketch delete mode 100644 Example-Old/Example.xcodeproj/project.pbxproj delete mode 100644 Example-Old/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 Example-Old/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme delete mode 100644 Example-Old/Example.xcworkspace/contents.xcworkspacedata delete mode 100644 Example-Old/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 Example-Old/Example/AppDelegate.swift delete mode 100644 Example-Old/Example/Base.lproj/LaunchScreen.storyboard delete mode 100644 Example-Old/Example/Base.lproj/Main.storyboard delete mode 100644 Example-Old/Example/BaseListVC.swift delete mode 100644 Example-Old/Example/EmptyVC.swift delete mode 100644 Example-Old/Example/Example-Bridging-Header.h delete mode 100644 Example-Old/Example/Info.plist delete mode 100644 Example-Old/Example/RootVC.swift delete mode 100644 Example-Old/Example/TestAlertVC.swift delete mode 100644 Example-Old/Example/TestGuardVC.swift delete mode 100644 Example-Old/Example/TestToastVC.swift delete mode 100644 Example-Old/Example/ViewController.swift delete mode 100644 Example-Old/Podfile delete mode 100644 Example-Old/Podfile.lock delete mode 100644 Example-Old/README.md delete mode 100644 Example-Xcode11/Example-Xcode11.xcodeproj/project.pbxproj delete mode 100644 Example-Xcode11/Example-Xcode11.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 Example-Xcode11/Example-Xcode11.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved delete mode 100644 Example-Xcode11/Example-Xcode11/Base.lproj/Main.storyboard delete mode 100644 Example-Xcode11/Example-Xcode11/Info.plist delete mode 100644 Example-Xcode11/Example-Xcode11Tests/Example_Xcode11Tests.swift delete mode 100644 Example-Xcode11/Example-Xcode11Tests/Info.plist delete mode 100644 Example-Xcode11/Example-Xcode11UITests/Example_Xcode11UITests.swift delete mode 100644 Example-Xcode11/Example-Xcode11UITests/Info.plist delete mode 100644 Example-Xcode11/README.md create mode 100644 PHDemo/PHDemo.xcodeproj/project.pbxproj rename {Example-Xcode11/Example-Xcode11.xcodeproj => PHDemo/PHDemo.xcodeproj}/project.xcworkspace/contents.xcworkspacedata (100%) rename {Example-Old/Example.xcodeproj => PHDemo/PHDemo.xcodeproj}/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) create mode 100644 PHDemo/PHDemo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved create mode 100644 PHDemo/PHDemo/AlertVC.swift rename {Example-Xcode11/Example-Xcode11 => PHDemo/PHDemo}/AppDelegate.swift (82%) create mode 100644 PHDemo/PHDemo/Assets.xcassets/AccentColor.colorset/Contents.json rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/Icon-76.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/Icon-Notification.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/Icon-Notification@2x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/Icon-Notification@3x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/Icon-Small-40.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/Icon-Small.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/AppIcon.appiconset/icon.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/Contents.json (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/Feel1.imageset/Contents.json (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/Feel1.imageset/Feel1@2x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/Feel1.imageset/Feel1@3x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/alert.buy.imageset/Contents.json (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/alert.buy.imageset/ProHUDBuy@2x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/alert.buy.imageset/ProHUDBuy@3x.png (100%) create mode 100644 PHDemo/PHDemo/Assets.xcassets/avatar.imageset/Contents.json create mode 100644 PHDemo/PHDemo/Assets.xcassets/avatar.imageset/avatar@2x.png create mode 100644 PHDemo/PHDemo/Assets.xcassets/avatar.imageset/avatar@3x.png rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/icloud.and.arrow.down.imageset/Contents.json (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/icloud.and.arrow.down.imageset/cloud download (2).png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/icloud.and.arrow.down.imageset/cloud download (3).png (100%) create mode 100644 PHDemo/PHDemo/Assets.xcassets/landscape.imageset/Contents.json create mode 100644 PHDemo/PHDemo/Assets.xcassets/landscape.imageset/F462262A-3B98-4677-A4F2-75827167E067_1_105_c.jpeg rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/prohud.rainbow.circle.imageset/Contents.json (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@2x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@3x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/prohud.trash.imageset/Contents.json (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/prohud.trash.imageset/prohud.trash@2x.png (100%) rename {Example-Old/Example => PHDemo/PHDemo}/Assets.xcassets/prohud.trash.imageset/prohud.trash@3x.png (100%) rename {Example-Xcode11/Example-Xcode11 => PHDemo/PHDemo}/Base.lproj/LaunchScreen.storyboard (100%) create mode 100644 PHDemo/PHDemo/Base.lproj/Main.storyboard create mode 100644 PHDemo/PHDemo/Info.plist create mode 100644 PHDemo/PHDemo/ListModel.swift create mode 100644 PHDemo/PHDemo/ListVC.swift rename {Example-Xcode11/Example-Xcode11 => PHDemo/PHDemo}/SceneDelegate.swift (61%) create mode 100644 PHDemo/PHDemo/Scenes.swift create mode 100644 PHDemo/PHDemo/SheetVC.swift create mode 100644 PHDemo/PHDemo/TableHeaderView.swift create mode 100644 PHDemo/PHDemo/ToastVC.swift delete mode 100644 Podfile delete mode 100644 Podfile.lock delete mode 100755 ProHUD.podspec delete mode 100644 ProHUD.xcodeproj/project.pbxproj delete mode 100644 ProHUD.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 ProHUD.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 ProHUD.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved delete mode 100644 ProHUD.xcworkspace/contents.xcworkspacedata delete mode 100644 ProHUD.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist delete mode 100644 ProHUD.xcworkspace/xcshareddata/swiftpm/Package.resolved delete mode 100644 ProHUD/Info.plist delete mode 100644 Source/Alert/AlertConfig.swift delete mode 100644 Source/Alert/AlertController.swift delete mode 100644 Source/Alert/AlertModel.swift delete mode 100644 Source/Guard/GuardConfig.swift delete mode 100644 Source/Guard/GuardController.swift delete mode 100644 Source/Guard/GuardModel.swift delete mode 100644 Source/HUDConfig.swift delete mode 100644 Source/HUDController.swift delete mode 100644 Source/HUDUtils.swift delete mode 100644 Source/HUDView.swift delete mode 100644 Source/ProHUD.h delete mode 100644 Source/ProHUD.swift delete mode 100644 Source/Toast/ToastConfig.swift delete mode 100644 Source/Toast/ToastController.swift delete mode 100644 Source/Toast/ToastModel.swift create mode 100644 Sources/ProHUD/Alert/Alert.swift create mode 100644 Sources/ProHUD/Alert/AlertConfiguration.swift create mode 100644 Sources/ProHUD/Alert/AlertConvenienceLayout.swift create mode 100644 Sources/ProHUD/Alert/AlertDefaultLayout.swift create mode 100644 Sources/ProHUD/Alert/AlertManager.swift create mode 100644 Sources/ProHUD/Alert/AlertWindow.swift create mode 100644 Sources/ProHUD/Core/Controllers/Controller.swift create mode 100644 Sources/ProHUD/Core/Models/Action.swift create mode 100644 Sources/ProHUD/Core/Models/Configuration.swift create mode 100644 Sources/ProHUD/Core/Models/Rotation.swift create mode 100644 Sources/ProHUD/Core/Models/ViewModel.swift create mode 100644 Sources/ProHUD/Core/Protocols/CommonLayout.swift create mode 100644 Sources/ProHUD/Core/Protocols/ConvenienceLayout.swift create mode 100644 Sources/ProHUD/Core/Protocols/DefaultLayout.swift create mode 100644 Sources/ProHUD/Core/Protocols/HUD.swift create mode 100644 Sources/ProHUD/Core/Protocols/LoadingAnimation.swift create mode 100644 Sources/ProHUD/Core/Utils/ConsolePrint.swift create mode 100644 Sources/ProHUD/Core/Utils/LayerExts.swift create mode 100644 Sources/ProHUD/Core/Utils/RotateAnimation.swift create mode 100644 Sources/ProHUD/Core/Utils/Utils.swift create mode 100644 Sources/ProHUD/Core/Utils/ViewExts.swift create mode 100644 Sources/ProHUD/Core/Views/Button.swift create mode 100644 Sources/ProHUD/Core/Views/ContentView.swift create mode 100644 Sources/ProHUD/Core/Views/ProgressView.swift create mode 100644 Sources/ProHUD/Core/Views/StackView.swift create mode 100644 Sources/ProHUD/Core/Views/Window.swift rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/Contents.json (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.checkmark.imageset/Contents.json (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.checkmark.imageset/prohud.checkmark@2x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.checkmark.imageset/prohud.checkmark@3x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.exclamationmark.imageset/Contents.json (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.exclamationmark.imageset/prohud.exclamationmark@2x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.exclamationmark.imageset/prohud.exclamationmark@3x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.message.imageset/Contents.json (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.message.imageset/prohud.message@2x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.message.imageset/prohud.message@3x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.note.imageset/Contents.json (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.note.imageset/prohud.note@2x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.note.imageset/prohud.note@3x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.privacy.imageset/Contents.json (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.privacy.imageset/prohud.privacy@2x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.privacy.imageset/prohud.privacy@3x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.questionmark.imageset/Contents.json (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.questionmark.imageset/prohud.questionmark@2x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.questionmark.imageset/prohud.questionmark@3x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.rainbow.circle.imageset/Contents.json (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@2x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.rainbow.circle.imageset/prohud.rainbow.circle@3x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.trash.imageset/Contents.json (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.trash.imageset/prohud.trash@2x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.trash.imageset/prohud.trash@3x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.windmill.imageset/Contents.json (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.windmill.imageset/prohud.windmill@2x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.windmill.imageset/prohud.windmill@3x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.xmark.imageset/Contents.json (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.xmark.imageset/prohud.xmark@2x.png (100%) rename {Source => Sources/ProHUD/Resources}/ProHUD.xcassets/prohud.xmark.imageset/prohud.xmark@3x.png (100%) create mode 100644 Sources/ProHUD/Sheet/Sheet.swift create mode 100644 Sources/ProHUD/Sheet/SheetButton.swift create mode 100644 Sources/ProHUD/Sheet/SheetConfiguration.swift create mode 100644 Sources/ProHUD/Sheet/SheetConvenienceLayout.swift create mode 100644 Sources/ProHUD/Sheet/SheetDefaultLayout.swift create mode 100644 Sources/ProHUD/Sheet/SheetManager.swift create mode 100644 Sources/ProHUD/Sheet/SheetWindow.swift create mode 100644 Sources/ProHUD/Toast/Toast.swift create mode 100644 Sources/ProHUD/Toast/ToastButton.swift create mode 100644 Sources/ProHUD/Toast/ToastConfiguration.swift create mode 100644 Sources/ProHUD/Toast/ToastConvenienceLayout.swift create mode 100644 Sources/ProHUD/Toast/ToastDefaultLayout.swift create mode 100644 Sources/ProHUD/Toast/ToastManager.swift create mode 100644 Sources/ProHUD/Toast/ToastWindow.swift delete mode 100755 podspec.sh 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:"> + + + + + + + + |W_}_O$)K0VPjh=JQM=p2g%yK1H zD`(^sI$zh&w9XxV&h-2n@^&ncNCHX)OBjh5XN2-3BJtoskRXji?z&721CF9xD{Zo+ z%)uGC_*@%&v!`_ zq^a*kB6gXNqN>Iq^!u3hO`<;P0KjIcO*=7gffhy<751~oIuEOgUGti|B<}Y6KJv=C zdm>lrrhS7Fa2@%nVyO*Oi{?pg!DQ`LUE$fbo@@0RdxuSHk1AVhHC=s414T!0OqNvx z2J0SIdg^o(pHggfhy5e8tK1}?$-hmO{lBub&)H-4`jS=(&Z|P%%s^?4jO%*c%DIBW zRrNFyo!#d>o<%AK)FUAeDWQj(VRYb=2NrpL=%>jrO`ZL8{{v7<0|XQR0ssgA00000 z@fkrtE?EEo23P|CF8}}laA9XgGjgj7Q0dR>O7F-ZNz!k|A`8SXO{(?u{Z$!r9X1IrYMpZsMx;m@!MufS!nVP;# z&(VMS>fe3+-Lp4uzWST5et7oHiMgG_v-im^X1oXf79c`meSZ4p`e{g5Na%# zloZ$+N}9%@jw62Q_pe@kclqq)zxmu;eX8iS6FQ0vn z|M=>^{~!O?fB)bA%dhCG`IFzwGrS(~_2ruv|Nh0xZ@O16-@JYO?8Qq=xukcWUk~^C z)!WmH;xBK$ef8sa&)e6R&;Iy#&))p8`xd`=J>=z2{^tMY2mfg-^FO^?@Y~!*fQeS^(+6idEj~dzP)_$&9`r-$Nc%l^S9ql|Mk=K=U?zAhW*<21}ot&`ggCM z&#Uq6vp3z1&#&k8=Ivj;yFG{blev|2jvh`XTX}HBNUA}z& zch6q`@$&WcHhll$t?xJf_0`{yug%+MuixJJnLodH`5Y7bhaY_^kjmeG_v7nZbDBPI zVH#dOgDkz1hOaMQVtD+-KgEmu>tErIzvAbcz{ePp+SL5}~hOefR1$MEdRPSKr-!`0ekUTZ7-fc8Pd-`DPZrul;AAy?Hym-nT!_ z&%gE7f1Q8m@~5}Iy?px?3xE5G-@JbI!?!QKe$(Cg8Q&M*-z$-N^~1BTU%dUxJm4Q* zeD~eyU0%F=dHMRc-#&Z(>d&W7-n{$EU#~>*>p%YP+t;st{N~%MMf?VT`vC{*)sJs) zP3P}^`|KaKF#HZz4FY3(4`q%SkCl%WqBr;U8YV`u^Rv`KDd{^z}==eRcf<c>5XyzFvkIh zjDI;Y{_@p}H921uU%r{v7a#pFE70*;2I%^;-@Q1+96sw64%y{%7@eCg zNcY{VH}Ayk2PopV|1jBv_VU|je|quC%?+KtacB9z{_*vnF8|)YF`4Gqc=A7-%n8e{ z=WmZ!8-3d5>BCuw==8VWy}J1WZj9gk;+1JXeds@W`e>TayI;JuVUL*@ElrHJPK zjFu)wTPH?4CKi__7Pn4p{zVt#Ke%Uma|SOjFQ2W*a)n{fE)I@zAld|x4!fU-jCq@UGRPtF+5G|9zW7RG%iQ(vLbRn`TQR&aF1s)9TyqOxt1Kc z8W{_f2PZoH3a5(Su~ZVVB-XlWNpEcZLl58aGEW@q-zk5qVR`F?Az{zG>@h zwc8wr&{oQATi9yz3DkbP3(5cM|NCG5`G5Pr58raZx2zXMsj68mg=(d1-?Cn$LX^nA zGN-HR2v}7nu_VeV%BfZ&UPOw*a89$knE3O_oJ%Pk<{NV;U26z|`YyChO`++uX*rD% zZrkBp9?s=cJC|qtmBV%Xf?da7IyKbC%AE*QVq+A<${3oy;V=w5Ff2ONAswlqFWr1U zaUuLTbYqWMgrQB4#FlcX)DNM{ti-XUG3$|UKaBI*eETmGkH-sWOUjg^#YCyv{TS^| zczIDv(kii1p%T4{9=~!CufB|nh+h^Y?K$G z=?hH8IOBz*q?$#dosCkLGXd`%YFBcg7Rt$@a;Yg+Gh0p$RAV*Ys%%A)Y)%cFdGxMV zVe!3UBPls)=H)lZG2{6VL!rXLDx3D@JtJ)wJcMjm-eRhFo1960{i}f8kED3F%2;^B zlf?JlFx?S7gNWdKSxVWja#?()k%X% zDGP~WXL;8FtR@h(SVb!alSK3UnNz|_XXubj6!V=`;Jf-J_T07Mi_k?TnT%AJAQjL(OIj9RTA&Oy zD+K2>FBVH!iiE|4co}cfv+teIj-7UOs#!EayXC5Mt!MB65rWc_Sx_HLu%6duTT-rP zmD8F0;Mw@XTFB~PZGZ)VYo}fI%wQKv%|nA-NhKcf#pf4alnYmX#TmbV8gXC4k;;2-bafvofnQa?7_OAQRy%nQ>rz!8nXeW*UN4Q)Rh z-ofYQ9q2`wD$=MRR4l31+u6rl;3;@`LJ!>?)(ei}XV?&9CJ)`7$V+IIq=PtyW*8|* z?IEMJ(@M(q=!dS>EHcwMw8!MbOc&L)3Y)eR5g++v=tiqhL)OqOSS^R90;N9ZEdsaX&dJ(l; z;7Dt(Q_53oQpQsw!GD&VZD9peu~qmv>=e9!DDyH(GWEPEmY`5cylDj#n@@%fiP^Nm zqnL(&dx zF|PtAr(6b_@@@rZEDMV}?O2RWvM|l4LM}-nCxXufx7~JK1(htMiScioGtU{HlE@-l zN>ujre`W~ALNeM@Vz&8{eP4k>(@exl6e=p!P zC@o)aOm zJrq+K0pmgcVMWt?J)_W$CHq+^p5N56um*x?hH-NI^>e}WCbu5(aDhZAj!2Tk+pegz zxJ^iqRE6@(aT;0?O}U}O0gS0K^Ue#ZinYxGk%ApelbqrB5gsP2F34HyqD_QtN`&`J z2F1$rG8#^5WK+t?AF)jcpslC-bk9B`n3PE$7#szxH4N@_|5x^{fLnif14SVVkhj?> zz~T1f2808vq7Prt`Q3j;oI530a1?mjCR6AESnMn~9D?(-?fol^HBZML139{DvWR|} zR3UhiVa)rkC~x~+h0pk1%Xf7U5_p%8R=lx7@~hnup-NsJl>*UoLyyZ{l@RKu5pj}ibM8mOus>Bsj zk7=}hFmk%Uant})3Q288Zo8%(p`4Dy)seV*dOW2oT||q}ujUmOH}I7Azjfd#kJQ#L zhNt`}7>D9AMU$+cXj)gTx5weThi6)uETS=u-t`Q-3&FRUw zsCyg7WOWEb%Q;A=5Yx{5uT9jpwA$svxjdZ9<5u)=9lt0%WuemONL}c=E(VG180wJ5 zFcccKZ>kPmJd#3Ry7>-tfuOgVrpTmPi(UrOrv+Iy)RIY8gLa8vv4<%!ltZG?l*dL* z`lH(Uu-G3x$nq{4Wd+RgHcD@E%z6IN+XLvkC_P?&m3!d2%?Qf#BW*5-xDU#UX$Hd8 z9K9SwN8gry_F@RAEHb}Wmu+PMcTsuMT`)m&3v{8fBr16qG1Fa8 zUM%w}&~yANvw0b2tmEU)@O$R8=i>WHxl}A>^y&h>;Ebg$ zDSMrmD8agyMJV_^-4Zv}znvXvALP=})~dy8{&28Mwq^X`3>i0uIxwz8#M=RuXCA)~ zV0jC*K3~))qsbRb*%Vr01;COjDbA2mQZIGk?EuUBBdxxL&hR{2gCExo+y@vE3RVdJ z)#CWnzRNtZrXB&uXBBXq!BbuZ9M{mxpUyxj=Op1f*d?Nt1ReiGA;-{Diw981*3=+P zvCyO@h6bkHT5i%%@)2?zA;-raayT}S6viPUgm?F7k{Yk3V>l3{c(t+?{wOc$?g92z zT+%s923zDzUgEkrTsr^g&kaxdscTn0Ev8uclyqn?l=aZi~b|4b9;j ze4fcjXeGD?a1Tnp!TVoQN>NkBcf9(0auRMLDG_0pn-_@_z=ure$*R=)p@nnO458Kx zAHkFZ0^~0AGHR2X*7DdM7m0_Da9kuF7l~g2ywWi*6j{{pZ;LhF-~=qGW`>H?C3xio zZb^jy6Mew3&^MbA%t-?qx;ie{_m1T28BmO<7 ziK|Jj*?Zb#@oTqjOlFRcGACf1a9pXJNVqUEo|shN8Y8COnHxPfee-*ONHn28OT3q7 zJCh|oznC#;Dbvm3^l$!v%V1blOjoUG2-*b7T|8AKplob%6? zc_q)BnbRmzB$0EEA%@$w2502|>b!n=Zj0fWrEHGYvba+U;EOui32td+ z#qrH2hCX&Q6=FzB995QU=i{*M0GTH!-B!s6SX$q z>9~9CkPhrn^dH!jm1at+@XIT?Uf?UDON8Qx#0{!H3EXtG1+@rGf-Nyp{6AKjiCSay zizq0XRI(<;q29O*m>zV7^a-_38MUXC>_j{BO0Ac6iR`vaKE`G zJb=YjQA+!;bVVzMseX@Gaw+pQW#Lq-mrYM#MSJ)>_)7ZKo?qk<8Fa{em6A#=zK1Dc zuF6%=y}6a zZ+|VCM&}TK4VcEjf;po02E#P;wnLLQ-lVRb;3LRFdud`B!YDNbQEo!p_c_F7q`|nc zemD@7pM9T7es7=3JoACQgHHZjP|AMni2HsBy;=#9`WPA|Z+GRmejBJiT2mfLswYoU z(GBF}tqzs&_^whVp8TCZnSX+hG}e*E`UN;?;}R!r+{#HCKWN)TS;3XN>Xvrr72*Y4 z9*s#5p?G!LeXf)<6-XX~;Kz#>$|0Jevbnw8`_Pq8$}-k*j7=BDzEJQ2&tPM; zkoqyV@E8yT&;h0VEPGpdB_Cq(;#Ie|*k$jaG=4e*nf!Tyl*U#XwI+;+oc;cjf?s=v zI*g?$eXm5r;aVQ9<#GRcIF4Twkg}o9dXdlw{t&n~q3xMN>6_NCqH19=!%*cYU_OlVM_<5v3yX8YdR^z}oeWvi+`VwA zd*eG4j^s0gWZluuamCmlpueM(i1;?KN?F_A(PQF>2s@rDCwWwd$6F8I^)lYbj;eV( zJH!lJs4l;aW8da!K%Ggp%A1=!o*Qb%UDuiIUy{Z%BE9h*>+Hk#+}+-Rl1*1`0wGF% zP447ZGI4w_bL8Jdg$Zp(1fCsfcN50@qO^bryb{^u7t>Y5cC}pmP~vyuYOd9r?P9oT zdU^SEq>9%&OgL39f!PfIyFbtlGHyt-aHZs>f*N_|)UTGN+7+*SC?ZQl)OWDfbF);R zVN5x@^3ti^XA>LwO{BHdQ}c*Snw{So!dVN;hgKzzH+7H&@eV`<+kt~De0^@2OXd`dbP`Y6_BB>*i`uKZoew_E3_ra($uYlK8 z`$yhkrfU6I?>-%9S{Wf0{-a1PWyRemc>^N6l%q`HaBpwledghxAr_STp&vSFLu#Z6 zh(o&2YM(@k3_UJGzXUL-sbsh% z-oMPto8!3(dyy4+#HnuG1CbXnH;@2ZLoJnz|8$~=lL^T zg#MM{E#lZgK3KdtsfgKmd+iz>6_+*wVIAeC#?d>TTEYLO`N5$eZ`wjEk>ftxTZEfI z=8P2VEIXy9neI`Y|IvYk_|QRCODRiCBYWiI7#HmRJW+B$Xv7;7len>i<^=OgiNu2p z7Q+Hh6Re&%;aohW@43}oi@+SK7hw8IWI5$U9qU%5ILJ(5@;c8&G%$7xKd9bjiXo%< zgv&|=N7jiC^VI%yD`O;FKbd;lm8^QgS9-oO`qnX=M)nr%`_2P zbHHrV3x=swKUyLfXT~Q&(_~AKRBvRN>Yj^?cNjHtylSN@rB2=*F+vA(#*@yTMMCvgOu-?rZ%dva?g-J3H!?E}P7HNj3rSv87RJzHW0pamGsac9}$*dnK-# z;OaXH$Scf9-vlcj*o_?myEJH!E*2XI2j^g-`uuw(+IxE?@_A$*)PNh;JexCqGNQ`J zUF&ut3@|PMN8Cc&QX8}{J&mPHT{-d&N8aJ-TO|s-DS;2+jxSTz8-PEv+uyqe{N4SX zBUN#vDt>{BFWr}8x=!@tF&Lv9lXG3i3>n-VN%8V4Fm8V)Xr!`D3SxDLnhivs+$HO4q* z1l^-`LAa~I5)YxzHKjg#_H#H=L|?A)&OZm>FSGMm775Z+3zBjl5LZj6%`hZunY-pF zQ$39Hr_m(QVHG8E%vE$TK7a48JU(iB&ro|>>P^6*RG1BhK)fd$E#ku_gpfsz>aMl& zb_(qCL+!&NUO}>ARqsQ#28(!&DCZ1b^lJUx$ ziRIhDDOnu`N4|};kt^3VAtxLN91xqih)v<^c+CpsD5+Z6*Mibn-nlS|Xiid3O!#;w z2ka@98Q*)bcw}0|TybK(#Z{&>Unk?&*^3RB9QJ2r;{rg`DqhypE?#gvYqRKD$kBE9 zKW4cPa(m0*a9+_9SiP>!YlHAxh2+K+H)&OqfhX?>8!piPfgoH$>-2@o*{yw z4h_U4SZ-2n*g=Wo5ea?nEgkQ5bi9G|JA>!D*V=KqFi%fLTV}&(qqZS-T^mGN4XvdV zD2@sL>t(Fz2$YUM>7&QhJ-4sZAuIR5!LYRMl9U@ zI(A4amwowS_NB#2h+(^#PkjwFmkCN%XaZ=c*8Kn8@ro z`RuLz*g5L9bvAWH!VztJ!kiOV9EOsL?#oG^nLc^DJnu({r~2u##iab1 zh4jXC4(@V2>k3Ri+!7E&OrfiBK)HJB$z6#6ac)M>fMc)bxjU3SL;FW!gy?a(f#3ZD zbQ*+lNWFJmIoXmABJ=0ww?q5+byR}bLt4q=e5K-f8}t41>kulk1aEh|p*T$-j3LzZ z+#1yZmg3h&nq87;+aYiqx2t7uC|zPsW$r0s)w!f%^#&<%p9GK=zd?f9q6E7-%UJa$ znd(*S(1PBdcnQbqplJNEcuP}2)LS2XsB9X@&gS(!7D|4YFpN>=L|*b34AaXXBaqtiGBmWk_Z0 zVi@z({%*(t`i;WCojAa=hhKAKoj$j$lUzUw<@&DaUDE0PH-4J#t0r*$o%;H_pFUa6 zNlcn{90Ei!J00o}D&;W@_^>18)TMgloQ|B+&(^E)T|VW=IUPBtUx2X`(Q-lXkW{MI zr69t6IP#jiWG4g{#W|;-wbM4vn3I~@QKoix;`hBLzQ=lUXW}b!WA|?o_tTo5UBvfC zd+*(?z_Ydu@1Q&mCT26{@5X(%)$nRn%Id+lcwcZ zS)E5n9j2F+oYwT0iIq&QaW({x6iHxVMOLF-IYO1#IN+Y?brQSb10DyK{^9 zaE{{M^!MZ_R(CmL5w0y_sJ_5gh=ee|&uwVP8X2k4Qq$opd~Uu1UpVl!o}q`h`<-$Z z6*b|XDt7o1hcEH*`x0LN=Z3h5kj^C+ zF-BNuvLsG=?!uhYB4+&7SD_u4@pB{XX*+QDW%QJOkDkOXj(oNhb*W7C_As2vT&{6@ z0Zq~`b$xQ0_jVi%-7q4@R(U!_l&dS2gL7>-o8!-ILrtT}Zy!&eJ-HM0G4$lp8 zRxW<_Yne0ar5EDu9jxT65r29$DU~I--8s2<-|^l;FS>e~X8~~2XLv&U?CU>zD(dC) zZceP7)Zpx&-1+WrUJgIq_Uz^#`^`%z%^#otk3W3(>e&rVI)3-+&;RO`dnQ-92ENth z+y2GZuKAz6hOYjnzn&bf%UQp_d^h&*@6K!$xpVeTDz!oe)tUS24RYuE-#U>y-~EPX z?XEplU$EExv$xM~`&ZYW`b6KHvW-8!cz$_hR{nJIXSeUgc=SR7U6@4S|$Ng1>J+)PQo-Z(K@niy@J810@IElrHJPKSNsyMu(8QEOQR~WB2Fq5C%JI)F;vl=oC3;iIUidUHC0CPu=w#3$b!~G6F3KW*t(s(0S3gx7rQX4mrfw4@}Vs0LG(o z{K)YfV8+AE{Gyr#X&tDiK8(^0K{{(f!(t&>M@cgDqVZYN9gkwLPuy}xHj$iC628RWC!#Pi3zmgONO`*rkSoQ0*X>Er(8PH)xkA*5R<%hrK@R^r!W`)q`y5Rkd>P?NwXJ%L1JWt;Q0|MCI&byK~C>m#z&VSCUVj@Z&X&ZaM2IF027g?W`=L#^reLh z)?hZnn2~fJCn`=sP7t)hULrU%A|`WOhn0wLn902*IKzpm@S=*Jrc?@%oG9_I zgxDslP8mzQu~m`t6cWTVyQ7(Nol7GztE5) zh>CYFsIe~6<7Q`mbYfLWSXTUP9wj*!C=^;`r!?HQ1nOPXD;z*C_RT_knxIR7LLK7U zy02XmO;n}`(I8rxiq(0MQ)KT32A%7Ry`&F_a9C?pIQB7l>#A9rlK1R_9`_)DbJrKCKQ zgnBKu6NEB*+cXFr&iPW=dc>K9VT5|sLTO?Mo(ICjV{zVDgNe($ku4T_5lfL&a42v9 zFucI7bA|qeTcdEEiXpPz*GlrXYM+>%A$#Pe$D6tMvla}*)Fu^M>C{Fy|yX4`0{%FCvbIj2j<}Eb-x#w=o z)WaALhQ|s#T3>{Xz3o=c?|fzdQP=;;*Y)>t(AvfzV_)z`;m~xEL&O_3BhIN6`vmLy ze>!UVkDC5f^{EIlp17tzx0J@F#xRWPB+Dg+mU;<&Q;ZvtM$>rIs2=&_PoSp1OJlAr zcVVDJuog`XO&U0)p&3W%#=f@osOdjy`ghgz3y+){>O$X-V~`U6)qlABL3BNS4rG^O(U+jZO zmqHt34Vn9)uh!?T<)eiEvtxzxn`!dG0dIch6g}64fcOqibsJQvXq*{jDP5@5usRH!Lo$Rh_CavQ906Pk8} zXD}AE5)a#a*yh7FAGY~RDA>0wtQ_mqrJZBuneEk?QRf~eQ6MM! z_0`2P%VII2W%eRG3{oI8bCFmrk<42RX!45xw5`6P}UfkYEIam zeHD1V?>gZ=7#=9u+_oLhghXf+i^_SaEVW|Oy{r}60beGUX`d|TnxlV5*oaf!Sc125 zg4>s%q~f#&0yj;((s?=pImROD&C!cf5ZxpHzFVEVevl2-$!iDSLnbXaVCr?PI<*I! zizp#xgcG3ItN3XNuyJRr@>HZw#p%YO6d)j)>Q+s-cI+KXfTKI96lk%C<+Qon70Vk5 zGVJsjTI^wE;0h%hoO*@kE>M2+I!3tN(?l@{RH1Ct1sd_Dk}AeXP_L(gVa@miQKUn7 zY#($9irgqdYjIYU>~c1hRcAMYSbOplhwm&YL?{ADu%}tPR`yhq3}ke`HeR11Q8 zqZwv~g)Cm&4Xf%czhG@?n@(Ik$35)p2GttjUYI)rGv1_3034O%8&K;KVq^6f8&u-T zvG>4s%-j9={y8+kkxTPgNURQDaIKge6tRTdDKOw-@FcKhnYq4So*u6iR}a1m&F2s( z*a6PfTLq+gf-1oMbebR|rwW2rUP5tUt`xZ~<^`QP^!V=J z6eqm@G)_t}JB-UpWp{74>4w#l+ym!=TMOwItgYaf@$8Pk-_2Zdjj$2fbP>+Ac92bQ zu62X&X{mxJ5grGk8^jQh=u~H?7ea1W^Adhi{~ zfJn5$03jlQ+b^)ibMQkL7@nzFWQQj`s2XM^;3&)~>Q=R>JZOro(O8 z6DhPyVaI+$d&fCKgC7D1P4Ntv=t8^JfnxFI@dc5iLhY700>(=bT&IL3Kw!9}AK_|7 z$2G&3S4?w83|E6g0|zuaE1OI5Mwlz(I1u6p_rKua$s9@JFBlkM1-wW^7Q0rUc&J=b zHn+(66sjtmGdOC_DCa4QMPuoJJ_vyO^1hCz_B$Cmkznp2$-*1;;@bJ`a+#pIA;ZSr z({Yxv;?zBslJoSyD95twGp!tCo71#v@B_~FdBWK!wb~C&38`(zAh91pGm3_aI3K#F zjLOX?2xq(e32*-WG}Qyxb^zN}fi&Q2KQXY4tr>@*EkWVS2SK0~+M+2GZJVaom_+#i zY8>~hTWVM4Mf}-%)udKp%@i6PBCKN((~|M8>oC!? zHB_AP$x0?o$FVqSoDQJd0dzZnZc9M7T)1UDrT`=5FjB*=>6k8bRkgH$3(9i|zdk)F+7>UNx zYWwkL5)b42vE07=V(6qee@Sxcd)2w9NW8fQXTxVTrX}9^Gh^Vxl4B-gqsWOfZ{-VL zIrfg4qB?)&;*{a1HVtQI|4N0wz~%d(X@f93o(ufSBp>Zqcr z<%dCq5-s)3n2{Sonw<%qy{?J36%f8>r0x4TQItDNd9tE}Fz?sD3VczbD8qh0o--5I z%Mj~AtsLihPg8NE7WtmOf1F2G%bf!s^g^D^^jsbZwU@5K&5S_Qqzyj2|xDXXVo63$p6}cot=L+)ggtt?$h4+(nta zygawMsi(@C+v%An)Ts&fIld&g}6vTzG!eMbbI+O7`7@V=)!Oo3hO7iq~;OvE%3*v%2hQ zp4+^~zRvEgI3uY`XXnnV>It8DYgI}~+v0-r^Es;OKhLWAE{&2~r{#=Y6Qt`(Xfu3e zyb8z08XHJH!K(WI<;Tl6M@jurQop{WUegno)DKPD^|8yLtxX>!W(kcSH*0$vy3wSK z{ZS)&xcMJ{Nqrl;fg0{Y?rjVrg&@h4LNnC9woT_$&qqo9QBuFFq(1erj#O&s#8Y=& z?-#LLgF~s?)U?*np)QY-`lGDlD5?JiO6qH2DJ3SvdRA)I8!@6coAn;t-jSM((shhz z&T1os7%_{8>2WNMlKP{h{wS$GO6r$N>XX)?&C-NE69NwPqC9S6=u&E|!{7T#M@ju> zSW+)c8D=(eO5Vc#DgdG4^*fv;Wvxbejz=h8Vpj35UQ#L zt}RPDjH8Wm)L?ynHCSBKt5*|EbyYWOusCYXT(i?#<~oR^3vqSzo5+t89~7^q^3+KdR~k2RcDpm!j5#P?sr7;3mxo~xAO*4(En~Si|jI^WO0ki=e{OC?TnWW7TVHtbcSf{h7&WDtc^w;v2*%qaP^?ag zyYRxQ>?EvF6ZSf)&5YO1&RhtQ5tOV*PTP3=4R2c0M5bR!OUf$leTn)t-I^_e%kYf82HF@~B=5WVuWh+C$<#;$O1W_gcKB{aj(h3J=bLSvf_#O>kxf9$^h z)Q7-Xd1LaXWpHX!o!gBi$KkH#z)Bp&+b24|Yp?DDq$)d024H3P6fj3!9 z#q2Z;L<&x@gABZp4sC0Qg(xC2R=GsDZ6{%!7ClZayb!;@|0mklAu%HkNYOjQc^l(N zkHT{=?!0&xE3esKY7CdXkzsY_M98PkeH;;su}hhEurx#)X=7Kk>h2U-RmW@09gq^l z6A>$XFYg&avdiPfs0e|){TpHLW1KNd2!_Pbw1k!R#z>1zLJ@mP_GU+_IGnSq2`AZm zQh1v%^(LB|RzN)@hsnlLup4^Cw;prFAk| z)!WOxXLfrcYMC^QC!i44s9bd+74P`tZFTY_V-LQ+AAIOMObFpHCOdBvA|se9Z(!&n z$+nD2f`&5h7Be*oN^|QkNJT}UtbX9IbFD-z> z1*3Qp-dm!cTFrWQcn8vZj-2zh6L5B9$NC%8HYCn_9Pc{-Fkx6%*VvxKnBN~(y~Y9) z0271V(J2rEGDvgG+3!H!mS69V4=AIEJ+ zV2%*0;ooyB=gCZG&-P)#)sLtc?K175b;#v+;6%h@?QJK4EG2&002&irxG|!Rk(gGM7!()NH zhZxV3XKw`Q?X#ysR><{|43t_NSxc@?8K+@dMhK~^>%x( z#}go2aoYmm7kwh$jJp;H+UyHf?3m%ix<4OrR`+#)bZ(ynIUu*H^%QwI#WxfIyD5jq zu_OcJiq0F-K^?>^@UaI--f-R@ic@nWm6r9D}4Th1O^c ztyfK0Mi4^f6GUadeD(J7Kw}?h?9~mTBL^TNq@-?Z!Ckjt&F z1CD*bu@5-*0mnYz*vlQx`WQPz%)vXR1hEuDL!&wqRM&E)JS6*+vQq~fdlekJUU1B5 zY7Q_#x~>Bd=8Ka35<$I~q|l7$BEGIdpTDN~q+Z-&7bSkG{7$VY_maENmaz@O)`m6_ zhun{CWleExk1l6NlIMV9ACBf11;@6AMPnnuhA{`J-uN-c6#7Vs25N^!^uS?!ZpJ%Z zL}rI!oNV{a_N3~hWN9+%-m7IY-ge=oab9`>Q%R-JjK?k)WQn3(ne->)%I#GmQwp^f z_?5+CsHsVz$=au}YM)y^Fd2vO{`mW1Wb;z)M5$=zGokB!bfb8sAy0j#>Iwfkf0>9? z^Og-8p~|QJRXKa*pQc@4PFez9&pj$KIik}hP^IRaw|0Tr*@o=wJRStVZ-u)*0ufn< zVyS6!&_?jMwE-5Pz%YMy5)qgsS(t} zDceU3^7ypw>cO`cyjCJAk*nlfXgUzTnwW^mJAM{~d@8aGfn%y9Dkjk!E;7?1)QJxP zK?UZYs%*o9t{i&D0yrCv+kMR?w4pvsy22GMD(#r)si-*{u!t(6n}z)KJjW;>iYI$WIapG#tJew2z8 z$PSBfi8UeK*tBo$;5*P@h^i1t!H<%u3-y^e=5FJ=ERLQOiqR&tD`K)h7v^XLM+9a~ zj-cAyuot5_NTJpx$)2pYrr@5N)k zq+2>a3cQl!2(aRfG%0VjeXFPVp;y5Y7TzYpGKD-O*|Z7{q;iHxMkMFi)3T8hW9{HO zRzaP|!4;m?oE7J5cC?E6L!BsXIunbl5d9~sW6B-(oMtSsqYB}!Sdug`b8VD`wNu=> z3eH@?n5nsfaiCt!GkUE$-9oMo<;3)D(Ho3Z#4E}$fbSW+m)UI>hBK9+S8^1sTM1Iu z4!%biJe^Rm78Bi|GsZ2yax`B!NBI`46U*9KmNWZ&?&&+cTf|GriDMlcXNm2UGKEA! zk)&i1XD2U4I8G1=vt~~0;{3Dgn%kZWXwHqa=k;!di1|!}xPV@FJ~wAPgeM7I;=Ee3 z(B~q>dG#4?%!yQSL-ew4daIM7+>G5gwmA$_QnYEDCT?g0x3z~Fl-@pt+M**V`naU1 zT_DPVQ*O>t0be`cV2gGyyW$+BtOdsKbUmpC@6%gDI5BFS6QTqMs-#I9I6I3yS#1$F zeII+%Aj4RKaFc>n#vj7DqrNRAA9T@2g7o80kk;Y^$bLtOU`b|nD5qlKJn@jlNsTWh zNLLTCB|*A!@Er+(T2$FoT#wWg?L=)92@jo;FBX>)Lx@_PubALRBIFdMnI6c==c+hG z8Y9%xjX9B(WA9i2_><9ZqTuAo#J%rNfX;RDsR*Y$Ip@(5HOT!zd>P64`}360$#G+l zxORSfR-ibUlV^0`oFV|2xNSTICF~(?@jiaCa1PcFvf&)89efWnhO^s{3!3L6(##wW zp>y6i=l97@rMMU&Cg&|DDHC5ZVz~0&Q8t7|YX{%63jU1hH5l+i^t1}O!f6&m;l%ccHOs_So z#p<~k=Yum{W{q;zI4jO==KS+hrjK0Ad@YhcfY&8X&m4-igYQ@eXQuM1xa$6<%nXf@ zodBLdVZZm!V#0TdI*HbjeYii$w3;XFSfJNn-0WOo&#JqFwUgYl4k;pFPf!i)v~M$G zsq=O^RcV2N@++DJ4Y_`h4H|Oo;5#DmIyDe*dGjzu%KQYg0{fJ!^NjMMt1$U9#cvF~ z!b4^X{Ii2>NIk3^d(RTwbjM~vyW@>nT}npW){Q5cD~(Q3?D;N&tFSQ_v2Jz;Y0~FO znxtCG(8LrXg7Y9YXlP)>0&5)m9u8wK{0WjK{qXw5pPqgFmxDLy;7wZQO@g2K#JovO z>?&fB9H@^?kaoYZx1ahRkK7QULZMhjWm4HA&gOEz7{m3Dg)VJN( zP!orPH|gL_+Qpm12+s=yDYTA7mbR&(4%7$jhn^`7S~(u-^59K6aJvU@($CJDbR!&0 z-iD)?*LLJs-?1cB&mg_~)^P|9mZXCv>0n7ZSdtc5lA7p!&ig*Z#EzmHQn0ZbgICa{ zQI&gb4wj@(KE605=C9D5c40}qpNp__C8c-h&U8`yqPm>Ok*+G1Zqp$>8QXPljdV4I zY(|K6$38SsHH@)s+Cri|>%oR}q;3v2q{E^7lGuWz}|Pfh!}j(TZkiaAfXR%gkW3)j7qc8!8n$!xr|0*W8POem*&>>o*yC&`{kI$u4 z@($X0YECaapGCsV9f*K~?OoLu#F#0e$y=Ca-hn=JBT@65Bq6t7Sf zQgf{Y-B`EQ#;={^2VV#%Q!g^bcBbq=+l>o>**Vq&a^~_}Y$LzK`q6hRgxBg8ENOKZ z7PQse5EyneL%$aXuS4(gGFk%Xf$>`etC)#S@D}pI_)IR$sX#6^HkHMWm}@U@at*T< z=el5;x;4WpIrteTcpsqN*EvSmvjo$g;tWy3>RWQC23!eox`bs~fg;}IR{XpcIt>D~ zP`ybp%wK_V-gqq5&T!8nWWOnfD#QUxj%S!3;qDxsLEdCL*CiCyBSzT(5?DR@j%C0m z!MB6t!|G&aEo+wHK8{KwBp0)V+mOnMX=BAQtiw^Q9DD}}QI6)u2fhamTAmrbqTBc4 z9k?Oi(VKBEI1J8!0?UX4EXt~<&BD(4QSl589JFoDA8dFkP+H0PYv7m6n}lP5kG=gg zCTL|Jt~6(F^)15r8Psyj5W*1Z^Zecea zTVZ5t2j2moa+ev-vsQ7nGaa}E*@se&IH=CrtOXVkzfv#Yd#i_SoDz$~bQxma7#>Ur zx#GR$VGgFFwd)13aK-xwAih<1f#x;De~{x9Gy9njzNOVDSKei z-5*LzA#a3xs>vO8m=JyM5RYDfnxRav-`TBw%gt9TnRw0)0z-h~gCQWT3|Db0Ky2LvKkyQqO;J6_sIYdBO^gcb24BtCle!W+8~ZT! zmV$I+7g}pMG(5DqG)2T+gSvX)A4|7Ir9TQz%G{F|;w&pwv(`>bR5sxM@3X z+J44*>pYcNzpJf2uHKHTw_lD33N96SiyEhihbq=N1VWtVE;GX8n24`fULOk6DkA&n zY)bGXYpG7{=r>^q1Bi2)@($$vD>epd>xbWy+>Oo#WSy>M-}Mfq=yw=W6fYm= zL~i!zAZpHPS$PFjFya-DqOcugg5^4~`4U`BbABy^M4C2|oUEPU2VMj0bShPxt%v;e zmNFG*2Qg=K&K3z?HU`_sEV^>&9XGZJjkUsYi_Y>xvV2|X_nHOq#6(5}$F6L@u0(i; z2tSISWZ}J}uwLEe9FTr`(Jih8o6xP+!wY#mDHkvFsEmQMRO(>5OWQI|&MJT0O12 z)Ol@cRDoy;u{@4ahMm;4Afz+R3C=zIV9@zI8FX@Nt&p~1aBPT-O&g3;6C@5jL&-N9 z(pX0jKq;`E!Pvht!Nsz(KPhJZP|1aK_+Bb;H2Lk{*N*M;hwm z=g%?f^H5+Y`Z{(&n%IXn_igBh+>V-^`9u%?oP$4S7k^IM%g_%>A+-V_)3FV;X;Sc- zUCD4)iXH0m;LkZy+XsKn&wrnD!9-d_WAg zH^BOH{6X>OrP3LiOq|=|#YEl#tXOERE1{9pYi?rG#`cpaCh{KESAW=%&p816hfjHs z>U;=N9aU@kwltxuPO3w#ggT64AnnXXDMRh_=;8ULIgl$b-ciRfMWu5!ZzHJ?P2&cjY0?K;-o!QK=}tx!B4($BctetMf3FQ$xwKgKR*St{i)F3wOO>iqTPvoY_Im=`zef z={Vue=%iP?g6P58wFd^O-r>Ha>H&vUDq9OQV<87|X~ZzejHB)&pt!%ZOFMl>Uanz> z8}Q?2pT46)P1S1$J!dLh@E^->Q>8lFO?14jS2mr`1FhN$7G}PL`_jyE)6@b0VUZ#A) z%0F@u9x=)m!kM+BuZCL>U1>@)#L#N(oUwQaZHaAYn}Hlo6pO?ox$@cJt?42qXM}Ka zq3Ha?SGko7o9M=}QOpkZm{Kj~M2noAgd#h=N}aDr=mJtm*_VGeTY(o$0lh%q$Blmq+ULq)C=r2oH=*|(Zr!OE23{_?z!=$yg6PyKhkEy zIa{DSUz1KKp}54#GP6!OL8HLFK!XU2$R^+DJx|~IHu<8|>eMwhago}T$2n2C3Iby2 zxjX^u*1V$WX{j-qGih#%Ox`onjyS|Y$WGi>$uX8SF9S30$ZOdH%)I%P_Jtwz-c^2> zN6wl;P5)L)fdi1>HM}%=px0g!21t^5ARFs z`-XXZWVL>ht3B$bBY4hT46#i;Jn9(XtqeH~L(}TOeb%lV9`zUNQJ)%im5W%WU@oaz zlAqV1hF#;f=Pu;Inji&o+N9Ekt}!DSIvYkg9O}cN{$w3$=0`i!A|J}3K8Y{JZ<%U-&xaB`pyqba<%VVMv7gu8Ysho##YwQ#N3Bm zbK7;=i;UgjJAZDzbGfLRG*k7CEn4ckF1KVC6pK3fyRrAunQ0Zg^HGsZT$Hr3JZ)n= zCa>*lb1+CDyk)0Y=*&Vp3|$XlB{=qnw|scZpN_X|-UE!)oSvGkB#2MGQ2*2$MGAS_ zAZTt~r1T=H$uA$Ba<|F@qiiAdS~>VGc5TGq&Wg@{qdL=6A|fxMD#;m!6O7p+!MGE> zyNgE{B**DSmXkM#VQ;?WT?te+6O6B#;4Zf*JHO)82S5ogQF#$AdHz>60VvN6wc~9* z3Pk0Z^CrpR*$`xjI(6MxtoAzp8(T`d&W-dTU&VV%?EWusP><=hd;gsRVMK-(Fnu8Wi$9u-uAn_~5-cc=O8nJ_s;DIKh zT-L0>eP&mKiO>Q^)&$X$u3Un3)UNBs-mwJE16j#P;E5ybo(giacz;Ur4rtX|Vl9@; zmFS2aC!Zx)%DJ156s;y++lDQ~@^0k!T|2>DOCWwn>;%sUvU9y}&NwdC%&i_|OU>NM z!9VaCcq^$2X>(fEsT=B+H8?xShgyR(gYV04KJJY_;QKwr+xU6$1CqV7WvoS(v$ZQ6 z!j;+D59kkiov>f9d5fYdQ_HZKhn}KYO3;AOlJfv8`75zPPkHw#mQ+riha*&M5$|~k z3+}j>jhz(NPjL?u`F(S+a3BKX zq?6FJorbYwYkF&9X%5!kgZ1~IqB>ZAe?hvnsnJgMY!$+OHA#FO4qkmiY5Ixd5F8x8 z2gmQh@q2LmE^++UCJj=CF;LaUxdSyc#k=LSqTU}4u|_>Oem^&kU%iM`mB=zjsa4;B zapnR-x@ybxGjaSTu4FBu4kN8WDk708f^a0Zg{dS>WBLR*e!Yf5W96wLsn#QVb8!3~ zKIOsj`yn`f`;MsZvjsKogOuJA+F1e*ZMMdSZfp)3n$M5p_W?tF$28A&`-0;{!)JPDUkaQg#-^!j~cDg%XiRjkBR{D3hf zV~GXdSS%7MSyK_>%2JDXrPi1BxYt6Fp}NOI(AW-p%f>?E-) zfL^2X9W8<&`~I@0jOfa_3F%-egvJ6-1X zmCy@iWibqh`9|0rU)h5u?@z*%BBDHKUu=^_o2RSMgTE57q>c;T zROtG+d2Z&(o?fDA63Vb1I5VZDsSHk2g6+=al+cEM9_9dj|7gRpq z0l^0O3aBpzRM@;(>iGwp7lRVPXS*QEcl1$8lTcf97V2n_y9DXBC8enmGl6p=I2NQ@ z@@Wukn2NV&DlwOh=&7|c+)-EwC6{CJ9g7)Dt}B+{UZv&QF}9Rmt{Z#T0&sE&Z1SRE zu{75s;~+rzA|4|V`ez9Vac-7XptE2jDs(!`GjGHLtsQ&E5|}YNi$Ru1In7*gRdk9{ zDB%I=o{6|e5mD5E5DAe`nlKO3AS&XpdUGsKtm}BK@7EWr!2n>#laoH1%(TSVd)GT6 zGLb>=Qilm^>m|@oSS5+hD2@t4pK-KdlXI?E?FAV?Tt#pzTzg|q$y-s7+nf}$z=Kd2 z$(lATKyt^~6_CJxov?L+aKb+b&34${7JH;?V?ktEraL62r19{F7XA%8NDT zNg#;cHv+psY9}#DFsUMG${#~Qw&}sO^V>mJ0e?&4@S~uUmmtEh^Rxy<-9320>cc@r-c1 zXUa@Sa`7yUKncMAvIQ+zF%8#qP#DGt8SLa%IRb)1oJujm9Pqt3=))` zim8^(Q1UhN+l;+-%nA$`_8upIXkK9$T|>y@QUTYl#$_!1{Yl=5V{+VxiCjDO4iRv? zk~bscRAI*u+ez9{!j-N-fc(v%>ayUt-7Ut2CqyLS z%)@<$^?yfSlrAO$kK!6IM>(+88(OD@@WE60+$eY5zs^!hCmEJSdK0x_xa@Mrq0nNVoE#|_wxohG*g71Af&-;tB z*fsIYes1lWc>eKwJl2wnm?hJc;2G+Qwuvt8h|$=lsnoQ+ZQ|LHc2QZKm70g!CZ3he zEnO2osGyx$o5dE1_xEyZL&UQWU+n~U+9K%d`_K(ZgFy6yAtDT!yS~k}7hyV_;Lp$r zrif6=omxQ*MK?J-)g$1THO7n>_?;IVAzl;>LAV#@{>7O;d@>;a5nmdbT03BP`j zEuQkq!S}RqTEimnRM2_m~6V8lI1&T#vDCSZU(QQT;0ViF2XAJdhOtQ zN_dLFL4+Q~JFAkO>Jtiv7xr|2rQ~3Th5Cdfb;DEUD6i7&j3kM#7$0@u9GfA^$m2^`jtk^|9v}#jr>Nw-^%s1bB&Pe7? zQ@ul@AMf}oK;=oPwRX5Of}VHo@Sx3&EdtrdWupBU{J6rk)PmVWrT|4y7hZQTRrTtY zAR;Yus4Lc`|@^CcJyq6b{m#O!A9PIJmDjU5t4Kok3IX@i<% z+MFZK(0XHT+>F$QjMZS^Wd-jRgdm!Xpckzt5{{Z<93)_ZYAGHu`mbBDBYvjAB+Y_S zAdKwX5uH*intHxa1&MW3m6ALTo#4Nf+N#2n=v2NM%UCH=Q?Eh8b#ruE;1 z@gm3Yj1gCcL8&;i9>0Ndxh`|(rQk`>DB%@b)A_kZ0M7HQ^fG7B$ASUIV9W-WGoE>` zlrk|EE(yRT0k~NLa5^hRZn)QkF}epQk2 zzPzXxD{u{d>>A#uKjFpZPM6Og9t&kb9Mc!4@}D*fYq&I3W<_0@g#nVTI97WEw0@wc z!;lA^K=E`RmmAkBUi$p);b}kdrWUhO3s&$b7(|at$7||4aKV((;$qqZvH&c%)O{5oGHOF-xlkI-+nXHHp(vXHd9ELI zVg`&;;>4fDQFo(!jz6btct;Q)o)Dje_$0(NJgt4t9jJ;Stx&M58zX4E70|XQR000O800000S8uEymuLV0l4t+`GXMYpX>DO= zWpgiNGBr3fGGsV3GGs9_FgG$bH)c3DF*7$~FgP-0V>f0uG%zqRGh{U`aBgP-l4xz0 ziBL{Q4GJ0x0000DNk~Le0001x0001x2nGNE0Ov;HxBvhE1ZP1_K>z@;j(q!3lK=n! zL}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@1ONa4 z0RR91ke~wq1ONa40RR91kN^Mx06#wphyVaU07*naRCod8y$Q5s*ID1W&$;JLZyu^% z&68B6$w;zg$-=}F0uQJm4Q=A!n6OB|^a7KCwbD)Km0pawKi;&#oYZGCUJtkZD0G<7)_x&U0t36a9kg;C&wT;65HvP;6U>jWUs z@HXe7DHoKsyVAs77q@bs&Vu4E4ITb_zx{UsvVY4EC=0UXm2p@7+DEcu0hUuBi$k+^==rPVX8Q#s{Ef;Crm4dxmN9Q7k64NAJknbYPtfSLDGSGWKMXa63}aPJZvM&^j)AzLZTNT(B&S^Tq_S- z1fSw0?~-5y>Nn=n{IIB?8=pStiX;16P}t-0<(>1c6#g&4uJ3v1a{j;m%Bz^;fc_ZSS^6f(V%@53|hiS#)VI<{Hf*x3~Z+xo2D{UU2zj$rW4$ftQ({^GJ|(5M(JcGyo}qbrm3Q3Y7K)SgiGzp#rnG(LgQb6T|Jfi2)S>ILT$c#cI{Dyjh2i$D)yKY+CDCKQ z9(0y>uOj1<QGxRgk0t<&iM#5huYulLeAzA{VB)E>b{a#HV_LF2RQ@8J{T#BpoY) zYOP=A+bb993jF(C`959c9l@x#AsL11a7u@?JnB)i;<9s{an239^pTQFPUc-$m~crt z>M9)!2vgH8nHjCSozow4d#3;2nfL$5=U)B2ul*g@9Rk(P{qfyHS@mPt((^O*)6cke z_46P_6}wE!6(#xV?};fO6U2tfhEUK>@p0`kDE(7K`?67kIX%-`5!s8#=E0h+-HrF0Iv@pEq$Rk7FF!G_`9q)J^tn9y0uiWG-zS@=WuK4+@elVN=!rRke_1*6L zBR`Ql^(D7*?qOH#z^;N740Cm0i1k;%<_H*(OrwI3ic-#p4zUH~AS9bSNE3AI36O}{ z&od$S8qUa0`DlO8V)0|9hlO;7dNGv2TXHQqrDt?H~uTd+>6 zEt&}-2*i=e0?uExBc$F8wZ3&~%&k2?;mVC&ZYTlqIyI;et`!9EEWmw|4I?9=1YiQ*kji2bV6I*`UH9?^4#AgmAqm6rNi)Vi$J^T55eEK1H|GX<^ z0F2p|LF$DJahQV*j{|2IkT<+7wd_T#>R!Q;fvI1lR`iqsqsP{ zP_BnW5$`i(V zvM`BRLPCBWd8k3ZRb7$x7F?-QaEs;8t?t|I>NnlcIXE-Jo9UQnwjVH~ZY7~S$>l&6Cn`*%JIF(+P$^zRRtntk@v56UdosUv^NqhV zG=`;neEMzN3@Lx@%4Q&VRjq>ONA1cNf5okxzpwf9gL_t%oFc=bfwAy&=TXO`|a=3gk6Wx0KW|UCBOT-SuQ#Kz^^CGufG5E zDOgtRxZ94cCd;q6927>xMZ`yd$}-#$`p0)s_y~=wEv(?bKJ2#ccl`*=(#scNmrCyj z|Lg1PulREY3oEwW&_v!f)*3EBql|1~sAC`zq*z_8;SMQqK5E07Aw~rzTmg7Bnu{*0 zw{GuDj{jQtKY#ZBFDbk}iwV$*nOPVO0|ZAQ4in7d1x*yW3{AVz>=Wgo0#%|zMOfCgPWuyI zCx6Y|LhtCm>rA?=GUisFC8A(u*p)jN7UlY&ZwVwv0R*+Eh#-wetpg0i;(!Gz8hsDl zTCw2fNAs?H<32aKclYm)%zo(u!H0iO()d8iz$j3C^^5<^6@Tm7;>Cx)ZF%9dZfb1F zm7p*oW_kf56p4YS=je2T+!HyFN193kB}%c+;3>}_>-i?0Y$CT3Vk2UC19(;z=A1sE zP*Q=7j0rrP;|36_`^l*+fyQx)nK%#tZb_xRwnYibC6@FO#?e9($8Y4@zfMCGC7HPb zu*sptrGfzy(Po&&E&;g|23J^g1G2G6>2kR?E?aC8pUicSlG6y6YFNd{n05%GE4oB&DQbul*(p@mhJ zM-s?&(gJ8relYutFv||8>Yzk2)TstpR?LCQpePLW>!V1E1SG&CZsMbBPr0?DiA&Cp zxZ&n@mzQOlo+Y`aC%Ew_H+uv!7|~}D;Q+Ue>`G>H0*aza$-diMbi)n5`CxVS`@i|a zAC@}0rDe-0(1+0%I=BAXFSz=n_gt6?M+mn3Xw^@+PbgiWJxJdo|J4S{Z7utUEF&a-Sq_5GNHS<4_R%I#t?I z&~061W}5;EIk8_U6xg@&BMLpS>A)3D4nqxqNXRWz6%hzAAaJb+SjglKB?hWyfiFO< z&H2y7T0MG9G2S1z^~j!DmOb#HAo%7jMWQW5p!UK8Kbjx@?f1FL6K`Fb{cATKEfK2& zKJ*Tbyk^5%$S5nsJH`1sTNq17dod5J`dVLrhu_C}_4^T1i~I0@8G#Mj)6doe{9B z2Gd|GfB^#mQC<3JpG>qOZ3jzaJr@P`MV}YPUH3B|&F3f1r9;F>2qw3W9!-Z43EEB9 zIeprVH?#LAk3W5XE(q@9u17eox@;K&#qrvmN&eis&Y$|E8*@ipS!}CL&=gul4mJ`F zExC4q0~S@3>7GyZ*_c0W3G21}2B}18KtVYn+s!2qhM6W#1m(&=B&qwMnXZ8zd|yj# z@@0^!teZM6SzU$FgP=kpX*imV*L9)YV7h3pTAC6NmlN{XFZyf@<4CJn2(z%>*;hTTQ!g&oDiLB1i!St4 z*kt5h4@%wCYkv2;Za~0}YaPcjFBiiD0=x)C)^ADB4iYGpXuqgk%s~i?#X!_ zy4-ulzS|E~ri1#81tLckLD2D%D~^|4ei+ads09OEEJQS(>7VwTK;QlE?pdoYAi~rzNiRxuxqT%);AMZbWOi6w!@smqB=S_f3eNnX1`GRX}5`0)UVLr zki`b=)kU}X$RoFOPM&{n_W94F(p`BGa$Zr%vajUVmMXuHYgP7C=YI8#S^6Au$0A|J zti3WeV=(Y_3;43Aib7}*2UJqzDalF^fX@vV;b_cO)RFcoHkB4G69wICYTJs0|x?a$yD<-zU;3dh#J;woZg8XM;v!slhKf0Y#mwBkgWe<3p8;- zCdE@)$vu)4 ziPN#>skJ(M(RgV+yrGmKJm(GTF5c6-ck4c1+y-k8NR^WeX9y$;E2QEu1nU3IJ}w-@ zgY|WoPzsYNAs6movaNmfNtYZy{|D#)`+q;!e~mA`^NJ9tNpgZxu>9@q(|_&SmA?YM z$C)jJWC+j{>m%W!l3`5#(F}tmo0|IK_iy1Z3EIRDWcL-&U-x{dM-4zdW+3YP&aI5duX) zEyNA+dkjzaC>jda>Lx_@X7+|g84vS_qO+-yB#^C(Wc{_|O77awh8~b$ zv*M;6Xu2+F3b{5>Owg8+01|cUilERzv+c%FZSxC@u73Q5L)GfSAEU8s8Xx*+rrkDI z&wl!yS$ytSYUjU1_~{u}D6E1kESAFpETf*N4)cb-cHI*a{qed7n(4jfY1{@@01mUQ z$9?QI0-OMeK%Ji&cEcDn7Z=<3*ifvjO$-dmG51E>)+YJ6z;cN3p@5>!0=|$={ZETYr@3&nS z@AIGvL0E5ORU_;_ZJ=So05uAVk{b%$FhYH23E2Sb$YX{HWpqS~ji58k+9izdspSSlK#Jg>FgeNn(M4=zGgC(TZ;3QC{nO$C8E^GzMGG8(l`Pp4oUflf zU0CQe{teeQg+M);@Tx6ZZGQP+DXRa^Y~_)mwDz!3pCH32s_EIKsxqTnLMGLQ`X1y6 z9=8k_x``rtijIL5(Lbmi4HD<^*sOQbO*?cF1Verv8YiA+n0OAADMnx?|h!r`(L3M~Duv|*vLZkG( zw6x;NtIc~(|K>-35@)zVL;EUyQy`M=q;cz1v9++e@3ZO zrfA$?WyZE>z9^3n%nWi+Dm9*!2E9S*tCfA;WW*X^*gGsBPl!VoX;dcJ2z59hR78TQ zth3=bYsnC{WpoS~s3NmdsJd^|WxWP?#OnRpx=$gD+AU-efHcTxl==yDLqax% zIJzt={boucXEM)vtF>=`BIQ7@q^k;@QQ+e=x7E+g=fjDUAHFbm;n%o&qM!Gun!ZY< zn*Gr3ByzuAY}D3&4epCZQ&9veYPYc&A`6H- z%qckoNF(IYJ%M~Wn<(a2ltyV32#-A!C}u$FQX~LJ8x1pHV&(8B4q?I1J$D>xm3$;S zeR`^&*Yt%z*>k^tZ?1XtE?0Y!kckVP!m!>c$jbcogJM|Hg}tf60Kq=RvJ4=aPF;DZ zpO#(eJ%+8kQ#0ArVOgN%0)Rq-G=e23?9fu^a3mtVA#vE?nJidxYHDKmqMLh1w{zVq zTlpc!XUbup0+T#k9exvznM+I95orSmAc}8&*~H5=2G#=`26`sy%NsO*a$L*t-W*6N zTB~#ACGrkjn7yz1=;waApVz4FS1eifVOqZSW5ca4&kV<3cKHI!k4WW~CS!DLgq%EL zU+T3V6m?&XR;raiA(zq}g+LOf^Q->gp23vvyHvlBhhz*cC;r3&Lb8;xdXLu%RQ|rC zK!m^uu8%RmfZHx+E_9%pUQAOP8Ayxx*Cg58%x+MQ>#MyB`uHm4)Z5fjNtQc3T!2IaLZ zulzpEJP8_7-Aj1$+t@}@LQsrMshb-g*Y5!p6V!pBXbj3Ag>Qz%Y5*@5X;2X>{esWMPQ4 zSua*642f7_8Aec+UI#Dzj_dYp$c#@VTrl$#@t7|&pBTV(>$3^8^w?w}1Ni{@0zK4Z zv;$j@|xXFZ~wVn72c8b^GG%B9vif5Am7^?&b<{rM{rnOAI0ec_Y8 zSST<5gI4=V{4#S)06JoDq$2>=gwdB_@xZ#bbexV zo!;{IuU9A;P38p|`Gi2MbLv#lj=b20NC2$upPm>Tz}4S2rk9Yk$J5w}+DD(yH=l0& z=k<18;>%?bsIl^;L%D3}ZI#8xA*UzN2D-eLKBh?WX0cUg2G^fUGik3X3bNZlqGVb(NGd!ih`0^^yqW znx8#b&aeH<^6b|T36_B?at{A7Aka(nUF(G8ARbRqUwSr-OTFPbKGzGhmlfLc3#br6 zWUjzoy@M zjjZpZ9ONTnu|oT2+*iJG=u$7aw1BksG%0tMhtn4Rt`r19`VX;1q^Puk)~*w0lQL}r zGY*14=I;_8A6(}y)%dGD$E{<}~ATC0I@VSVufXFtgjO?Z9fHnK7{&>`+lXN)2AE;F=A@9q>$`+n{VtDr4g-dE; z*7ldb`SGmNdW_R2T|TTxsiY$%C_TnQshLWWWN9<-b&2{6s#h;>*p{9V0@>ime25HW z!n6ECtcb`%g@jka8)MyD`sSBZCUR$1^C9B7bGTMCVTYhbP|N6zU1jG`zc{v zTA+}}-UI@%_{Ej$4L30{@n0_WqDvxBrShQbw4XvTndQJeA*T$iE07lw6;Iljm-+zu zpy~UiTD?W*i~=z^G(3KWivn>lC$y}FMYFg+IDn@|wk>+`OREtAiJHeGE?&kSPP*b8 z>y?y4&3LKdkJ@G}ed*I%_FI8CthmG8r;h7&q}Kr+IjGR;sWW$HfAaBfeCf+xhCnni z=%j1;I5~@B5wo`JJccBylqEFMErp=!vzVo+x;pXoSGx18D@bdsIHNwn)&gQY433-| z_!8+Z1_*n$E&U^8QPhHRGbN->u0n+qkaw!lb}_O2t+?J&tWIV16Rwk-vr4wS zeOFMSw|vO@@#@FstJmOeDEwp&@(&O~acpI)Af(Ckl3O=Cb@{LB)Lztw!2lscY)mSN z>}hCNDbD6B8F#H^90(A3ExHWBw2;^UOG9h}swecEkVptLz+#F8Zv$Z>46QjCTfrtF z{p#GDJ9YBZwvB9T9f6#i9qPobk5ns90kG2pY~kjrHnt?0LW4)nKTe;GGANBkQ-2D0a=oMYnDH_K&z{|ArtiUtYw* zn(bM%uNPb)KWoZJ@1|@1X`R~8ijCCZa^E-H{z_jrKF&yaYQq>MEQ6M}KEg7c)V;Q8 zA+N7g*~V+@)JG>_0it3Wj5ZVw>JuuSiln0L7E|H^`c`FvRCNVrJ#rJXKD7LZvfhe? z(IBwcFPaz}0{Q0CPO(hhN9GvJ8#1Kw1#}+64!C;k1-Ed|cI-I5Y-r7nde*r>PtUPZ zLAgI)4BFlUf15s`4;#7zDD+cIU-C*9nWT+LAeKHTycV2*WgM5RPS-ENI zC0Cur^F2@Cd~@6th_4E@JPP&MRsRgQMFhwZ>oF>MPbu%7&;@8Ew3C z@~w`P>8$^w-OrzO z1j^j!t{CcrywkWq-5^k2zZKyi1he~vd@AY_>%zL$XlZ3$F7j8m z`mf$!b)VlHLJ8(F^Q%4{7XL_x$EV9X9r}H)wR6)0+Q=0L(tDdL9Ed4U-LZf*b*%qqfD9 z!c-TaHcMn%t#3!xz``%YF$x3A;JY78ArKRV{?Qt)V@J|vEdwfIR7yE0m>Oybp*cDj z6%&q-Xn|yjd_zI>)>^gt57i9j7j4Sd-&riRZeKk;M+#mUzVN}wL3$k&bx8SeG}P;I zsi4cOkWp0UC9~+7kKof>v9r4JipAT3y0?gp@tEq-A-Z98Le342{Z+aCK92+<@YGA) zo_#Se80peV<{D?4E~-wFu6G;lmXIyvkdaaCR|hqC8Xi$5K3I^Ty+QONQv}2o7j;kG zcp*z(M-PU)F98OY4Htmq33jWmHr&E#nR>bi)JSGKY5M}?tBK~pY#`qtJ+m9G?2mf9 zv0NVd43EFjKDysckmWQ#BUDLcaJAB_hVvE-Mkl2iDJ(-z;%M=MR z9HwD?h>$7_h)U%L-7^ce>JZjKd4zaMJnBstAQ7ldCP>|}ovORuV|q zOaX30a!VP%RJTGtVh-%B8fB83t~Sq( zvaCr)upEz^6tJjMh$7f0u)Toy%5%ZPEPtJH>GC*XqP(*uB0#6xTv%G{BHL_(kxwYbGfKG8RZiLC1dH_N-vR};6&psfP9B}TXkzg7M7 z(J1$NV;)Z%5@{9|07gK$znB@?kuXw1O*$BIjIfMnPqE`B8OS~Oa(0o7a~nuVkOW9Z zKWKx}oFpvM)Do7E_o+Jy9Ti52CDL5l$;=l!(O_9LqTv^m0>tIIml1oIBG3zY^hu#U zjlJpz5FjVWQy+2J`61UigTTBr&GX7L1FK?p#Y{_`2$dmW(Zz>VkCkrS_Fe5WiGyF= zcln#P?5~#p3uml(g9s;Bx4L^W|rykw!42p{K4hn9zOA~`E*;|@Io_)CTKrzrJ7!n+z zNJ&oFTJvt1fqk@$qpntS%WUho3gRrXIGvp{Tmy}&3i5UGY(!fo4wCneLrIEs%$h>& zUOu2osD}WlO!NwFV>n%vL3oO7zY9>Cr&zK(i8FE=ecH=vi@l|s+rhHsVN!CGsW{hw z%F0rvwdd*}vT6d-w3%^20LfD!@}RAfAnQVrzC=(GA2Y-KLN39J5Kzr4aU9{HDK3Hy zYp!zGbzEcIrAtGwEl%>zFkhw3up&LAk|@KRzEj_;mVWMe)k-dZg9aX?VX%>4icm?y zJJd0QJN7EZrxT9S^+~sQo`ej{0d`%eu$Zlelf91rN5G`09>Q1sVDZ^SEM2m0Yrwj< zip{h!$(x|nT_Z13yq3$FDw7*=?b5hg0)fs0)Z_50FV#rJPnc1iK}ib$d6;ahG_C62)x<4`C8k^*A{frt{sLYxC0d4Os>2}D!U z2+1o-@-0?waON?KcA$}kI+TZ9nbY}ES33jcSjBBYn1(X(2e#py)bp|(<}|hZNnNC} zx4-s(Bt)m!a5Q;Jtc=y<519O#B+6M`$-}7f+kpBG*I0(4(rw}j*$tTu%#wr*swAZr z`7!tbFrOAh00J;VL_-WFp5W^V055?;aD&1PjP#2naeo4qNvzTU6yR5{h+)q+|)!m=trcfqAY$g>oRD`o$u2 zUx$E92nTQBxVDHx1FUF*c8~#!jDt43kzA;zrBT^63QUC3Ue}CvGW10KtjaFLB~hS^ zZMB_kH!0F8cA%%!F*?cUXr}3>22RK$;Oa1-3ee=S0W#!}%XvY#P=tq;-B||g8MZAt z2DzEz_cEDNV@w1Ss)%<;Ak0z(cUFTIX#8+qaub~pABOtq{Y_*bQ5lsU;)wF-us|<$ zS{L~&G9{*xRahZ?P#0)x3puPF5vX1sg}S8<6PPwC0|h=V{Mdy+Qrg5g`%?{fcEn0Kt{L`woHnj8gX_pW z@^Ohr3bL9Frs;@kiHeefPcSu@aLY9+8WHV)-Gme5ktK6%wdn_#i4g2^wcK7;D;(ka zZa7vRqJ!*KL5dXxDxtnB{VO|txEvJQ#0x>jFvMVF-C~UFjJ(N;N|3kO$deub3atWL z4MoH544E*FS5kL$x#JeuiD$VOm{i|nBQ*_ufXQA+spLi)WeXSJe2kE5>@FK?5W$rb|qaScPk%iWP+Q zrx$AOc9JXHoSSev5uUTo8tsD0Xo83p!rFyTN>{@RpxN|52t}1R>TMBV*nmCZj&ODI z1yp#?JQV7}lyF)rg<*rtX8LOOHGE*!X0!WnUVca0sS%cEZ{p*c6k#!}mS})9qfHSA zLSHi|YR!$fYHmN`!2vX8`Ur5+bRNxFA+MsSkgGsePNtnGtH#w+Rsmie7ZA7#p6HT@ zO=8nhA+E?H;|QOytW&V1=cwjsD9?!&l6-y|wOJYz^n!(n1=xhBNi{bK{Gk#8D%TLd zRV9rPgW|WQB!}K^36`K75E8UK{wOeoBL7%wtdk!aDG);1Lo>w3#CKD*K~5o-WSSV3 z6N}{l6h+!7sPb5T+*RN~b>fi8U*HPk6PEIB*eJ3l6r+zYUVxm%d2QGr2zfY|h6)Vw zY)k3t2*L=;=>mOSfyz{g9Bl2P4{YkoA?q=%;7ML$+7{GESjggpKxuIpB)?pWTdrlH zgSPXd*}l|Uhyq5DYHqu$g}b2OJK!Mn4}Ym6PeSn2a+R2&dA1FN0+|p;UwFVHqjn#MV;5YP#fgXl`!-nvl z=TX7)sP_f>W-<%x2<8Z%XJZx~SSfFJa}CWWo?m5mWLW1N3hw+8`?~33OYREHaUn@pZL^Fe@mYS@I1JDGXMC13qRXv>D28dToDc zxBq58uh}1gQ*g_(DO)a&Qj{U*poLbWeQqtk2eDuqktjp-0Xb2VQkvw4cKm8o%z|l{1v@T{(8y3>Sh7-URo?!+(u~v1bs+n5=T1uy{ zfb4)7EK70@3ZiY8Bsdey;6@o#kD5Jr@k_|67rdmH#v(ftNCK`{oAj(O1_FfL1|+6_ z34r2MGWN-MX*&ZL1@Z$VHYqtnil(>jY6Yfh^sIM*^N-_5uCPn=VRp(n#D=!JxEw7k zLrBo*k|CZQp&w8Sv78$8av506Bga$_w3|#8TnvFUQd%0JJ%VM_FKvtad5_m-p-5tB zc8#{%p7N59u62>MuVYEbQzm}HO|qHqHn$cXcGWx^5nxRN%0ONOg{j2?$b6K4S5zLE z_=DO7sDn*uAV!}^KLrdCAVp8+mm3z8j^u&X(ZD*`t}jkY1{w3pFD2uBq)$^a^zM@fe=gB-&d z@u?P6&ovNE0<&0_W2K9zuE>%C%3LAn_73Ril9rj74lv-J188vLmftmK5(>+;0x;6@>lEtSZY*NRB`1!CVm+EhBcj0-`Qg76^;d^3={l8(U7V}b-E(Iv z?tF+%pakoHT;-t#nZhwevJgVW9%9@KZEP@2J{2s5K4!9zD%5pDA_;H^I{vp1$#C5b z@jf~7v|51wct`l;Tn-8-&LG5*vs`K0atOaU5I3ftHnNg-Lu`W}^5sa*P$-2|Y-M#+ zcCN`z7367IyU+#EG@y|Yex^>{jgj2o02FqjHR^I}u)r#mb*Y8@Lz+j4c8#Ekuv$Zl z|EMqJouaFW;HG#OGF(`WA7!tF<@rrxgeZ`H@k1dTGu^DvN`$4E+jpUU8xTFv9UPtN z6^+r$N^bylt#|0A-r&kQkBrFpb`axatVHwu&q1-;c2mn+E!iMcpS7b>{#I8U& ze0q88JcXcYyKH7e0p=V6FNkWaQY45vBtL26+C17vh>IZ$*zgtvIl3CT@T zeAA7!=BRH0+s6zfocmyDBFx%lQ7UgPAX7g`phTTQ{&s}6BB38+iD2g&2?EF4xeit1 zlzI@7IZY-BJ=0%dGBLmz8Y|hGc!$^_L_iZ(wZLKni>SaB1*H{L(ON#eLB?6-i_D-P zBs%7P-l^xc`Z!!h=_$I?h1==dPBd2pW>_*)1-Q~PRL+EYWOmS|cnK~ei38#rG>C&) zs;=`^JA}mIdD4DF91>2{VQm%2`cY=&)5L`|^6V&#&qVk5VeAhCgSbmQW%8mm2N^UP+3?ZiSgG^oM>5YwZB22+TmlYH7mozoe?+io@LYnS?j zphSL;I80dT7vo`i@*TvXA~|D~v%s9PPznC?4(?;3c>4owumq_xPpEAkA(MDF63`fg zaX;s=Hp8}@5~yl(zwVvJmDCqeP!8b?N-bP9^b@SEX~CdKyBp9qu?S;lXlx4NQkoPz#K0TCGHtYEN0#nJ z;YKn~0J!=gw^q5uEw9|*I?Y{ftb-=Cf-F#ndS!D^*j4;;Gh`=5hKpta)oG~BB2pZr?Bi+*zKl+ zu_a+P`oJzaaSe-Rbqq*%H!cKB7fv@KS*fKVp)FxFNRK>Z>|$hyXE9fu2sRt zv9!z8>$jq&-wZVx#s3Bz=zECO88@n1z-O1Eo-vYNDlR4;%`;3$Jji;`c4oF<#yfaO z4q0hiS`u>+FGSll;DT}YJKv1O*%|)yT|gjMma!@rh-X>eg|Z$BvY{@?e^M$G{NmrQ zXW=bS;8-#ul(UU*D^70)P4+WUKqiolq`!1W70%=cD3K8B3!y zB4I2TEON&TN&$c(VdV~K<6^jgbM32(4flL!$}Q$6&~UH^kQX}Cz)0H=72}C(R@A9H ztff#xGa%k3VTmw<8!;JV%u84zoCFh4ar`;Wy>7KKj$iIAsNaNEG{-Pa%)r+bF_5`c z;*oYB1S?aQg2~%Bd)KgC#l$fekQqxD(#iK4x4$OpFRfB&wYefqQj^#13!cBZ_QMg^Y0uwd^2=Ht?+1 z5R@Cy4H!~yGE$SM2NxMpLYTU~v1RST$;8H{f3{g+YHoc(?_jW`!0 zVCKnGnkec3)^0Zm%TU;bnyhF$#r(+X)3p`r&97N`DFR8j6q_kw zBw(^ZLB)8PC$a@Gt8}cjZg$J7x48-k)b8BOAeN1#hnDM_Y$P zM{t(xR7LZUJ7WkfEbb6866}Mr&C~be?8$l_ZEu0!7!Qpy@!k+?G{Ydjnq@QrY1Wa+ z5KFD|bVxX`eoCibsff}jPm`#Yu|(C&sEa#l^cBwp1xy)uO$MckF%}M6Rk&(`eA5u6 zf%2?@NUOo5Tg7@`#ds`=JI4MTLYe^TBg3LNl9phHm}+7oG$O`durF|b?zg7CKZ*+z zBT)krwb>+uuN3h}zO;zdIZ1`jVRfCOf(C-LW?4yAYYy6a`Sc#~rrvY}x%RMMm(v>SG`>L%GgWc7^+w}_!U z4ajse*+bOhZBU+@UA=Y-8pj^m4hv=g66L*ST(t%v1aT}rhnbTjgj0LomzrF`z0sCn z%sn}iHRR#XGnrtKkd02b7j}SA4Vy_m!;u3E4VlTZQ$@fDLmPeIJ2iN<-gimxT4!;a z>ZPYvzAh%Rgj*pIMRIHhLeK)i#7qcBu=5Kivh4GgA^K^JepO3nHJ*HiV?sS zFI+~A*MMcYHOv~a*aD|yntO43V0bH}i)d&|Ak7+<>N5Zu8You70O>6jJI=d%RL3+L zG$ggX-{S98`(^hQt?~6`>I;(~X41%>qfKy_2CiBV;t*5ipg!StjtP!o5R4}=vg+++ zkY`9{4(?BoorE|#FCV59q!f$0kWdJwCEhVxMvRROxry-+(2ruN>!eA6VX`9#zzuFX z2Zf*I#dGk;HkQayq829!bts~`!^oI{BW53pkRd?G0hM0G0^LSX_s;iT%Md|^TUenb zB-UCpZfR}5TU31Kp;^csCozslnt#-z@DsaqvPXlbURvD zt2KsT1a=YV-nM-r3V30Q?$gl$_gM2htSs-QV$5?|q5})7A#}BfqY-cvBtMMrDS{6S zhWbEKwSs}c&9q^PVrOW6z-*IYEXF=lz^x*!A;IY?Q@!jM?anQ(zH+B)F5iM8aWk`I zhX*dtOW72lJBoGIbTMj!peR=i?~$O{#vf)8)lk(0VO&DBgwqb;chYMd4pfnS<|r`s zZXD5r6pOc5M*xi4c=K~SUtl7Zm~6NLGc>fCA_c5AD9U1Q|{Hl7<9=v`glF;h)Lp*H!0G$0fSq5_TtULOMu zE08P!8x*o+40fbGLf2cQH&y_h_B`{nx<_B6HUoEBgdu@i@$83pfFP*9AW(rFgGx~E zB9Q|4`%ywbCaqi{+ELPq)MF_w>ngbXQ?$z;yif9(>Xi&8>Ojn`*b^(ZkU__g!9W_e zrS1?_*+6)2LlD}uUz1!mBDK}GPNAy$s`sf*G)(?#{a2Qk;4BzO^-vr*edk?LUoN(D;~46inFXvL8}G3z^oJe^8Tj8}QcO-x zxHIQw|IO_`eDjHDbo9u4cJ`P5zhHFNeVyivo2R2E>Z?fd;BSH8aAsyxBoD8=ZMP`@ zkG)Wp^J0!c8WKZ%H?m1cU9vUd81Pc%*1^pnt26o{NQ7M`nQ^uHjR?$l!NQPLk^>Cl zl%a}EI2!GDEdm?>LntC-QroTlAeoRyPJW?B%(Uy6w;oSD=6F#j-Pcc1y;z?NINl8) zpCU;#p$Z{N2aUCNEANgpIjyKIiNcG0^$wo!g@zjo^TtC7`U}|WybXv6fb448r$$8$ z6h#&_6*Zv(^>ZsqZ<4j4#zUpZP4AheLB?45o8JbnYPd#m#+`4?x|2V0KY;)MC+$f@ zK~yaaQHmHRVoz((MPU_OCIgbGc03|jilwd>oftszGlPm%zgb^FWT=6NcnW*5SstLC zwm_bx8{As$CT<+%JTd_@QIClI@US66!f%g61-uu2d*_OGD@_&w2y?GT{XEDL&jR(P%|lccngg*+;^$p3?oQL>I+ApgJIR z8v)+jAGB3D4CVaR8c9tMvporcBtt<2V&o%HtNx4cqu_3Bvo>S3pbM&x<#9a{C!rqZbr3Vt`9}`xq^pHnmV>8&F-txbpGUQ9{ zfK|~1K0$5`2{9~fZ|5GVv$UE2>Vg-LVOuthJK-{3mHKearM1k1a+S)66Em~)6RCXEa5^d1n2&q(v z+Qv51g{+-Ye|1G2whs8OLOT#^th=&RPgt92n2e!l65OrY#iIT9HECT?Ew$;@ip76% zpG`Gx7rf{>?*@5*RScqPkJ+W_(i3+~?Ej?dGa(??8u^|1c;!Q_+>SS%Bh7w=mu65O z+=7NEA%SGRKQC{@Ad$y9Y)gNck(z)2C$kj+bO^F9P=y%sR+jd=m3h?l_%NNcE}Q{u9n`>PGBa8|QcxEs7+g=C)JNUk24HIdt4d^H6JKD8wx@yWe_ zJ1N2yNiCuUwz{PIUJX)Ht6_~w+MT+aX7#9swMrK#&`;V?)~Z+4OQn``NVTe){4tiP zz5*SYdovKTALOy>yMJCf%5tphpQJf0nyaO?a})QLkLz}WcCh>I`i1$={$|r{zjLKg zjM_trzVFtizL?6|{mqAftg`VQe`c%yYG6hE01&PdEhWi_DON5Wsq9(02h#&=t9pa0 zHHqcPW@wX43Ou3#0TDD7HhKahGclzuQ8e{I!m%#*CPA;ul6`8#$*zJxHL-E-$3570 z5u2=ZmoDic*?>ejMDaA3>uv}msSE-p5+(LpFUG#~OXoBI9tm~E+9=8i(kOG8v?ZaX z*s?P1s~Yv)45D07@SBjS-?E_)p3fmrd=m9L+D;H^JDeb@1S z)oKmxb|nyqD+02Pi_Q1Hg*bYV0iN$Ygz{BxR8H|Dw3L+nJCbY~V1YQb z*Ws$Tfdy|w(BY?%q~e8T83qMF8VI}ch$z;fwu4v*$tE|@5y^PEO+}PRNtUXG&@H!P zV`DKIXoQfvev{pK`9DJY3YxCoEg@E*&oPVjUG^i-)c6#9b&hBUg=JhUg02pg4UMy( z2`c*gP+#MnnFoq*H3R8F5v?mKSDGex9jCN|DYE-Y?^r zRs_gDvxAV+gTyiKgLM(hQo$Yyqdq1?X%rM7h04s4lYFI4@!txU zjZV-vtyHa|$+Vb#$`6Pb*mn_&8plE}zm%xMrIb5?Ex>n*b=NZBtPe=WvmTRrl`Klk1hM3In!Yp!X{Zkp+x2#xCh3NM`8B*cc4>YYR2` ztP5v#Panmg(tV$Zm^3gSM*u?7@!|23TU%QDfje%SWObx3FQPzgS3NPA9e8GU>+V}x z!6R(_NK8Tt)+P6zH7aWIF-?W1sqf}F;%G9idqW*zxn$TP;+kG70KvBM2)kNFu` zu)Tl#i~p)Eq7D~}7GUONVehjfBKa>X8hILIhc4>3itoGse)+$;I|fM_m~*tGtB7~L zKpH;9d({gSw^mqiGrQ|m_*tMTdX4Q}*}BgVn~u!rsa6pX@t4DS8sMU6)?|GqWI^jzD7Gc}x&yMm_iG^3 zN3jVBw?YO{7|%i^Ul6uQ_bN=D1_)#Fli+~yPJ2k`kZVWgg`VNhsLkNO(O<{xuKp0G zSD{g6NUD(8uO}1gc_*{-WRHxFAZynD^5B6Z5A~kW=Zg?XC*C^so_`&txnF102;IaO z1-lS&!QZV(%3t`ZZZu#+zkSS%ftof7 z$@KQ?0)zSi!%OZF0x8l#laf9_ETqwO5D$`kt2(`7`j4mX4p`@XvAhg{7_8)>?2|t+ zS{^6K6Rb*BO!&W?XqHwEpj(mv&0OlSb>;&ESf(&jUX+Feyc6pqd8a{mYO{Wr(b`2P z@ddGRKxtw&yZxqsqbVU|=xuFeIA!or3K$Rvf8gn%qMIvYAkd0To-u?I0(B1|of+_W z*euQigvZ69+xl-}@1bQ`11*?Lf=?{jti(PB?Uf5}`X@L4;!EH9G6d2M_uX<|`G(y$ zAtew;0`C_IvYEwK8K`W7THVNb@6;RIj7ybP&d43E3=pN=8FRHY(yX-!)d+Wj!5|P? zjA^qysa9?4qbQ6)Ef*`&Ixa;W(nDim0;XI5t5Be`P@p+X_;u30NVpbYC9LAr0+}R_ zh%yO@#0dB|IB@jQtE;$$hDWe4lN0Gjf{Ysz!qOsw;HKMeeEw23UlM^16mJd>P2A+h zS@s(s1Sniwa)>CwI-mfSirFvx*GtuZmFE}?22%2ugmopgYO(&k$@TzJ>l17~3>ygD zvsrC!1V zHrI-)1kn~gu6A1*9ve@wFTzj=yC2?Gbh8WRfA~_bx+DUzI40Ru+PAc$yr&a2S?NH` zNq{z@%ou)_`Kt7=w^m-N>a92@7Aji?152Ds!us}x76G!VG|}QXCVz*hKXGYA2U<3D z8_fRRE#+4_fh^MMi;R5AeVC%wYhq9%HX3|`xHQhAS)D-+S}GEcLy(=U)!f2+Jxt`w z@+{E{<^8qbdb`VJ4?O~+*wI?}8&N++`Ty;AeD~YVU#hj2M4&gi`(79i5A2%C&3tw; zzui>2JnYP*Xg}pHRo7t7DU4OZDO1FcmYCPvmx zfNM%tkr>!c?iq8tZ`}EOaL6p3FMI!s>_EM%T|K}3nYoXpt#dW^wPjM9ka<;!7J6h} z#;fkg^&T6{C#t(*Q34EyS!Wl{Q-ph1s=V!~Jo1oPpFE1*YrrKk^;^*3Bu9JWA2u(Z zl@Ki(mp+vsQ$n#;w^m4;b%tf&)0l8($O)jWM9ja1MO$V<)9Cm#N2$T4-$qz%1ct9-pzZq@Be`vqq`r9wB&=tK(Y_`BIMEW8Wa#n z%WQ*ml5m$9QUH?xib2hYGfp`y1eB(Dad>m>>8&l7G9XH_PJzHh*@OzPNFk9ZO3P%S zvYRKUyn=S7-*U2QYlj{J>g}q@+r2l}mh0heji^Geln)?Au1umh-L-G#vlI7}UbtNQ zdKhuZ>o>Y@IJawR_h)xZllB9FqbKilEpA$5~iS~ z#1=!$h+hFd%LF0h5!sSkL1C;yA|Zq*iDV;hU<9Bb%o?nV+@ys2szu08iWBFbkWccE z6|QYuK-fLI{-I`GK~vYCALJK}Ws6kFa&XCbymQa?&c0hG|HUi4^O7uV;{&^gwk_Ou z!<${}X|{ZBpK-NOv>~Qtu0!GzR@Nz6PqDro2A~JSjn7~0_k21^XsTQ)6gSkyZq&kZ&E)k$HWg^XiJBE)u>}jxW2lhcJE(rz zQ9#slFwoNkP$&!b9Bs`2yH%03S(!^P7+V{a53{3exNLedQXhBA!?Uh*6F$1#o&VDj zqh}9Y=Fcl4kc^58t%v_OEARb#Q{ldM%(hoY*qN6akE+-a z^~v5(FV_1@J9(!p&de3stwz!^D6s8R%~nstGsT6OH%@+1IPgl%c|`=$gWHO4e43B% z_|0d3>FI^#`YrVaIsJg9TpS7E6?I`a4Nx4)Ac{QLbd~yfk7f*`qTha01Q~UnB1j1u z11Nf<;-4B&In7oD+Y@5u#-R4Q(9Wh&bw>#}Q!cMeamh48)JzDZoCIQt;*>(z#f_0ki5cu_>(xk&L7QHE1?|e3G zDgyPM-Z^#n1ACh1{&;@r1(qWsz?LD409M{`7z?)vQGJ7Y&uqn~@)nt4k6<#SJM;Wo zkiDtiz4r-3An?WMwiT~_Q5{M!*}|3420K{YWg(u!_zHJ|MB^p$3BeskSsj}v@X9il zVZ~N~vl}8A5_P|;wUW6cgB2J=h!BIUvs+*MyDru%WRZ=_A3_>k^KgujCzsj6;N}B| zAGzxX4nA`6smp)URPL*M%l2=1By0sgam%(l+z4yIBZW{fds1yqCkPCxfHcOg6w+$E z18QXRRZV|s^9R=s`M^2|GAXgrwz!Xd&z9JH?Kpz4+Kp-yX&+lNp+ z3As`Dhtz*<^`K8^HLdn+L#tei@HSB`?aQ^owt$2-c>=or)~)$sAvs2wRiA&qA(E(} z{^4JY5w4XiqA)@4_5}a-9pChg7y5nsrVwcEZ`OWy$J=+_dDFzbKmO?QX9(;f%?s=d ziIDfHszD6kAnNQFJiYs*s`C%Zq5&VpCYGbm5`yR0DyjlIuaj3%KC%?;#thi7CkfVa z(n|Z%;K^#xfd%SQAd|^J8}$jj1_QfZ`;F#Y938!mw#TUK8OwB9WHrf+=iKzpiHGj} zz~P^|_|&U^+Y|!5?|tu+p!2W)=;-e>PcANtJMrwG8Z8-H^p|CYpZ>+HFyG;(o2>B<(w9y1Zju5V>&0b0f)ddbv z#nyj`3rq77#VPW9oe>Z>Stk$8T|k%7ob(1~z!oBC(31x4_EuUHn=DA|%qWu?Ru~ zC{!yzA<`JiYC8k1(v&K0gMlo#hN1C1Su2i`(eESSAA4AP9hh#k3}$`OfHJ4Ohn%gTtWNwCznR4KerG2yblY z7JL_7i=?hVS;T_YkazUj7(|i{C$Buxkd`_@R-bq<>t$#S4Pftv+8($bpS zQ_tKHRR0b;`|QF>T_S=}t`R1_Ar9Gu-7tqJQHy$C4Uu|16MTK?owY0PD-~ZE>ui=%iTrmQv+Pz~(-tkm6`_1F!ZU3Va*SE_7rw|L- zK?+!kl_FP*_Y}O|CbF$TsyLMrnN<5OViS1dLuPISHBv$*dCOIl&K7CH&^5r}Ylx(& zy~RZ}+Mvk}#Sd>y)=M-gJadx4N46f6G}L$Jj$yH0Wq_0xS*sn|XmHyw;197EYyrXA z{A}u%^+nT-N!ObP)_(nf&~^_Ym%htjn<+wpCl&N>u3K*P?cj!PvHGa94YgFoq{!fT zra1DXQS~C3%EpS1v3CADw%=Pi-Ft4cpI3!IM}i}=Ab#Q(PXF{n$1Bg>f2{U|Yn7LX zrN){`DC|gc(v{guw8?JJi(~U{Wq1`bp1M5?yN!hQ(^wfRm8cR~)s+Dp(KrSKZGRGz zdN+%f8L=6%-|aIBr+uhBHR`AK{_bIXU{|7asPN1Wl9O7|fcM-H++pX?=-n`^X@PxM zYaq`W4%az$Gde+3;{mn;-N&|vlO!)4kuQ;$n_Nj$$q%lyGo^2_e^jo2Jp_tS+q5r* zlA0%l6%dm|Qe-02K3+l=MFB)OK!sq2Tp)~mbIU`@YQiSNjS)B6#(zjc)P(IIcHB7T z$~P4L-J$m$zGCE2hp!5O3}XDbbMHMr96gi&WFx8Gbhbhc2e7_@RWmHF0$^w~uaWa^ za%~#`f+f8gt?pHyyPcs zb8hF7LV+cC2kbfO+^J#KixJtl+)3RG8`jN`1!Wt^G}3|%qM?bF2svdll7^@5&{3mL z60#d~(X1t$F0dVw($^$Vcd>F?&Me9Tg%lzQ%@mh`Nz+Y%w4f(J3#`PYz8c$0O&%C^ zqc=?b=H6Rou1N0TrR!x&5a=zzJ5PQ5)F0j7X|zA-8p)xvjias&@>I(t=O)`}M4H$L zr|3kDXhOLJ3Z$*;yC_su&QwzEk`pLjaY76TK;fL=TW`9tmwgSr5Jjf)0z%R*DwMaxsc&woIB_ zdhVJDkv}Erg#6v^g#CzXn^=Az^X^~?T4Q(HkWRhc;oZM5$NfUVbN1#+W9JCVGV_Ct$ z5-EZLn^+bbh$6U4o?_LoQ6F$Y!ZBAAu_=*Xnrp#qR=8lWG>^_e#&#Ee?~WhX`+==M z9>IFc5J;7M*Bjn{;!ltN)_cq2#it**Kz`+Rn{>DAxs_*k`VPC?i2cZtwy7deP{>9W zk^nR+kU1nrj$@V?D+8%^?*m!@PpneK?)G1=(O(JE^UM{~{25ejTr(`UyjTo^Yy&y) zJbJ`DhNW;Ub7wkArJTA^$jme*f$fNKQ&?w*QO%_32_+Y?x5D&!G(w-kX?;k^g%Jacq)`j>-J z_CudJ`*AmyoPzu|NZ|$oAVf#_k@}@Rs!tp$LJ$=Y;NV!kS6rz`vhRe6f{0 z6l?Z4QFN1NmSaSMj_`Yk^9o8+65?=}?IzH4i*l1-6O+&!v$;!~ecZHtfdcSMP3K*C z4264lkuNfA{PNmE&-}S2# zR1hKmiSpD*rr9I`d{$(u11NveTw}7f-Qk-j-SoDh|90WP;UE3qfBX(maBIt!BaoU0 zi3CmD_x-`iU%4SaTKcPF^{GQAThBqd@!U(#C4j15Dq+4bW}4q}2)<9o`XLY~Uq9no zY{Ts`OacJXase6+Z3Z>f+QAfQRH8sad}&Y0HzZ+KNF@rT@1jga5Tyu`D2cZM%v!8V zGnq$pg)Oy8$a}VZS!*S5hE9w2&<(gGLnus*+tkBEYS{`n5a@4t7tl z5Mh7g6MMgT_aA;w3DtD~WgrODYv+3p{L>d6ZG7>*iIdy@JYOr_@=X0P09oO3|AVY> zOSD?p6tWJ$56F{P9$s{%`Z-r^OB>PtVC0UDab~JFhP%BMT$@h?YmJk)mk*G|_qGYE z64em`dBjrsV11`^qDpqzBbNPu&1E=fTS7o&r8-o{@-%W|8^uBK+1f16BM=)WMC{wa z3v$RzQ>f~99vODG>=^m|9p%X%L{vIFC`b$xfz;?Xl;3>fX#K%=78XmN>?|a=9Irmf zm`jZZVto}L&b=YLU52#|TLeUTwwxSUCRxWE62Wfx0NXT@6aZ4htwPRz>+Y)oo4!eJ zSAHD}+2DscU7Vmm#Kp0UhK>?B3>Xhu1(qHY} zE|0&2br#{+3f>YsDBf`(@7{7l`J?~rw&)+(%ba_-`?=*G(q9H%jtqU{ncY+SzU57a z-ulF?yKl#KqwoxX)JG8zZKGQyQ9y*ulp~ov+RMXebnKCu)AC!uoA#!9A9cPKw{caCGtE(mAZw;ZPOV2T3v++#E}Y zQ}}p{x}ULeTF$XQ6>?Alh0#(JS!p8>AdT5vH(z5b%9^Xhr2R#ZOqkID_b3UJtk>H2 zOu_4hIVNNnYVliycfehj)6<4ce?>L)&wnbU!>7g34Nw(PCJ;$1j1JHb?AO zM6XGCB>U3cPrUHuZ=bCn|H-qh$K6753=+WWonBQ7u7k>WVj7F8lTw0(%35sL|0)==zT zzq8yqvTytM-g8r7;Z2eI92)RIw5?wIU-~)VY53CDUHpAlaPL6@y`Pl!!Dvh_C~ zU3_rttCdIpWG+7X_Gg#B!bW%VB={x}3m_`7R45q&RYS?Xi?FaFzAtU34JchTyWO2y zd9ype@<#Fo-H1FvPHCFxJ^uF1*n;go4C2ZCA(sN<0YQ=gu6wq=$j(C}jD^ZlEaX+D z4;8h|*p>Z~YQRp$9N0JWGlzG% zkH57XeA=qHMt`mu1=`r(Bh%kld4B2n|Mi93o?D}I>Q|p%ef-FL=OocTD`qs)Mz9G< z7FfCsX~&HyL{MBzb{@lI5hL3+H(r}?RqR1c37A0NW-xb29+Hx)&j6&;Ao>(;gPl9_ zlK1jJgTYX6)0q z6bnE2o%@3q=)qvH-&)n*pTR=0zc#$=u1{2d{a>74dHz2gJ@b&8t+H(rv7hzAGE@m| zjTtJa<#L2}uzRv(rFQ*p*I2sSEiS*wEjGT1L0}+k&rb%2$?vy&QXV16JYr+){mDJb ze?6!%Py$ZBErX95)OUqhC|SGc3u{7Y56CSo6Ss$i<_KF?UiL1O2w9*Doi(=&Q^jq2 zBX@XvGI!feGkrUMA#S;&@GmVO? zD@6)yEx@;ygVBXZ362C*wZ4ww%o4adTsxX(ie7* z#o_g>l%T2Pt zPI)$Ze1!VJ0sgNcqH!^(xIto6f;!QM@cJQK^?J+(8;8+#9;Q4>@(JAFK3eDLI zfAncLS#-Un+1F8`$60?Ix(E_3sap6`j&59{X|{;Ih1-~|^ze3yX+Qz;vnkSg@iZJtIT z0Un@HQfaT?B&)UI=`(k~sAp}Z)leou)tm$6^BL^6A{;=I`71pR_-nbBfIXV_1qVqV z7>wa6;93Io^?)a5?@Lvdz!;qrh@d@XTn_~k5Z@cH363NM zPL&b&#V4TFpA+ec6VlnVdr{P?v0_DpO|$@MMt!upm(<|8NK)iseKek?tUY8w?E(#|>{Py9suq39g;N-9G?mplcL< zxBgC9#HM3qhH~L4bVl=w#z}~2OXzC}uar=8#0iG!u7FqBko0!nK$Q;8J`KTV0-|8B z)t#evbAad>Yz%V)HWUa09+-o%#TRLFPUL~2nP%(Ux^swBNt z07%>P*{UN9LIMZ@6C#I@dD6)xZo1V|OPDAq^VmOouO8eHX5F}K=^h)K|04sE7MB;R z7SRv*AD$zS|K&M)X5Lwj|E3WV1_1(s{?6s>XzajX;b?2aAJ=K4#S9m$S2S$}fhHc7 z$oY{k>W2W{hK8?w)W^QPkJAL&0RMhjl)``$6mxWa?bVXv{Po$^v9bQxpXC~Q@Z#3# zts5Px_n2^}wBB;?oA?oO(O#+=im$zFLhL6Fiar|sUvfE%R790m zDrk|ax%sveb!vV2;-RMfCijhHU{HK=^bJ5N zA3;C3>m(k|36aGdaKJ(JB_nc0b7RTLdsjS@*VEu4)Y;w3n0^kBB*OgYJ-2t-jg8P} zs!UAvu%4OBE#|nG(dAt>+yuzd-Aa{riCdKcSy-CJAQ8nK{7Gv1^y{v>r72s! z{m$9lUaP}a`=J+MgrE=_^esO(6C@UckZe5e$m`x`L(l4Z?7)pnv*Hr;_s3xZWyczV z@6yA=+U0#$OO@~FJ~ho-4>oo1+XvzQz2j1cI$7+#JMGUmH`Kq5vo>}z_^;!#5@c-F zn2&(-<3Q8b4X^VgHb;0d%1p5*b!`?|*iRO9BI0?7}e)0$?4U zCjO(j)09HC|28Gj6#c6*urL%)YV4a55jGZ=C;gvRy z4EXaGNN*EMO2Gzs%>2QfA#n4!O#UiXyO&%2aMVtD0-ybOe*G9qv9+bzzGbGkCMz^W z!$rZvAf`GuCjV0uf^3>uR?5|f7vketuj|uAy*K~3A%M7aZ0=8XBcXUUl+#n)oa*V?a6hl7(ZPn zjXRt=sY74gyt+2Fu8)Bwst9e>-ViVBG|_R%<;=T%Z31kxGdf8r)iX!P2TTM7N2@H1 zLWF!`ojPxwv%O<#D4Gd?9go(l9STKs_NQ6fup~$!NL4Y|4#uLXsMSZ<%v$9DYKRO) zDD}s$pF^l~TyS1-ypTr@PQ)o3lCp*eFafdvd}-!$5Q9`HYrNk-CDN37K4d=0 z$`B{ zGRDhWn?bDvZ=>&r%FahO_VDNM<`katY11B8asp~Ub6Ju{B-G2V3_cXV^MiOAYuifp z&S)>zYu;FJ=wMK)KXClolKn`v9mA=D+8+i5n?QAU@i}B**!1P{RTEZbP2`(kj`?D* z&)rL5C?w0A=e$6$+s-=pD!iK#|GXSKL-+G`jI&*{KMjSfy?AzcsRYsalslSJ_`ma} z@hvj8J_`c@-F;tZ-+xOx2V)m=V^>GU|GoK-80}6NuIv9vj0PO^oj>|NVl-w&-|sOA z2-p!IDFReIiFfk-d0YpD11oY=oNu)@rgn;k6>&*u~Vu z)1?7#K*mCz$N_1qK8H?C&QeM6@m3 zV+e-8H=?f8jsZ)HnO9hbcJSzs*qm6&Jh(3?>GaOPJePvIXnS++XfUI+(Q@*fq)GMLiYJ;2qqaR zNxGw0k5!ujg3#CZw)a{U6#Qg*24RE`T1de_@cuO0(I55N$Pgg>{jvKrRtbjm$5S_c z){zB>i@YMS#(QRFR;4~6IaG#9-7qqI_`t;O(nA3yYK zgfOPSAx2q)X0raH4e!~Wpw0e3et4Pa|qIkDR!{B+zWAMlADeWP`AYb+EXNzuylq z5)`Nk%SHXaiwa&upPH3wI+?scnJ6q+8*3Y zZoioy2HTP$`U;FFrfWx2ljlM}Hzv# zgv80Mq0CUA$mKklyvOcR)dae$Ku8t-I%7wiz3N1f0BG^ilz*JYq@46O+X*`@^SiLw zaeG6-BBJnVKE@Kc#hHL9_K`+hAN!EUI@xU-FuE3;D?y&BwdUXY6e4nxe#z2Wxf@b5 z(ExoR(5lcQsq;HMt-k#{s*ItL#ZGqOW82resgW>zm?lL8d6*dlJvr&gdK&1)30n|d zBLvb`{M#?u|a6KdU#?t z*R384O|d@xrJ1?*%aAU8Zu2iCAt-AO=Fh2!TQ;==3HV` zpC+0LJi1tiH;ySxV;XbMR+^4ENGuf0z(i;W-A$%7`ur4+n$kjBh_kVsl9}|8TC5L= zb$^>eWRb&Rf!bua|3=+S6E=kg4e?tuApnC0BM~Pm720M8RYi5?U`8C5DM78lu1znk z4|CVo<;ifH=qaE$HIhh$JS<8GTY}@W$d^A1{7(8;QdmgQcwkX1<=w%39y4}* zhTsOp+JY9KHL&buCFjInW|80NSD9?7YvvOo5VXNFvKmqq#xb2PQ3yM{$T09$)WGDW z-z`oL-7>3YRBXUQCk|>>Z=Tpl*6J3%)swvcDB-4O66|kR8k!tR*UTln& z#wP#Bvf3iCC>@2{STlAl;&|mt*1t%8>^4OxXitvB<>$AH+h1HX(?l_Q3zmv`ST^@t zPG(OWiwSBR_HJHdptvXw22>a6@{8t|TP~^N%74DRSgx1VmxzT+G$4I@5hRo9UL!@JcglIwV zKSA8*G#VbU&5S2G1@8tr1~c8}(pJ48bdL9uMf&Tds7XPO*A#Tj55wFe*l&ti`QP9G z;oql>M{83)k(?jv77p+++cHyZIu$$T_>)VD)SM;6*_VRHQ#Z7uU?9<1-?Mdr?^Vp0NxDIdDQ%BXBVY=0;=lKb)O5H-weups! zZlc?vQ_th200ZMEn6;W7V+!TEzHypB-*6IOG)9@9^+3)8v-f@eThp2n05;{gPa#ErzIJj;hVd*V8+1 zayd=6vh)@5gZ@vzns~R+E?ZUja}UpRde+I{?^9K?HQSzuPVPPLY}T6*=X0+n@Td%_ z+FGkTy*qi%AG(&pV*>JKlr9!Sn+lCcymP2zNIxTlGKBO~I$&uq%IQs|x;D!?ug~+8 z;(m?URM`G}?P+o>LVc_p?U2Z7i6W1fXP=V-F*sGa&%1lsQzAu63lhyWglIB%ij2< zvY#>KC|?8EGs$^65enJgZ4z8T5Klx|uD6i=)J?>}G>60ov9`q=Vx2zi(^RnaEWYol zCoLgalCX*PK0f={dewI3GbTt|DnPqn`zt7w2Jdv(v#YnoU0{Dv9MuFh?;)(F>;?B3K4Hzg4Ui1kFgcUNcjs* z`ykQfH*^`O)Wh*Ni}`wkif4P=_32zC*9Sha{>@_&Y1Uu>Oad&wMgDuCSNGxO>I;I2 zjpraE{j#{M+kup691<*eafU6Zy7j=m3gJy_XVG3da7CD#2~rr-HV^4R(pWipw37)M zH<}5QL|J62B&j?6tm#&aXDl6lynCE0ueE+XfUMzA=X=MzTmcHXbISC^l{CJM%I9{Z zSsFQtE-xDciVr4K12h<>}IVIHCEgWs7yj zK2OOv;dO4DjWQ;<#7c<#{cylm!9fOv5G2bQnm^-rBd9nW2tGwgUnk(T`q0hWr*0BU z2zlT)KmxYL8D7AYI0e^|6(*pEETehs;f(mvWU1Ut;kBEQ`~1#k#%Pz2qw_y{qg_6B zUQ2EShJ-lM<2}=+e*sX&%|H8k6fgc>VrmjeQXul(q(>d9%%`M6HNb*-J|k`~pdC7h zJk|3_;Yr@a+P+_ysK9o(qY1i0RAGa?lI%VNP;$&r&_yX%2dG7H{F199>C*&%YNt)GYxmhIP>@KINo zfH_M|nmy2S5A5@O*0q%-20f92u)U_OZTu0J>6bQN$0suk75YjG?aKSyOSp<;^UPu6pFN(uSmTStgNY8I_(m4$8OVx!lKn^@5yvHQ(Qjlg#dAZ?w=FT%HUdrPe!5hBpoL7nzYJ z>-G3>$qZvvjoyo_3`LQG@K%F>&&l2B;hx?ZK|Xw1LkkXZ*$#VO`C7!m={pb&G-x(@ zZTYZ_1T=VOhsO)FGuticna%xH)%i-%_aGh@*8#CJG8|*|*8s9|#%pzzcML(TN+BRx ziPU|eH-yRq=^L{}GMiC@?`(ea=IdVAdT=OaPnZ``>an3p7sM}i9IP*L{nEABjCj0e1^kw;y_dHo;(%10h7p;BXUBl{e)gP;&kl_R%`CQ zOd-!$SE$7e&r1_!avo5^O5C{$Ftk4atT!I&ZuI%#F7#CpCTKFiz&7sNOyT~(@{-QD z^ht%~E2}NghibUH6)~MzS|#y?O6vYlqoGZX17Z#G&*e#feY|~K8os}`?q)d;*)8hN8QPZp3O+Pe z8M~QUaP37d+sM?T^;6Xa4X zqO`5UjD=L;;f#+wRPk@VC&pjkgIQ4~SFxwtC&VY%k}A4t$hB$h!gkUxkhsNBZ*GyN z16x(Cb2G}3In2|1$L4Q-5MP$%$XwdX%q^`f)eT!y-2iUa)q8@})cC0cIqdw~}slMJj`B0eN?<-}EDaTfO%N)_Y~sd}S?T$TKh$>T!}g zY}_5iiUWLq_pb)2Ld5yA!vC3hhEGagFR^jHt{ZAE-Pa<$73apYo0u&d(SrCZ&+g1s z29g6sEm}y280?a2brXzOaY4p1WQfgfbXimn7JOe^)pwV|2&Hv*uWgX>7+o@!$BJ^i?M zSgbtfcKXM)*Ao|OGWIFH78BprI6JMpk^)8*6*hPz21HJ-ihFtPH2R{~p}B{k^D45)(^uzmdLXTf9!a5lruQTbQ&ih@# z>T(0DpzM8q+#czRln_Ju{DaL;c*8z>&Rx{2QxO!vI#W-K%`qmho+hs)=AAgtbkLQ{ zyS@JBuJV>Mqh)$N(J7e%^I!cF8M8QxFIt2z=m7hfvk-{M6xFUWp#tkRGmU zNLTHYKlYH&cW90VJyh3_Ps=l>*UKW4pZ8qp6; H%Egu%HtDf-M>}H&7v(8@JJ} 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 N!j(XWWpII92LK*N /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 0000000000000000000000000000000000000000..329f94fa00d7050a0f443b736f2a22b4e8d97068 GIT binary patch literal 26793 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 literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..95103bba21915e00a0ff9975973f282e05d7e65a GIT binary patch literal 54072 zcmV)PK()V#P)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91z@P&F1ONa40RR91zyJUM08KkN$^ZaB07*naRCod8-C2_)Np_~^SUk3j z$UUp7vCnWu=7Jm%Uhx0_2HsGFq{vW)1VJ=^$tbb?^V~!-GoZKxdsyw#PjL zclRsfYwvOMxcjJz)0_A-q}XyStAH?dBErs<$Ay%|!(`ss-6Ma+b{=*KaCe_l+)D6LRZ^aVokx{E?!_hz$t$=2 z`+JW^!$k7!Nw2z!xt!n5|Ir85_G#9E`tES_Pbcz^uI-pwEucd#9<6RLrwKMxtF8%Q#>$Cg0nIsRg-J`sZqJHHF-ZQf3{( zea~rM?(_-b5086$d!0z|-@i_NdW^M)MfM8_2uP z1Qs;by@#F0J7BC zg88?KsZdHsrMtJipZA*<48t7Q)=VIb1+2Lh*!s$DLm{@E$g(W!rpxR-sR(EE1gnmY zRc=lzH$1zF^5f2?yDP``yE@0k)&62HghAsvaq9uL=THx9ty&~4SF¿phOvdO(A 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 Rg;)Rp002ovPDHLkV1g*nRnGtb literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..c2c8440fcb9e08910d99bb755869cb313007f963 GIT binary patch literal 96309 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 z�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 J$(l)+2in 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 AcmMzZ literal 0 HcmV?d00001 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