├── calendarDemo.gif ├── debugKitDemo.gif ├── NineDotViewDemo.gif ├── passcodeViewDemo.gif ├── slidePluginDemo.gif ├── HPPluginRepo ├── Assets.xcassets │ ├── Contents.json │ ├── calendar_back.imageset │ │ ├── calendar_back@2x.png │ │ └── Contents.json │ ├── calendar_forward.imageset │ │ ├── calendar_forward@2x.png │ │ └── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── Common │ ├── HPGlobal.swift │ └── HPExts.swift ├── Plugins │ ├── HPSerialize │ │ └── HPSerialize.swift │ ├── HPCalendarExt │ │ ├── BuildInView │ │ │ ├── HPCalendarViewCell.swift │ │ │ ├── HPCalendarHorizontalLayout.swift │ │ │ ├── HPCalendarViewCell.xib │ │ │ ├── HPCalendarView.swift │ │ │ └── HPCalendarView.xib │ │ └── HPCalendarDate.swift │ ├── HPDebugKit │ │ ├── HDKGuideViewController.swift │ │ ├── HDKRootViewController.swift │ │ ├── HDKExtension.swift │ │ ├── resources │ │ │ └── guide.html │ │ ├── HDKSettingViewController.swift │ │ ├── HDKFloatingButton.swift │ │ └── HDKContext.swift │ ├── HPSlidePlugin │ │ ├── HSPMessageBridge.swift │ │ ├── HSPBottomViewController.swift │ │ ├── HSPTopViewController.swift │ │ └── HSPParentViewController.swift │ ├── HPPasswordPlugin │ │ ├── BuildInViews │ │ │ ├── HPNineDotView.xib │ │ │ ├── HPSimplePasscodeView.swift │ │ │ ├── HPNineDotView.swift │ │ │ └── HPSimplePasscodeView.xib │ │ └── HPPasswordView.swift │ └── HPTaskManager │ │ └── HPTaskManager.swift ├── HPPluginRepo.xcdatamodeld │ ├── .xccurrentversion │ └── HPToolKit.xcdatamodel │ │ └── contents ├── Demos │ ├── DemoAppSettings.swift │ ├── DebugKitDemo │ │ ├── HDKRootConfig.plist │ │ ├── HDKTestViewController.swift │ │ ├── HDKTest2ViewController.swift │ │ ├── HDKPasswordSettingViewController.swift │ │ ├── HDKSettingConfig.plist │ │ └── HDKSettingEventHandler.swift │ ├── HPNavView.swift │ ├── SlidePluginDemo │ │ ├── HSPDemoTopViewController.swift │ │ ├── HSPDemoBottomViewController.swift │ │ └── HSPDemoParentViewController.swift │ ├── CalendarDemo │ │ └── HPCalendarViewController.swift │ └── PasswordPluginDemo │ │ └── HPPasswordDemoViewController.swift ├── MyNavigationController.swift ├── Info.plist ├── Base.lproj │ └── LaunchScreen.storyboard ├── RootViewController.swift └── AppDelegate.swift ├── HPPluginRepo.xcodeproj ├── xcuserdata │ ├── rkhd.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ ├── hupeng.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ └── i324891.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ └── HPPluginRepo.xcscheme └── project.xcworkspace │ ├── xcuserdata │ └── hupeng.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── .gitignore ├── HPPluginRepoTests ├── Info.plist └── HPPluginRepoTests.swift ├── HPPluginRepoUITests ├── Info.plist └── HPPluginRepoUITests.swift ├── The MIT License (MIT) └── README.md /calendarDemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuangyu/HPPluginRepo/HEAD/calendarDemo.gif -------------------------------------------------------------------------------- /debugKitDemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuangyu/HPPluginRepo/HEAD/debugKitDemo.gif -------------------------------------------------------------------------------- /NineDotViewDemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuangyu/HPPluginRepo/HEAD/NineDotViewDemo.gif -------------------------------------------------------------------------------- /passcodeViewDemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuangyu/HPPluginRepo/HEAD/passcodeViewDemo.gif -------------------------------------------------------------------------------- /slidePluginDemo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuangyu/HPPluginRepo/HEAD/slidePluginDemo.gif -------------------------------------------------------------------------------- /HPPluginRepo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /HPPluginRepo.xcodeproj/xcuserdata/rkhd.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /HPPluginRepo.xcodeproj/xcuserdata/hupeng.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /HPPluginRepo/Assets.xcassets/calendar_back.imageset/calendar_back@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuangyu/HPPluginRepo/HEAD/HPPluginRepo/Assets.xcassets/calendar_back.imageset/calendar_back@2x.png -------------------------------------------------------------------------------- /HPPluginRepo/Assets.xcassets/calendar_forward.imageset/calendar_forward@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuangyu/HPPluginRepo/HEAD/HPPluginRepo/Assets.xcassets/calendar_forward.imageset/calendar_forward@2x.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | HPPluginRepo.xcodeproj/project.xcworkspace/xcuserdata/hupeng.xcuserdatad/UserInterfaceState.xcuserstate 3 | 4 | *.xcuserstate 5 | 6 | HPPluginRepo.xcodeproj/project.xcworkspace/xcuserdata/hupeng.xcuserdatad/UserInterfaceState.xcuserstate 7 | -------------------------------------------------------------------------------- /HPPluginRepo.xcodeproj/project.xcworkspace/xcuserdata/hupeng.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shuangyu/HPPluginRepo/HEAD/HPPluginRepo.xcodeproj/project.xcworkspace/xcuserdata/hupeng.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /HPPluginRepo/Common/HPGlobal.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnwMacros.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 15/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // MARK: - 12 | 13 | 14 | -------------------------------------------------------------------------------- /HPPluginRepo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPSerialize/HPSerialize.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HPSerialize.swift 3 | // HPPluginRepo 4 | // 5 | // Created by 胡鹏 on 23/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | 13 | class HPSerialize { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /HPPluginRepo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /HPPluginRepo/HPPluginRepo.xcdatamodeld/.xccurrentversion: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | _XCCurrentVersionName 6 | HPToolKit.xcdatamodel 7 | 8 | 9 | -------------------------------------------------------------------------------- /HPPluginRepo/HPPluginRepo.xcdatamodeld/HPToolKit.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /HPPluginRepo/Assets.xcassets/calendar_back.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "calendar_back@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /HPPluginRepo/Assets.xcassets/calendar_forward.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "calendar_forward@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPCalendarExt/BuildInView/HPCalendarViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CollectionViewCell.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 12/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class HPCalendarViewCell: UICollectionViewCell { 12 | 13 | @IBOutlet weak var titleLabel: UILabel! 14 | override func awakeFromNib() { 15 | super.awakeFromNib() 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /HPPluginRepo.xcodeproj/xcuserdata/hupeng.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | HPPluginRepo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /HPPluginRepo.xcodeproj/xcuserdata/rkhd.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | HPPluginRepo.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /HPPluginRepo/Demos/DemoAppSettings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DemoAppContext.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 05/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | import UIKit 9 | 10 | public struct DemoAppSettings { 11 | var ADKUserDefaultTheme: Bool { 12 | return !UserDefaults.standard.bool(forKey: "ADKNotDefaultThemeKey") 13 | } 14 | 15 | var ASPScaleRatio: Float { 16 | return UserDefaults.standard.float(forKey: "ASPScaleRatioKey") 17 | } 18 | } 19 | 20 | public let appSettings = DemoAppSettings() 21 | -------------------------------------------------------------------------------- /HPPluginRepo/Demos/DebugKitDemo/HDKRootConfig.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | title 7 | Segue ID Test Cell 8 | segueID 9 | openTestPage 10 | 11 | 12 | title 13 | Controller Test Cell 14 | controllerName 15 | HPPluginRepo.HDKTest2ViewController 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /HPPluginRepo/Demos/HPNavView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HPNavView.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 11/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class HPNavView: UIView { 12 | @IBOutlet weak var heightConstraint: NSLayoutConstraint? 13 | override func awakeFromNib() { 14 | super.awakeFromNib() 15 | let screentH = UIScreen.main.bounds.height 16 | if (screentH == 812 || screentH == 896) { 17 | heightConstraint?.constant = 84 18 | } else { 19 | heightConstraint?.constant = 64 20 | } 21 | updateConstraintsIfNeeded() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /HPPluginRepo/MyNavigationController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyNavigationController.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 30/11/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class MyNavigationController: UINavigationController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | // Do any additional setup after loading the view. 17 | } 18 | 19 | override func didReceiveMemoryWarning() { 20 | super.didReceiveMemoryWarning() 21 | // Dispose of any resources that can be recreated. 22 | } 23 | 24 | override var preferredStatusBarStyle: UIStatusBarStyle { 25 | return UIStatusBarStyle.lightContent 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /HPPluginRepoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /HPPluginRepoUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /HPPluginRepo/Demos/DebugKitDemo/HDKTestViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HDKTestViewController.swift 3 | // AnwDebugKitDemo 4 | // 5 | // Created by Hu, Peng on 26/10/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class HDKTestViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | // Do any additional setup after loading the view. 17 | } 18 | 19 | override var preferredStatusBarStyle: UIStatusBarStyle { 20 | return UIStatusBarStyle.lightContent 21 | } 22 | 23 | @IBAction func dismissBtnClicked(_ sender: Any) { 24 | HDKFloatingButton.shrink() 25 | } 26 | 27 | @IBAction func backBtnClicked(_ sender: Any) { 28 | self.navigationController?.popViewController(animated: true) 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /HPPluginRepo/Demos/DebugKitDemo/HDKTest2ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HDKTest2ViewController.swift 3 | // AnwDebugKitDemo 4 | // 5 | // Created by Hu, Peng on 26/10/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class HDKTest2ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | applyADKNavigationBar(title: "Test Page 2", backAction: #selector(backBtnClicked(_:)), dismissAction: #selector(dismissBtnClicked(_:)), theme: HDKContext.shared.theme) 17 | self.view.backgroundColor = UIColor.white 18 | } 19 | 20 | override var preferredStatusBarStyle: UIStatusBarStyle { 21 | return UIStatusBarStyle.lightContent 22 | } 23 | 24 | @IBAction func dismissBtnClicked(_ sender: Any) { 25 | HDKFloatingButton.shrink() 26 | } 27 | 28 | @IBAction func backBtnClicked(_ sender: Any) { 29 | self.navigationController?.popViewController(animated: true) 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /HPPluginRepo/Demos/SlidePluginDemo/HSPDemoTopViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HSPDemoTopViewController.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 01/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class HSPDemoTopViewController: HSPTopViewController { 12 | 13 | @IBOutlet weak var menuBtn: UIButton! 14 | @IBOutlet weak var label: UILabel! 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | } 19 | 20 | override func viewDidAppear(_ animated: Bool) { 21 | self.view.backgroundColor = UIColor.randomColor 22 | } 23 | 24 | @IBAction func dismissBtnClicked(_ sender: Any?) { 25 | self.parent?.dismiss(animated: true, completion: nil) 26 | } 27 | 28 | override func sliding(with ratio: Float) { 29 | super.sliding(with: ratio) 30 | menuBtn.alpha = CGFloat(1 - ratio) 31 | } 32 | 33 | override func asp_recevice(_ message: Any) { 34 | self.label.text = "item(\(message))" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPDebugKit/HDKGuideViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HDKGuideViewController.swift 3 | // AnwDebugKitDemo 4 | // 5 | // Created by Hu, Peng on 02/11/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import WebKit 11 | 12 | class HDKGuideViewController: UIViewController { 13 | 14 | @IBOutlet weak var webview: WKWebView! 15 | 16 | @IBAction func dismissBtnClicked(_ sender: Any) { 17 | HDKFloatingButton.shrink() 18 | } 19 | 20 | @IBAction func backBtnClicked(_ sender: Any) { 21 | self.navigationController?.popViewController(animated: true) 22 | } 23 | 24 | override var preferredStatusBarStyle: UIStatusBarStyle { 25 | return UIStatusBarStyle.lightContent 26 | } 27 | 28 | override func viewDidLoad() { 29 | super.viewDidLoad() 30 | let guideFilePath = Bundle.main.path(forResource: "guide", ofType: "html") 31 | let htmlStr = try! String(contentsOfFile: guideFilePath!) 32 | webview.loadHTMLString(htmlStr, baseURL: nil) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /HPPluginRepo/Demos/SlidePluginDemo/HSPDemoBottomViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HSPDemoBottomViewController.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 01/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class HSPDemoBottomViewController: HSPBottomViewController, UITableViewDelegate, UITableViewDataSource { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | } 16 | 17 | // MARK: - table view delegate 18 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 19 | return 20 20 | } 21 | 22 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 23 | let cell = tableView.dequeueReusableCell(withIdentifier: "cell") 24 | cell?.textLabel?.text = "Item \(indexPath.row)" 25 | return cell! 26 | } 27 | 28 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 29 | self.asp_send(indexPath.row) 30 | self.dismiss(nil) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /The MIT License (MIT): -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) <2017> 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /HPPluginRepoTests/HPPluginRepoTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HPPluginRepoTests.swift 3 | // HPPluginRepoTests 4 | // 5 | // Created by Hu, Peng on 30/11/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import HPPluginRepo 11 | 12 | class HPPluginRepoTests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | // Use XCTAssert and related functions to verify your tests produce the correct results. 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | func testTaskRegister() { 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | HPPluginRepo(Continuous Update...) 2 | ============== 3 | [![License MIT](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://github.com/shuangyu/HPPluginRepo/blob/master/The%20MIT%20License%20(MIT))  4 | ![Support](https://img.shields.io/badge/language-swift-orange.svg)  5 | ![Platform](https://img.shields.io/badge/platform-ios-lightgrey.svg)  6 | [![Build Status](https://api.travis-ci.org/shuangyu/HPPluginRepo.svg?branch=master)](https://travis-ci.org/shuangyu/HPPluginRepo) 7 | 8 | Plugins 9 | ============== 10 | 11 | ### Debug Kit(Guide Page not update yet!) 12 | ![alt tag](https://github.com/shuangyu/HPPluginRepo/blob/master/debugKitDemo.gif) 13 | 14 | ### Slide Plugin 15 | ![alt tag](https://github.com/shuangyu/HPPluginRepo/blob/master/slidePluginDemo.gif) 16 | 17 | ### Calendar Plugin 18 | ![alt tag](https://github.com/shuangyu/HPPluginRepo/blob/master/calendarDemo.gif) 19 | 20 | ### Password Plugin 21 | #### Nine Dot View Demo(build on password plugin) 22 | ![alt tag](https://github.com/shuangyu/HPPluginRepo/blob/master/NineDotViewDemo.gif) 23 | #### Simple Passcode View Demo(build on password plugin) 24 | ![alt tag](https://github.com/shuangyu/HPPluginRepo/blob/master/passcodeViewDemo.gif) 25 | -------------------------------------------------------------------------------- /HPPluginRepoUITests/HPPluginRepoUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HPPluginRepoUITests.swift 3 | // HPPluginRepoUITests 4 | // 5 | // Created by Hu, Peng on 30/11/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | class HPPluginRepoUITests: XCTestCase { 12 | 13 | override func setUp() { 14 | super.setUp() 15 | 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | 18 | // In UI tests it is usually best to stop immediately when a failure occurs. 19 | continueAfterFailure = false 20 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 21 | XCUIApplication().launch() 22 | 23 | // 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. 24 | } 25 | 26 | override func tearDown() { 27 | // Put teardown code here. This method is called after the invocation of each test method in the class. 28 | super.tearDown() 29 | } 30 | 31 | func testExample() { 32 | // Use recording to get started writing UI tests. 33 | // Use XCTAssert and related functions to verify your tests produce the correct results. 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /HPPluginRepo/Demos/SlidePluginDemo/HSPDemoParentViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HSPDemoParentViewController.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 01/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class HSPDemoParentViewController: HSPParentViewController { 12 | 13 | weak private var _topViewController: HSPTopViewController? 14 | weak private var _bottomViewController: HSPBottomViewController? 15 | 16 | override var config: ASPAnimationConfig { 17 | return ASPAnimationConfig(scaleRatio: appSettings.ASPScaleRatio) 18 | } 19 | override var topViewController: HSPTopViewController? { 20 | 21 | if _topViewController == nil { 22 | _topViewController = HSPDemoTopViewController.loadFromStoryboard() as? HSPTopViewController 23 | } 24 | return _topViewController 25 | } 26 | override var bottomViewController: HSPBottomViewController? { 27 | if _bottomViewController == nil { 28 | _bottomViewController = HSPDemoBottomViewController.loadFromStoryboard() as? HSPBottomViewController 29 | } 30 | return _bottomViewController 31 | } 32 | 33 | override var preferredStatusBarStyle: UIStatusBarStyle { 34 | return UIStatusBarStyle.lightContent 35 | } 36 | 37 | override func viewDidLoad() { 38 | super.viewDidLoad() 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPSlidePlugin/HSPMessageBridge.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HSPMessageBridge.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 08/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @objc 12 | public protocol ASPMessageSender { 13 | func asp_send(_ message: Any) 14 | func asp_add(receiver: ASPMessageReceiver) 15 | } 16 | 17 | @objc 18 | public protocol ASPMessageReceiver { 19 | func asp_recevice(_ message: Any) 20 | } 21 | 22 | struct ASPAssociatedKeys { 23 | static var observerKey: UInt8 = 0 24 | } 25 | 26 | extension UIViewController: ASPMessageSender { 27 | 28 | private(set) var asp_observer: ASPMessageReceiver? { 29 | set(newValue) { 30 | guard let value = newValue else { 31 | objc_removeAssociatedObjects(self) 32 | return 33 | } 34 | // use weak reference to avoid retain cycles 35 | objc_setAssociatedObject(self, &ASPAssociatedKeys.observerKey, value, objc_AssociationPolicy.OBJC_ASSOCIATION_ASSIGN) 36 | } 37 | get { 38 | guard let receiver = objc_getAssociatedObject(self, &ASPAssociatedKeys.observerKey) as? ASPMessageReceiver else { 39 | return nil 40 | } 41 | return receiver 42 | } 43 | } 44 | public func asp_add(receiver: ASPMessageReceiver) { 45 | self.asp_observer = receiver 46 | } 47 | 48 | // MARK: - ASPMessageSender 49 | 50 | public func asp_send(_ message: Any) { 51 | self.asp_observer?.asp_recevice(message) 52 | } 53 | } 54 | 55 | -------------------------------------------------------------------------------- /HPPluginRepo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UIStatusBarStyle 32 | UIStatusBarStyleLightContent 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /HPPluginRepo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /HPPluginRepo/Demos/CalendarDemo/HPCalendarViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HPCalendarViewController.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 11/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class HPCalendarViewController: UIViewController { 12 | 13 | private var calendarView: HPCalendarView = Bundle.main.loadNibNamed("HPCalendarView", owner: nil, options: nil)?.first as! HPCalendarView 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | self.title = "Calendar Demo" 17 | self.view.addSubview(calendarView) 18 | calendarView.translatesAutoresizingMaskIntoConstraints = false 19 | 20 | } 21 | 22 | override func updateViewConstraints() { 23 | super.updateViewConstraints() 24 | 25 | let insets = self.view.safeAreaInsets 26 | let topConstraint = NSLayoutConstraint(item: calendarView, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.top, multiplier: 1.0, constant: insets.top) 27 | 28 | let bottomConstraint = NSLayoutConstraint(item: calendarView, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.bottom, multiplier: 1.0, constant: insets.bottom) 29 | 30 | let leadingConstraint = NSLayoutConstraint(item: calendarView, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.leading, multiplier: 1.0, constant: insets.left) 31 | 32 | let trailingConstraint = NSLayoutConstraint(item: calendarView, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.trailing, multiplier: 1.0, constant: insets.right) 33 | 34 | self.view.addConstraints([topConstraint, bottomConstraint, leadingConstraint, trailingConstraint]) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /HPPluginRepo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPDebugKit/HDKRootViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HDKRootViewController.swift 3 | // AnwDebugKitDemo 4 | // 5 | // Created by Hu, Peng on 24/10/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | class HDKRootViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { 13 | 14 | private let configs = HDKContext.shared.config 15 | private lazy var configItems = ADKRootCellItem.parse(file: configs.rootPageConfigFileName) 16 | 17 | override func viewDidLoad() { 18 | super.viewDidLoad() 19 | configItems.append(contentsOf: configs.defaultItems) 20 | } 21 | 22 | @IBAction func dismissBtnClicked(_ sender: Any) { 23 | HDKFloatingButton.shrink() 24 | } 25 | 26 | override var preferredStatusBarStyle: UIStatusBarStyle { 27 | return UIStatusBarStyle.lightContent 28 | } 29 | 30 | // UITableViewDelegate 31 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 32 | return configItems.count 33 | } 34 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 35 | let cell = tableView.dequeueReusableCell(withIdentifier: configs.rootPageCellReuseID) 36 | assert(cell != nil, "cell with reusable identifier \(configs.rootPageCellReuseID) not found") 37 | 38 | let title = configItems[indexPath.row].title 39 | assert(title != nil, "config item must contain \"title\" info") 40 | cell?.textLabel?.text = title 41 | return cell! 42 | } 43 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 44 | let cellItem = configItems[indexPath.row] 45 | 46 | if let segueID = cellItem.segueID { 47 | self.performSegue(withIdentifier: segueID, sender: self) 48 | } else if let controller = try? cellItem.controller() { 49 | self.navigationController?.pushViewController(controller!, animated: true) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /HPPluginRepo.xcodeproj/xcuserdata/i324891.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 24 | 36 | 37 | 38 | 40 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPDebugKit/HDKExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HDKExtension.swift 3 | // AnwDebugKitDemo 4 | // 5 | // Created by Hu, Peng on 24/10/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | let navBarHeight: Int = 64 12 | 13 | public extension UIViewController { 14 | 15 | public func applyADKNavigationBar(title: String, backAction: Selector?, dismissAction: Selector?, theme: ADKTheme) { 16 | 17 | let w = Int(UIScreen.main.bounds.width) 18 | let h = navBarHeight 19 | let leftMargin = 12 20 | let topMargin = 26 21 | let navBar = UIView(frame: CGRect(x: 0, y: 0, width: w, height: h)) 22 | navBar.backgroundColor = theme.mainColor 23 | navBar.autoresizingMask = UIViewAutoresizing.flexibleWidth 24 | 25 | let titleLabel = UILabel() 26 | titleLabel.text = title 27 | titleLabel.textColor = theme.fontColor 28 | titleLabel.font = UIFont.systemFont(ofSize: 17.0) 29 | titleLabel.sizeToFit() 30 | titleLabel.center = CGPoint(x :w / 2, y: 20 + (h - 20) / 2) 31 | titleLabel.autoresizingMask = UIViewAutoresizing(rawValue: UIViewAutoresizing.flexibleLeftMargin.rawValue | UIViewAutoresizing.flexibleRightMargin.rawValue) 32 | navBar.addSubview(titleLabel) 33 | 34 | if backAction != nil { 35 | let backBtn = UIButton(type: UIButtonType.custom) 36 | backBtn.frame = CGRect(x: leftMargin, y: topMargin, width: 0, height: 0) 37 | backBtn.titleLabel?.textColor = theme.fontColor 38 | backBtn.titleLabel?.font = UIFont.systemFont(ofSize: 15.0) 39 | backBtn.setTitle("Back", for: UIControlState.normal) 40 | backBtn.autoresizingMask = UIViewAutoresizing.flexibleRightMargin 41 | backBtn.addTarget(self, action: backAction!, for: UIControlEvents.touchUpInside) 42 | backBtn.sizeToFit() 43 | navBar.addSubview(backBtn) 44 | } 45 | 46 | if dismissAction != nil { 47 | let dismissBtn = UIButton(type: UIButtonType.custom) 48 | dismissBtn.titleLabel?.textColor = theme.fontColor 49 | dismissBtn.titleLabel?.font = UIFont.systemFont(ofSize: 15.0) 50 | dismissBtn.setTitle("Dismiss", for: UIControlState.normal) 51 | dismissBtn.autoresizingMask = UIViewAutoresizing.flexibleLeftMargin 52 | dismissBtn.addTarget(self, action: dismissAction!, for: UIControlEvents.touchUpInside) 53 | dismissBtn.sizeToFit() 54 | dismissBtn.frame = CGRect(x: w - leftMargin - Int(dismissBtn.bounds.width), y: topMargin, width: Int(dismissBtn.bounds.width), height: Int(dismissBtn.bounds.height)) 55 | navBar.addSubview(dismissBtn) 56 | } 57 | 58 | self.view.addSubview(navBar) 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /HPPluginRepo/RootViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RootViewController.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 30/11/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public struct MyTheme : ADKTheme { 12 | 13 | public var description: String { 14 | return "MyTheme" 15 | } 16 | public var mainColor: UIColor { 17 | return UIColor.colorFrom(hex: "0C5195") 18 | } 19 | public var fontColor: UIColor { 20 | return UIColor.white 21 | } 22 | public var floatingButtonSize: CGSize { 23 | return CGSize(width: 60, height: 60) 24 | } 25 | public var floationButtonColor: UIColor { 26 | return UIColor.colorFrom(hex: "0C5195") 27 | } 28 | public var floatingButtonText: String { 29 | return NSLocalizedString("MyBtn", comment: self.description) 30 | } 31 | public var floationButtonTextColor: UIColor { 32 | return UIColor.yellow 33 | } 34 | public var floationButtonFontSize: CGFloat { 35 | return 14.0 36 | } 37 | } 38 | 39 | class RootViewController: UITableViewController { 40 | 41 | private let dataSource = ["Debug Kit Demo", "Slide Plugin Demo", "Calendar Demo", "Password Plugin Demo"] 42 | private let segueIDs = ["openDebugKitPage", "openSlidePluginPage", "openCalendarDemoPage", "openPasswordPluginPage"] 43 | 44 | override func viewDidLoad() { 45 | super.viewDidLoad() 46 | // Important! : init event handler for ADK Demo 47 | ADKSettingCellEventCenter.register(eventHandler: HDKSettingEventHandler()) 48 | // user self-defined thems for debug kit 49 | if !appSettings.ADKUserDefaultTheme { 50 | HDKContext.shared.theme = MyTheme() 51 | } else { 52 | HDKContext.shared.theme = ADKDefaultTheme() 53 | } 54 | } 55 | 56 | // MARK: - Table view data source 57 | override func numberOfSections(in tableView: UITableView) -> Int { 58 | return 1 59 | } 60 | 61 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 62 | return dataSource.count 63 | } 64 | 65 | 66 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 67 | let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) 68 | cell.textLabel?.text = dataSource[indexPath.row] 69 | return cell 70 | } 71 | 72 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 73 | if indexPath.row == 0 { 74 | HDKFloatingButton.shift() 75 | } else { 76 | self.performSegue(withIdentifier: segueIDs[indexPath.row], sender: self) 77 | } 78 | tableView.cellForRow(at: indexPath)?.setSelected(false, animated: false) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPCalendarExt/BuildInView/HPCalendarHorizontalLayout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HPCalHorizontalLayout.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 12/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class HPCalendarHorizontalLayout: UICollectionViewLayout { 12 | 13 | private var contentSize: CGSize? 14 | private var itemSize: CGSize? 15 | private var w: CGFloat = 0 16 | private var h: CGFloat = 0 17 | 18 | init(itemHeight: Int) { 19 | self.itemSize = CGSize(width: 0, height: CGFloat(itemHeight)) 20 | super.init() 21 | } 22 | 23 | required init?(coder aDecoder: NSCoder) { 24 | super.init(coder: aDecoder) 25 | } 26 | 27 | override func prepare() { 28 | super.prepare() 29 | guard let unwrappedView = self.collectionView else { 30 | return 31 | } 32 | w = unwrappedView.bounds.width 33 | h = unwrappedView.bounds.height 34 | let sectionCount = unwrappedView.numberOfSections 35 | 36 | let itemWidth = w/7 37 | itemSize!.width = itemWidth 38 | let contentWidth = w * CGFloat(sectionCount) 39 | 40 | contentSize = CGSize(width: contentWidth, height: h) 41 | } 42 | 43 | override var collectionViewContentSize: CGSize { 44 | return contentSize! 45 | } 46 | 47 | override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { 48 | 49 | let attrs = UICollectionViewLayoutAttributes(forCellWith: indexPath) 50 | let section = indexPath.section 51 | let item = indexPath.item 52 | let row: Int = item/7 53 | let column: Int = item%7 54 | let offsetX = CGFloat(section) * w + CGFloat(column) * itemSize!.width 55 | let offsetY = CGFloat(row) * itemSize!.height 56 | 57 | attrs.frame = CGRect(x: offsetX, y: offsetY, width: itemSize!.width, height: itemSize!.height) 58 | return attrs 59 | } 60 | 61 | override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { 62 | 63 | let a: Int = Int(rect.minX/w) 64 | let b: Int = Int(rect.maxX/w) 65 | 66 | var attrs: [UICollectionViewLayoutAttributes] = [] 67 | 68 | for section in a...b { 69 | 70 | if section < 0 { 71 | continue 72 | } 73 | 74 | guard section < self.collectionView!.numberOfSections else { 75 | return attrs 76 | } 77 | 78 | let itemsCount = self.collectionView!.numberOfItems(inSection: section) 79 | for item in 0.. Void)) { 71 | let _ratio: Float = ratio >= 0.5 ? 1.0 : 0.0 72 | 73 | // if this animation is triggered by a tap gestrue, 74 | // we need to set up a intialized interface to 75 | // make this animation smooth. 76 | if maskView == nil { 77 | sliding(with: currentRatio) 78 | } 79 | 80 | UIView.animate(withDuration: 0.25, animations: { 81 | self.sliding(with: _ratio) 82 | }) {[unowned self] (finished) in 83 | 84 | self.currentRatio = _ratio 85 | self.maskView?.removeFromSuperview() 86 | self.maskView = nil 87 | block(_ratio > 0.0) 88 | } 89 | } 90 | 91 | // MARK: - ASPMessageSender 92 | open func asp_recevice(_ message: Any) { 93 | 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPCalendarExt/BuildInView/HPCalendarViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /HPPluginRepo/Demos/DebugKitDemo/HDKPasswordSettingViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HDKPasswordSettingViewController.swift 3 | // HPPluginRepo 4 | // 5 | // Created by 胡鹏 on 20/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ADKPasswordViewSettingCell: UITableViewCell { 12 | @IBOutlet weak var selectedLabel: UILabel! 13 | 14 | override func prepareForReuse() { 15 | super.prepareForReuse() 16 | selectedLabel.isHidden = true 17 | } 18 | 19 | override func setSelected(_ selected: Bool, animated: Bool) { 20 | super.setSelected(selected, animated: animated) 21 | selectedLabel.isHidden = !selected 22 | } 23 | } 24 | 25 | let viewTypeKey = "com.hpDemo.passwordViewSetting.viewTypeKey" 26 | let initialTypeKey = "com.hpDemo.passwordViewSetting.initialTypeKey" 27 | 28 | struct ADKPasswordViewSetting { 29 | let cache = UserDefaults.standard 30 | 31 | var viewType: Int { 32 | get { 33 | return cache.integer(forKey: viewTypeKey) 34 | } 35 | set(newValue) { 36 | cache.set(newValue, forKey: viewTypeKey) 37 | } 38 | } 39 | 40 | var initialType: Int { 41 | get { 42 | return cache.integer(forKey: initialTypeKey) 43 | } 44 | set(newValue) { 45 | cache.set(newValue, forKey: initialTypeKey) 46 | } 47 | } 48 | } 49 | 50 | class HDKPasswordSettingViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { 51 | 52 | let passwordViews = ["Nine Dot View"] 53 | let initialStatus = ["create", "reset", "delete", "verify"] 54 | var settings = ADKPasswordViewSetting() 55 | @IBOutlet weak var tableView: UITableView! 56 | 57 | override var preferredStatusBarStyle: UIStatusBarStyle { 58 | return UIStatusBarStyle.lightContent 59 | } 60 | 61 | override func viewDidLoad() { 62 | super.viewDidLoad() 63 | 64 | tableView.selectRow(at: IndexPath(row: settings.initialType, section: 0), animated: false, scrollPosition: UITableViewScrollPosition.none) 65 | } 66 | 67 | @IBAction func backBtnClicked(_ sender: Any) { 68 | self.navigationController?.popViewController(animated: true) 69 | } 70 | 71 | // MARK: - UITableViewDelegate 72 | func numberOfSections(in tableView: UITableView) -> Int { 73 | // return 2 74 | return 1 75 | } 76 | 77 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 78 | // return section == 0 ? passwordViews.count : initialStatus.count 79 | return initialStatus.count 80 | } 81 | 82 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 83 | let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! ADKPasswordViewSettingCell 84 | 85 | // if indexPath.section == 0 { 86 | // cell.textLabel?.text = passwordViews[indexPath.row] 87 | //// cell.setSelected(settings.viewType == indexPath.row, animated: false) 88 | // } else { 89 | cell.textLabel?.text = initialStatus[indexPath.row] 90 | cell.setSelected(settings.initialType == indexPath.row, animated: false) 91 | // } 92 | 93 | return cell 94 | } 95 | 96 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 97 | 98 | settings.initialType = indexPath.row 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /HPPluginRepo.xcodeproj/xcuserdata/i324891.xcuserdatad/xcschemes/HPPluginRepo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPSlidePlugin/HSPTopViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HSPTopViewController.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 30/11/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class HSPTopViewController: UIViewController, ASPSlideProtocol, ASPMessageReceiver 12 | { 13 | 14 | private var maskView: UIView? 15 | public var parentController: HSPParentViewController { 16 | return self.parent as! HSPParentViewController 17 | } 18 | override func viewDidLoad() { 19 | super.viewDidLoad() 20 | } 21 | 22 | override func viewWillAppear(_ animated: Bool) { 23 | super.viewWillAppear(animated) 24 | print("\(#function)") 25 | } 26 | 27 | override func viewDidAppear(_ animated: Bool) { 28 | super.viewDidAppear(animated) 29 | print("\(#function)") 30 | } 31 | 32 | override func viewWillDisappear(_ animated: Bool) { 33 | super.viewWillDisappear(animated) 34 | print("\(#function)") 35 | } 36 | 37 | override func viewDidDisappear(_ animated: Bool) { 38 | super.viewDidDisappear(animated) 39 | print("\(#function)") 40 | } 41 | 42 | @IBAction func slideOut(_ sender: Any?) { 43 | parentController.update(UIGestureRecognizerState.ended, with: 1.0) 44 | } 45 | 46 | open func sliding(with ratio: Float) { 47 | 48 | let translationRatio = parentController.config.translationRatio 49 | let scaleRatio = parentController.config.scaleRatio 50 | let w = Float(self.view.bounds.width) 51 | 52 | let t = CGAffineTransform(translationX: CGFloat(w * ratio * translationRatio), y: 0) 53 | let s = CGAffineTransform(scaleX: CGFloat(1 - scaleRatio * ratio), y: CGFloat(1 - scaleRatio * ratio)) 54 | self.view.transform = t.concatenating(s) 55 | } 56 | 57 | open func finishSliding(with ratio: Float, completion block: @escaping ((Bool) -> Void)) { 58 | 59 | let _ratio = ratio >= 0.5 ? 1.0 : 0.0 60 | 61 | UIView.animate(withDuration: 0.25, animations: { 62 | self.sliding(with: Float(_ratio)) 63 | }) {[unowned self] (finished: Bool) in 64 | if _ratio > 0.0 { 65 | 66 | if self.maskView != nil { 67 | self.maskView?.removeFromSuperview() 68 | self.maskView = nil 69 | } 70 | 71 | self.maskView = UIView(frame: self.view.bounds) 72 | self.maskView!.backgroundColor = UIColor.clear 73 | self.view.addSubview(self.maskView!) 74 | 75 | let panGesture = UIPanGestureRecognizer(target: self, action: #selector(self.handlePanGesture(_:))) 76 | self.maskView?.addGestureRecognizer(panGesture) 77 | 78 | let tapGesture = UITapGestureRecognizer(target: self, action: #selector(self.handleTapGesture(_:))) 79 | self.maskView?.addGestureRecognizer(tapGesture) 80 | 81 | } else { 82 | self.maskView?.removeFromSuperview() 83 | self.maskView = nil 84 | } 85 | block(_ratio > 0.0) 86 | } 87 | } 88 | 89 | @objc 90 | private func handlePanGesture(_ sender: UIPanGestureRecognizer) { 91 | let vector = sender.translation(in: self.maskView) 92 | let ratio = Float(-vector.x)/parentController.maxTranslateDistance 93 | parentController.update(sender.state, with: 1 - ratio) 94 | } 95 | 96 | @objc 97 | private func handleTapGesture(_ sender: UIPanGestureRecognizer) { 98 | parentController.update(sender.state, with: 0.0) 99 | } 100 | 101 | // MARK: - ASPMessageSender 102 | open func asp_recevice(_ message: Any) { 103 | 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /HPPluginRepo/Demos/DebugKitDemo/HDKSettingConfig.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | type 7 | ADKCellTypeGroupHeader 8 | title 9 | Debug Kit Demo 10 | items 11 | 12 | 13 | title 14 | Detail Cell Demo 15 | action 16 | openDetailPage 17 | type 18 | ADKCellTypeDetail 19 | 20 | 21 | title 22 | Input Cell Demo 23 | action 24 | inputValueChanged: 25 | type 26 | ADKCellTypeInput 27 | defaultValue 28 | inputCellDefaultValue 29 | 30 | 31 | title 32 | Switch Cell Demo 33 | action 34 | switchValueChanged: 35 | type 36 | ADKCellTypeSwitch 37 | defaultValue 38 | switchCellDefaultValue 39 | 40 | 41 | title 42 | Slider Cell Demo 43 | action 44 | sliderValueChanged: 45 | type 46 | ADKCellTypeSlider 47 | defaultValue 48 | sliderCellDefaultValue 49 | 50 | 51 | title 52 | Plain Cell Demo 53 | type 54 | ADKCellTypePlain 55 | 56 | 57 | title 58 | Async Cell Demo(try to click) 59 | action 60 | asyncProcess 61 | type 62 | ADKCellTypeAsync 63 | 64 | 65 | 66 | 67 | type 68 | ADKCellTypeGroupHeader 69 | title 70 | Debug Kit Settings 71 | items 72 | 73 | 74 | title 75 | Use Default Theme 76 | action 77 | toggleTheme: 78 | type 79 | ADKCellTypeSwitch 80 | defaultValue 81 | isDefaultTheme 82 | 83 | 84 | 85 | 86 | type 87 | ADKCellTypeGroupHeader 88 | title 89 | Slide Plugin Settings 90 | items 91 | 92 | 93 | title 94 | scale ratio 95 | action 96 | setScaleRatio: 97 | type 98 | ADKCellTypeSlider 99 | defaultValue 100 | getScaleRatio 101 | 102 | 103 | 104 | 105 | type 106 | ADKCellTypeGroupHeader 107 | title 108 | Password View Settings 109 | items 110 | 111 | 112 | title 113 | simplePasscodeView 114 | action 115 | passwordViewChanged: 116 | type 117 | ADKCellTypeSwitch 118 | defaultValue 119 | passwordViewType 120 | 121 | 122 | type 123 | ADKCellTypePlain 124 | varTitle 125 | getPassword 126 | 127 | 128 | title 129 | set initial status 130 | action 131 | openPasswodViewSettingPage 132 | type 133 | ADKCellTypeDetail 134 | 135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPPasswordPlugin/BuildInViews/HPNineDotView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPSlidePlugin/HSPParentViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HSPParentViewController.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 30/11/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public struct ASPAnimationConfig { 12 | // max slide distance will be calculated by translationRatio * viewWidth 13 | var translationRatio: Float 14 | // if scale ratio is equal to zero, view won't be scaled while sliding 15 | // else view will be minimally scaled to 1 - scaleRatio 16 | var scaleRatio: Float 17 | init(translationRatio: Float = 0.8, scaleRatio: Float = 0.0) { 18 | self.translationRatio = translationRatio 19 | self.scaleRatio = scaleRatio 20 | } 21 | } 22 | 23 | public protocol ASPSlideProtocol { 24 | func sliding(with ratio: Float) 25 | func finishSliding(with ratio: Float, completion block: @escaping ((Bool) -> Swift.Void)) 26 | } 27 | 28 | class ASPEmptySegue: UIStoryboardSegue { 29 | 30 | } 31 | 32 | class HSPParentViewController: UIViewController { 33 | 34 | open var config: ASPAnimationConfig { 35 | return ASPAnimationConfig() 36 | } 37 | open var topViewController: HSPTopViewController? { 38 | return nil 39 | } 40 | open var bottomViewController: HSPBottomViewController? { 41 | return nil 42 | } 43 | 44 | private var edgePan: UIScreenEdgePanGestureRecognizer? 45 | public var maxTranslateDistance: Float = 0.0 46 | 47 | override func viewDidLoad() { 48 | super.viewDidLoad() 49 | edgePan = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(handleEdgePan(_:))) 50 | edgePan!.edges = UIRectEdge.left 51 | self.view.addGestureRecognizer(edgePan!) 52 | 53 | let width = Float(UIScreen.main.bounds.width) 54 | maxTranslateDistance = config.translationRatio * width 55 | 56 | assert(topViewController != nil, "no top view controller has been setted!!!") 57 | assert(bottomViewController != nil, "no bottom view controller has been setted!!!") 58 | 59 | self.quickAdd(childViewController: bottomViewController!) 60 | self.quickAdd(childViewController: topViewController!) 61 | 62 | topViewController?.asp_add(receiver: bottomViewController!) 63 | bottomViewController?.asp_add(receiver: topViewController!) 64 | } 65 | 66 | @objc 67 | private func handleEdgePan(_ sender: UIScreenEdgePanGestureRecognizer) { 68 | let vector = sender.translation(in: self.view) 69 | let ratio = Float(vector.x)/maxTranslateDistance 70 | update(sender.state, with: ratio) 71 | } 72 | 73 | public func update(_ state: UIGestureRecognizerState, with ratio: Float) { 74 | 75 | if state == .began { 76 | 77 | topViewController?.sliding(with: ratio) 78 | bottomViewController?.sliding(with: ratio) 79 | 80 | // ???? 81 | if ratio <= 0.2 { 82 | bottomViewController?.viewWillAppear(true) 83 | topViewController?.viewWillDisappear(true) 84 | } else if ratio >= 0.8 { 85 | topViewController?.viewWillAppear(true) 86 | bottomViewController?.viewWillDisappear(true) 87 | } 88 | 89 | } else if state == .changed { 90 | 91 | topViewController?.sliding(with: ratio) 92 | bottomViewController?.sliding(with: ratio) 93 | 94 | } else { 95 | 96 | bottomViewController?.finishSliding(with: ratio, completion: { [unowned self](flag: Bool) in 97 | self.edgePan!.isEnabled = !flag 98 | flag ? self.bottomViewController?.viewDidAppear(true) : self.bottomViewController?.viewDidDisappear(true) 99 | }) 100 | 101 | topViewController?.finishSliding(with: ratio, completion: { [unowned self](flag: Bool) in 102 | self.edgePan!.isEnabled = !flag 103 | flag ? self.topViewController?.viewDidDisappear(true) : self.topViewController?.viewDidAppear(true) 104 | 105 | }) 106 | } 107 | } 108 | 109 | deinit { 110 | self.quickRemove(childViewController: self.topViewController!) 111 | self.quickRemove(childViewController: self.bottomViewController!) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPCalendarExt/HPCalendarDate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSDateCalExt.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 11/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | /* 10 | * !!! Cautions: this Extension only works for Gregorian calendar 11 | */ 12 | 13 | import UIKit 14 | 15 | typealias HPCalDate = Date 16 | typealias HPCalYear = Int 17 | typealias HPCalMonth = Int 18 | typealias HPCalDay = Int 19 | typealias HPCalWeekDay = Int 20 | 21 | let kHPCalMonthLengths = [31,28,31,30,31,30,31,31,30,31,30,31] 22 | let kHPCalLeapMonthLengths = [31,29,31,30,31,30,31,31,30,31,30,31] 23 | let kHPCalMonthName = ["January","February","March","April","May","Jun","July","August","September","October","November","December"] 24 | let kHPCalMonthShortName = ["Jan.","Feb.","Mar.","Apr.","May","Jun","July","Agu.","Sept.","Oct.","Nov.","Dec."] 25 | 26 | enum HPCalendarError: Error { 27 | case invalidParameter 28 | } 29 | 30 | extension HPCalDate { 31 | static var today: HPCalDate { 32 | return Date() 33 | } 34 | var year: HPCalYear { 35 | return Calendar(identifier:.gregorian).component(.year, from: self) 36 | } 37 | 38 | var month: HPCalMonth { 39 | return Calendar(identifier:.gregorian).component(.month, from: self) 40 | } 41 | 42 | var day: HPCalDay { 43 | return Calendar(identifier:.gregorian).component(.day, from: self) 44 | } 45 | // start from 1 to 7, and 1 represent Sunday 46 | var weekDay: HPCalWeekDay { 47 | return Calendar(identifier:.gregorian).component(.weekday, from: self) 48 | } 49 | } 50 | 51 | extension HPCalYear { 52 | var isLeapYear: Bool { 53 | return (self%4 == 0 && self%100 != 0) || (self%400 == 0); 54 | } 55 | } 56 | 57 | struct HPMonth { 58 | 59 | let year: HPCalYear 60 | let month: HPCalMonth 61 | 62 | // contains pre-month's tail and next-month's head 63 | // use this value to draw month view 64 | let lengthIncludePadding: Int 65 | let length: Int 66 | let startWeekDay: HPCalWeekDay 67 | let endWeekDay: HPCalWeekDay 68 | // use this as data source of calendar view 69 | var days: [String] = [] 70 | 71 | var name: String { 72 | return "\(kHPCalMonthName[month - 1]) \(year)" 73 | } 74 | var shortName: String { 75 | return "\(kHPCalMonthShortName[month - 1]) \(year)" 76 | } 77 | 78 | init(year: HPCalYear = HPCalDate.today.year, month: HPCalMonth = HPCalDate.today.month) throws { 79 | 80 | self.year = year 81 | self.month = month 82 | 83 | let monthStr = month > 9 ? "\(month)" : "0\(month)" 84 | 85 | let formatter = DateFormatter() 86 | formatter.dateFormat = "yyyy-MM-dd" 87 | 88 | let startDateStr = "\(year)-\(monthStr)-01" 89 | let startDate = formatter.date(from: startDateStr) 90 | 91 | guard let unwrappedStartDate = startDate else { 92 | throw HPCalendarError.invalidParameter 93 | } 94 | 95 | self.length = year.isLeapYear ? kHPCalLeapMonthLengths[month-1] : kHPCalMonthLengths[month-1] 96 | 97 | let endDateStr = "\(year)-\(monthStr)-\(self.length)" 98 | let endDate: HPCalDate! = formatter.date(from: endDateStr)! 99 | 100 | self.startWeekDay = unwrappedStartDate.weekDay 101 | self.endWeekDay = endDate.weekDay 102 | 103 | let preOffset = (self.startWeekDay - 1) 104 | let sufOffset = (7 - self.endWeekDay) 105 | 106 | self.lengthIncludePadding = self.length + preOffset + sufOffset 107 | 108 | for _ in 0.. HPMonth { 122 | let nextMonth = self.month + 1 123 | let month = nextMonth > 12 ? nextMonth%12 : nextMonth 124 | let year = nextMonth > 12 ? self.year + 1 : self.year 125 | return try HPMonth(year: year, month: month) 126 | } 127 | 128 | func preMonth() throws -> HPMonth { 129 | let preMonth = self.month - 1 130 | let month = preMonth < 1 ? preMonth + 12 : preMonth 131 | let year = preMonth < 1 ? self.year - 1 : self.year 132 | return try HPMonth(year: year, month: month) 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /HPPluginRepo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 30/11/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import CoreData 11 | 12 | @UIApplicationMain 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | var window: UIWindow? 16 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 17 | // Override point for customization after application launch. 18 | 19 | UIBarButtonItem.appearance().tintColor = UIColor.white 20 | return true 21 | } 22 | 23 | func applicationWillResignActive(_ application: UIApplication) { 24 | // 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. 25 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 26 | } 27 | 28 | func applicationDidEnterBackground(_ application: UIApplication) { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | func applicationWillEnterForeground(_ application: UIApplication) { 34 | // 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. 35 | } 36 | 37 | func applicationDidBecomeActive(_ application: UIApplication) { 38 | // 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. 39 | } 40 | 41 | func applicationWillTerminate(_ application: UIApplication) { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | // Saves changes in the application's managed object context before the application terminates. 44 | self.saveContext() 45 | } 46 | 47 | // MARK: - Core Data stack 48 | 49 | lazy var persistentContainer: NSPersistentContainer = { 50 | /* 51 | The persistent container for the application. This implementation 52 | creates and returns a container, having loaded the store for the 53 | application to it. This property is optional since there are legitimate 54 | error conditions that could cause the creation of the store to fail. 55 | */ 56 | let container = NSPersistentContainer(name: "HPPluginRepo") 57 | container.loadPersistentStores(completionHandler: { (storeDescription, error) in 58 | if let error = error as NSError? { 59 | // Replace this implementation with code to handle the error appropriately. 60 | // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 61 | 62 | /* 63 | Typical reasons for an error here include: 64 | * The parent directory does not exist, cannot be created, or disallows writing. 65 | * The persistent store is not accessible, due to permissions or data protection when the device is locked. 66 | * The device is out of space. 67 | * The store could not be migrated to the current model version. 68 | Check the error message to determine what the actual problem was. 69 | */ 70 | fatalError("Unresolved error \(error), \(error.userInfo)") 71 | } 72 | }) 73 | return container 74 | }() 75 | 76 | // MARK: - Core Data Saving support 77 | 78 | func saveContext () { 79 | let context = persistentContainer.viewContext 80 | if context.hasChanges { 81 | do { 82 | try context.save() 83 | } catch { 84 | // Replace this implementation with code to handle the error appropriately. 85 | // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 86 | let nserror = error as NSError 87 | fatalError("Unresolved error \(nserror), \(nserror.userInfo)") 88 | } 89 | } 90 | } 91 | 92 | } 93 | 94 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPCalendarExt/BuildInView/HPCalendarView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HPCalendarView.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 12/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class HPCalendarView: UIView, UICollectionViewDelegate, UICollectionViewDataSource { 12 | 13 | @IBOutlet weak var titleLabel: UILabel! 14 | @IBOutlet weak var collectionView: UICollectionView! 15 | 16 | private var _dataSource: [HPMonth]? 17 | private var dataSource: [HPMonth] { 18 | get { 19 | if _dataSource == nil { 20 | _dataSource = [try! selectedMonth.preMonth() ,selectedMonth, try! selectedMonth.nextMonth()] 21 | } 22 | return _dataSource! 23 | } 24 | } 25 | private var selectedMonth: HPMonth = try! HPMonth() 26 | private var selectedIndex: Int = 1 27 | 28 | @IBAction func nextBtnClicked(_ sender: Any) { 29 | 30 | scroll(to: selectedIndex + 1, animated: true) 31 | selectMonth(at: selectedIndex + 1, animated: true) 32 | 33 | } 34 | @IBAction func preBtnClicked(_ sender: Any) { 35 | scroll(to: selectedIndex - 1, animated: true) 36 | selectMonth(at: selectedIndex - 1, animated: true) 37 | } 38 | 39 | override func awakeFromNib() { 40 | let layout = HPCalendarHorizontalLayout(itemHeight: 40) 41 | collectionView.collectionViewLayout = layout 42 | let cell = UINib(nibName: "HPCalendarViewCell", bundle: nil) 43 | collectionView.register(cell, forCellWithReuseIdentifier: "cell") 44 | collectionView.isPagingEnabled = true 45 | collectionView.showsHorizontalScrollIndicator = false 46 | perform(#selector(scrollToSelectedMonth(animated:)), with: self, afterDelay: 0.1) 47 | updateTitleLabel() 48 | } 49 | 50 | @objc 51 | private func scrollToSelectedMonth(animated: Bool = false) { 52 | scroll(to: selectedIndex, animated: animated) 53 | } 54 | 55 | private func scroll(to section: Int, animated: Bool) { 56 | collectionView.scrollToItem(at: IndexPath(item: 0, section: section), at: UICollectionViewScrollPosition.left, animated: animated) 57 | } 58 | 59 | private func selectMonth(at index: Int, animated: Bool = false) { 60 | 61 | selectedMonth = dataSource[index] 62 | print("current index is \(index)") 63 | do { 64 | if index < selectedIndex { 65 | 66 | if index == 0 { 67 | try _dataSource!.insert(selectedMonth.preMonth(), at: 0) 68 | collectionView.insertSections([0]) 69 | selectedIndex = 1 70 | scrollToSelectedMonth(animated: animated) 71 | } else { 72 | selectedIndex = index 73 | } 74 | } else { 75 | if index == dataSource.count - 1 { 76 | try _dataSource!.append(selectedMonth.nextMonth()) 77 | collectionView.insertSections([dataSource.count - 1]) 78 | } 79 | selectedIndex = index 80 | } 81 | 82 | print("data source count is \(dataSource.count)") 83 | updateTitleLabel() 84 | 85 | } catch HPCalendarError.invalidParameter { 86 | // alert... 87 | } catch { 88 | // ... 89 | } 90 | } 91 | 92 | private func updateTitleLabel() { 93 | titleLabel.text = selectedMonth.shortName 94 | } 95 | 96 | // MARK : - UICollectionViewDelegate 97 | func numberOfSections(in collectionView: UICollectionView) -> Int { 98 | return dataSource.count 99 | } 100 | 101 | func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { 102 | return dataSource[section].lengthIncludePadding 103 | } 104 | 105 | func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { 106 | 107 | let month = dataSource[indexPath.section] 108 | let cell: HPCalendarViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! HPCalendarViewCell 109 | cell.titleLabel.text = month.days[indexPath.row] 110 | return cell 111 | } 112 | 113 | func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { 114 | // TBD... 115 | // add ur handler 116 | } 117 | 118 | // MARK : - UIScrollViewDelegate 119 | 120 | func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) { 121 | 122 | let currentIndex = Int(scrollView.contentOffset.x)/Int(collectionView.bounds.width) 123 | 124 | guard currentIndex != selectedIndex else { 125 | return 126 | } 127 | 128 | selectMonth(at: currentIndex) 129 | 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPPasswordPlugin/HPPasswordView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HPPasswordView.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 14/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | enum HPPasswordViewStatus: Int { 13 | // initial status 14 | case create 15 | case reset 16 | case delete 17 | case verify 18 | case empty 19 | // result status 20 | case mismatch 21 | case match 22 | case invalid 23 | } 24 | 25 | struct HPPasswordViewStatusChange { 26 | var from: HPPasswordViewStatus 27 | var to: HPPasswordViewStatus 28 | var tryTimes : Int 29 | init(from: HPPasswordViewStatus, to: HPPasswordViewStatus = .empty, tryTimes: Int = Int.max) { 30 | self.from = from 31 | self.to = to 32 | self.tryTimes = tryTimes 33 | } 34 | } 35 | 36 | protocol IHPPasswordView: NSObjectProtocol { 37 | 38 | var maxTryTime: Int { get } 39 | var status: HPPasswordViewStatus { get set } // ==> current status 40 | var tmpPassword: Any? { get set } // ==> current inputted password 41 | weak var delegate: HPPasswordViewDelegate? { get set } 42 | /* 43 | * generate password image for some special password view type, 44 | * like 9 Dot View, for save sake 45 | * just return nil if don't need this method 46 | */ 47 | func passwordImage() -> UIImage? 48 | func updateView(with change: HPPasswordViewStatusChange) 49 | } 50 | 51 | protocol HPPasswordViewDelegate: NSObjectProtocol { 52 | // called before password view updateView(with change: HPPasswordViewStatusChange) 53 | func statusWill(change: HPPasswordViewStatusChange) 54 | // called after password view updateView(with change: HPPasswordViewStatusChange) 55 | func statusDid(change: HPPasswordViewStatusChange) 56 | 57 | func beginInput(passwordView: T) 58 | func endInput(passwordView: T) 59 | } 60 | 61 | protocol IHPPasswordStorage: NSObjectProtocol { 62 | 63 | var password: String? { get } 64 | 65 | func save(password: String) 66 | func deletePassword() 67 | 68 | /* 69 | * validate inputted password 70 | */ 71 | func validate(password: Any?) -> Bool 72 | /* 73 | * convert inputted password to a string value 74 | * For example original inputted password of 9 Dot View 75 | * maybe an array of indeies, we need to convert it to string value to save 76 | */ 77 | func password(from: Any?) -> String? 78 | } 79 | 80 | class HPPasswordViewDecorator { 81 | 82 | // use weak property to avoid retain recycle 83 | weak var passwordView: T? 84 | var storage: P? 85 | var tmpPwd: String? 86 | 87 | init(passwordView: T, storage: P) { 88 | self.passwordView = passwordView 89 | self.storage = storage 90 | } 91 | 92 | func triggerStatusChange(_ change: HPPasswordViewStatusChange) { 93 | var outChange = change 94 | let inputtedPwd = storage!.password(from: passwordView!.tmpPassword) 95 | let pwd = storage!.password 96 | let tryTimes = change.tryTimes 97 | 98 | if change.from == .create { 99 | if tmpPwd == nil { // input first time 100 | let validePwd = storage!.validate(password: passwordView!.tmpPassword) 101 | outChange.to = validePwd ? .create : .invalid 102 | if validePwd { 103 | tmpPwd = inputtedPwd 104 | } 105 | } else { // input second time 106 | if tmpPwd == inputtedPwd { 107 | outChange.to = .match 108 | storage!.save(password: inputtedPwd!) 109 | } else { 110 | tmpPwd = nil 111 | outChange.to = .mismatch 112 | } 113 | } 114 | } else if change.from == .reset { 115 | 116 | if pwd == inputtedPwd { // unlock first, then skip to create process 117 | outChange.to = .match 118 | passwordView!.status = .create 119 | } else { // unlock failed 120 | outChange.tryTimes = tryTimes - 1 121 | outChange.to = .mismatch 122 | } 123 | } else if change.from == .delete { 124 | 125 | if pwd == inputtedPwd { 126 | outChange.to = .match 127 | storage!.deletePassword() 128 | } else { 129 | outChange.tryTimes = tryTimes - 1 130 | outChange.to = .mismatch 131 | } 132 | } else if change.from == .verify { 133 | if pwd == inputtedPwd { 134 | outChange.to = .match 135 | } else { 136 | outChange.tryTimes = tryTimes - 1 137 | outChange.to = .mismatch 138 | } 139 | } 140 | passwordView!.delegate?.statusWill(change: outChange) 141 | passwordView!.updateView(with: outChange) 142 | passwordView!.delegate?.statusDid(change: outChange) 143 | } 144 | } 145 | 146 | -------------------------------------------------------------------------------- /HPPluginRepo/Demos/DebugKitDemo/HDKSettingEventHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HDKSettingEventHandler.swift 3 | // AnwDebugKitDemo 4 | // 5 | // Created by Hu, Peng on 01/11/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @objcMembers 12 | class HDKSettingEventHandler: NSObject { 13 | 14 | let cache = UserDefaults.standard 15 | var ADK_Demo_CachedText: String? 16 | var ADK_Demo_CachedBool: Bool = false 17 | var ADK_Demo_CachedFloat: Float = 0.0 18 | var ADK_NotDefaultTheme: Bool = false 19 | var ASP_ScaleRatio: Float = 0.0 20 | var APP_PasswordViewType: Int = 0 21 | override init() { 22 | super.init() 23 | 24 | ADK_Demo_CachedText = cache.string(forKey: "demoInputCellKey") 25 | ADK_Demo_CachedBool = cache.bool(forKey: "demoSwitchCellKey") 26 | ADK_Demo_CachedFloat = cache.float(forKey: "demoSliderCellKey") 27 | ADK_NotDefaultTheme = cache.bool(forKey: "ADKNotDefaultThemeKey") 28 | ASP_ScaleRatio = cache.float(forKey: "ASPScaleRatioKey") 29 | APP_PasswordViewType = cache.integer(forKey: "APPPasswordViewTypeKey") 30 | NotificationCenter.default.addObserver(forName: HDKFloatingButtonShrinkNotifName, object: nil, queue: nil) { [unowned self](notif) in 31 | self.save() 32 | } 33 | } 34 | 35 | private func save() { 36 | self.cache.set(self.ADK_Demo_CachedText, forKey: "demoInputCellKey") 37 | self.cache.set(NSNumber(value: self.ADK_Demo_CachedBool), forKey: "demoSwitchCellKey") 38 | self.cache.set(NSNumber(value: self.ADK_Demo_CachedFloat), forKey: "demoSliderCellKey") 39 | self.cache.set(NSNumber(value: self.ADK_NotDefaultTheme), forKey: "ADKNotDefaultThemeKey") 40 | self.cache.set(NSNumber(value: self.ASP_ScaleRatio), forKey: "ASPScaleRatioKey") 41 | self.cache.set(NSNumber(value: self.APP_PasswordViewType), forKey: "APPPasswordViewTypeKey") 42 | } 43 | 44 | // MARK: - AnwDebugKit Demo 45 | public func openDetailPage() { 46 | print("\(#file)-\(#function)") 47 | } 48 | 49 | public func inputValueChanged(_ newValue: String) { 50 | ADK_Demo_CachedText = newValue 51 | } 52 | 53 | public func inputCellDefaultValue() -> String { 54 | 55 | if ADK_Demo_CachedText == nil { 56 | ADK_Demo_CachedText = "INPUT CELL DEFAULT VALUE" 57 | } 58 | return ADK_Demo_CachedText! 59 | } 60 | 61 | public func switchValueChanged(_ newValue: NSNumber) { 62 | ADK_Demo_CachedBool = newValue.boolValue 63 | } 64 | 65 | public func switchCellDefaultValue() -> NSNumber { 66 | return NSNumber(value: ADK_Demo_CachedBool) 67 | } 68 | 69 | public func sliderValueChanged(_ newValue: NSNumber) { 70 | ADK_Demo_CachedFloat = newValue.floatValue 71 | } 72 | 73 | public func sliderCellDefaultValue() -> NSNumber { 74 | return NSNumber(value: ADK_Demo_CachedFloat) 75 | } 76 | 77 | // async cell action will run async thread 78 | public func asyncProcess() { 79 | sleep(5) 80 | print("\(#file)-\(#function)") 81 | } 82 | 83 | // MARK: - AnwDebugKit Settings 84 | 85 | public func toggleTheme(_ newValue: NSNumber) { 86 | ADK_NotDefaultTheme = !newValue.boolValue 87 | 88 | self.save() 89 | 90 | let okAction = UIAlertAction(title: "OK", style: UIAlertActionStyle.default) { (actionItem) in 91 | exit(0) 92 | } 93 | let controller = UIAlertController(title: "Tips", message: "You need to restart app to apply this change", preferredStyle: UIAlertControllerStyle.alert) 94 | controller.addAction(okAction) 95 | UIApplication.shared.keyWindow!.rootViewController!.present(controller, animated: true) { 96 | 97 | } 98 | } 99 | 100 | public func isDefaultTheme() -> NSNumber { 101 | return NSNumber(value: !ADK_NotDefaultTheme) 102 | } 103 | 104 | // MARK: - AnwDebugKit Settings 105 | 106 | public func setScaleRatio(_ newValue: NSNumber) { 107 | ASP_ScaleRatio = newValue.floatValue 108 | } 109 | 110 | public func getScaleRatio() -> NSNumber { 111 | return NSNumber(value: ASP_ScaleRatio) 112 | } 113 | 114 | // MARK: - HPPasswordView Demo Settings 115 | 116 | public func passwordViewChanged(_ newValue: NSNumber) { 117 | APP_PasswordViewType = newValue.intValue 118 | } 119 | public func passwordViewType() -> NSNumber { 120 | return NSNumber(value: APP_PasswordViewType) 121 | } 122 | 123 | public func getPassword() -> String { 124 | 125 | let pwd = APP_PasswordViewType == 0 ? HPNineDotViewStorage().password : HPSimplePasscodeViewStorage().password 126 | guard pwd != nil else { 127 | return "no password" 128 | } 129 | 130 | return "password is: \(pwd!)" 131 | } 132 | 133 | public func openPasswodViewSettingPage() { 134 | let passwordVC = HDKPasswordSettingViewController.loadFromStoryboard("HDKStoryboard_phone") 135 | 136 | let navigationVC = UIApplication.shared.keyWindow!.rootViewController as! UINavigationController 137 | 138 | navigationVC.pushViewController(passwordVC, animated: true) 139 | 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /HPPluginRepo/Demos/PasswordPluginDemo/HPPasswordDemoViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HPPasswordDemoViewController.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 15/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class HPPasswordDemoViewController: UIViewController, HPPasswordViewDelegate { 12 | 13 | @IBOutlet weak var statusLabel: UILabel! 14 | 15 | let passwordViewType = UserDefaults.standard.integer(forKey: "APPPasswordViewTypeKey") 16 | 17 | private var passwordView: IHPPasswordView? 18 | 19 | override func viewDidLoad() { 20 | super.viewDidLoad() 21 | let nibName = passwordViewType == 0 ? "HPNineDotView" : "HPSimplePasscodeView" 22 | self.title = passwordViewType == 0 ? "Nine Dot View Demo" : "Simple Passcode View Demo" 23 | passwordView = Bundle.main.loadNibNamed(nibName, owner: nil, options: nil)?.first as? IHPPasswordView 24 | let initalType = ADKPasswordViewSetting().initialType 25 | passwordView!.status = HPPasswordViewStatus(rawValue:initalType)! 26 | 27 | passwordView!.delegate = self 28 | 29 | self.view.insertSubview(passwordView as! UIView, belowSubview: statusLabel) 30 | (passwordView as! UIView).translatesAutoresizingMaskIntoConstraints = false 31 | 32 | } 33 | 34 | override func updateViewConstraints() { 35 | super.updateViewConstraints() 36 | let pwdView = passwordView as! UIView 37 | let insets = self.view.safeAreaInsets 38 | let topConstraint = NSLayoutConstraint(item: pwdView, attribute: NSLayoutAttribute.top, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.top, multiplier: 1.0, constant: insets.top) 39 | 40 | let bottomConstraint = NSLayoutConstraint(item: pwdView, attribute: NSLayoutAttribute.bottom, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.bottom, multiplier: 1.0, constant: insets.bottom) 41 | 42 | let leadingConstraint = NSLayoutConstraint(item: pwdView, attribute: NSLayoutAttribute.leading, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.leading, multiplier: 1.0, constant: insets.left) 43 | 44 | let trailingConstraint = NSLayoutConstraint(item: pwdView, attribute: NSLayoutAttribute.trailing, relatedBy: NSLayoutRelation.equal, toItem: self.view, attribute: NSLayoutAttribute.trailing, multiplier: 1.0, constant: insets.right) 45 | 46 | self.view.addConstraints([topConstraint, bottomConstraint, leadingConstraint, trailingConstraint]) 47 | } 48 | 49 | private func update(status: String, with error: Bool = false) { 50 | statusLabel.text = status 51 | statusLabel.textColor = error ? UIColor.colorFrom(hex: "F26D5F") : UIColor.colorFrom(hex: "4E4749") 52 | } 53 | 54 | @objc 55 | private func closePage() { 56 | self.navigationController?.popViewController(animated: true) 57 | } 58 | 59 | // MARK: - HPPasswordViewDelegate 60 | 61 | func statusWill(change: HPPasswordViewStatusChange) { 62 | //... 63 | 64 | let fromStatus = change.from 65 | let toStatus = change.to 66 | let tryTimes = change.tryTimes 67 | 68 | if fromStatus == .create { 69 | switch toStatus { 70 | 71 | case .invalid: 72 | update(status: "Passcode length should be longger than 3", with: true) 73 | case .create: 74 | 75 | passwordViewType == 0 ? update(status: "Draw Again to Confirm") : update(status: "Input Again to Confirm") 76 | case .mismatch: 77 | update(status: "Mismatch! Please Try Again", with: true) 78 | case .match: 79 | passwordViewType == 0 ? update(status: "Pattern Saved") : update(status: "Passcode Saved") 80 | perform(#selector(closePage), with: nil, afterDelay: 1) 81 | default: 82 | break 83 | } 84 | } else if fromStatus == .reset { 85 | 86 | switch toStatus { 87 | case .match: 88 | passwordViewType == 0 ? update(status: "Draw A New Pattern") : update(status: "Input A New Passcode") 89 | case .mismatch: 90 | update(status: "Mismatch! Left Try Times \(tryTimes)", with: true) 91 | if tryTimes == 0 { 92 | perform(#selector(closePage), with: nil, afterDelay: 1) 93 | } 94 | default: 95 | break 96 | } 97 | } else if fromStatus == .delete { 98 | switch toStatus { 99 | case .mismatch: 100 | update(status: "Mismatch! Left Try Times \(tryTimes)", with: true) 101 | if tryTimes == 0 { 102 | perform(#selector(closePage), with: nil, afterDelay: 1) 103 | } 104 | case .match: 105 | passwordViewType == 0 ? update(status: "Pattern Deleted") : update(status: "Passcode Deleted") 106 | perform(#selector(closePage), with: nil, afterDelay: 1) 107 | default: 108 | break 109 | } 110 | } else if fromStatus == .verify { 111 | switch toStatus { 112 | case .mismatch: 113 | update(status: "Mismatch! Left Try Times \(tryTimes)", with: true) 114 | if tryTimes == 0 { 115 | perform(#selector(closePage), with: nil, afterDelay: 1) 116 | } 117 | case .match: 118 | update(status: "Unlocked") 119 | perform(#selector(closePage), with: nil, afterDelay: 1) 120 | default: 121 | break 122 | } 123 | } 124 | 125 | } 126 | 127 | func statusDid(change: HPPasswordViewStatusChange) { 128 | // 129 | } 130 | 131 | func beginInput(passwordView: T) where T : IHPPasswordView { 132 | update(status: "Release Finger When Done") 133 | } 134 | 135 | func endInput(passwordView: T) where T : IHPPasswordView { 136 | 137 | } 138 | 139 | } 140 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPDebugKit/resources/guide.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 24 | 25 | 26 | 27 |

Rrerequisite

28 |
29 |

30 |

  • 1.This plugin only support storyboard
  • 31 |
  • 2.This plugin's initial viewcontroller must be a navigation controller
  • 32 |
  • 3.This plugin's root viewcontroller must be HDKRootViewController
  • 33 |

    34 | 35 |

    How to apply self-defined theme or config to this plugin

    36 |
    37 |

    First implement the ADKTheme or ADKConfig protocol, then set it to HDKContext singleton before using this plugin

    38 | 39 |

    Descriptions of ADKTheme's parameters

    40 |
    41 |

    Default theme is ADKDefaultTheme

    42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
    Var.Description
    description-
    mainColorbackground color of floating button and all viewcontrollers' navigation bar initialized by applying method applyADKNavigationBar of UIViewController extension
    fontColortext color of all texts on build-in viewcontroller's navigation bar
    floatingButtonSize-
    floatingButtonText-
    floationButtonTextColor-
    floationButtonFontSize-
    68 | 69 |

    Descriptions of ADKConfig's parameters

    70 |
    71 |

    Default config is ADKDefaultConfig

    72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
    Var.Description
    storyboardName_phonestoryboard file name of iPhone,leave empty if current device is iPad
    storyboardName_padstoryboard file name of iPad,leave empty if current device is iPhone
    rootPageConfigFileNameconfig file name of plugin's root viewcontroller
    settingPageConfigFileNameconfig file name of plugin's setting viewcontroller
    storyboardNamestoryboard name of current platform
    storyboardstoryboard instance of current platform
    rootPageCellReuseID-
    defaultItemsdefault build-in items, like guideItem and settingItem
    101 | 102 |

    Description of root config file

    103 |
    104 |

    Demo file : HDKRootConfig.plist

    105 | 106 |

    107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 |
    FieldRequiredTypeComment
    titletrueStringcell item title
    segueIDfalseStringsegue identifier of cell click action in the plugin storyboard
    controllerNamefalseStringfull classname of the viewcontroller you want to push without storyboard, like AnwDebugKitDemo.HDKTest2ViewController
    controllerIDfalseStringcontroller id in the external storyboard
    controllerContainerfalseStringname of the external storyboard which holds the viewcontroller you want to push
    127 | 128 |

    Description of setting config file

    129 |
    130 |

    Demo file : HDKSettingConfig.plist

    131 |

    132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 |
    FieldRequiredTypeComment
    titletrueStringcell item title
    typetrueStringone cell type of below:
    142 | ADKCellTypeDetail
    143 | ADKCellTypeInput
    144 | ADKCellTypeSwitch
    145 | ADKCellTypePlain
    146 | ADKCellTypeAsync 147 |
    actionfalseStringstring name of the selector which will response to the cell action
    defaultValuefalseStringstring name of the selector which will response to the cell default value action
    156 |

    How to register a event handler of setting viewcontroller

    157 |
    158 |

    First implement a class which contains all the selectors defined in setting config file, refer to demo class HDKSettingEventHandler , then register it using ADKSettingCellEventCenter.register(eventHandler: HDKSettingEventHandler.init())

    159 | 160 |

    Selector name of a selector

    161 |
    162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 |
    selectorselector name
    func testSelector1() -> AnytestSelector1
    func testSelector2(_ param: Any) -> AnytestSelector2:
    func testSelector3(with param: Any) -> AnytestSelector3With:
    func testSelector4(with param1: Any, and param2: Any) -> AnytestSelector4With:and:
    170 | 171 | 172 | 173 | -------------------------------------------------------------------------------- /HPPluginRepo/Common/HPExts.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnwExts.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 30/11/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension Float { 13 | static func == (lhs: Float, rhs: Float) -> Bool { 14 | return fabsf(rhs - lhs) < Float.ulpOfOne 15 | } 16 | static func != (lhs: Float, rhs: Float) -> Bool { 17 | return fabsf(rhs - lhs) >= Float.ulpOfOne 18 | } 19 | } 20 | 21 | //extension Date { 22 | // func beginDateOfThisWeek() -> Date { 23 | // let calendar = Calendar(identifier:.gregorian) 24 | // let d = calendar.component(.weekday, from: self) 25 | // return self 26 | //// return self.addingTimeInterval(<#T##timeInterval: TimeInterval##TimeInterval#>) 27 | // } 28 | // func endDateOfThisWeek() -> Date { 29 | // return self 30 | // } 31 | //} 32 | 33 | extension CGPoint { 34 | func add(_ point: CGPoint) -> CGPoint { 35 | return CGPoint(x: self.x + point.x, y: self.y + point.y) 36 | } 37 | 38 | func divide(by point: CGPoint) -> CGPoint { 39 | return CGPoint(x: self.x / point.x, y: self.y / point.y) 40 | } 41 | 42 | func restricted(to bound: CGRect) -> CGPoint { 43 | var x = self.x 44 | var y = self.y 45 | x = max(x, bound.minX) 46 | x = min(x, bound.maxX) 47 | y = max(y, bound.minY) 48 | y = min(y, bound.maxY) 49 | return CGPoint(x: x, y: y) 50 | } 51 | 52 | func slope(with point: CGPoint) -> Float { 53 | return Float((self.y - point.y) / (self.x - point.x)) 54 | } 55 | } 56 | 57 | extension CGRect { 58 | static func rectOfCircle(center:CGPoint, radius: CGFloat) -> CGRect { 59 | return CGRect(x: center.x - radius, y: center.y - radius, width: 2 * radius, height: 2 * radius) 60 | } 61 | 62 | var center: CGPoint { 63 | return CGPoint(x: self.width/2.0 + self.origin.x, y: self.height/2.0 + self.origin.y) 64 | } 65 | 66 | static func rect(with center: CGPoint, size: CGSize) -> CGRect { 67 | let origin = CGPoint(x: center.x - size.width * 0.5, y: center.y - size.height * 0.5) 68 | return CGRect(origin: origin, size: size) 69 | } 70 | } 71 | 72 | extension UIViewController { 73 | 74 | func quickAdd(childViewController: UIViewController) { 75 | childViewController.willMove(toParentViewController: self) 76 | self.view.addSubview(childViewController.view) 77 | self.addChildViewController(childViewController) 78 | childViewController.didMove(toParentViewController: self) 79 | } 80 | 81 | func quickRemove(childViewController: UIViewController) { 82 | childViewController.willMove(toParentViewController: nil) 83 | childViewController.view.removeFromSuperview() 84 | childViewController.removeFromParentViewController() 85 | childViewController.didMove(toParentViewController: nil) 86 | 87 | } 88 | 89 | static func loadFromStoryboard(_ storyboardName: String? = nil ,with identifier: String?=nil) -> UIViewController { 90 | 91 | let _identifier = identifier == nil ? self.nameOfClass : identifier 92 | var sb = UIStoryboard.default() 93 | if storyboardName != nil { 94 | sb = UIStoryboard.init(name: storyboardName!, bundle: nil) 95 | } 96 | 97 | return sb.instantiateViewController(withIdentifier:_identifier!) 98 | } 99 | } 100 | 101 | extension UIStoryboard { 102 | 103 | static func `default`() -> UIStoryboard { 104 | let infoKey = UIDevice.isPhone() ? "UIMainStoryboardFile~iphone" : "UIMainStoryboardFile~ipad" 105 | var value: String? = Bundle.main.object(forInfoDictionaryKey: infoKey) as? String 106 | value = value ?? "Main" 107 | return UIStoryboard(name: value!, bundle: Bundle.main) 108 | } 109 | } 110 | 111 | extension UIDevice { 112 | static func isPhone() -> Bool { 113 | return UIDevice.current.model == "iPhone" 114 | } 115 | } 116 | 117 | extension NSObject { 118 | class var nameOfClass: String{ 119 | return NSStringFromClass(self).components(separatedBy: ".").last! 120 | } 121 | 122 | var nameOfClass: String { 123 | return NSStringFromClass(self as! AnyClass).components(separatedBy: ".").last! 124 | } 125 | } 126 | 127 | extension Float { 128 | static var random099: Float { 129 | return Float(arc4random()%100)/100.0 130 | } 131 | } 132 | 133 | extension UIColor { 134 | static var randomColor: UIColor { 135 | return UIColor(red: CGFloat(Float.random099), green: CGFloat(Float.random099), blue: CGFloat(Float.random099), alpha: 1.0) 136 | } 137 | static func color01(from tuple: (r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat)) -> UIColor { 138 | return UIColor(red: tuple.r, green: tuple.g, blue: tuple.b, alpha: tuple.a) 139 | } 140 | static func color255(from tuple: (r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat)) -> UIColor { 141 | return UIColor(red: tuple.r/255.0, green: tuple.g/255.0, blue: tuple.b/255.0, alpha: tuple.a) 142 | } 143 | 144 | static func colorFrom(hex: String, with alpha: CGFloat = 1.0) -> UIColor { 145 | 146 | /* 147 | * legnth of hex string should be 6 or 8 148 | */ 149 | guard hex.count == 6 || hex.count == 8 else { 150 | return UIColor.gray 151 | } 152 | 153 | var cString: String = hex.uppercased() 154 | 155 | if cString.hasPrefix("0X") { 156 | let index = cString.index(cString.startIndex, offsetBy: 2) 157 | cString = String(cString[index...]) 158 | } 159 | 160 | guard cString.count == 6 else { 161 | return UIColor.gray 162 | } 163 | var fromIndex = hex.index(hex.startIndex, offsetBy: 0) 164 | var toIndex = hex.index(hex.startIndex, offsetBy: 2) 165 | let rStr = String(cString[fromIndex..() 12 | 13 | public class ADKSettingCellEventCenter { 14 | 15 | public static let sharedInstance = ADKSettingCellEventCenter() 16 | 17 | private init() {} 18 | 19 | public static func register(eventHandler : NSObject) { 20 | 21 | for handler in _eventHandlers { 22 | if type(of: handler) === type(of: eventHandler) { 23 | return 24 | } 25 | } 26 | _eventHandlers.append(eventHandler) 27 | } 28 | 29 | @discardableResult 30 | func handleEvent(with selectorName: String, params: Any? = nil, callback:((AnyObject?) -> Swift.Void)? = nil) -> Unmanaged! { 31 | 32 | let selector = NSSelectorFromString(selectorName) 33 | for eventHandler in _eventHandlers { 34 | if !eventHandler.responds(to: selector) { 35 | continue 36 | } 37 | 38 | if callback != nil { 39 | DispatchQueue.global(qos: .userInitiated).async { 40 | // TBD : may cause some leak if result is a retained object 41 | let result = eventHandler.perform(selector) != nil ? eventHandler.perform(selector).takeUnretainedValue() : nil 42 | DispatchQueue.main.async { 43 | callback!(result) 44 | } 45 | } 46 | return nil 47 | } else { 48 | return eventHandler.perform(selector, with: params) 49 | } 50 | 51 | } 52 | return nil 53 | } 54 | } 55 | 56 | class ADKSettingCell: UITableViewCell, UITextFieldDelegate { 57 | @IBOutlet weak var titleLabel: UILabel! 58 | @IBOutlet weak var switchControl: UISwitch! 59 | @IBOutlet weak var sliderControl: UISlider! 60 | @IBOutlet weak var textField: UITextField! 61 | @IBOutlet weak var indicatorView: UIActivityIndicatorView! 62 | private var cellItem: ADKSettingCellItem? 63 | 64 | @IBAction func valueChanged(_ sender: AnyObject) { 65 | var value = NSNumber(value: 0) 66 | if let control = sender as? UISwitch { 67 | value = NSNumber(value: control.isOn) 68 | } else if let control = sender as? UISlider { 69 | value = NSNumber(value: control.value) 70 | } 71 | ADKSettingCellEventCenter.sharedInstance.handleEvent(with: cellItem!.action!, params: value) 72 | 73 | } 74 | 75 | override func prepareForReuse() { 76 | super.prepareForReuse() 77 | } 78 | 79 | func configCell(with cellItem: ADKSettingCellItem) { 80 | self.cellItem = cellItem 81 | if titleLabel != nil { 82 | if cellItem.varTitle != nil { 83 | let title = ADKSettingCellEventCenter.sharedInstance.handleEvent(with: cellItem.varTitle!).takeUnretainedValue() as! String 84 | titleLabel.text = title 85 | } else { 86 | titleLabel.text = cellItem.title 87 | } 88 | } 89 | 90 | switch cellItem.type! { 91 | case .inputValue: 92 | let placeHolder = ADKSettingCellEventCenter.sharedInstance.handleEvent(with: cellItem.defaultValue!).takeUnretainedValue() as! String 93 | textField.text = placeHolder 94 | case .switchValue: 95 | let isOn = ADKSettingCellEventCenter.sharedInstance.handleEvent(with: cellItem.defaultValue!).takeUnretainedValue() as! NSNumber 96 | switchControl.isOn = isOn.boolValue 97 | case .sliderValue: 98 | let value = ADKSettingCellEventCenter.sharedInstance.handleEvent(with: cellItem.defaultValue!).takeUnretainedValue() as! NSNumber 99 | sliderControl.value = value.floatValue 100 | case .async: 101 | cellItem.processing ? indicatorView.startAnimating() : indicatorView.stopAnimating() 102 | default: 103 | break 104 | } 105 | } 106 | 107 | func handleEvent() { 108 | switch cellItem!.type! { 109 | case .async: 110 | cellItem!.processing = true 111 | indicatorView.startAnimating() 112 | ADKSettingCellEventCenter.sharedInstance.handleEvent(with: cellItem!.action!, callback:{ 113 | [unowned self] (result) in 114 | self.indicatorView.stopAnimating() 115 | }) 116 | case .detail: 117 | ADKSettingCellEventCenter.sharedInstance.handleEvent(with: cellItem!.action!) 118 | default: 119 | break 120 | } 121 | } 122 | 123 | func textFieldDidEndEditing(_ textField: UITextField, reason: UITextFieldDidEndEditingReason) { 124 | ADKSettingCellEventCenter.sharedInstance.handleEvent(with: cellItem!.action!, params: textField.text) 125 | } 126 | } 127 | 128 | 129 | class HDKSettingViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { 130 | private let config = HDKContext.shared.config 131 | private lazy var items: (sections: Array, rows: Array>) = ADKSettingCellItem.parse(file: config.settingPageConfigFileName) 132 | 133 | override func viewDidLoad() { 134 | super.viewDidLoad() 135 | } 136 | 137 | override var preferredStatusBarStyle: UIStatusBarStyle { 138 | return UIStatusBarStyle.lightContent 139 | } 140 | 141 | @IBAction func dismissBtnClicked(_ sender: Any) { 142 | HDKFloatingButton.shrink() 143 | } 144 | 145 | @IBAction func backBtnClicked(_ sender: Any) { 146 | self.navigationController?.popViewController(animated: true) 147 | } 148 | 149 | func numberOfSections(in tableView: UITableView) -> Int { 150 | return items.sections.count 151 | } 152 | 153 | func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { 154 | let section = items.sections[section] 155 | return section.title 156 | } 157 | 158 | 159 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 160 | let rows = items.rows 161 | return rows[section].count 162 | } 163 | 164 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 165 | let rows = items.rows[indexPath.section] 166 | let item = rows[indexPath.row] 167 | let cell = tableView.dequeueReusableCell(withIdentifier: item.type!.rawValue) as! ADKSettingCell 168 | cell.configCell(with: item) 169 | return cell 170 | } 171 | 172 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 173 | let cell = tableView.cellForRow(at: indexPath) as! ADKSettingCell 174 | cell.handleEvent() 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPDebugKit/HDKFloatingButton.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HDKFloatingButton.swift 3 | // AnwDebugKitDemo 4 | // 5 | // Created by Hu, Peng on 23/10/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public let HDKFloatingButtonShrinkNotifName = Notification.Name("HDKFloatingButtonShrinkNotifName") 12 | public let HDKFloatingButtonExpandNotifName = Notification.Name("HDKFloatingButtonExpandNotifName") 13 | 14 | 15 | 16 | public class HDKFloatingButton: UIWindow { 17 | 18 | class ADKPlaceHolderViewController : UIViewController { 19 | override var preferredStatusBarStyle: UIStatusBarStyle { 20 | return UIStatusBarStyle.lightContent 21 | } 22 | } 23 | 24 | public var isShow = false 25 | 26 | static let sharedInstance = HDKFloatingButton(frame: UIScreen.main.bounds) 27 | static let holdOnDuration: TimeInterval = 10.0 28 | private var activeTime: NSDate? 29 | private var panCenter: CGPoint? 30 | private var isExpand = false 31 | private let control: UILabel = UILabel() 32 | private let theme = HDKContext.shared.theme 33 | private let config = HDKContext.shared.config 34 | 35 | private let placeHolder = ADKPlaceHolderViewController() 36 | 37 | private override init(frame: CGRect) { 38 | 39 | super.init(frame: frame) 40 | let insets = self.safeAreaInsets 41 | // init floating button 42 | control.frame = CGRect(origin: CGPoint(x: insets.left, y: insets.top), size: HDKContext.shared.theme.floatingButtonSize) 43 | control.backgroundColor = theme.floationButtonColor 44 | control.text = theme.floatingButtonText 45 | control.textAlignment = NSTextAlignment.center 46 | control.textColor = theme.floationButtonTextColor 47 | control.font = UIFont.boldSystemFont(ofSize: theme.floationButtonFontSize) 48 | control.layer.cornerRadius = theme.floatingButtonSize.width * 0.5 49 | control.adjustsFontSizeToFitWidth = true 50 | control.clipsToBounds = true 51 | self.addSubview(control) 52 | 53 | // add gesture handlers 54 | let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tap(_:))) 55 | control.addGestureRecognizer(tapGesture) 56 | let panGesture = UIPanGestureRecognizer(target: self, action: #selector(pan(_:))) 57 | control.addGestureRecognizer(panGesture) 58 | 59 | self.rootViewController = placeHolder 60 | } 61 | 62 | public override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { 63 | if(self.rootViewController!.isKind(of: UINavigationController.self)) { 64 | return super.hitTest(point, with: event) 65 | } else if (control.frame.contains(point)) { 66 | return control 67 | } else { 68 | return nil 69 | } 70 | } 71 | 72 | required public init?(coder aDecoder: NSCoder) { 73 | super.init(coder: aDecoder) 74 | } 75 | 76 | // gesture handlers 77 | @objc 78 | func tap(_ sender: UIGestureRecognizer) { 79 | if isExpand { 80 | shrink() 81 | } else { 82 | expand() 83 | } 84 | } 85 | @objc 86 | func pan(_ sender: UIPanGestureRecognizer) { 87 | 88 | let point = __CGPointApplyAffineTransform(sender.translation(in: self), self.transform) 89 | let w = self.bounds.width 90 | let h = self.bounds.height 91 | let controlHalfW = control.bounds.width * 0.5 92 | activeTime = NSDate() 93 | 94 | if sender.state == UIGestureRecognizerState.began { 95 | panCenter = control.center 96 | } else if sender.state == UIGestureRecognizerState.changed { 97 | control.center = panCenter!.add(point).restricted(to: self.bounds.insetBy(dx: controlHalfW, dy: controlHalfW)) 98 | } else { 99 | let pinLeft = control.center.divide(by: CGPoint(x: w, y: h)).x <= 0.5 100 | let controlY = control.center.y 101 | UIView.animate(withDuration: 0.25, delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.2, options: UIViewAnimationOptions(rawValue: 0x01), animations: { 102 | [unowned self] in 103 | 104 | if pinLeft { 105 | self.control.center = CGPoint(x: controlHalfW, y: controlY) 106 | self.control.autoresizingMask = UIViewAutoresizing(rawValue: UIViewAutoresizing.flexibleRightMargin.rawValue | UIViewAutoresizing.flexibleTopMargin.rawValue | UIViewAutoresizing.flexibleBottomMargin.rawValue ) 107 | 108 | } else { 109 | self.control.center = CGPoint(x: w - controlHalfW, y: controlY) 110 | self.control.autoresizingMask = UIViewAutoresizing(rawValue: UIViewAutoresizing.flexibleLeftMargin.rawValue | UIViewAutoresizing.flexibleTopMargin.rawValue | UIViewAutoresizing.flexibleBottomMargin.rawValue ) 111 | } 112 | 113 | }, completion: { [unowned self](finished) in 114 | self.perform(#selector(HDKFloatingButton.resignActive), with: nil, afterDelay: HDKFloatingButton.holdOnDuration) 115 | }) 116 | } 117 | } 118 | 119 | // private methods 120 | func expand() { 121 | 122 | let scaleRatio = min(self.bounds.width/control.bounds.width, self.bounds.height/control.bounds.height) 123 | 124 | UIView.animate(withDuration: 0.15, animations: { 125 | [unowned self] in 126 | self.control.transform = CGAffineTransform.init(scaleX: scaleRatio, y: scaleRatio) 127 | self.control.alpha = 0.0; 128 | 129 | }) { [unowned self](finished) in 130 | let sb = self.config.storyboard 131 | let rootVC = sb.instantiateInitialViewController() 132 | 133 | assert(rootVC != nil, "storyboard \(self.config.storyboardName) must have a root viewcontroller") 134 | assert(rootVC!.isKind(of: UINavigationController.self), "root view controller of storyboard \(self.config.storyboardName) must be a navigation controller") 135 | 136 | self.rootViewController = rootVC 137 | 138 | self.isExpand = !self.isExpand 139 | NotificationCenter.default.post(name: HDKFloatingButtonExpandNotifName, object: nil) 140 | } 141 | } 142 | func shrink() { 143 | self.rootViewController = placeHolder 144 | UIView.animate(withDuration: 0.15, animations: { 145 | [unowned self] in 146 | self.control.transform = CGAffineTransform.identity 147 | self.control.alpha = 1.0 148 | }) { [unowned self](finised) in 149 | self.isExpand = !self.isExpand 150 | 151 | NotificationCenter.default.post(name: HDKFloatingButtonShrinkNotifName, object: nil) 152 | } 153 | } 154 | 155 | func shift() { 156 | isShow = !isShow 157 | if isShow { 158 | self.makeKeyAndVisible() 159 | self.perform(#selector(HDKFloatingButton.resignActive), with: nil, afterDelay: HDKFloatingButton.holdOnDuration) 160 | } else { 161 | UIApplication.shared.delegate?.window??.makeKeyAndVisible() 162 | } 163 | } 164 | 165 | @objc 166 | func resignActive() { 167 | // if activeTime == nil || activeTime!.timeIntervalSinceNow < -5 { 168 | // control.center = CGPoint(x: 0, y: control.center.y) 169 | // } 170 | } 171 | 172 | // public APIS 173 | public static func shift() { 174 | HDKFloatingButton.sharedInstance.shift() 175 | } 176 | public static func expand() { 177 | HDKFloatingButton.sharedInstance.expand() 178 | } 179 | public static func shrink() { 180 | HDKFloatingButton.sharedInstance.shrink() 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPPasswordPlugin/BuildInViews/HPSimplePasscodeView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HPSimplePasscodeView.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 22/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class HPPasscodeInputViewCursor: UIView { 12 | 13 | private var _show = false 14 | var show: Bool { 15 | set(newValue) { 16 | _show = newValue 17 | if newValue { 18 | timer.fire() 19 | } else { 20 | timer.invalidate() 21 | self.isHidden = true 22 | } 23 | } 24 | get { 25 | 26 | return _show 27 | } 28 | } 29 | var _timer: Timer? 30 | 31 | var timer: Timer { 32 | if _timer == nil || !_timer!.isValid { 33 | _timer = Timer.scheduledTimer(withTimeInterval: 0.4, repeats: true) { (t) in 34 | self.isHidden = !self.isHidden 35 | } 36 | } 37 | return _timer! 38 | } 39 | } 40 | 41 | @IBDesignable class HPPasscodeInputView: UIView { 42 | 43 | enum BorderMask: Int { 44 | case none = 0 45 | case top = 1 46 | case right = 2 47 | case bottom = 4 48 | case left = 8 49 | case all = 15 50 | } 51 | 52 | @IBInspectable var borderColor: UIColor = UIColor.color255(from: (r: 12.0, g: 81.0, b: 149, a: 1.0)) 53 | @IBInspectable var errorColor: UIColor = UIColor.color255(from: (r: 255.0, g: 78.0, b: 78.0, a: 1.0)) 54 | @IBInspectable var borderWidth: CGFloat = 1 55 | @IBInspectable var borderMask: Int = BorderMask.all.rawValue 56 | 57 | @IBOutlet weak var cursor: HPPasscodeInputViewCursor! 58 | @IBOutlet weak var titleLabel: UILabel! 59 | 60 | private var _selected: Bool = false; 61 | private var _text: String? 62 | 63 | var showError: Bool = false 64 | 65 | var selected: Bool { 66 | get { 67 | return _selected 68 | } 69 | set(newValue) { 70 | cursor.show = newValue 71 | _selected = newValue 72 | } 73 | } 74 | 75 | var text: String? { 76 | get { 77 | return _text 78 | } 79 | set(newValue) { 80 | 81 | _text = newValue 82 | titleLabel.text = newValue 83 | } 84 | } 85 | 86 | override func awakeFromNib() { 87 | super.awakeFromNib() 88 | self.selected = false 89 | } 90 | 91 | override func draw(_ rect: CGRect) { 92 | super.draw(rect) 93 | let w = rect.width 94 | let h = rect.height 95 | let context = UIGraphicsGetCurrentContext()! 96 | context.setStrokeColor(showError ? errorColor.cgColor : borderColor.cgColor) 97 | context.setLineWidth(borderWidth) 98 | if borderMask | BorderMask.top.rawValue > 0 { 99 | context.move(to: CGPoint.zero) 100 | context.addLine(to: CGPoint(x: w, y: 0)) 101 | context.strokePath() 102 | context.saveGState() 103 | } 104 | 105 | if borderMask | BorderMask.right.rawValue > 0 { 106 | context.move(to: CGPoint(x: w, y: 0)) 107 | context.addLine(to: CGPoint(x: w, y: h)) 108 | context.strokePath() 109 | context.saveGState() 110 | } 111 | 112 | if borderMask | BorderMask.bottom.rawValue > 0 { 113 | context.move(to: CGPoint(x: w, y: h)) 114 | context.addLine(to: CGPoint(x: 0, y: h)) 115 | context.strokePath() 116 | context.saveGState() 117 | } 118 | 119 | if borderMask | BorderMask.left.rawValue > 0 { 120 | context.move(to: CGPoint(x: 0, y: h)) 121 | context.addLine(to: CGPoint(x: 0, y: 0)) 122 | context.strokePath() 123 | context.saveGState() 124 | } 125 | } 126 | } 127 | 128 | class HPSimplePasscodeViewStorage: NSObject, IHPPasswordStorage { 129 | 130 | static let passwordKey = "com.hpDemo.simplePasswordView.key" 131 | 132 | let defaultStorage = UserDefaults.standard 133 | var _password: String? 134 | var password: String? { 135 | if _password == nil { 136 | _password = defaultStorage.string(forKey: HPSimplePasscodeViewStorage.passwordKey) 137 | } 138 | return _password 139 | } 140 | 141 | func save(password: String) { 142 | defaultStorage.set(password, forKey: HPSimplePasscodeViewStorage.passwordKey) 143 | } 144 | 145 | func deletePassword() { 146 | defaultStorage.removeObject(forKey: HPSimplePasscodeViewStorage.passwordKey) 147 | } 148 | func validate(password: Any?) -> Bool { 149 | return true 150 | } 151 | 152 | func password(from: Any?) -> String? { 153 | guard let passcodeArr = from as? Array else { 154 | return nil 155 | } 156 | return passcodeArr.joined(separator: "-") 157 | } 158 | } 159 | 160 | @IBDesignable class HPSimplePasscodeView: UIView, IHPPasswordView, UITextFieldDelegate { 161 | 162 | @IBOutlet var inputViews: [HPPasscodeInputView]! 163 | @IBOutlet weak var textField: UITextField! 164 | private var enable: Bool = true 165 | 166 | var tmpPassword: Any? { 167 | get { 168 | return [inputViews[0].text, inputViews[1].text, inputViews[2].text, inputViews[3].text] 169 | } 170 | set(newValue) { 171 | guard let textArr = newValue as? Array else { 172 | return 173 | } 174 | inputViews[0].text = textArr[0] 175 | inputViews[1].text = textArr[1] 176 | inputViews[2].text = textArr[2] 177 | inputViews[3].text = textArr[3] 178 | } 179 | 180 | } 181 | var maxTryTime: Int { 182 | return 3 183 | } 184 | var status: HPPasswordViewStatus = .create 185 | 186 | var delegate: HPPasswordViewDelegate? 187 | 188 | private var _decorator: HPPasswordViewDecorator? = nil 189 | 190 | private var decorator: HPPasswordViewDecorator { 191 | if _decorator == nil { 192 | _decorator = HPPasswordViewDecorator(passwordView: self, storage: HPSimplePasscodeViewStorage()) 193 | } 194 | return _decorator! 195 | } 196 | 197 | private var currentIndex = 0 198 | lazy private var leftTryTime = self.maxTryTime 199 | 200 | 201 | override func didMoveToSuperview() { 202 | super.didMoveToSuperview() 203 | textField.becomeFirstResponder() 204 | inputViews.first!.selected = true 205 | } 206 | 207 | @objc private func resetView() { 208 | 209 | for inputView in inputViews { 210 | inputView.text = nil 211 | inputView.selected = false 212 | inputView.showError = false 213 | inputView.setNeedsDisplay() 214 | } 215 | currentIndex = 0 216 | enable = true 217 | inputViews[currentIndex].selected = true 218 | } 219 | 220 | private func showErrorStatus() { 221 | 222 | 223 | inputViews[currentIndex].selected = false 224 | for inputView in inputViews { 225 | inputView.showError = true 226 | inputView.setNeedsDisplay() 227 | } 228 | } 229 | 230 | // MARK: - IHPPasswordView 231 | func passwordImage() -> UIImage? { 232 | return nil 233 | } 234 | 235 | func updateView(with change: HPPasswordViewStatusChange) { 236 | let toStatus = change.to 237 | leftTryTime = change.tryTimes 238 | enable = false 239 | if toStatus != .mismatch && toStatus != .invalid { 240 | perform(#selector(resetView), with: nil, afterDelay: 0.5) 241 | } else { 242 | showErrorStatus() 243 | perform(#selector(resetView), with: nil, afterDelay: 1) 244 | } 245 | } 246 | 247 | // MARK: - IHPPasswordView 248 | func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { 249 | 250 | if !enable { 251 | return false 252 | } 253 | 254 | inputViews[currentIndex].text = string 255 | inputViews[currentIndex].selected = false 256 | currentIndex = (currentIndex + 1)%inputViews.count 257 | inputViews[currentIndex].selected = true 258 | 259 | if currentIndex == 0 { 260 | decorator.triggerStatusChange(HPPasswordViewStatusChange(from: self.status, to: .empty, tryTimes: self.leftTryTime)) 261 | } 262 | 263 | return false 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPTaskManager/HPTaskManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HPTaskManager.swift 3 | // HPPluginRepo 4 | // 5 | // Created by 胡鹏 on 23/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | private func __HPTaskManagerDateFormatter() -> DateFormatter { 12 | let formatter = DateFormatter() 13 | formatter.dateFormat = "yyyy-MM-dd" 14 | formatter.calendar = Calendar.init(identifier: .gregorian) 15 | return formatter 16 | } 17 | 18 | enum HPTaskManagerError: Error { 19 | case duplicatedTask(key: String, user: String) 20 | case taskNotFound(key: String, user: String) 21 | case taskHasBeenCompleted(key: String, user: String) 22 | case taskInactive(key: String, user: String) 23 | case invalidParameter(message: String) 24 | } 25 | 26 | public class HPTaskManager { 27 | 28 | public typealias TaskTimeDuration = Array 29 | public typealias TaskTimeWeekdays = Int 30 | public typealias TaskTimeWeekday = Int 31 | public static let Monday: TaskTimeWeekday = 1 << 0 32 | public static let Tuesday: TaskTimeWeekday = 1 << 1 33 | public static let Wednesday: TaskTimeWeekday = 1 << 2 34 | public static let Thursday: TaskTimeWeekday = 1 << 3 35 | public static let Friday: TaskTimeWeekday = 1 << 4 36 | public static let Saturday: TaskTimeWeekday = 1 << 5 37 | public static let Sunday: TaskTimeWeekday = 1 << 6 38 | 39 | public enum TaskType: Int { 40 | /* 41 | * task can be registed anytime 42 | * task can be completed anytime 43 | */ 44 | case normal 45 | /* 46 | * task will be refreshed everyday automatically 47 | */ 48 | case daily 49 | /* 50 | * task will be achievable only on specified weekdays 51 | */ 52 | case weekly 53 | /* 54 | * task can only be registed before the end date of the duration 55 | * task will be removed after the end date of the duration 56 | */ 57 | case periodic 58 | } 59 | 60 | public struct TaskTimeArg { 61 | var duration: TaskTimeDuration? 62 | var weekdays: TaskTimeWeekdays? 63 | 64 | init(duration: TaskTimeDuration) throws { 65 | guard duration.count == 2 else { 66 | throw HPTaskManagerError.invalidParameter(message: "duration must has two date string element") 67 | } 68 | self.duration = duration 69 | } 70 | init(weekdays: TaskTimeWeekdays) { 71 | self.weekdays = weekdays 72 | } 73 | } 74 | 75 | public struct Task: Equatable { 76 | 77 | let type: TaskType 78 | let key : String 79 | var user: String 80 | let taskTimeArg: TaskTimeArg? 81 | var times: Int 82 | var leftTimes: Int 83 | // string of date & dateFormat = "yyyy-MM-dd" 84 | var updateTime: String 85 | 86 | init(type: TaskType = .normal, 87 | key: String, 88 | user: String = "com.hp.task.default.key", 89 | arg: TaskTimeArg? = nil, 90 | times: Int = 1) { 91 | 92 | self.type = type 93 | self.key = key 94 | self.user = user 95 | self.taskTimeArg = arg 96 | self.times = Task.taskIsActive(with: arg) ? times : 0 97 | self.leftTimes = times 98 | self.updateTime = Task.getLatestUpdateTime() 99 | } 100 | public static func weekDay(of date: Date) -> TaskTimeWeekday { 101 | let cal = Calendar.init(identifier: .gregorian) 102 | let weekDay = cal.component(.weekday, from: Date()) 103 | switch weekDay { 104 | case 1: 105 | return HPTaskManager.Sunday 106 | case 2: 107 | return HPTaskManager.Monday 108 | case 3: 109 | return HPTaskManager.Tuesday 110 | case 4: 111 | return HPTaskManager.Wednesday 112 | case 5: 113 | return HPTaskManager.Thursday 114 | case 6: 115 | return HPTaskManager.Friday 116 | case 7: 117 | return HPTaskManager.Saturday 118 | default: 119 | return HPTaskManager.Sunday 120 | } 121 | } 122 | 123 | public static func taskIsActive(with arg: TaskTimeArg?) -> Bool { 124 | guard let taskTimeArg = arg else { 125 | return true 126 | } 127 | let today = Date() 128 | if taskTimeArg.duration != nil { 129 | let beginDate = taskTimeArg.duration![0] 130 | let endDate = taskTimeArg.duration![1] 131 | guard today.timeIntervalSince(beginDate) < 0 else { 132 | return false 133 | } 134 | guard today.timeIntervalSince(endDate) > 0 else { 135 | return false 136 | } 137 | } else if taskTimeArg.weekdays != nil { 138 | let today = weekDay(of: Date()) 139 | return today | taskTimeArg.weekdays! > 0 140 | } 141 | return true 142 | } 143 | public static func getLatestUpdateTime() -> String { 144 | let formatter = __HPTaskManagerDateFormatter() 145 | return formatter.string(from: Date()) 146 | } 147 | public static func == (lhs: Task, rhs: Task) -> Bool { 148 | return lhs.key == rhs.key && lhs.user == rhs.user 149 | } 150 | public static func != (lhs: Task, rhs: Task) -> Bool { 151 | return lhs.key != rhs.key || lhs.user != rhs.user 152 | } 153 | } 154 | 155 | static let `default` = HPTaskManager() 156 | private var tasks: Array = [] 157 | private let persistence = UserDefaults.standard 158 | private let cacheKey = "com.HPTaskManager.tasks.cacheKey" 159 | private let threadSafeQueue = DispatchQueue(label: "com.HPTaskManager.threadSafeQ", attributes: .concurrent) 160 | 161 | private init() { 162 | loadTasks() 163 | 164 | NotificationCenter.default.addObserver(forName: NSNotification.Name.UIApplicationDidEnterBackground, object: self, queue: nil) { (notif) in 165 | self.saveTasks() 166 | } 167 | NotificationCenter.default.addObserver(forName: NSNotification.Name.UIApplicationWillTerminate, object: self, queue: nil) { (notif) in 168 | self.saveTasks() 169 | } 170 | } 171 | 172 | private func saveTasks() { 173 | persistence.set(tasks, forKey: cacheKey) 174 | } 175 | 176 | private func loadTasks() { 177 | let caches: Array = (persistence.object(forKey: cacheKey) as? Array) ?? [] 178 | for t in caches { 179 | var task = t 180 | let type = task.type 181 | let today = Task.getLatestUpdateTime() 182 | if type == .normal { 183 | if task.leftTimes > 0 { // remove completed tasks 184 | tasks.append(task) 185 | } 186 | } else if type == .daily { 187 | if today != task.updateTime { // refresh daily task 188 | task.leftTimes = task.times 189 | task.updateTime = today 190 | } 191 | tasks.append(task) 192 | } else if type == .weekly { 193 | if today != task.updateTime { // refresh weekly task 194 | let isSpecifiedWeekday = Task.taskIsActive(with: task.taskTimeArg) 195 | task.leftTimes = isSpecifiedWeekday ? task.times : 0 196 | task.updateTime = today 197 | } 198 | tasks.append(task) 199 | } else if type == .periodic { 200 | let endDate = task.taskTimeArg!.duration![1] 201 | if Date().timeIntervalSince(endDate) <= 0 { // remove expired task 202 | tasks.append(task) 203 | } 204 | } 205 | } 206 | 207 | } 208 | 209 | public func register(task: Task) throws { 210 | let index = tasks.index(of: task) 211 | guard index == nil else { 212 | throw HPTaskManagerError.duplicatedTask(key: task.key, user: task.user) 213 | } 214 | tasks.append(task) 215 | } 216 | 217 | public func revoke(task: Task) throws { 218 | let index = tasks.index(of: task) 219 | guard let unwrappedIndex = index else { 220 | throw HPTaskManagerError.taskNotFound(key: task.key, user: task.user) 221 | } 222 | tasks.remove(at: unwrappedIndex) 223 | } 224 | 225 | public func complete( task: inout Task) throws { 226 | let index = tasks.index(of: task) 227 | guard index != nil else { 228 | throw HPTaskManagerError.taskNotFound(key: task.key, user: task.user) 229 | } 230 | guard Task.taskIsActive(with: task.taskTimeArg) != false else { 231 | throw HPTaskManagerError.taskInactive(key: task.key, user: task.user) 232 | } 233 | guard task.leftTimes > 0 else { 234 | throw HPTaskManagerError.taskHasBeenCompleted(key: task.key, user: task.user) 235 | } 236 | task.leftTimes -= 1 237 | } 238 | 239 | } 240 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPDebugKit/HDKContext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ADKTheme.swift 3 | // AnwDebugKitDemo 4 | // 5 | // Created by Hu, Peng on 23/10/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | enum ADKError : Error { 12 | case invalidClassName(className: String) 13 | case invalidSelectorName(selectorName: String) 14 | } 15 | 16 | enum ADKCellType : String { 17 | case groupHeader = "ADKCellTypeGroupHeader" 18 | case plain = "ADKCellTypePlain" 19 | case detail = "ADKCellTypeDetail" 20 | case async = "ADKCellTypeAsync" 21 | case inputValue = "ADKCellTypeInput" 22 | case switchValue = "ADKCellTypeSwitch" 23 | case sliderValue = "ADKCellTypeSlider" 24 | } 25 | 26 | public struct ADKRootCellItem { 27 | var title: String? // ===> item title displayed on the cell 28 | var segueID: String? // ===> id of segue which connected to this controller in the root storyboard 29 | var controllerName: String? // ===> class name of this controller 30 | var controllerID: String? // ===> stoaryboard id of this controller 31 | // ===> stoaryboard name which contains this controller 32 | var controllerContainer : String? = HDKContext.shared.config.storyboardName 33 | 34 | func controller () throws -> UIViewController? { 35 | if controllerName != nil { 36 | guard let clz = NSClassFromString(controllerName!) else { 37 | throw ADKError.invalidClassName(className: controllerName!) 38 | } 39 | let controllerClz = clz as! UIViewController.Type 40 | return controllerClz.init() 41 | } else if controllerID != nil { 42 | let sb = UIStoryboard(name: controllerContainer!, bundle: nil) 43 | return sb.instantiateViewController(withIdentifier: controllerID!) 44 | } else { 45 | return nil 46 | } 47 | } 48 | 49 | init(title: String?, segueID: String?, controllerName: String?, controllerID: String? ,controllerContainer: String?) { 50 | self.title = title 51 | self.segueID = segueID 52 | self.controllerName = controllerName 53 | self.controllerID = controllerID 54 | self.controllerContainer = controllerContainer 55 | } 56 | 57 | static func parse(file: String) -> Array { 58 | let path = Bundle.main.path(forResource: file, ofType: "plist") 59 | assert(path != nil, "config file [\(file)] not found") 60 | let rawItems = NSArray(contentsOfFile: path!) 61 | var items = Array() 62 | 63 | for rawItem in rawItems! { 64 | let rawItemInfo: NSDictionary = rawItem as! NSDictionary 65 | let item = ADKRootCellItem(title: (rawItemInfo["title"] as? String), 66 | segueID: (rawItemInfo["segueID"] as? String), 67 | controllerName: (rawItemInfo["controllerName"] as? String), 68 | controllerID: nil, 69 | controllerContainer: nil) 70 | items.append(item) 71 | } 72 | return items 73 | } 74 | } 75 | 76 | public struct ADKSettingCellItem { 77 | var title: String? // ===> cell title 78 | var varTitle: String? // ===> string value of cell title selector 79 | var action: String? // ===> string value of cell action selector 80 | var type: ADKCellType? // ===> cell type 81 | var defaultValue: String? // ===> string value of cell default value selector 82 | var processing = false // ===> only used for async cell type 83 | 84 | static func parse(file: String) -> (sections: Array, rows: Array>) { 85 | let path = Bundle.main.path(forResource: file, ofType: "plist") 86 | assert(path != nil, "config file [\(file)] not found") 87 | let rawSections = NSArray(contentsOfFile: path!) 88 | 89 | guard rawSections != nil else { 90 | return ([], []) 91 | } 92 | 93 | var rows = Array>() 94 | var sections = Array() 95 | 96 | for rawSection in rawSections! { 97 | 98 | let rawSectionInfo: NSDictionary = rawSection as! NSDictionary 99 | var section = ADKSettingCellItem() 100 | section.title = rawSectionInfo["title"] as? String 101 | section.type = ADKCellType(rawValue: rawSectionInfo["type"] as! String) 102 | 103 | let rawRows: NSArray? = rawSectionInfo["items"] as? NSArray 104 | var sectionRows = Array() 105 | 106 | if rawRows != nil { 107 | for rawRow in rawRows! { 108 | let rawRowInfo: NSDictionary = rawRow as! NSDictionary 109 | var item = ADKSettingCellItem() 110 | item.title = rawRowInfo["title"] as? String 111 | item.action = rawRowInfo["action"] as? String 112 | item.type = ADKCellType(rawValue: rawRowInfo["type"] as! String) 113 | item.defaultValue = rawRowInfo["defaultValue"] as? String 114 | item.varTitle = rawRowInfo["varTitle"] as? String 115 | sectionRows.append(item) 116 | } 117 | } 118 | sections.append(section) 119 | rows.append(sectionRows) 120 | } 121 | return (sections: sections, rows: rows) 122 | } 123 | } 124 | 125 | public let settingItem = ADKRootCellItem(title: "Settings", 126 | segueID: nil, 127 | controllerName: nil, 128 | controllerID: "HDKSettingViewController", 129 | controllerContainer: "ADKStoryboard_container") 130 | 131 | public let guideItem = ADKRootCellItem(title: "Guide", 132 | segueID: nil, 133 | controllerName: nil, 134 | controllerID: "HDKGuideViewController", 135 | controllerContainer: "ADKStoryboard_container") 136 | 137 | 138 | public protocol ADKTheme { 139 | var description: String { get } 140 | var mainColor: UIColor { get } 141 | var fontColor: UIColor { get } 142 | var floatingButtonSize: CGSize { get } 143 | var floationButtonColor: UIColor { get } 144 | var floatingButtonText: String { get } 145 | var floationButtonTextColor: UIColor { get } 146 | var floationButtonFontSize: CGFloat { get } 147 | } 148 | 149 | public protocol ADKConfig { 150 | var storyboardName_phone: String { get } 151 | var storyboardName_pad: String { get } 152 | var rootPageConfigFileName: String { get } 153 | var settingPageConfigFileName: String { get } 154 | 155 | var storyboardName: String { get } 156 | var storyboard: UIStoryboard { get } 157 | var rootPageCellReuseID: String { get } 158 | var defaultItems: Array { get } 159 | } 160 | 161 | public struct ADKDefaultConfig: ADKConfig { 162 | public var storyboardName_phone: String { 163 | return "HDKStoryboard_phone" 164 | } 165 | public var storyboardName_pad: String { 166 | return "ADKStoryboard_pad" 167 | } 168 | public var rootPageConfigFileName: String { 169 | return "HDKRootConfig" 170 | } 171 | public var settingPageConfigFileName: String { 172 | return "HDKSettingConfig" 173 | } 174 | public var storyboardName: String { 175 | return UIDevice.current.userInterfaceIdiom == UIUserInterfaceIdiom.pad ? storyboardName_pad : storyboardName_phone 176 | } 177 | public var storyboard: UIStoryboard { 178 | return UIStoryboard(name: storyboardName, bundle: nil) 179 | } 180 | public var rootPageCellReuseID: String { 181 | return "cell" 182 | } 183 | public var defaultItems: Array { 184 | return [guideItem ,settingItem] 185 | } 186 | } 187 | 188 | public struct ADKDefaultTheme : ADKTheme { 189 | 190 | public var description: String { 191 | return "ADKDefaultTheme" 192 | } 193 | public var mainColor: UIColor { 194 | return UIColor(red: 137.0/255.0, green: 49.0/255.0, blue: 234.0/255.0, alpha: 1.0) 195 | } 196 | public var fontColor: UIColor { 197 | return UIColor.white 198 | } 199 | public var floatingButtonSize: CGSize { 200 | return CGSize(width: 60, height: 60) 201 | } 202 | public var floationButtonColor: UIColor { 203 | return UIColor(red: 137.0/255.0, green: 49.0/255.0, blue: 234.0/255.0, alpha: 1.0) 204 | } 205 | public var floatingButtonText: String { 206 | return NSLocalizedString("Debug", comment: self.description) 207 | } 208 | public var floationButtonTextColor: UIColor { 209 | return UIColor.white 210 | } 211 | public var floationButtonFontSize: CGFloat { 212 | return 14.0 213 | } 214 | } 215 | 216 | public class HDKContext { 217 | public static let shared = HDKContext() 218 | public var theme: ADKTheme = ADKDefaultTheme() 219 | public var config: ADKConfig = ADKDefaultConfig() 220 | private init() {} 221 | } 222 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPPasswordPlugin/BuildInViews/HPNineDotView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HPNineDotView.swift 3 | // HPPluginRepo 4 | // 5 | // Created by Hu, Peng on 15/12/2017. 6 | // Copyright © 2017 Hu, Peng. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | let kNDVMainColor = UIColor.color255(from: (r: 91.0, g: 153.0, b: 238.0, a: 1.0)) 12 | let kNDVSelectedBorderColor = UIColor.color255(from: (r: 53.0, g: 183.0, b: 127.0, a: 1.0)) 13 | let kNDVErrorLineColor = UIColor.color255(from: (r: 255.0, g: 78.0, b: 78.0, a: 1.0)) 14 | 15 | class HPNineDotViewStorage: NSObject, IHPPasswordStorage { 16 | 17 | static let passwordKey = "com.hpDemo.9DotView.password.key" 18 | let defaultStorage = UserDefaults.standard 19 | var _password: String? 20 | var password: String? { 21 | if _password == nil { 22 | _password = defaultStorage.string(forKey: HPNineDotViewStorage.passwordKey) 23 | } 24 | return _password 25 | } 26 | 27 | func save(password: String) { 28 | defaultStorage.set(password, forKey: HPNineDotViewStorage.passwordKey) 29 | } 30 | 31 | func deletePassword() { 32 | defaultStorage.removeObject(forKey: HPNineDotViewStorage.passwordKey) 33 | } 34 | 35 | func validate(password: Any?) -> Bool { 36 | 37 | guard let dots = password as? Array else { 38 | return false 39 | } 40 | return dots.count >= 3 41 | } 42 | 43 | func password(from: Any?) -> String? { 44 | guard let dots = from as? Array else { 45 | return nil 46 | } 47 | 48 | return dots.map({ (dot) -> String in 49 | return "\(dot.index)" 50 | }) .joined(separator: "-") 51 | } 52 | } 53 | 54 | @IBDesignable open class HPNineDotView: UIView, IHPPasswordView { 55 | 56 | public struct Dot { 57 | var center: CGPoint { 58 | return rect.center 59 | } 60 | var rect: CGRect 61 | var index: Int 62 | 63 | init(rect: CGRect, index: Int) { 64 | self.rect = rect 65 | self.index = index 66 | } 67 | 68 | func contains(_ point: CGPoint) -> Bool { 69 | return rect.contains(point) 70 | } 71 | 72 | static func == (lhs: Dot, rhs: Dot) -> Bool { 73 | return lhs.index == rhs.index 74 | } 75 | static func != (lhs: Dot, rhs: Dot) -> Bool { 76 | return lhs.index != rhs.index 77 | } 78 | } 79 | 80 | // UI Var. 81 | @IBInspectable var dotRadius: CGFloat = 30 82 | @IBInspectable var dotMargin: CGFloat = 30 83 | @IBInspectable var dotBorderWidth: CGFloat = 1 84 | @IBInspectable var dotBorderColor: UIColor = kNDVMainColor 85 | @IBInspectable var dotSelectedBorderColor: UIColor = kNDVSelectedBorderColor 86 | 87 | 88 | @IBInspectable var connectLineWidth: CGFloat = 2 89 | @IBInspectable var connectLineColor: UIColor = kNDVMainColor 90 | 91 | @IBInspectable var errorLineColor: UIColor = kNDVErrorLineColor 92 | 93 | @IBOutlet weak var draggedLineMaskView: UIImageView! 94 | @IBOutlet weak var connectedLineMaskView: UIImageView! 95 | 96 | 97 | private var effectViews: Array = [] 98 | private var selectedDots: Array = [] 99 | 100 | // Logic Var. 101 | private var dots: Array = [] 102 | private var preDot: Dot? 103 | lazy private var leftTryTime = self.maxTryTime 104 | 105 | // MARK: - IHPPasswordView implementation 106 | var maxTryTime: Int { 107 | return 3 108 | } 109 | 110 | var status: HPPasswordViewStatus = .create 111 | 112 | var tmpPassword: Any? { 113 | get { 114 | return selectedDots 115 | } 116 | set(newValue) { 117 | selectedDots = newValue as! Array 118 | } 119 | 120 | } 121 | 122 | var delegate: HPPasswordViewDelegate? 123 | 124 | // 125 | 126 | private var _decorator: HPPasswordViewDecorator? = nil 127 | 128 | private var decorator: HPPasswordViewDecorator { 129 | if _decorator == nil { 130 | _decorator = HPPasswordViewDecorator(passwordView: self, storage: HPNineDotViewStorage()) 131 | } 132 | return _decorator! 133 | } 134 | 135 | override open func touchesBegan(_ touches: Set, with event: UIEvent?) { 136 | 137 | self.delegate?.beginInput(passwordView: self) 138 | 139 | let touch = touches.first! 140 | let point = touch.location(in: self) 141 | 142 | let dot = selectedDot(with: point) 143 | 144 | guard dot != nil else { 145 | return 146 | } 147 | didSelect(dot: dot!) 148 | } 149 | 150 | override open func touchesMoved(_ touches: Set, with event: UIEvent?) { 151 | 152 | guard preDot != nil else { 153 | return 154 | } 155 | 156 | let touch = touches.first! 157 | let point = touch.location(in: self) 158 | 159 | connect(point: preDot!.center, to: point) 160 | 161 | let dot = selectedDot(with: point) 162 | 163 | guard dot != nil else { 164 | return 165 | } 166 | 167 | guard dot! != preDot! else { 168 | return 169 | } 170 | 171 | let midDot = middleDot(between: preDot!, and: dot!) 172 | 173 | if midDot != nil { 174 | connect(preDot!, to: midDot!) 175 | didSelect(dot: midDot!) 176 | } 177 | 178 | connect(preDot!, to: dot!) 179 | didSelect(dot: dot!) 180 | } 181 | 182 | override open func touchesEnded(_ touches: Set, with event: UIEvent?) { 183 | 184 | guard preDot != nil else { 185 | return 186 | } 187 | 188 | decorator.triggerStatusChange(HPPasswordViewStatusChange(from: self.status, to: .empty, tryTimes: leftTryTime)) 189 | draggedLineMaskView.image = nil 190 | 191 | self.delegate?.endInput(passwordView: self) 192 | } 193 | 194 | open override func touchesCancelled(_ touches: Set, with event: UIEvent?) { 195 | touchesEnded(touches, with: event) 196 | } 197 | 198 | override open func draw(_ rect: CGRect) { 199 | 200 | super.draw(rect) 201 | let context = UIGraphicsGetCurrentContext()! 202 | for i in 0..<9 { 203 | let center = centerOfDot(at: i) 204 | draw(dot: (radius: CGFloat(dotRadius), center: center), with: context) 205 | let dot = Dot(rect:CGRect.rectOfCircle(center: center, radius: dotRadius), index: i) 206 | dots.append(dot) 207 | } 208 | } 209 | 210 | @objc private func resetView() { 211 | connectedLineMaskView.image = nil 212 | draggedLineMaskView.image = nil 213 | selectedDots.removeAll() 214 | preDot = nil 215 | for view in effectViews { 216 | view.removeFromSuperview() 217 | } 218 | effectViews.removeAll() 219 | } 220 | 221 | private func showErrorStatus() { 222 | 223 | var preDot = selectedDots.first! 224 | 225 | for dot in selectedDots { 226 | 227 | if dot != preDot { 228 | connect(preDot, to: dot, error: true) 229 | preDot = dot 230 | } 231 | applySelectedEffect(to: dot, error: true) 232 | } 233 | 234 | } 235 | 236 | // MARK: - IHPPasswordView implementation 237 | 238 | open func passwordImage() -> UIImage? { 239 | return nil 240 | } 241 | 242 | func updateView(with change: HPPasswordViewStatusChange) { 243 | 244 | let toStatus = change.to 245 | leftTryTime = change.tryTimes 246 | 247 | if toStatus != .mismatch && toStatus != .invalid { 248 | resetView() 249 | } else { 250 | showErrorStatus() 251 | perform(#selector(resetView), with: nil, afterDelay: 1) 252 | } 253 | } 254 | 255 | // MARK: - 256 | private func centerOfDot(at index: Int) -> CGPoint { 257 | let w = self.bounds.width 258 | let h = self.bounds.height 259 | 260 | let viewCenter = CGPoint(x: w/2.0, y: h/2.0) 261 | let viewCenterRow = 1 262 | let viewCenterColumn = 1 263 | 264 | let row = index/3 265 | let column = index%3 266 | 267 | let x = viewCenter.x + CGFloat(column - viewCenterRow) * (dotRadius * 2 + dotMargin) 268 | let y = viewCenter.y + CGFloat(row - viewCenterColumn) * (dotRadius * 2 + dotMargin) 269 | return CGPoint(x: x, y: y) 270 | } 271 | 272 | open func draw(dot: (radius: CGFloat, center: CGPoint), with context: CGContext) { 273 | context.addArc(center: dot.center, radius: dot.radius, startAngle: 0, endAngle: CGFloat(2 * Double.pi), clockwise: false) 274 | context.setStrokeColor(dotBorderColor.cgColor) 275 | context.setLineWidth(dotBorderWidth) 276 | context.strokePath() 277 | } 278 | 279 | private func selectedDot(with touchPoint: CGPoint) -> Dot? { 280 | 281 | var matchedDot: Dot? = nil 282 | for dot in dots { 283 | if dot.contains(touchPoint) { 284 | matchedDot = dot 285 | break 286 | } 287 | } 288 | 289 | // case: no matched dot has been found 290 | guard matchedDot != nil else { 291 | return nil 292 | } 293 | 294 | // case: first dot always can be selected 295 | guard preDot != nil else { 296 | return matchedDot 297 | } 298 | 299 | // case: duplicated seleted index 300 | let duplicated = selectedDots.contains { (dot) -> Bool in 301 | return dot == matchedDot! 302 | } 303 | 304 | guard !duplicated else { 305 | return nil 306 | } 307 | 308 | // case: some special connect logic has not been fulfilled 309 | guard can(connect: preDot!, to: matchedDot!) else { 310 | return nil 311 | } 312 | 313 | return matchedDot 314 | } 315 | 316 | private func middleDot(between oneDot: Dot, and anotherDot: Dot) -> Dot? { 317 | 318 | guard (oneDot.index + anotherDot.index)%2 == 0 else { 319 | return nil 320 | } 321 | 322 | let middleIndex = (oneDot.index + anotherDot.index)/2 323 | let midDot = dots[middleIndex] 324 | 325 | let duplicated = selectedDots.contains { (dot) -> Bool in 326 | return dot == midDot 327 | } 328 | 329 | guard !duplicated else { 330 | return nil 331 | } 332 | 333 | let fromPoint = oneDot.center 334 | let toPoint = anotherDot.center 335 | let midPoint = midDot.center 336 | 337 | guard midPoint.slope(with: fromPoint) == midPoint.slope(with: toPoint) else { 338 | return nil 339 | } 340 | return midDot 341 | } 342 | 343 | /* 344 | * override this function if there are some special demands 345 | * ex. only nearby point can be connected to each other... 346 | */ 347 | open func can(connect dot: Dot, to anotherDot: Dot) -> Bool { 348 | return true 349 | } 350 | 351 | private func didSelect(dot: Dot) { 352 | selectedDots.append(dot) 353 | preDot = dot 354 | applySelectedEffect(to: dot, error: false) 355 | } 356 | 357 | open func applySelectedEffect(to dot: Dot, error: Bool) { 358 | 359 | let effectView = UIView(frame: dot.rect.insetBy(dx: -dotBorderWidth, dy: -dotBorderWidth)) 360 | effectView.backgroundColor = error ? errorLineColor : connectLineColor 361 | effectView.layer.cornerRadius = effectView.frame.width * 0.5 362 | effectView.layer.borderWidth = dotBorderWidth 363 | effectView.layer.borderColor = error ? errorLineColor.cgColor : connectLineColor.cgColor 364 | 365 | 366 | let animatedLayerSize: CGFloat = 20.0 367 | let scale = animatedLayerSize/dot.rect.width 368 | let animatedLayer = CALayer() 369 | animatedLayer.frame = effectView.bounds 370 | animatedLayer.cornerRadius = effectView.layer.cornerRadius 371 | animatedLayer.backgroundColor = UIColor.color255(from: (r: 245.0, g: 246.0, b: 247.0, a: 1.0)).cgColor 372 | 373 | let animation = CABasicAnimation(keyPath: "transform") 374 | animation.fromValue = CATransform3DMakeAffineTransform(CGAffineTransform(scaleX: scale, y: scale)) 375 | animation.toValue = CATransform3DIdentity 376 | animation.duration = 0.2 377 | animation.isRemovedOnCompletion = false 378 | animatedLayer.add(animation, forKey: "scale") 379 | 380 | 381 | let centerLayer = CALayer() 382 | centerLayer.frame = CGRect.rect(with: effectView.bounds.center, size: CGSize(width: animatedLayerSize, height: animatedLayerSize)) 383 | centerLayer.cornerRadius = animatedLayerSize * 0.5 384 | centerLayer.backgroundColor = error ? errorLineColor.cgColor : connectLineColor.cgColor 385 | 386 | effectView.layer.addSublayer(animatedLayer) 387 | effectView.layer.addSublayer(centerLayer) 388 | 389 | self.addSubview(effectView) 390 | effectViews.append(effectView) 391 | 392 | } 393 | 394 | private func connect(_ dot: Dot, to anotherDot: Dot, error: Bool = false) { 395 | 396 | let fromPoint = dot.center 397 | let toPoint = anotherDot.center 398 | 399 | UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale) 400 | let context = UIGraphicsGetCurrentContext()! 401 | connectedLineMaskView.image?.draw(in: self.bounds) 402 | context.saveGState() 403 | 404 | let line = (width: connectLineWidth, color: error ? errorLineColor : connectLineColor) 405 | connect(point: fromPoint, to: toPoint, in: context, with: line) 406 | 407 | connectedLineMaskView.image = UIGraphicsGetImageFromCurrentImageContext() 408 | context.saveGState() 409 | UIGraphicsEndImageContext() 410 | 411 | } 412 | 413 | open func connect(point: CGPoint, to anotherPoint: CGPoint) { 414 | UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, UIScreen.main.scale) 415 | let context = UIGraphicsGetCurrentContext()! 416 | context.saveGState() 417 | let line = (width: connectLineWidth, color: connectLineColor) 418 | connect(point: point, to: anotherPoint, in: context, with: line) 419 | draggedLineMaskView.image = UIGraphicsGetImageFromCurrentImageContext() 420 | context.saveGState() 421 | UIGraphicsEndImageContext() 422 | } 423 | 424 | open func connect(point: CGPoint, to anotherPoint: CGPoint, `in` context: CGContext, with line:(width: CGFloat, color: UIColor)) { 425 | 426 | let lineColor = line.color 427 | let lineWidth = line.width 428 | 429 | context.setLineCap(.round) 430 | context.move(to: point) 431 | context.addLine(to: anotherPoint) 432 | context.setLineWidth(lineWidth) 433 | context.setStrokeColor(lineColor.cgColor) 434 | context.strokePath() 435 | context.saveGState() 436 | } 437 | } 438 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPPasswordPlugin/BuildInViews/HPSimplePasscodeView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /HPPluginRepo/Plugins/HPCalendarExt/BuildInView/HPCalendarView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | HelveticaNeue 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 32 | 43 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 79 | 85 | 91 | 97 | 103 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | --------------------------------------------------------------------------------