├── 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 | [](https://github.com/shuangyu/HPPluginRepo/blob/master/The%20MIT%20License%20(MIT))
4 | 
5 | 
6 | [](https://travis-ci.org/shuangyu/HPPluginRepo)
7 |
8 | Plugins
9 | ==============
10 |
11 | ### Debug Kit(Guide Page not update yet!)
12 | 
13 |
14 | ### Slide Plugin
15 | 
16 |
17 | ### Calendar Plugin
18 | 
19 |
20 | ### Password Plugin
21 | #### Nine Dot View Demo(build on password plugin)
22 | 
23 | #### Simple Passcode View Demo(build on password plugin)
24 | 
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 |
22 |
23 |
24 |
25 |
26 |
27 |
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 | Var. Description
45 |
46 |
47 | description -
48 |
49 |
50 | mainColor background color of floating button and all viewcontrollers' navigation bar initialized by applying method applyADKNavigationBar of UIViewController extension
51 |
52 |
53 | fontColor text color of all texts on build-in viewcontroller's navigation bar
54 |
55 |
56 | floatingButtonSize -
57 |
58 |
59 | floatingButtonText -
60 |
61 |
62 | floationButtonTextColor -
63 |
64 |
65 | floationButtonFontSize -
66 |
67 |
68 |
69 | Descriptions of ADKConfig's parameters
70 |
71 | Default config is ADKDefaultConfig
72 |
73 |
74 | Var. Description
75 |
76 |
77 | storyboardName_phone storyboard file name of iPhone,leave empty if current device is iPad
78 |
79 |
80 | storyboardName_pad storyboard file name of iPad,leave empty if current device is iPhone
81 |
82 |
83 | rootPageConfigFileName config file name of plugin's root viewcontroller
84 |
85 |
86 | settingPageConfigFileName config file name of plugin's setting viewcontroller
87 |
88 |
89 | storyboardName storyboard name of current platform
90 |
91 |
92 | storyboard storyboard instance of current platform
93 |
94 |
95 | rootPageCellReuseID -
96 |
97 |
98 | defaultItems default build-in items, like guideItem and settingItem
99 |
100 |
101 |
102 | Description of root config file
103 |
104 | Demo file : HDKRootConfig.plist
105 |
106 |
107 |
108 |
109 | Field Required Type Comment
110 |
111 |
112 | title true String cell item title
113 |
114 |
115 | segueID false String segue identifier of cell click action in the plugin storyboard
116 |
117 |
118 | controllerName false String full classname of the viewcontroller you want to push without storyboard, like AnwDebugKitDemo.HDKTest2ViewController
119 |
120 |
121 | controllerID false String controller id in the external storyboard
122 |
123 |
124 | controllerContainer false String name of the external storyboard which holds the viewcontroller you want to push
125 |
126 |
127 |
128 | Description of setting config file
129 |
130 | Demo file : HDKSettingConfig.plist
131 |
132 |
133 |
134 | Field Required Type Comment
135 |
136 |
137 | title true String cell item title
138 |
139 |
140 | type true String
141 | one cell type of below:
142 | ADKCellTypeDetail
143 | ADKCellTypeInput
144 | ADKCellTypeSwitch
145 | ADKCellTypePlain
146 | ADKCellTypeAsync
147 |
148 |
149 |
150 | action false String string name of the selector which will response to the cell action
151 |
152 |
153 | defaultValue false String string name of the selector which will response to the cell default value action
154 |
155 |
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 | selector selector name
165 | func testSelector1() -> Any testSelector1
166 | func testSelector2(_ param: Any) -> Any testSelector2:
167 | func testSelector3(with param: Any) -> Any testSelector3With:
168 | func testSelector4(with param1: Any, and param2: Any) -> Any testSelector4With:and:
169 |
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 |
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 |
57 |
58 |
59 |
60 |
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 |
88 |
89 |
90 |
91 |
92 |
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 |
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 |
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 |
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 |
57 |
58 |
59 |
60 |
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 |
88 |
89 |
90 |
91 |
92 |
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 |
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 |
--------------------------------------------------------------------------------