Compare commits

..

86 Commits

Author SHA1 Message Date
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
Ivan Vorobei 5b8fdf6590 Update to 1.1.1 2018-12-06 15:21:50 +03:00
162 changed files with 2338 additions and 4802 deletions
File diff suppressed because it is too large Load Diff
@@ -7,6 +7,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.launch(rootViewController: Controller())
return true
}
@@ -32,6 +33,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
present(modal, animated: true, completion: nil)
}
@objc func presentModalTableViewController() {
let modal = ModalTableViewController()
let transitionDelegate = SPStorkTransitioningDelegate()
modal.transitioningDelegate = transitionDelegate
modal.modalPresentationStyle = .custom
present(modal, animated: true, completion: nil)
}
}
@@ -23,7 +23,7 @@ import UIKit
public struct SPStorkController {
static func scrollViewDidScroll(_ scrollView: UIScrollView) {
static public func scrollViewDidScroll(_ scrollView: UIScrollView) {
if let controller = self.controller(for: scrollView) {
if let presentationController = controller.presentationController as? SPStorkPresentationController {
let translation = -(scrollView.contentOffset.y + scrollView.contentInset.top)
@@ -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) {
@@ -24,9 +24,13 @@ import UIKit
class SPStorkPresentationController: UIPresentationController, UIGestureRecognizerDelegate {
var isSwipeToDismissEnabled: Bool = true
var isTapAroundToDismissEnabled: Bool = true
var showIndicator: Bool = true
var customHeight: CGFloat? = nil
var transitioningDelegate: SPStorkTransitioningDelegate?
var pan: UIPanGestureRecognizer?
var tap: UITapGestureRecognizer?
private var indicatorView = SPStorkIndicatorView()
private var gradeView: UIView = UIView()
@@ -55,13 +59,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)
}
@@ -82,6 +93,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 +157,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 +179,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 }
@@ -270,6 +293,7 @@ extension SPStorkPresentationController {
animations: {
self.snapshotView?.transform = .identity
self.presentedView?.transform = .identity
self.gradeView.alpha = self.alpha
})
}
default:
@@ -283,12 +307,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 +331,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 +376,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)
@@ -23,11 +23,17 @@ import UIKit
public final class SPStorkTransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
var isSwipeToDismissEnabled: Bool = true
var showIndicator: Bool = true
public var isSwipeToDismissEnabled: Bool = true
public var isTapAroundToDismissEnabled: Bool = true
public var showIndicator: Bool = true
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.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,7 @@
import UIKit
struct SPCodeDraw { private init(){} }
struct SPCodeDraw {
private init() {}
}
@@ -19,7 +19,6 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
import UIKit
extension SPCodeDraw {
@@ -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
}
}
@@ -32,7 +32,7 @@ extension UIViewController {
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
@@ -55,12 +55,10 @@ extension UIViewController {
extension UIViewController {
func save(image: UIImage) {
if SPPermission.isAllow(.photoLibrary) {
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")
}
}
@@ -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:
@@ -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()
}
@@ -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