Compare commits

...

90 Commits

Author SHA1 Message Date
Ivan Vorobei 962d1a937d Update to 1.2.2
Add new parametr - `colorIndicator` for change color arrow. Update example & Readme. Fix `SPStorkIndicatorView `
2019-01-31 21:20:53 +03:00
Ivan Vorobei bc6c7ff45e Update README.md 2019-01-31 08:06:47 +03:00
Ivan Vorobei ec7abd4a2a Update example
Update `SparrowKit` pod
2019-01-26 14:01:36 +03:00
Ivan Vorobei 6904e0916a Update UserInterfaceState.xcuserstate 2019-01-21 16:33:48 +03:00
Ivan Vorobei 90ee3d35da Add navigation controller for example 2019-01-21 15:15:54 +03:00
Ivan Vorobei 7f998787a4 Update to 1.2.1 version
Now if set custom height more default value, it aotu change to default value. Update example and pod version.
2019-01-18 13:51:49 +03:00
Ivan Vorobei 618da7d9ea Update README.md 2019-01-18 11:58:08 +03:00
Ivan Vorobei f062d07f94 Add Images 2019-01-15 20:31:03 +03:00
Ivan Vorobei 926e1f643c Add Images 2019-01-15 20:28:19 +03:00
Ivan Vorobei cdd8f4a2f4 Remove images 2019-01-13 14:28:54 +03:00
Ivan Vorobei 30cf10c595 Update README.md 2019-01-13 14:28:10 +03:00
Ivan Vorobei 884791b05c Create youtube3.jpg 2019-01-13 14:27:50 +03:00
Ivan Vorobei 4d0530e0a1 Update README.md 2019-01-13 14:25:42 +03:00
Ivan Vorobei 48741988b2 img 2019-01-13 14:25:20 +03:00
Ivan Vorobei 6297d5a5db Update youtube.jpg 2019-01-13 14:24:45 +03:00
Ivan Vorobei 3f60e48547 Update README.md 2019-01-13 14:23:44 +03:00
Ivan Vorobei 2ffe86afb9 Update youtube.jpg 2019-01-13 14:23:12 +03:00
Ivan Vorobei cf5bf12513 Update README.md 2019-01-13 14:18:03 +03:00
Ivan Vorobei 96aa1a6064 Create youtube.jpg 2019-01-13 14:15:38 +03:00
Ivan Vorobei 3241abd195 Delete SPStorkController-YouTube.jpg 2019-01-02 12:08:27 +03:00
Ivan Vorobei b72f10c7bd Update README.md 2019-01-02 12:08:06 +03:00
Ivan Vorobei 40bcff3cb6 Create SPStorkController-YouTube.jpg 2019-01-02 12:07:19 +03:00
Ivan Vorobei 01cc226253 Update README.md 2019-01-01 22:51:43 +03:00
Ivan Vorobei 691045d012 Update README.md 2019-01-01 22:49:49 +03:00
Ivan Vorobei 59f52f258a Update README.md 2018-12-31 18:50:40 +03:00
Ivan Vorobei bfece3194a Update README.md 2018-12-31 18:49:18 +03:00
Ivan Vorobei 6cccf24ffa Update README.md 2018-12-31 18:47:17 +03:00
Ivan Vorobei 635878e456 Update README.md 2018-12-30 18:55:52 +03:00
Ivan Vorobei d839e0f414 Update README.md 2018-12-30 18:54:01 +03:00
Ivan Vorobei e3cbc318be Update README.md 2018-12-30 18:51:38 +03:00
Ivan Vorobei e4232ec045 Update README.md 2018-12-29 17:31:29 +03:00
Ivan Vorobei 02346c0814 Update README.md 2018-12-28 21:55:13 +03:00
Ivan Vorobei 0b98593954 Update README.md 2018-12-28 21:54:36 +03:00
Ivan Vorobei 518700f9cd Delete spstork-preivew.jpg 2018-12-28 20:53:53 +03:00
Ivan Vorobei 5e02985ef2 Update README.md 2018-12-28 20:33:00 +03:00
Ivan Vorobei 539589e029 Update README.md 2018-12-28 19:50:04 +03:00
Ivan Vorobei 3434c487cd Update README.md 2018-12-28 19:48:53 +03:00
Ivan Vorobei c18e72add2 Update README.md 2018-12-28 19:46:59 +03:00
Ivan Vorobei c5e407fd80 Update README.md 2018-12-28 19:46:16 +03:00
Ivan Vorobei 3937c9caa5 Update README.md 2018-12-28 19:45:34 +03:00
Ivan Vorobei 38332bed39 Update README.md 2018-12-28 19:44:41 +03:00
Ivan Vorobei 40c7eee5de Update README.md 2018-12-28 19:43:48 +03:00
Ivan Vorobei 2e881179ee Update README.md 2018-12-28 19:42:10 +03:00
Ivan Vorobei 749640d359 Add video tutorial 2018-12-28 19:41:29 +03:00
Ivan Vorobei fd68fcb9f5 Update Readme 2018-12-28 18:44:07 +03:00
Ivan Vorobei 473f8ae0f1 Update README.md 2018-12-28 18:43:08 +03:00
Ivan Vorobei 75825b5e0a Update README 2018-12-28 18:42:17 +03:00
Ivan Vorobei f1e053d0d3 Update UserInterfaceState.xcuserstate 2018-12-24 16:49:58 +03:00
Ivan Vorobei 6208c93d40 Update README.md 2018-12-18 21:16:13 +03:00
Ivan Vorobei 8c64cd09da Update README.md 2018-12-18 16:32:23 +03:00
Ivan Vorobei c36078cda2 Update to 1.2
- After tap parrent controller auto dismiss
- Update example
2018-12-17 21:47:26 +03:00
Ivan Vorobei b78c82194f Update README.md 2018-12-17 20:02:13 +03:00
Ivan Vorobei a112473a04 Update Readme.md 2018-12-17 13:40:22 +03:00
Ivan Vorobei c1b135a30a Add example of TableView for SPStorkController
- Upadte example
- Update readme
- Add example table view for SPStorkController
2018-12-14 12:46:33 +03:00
Ivan Vorobei c1a7622a26 Update README.md 2018-12-13 23:29:42 +03:00
Ivan Vorobei c3421432b0 Update README.md 2018-12-13 19:58:12 +03:00
Ivan Vorobei 99353d3610 Update README.md 2018-12-12 17:01:17 +03:00
Ivan Vorobei 3bee6898e0 Update README.md 2018-12-12 16:54:24 +03:00
Ivan Vorobei 587790b1db Merge pull request #11 from jobinsjohn/patch-3
Updated ReadMe
2018-12-12 16:53:21 +03:00
Ivan Vorobei 2698cfe23d Merge pull request #12 from jobinsjohn/patch-4
Updated ReadMe
2018-12-12 16:52:48 +03:00
Jobins John 42b82886ca Updated ReadMe
Fixed typo in read me file
2018-12-12 17:44:46 +04:00
Jobins John 7af77b2596 Updated ReadMe file
Fixed typos
2018-12-12 17:43:36 +04:00
Ivan Vorobei 7c663e7760 Update README.md 2018-12-12 16:36:08 +03:00
Ivan Vorobei f561e94110 Update README.md 2018-12-12 16:35:47 +03:00
Ivan Vorobei 3bf06ae2b3 Update README.md 2018-12-12 16:35:27 +03:00
Ivan Vorobei a6d5e6f97d Merge pull request #10 from jobinsjohn/patch-2
Updated ReadMe
2018-12-12 16:34:35 +03:00
Ivan Vorobei 0f20afb87c Merge pull request #9 from jobinsjohn/patch-1
Updated ReadMe
2018-12-12 16:34:13 +03:00
Jobins John 2368747150 Updated Readme File
Added shields in read me for platform
2018-12-12 17:29:21 +04:00
Jobins John 32a010e1ca Updated ReadMe file
fixed typos and grammar mistakes
2018-12-12 17:23:49 +04:00
Ivan Vorobei fce0efaffa Update example 2018-12-12 16:10:45 +03:00
Ivan Vorobei 1500c272b1 Update to 1.1.8 version
- Fix bugs with paramtrs
- Add paramtr custom height
- Update Readme
2018-12-12 16:04:25 +03:00
Ivan Vorobei ba859e3646 Update README.md 2018-12-12 12:47:52 +03:00
Ivan Vorobei 01b8702c4a Update README.md 2018-12-12 12:46:22 +03:00
Ivan Vorobei ec809ee1c5 Update Readme.md 2018-12-12 12:28:53 +03:00
Ivan Vorobei a5f41ab3d6 Update gif 2018-12-12 12:27:47 +03:00
Ivan Vorobei 58554f1449 Update README.md 2018-12-12 11:43:18 +03:00
Ivan Vorobei 8c1b6e2c8d Add custom height 2018-12-10 21:39:48 +03:00
Ivan Vorobei 724635e387 Update README.md 2018-12-10 21:36:35 +03:00
Ivan Vorobei dfc0fb8e52 Update gif 2018-12-10 21:34:47 +03:00
Ivan Vorobei 50c9ab4104 Create gif-mockup.gif 2018-12-10 21:33:23 +03:00
Ivan Vorobei bb0821d2cc Update README.md 2018-12-07 13:45:03 +03:00
Ivan Vorobei ae29eba5b9 Update README.md 2018-12-07 13:44:30 +03:00
Ivan Vorobei 0c98c3c699 Update to 1.1.6 2018-12-07 13:40:49 +03:00
Ivan Vorobei 4ecc8e96d8 Update Readme.md 2018-12-07 13:40:13 +03:00
Ivan Vorobei fac454f41d remove source 2018-12-07 13:14:31 +03:00
Ivan Vorobei ae68a1be5d Update README.md 2018-12-06 17:33:44 +03:00
Ivan Vorobei c111a20c86 Update README.md 2018-12-06 17:28:05 +03:00
Ivan Vorobei cc1b1ac604 Update SPStorkPresentationController.swift 2018-12-06 17:14:37 +03:00
Ivan Vorobei 265f77dd5e Update README.md 2018-12-06 15:35:02 +03:00
Ivan Vorobei aacf153d0e Update README.md 2018-12-06 15:26:51 +03:00
163 changed files with 3183 additions and 4743 deletions
File diff suppressed because it is too large Load Diff
@@ -7,6 +7,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let navigationController = UINavigationController(rootViewController: Controller())
self.launch(rootViewController: navigationController)
return true
}
@@ -32,6 +36,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
func launch(rootViewController: UIViewController) {
let frame = UIScreen.main.bounds
self.window = UIWindow(frame: frame)
self.window!.rootViewController = rootViewController
self.window!.makeKeyAndVisible()
}
}
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
+43
View File
@@ -0,0 +1,43 @@
import UIKit
class Controller: UIViewController {
var presentControllerButton = UIButton.init(type: UIButton.ButtonType.system)
var presentTableControllerButton = UIButton.init(type: UIButton.ButtonType.system)
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
self.presentControllerButton.setTitle("Show ViewController", for: .normal)
self.presentControllerButton.addTarget(self, action: #selector(self.presentModalViewController), for: .touchUpInside)
self.presentControllerButton.sizeToFit()
self.presentControllerButton.center.x = self.view.frame.width / 2
self.presentControllerButton.center.y = self.view.frame.height / 4 * 3
self.view.addSubview(self.presentControllerButton)
self.presentTableControllerButton.setTitle("Show TableController", for: .normal)
self.presentTableControllerButton.addTarget(self, action: #selector(self.presentModalTableViewController), for: .touchUpInside)
self.presentTableControllerButton.sizeToFit()
self.presentTableControllerButton.center.x = self.view.frame.width / 2
self.presentTableControllerButton.frame.origin.y = self.presentControllerButton.frame.bottomYPosition + 10
self.view.addSubview(self.presentTableControllerButton)
}
@objc func presentModalViewController() {
let modal = ModalViewController()
let transitionDelegate = SPStorkTransitioningDelegate()
modal.transitioningDelegate = transitionDelegate
modal.modalPresentationStyle = .custom
self.present(modal, animated: true, completion: nil)
}
@objc func presentModalTableViewController() {
let modal = ModalTableViewController()
let transitionDelegate = SPStorkTransitioningDelegate()
modal.transitioningDelegate = transitionDelegate
modal.modalPresentationStyle = .custom
self.present(modal, animated: true, completion: nil)
}
}
@@ -41,6 +41,18 @@ public struct SPStorkController {
}
}
static public func updatePresentingController(parent controller: UIViewController) {
if let presentationController = controller.presentedViewController?.presentationController as? SPStorkPresentationController {
presentationController.updatePresentingController()
}
}
static public func updatePresentingController(modal controller: UIViewController) {
if let presentationController = controller.presentationController as? SPStorkPresentationController {
presentationController.updatePresentingController()
}
}
static private func controller(for view: UIView) -> UIViewController? {
var nextResponder = view.next
while nextResponder != nil && !(nextResponder! is UIViewController) {
@@ -42,6 +42,13 @@ class SPStorkIndicatorView: UIView {
}
}
var color: UIColor = UIColor.init(red: 202/255, green: 201/255, blue: 207/255, alpha: 1) {
didSet {
self.leftView.backgroundColor = self.color
self.rightView.backgroundColor = self.color
}
}
private var leftView: UIView = UIView()
private var rightView: UIView = UIView()
@@ -50,8 +57,7 @@ class SPStorkIndicatorView: UIView {
self.backgroundColor = UIColor.clear
self.addSubview(self.leftView)
self.addSubview(self.rightView)
self.leftView.backgroundColor = UIColor.init(red: 202/255, green: 201/255, blue: 207/255, alpha: 1)
self.rightView.backgroundColor = UIColor.init(red: 202/255, green: 201/255, blue: 207/255, alpha: 1)
self.color = UIColor.init(red: 202/255, green: 201/255, blue: 207/255, alpha: 1)
}
required init?(coder aDecoder: NSCoder) {
@@ -24,9 +24,14 @@ import UIKit
class SPStorkPresentationController: UIPresentationController, UIGestureRecognizerDelegate {
var isSwipeToDismissEnabled: Bool = true
var isTapAroundToDismissEnabled: Bool = true
var showIndicator: Bool = true
var indicatorColor: UIColor = UIColor.init(red: 202/255, green: 201/255, blue: 207/255, alpha: 1)
var customHeight: CGFloat? = nil
var transitioningDelegate: SPStorkTransitioningDelegate?
var pan: UIPanGestureRecognizer?
var tap: UITapGestureRecognizer?
private var indicatorView = SPStorkIndicatorView()
private var gradeView: UIView = UIView()
@@ -55,13 +60,20 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
private var scaleForPresentingView: CGFloat {
guard let containerView = containerView else { return 0 }
let factor = 1 - (topSpace * 2 / containerView.frame.height)
let factor = 1 - (self.topSpace * 2 / containerView.frame.height)
return factor
}
override var frameOfPresentedViewInContainerView: CGRect {
guard let containerView = containerView else { return .zero }
let yOffset: CGFloat = topSpace + 13
var customHeight = self.customHeight ?? containerView.bounds.height
if customHeight > containerView.bounds.height {
customHeight = containerView.bounds.height
print("SPStorkController - Custom height change to default value. Your height more maximum value")
}
let additionTranslate = containerView.bounds.height - customHeight
let yOffset: CGFloat = self.topSpace + 13 + additionTranslate
return CGRect(x: 0, y: yOffset, width: containerView.bounds.width, height: containerView.bounds.height - yOffset)
}
@@ -71,6 +83,7 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
guard let containerView = self.containerView, let presentedView = self.presentedView, let window = containerView.window else { return }
if self.showIndicator {
self.indicatorView.color = self.indicatorColor
presentedView.addSubview(self.indicatorView)
}
self.updateLayoutIndicator()
@@ -82,6 +95,7 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
containerView.insertSubview(self.snapshotViewContainer, belowSubview: presentedViewController.view)
self.snapshotViewContainer.frame = initialFrame
self.updateSnapshot()
self.snapshotView?.layer.cornerRadius = 0
self.backgroundView.backgroundColor = UIColor.black
self.backgroundView.translatesAutoresizingMaskIntoConstraints = false
containerView.insertSubview(self.backgroundView, belowSubview: self.snapshotViewContainer)
@@ -145,14 +159,21 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
override func presentationTransitionDidEnd(_ completed: Bool) {
super.presentationTransitionDidEnd(completed)
guard let containerView = containerView else { return }
self.updateSnapshot()
self.presentedViewController.view.frame = self.frameOfPresentedViewInContainerView
self.snapshotViewContainer.transform = .identity
self.snapshotViewContainer.translatesAutoresizingMaskIntoConstraints = false
self.snapshotViewContainer.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
self.updateSnapshotAspectRatio()
if self.isTapAroundToDismissEnabled {
self.tap = UITapGestureRecognizer.init(target: self, action: #selector(self.handleTap))
self.tap?.cancelsTouchesInView = false
self.snapshotViewContainer.addGestureRecognizer(self.tap!)
}
if self.isSwipeToDismissEnabled {
self.pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan))
self.pan = UIPanGestureRecognizer(target: self, action: #selector(self.handlePan))
self.pan!.delegate = self
self.pan!.maximumNumberOfTouches = 1
self.pan!.cancelsTouchesInView = false
@@ -160,6 +181,10 @@ class SPStorkPresentationController: UIPresentationController, UIGestureRecogniz
}
}
@objc func handleTap() {
self.presentedViewController.dismiss(animated: true, completion: nil)
}
override func dismissalTransitionWillBegin() {
super.dismissalTransitionWillBegin()
guard let containerView = containerView else { return }
@@ -245,6 +270,8 @@ extension SPStorkPresentationController {
self.workGester = true
self.indicatorView.style = .line
self.presentingViewController.view.layer.removeAllAnimations()
self.presentingViewController.view.endEditing(true)
self.presentedViewController.view.endEditing(true)
gestureRecognizer.setTranslation(CGPoint(x: 0, y: 0), in: containerView)
case .changed:
self.workGester = true
@@ -270,6 +297,7 @@ extension SPStorkPresentationController {
animations: {
self.snapshotView?.transform = .identity
self.presentedView?.transform = .identity
self.gradeView.alpha = self.alpha
})
}
default:
@@ -283,12 +311,17 @@ extension SPStorkPresentationController {
}
}
func updatePresentingController() {
if self.startDismissing { return }
self.updateSnapshot()
}
private func updatePresentedViewForTranslation(inVerticalDirection translation: CGFloat) {
if self.startDismissing { return }
let elasticThreshold: CGFloat = 120
let translationFactor: CGFloat = 1 / 2
if translation >= 0 {
let translationForModal: CGFloat = {
if translation >= elasticThreshold {
@@ -302,11 +335,9 @@ extension SPStorkPresentationController {
self.presentedView?.transform = CGAffineTransform(translationX: 0, y: translationForModal)
if !self.presentingViewController.isPresentedAsStork {
let factor = 1 + (translationForModal / 6000)
self.snapshotView?.transform = CGAffineTransform.init(scaleX: factor, y: factor)
self.gradeView.alpha = self.alpha - ((factor - 1) * 15)
}
let factor = 1 + (translationForModal / 6000)
self.snapshotView?.transform = CGAffineTransform.init(scaleX: factor, y: factor)
self.gradeView.alpha = self.alpha - ((factor - 1) * 15)
}
}
}
@@ -349,6 +380,11 @@ extension SPStorkPresentationController {
self.snapshotViewContainer.addSubview(currentSnapshotView)
self.constraints(view: currentSnapshotView, to: self.snapshotViewContainer)
self.snapshotView = currentSnapshotView
self.snapshotView?.layer.cornerRadius = self.cornerRadius
self.snapshotView?.layer.masksToBounds = true
if #available(iOS 11.0, *) {
snapshotView?.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
}
self.gradeView.removeFromSuperview()
self.gradeView.backgroundColor = UIColor.black
self.snapshotView!.addSubview(self.gradeView)
@@ -24,10 +24,18 @@ import UIKit
public final class SPStorkTransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
public var isSwipeToDismissEnabled: Bool = true
public var isTapAroundToDismissEnabled: Bool = true
public var showIndicator: Bool = true
public var indicatorColor: UIColor = UIColor.init(red: 202/255, green: 201/255, blue: 207/255, alpha: 1)
public var customHeight: CGFloat? = nil
public func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
let controller = SPStorkPresentationController(presentedViewController: presented, presenting: presenting)
controller.isSwipeToDismissEnabled = self.isSwipeToDismissEnabled
controller.isTapAroundToDismissEnabled = self.isTapAroundToDismissEnabled
controller.showIndicator = self.showIndicator
controller.indicatorColor = self.indicatorColor
controller.customHeight = self.customHeight
controller.transitioningDelegate = self
return controller
}
@@ -1,91 +0,0 @@
// The MIT License (MIT)
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
class SPImagesLineCollectionView: SPCollectionView {
fileprivate let imageCellIdentificator: String = "imageCellIdentificator"
var links: [String] = []
var images: [UIImage] = []
var mode: Mode = .links {
didSet {
self.reloadData()
}
}
override init() {
super.init()
self.layout.scrollDirection = .horizontal
self.dataSource = self
self.register(SPImageCollectionViewCell.self, forCellWithReuseIdentifier: self.imageCellIdentificator)
self.layout.cellSideRatio = 1
self.layout.heightFactor = 1
self.layout.minItemSpace = 10
self.layout.maxItemSpace = 10
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
enum Mode {
case links
case images
}
}
extension SPImagesLineCollectionView: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch self.mode {
case .links:
return self.links.count
case .images:
return self.images.count
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = dequeueReusableCell(withReuseIdentifier: self.imageCellIdentificator, for: indexPath) as! SPImageCollectionViewCell
switch self.mode {
case .links:
let link = self.links[indexPath.row]
if let image = self.fromCahce(link: link) {
cell.view.setImage(image: image, animatable: false)
} else {
cell.view.setImage(link: link) { (image) in
self.toCache(link: link, image: image)
}
}
case .images:
cell.view.setImage(image: self.images[indexPath.row], animatable: false)
}
return cell
}
}
@@ -1,155 +0,0 @@
// The MIT License (MIT)
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
class SPCollectionImagesTableViewCell: SPTableViewCell {
let titleLabel = UILabel()
let subtitleLabel = UILabel()
let collectionView = SPImagesLineCollectionView()
var topSpace: CGFloat = 11 {
didSet {
self.titleLabelTopConstraint.constant = self.topSpace
self.updateConstraints()
}
}
var collectionHeight: CGFloat = 63 {
didSet {
self.collectionHeightConstraint.constant = self.collectionHeight
self.updateConstraints()
}
}
//constraints
private var collectionTopConstraint: NSLayoutConstraint!
private var collectionHeightConstraint: NSLayoutConstraint!
private var titleLabelTopConstraint: NSLayoutConstraint!
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.commonInit()
}
private func commonInit() {
let marginGuide = contentView.layoutMarginsGuide
self.titleLabel.numberOfLines = 0
self.titleLabel.font = UIFont.system(type: UIFont.BoldType.Medium, size: 21)
self.titleLabel.textAlignment = .left
self.titleLabel.textColor = UIColor.black
self.contentView.addSubview(self.titleLabel)
self.titleLabel.translatesAutoresizingMaskIntoConstraints = false
self.titleLabel.leadingAnchor.constraint(equalTo:
marginGuide.leadingAnchor, constant: 0).isActive = true
self.titleLabel.trailingAnchor.constraint(equalTo:
marginGuide.trailingAnchor).isActive = true
self.titleLabelTopConstraint = self.titleLabel.topAnchor.constraint(equalTo:
marginGuide.topAnchor, constant: 0)
self.titleLabelTopConstraint.isActive = true
self.subtitleLabel.numberOfLines = 3
self.subtitleLabel.font = UIFont.system(type: UIFont.BoldType.Regular, size: 15)
self.subtitleLabel.textAlignment = .left
self.subtitleLabel.textColor = SPNativeStyleKit.Colors.gray
self.contentView.addSubview(self.subtitleLabel)
self.subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
self.subtitleLabel.leadingAnchor.constraint(equalTo:
self.titleLabel.leadingAnchor).isActive = true
self.subtitleLabel.trailingAnchor.constraint(equalTo:
marginGuide.trailingAnchor).isActive = true
self.subtitleLabel.topAnchor.constraint(equalTo:
titleLabel.bottomAnchor, constant: 3).isActive = true
self.collectionView.backgroundColor = UIColor.clear
self.collectionView.showsHorizontalScrollIndicator = false
self.collectionView.translatesAutoresizingMaskIntoConstraints = false
self.contentView.addSubview(self.collectionView)
self.collectionView.leadingAnchor.constraint(equalTo:
self.leadingAnchor).isActive = true
self.collectionView.trailingAnchor.constraint(equalTo:
self.trailingAnchor).isActive = true
self.collectionHeightConstraint = self.collectionView.heightAnchor.constraint(equalToConstant: 63)
self.collectionHeightConstraint.isActive = true
self.collectionTopConstraint = self.collectionView.topAnchor.constraint(equalTo:
subtitleLabel.bottomAnchor, constant: 10)
self.collectionTopConstraint.isActive = true
self.collectionView.bottomAnchor.constraint(equalTo:
marginGuide.bottomAnchor, constant: -7).isActive = true
}
override func prepareForReuse() {
super.prepareForReuse()
self.collectionView.reloadData()
self.accessoryType = .none
}
override func layoutSubviews() {
super.layoutSubviews()
self.collectionView.contentInset.left = self.contentView.layoutMargins.left
self.collectionView.contentInset.right = self.contentView.layoutMargins.right
self.accessoryView?.center.y = self.titleLabel.frame.bottomYPosition + self.subtitleLabel.frame.height / 2
if self.accessoryView?.frame.origin.y ?? 0 < 5 {
self.accessoryView?.center.y = self.frame.height / 2
}
}
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
var backgroundColor = SPNativeStyleKit.Colors.customGray
if let cell = self.collectionView.cellForItem(at: IndexPath.init(row: 0, section: 0)) as? SPImageCollectionViewCell {
if let color = cell.view.gradeView.backgroundColor {
backgroundColor = color
}
}
super.setHighlighted(highlighted, animated: animated)
for cell in self.collectionView.visibleCells {
if let imageCell = cell as? SPImageCollectionViewCell {
imageCell.view.gradeView.backgroundColor = backgroundColor
}
}
}
override func setSelected(_ selected: Bool, animated: Bool) {
var backgroundColor = SPNativeStyleKit.Colors.customGray
if let cell = self.collectionView.cellForItem(at: IndexPath.init(row: 0, section: 0)) as? SPImageCollectionViewCell {
if let color = cell.view.gradeView.backgroundColor {
backgroundColor = color
}
}
super.setSelected(selected, animated: animated)
for cell in self.collectionView.visibleCells {
if let imageCell = cell as? SPImageCollectionViewCell {
imageCell.view.gradeView.backgroundColor = backgroundColor
}
}
}
}
@@ -20,6 +20,7 @@
// SOFTWARE.
import UIKit
import StoreKit
struct SPApp {
@@ -56,5 +57,12 @@ struct SPApp {
}
}
static func set(elementsColor: UIColor) {
UINavigationController.elementsColor = elementsColor
UIAlertController.elementsColor = elementsColor
UITabBarController.elementsColor = elementsColor
UITabBar.appearance().tintColor = elementsColor
}
private init() {}
}
@@ -21,25 +21,24 @@
import UIKit
struct SPLaunch {
extension SPApp {
static func run() {
self.count += 1
}
static var count: Int {
get {
return UserDefaults.standard.value(forKey: "SPLaunchCount") as? Int ?? 0
public struct Badge {
static var number: Int {
get {
return UIApplication.shared.applicationIconBadgeNumber
}
set {
UIApplication.shared.applicationIconBadgeNumber = newValue
}
}
set {
UserDefaults.standard.set(newValue, forKey: "SPLaunchCount")
static func reset() {
UIApplication.shared.applicationIconBadgeNumber = 0
}
private init() {}
}
static var isFirstOpen: Bool {
return (self.count == 1) || (self.count == 0)
}
private init() {}
}
@@ -21,22 +21,27 @@
import UIKit
class SPImageCollectionViewCell: SPCollectionContainerCell<SPDownloadingImageView> {
extension SPApp {
override init(frame: CGRect) {
super.init(frame: frame)
self.view.layer.cornerRadius = 10
self.view.contentMode = .scaleAspectFill
self.view.setNative()
}
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepareForReuse() {
super.prepareForReuse()
self.view.contentMode = .scaleAspectFill
self.view.startLoading()
struct Launch {
static func run() {
self.count += 1
}
static var count: Int {
get {
return UserDefaults.standard.value(forKey: "SPLaunchCount") as? Int ?? 0
}
set {
UserDefaults.standard.set(newValue, forKey: "SPLaunchCount")
}
}
static var isFirstLaunch: Bool {
return (self.count == 1) || (self.count == 0)
}
private init() {}
}
}
@@ -0,0 +1,86 @@
// The MIT License (MIT)
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
import SafariServices
extension SPApp {
static func open(app: SPSystemApp) {
switch app {
case SPSystemApp.photos:
guard let settingsUrl = URL(string: "photos-redirect://") else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
if #available(iOS 10.0, *) {
UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
print("SPApp - Photos opened: \(success)")
})
} else {
UIApplication.shared.openURL(settingsUrl as URL)
}
} else {
print("SPApp - Photos not opened")
}
case SPSystemApp.setting:
DispatchQueue.main.async {
guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
return
}
if UIApplication.shared.canOpenURL(settingsUrl) {
if #available(iOS 10.0, *) {
UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
print("SPApp - Settings opened: \(success)")
})
} else {
UIApplication.shared.openURL(settingsUrl as URL)
}
} else {
print("SPApp - Settings not opened")
}
}
}
}
static func open(link: String, redirect: Bool) {
guard let url = URL(string: link) else {
print("SPOpener - can not create URL")
return
}
if redirect {
UIApplication.shared.open(url, options: convertToUIApplicationOpenExternalURLOptionsKeyDictionary([:]), completionHandler: nil)
} else {
if let rootController = SPApp.rootController {
let safariController = SFSafariViewController.init(url: url)
rootController.present(safariController, animated: true, completion: nil)
}
}
}
}
fileprivate func convertToUIApplicationOpenExternalURLOptionsKeyDictionary(_ input: [String: Any]) -> [UIApplication.OpenExternalURLOptionsKey: Any] {
return Dictionary(uniqueKeysWithValues: input.map { key, value in (UIApplication.OpenExternalURLOptionsKey(rawValue: key), value)})
}
@@ -56,6 +56,12 @@ struct SPAppStore {
}
}
static func requestReview() {
if #available(iOS 10.3, *) {
SKStoreReviewController.requestReview()
}
}
static func isUpdateAvailable(completion: @escaping (Bool)->()) {
guard let info = Bundle.main.infoDictionary,
@@ -128,7 +134,6 @@ extension String {
}
}
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertToUIApplicationOpenExternalURLOptionsKeyDictionary(_ input: [String: Any]) -> [UIApplication.OpenExternalURLOptionsKey: Any] {
return Dictionary(uniqueKeysWithValues: input.map { key, value in (UIApplication.OpenExternalURLOptionsKey(rawValue: key), value)})
}
@@ -36,7 +36,6 @@ public struct SPAudio {
private init() {}
}
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertFromAVAudioSessionCategory(_ input: AVAudioSession.Category) -> String {
return input.rawValue
}
@@ -21,4 +21,4 @@
import UIKit
struct SPCodeDraw { private init(){} }
struct SPCodeDraw { private init() {} }
@@ -23,15 +23,19 @@ import UIKit
public struct SPConstraints {
static func setEqualSize(_ view: UIView, superVuew: UIView) {
view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
view.topAnchor.constraint(equalTo: superVuew.topAnchor),
view.leftAnchor.constraint(equalTo: superVuew.leftAnchor),
view.rightAnchor.constraint(equalTo: superVuew.rightAnchor),
view.bottomAnchor.constraint(equalTo: superVuew.bottomAnchor)
])
static func setEqualSizeSuperview(for view: UIView) {
if let superView = view.superview {
view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
view.topAnchor.constraint(equalTo: superView.topAnchor),
view.leftAnchor.constraint(equalTo: superView.leftAnchor),
view.rightAnchor.constraint(equalTo: superView.rightAnchor),
view.bottomAnchor.constraint(equalTo: superView.bottomAnchor)
])
}
}
private init() {}
}
@@ -23,11 +23,11 @@ import UIKit
struct SPDevice {
static var isIphone: Bool {
static var iphone: Bool {
return UIDevice.current.userInterfaceIdiom == .phone
}
static var isIpad: Bool {
static var ipad: Bool {
return UIDevice.current.userInterfaceIdiom == .pad
}
@@ -30,6 +30,7 @@ struct SPDownloader {
}
return
}
URLSession.shared.dataTask(with: url) { (data, response, error) in
guard
let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200,
@@ -47,6 +48,8 @@ struct SPDownloader {
}
}.resume()
}
private init() {}
}
@@ -19,22 +19,20 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
import Foundation
public struct SPBadge {
extension Date {
static func reset() {
UIApplication.shared.applicationIconBadgeNumber = 0
func format(mask: String) -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = mask
return dateFormatter.string(from: self)
}
static var number: Int {
get {
return UIApplication.shared.applicationIconBadgeNumber
}
set {
UIApplication.shared.applicationIconBadgeNumber = newValue
}
static func create(from value: String) -> Date? {
let formatter = DateFormatter()
formatter.dateFormat = "dd.MM.yyyy HH:mm"
let date = formatter.date(from: value)
return date
}
private init() {}
}
@@ -24,6 +24,10 @@ import UIKit
extension String {
var digits: String {
return components(separatedBy: CharacterSet.decimalDigits.inverted).joined()
}
mutating func dropLast(substring: String) {
if self.hasSuffix(substring) {
self = String(dropLast(substring.count))
@@ -69,4 +73,8 @@ extension String {
mutating func replace(_ replacingString: String, with newString: String) {
self = self.replacingOccurrences(of: replacingString, with: newString)
}
func replace(_ replacingString: String, with newString: String) -> String {
return self.replacingOccurrences(of: replacingString, with: newString)
}
}
@@ -98,11 +98,11 @@ extension UIButton {
}
func setAnimatableText(_ text: String, withComplection completion: (() -> Void)! = {}) {
SPAnimation.animate(0.2, animations: {
SPAnimation.animate(0.3, animations: {
self.titleLabel?.alpha = 0
}, withComplection: {
self.setTitle(text, for: .normal)
SPAnimation.animate(0.2, animations: {
SPAnimation.animate(0.3, animations: {
self.titleLabel?.alpha = 1
}, withComplection: {
completion()
@@ -23,55 +23,10 @@ import UIKit
public extension UIFont {
public struct fonts {
public static func AvenirNext(type: BoldType, size: CGFloat) -> UIFont {
return UIFont.createFont(.AvenirNext, boldType: type, size: size)
}
}
public static func system(type: BoldType, size: CGFloat) -> UIFont {
if #available(iOS 8.2, *) {
return UIFont.systemFont(ofSize: size, weight: self.getBoldTypeBy(boldType: type))
} else {
return self.createFont(.AvenirNext, boldType: type, size: size)
}
return UIFont.systemFont(ofSize: size, weight: self.getBoldTypeBy(boldType: type))
}
public static func createFont(_ fontType: FontType, boldType: BoldType, size: CGFloat) -> UIFont {
return UIFont.init(
name: self.getFontNameBy(fontType: fontType) + self.getBoldTypeNameBy(boldType: boldType),
size: size
)!
}
private static func getFontNameBy(fontType: FontType) -> String {
switch fontType {
case .AvenirNext:
return "AvenirNext"
}
}
private static func getBoldTypeNameBy(boldType: BoldType) -> String {
switch boldType {
case .UltraLight:
return "-UltraLight"
case .Light:
return "-Light"
case .Medium:
return "-Medium"
case .Regular:
return "-Regular"
case .Bold:
return "-Bold"
case .DemiBold:
return "-DemiBold"
default:
return "-Regular"
}
}
@available(iOS 8.2, *)
private static func getBoldTypeBy(boldType: BoldType) -> UIFont.Weight {
switch boldType {
@@ -94,10 +49,6 @@ public extension UIFont {
}
}
public enum FontType {
case AvenirNext
}
public enum BoldType {
case Regular
case Medium
@@ -25,7 +25,7 @@ extension UIImageView {
public func setNative() {
self.layer.borderWidth = 0.5
self.layer.borderColor = SPNativeStyleKit.Colors.midGray.cgColor
self.layer.borderColor = SPNativeColors.midGray.cgColor
self.layer.masksToBounds = true
}
@@ -53,4 +53,25 @@ public extension UILabel {
attributedText = NSAttributedString(string: textString, attributes: attrs)
}
}
func setLineSpacing(lineSpacing: CGFloat = 0.0, lineHeightMultiple: CGFloat = 0.0) {
guard let labelText = self.text else { return }
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = lineSpacing
paragraphStyle.lineHeightMultiple = lineHeightMultiple
let attributedString:NSMutableAttributedString
if let labelattributedText = self.attributedText {
attributedString = NSMutableAttributedString(attributedString: labelattributedText)
} else {
attributedString = NSMutableAttributedString(string: labelText)
}
attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value:paragraphStyle, range:NSMakeRange(0, attributedString.length))
self.attributedText = attributedString
}
}
@@ -28,7 +28,7 @@ extension UINavigationController {
if UINavigationBar.appearance().tintColor != nil {
return UINavigationBar.appearance().tintColor
} else {
return SPNativeStyleKit.Colors.blue
return SPNativeColors.blue
}
}
set {
@@ -23,6 +23,19 @@ import UIKit
extension UITabBarController {
static var elementsColor: UIColor {
get {
if UITabBar.appearance().tintColor != nil {
return UITabBar.appearance().tintColor
} else {
return SPNativeColors.blue
}
}
set {
UINavigationBar.appearance().tintColor = newValue
}
}
func addTabBarItem(title: String, image: UIImage, selectedImage: UIImage? = nil, controller: UIViewController) {
let tabBarItem = UITabBarItem(
@@ -33,7 +33,7 @@ extension UITableViewCell {
}
set {
let backgroundView = UIView()
backgroundView.backgroundColor = SPNativeStyleKit.Colors.customGray
backgroundView.backgroundColor = SPNativeColors.customGray
self.selectedBackgroundView = backgroundView
}
}
@@ -24,15 +24,15 @@ import Photos
extension UIViewController {
func present(_ viewControllerToPresent: UIViewController, completion: (() -> Swift.Void)? = nil) {
public func present(_ viewControllerToPresent: UIViewController, completion: (() -> Swift.Void)? = nil) {
self.present(viewControllerToPresent, animated: true, completion: completion)
}
@objc func dismiss() {
@objc public func dismiss() {
self.dismiss(animated: true, completion: nil)
}
func wrapToNavigationController(statusBar: SPStatusBar = .dark) -> UINavigationController {
public func wrapToNavigationController(statusBar: SPStatusBar = .dark) -> UINavigationController {
let controller = SPStatusBarManagerNavigationController(rootViewController: self)
controller.statusBar = statusBar
return controller
@@ -41,30 +41,28 @@ extension UIViewController {
extension UIViewController {
func dismissKeyboardWhenTappedAround() {
public func dismissKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
@objc func dismissKeyboard() {
@objc public func dismissKeyboard() {
view.endEditing(true)
}
}
extension UIViewController {
func save(image: UIImage) {
if SPPermission.isAllow(.photoLibrary) {
public func save(image: UIImage) {
if PHPhotoLibrary.authorizationStatus() == PHAuthorizationStatus.authorized {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(self.image(_:didFinishSavingWithError:contextInfo:)), nil)
} else {
SPPermission.request(.photoLibrary) {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(self.image(_:didFinishSavingWithError:contextInfo:)), nil)
}
print("Saving image error. Not allowed permission")
}
}
func saveVideo(url: String, complection: @escaping (Bool)->()) {
public func saveVideo(url: String, complection: @escaping (Bool)->()) {
DispatchQueue.global(qos: .utility).async {
let urls = URL(string: url)
let urldata = try? Data(contentsOf: urls!)
@@ -121,7 +119,7 @@ extension UIViewController {
}
}
func setNavigationTitle(_ title: String, style: SPNavigationTitleStyle) {
public func setNavigationTitle(_ title: String, style: SPNavigationTitleStyle) {
self.navigationItem.title = title
switch style {
case .large:
@@ -143,7 +141,7 @@ extension UIViewController {
extension UIViewController {
var safeArea: UIEdgeInsets {
public var safeArea: UIEdgeInsets {
if #available(iOS 11.0, *) {
return self.view.safeAreaInsets
} else {
@@ -151,18 +149,18 @@ extension UIViewController {
}
}
var navigationBarHeight: CGFloat {
public var navigationBarHeight: CGFloat {
return self.navigationController?.navigationBar.frame.height ?? 0
}
static var statusBarHeight: CGFloat {
public static var statusBarHeight: CGFloat {
return UIApplication.shared.statusBarFrame.height
}
}
extension UIViewController {
var navigationTitleColor: UIColor? {
public var navigationTitleColor: UIColor? {
get {
return (self.navigationController?.navigationBar.titleTextAttributes?[NSAttributedString.Key.foregroundColor] as? UIColor) ?? nil
}
@@ -34,20 +34,17 @@ public extension UIView {
public extension UIView {
var topSafeArea: CGFloat {
var topSafeArea: CGFloat = 0
var safeArea: UIEdgeInsets {
if #available(iOS 11.0, *) {
topSafeArea = self.safeAreaInsets.top
return self.safeAreaInsets
} else{
return UIEdgeInsets.zero
}
return topSafeArea
}
var bottomSafeArea: CGFloat {
var bottomSafeArea: CGFloat = 0
if #available(iOS 11.0, *) {
bottomSafeArea = self.safeAreaInsets.bottom
}
return bottomSafeArea
func set(width: CGFloat, height: CGFloat) {
self.setHeight(height)
self.setWidth(width)
}
func setHeight(_ height: CGFloat) {
@@ -82,10 +79,10 @@ public extension UIView {
if self.superview == nil { return }
self.frame = CGRect.init(origin: CGPoint.zero, size: self.superview!.frame.size)
if customWidth != nil {
self.frame = CGRect.init(origin: CGPoint.zero, size: CGSize.init(width: customWidth!, height: self.frame.height))
self.frame = CGRect.init(origin: CGPoint.zero, size: CGSize.init(width: customWidth!, height: self.superview!.frame.height))
}
if customHeight != nil {
self.frame = CGRect.init(origin: CGPoint.zero, size: CGSize.init(width: self.frame.width, height: customHeight!))
self.frame = CGRect.init(origin: CGPoint.zero, size: CGSize.init(width: self.superview!.frame.width, height: customHeight!))
}
}
@@ -153,7 +150,7 @@ public extension UIView {
let gradeView = UIView.init()
gradeView.alpha = 0
self.addSubview(gradeView)
SPConstraints.setEqualSize(gradeView, superVuew: self)
SPConstraints.setEqualSizeSuperview(for: gradeView)
gradeView.alpha = alpha
gradeView.backgroundColor = color
return gradeView
@@ -21,22 +21,34 @@
import UIKit
class SPLayout {
struct SPLayout {
static func sizeWith(widthFactor: CGFloat, maxWidth: CGFloat, heightFactor: CGFloat, maxHeight: CGFloat, relativeSideFactor: CGFloat, from relativeSize: CGSize) -> CGSize {
static func sizeWith(widthFactor: CGFloat, maxWidth: CGFloat?, heightFactor: CGFloat, maxHeight: CGFloat?, relativeSideFactor: CGFloat?, from size: CGSize) -> CGSize {
var widthArea = relativeSize.width * widthFactor
var heightArea = relativeSize.height * heightFactor
var widthArea = size.width * widthFactor
var heightArea = size.height * heightFactor
widthArea.setIfMore(when: maxWidth)
heightArea.setIfMore(when: maxHeight)
if let maxWidth = maxWidth {
widthArea.setIfMore(when: maxWidth)
}
if let maxHeight = maxHeight {
heightArea.setIfMore(when: maxHeight)
}
var prepareWidth = widthArea
var prepareHeight = widthArea / relativeSideFactor
if prepareHeight > heightArea {
prepareHeight = heightArea
prepareWidth = heightArea * relativeSideFactor
var prepareHeight = heightArea
if let relativeSideFactor = relativeSideFactor {
prepareHeight = widthArea / relativeSideFactor
if prepareHeight > heightArea {
prepareHeight = heightArea
prepareWidth = heightArea * relativeSideFactor
}
}
return CGSize.init(width: prepareWidth, height: prepareHeight)
}
private init() {}
}
@@ -0,0 +1,60 @@
// The MIT License (MIT)
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
import LocalAuthentication
struct SPLocalAuthentication {
static var isEnable: Bool {
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
return true
} else {
if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {
return true
} else {
return false
}
}
}
static func request(reason: String, complecton: @escaping (Bool)->()) {
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason) { success, error in
DispatchQueue.main.async { complecton(success) }
}
} else {
if context.canEvaluatePolicy(.deviceOwnerAuthentication, error: &error) {
context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason) { success, error in
DispatchQueue.main.async { complecton(success) }
}
} else {
complecton(false)
}
}
}
private init() {}
}
@@ -28,7 +28,7 @@ struct SPMail {
return MFMailComposeViewController.canSendMail()
}
static func openMailApp(to email: String, subject: String? = nil, body: String? = nil) {
static func openApp(to email: String, subject: String? = nil, body: String? = nil) {
let parametrs = "mailto:\(email)?subject=\(subject ?? "")&body=\(body ?? "")".addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
if parametrs != nil {
@@ -40,7 +40,7 @@ struct SPMail {
}
}
static func mailDialog(to email: String, subject: String? = nil, body: String? = nil, on viewController: UIViewController) {
static func dialog(to email: String, subject: String? = nil, body: String? = nil, on viewController: UIViewController) {
let mailVC = MFMailComposeViewController()
mailVC.mailComposeDelegate = SPMailSingltone.sharedInstance
@@ -69,7 +69,6 @@ struct SPMail {
private init() {}
}
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertToUIApplicationOpenExternalURLOptionsKeyDictionary(_ input: [String: Any]) -> [UIApplication.OpenExternalURLOptionsKey: Any] {
return Dictionary(uniqueKeysWithValues: input.map { key, value in (UIApplication.OpenExternalURLOptionsKey(rawValue: key), value)})
}
@@ -0,0 +1,41 @@
// The MIT License (MIT)
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
enum SPNativeColors {
static let red = UIColor.init(hex: "FF3B30")
static let orange = UIColor.init(hex: "FF9500")
static let yellow = UIColor.init(hex: "FFCC00")
static let green = UIColor.init(hex: "4CD964")
static let tealBlue = UIColor.init(hex: "5AC8FA")
static let blue = UIColor.init(hex: "007AFF")
static let purple = UIColor.init(hex: "5856D6")
static let pink = UIColor.init(hex: "FF2D55")
static let white = UIColor.init(hex: "FFFFFF")
static let customGray = UIColor.init(hex: "EFEFF4")
static let lightGray = UIColor.init(hex: "E5E5EA")
static let lightGray2 = UIColor.init(hex: "D1D1D6")
static let midGray = UIColor.init(hex: "C7C7CC")
static let gray = UIColor.init(hex: "8E8E93")
static let black = UIColor.init(hex: "000000")
}
@@ -29,7 +29,7 @@ struct SPLocalNotification {
let content = UNMutableNotificationContent()
content.body = body
content.title = title ?? ""
content.badge = NSNumber(value: SPBadge.number + 1)
content.badge = NSNumber(value: 1)
content.sound = UNNotificationSound.default
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval, repeats: false)
@@ -55,7 +55,7 @@ struct SPLocalNotification {
let content = UNMutableNotificationContent()
content.body = body
content.title = title ?? ""
content.badge = NSNumber(value: SPBadge.number + 1)
content.badge = NSNumber(value: 1)
content.sound = UNNotificationSound.default
let triggerDate = Calendar.current.dateComponents([.year,.month,.day,.hour,.minute,.second,], from: date)
@@ -33,12 +33,6 @@ public extension String {
}
}
public extension Bool {
public static func random() -> Bool {
return arc4random_uniform(2) == 0
}
}
public extension Int {
public static func random(_ n: Int) -> Int {
return Int(arc4random_uniform(UInt32(n)))
@@ -80,7 +74,7 @@ public extension CGFloat {
}
public extension Collection {
/// Return a copy of `self` with its elements shuffled
func shuffle() -> [Iterator.Element] {
var list = Array(self)
list.shuffleInPlace()
@@ -96,9 +90,9 @@ extension Collection where Index == Int {
}
public extension MutableCollection where Index == Int {
/// Shuffle the elements of `self` in-place.
mutating func shuffleInPlace() {
// empty and single-element collections don't shuffle
if count < 2 { return }
for i in startIndex ..< endIndex - 1 {
@@ -24,11 +24,7 @@ import UIKit
class SPInstagram {
static var isSetApp: Bool {
if UIApplication.shared.canOpenURL(URL(string: "instagram://user?username=test")!) {
return true
} else {
return false
}
return UIApplication.shared.canOpenURL(URL(string: "instagram://user?username=test")!)
}
static func openPost(id: String) {
@@ -38,7 +34,7 @@ class SPInstagram {
if UIApplication.shared.canOpenURL(instagramUrl!) {
UIApplication.shared.open(instagramUrl!, options: convertToUIApplicationOpenExternalURLOptionsKeyDictionary([:]), completionHandler: nil)
} else {
SPOpener.Link.redirectToBrowserAndOpen(link: safariURL)
SPApp.open(link: safariURL.absoluteString, redirect: true)
}
}
@@ -49,14 +45,13 @@ class SPInstagram {
if UIApplication.shared.canOpenURL(instagramUrl!) {
UIApplication.shared.open(instagramUrl!, options: convertToUIApplicationOpenExternalURLOptionsKeyDictionary([:]), completionHandler: nil)
} else {
SPOpener.Link.redirectToBrowserAndOpen(link: safariURL)
SPApp.open(link: safariURL.absoluteString, redirect: true)
}
}
private init() {}
}
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertToUIApplicationOpenExternalURLOptionsKeyDictionary(_ input: [String: Any]) -> [UIApplication.OpenExternalURLOptionsKey: Any] {
return Dictionary(uniqueKeysWithValues: input.map { key, value in (UIApplication.OpenExternalURLOptionsKey(rawValue: key), value)})
}
@@ -24,11 +24,7 @@ import UIKit
class SPTelegram {
static var isSetApp: Bool {
if UIApplication.shared.canOpenURL(URL(string: "tg://msg?text=test")!) {
return true
} else {
return false
}
return UIApplication.shared.canOpenURL(URL(string: "tg://msg?text=test")!)
}
static func share(text: String, complection: @escaping (_ isOpened: Bool)->() = {_ in }) {
@@ -47,7 +43,7 @@ class SPTelegram {
static func joinChannel(id: String) {
let url = "https://t.me/joinchat/\(id)"
SPOpener.Link.redirectToBrowserAndOpen(link: url)
SPApp.open(link: url, redirect: true)
}
static func openBot(username: String) {
@@ -56,13 +52,12 @@ class SPTelegram {
username.removeFirst()
}
let url = "https://telegram.me/\(username)"
SPOpener.Link.redirectToBrowserAndOpen(link: url)
SPApp.open(link: url, redirect: true)
}
private init() {}
}
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertToUIApplicationOpenExternalURLOptionsKeyDictionary(_ input: [String: Any]) -> [UIApplication.OpenExternalURLOptionsKey: Any] {
return Dictionary(uniqueKeysWithValues: input.map { key, value in (UIApplication.OpenExternalURLOptionsKey(rawValue: key), value)})
}
@@ -24,11 +24,7 @@ import UIKit
class SPTwitter {
static var isSetApp: Bool {
if UIApplication.shared.canOpenURL(URL(string: "twitter://post?message=test")!) {
return true
} else {
return false
}
return UIApplication.shared.canOpenURL(URL(string: "twitter://post?message=test")!)
}
static func share(text: String, complection: @escaping (_ isOpened: Bool)->() = {_ in }) {
@@ -48,7 +44,6 @@ class SPTwitter {
private init() {}
}
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertToUIApplicationOpenExternalURLOptionsKeyDictionary(_ input: [String: Any]) -> [UIApplication.OpenExternalURLOptionsKey: Any] {
return Dictionary(uniqueKeysWithValues: input.map { key, value in (UIApplication.OpenExternalURLOptionsKey(rawValue: key), value)})
}
@@ -24,11 +24,7 @@ import UIKit
class SPViber {
static var isSetApp: Bool {
if UIApplication.shared.canOpenURL(URL(string: "viber://forward?text=test")!) {
return true
} else {
return false
}
return UIApplication.shared.canOpenURL(URL(string: "viber://forward?text=test")!)
}
static func share(text: String, complection: @escaping (_ isOpened: Bool)->() = {_ in }) {
@@ -48,9 +44,6 @@ class SPViber {
private init() {}
}
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertToUIApplicationOpenExternalURLOptionsKeyDictionary(_ input: [String: Any]) -> [UIApplication.OpenExternalURLOptionsKey: Any] {
return Dictionary(uniqueKeysWithValues: input.map { key, value in (UIApplication.OpenExternalURLOptionsKey(rawValue: key), value)})
}
@@ -24,11 +24,7 @@ import UIKit
class SPWhatsApp {
static var isSetApp: Bool {
if UIApplication.shared.canOpenURL(URL(string: "whatsapp://send?text=test")!) {
return true
} else {
return false
}
return UIApplication.shared.canOpenURL(URL(string: "whatsapp://send?text=test")!)
}
static func share(text: String, complection: @escaping (_ isOpened: Bool)->() = {_ in }) {
@@ -48,7 +44,6 @@ class SPWhatsApp {
private init() {}
}
// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertToUIApplicationOpenExternalURLOptionsKeyDictionary(_ input: [String: Any]) -> [UIApplication.OpenExternalURLOptionsKey: Any] {
return Dictionary(uniqueKeysWithValues: input.map { key, value in (UIApplication.OpenExternalURLOptionsKey(rawValue: key), value)})
}
@@ -26,11 +26,6 @@ public enum SPStatusBar {
case light
}
public enum SPSnapToSide {
case left
case right
}
public enum SPSystemIconType {
case share
case close
@@ -63,50 +58,6 @@ public enum SPSeparatorInsetStyle {
case auto
}
@objc public enum SPPermissionType: Int {
case camera = 0
case photoLibrary = 1
case notification = 2
case microphone = 3
case calendar = 4
case contacts = 5
case reminders = 6
case speech = 7
case locationAlways = 8
case locationWhenInUse = 9
case locationWithBackground = 10
case mediaLibrary = 11
var name: String {
switch self {
case .camera:
return "Camera"
case .photoLibrary:
return "Photo Library"
case .notification:
return "Notification"
case .microphone:
return "Microphone"
case .calendar:
return "Calendar"
case .contacts:
return "Contacts"
case .reminders:
return "Reminders"
case .speech:
return "Speech"
case .locationAlways:
return "Location"
case .locationWhenInUse:
return "Location"
case .locationWithBackground:
return "Location"
case .mediaLibrary:
return "Media Library"
}
}
}
public enum SPNavigationTitleStyle {
case large
case small
@@ -117,3 +68,8 @@ public enum SPSystemApp {
case photos
case setting
}
public enum SPSelectionType {
case select
case unselect
}
@@ -23,21 +23,21 @@ import UIKit
class SPAppleMusicButton: SPButton {
var mode: Mode = .unselect {
var type: SPSelectionType = .unselect {
didSet {
self.updateStyle(animated: false)
self.updateType(animated: false)
}
}
var selectColor: UIColor = UIColor.init(hex: "FD2D55") {
didSet {
self.updateStyle(animated: false)
self.updateType(animated: false)
}
}
var baseColor: UIColor = UIColor.init(hex: "F8F7FC") {
didSet {
self.updateStyle(animated: false)
self.updateType(animated: false)
}
}
@@ -46,11 +46,11 @@ class SPAppleMusicButton: SPButton {
self.layer.cornerRadius = 8
self.titleLabel?.font = UIFont.system(type: .DemiBold, size: 15)
self.contentEdgeInsets = UIEdgeInsets.init(top: 12, left: 27, bottom: 12, right: 27)
self.mode = .unselect
self.type = .unselect
}
private func updateStyle(animated: Bool) {
switch self.mode {
private func updateType(animated: Bool) {
switch self.type {
case .select:
self.backgroundColor = self.selectColor
self.setTitleColor(UIColor.white)
@@ -61,10 +61,5 @@ class SPAppleMusicButton: SPButton {
break
}
}
enum Mode {
case select
case unselect
}
}
@@ -0,0 +1,93 @@
// The MIT License (MIT)
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
class SPAppleMusicSectionButtonsView: SPView {
let topSeparatorView = SPSeparatorView()
let bottomSeparatorView = SPSeparatorView()
let leftButton = SPAppleMusicButton()
let rightButton = SPAppleMusicButton()
var sectionHeight: CGFloat = 92 {
didSet { self.layoutSubviews() }
}
var buttonsSpace: CGFloat = 18 {
didSet { self.layoutSubviews() }
}
var selectColor: UIColor = UIColor.init(hex: "FD2D55") {
didSet {
self.leftButton.selectColor = selectColor
self.rightButton.selectColor = selectColor
}
}
var baseColor: UIColor = UIColor.init(hex: "F8F7FC") {
didSet {
self.leftButton.baseColor = baseColor
self.rightButton.baseColor = baseColor
}
}
override func commonInit() {
super.commonInit()
self.addSubview(self.topSeparatorView)
self.addSubview(self.bottomSeparatorView)
for button in [self.leftButton, self.rightButton] {
button.type = .unselect
button.setTitle("Title")
self.addSubview(button)
}
}
func layout(origin: CGPoint, width: CGFloat) {
self.frame.origin = origin
self.set(width: width, height: sectionHeight)
self.layoutSubviews()
}
override func layoutSubviews() {
super.layoutSubviews()
self.topSeparatorView.frame.origin = .zero
self.topSeparatorView.setWidth(self.frame.width)
self.bottomSeparatorView.frame.origin.x = 0
self.bottomSeparatorView.frame.bottomYPosition = self.frame.height
self.bottomSeparatorView.setWidth(self.frame.width)
let buttonWidth = (self.frame.width - self.buttonsSpace) / 2
self.leftButton.sizeToFit()
self.leftButton.setWidth(buttonWidth)
self.leftButton.frame.origin.x = 0
self.leftButton.center.y = self.frame.height / 2
self.rightButton.sizeToFit()
self.rightButton.setWidth(buttonWidth)
self.rightButton.frame.bottomXPosition = self.frame.width
self.rightButton.center.y = self.frame.height / 2
}
}
@@ -59,7 +59,7 @@ class SPDotButton: SPButton {
override func commonInit() {
super.commonInit()
self.backgroundColor = UIColor.black.withAlphaComponent(0.2)
self.backgroundColor = UIColor.black.withAlphaComponent(0.5)
for _ in 0...2 {
let dotView = UIView()
dotView.isUserInteractionEnabled = false
@@ -46,7 +46,7 @@ class SPNativeLargeButton: SPDownloadingButton {
super.commonInit()
self.titleLabel?.font = UIFont.system(type: UIFont.BoldType.DemiBold, size: 16)
self.setTitleColor(UIColor.white)
self.backgroundColor = SPNativeStyleKit.Colors.blue
self.backgroundColor = SPNativeColors.blue
self.layer.masksToBounds = true
self.layer.cornerRadius = 8
self.contentEdgeInsets = UIEdgeInsets.init(top: 15, left: 15, bottom: 15, right: 15)
@@ -39,7 +39,7 @@ class SPPlayCircleButton: UIButton {
}
}
var iconColor = SPNativeStyleKit.Colors.white {
var iconColor = SPNativeColors.white {
didSet {
self.iconView.color = self.iconColor
}
@@ -52,7 +52,7 @@ class SPPlayCircleButton: UIButton {
self.addSubview(self.iconView)
self.iconView.isUserInteractionEnabled = false
self.setTitle("", for: .normal)
self.backgroundColor = SPNativeStyleKit.Colors.blue
self.backgroundColor = SPNativeColors.blue
self.audioState = .play
}
@@ -75,8 +75,8 @@ class SPSocialButton: UIButton {
fileprivate func commonInit() {
self.iconView.isUserInteractionEnabled = false
self.addSubview(self.iconView)
self.backgroundColor = SPNativeStyleKit.Colors.blue
self.iconView.color = SPNativeStyleKit.Colors.white
self.backgroundColor = SPNativeColors.blue
self.iconView.color = SPNativeColors.white
}
override func layoutSubviews() {
@@ -33,7 +33,7 @@ class SPSystemIconButton: UIButton {
}
}
var color = SPNativeStyleKit.Colors.blue {
var color = SPNativeColors.blue {
didSet {
self.iconView.color = self.color
}
@@ -76,5 +76,4 @@ class SPSystemIconButton: UIButton {
super.layoutSubviews()
self.iconView.setEqualsFrameFromBounds(self, withWidthFactor: self.widthIconFactor, withHeightFactor: self.heightIconFactor, withCentering: true)
}
}
@@ -0,0 +1,64 @@
// The MIT License (MIT)
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
public class SPController: SPStatusBarManagerController {
let emptyTitlesView = SPEmptyTitlesView(title: "No Data", subtitle: "No data or information")
override public func viewDidLoad() {
super.viewDidLoad()
self.emptyTitlesView.isHidden = true
self.view.addSubview(self.emptyTitlesView)
self.updateLayout(with: self.view.frame.size)
}
override public func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { (contex) in
self.updateLayout(with: size)
}, completion: nil)
}
@available(iOS 11.0, *)
override public func viewLayoutMarginsDidChange() {
super.viewLayoutMarginsDidChange()
self.updateLayout(with: self.view.frame.size)
}
func updateLayout(with size: CGSize) {
self.emptyTitlesView.layout(centerY: size.height / 2)
}
func addHideButton(title: String) {
self.navigationItem.rightBarButtonItem = UIBarButtonItem.init(
title: title,
style: UIBarButtonItem.Style.done,
target: self,
action: #selector(self.dismiss(sender:))
)
}
@objc func dismiss(sender: Any) {
self.dismiss()
}
}
@@ -21,7 +21,7 @@
import UIKit
class SPNativeTableViewController: SPBaseTableViewController {
class SPNativeTableController: SPTableController {
let labelTableViewCellIdentifier: String = "labelTableViewCellIdentifier"
let textFieldTableViewCellIdentifier: String = "textFieldTableViewCellIdentifier"
@@ -31,7 +31,6 @@ class SPNativeTableViewController: SPBaseTableViewController {
let promoTableViewCellIdentifier: String = "promoTableViewCellIdentifier"
let featuredTitleTableViewCellIdentifier: String = "featuredTitleTableViewCellIdentifier"
let mailTableViewCellIdentifier: String = "mailTableViewCellIdentifier"
let collectionImagesTableViewCellIdentifier: String = "collectionImagesTableViewCellIdentifier"
let imageTableViewCellIdentifier: String = "imageTableViewCellIdentifier"
let proposeTableViewCellIdentifier: String = "proposeTableViewCellIdentifier"
let mengTransformTableViewCell = "mengTransformTableViewCell"
@@ -40,16 +39,9 @@ class SPNativeTableViewController: SPBaseTableViewController {
var showBottomInsets: Bool = true
var autoTopSpace: Bool = true
var autoBottomSpace: Bool = true
private var autoSpaceHeight: CGFloat = 35
init() {
super.init(nibName: nil, bundle: nil)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
@@ -62,7 +54,7 @@ class SPNativeTableViewController: SPBaseTableViewController {
self.tableView.contentInsetAdjustmentBehavior = .always
}
self.tableView.backgroundColor = SPNativeStyleKit.Colors.customGray
self.tableView.backgroundColor = SPNativeColors.customGray
self.tableView.delaysContentTouches = false
self.tableView.allowsSelection = false
self.tableView.rowHeight = UITableView.automaticDimension
@@ -78,13 +70,12 @@ class SPNativeTableViewController: SPBaseTableViewController {
self.tableView.register(SPPromoTableViewCell.self, forCellReuseIdentifier: self.promoTableViewCellIdentifier)
self.tableView.register(SPFormFeaturedTitleTableViewCell.self, forCellReuseIdentifier: self.featuredTitleTableViewCellIdentifier)
self.tableView.register(SPFormMailTableViewCell.self, forCellReuseIdentifier: self.mailTableViewCellIdentifier)
self.tableView.register(SPCollectionImagesTableViewCell.self, forCellReuseIdentifier: self.collectionImagesTableViewCellIdentifier)
self.tableView.register(SPImageTableViewCell.self, forCellReuseIdentifier: self.imageTableViewCellIdentifier)
self.tableView.register(SPProposeTableViewCell.self, forCellReuseIdentifier: self.proposeTableViewCellIdentifier)
self.tableView.register(SPMengTransformTableViewCell.self, forCellReuseIdentifier: self.mengTransformTableViewCell)
self.activityIndicatorView.stopAnimating()
self.activityIndicatorView.color = SPNativeStyleKit.Colors.gray
self.activityIndicatorView.color = SPNativeColors.gray
self.view.addSubview(self.activityIndicatorView)
self.updateLayout(with: self.view.frame.size)
@@ -150,10 +141,6 @@ class SPNativeTableViewController: SPBaseTableViewController {
return cell
}
func dequeueCollectionImagesTableViewCell(indexPath: IndexPath) -> SPCollectionImagesTableViewCell {
return tableView.dequeueReusableCell(withIdentifier: self.collectionImagesTableViewCellIdentifier, for: indexPath as IndexPath) as! SPCollectionImagesTableViewCell
}
func dequeueImageTableViewCell(indexPath: IndexPath) -> SPImageTableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: self.imageTableViewCellIdentifier, for: indexPath as IndexPath) as! SPImageTableViewCell
cell.currentIndexPath = indexPath
@@ -170,7 +157,7 @@ class SPNativeTableViewController: SPBaseTableViewController {
}
//MARK: - manage selection
extension SPNativeTableViewController {
extension SPNativeTableController {
override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
@@ -184,7 +171,7 @@ extension SPNativeTableViewController {
}
//MARK: - manage spaces
extension SPNativeTableViewController {
extension SPNativeTableController {
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
if section == 0 {
@@ -21,10 +21,11 @@
import UIKit
class SPProposeViewController: SPBaseViewController {
class SPProposeController: SPController {
private let data: Data
internal let areaView = AreaView()
private var isPresent: Bool = false
private var animationDuration: TimeInterval {
return 0.5
@@ -78,28 +79,24 @@ class SPProposeViewController: SPBaseViewController {
self.updateLayout(with: self.view.frame.size)
}
override func updateLayout(with size: CGSize) {
self.areaView.setWidth(size.width - (self.space * 2))
self.areaView.layoutSubviews()
self.areaView.sizeToFit()
self.areaView.frame.origin.x = self.space
self.areaView.frame.origin.y = self.view.frame.size.height - self.areaView.frame.height - (self.bottomSafeArea / 2) - self.space
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if !self.isPresent {
self.present()
self.isPresent = true
}
}
func present(on viewController: UIViewController) {
viewController.present(self, animated: false, completion: {
SPVibration.impact(SPVibration.Mode.warning)
self.areaView.frame.origin.y = self.view.frame.size.height
self.areaView.isHidden = false
SPAnimationSpring.animate(self.animationDuration, animations: {
self.view.backgroundColor = UIColor.black.withAlphaComponent(0.6)
self.areaView.frame.origin.y = self.view.frame.size.height - self.areaView.frame.height - (self.bottomSafeArea / 2) - self.space
}, spring: 1,
velocity: 1,
options: .transitionCurlUp)
})
private func present() {
SPVibration.impact(system: .warning)
self.areaView.frame.origin.y = self.view.frame.size.height
self.areaView.isHidden = false
SPAnimationSpring.animate(self.animationDuration, animations: {
self.view.backgroundColor = UIColor.black.withAlphaComponent(0.6)
self.areaView.frame.origin.y = self.view.frame.size.height - self.areaView.frame.height - (self.bottomSafeArea / 2) - self.space
}, spring: 1,
velocity: 1,
options: .transitionCurlUp)
}
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
@@ -130,8 +127,16 @@ class SPProposeViewController: SPBaseViewController {
}
}
@objc func handleGesture(sender: UIPanGestureRecognizer) {
override func updateLayout(with size: CGSize) {
self.areaView.setWidth(size.width - (self.space * 2))
self.areaView.layoutSubviews()
self.areaView.sizeToFit()
self.areaView.frame.origin.x = self.space
self.areaView.frame.origin.y = self.view.frame.size.height - self.areaView.frame.height - (self.bottomSafeArea / 2) - self.space
}
@objc func handleGesture(sender: UIPanGestureRecognizer) {
let returnAreaViewToPoint = {
SPAnimationSpring.animate(self.animationDuration, animations: {
self.areaView.frame.origin.y = self.view.frame.size.height - self.areaView.frame.height - (self.bottomSafeArea / 2) - self.space
@@ -195,7 +200,7 @@ class SPProposeViewController: SPBaseViewController {
self.addSubview(self.titleLabel)
self.subtitleLabel.font = UIFont.system(type: .Regular, size: 16)
self.subtitleLabel.textColor = SPNativeStyleKit.Colors.black
self.subtitleLabel.textColor = SPNativeColors.black
self.subtitleLabel.numberOfLines = 0
self.subtitleLabel.setCenteringAlignment()
self.addSubview(self.subtitleLabel)
@@ -206,7 +211,7 @@ class SPProposeViewController: SPBaseViewController {
self.addSubview(self.imageView)
self.button.titleLabel?.font = UIFont.system(type: UIFont.BoldType.Medium, size: 15)
self.button.setTitleColor(SPNativeStyleKit.Colors.black)
self.button.setTitleColor(SPNativeColors.black)
self.button.backgroundColor = UIColor.init(hex: "D4D3DB")
self.addSubview(self.button)
@@ -21,7 +21,7 @@
import UIKit
public class SPStatusBarManagerViewController: UIViewController {
public class SPStatusBarManagerController: UIViewController {
var statusBar: SPStatusBar = .dark {
didSet {
@@ -57,7 +57,7 @@ public class SPStatusBarManagerViewController: UIViewController {
}
}
public class SPStatusBarManagerTableViewController: UITableViewController {
public class SPStatusBarManagerTableController: UITableViewController {
var statusBar: SPStatusBar = .dark {
didSet {
@@ -0,0 +1,108 @@
// The MIT License (MIT)
// Copyright © 2017 Ivan Vorobei (hello@ivanvorobei.by)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
class SPTableController: SPStatusBarManagerTableController {
var activityIndicatorView = UIActivityIndicatorView.init()
override func viewDidLoad() {
super.viewDidLoad()
self.activityIndicatorView.stopAnimating()
self.activityIndicatorView.color = SPNativeColors.gray
self.view.addSubview(self.activityIndicatorView)
self.updateLayout(with: self.view.frame.size)
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { (contex) in
self.updateLayout(with: size)
}, completion: nil)
}
@available(iOS 11.0, *)
override func viewLayoutMarginsDidChange() {
super.viewLayoutMarginsDidChange()
self.updateLayout(with: self.view.frame.size)
}
func updateLayout(with size: CGSize) {
self.activityIndicatorView.center = CGPoint.init(
x: size.width / 2,
y: (size.height - self.safeArea.top - self.safeArea.bottom) / 2
)
}
//MARK: - Cache
private var cacheImages: [(link: String, image: UIImage)] = []
func toCache(link: String, image: UIImage?) {
if image == nil {
return
}
if self.fromCahce(link: link) == nil {
self.cacheImages.append((link: link, image: image!))
}
}
func fromCahce(link: String) -> UIImage? {
let cachedData = self.cacheImages.first(where: {
$0.link == link
})
return cachedData?.image
}
//MARK: - Reload Table View
func reloadTableView(animated: Bool, complection: @escaping ()->() = {}) {
if animated {
UIView.transition(
with: self.tableView,
duration: 0.3,
options: [.transitionCrossDissolve, UIView.AnimationOptions.beginFromCurrentState],
animations: {
self.tableView.reloadData()
}, completion: {(state) in
complection()
})
} else {
self.tableView.reloadData()
complection()
}
}
//MARK: - Other
@objc func dismiss(sender: Any) {
self.dismiss()
}
func addHideButton(title: String) {
self.navigationItem.rightBarButtonItem = UIBarButtonItem.init(
title: title,
style: UIBarButtonItem.Style.done,
target: self,
action: #selector(self.dismiss(sender:))
)
}
}
@@ -29,7 +29,7 @@ class SPAudioIconView: UIView {
}
}
var color = SPNativeStyleKit.Colors.white {
var color = SPNativeColors.white {
didSet {
self.setNeedsDisplay()
}
@@ -29,7 +29,7 @@ class SPGolubevIconView: UIView {
}
}
var whiteColor = SPNativeStyleKit.Colors.white {
var whiteColor = SPNativeColors.white {
didSet {
self.setNeedsDisplay()
}
@@ -103,6 +103,9 @@ class SPGolubevIconView: UIView {
case .headphones:
SPCodeDraw.GolubevIconPack.drawHeadphones(frame: rect, resizing: .aspectFit, white: self.whiteColor, light: self.lightColor, medium: self.mediumColor, dark: self.darkColor)
break
case .windmill:
SPCodeDraw.GolubevIconPack.drawWindmill(frame: rect, resizing: .aspectFit, white: self.whiteColor, light: self.lightColor, medium: self.mediumColor, dark: self.darkColor)
break
}
}
@@ -116,6 +119,7 @@ class SPGolubevIconView: UIView {
case documents
case compass
case headphones
case windmill
}
}
@@ -29,7 +29,7 @@ class SPSocialIconView: UIView {
}
}
var color = SPNativeStyleKit.Colors.blue {
var color = SPNativeColors.blue {
didSet {
self.setNeedsDisplay()
}
@@ -29,7 +29,7 @@ class SPSystemIconView: UIView {
}
}
var color = SPNativeStyleKit.Colors.blue {
var color = SPNativeColors.blue {
didSet {
self.setNeedsDisplay()
}
@@ -86,8 +86,8 @@ class SPMengTransformCollectionViewCell: SPCollectionViewCell {
self.backgroundImageView.bottomAnchor.constraint(equalTo:
contentView.bottomAnchor, constant: 0).isActive = true
self.gradientView.setStartColorPosition(SPGradientView.Position.TopLeft)
self.gradientView.setEndColorPosition(.BottomRight)
self.gradientView.startColorPosition = .topLeft
self.gradientView.endColorPosition = .bottomRight
self.gradientView.isHidden = true
self.gradientView.translatesAutoresizingMaskIntoConstraints = false
self.gradientView.layer.masksToBounds = false
@@ -196,7 +196,6 @@ public class SPCollectionViewLayout: UICollectionViewFlowLayout {
if isAllowInsertAnimation {
if self.insertIndexPaths.contains(itemIndexPath) {
//attributes?.center = CGPoint.init(x: attributes?.center.x ?? 0, y: 40)
attributes?.alpha = 0
attributes?.zIndex = 0
attributes?.transform = CGAffineTransform.init(scaleX: self.minimumScaleFactor, y: self.minimumScaleFactor)
@@ -207,11 +206,10 @@ public class SPCollectionViewLayout: UICollectionViewFlowLayout {
}
override public func finalLayoutAttributesForDisappearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
var attributes: UICollectionViewLayoutAttributes?
let attributes: UICollectionViewLayoutAttributes? = super.finalLayoutAttributesForDisappearingItem(at: itemIndexPath)
if self.deleteIndexPaths.contains(itemIndexPath) {
attributes = self.layoutAttributesForItem(at: itemIndexPath)
attributes?.alpha = 0
attributes?.zIndex = 0
attributes?.transform3D = CATransform3DScale(CATransform3DIdentity, self.minimumScaleFactor, self.minimumScaleFactor, 1)
@@ -229,9 +227,19 @@ public class SPCollectionViewLayout: UICollectionViewFlowLayout {
collectionView.decelerationRate = UIScrollView.DecelerationRate.fast
if cellSideRatio == nil {
var height = collectionView.bounds.size.height * self.heightFactor
if height > self.maxHeight {
height = self.maxHeight
}
var width = collectionView.bounds.size.width * self.widthFactor
if width > self.maxWidth {
width = self.maxWidth
}
self.itemSize = CGSize.init(
width: collectionView.bounds.size.width * self.widthFactor,
height: collectionView.bounds.size.height * self.heightFactor
width: width,
height: height
)
} else {
self.itemSize = SPLayout.sizeWith(

Some files were not shown because too many files have changed in this diff Show More