diff --git a/Classes/Default/RMRPullToRefreshBaseMessageView.swift b/Classes/Default/RMRPullToRefreshBaseMessageView.swift new file mode 100644 index 0000000..ad76062 --- /dev/null +++ b/Classes/Default/RMRPullToRefreshBaseMessageView.swift @@ -0,0 +1,122 @@ +// +// RMRPullToRefreshBaseMessageView.swift +// RMRPullToRefreshExample +// +// Created by Merkulov Ilya on 17.04.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit + +class RMRPullToRefreshBaseMessageView: RMRPullToRefreshBaseView { + + var messageView = UIView(frame: CGRect.zero) + var messageViewLeftConstaint: NSLayoutConstraint? + + // MARK: - Init + + override init(result: RMRPullToRefreshResultType) { + super.init(result: result) + configure() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Private + + func configure() { + configureMessageView() + configureLabel() + } + + func configureLabel() { + let label = UILabel(frame: self.messageView.bounds) + label.textColor = UIColor.whiteColor() + label.textAlignment = .Center + label.text = messageText() + messageView.addSubview(label) + label.translatesAutoresizingMaskIntoConstraints = false + + for attribute in [NSLayoutAttribute.Top, NSLayoutAttribute.Right, NSLayoutAttribute.Left, NSLayoutAttribute.Bottom] { + messageView.addConstraint(NSLayoutConstraint(item: label, + attribute: attribute, + relatedBy: NSLayoutRelation.Equal, + toItem: messageView, + attribute: attribute, + multiplier: 1, + constant: 0)) + } + } + + func configureMessageView() { + messageView.backgroundColor = messageBackgroundColor() + messageView.layer.cornerRadius = 5.0 + messageView.clipsToBounds = true + addSubview(messageView) + messageView.translatesAutoresizingMaskIntoConstraints = false + + let heightConstraint = NSLayoutConstraint(item: messageView, + attribute: NSLayoutAttribute.Height, + relatedBy: NSLayoutRelation.Equal, + toItem: nil, + attribute: NSLayoutAttribute.NotAnAttribute, + multiplier: 1, + constant: 30) + + let widthConstraint = NSLayoutConstraint(item: messageView, + attribute: NSLayoutAttribute.Width, + relatedBy: NSLayoutRelation.Equal, + toItem: nil, + attribute: NSLayoutAttribute.NotAnAttribute, + multiplier: 1, + constant: 150) + + messageView.addConstraints([heightConstraint, widthConstraint]) + + let verticalConstraint = NSLayoutConstraint(item: messageView, + attribute: .CenterY, + relatedBy: NSLayoutRelation.Equal, + toItem: self, + attribute: .CenterY, + multiplier: 1, + constant: 0) + + let leftConstraint = NSLayoutConstraint(item: messageView, + attribute: .Left, + relatedBy: NSLayoutRelation.Equal, + toItem: self, + attribute: .Right, + multiplier: 1, + constant: 0) + + addConstraints([verticalConstraint, leftConstraint]) + + messageViewLeftConstaint = leftConstraint + } + + func messageBackgroundColor() -> UIColor { + return UIColor.whiteColor() + } + + func messageText() -> String? { + return nil + } + + // MARK: - RMRPullToRefreshViewProtocol + + override func willEndLoadingAnimation() { + self.logoHorizontalConstraint?.constant = -CGRectGetWidth(self.bounds)/2.0 + CGRectGetWidth(self.logoImageView.bounds) + self.messageViewLeftConstaint?.constant = -CGRectGetWidth(messageView.bounds) - 10.0 + UIView.animateWithDuration(0.4) {[weak self] in + self?.layoutIfNeeded() + } + } + + override func didEndLoadingAnimation(hidden: Bool) { + super.didEndLoadingAnimation(hidden) + self.logoHorizontalConstraint?.constant = 0.0 + self.messageViewLeftConstaint?.constant = 0.0 + } +} diff --git a/Classes/Default/RMRPullToRefreshBaseView.swift b/Classes/Default/RMRPullToRefreshBaseView.swift new file mode 100644 index 0000000..689bbb9 --- /dev/null +++ b/Classes/Default/RMRPullToRefreshBaseView.swift @@ -0,0 +1,155 @@ +// +// RMRPullToRefreshBaseView.swift +// RMRPullToRefreshExample +// +// Created by Merkulov Ilya on 12.04.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit + +let image1: String = "redmadlogo-1" +let image2: String = "redmadlogo-2" +let image3: String = "redmadlogo-3" + +class RMRPullToRefreshBaseView: RMRPullToRefreshView { + + let images = [UIImage(named: image1)!, + UIImage(named: image2)!, + UIImage(named: image3)!] + + let logoImageView = UIImageView(image: UIImage(named: image1)) + + var logoHorizontalConstraint: NSLayoutConstraint? + + var result: RMRPullToRefreshResultType? + + var isConfigured: Bool = false + var didRotateToTop: Bool = false + var didRotateToBottom: Bool = false + var animating: Bool = true + + init(result: RMRPullToRefreshResultType) { + self.result = result + super.init(frame: CGRect.zero) + addSubview(logoImageView) + configureConstraints() + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Private + + func configureConstraints() { + logoImageView.translatesAutoresizingMaskIntoConstraints = false + let heightConstraint = NSLayoutConstraint(item: logoImageView, + attribute: NSLayoutAttribute.Height, + relatedBy: NSLayoutRelation.Equal, + toItem: nil, + attribute: NSLayoutAttribute.NotAnAttribute, + multiplier: 1, + constant: 50) + + let widthConstraint = NSLayoutConstraint(item: logoImageView, + attribute: NSLayoutAttribute.Width, + relatedBy: NSLayoutRelation.Equal, + toItem: nil, + attribute: NSLayoutAttribute.NotAnAttribute, + multiplier: 1, + constant: 50) + + logoImageView.addConstraints([heightConstraint, widthConstraint]) + + let verticalConstraint = NSLayoutConstraint(item: logoImageView, + attribute: .CenterY, + relatedBy: NSLayoutRelation.Equal, + toItem: self, + attribute: .CenterY, + multiplier: 1, + constant: 0) + + let horizontalConstraint = NSLayoutConstraint(item: logoImageView, + attribute: .CenterX, + relatedBy: NSLayoutRelation.Equal, + toItem: self, + attribute: .CenterX, + multiplier: 1, + constant: 0) + + addConstraints([verticalConstraint, horizontalConstraint]) + + logoHorizontalConstraint = horizontalConstraint + } + + func resetTransformIfNecessary() { + if !isConfigured { + logoImageView.transform = CGAffineTransformMakeRotation(CGFloat(M_PI)) + didRotateToBottom = true + isConfigured = true + } + } + + func makeIncreasePulling(animated: Bool) { + didRotateToTop = true + didRotateToBottom = false + let rotateTransform = CGAffineTransformRotate(logoImageView.transform, CGFloat(M_PI)); + if animated { + UIView .animateWithDuration(0.4, animations: { + self.logoImageView.transform = rotateTransform + }) + } else { + self.logoImageView.transform = rotateTransform + } + } + + func makeDecreasePulling(animated: Bool) { + didRotateToBottom = true + didRotateToTop = false + let rotateTransform = CGAffineTransformRotate(logoImageView.transform, -CGFloat(M_PI)); + if animated { + UIView .animateWithDuration(0.4, animations: { + self.logoImageView.transform = rotateTransform + }) + } else { + self.logoImageView.transform = rotateTransform + } + } + + // MARK: - RMRPullToRefreshViewProtocol + + override func didChangeDraggingProgress(progress: CGFloat) { + + resetTransformIfNecessary() + + if progress >= 1.0 && !didRotateToTop && didRotateToBottom { + makeIncreasePulling(animating) + if !animating { + animating = true + } + } else if progress < 1.0 && !didRotateToBottom && didRotateToTop{ + makeDecreasePulling(true) + } + } + + override func prepareForLoadingAnimation(startProgress: CGFloat) { + if logoImageView.animationImages == nil { + logoImageView.animationImages = images + logoImageView.animationDuration = 0.8 + logoImageView.animationRepeatCount = 0 + } + } + + override func beginLoadingAnimation() { + logoImageView.startAnimating() + } + + override func didEndLoadingAnimation(hidden: Bool) { + logoImageView.stopAnimating() + logoImageView.layer.removeAllAnimations() + isConfigured = false + didRotateToTop = false + animating = hidden + } +} diff --git a/Classes/Default/RMRPullToRefreshErrorView.swift b/Classes/Default/RMRPullToRefreshErrorView.swift new file mode 100644 index 0000000..b0f627c --- /dev/null +++ b/Classes/Default/RMRPullToRefreshErrorView.swift @@ -0,0 +1,23 @@ +// +// RMRPullToRefreshErrorView.swift +// RMRPullToRefreshExample +// +// Created by Merkulov Ilya on 17.04.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit + +class RMRPullToRefreshErrorView: RMRPullToRefreshBaseMessageView { + + override func messageText() -> String? { + return "Ошибка" + } + + override func messageBackgroundColor() -> UIColor { + return UIColor(red: 234.0/255.0, + green: 33.0/255.0, + blue: 45.0/255.0, + alpha: 1.0) + } +} diff --git a/Classes/Default/RMRPullToRefreshNoUpdatesView.swift b/Classes/Default/RMRPullToRefreshNoUpdatesView.swift new file mode 100644 index 0000000..1f787b3 --- /dev/null +++ b/Classes/Default/RMRPullToRefreshNoUpdatesView.swift @@ -0,0 +1,23 @@ +// +// RMRPullToRefreshNoUpdatesView.swift +// RMRPullToRefreshExample +// +// Created by Merkulov Ilya on 17.04.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit + +class RMRPullToRefreshNoUpdatesView: RMRPullToRefreshBaseMessageView { + + override func messageText() -> String? { + return "Нет обновлений" + } + + override func messageBackgroundColor() -> UIColor { + return UIColor(red: 148.0/255.0, + green: 199.0/255.0, + blue: 111.0/255.0, + alpha: 1.0) + } +} diff --git a/Classes/Default/RMRPullToRefreshSuccessView.swift b/Classes/Default/RMRPullToRefreshSuccessView.swift new file mode 100644 index 0000000..d84cdfa --- /dev/null +++ b/Classes/Default/RMRPullToRefreshSuccessView.swift @@ -0,0 +1,13 @@ +// +// RMRPullToRefreshSuccessView.swift +// RMRPullToRefreshExample +// +// Created by Merkulov Ilya on 17.04.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit + +class RMRPullToRefreshSuccessView: RMRPullToRefreshBaseView { + +} diff --git a/Classes/Default/RMRPullToRefreshViewFactory.swift b/Classes/Default/RMRPullToRefreshViewFactory.swift new file mode 100644 index 0000000..a004fcf --- /dev/null +++ b/Classes/Default/RMRPullToRefreshViewFactory.swift @@ -0,0 +1,24 @@ +// +// RMRPullToRefreshViewFactory.swift +// RMRPullToRefresh +// +// Created by Merkulov Ilya on 19.03.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit + +public class RMRPullToRefreshViewFactory: NSObject { + + class func create(result: RMRPullToRefreshResultType) -> RMRPullToRefreshView? { + switch result { + case .Success: + return RMRPullToRefreshSuccessView(result: result) + case .NoUpdates: + return RMRPullToRefreshNoUpdatesView(result: result) + case .Error: + return RMRPullToRefreshErrorView(result: result) + } + + } +} diff --git a/Classes/Images/redmadlogo-1.png b/Classes/Images/redmadlogo-1.png new file mode 100644 index 0000000..c5a41e2 Binary files /dev/null and b/Classes/Images/redmadlogo-1.png differ diff --git a/Classes/Images/redmadlogo-2.png b/Classes/Images/redmadlogo-2.png new file mode 100644 index 0000000..bf1d336 Binary files /dev/null and b/Classes/Images/redmadlogo-2.png differ diff --git a/Classes/Images/redmadlogo-3.png b/Classes/Images/redmadlogo-3.png new file mode 100644 index 0000000..ecd7ac2 Binary files /dev/null and b/Classes/Images/redmadlogo-3.png differ diff --git a/Classes/RMRPullToRefresh.swift b/Classes/RMRPullToRefresh.swift new file mode 100644 index 0000000..d5bb569 --- /dev/null +++ b/Classes/RMRPullToRefresh.swift @@ -0,0 +1,71 @@ +// +// RMRPullToRefresh.swift +// RMRPullToRefresh +// +// Created by Merkulov Ilya on 03.04.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit + +public class RMRPullToRefresh: NSObject { + + private var сontroller: RMRPullToRefreshController? + + public var height : CGFloat = RMRPullToRefreshConstants.DefaultHeight { + didSet { + сontroller?.configureHeight(height) + } + } + + public var backgroundColor : UIColor = RMRPullToRefreshConstants.DefaultBackgroundColor { + didSet { + сontroller?.configureBackgroundColor(backgroundColor) + } + } + + public var hideWhenError: Bool = true { + didSet { + сontroller?.hideWhenError = hideWhenError + } + } + + public init(scrollView: UIScrollView, position:RMRPullToRefreshPosition, actionHandler: () -> Void) { + super.init() + + let controller = RMRPullToRefreshController(scrollView: scrollView, + position: position, + actionHandler: actionHandler) + + scrollView.addSubview(controller.containerView) + self.сontroller = controller + } + + public func configureView(view :RMRPullToRefreshView, state:RMRPullToRefreshState, result:RMRPullToRefreshResultType) { + сontroller?.configureView(view, state: state, result: result) + } + + public func configureView(view :RMRPullToRefreshView) { + сontroller?.configureView(view, result: .Success) + } + + public func setupDefaultSettings() { + сontroller?.setupDefaultSettings() + } + + public func startLoading() { + сontroller?.startLoading() + } + + public func stopLoading() { + stopLoading(.Success) + } + + public func stopLoading(result:RMRPullToRefreshResultType) { + сontroller?.stopLoading(result) + } + + public func setHideDelay(delay: NSTimeInterval, result: RMRPullToRefreshResultType) { + сontroller?.setHideDelay(delay, result: result) + } +} diff --git a/Classes/RMRPullToRefreshConstants.swift b/Classes/RMRPullToRefreshConstants.swift new file mode 100644 index 0000000..abd25ab --- /dev/null +++ b/Classes/RMRPullToRefreshConstants.swift @@ -0,0 +1,40 @@ +// +// RMRPullToRefreshConstants.swift +// RMRPullToRefresh +// +// Created by Merkulov Ilya on 19.03.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit + +public enum RMRPullToRefreshPosition: Int { + case Top + case Bottom +} + +public enum RMRPullToRefreshState: Int { + case Stopped + case Dragging + case Loading +} + +public enum RMRPullToRefreshResultType: Int { + case Success = 0 + case NoUpdates + case Error +} + +public struct RMRPullToRefreshConstants { + + struct KeyPaths { + static let ContentOffset = "contentOffset" + static let ContentSize = "contentSize" + static let ContentInset = "contentInset" + static let PanState = "pan.state" + static let Frame = "frame" + } + + static let DefaultHeight = CGFloat(90.0) + static let DefaultBackgroundColor = UIColor.whiteColor() +} \ No newline at end of file diff --git a/Classes/RMRPullToRefreshContainerView.swift b/Classes/RMRPullToRefreshContainerView.swift new file mode 100644 index 0000000..deff608 --- /dev/null +++ b/Classes/RMRPullToRefreshContainerView.swift @@ -0,0 +1,90 @@ +// +// RMRPullToRefreshContainerView.swift +// RMRPullToRefresh +// +// Created by Merkulov Ilya on 19.03.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit + +public class RMRPullToRefreshContainerView: UIView { + + var currentView: RMRPullToRefreshView? + + var storage = [String: RMRPullToRefreshView]() + + public func configureView(view:RMRPullToRefreshView, state:RMRPullToRefreshState, result:RMRPullToRefreshResultType) { + let key = storageKey(state, result:result) + self.storage[key] = view + } + + func updateView(state: RMRPullToRefreshState, result: RMRPullToRefreshResultType) { + + clear() + if let view = obtainView(state, result: result) { + view.translatesAutoresizingMaskIntoConstraints = false + addSubview(view) + addConstraint(constraint(self, subview: view, attribute: NSLayoutAttribute.Left)) + addConstraint(constraint(self, subview: view, attribute: NSLayoutAttribute.Top)) + addConstraint(constraint(self, subview: view, attribute: NSLayoutAttribute.Right)) + addConstraint(constraint(self, subview: view, attribute: NSLayoutAttribute.Bottom)) + view.layoutIfNeeded() + self.currentView = view + } + } + + func dragging(progress: CGFloat) { + if let view = self.currentView { + view.didChangeDraggingProgress(progress) + } + } + + func startLoadingAnimation(startProgress: CGFloat) { + if let view = self.currentView { + if !view.pullToRefreshIsLoading { + view.prepareForLoadingAnimation(startProgress) + view.pullToRefreshIsLoading = true + view.beginLoadingAnimation() + } + } + } + + func prepareForStopAnimations() { + if let view = self.currentView { + view.willEndLoadingAnimation() + } + } + + func stopAllAnimations(hidden: Bool) { + for view in storage.values { + view.didEndLoadingAnimation(hidden) + view.pullToRefreshIsLoading = false + } + } + + // MARK: - Private + + func clear() { + for view in subviews { + view.removeFromSuperview() + } + self.currentView = nil + } + + func obtainView(state: RMRPullToRefreshState, result: RMRPullToRefreshResultType) -> RMRPullToRefreshView? { + let key = storageKey(state, result:result) + return self.storage[key] + } + + func storageKey(state: RMRPullToRefreshState, result: RMRPullToRefreshResultType) -> String { + return String(state.rawValue) + "_" + String(result.rawValue) + } + + + // MARK: - Constraint + + func constraint(superview: UIView, subview: UIView, attribute: NSLayoutAttribute) -> NSLayoutConstraint { + return NSLayoutConstraint(item: subview, attribute: attribute, relatedBy: NSLayoutRelation.Equal, toItem: superview, attribute: attribute, multiplier: 1, constant: 0) + } +} diff --git a/Classes/RMRPullToRefreshController.swift b/Classes/RMRPullToRefreshController.swift new file mode 100644 index 0000000..b7e27ed --- /dev/null +++ b/Classes/RMRPullToRefreshController.swift @@ -0,0 +1,397 @@ +// +// RMRPullToRefreshController.swift +// RMRPullToRefresh +// +// Created by Merkulov Ilya on 19.03.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit + +public class RMRPullToRefreshController: NSObject { + + // MARK: - Vars + + weak var scrollView: UIScrollView? + + let containerView = RMRPullToRefreshContainerView() + + let backgroundView = UIView(frame: CGRectZero) + var backgroundViewHeightConstraint: NSLayoutConstraint? + var backgroundViewTopConstraint: NSLayoutConstraint? + + var stopped = true + var subscribing = false + + var actionHandler: (() -> Void)! + + var height = CGFloat(0.0) + var originalTopInset = CGFloat(0.0) + var originalBottomInset = CGFloat(0.0) + + var state = RMRPullToRefreshState.Stopped + var result = RMRPullToRefreshResultType.Success + var position: RMRPullToRefreshPosition? + + var changingContentInset = false + var contentSizeWhenStartLoading: CGSize? + + var hideDelayValues = [RMRPullToRefreshResultType: NSTimeInterval]() + + public var hideWhenError: Bool = true + + // MARK: - Init + + init(scrollView: UIScrollView, position:RMRPullToRefreshPosition, actionHandler: () -> Void) { + + super.init() + self.scrollView = scrollView + self.actionHandler = actionHandler + self.position = position + + self.configureBackgroundView(self.backgroundView) + self.configureHeight() + + self.containerView.backgroundColor = UIColor.clearColor() + + self.subscribeOnScrollViewEvents() + } + + deinit { + self.unsubscribeFromScrollViewEvents() + } + + private func configureBackgroundView(backgroundView: UIView) { + backgroundView.translatesAutoresizingMaskIntoConstraints = false + scrollView?.addSubview(backgroundView) + addBackgroundViewConstraints(backgroundView) + } + + private func addBackgroundViewConstraints(backgroundView: UIView) { + // Constraints + self.backgroundViewHeightConstraint = NSLayoutConstraint(item: backgroundView, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: 0) + backgroundView.addConstraint(self.backgroundViewHeightConstraint!) + + scrollView?.addConstraint(NSLayoutConstraint(item: backgroundView, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: scrollView, attribute: NSLayoutAttribute.Width, multiplier: 1, constant: 0)) + + if position == .Top { + scrollView?.addConstraint(NSLayoutConstraint(item: backgroundView, attribute: NSLayoutAttribute.Bottom, relatedBy: NSLayoutRelation.Equal, toItem: scrollView, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: 0)) + } else if position == .Bottom, let scrollView = self.scrollView { + let constant = max(scrollView.contentSize.height, CGRectGetHeight(scrollView.bounds)) + self.backgroundViewTopConstraint = NSLayoutConstraint(item: backgroundView, attribute: NSLayoutAttribute.Top, relatedBy: NSLayoutRelation.Equal, toItem: scrollView, attribute: NSLayoutAttribute.Top, multiplier: 1, constant: constant) + scrollView.addConstraint(self.backgroundViewTopConstraint!) + } + } + + private func configureHeight() { + + if let scrollView = self.scrollView { + self.originalTopInset = scrollView.contentInset.top + self.originalBottomInset = scrollView.contentInset.bottom + } + configureHeight(RMRPullToRefreshConstants.DefaultHeight) + } + + // MARK: - Public + + public func configureView(view:RMRPullToRefreshView, result:RMRPullToRefreshResultType) { + configureView(view, state: .Loading, result: result) + configureView(view, state: .Dragging, result: result) + configureView(view, state: .Stopped, result: result) + } + + public func configureView(view:RMRPullToRefreshView, state:RMRPullToRefreshState, result:RMRPullToRefreshResultType) { + containerView.configureView(view, state: state, result: result) + } + + public func configureHeight(height: CGFloat) { + self.height = height + updateContainerFrame() + } + + public func configureBackgroundColor(color: UIColor) { + self.backgroundView.backgroundColor = color + } + + public func setupDefaultSettings() { + setupDefaultSettings(.Success, hideDelay: 0.0) + setupDefaultSettings(.NoUpdates, hideDelay: 2.0) + setupDefaultSettings(.Error, hideDelay: 2.0) + configureBackgroundColor(UIColor.whiteColor()) + updateContainerView(self.state) + } + + public func startLoading() { + startLoading(0.0) + } + + public func stopLoading(result:RMRPullToRefreshResultType) { + + self.result = result + self.state = .Stopped + updateContainerView(self.state) + containerView.prepareForStopAnimations() + + let delay = hideDelay(result) + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), { [weak self] in + if self?.shouldHideWhenStopLoading() == true { + self?.resetContentInset() + if let position = self?.position { + switch (position) { + case .Top: + self?.scrollToTop(true) + case .Bottom: + self?.scrollToBottom(true) + } + } + self?.contentSizeWhenStartLoading = nil + self?.performSelector(#selector(self?.resetBackgroundViewHeightConstraint), withObject: nil, afterDelay: 0.4) + } + self?.performSelector(#selector(self?.stopAllAnimations), withObject: nil, afterDelay: 0.4) + }) + } + + public func setHideDelay(delay: NSTimeInterval, result: RMRPullToRefreshResultType) { + hideDelayValues[result] = delay + } + + // MARK: - Private + + func setupDefaultSettings(result:RMRPullToRefreshResultType, hideDelay: NSTimeInterval) { + if let view = RMRPullToRefreshViewFactory.create(result) { + configureView(view, result: result) + setHideDelay(hideDelay, result: result) + } + } + + func scrollToTop(animated: Bool) { + if let scrollView = self.scrollView { + if scrollView.contentOffset.y < -originalTopInset { + let offset = CGPointMake(scrollView.contentOffset.x, -self.originalTopInset) + scrollView.setContentOffset(offset, animated: true) + } + } + } + + func scrollToBottom(animated: Bool) { + if let scrollView = self.scrollView { + var offset = scrollView.contentOffset + if let contentSize = self.contentSizeWhenStartLoading { + offset.y = contentSize.height - CGRectGetHeight(scrollView.bounds) + scrollView.contentInset.bottom + if state == .Stopped { + if scrollView.contentOffset.y < offset.y { + return + } else if scrollView.contentOffset.y > offset.y { + offset.y += height + } + } + } else { + offset.y = scrollView.contentSize.height - CGRectGetHeight(scrollView.bounds) + scrollView.contentInset.bottom + } + scrollView.setContentOffset(offset, animated: animated) + } + } + + func startLoading(startProgress: CGFloat) { + stopped = false + contentSizeWhenStartLoading = scrollView?.contentSize + state = .Loading + updateContainerView(state) + actionHandler() + + containerView.startLoadingAnimation(startProgress) + } + + @objc private func stopAllAnimations() { + stopped = true + containerView.stopAllAnimations(shouldHideWhenStopLoading()) + } + + @objc private func resetBackgroundViewHeightConstraint() { + backgroundViewHeightConstraint?.constant = 0 + } + + private func scrollViewDidChangePanState(scrollView: UIScrollView, panState: UIGestureRecognizerState) { + if panState == .Ended || panState == .Cancelled || panState == .Failed { + + if state == .Loading { + return + } + + var y: CGFloat = 0.0 + if position == .Top { + y = -scrollView.contentOffset.y + } else if position == .Bottom { + y = -(scrollView.contentSize.height - (scrollView.contentOffset.y + CGRectGetHeight(scrollView.bounds) + originalBottomInset)); + } + + if y >= height && stopped { + startLoading(y/height) + // inset + var inset = scrollView.contentInset + if position == .Top { + inset.top = originalTopInset+height + } else if position == .Bottom { + inset.bottom = originalBottomInset+height + } + setContentInset(inset, animated: true) + } else { + state = .Stopped + updateContainerView(state) + if !shouldHideWhenStopLoading() { + var inset = scrollView.contentInset + inset.top = 0.0 + inset.bottom = 0.0 + setContentInset(inset, animated: true) + } + } + } + } + + private func scrollViewDidChangeContentSize(scrollView: UIScrollView, contentSize: CGSize) { + updateContainerFrame() + if position == .Bottom { + self.backgroundViewTopConstraint?.constant = max(scrollView.contentSize.height, CGRectGetHeight(scrollView.bounds)) + if changingContentInset { + scrollToBottom(true) + } + } + } + + private func scrollViewDidScroll(scrollView: UIScrollView, contentOffset: CGPoint) { + if scrollView.dragging && state == .Stopped { + state = .Dragging + updateContainerView(state) + } + var y: CGFloat = 0.0 + + if position == .Top { + y = -(contentOffset.y) + } else if position == .Bottom { + y = -(scrollView.contentSize.height - (contentOffset.y + CGRectGetHeight(scrollView.bounds) + originalBottomInset)) + } + if y > 0 { + if state == .Dragging { + containerView.dragging(y/height) + } + configureBackgroundHeightConstraint(y, contentInset: scrollView.contentInset) + } + } + + private func configureBackgroundHeightConstraint(contentOffsetY: CGFloat, contentInset: UIEdgeInsets) { + var constant = CGFloat(-1.0) + if position == .Top { + constant = contentOffsetY + contentInset.top + } else { + constant = contentOffsetY + contentInset.bottom + } + if constant > 0 && constant > backgroundViewHeightConstraint?.constant { + backgroundViewHeightConstraint?.constant = constant + } + } + + func updateContainerView(state: RMRPullToRefreshState) { + containerView.updateView(state, result: self.result) + } + + func updateContainerFrame() { + if let scrollView = self.scrollView, let position = self.position { + var frame = CGRectZero + switch (position) { + case .Top: + frame = CGRectMake(0, -height, CGRectGetWidth(scrollView.bounds), height) + case .Bottom: + let y = max(scrollView.contentSize.height, CGRectGetHeight(scrollView.bounds)) + frame = CGRectMake(0, y, CGRectGetWidth(scrollView.bounds), height) + } + + self.containerView.frame = frame + } + } + + func resetContentInset() { + if let scrollView = scrollView, let position = self.position { + var inset = scrollView.contentInset + switch (position) { + case .Top: + inset.top = originalTopInset + case .Bottom: + inset.bottom = originalBottomInset + } + setContentInset(inset, animated: true) + } + } + + func setContentInset(contentInset: UIEdgeInsets, animated: Bool) { + changingContentInset = true + UIView.animateWithDuration(0.3, + delay: 0.0, + options: UIViewAnimationOptions.BeginFromCurrentState, + animations: { () -> Void in + self.scrollView?.contentInset = contentInset + }, completion: { (finished) -> Void in + self.changingContentInset = false + }) + } + + func checkContentSize(scrollView: UIScrollView) -> Bool{ + let height = CGRectGetHeight(scrollView.bounds) + if scrollView.contentSize.height < height { + scrollView.contentSize = CGSizeMake(scrollView.contentSize.width, height) + return false + } + return true + } + + func shouldHideWhenStopLoading() -> Bool{ + return (result != .Error) || (result == .Error && hideWhenError) + } + + func hideDelay(result: RMRPullToRefreshResultType) -> NSTimeInterval { + if let delay = hideDelayValues[result] { + return delay + } + return 0.0 + } + + // MARK: - KVO + + public func subscribeOnScrollViewEvents() { + if !subscribing, let scrollView = self.scrollView { + scrollView.addObserver(self, forKeyPath: RMRPullToRefreshConstants.KeyPaths.ContentOffset, options: .New, context: nil) + scrollView.addObserver(self, forKeyPath: RMRPullToRefreshConstants.KeyPaths.ContentSize, options: .New, context: nil) + scrollView.addObserver(self, forKeyPath: RMRPullToRefreshConstants.KeyPaths.PanState, options: .New, context: nil) + subscribing = true + } + } + + public func unsubscribeFromScrollViewEvents() { + if subscribing, let scrollView = self.containerView.superview { + scrollView.removeObserver(self, forKeyPath: RMRPullToRefreshConstants.KeyPaths.ContentOffset) + scrollView.removeObserver(self, forKeyPath: RMRPullToRefreshConstants.KeyPaths.ContentSize) + scrollView.removeObserver(self, forKeyPath: RMRPullToRefreshConstants.KeyPaths.PanState) + subscribing = false + } + } + + override public func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer) { + if keyPath == RMRPullToRefreshConstants.KeyPaths.ContentOffset { + if let newContentOffset = change?[NSKeyValueChangeNewKey]?.CGPointValue, scrollView = self.scrollView { + scrollViewDidScroll(scrollView, contentOffset:newContentOffset) + } + } else if keyPath == RMRPullToRefreshConstants.KeyPaths.ContentSize { + if let newContentSize = change?[NSKeyValueChangeNewKey]?.CGSizeValue(), scrollView = self.scrollView { + if checkContentSize(scrollView) { + scrollViewDidChangeContentSize(scrollView, contentSize: newContentSize) + } + } + } else if keyPath == RMRPullToRefreshConstants.KeyPaths.PanState { + if let rawValue = change?[NSKeyValueChangeNewKey] as? Int { + if let state = UIGestureRecognizerState(rawValue: rawValue), scrollView = self.scrollView { + scrollViewDidChangePanState(scrollView, panState: state) + } + } + } + } + +} \ No newline at end of file diff --git a/Classes/RMRPullToRefreshView.swift b/Classes/RMRPullToRefreshView.swift new file mode 100644 index 0000000..a748f95 --- /dev/null +++ b/Classes/RMRPullToRefreshView.swift @@ -0,0 +1,25 @@ +// +// RMRPullToRefreshView.swift +// RMRPullToRefresh +// +// Created by Merkulov Ilya on 03.04.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit + +public class RMRPullToRefreshView: UIView, RMRPullToRefreshViewProtocol { + + var pullToRefreshIsLoading = false + + // Begin Loading + public func prepareForLoadingAnimation(startProgress: CGFloat) {} + public func beginLoadingAnimation() {} + + // End Loading + public func willEndLoadingAnimation() {} + public func didEndLoadingAnimation(hidden: Bool) {} + + // Dragging + public func didChangeDraggingProgress(progress: CGFloat) {} +} diff --git a/Classes/RMRPullToRefreshViewProtocol.swift b/Classes/RMRPullToRefreshViewProtocol.swift new file mode 100644 index 0000000..73f20f9 --- /dev/null +++ b/Classes/RMRPullToRefreshViewProtocol.swift @@ -0,0 +1,23 @@ +// +// RMRPullToRefreshViewProtocol.swift +// RMRPullToRefreshViewProtocol +// +// Created by Merkulov Ilya on 19.03.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit + +public protocol RMRPullToRefreshViewProtocol { + + // Begin Loading + func prepareForLoadingAnimation(startProgress: CGFloat) + func beginLoadingAnimation() + + // End Loading + func willEndLoadingAnimation() + func didEndLoadingAnimation(hidden: Bool) + + // Dragging + func didChangeDraggingProgress(progress: CGFloat) +} \ No newline at end of file diff --git a/Example/Podfile b/Example/Podfile new file mode 100644 index 0000000..4ea4e4b --- /dev/null +++ b/Example/Podfile @@ -0,0 +1,5 @@ +source 'https://github.com/CocoaPods/Specs.git' + +use_frameworks! + +pod 'RMRPullToRefresh', :git => "https://git.redmadrobot.com/im/RMRPullToRefresh" \ No newline at end of file diff --git a/Example/RMRPullToRefresh/AppDelegate.swift b/Example/RMRPullToRefresh/AppDelegate.swift new file mode 100644 index 0000000..97353b2 --- /dev/null +++ b/Example/RMRPullToRefresh/AppDelegate.swift @@ -0,0 +1,46 @@ +// +// AppDelegate.swift +// RMRPullToRefresh +// +// Created by Merkulov Ilya on 19.03.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func applicationWillResignActive(application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(application: UIApplication) { + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/Example/RMRPullToRefresh/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..118c98f --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,38 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/beeline.imageset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/beeline.imageset/Contents.json new file mode 100644 index 0000000..d7244ea --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/beeline.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "beeline.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/beeline.imageset/beeline.png b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/beeline.imageset/beeline.png new file mode 100644 index 0000000..c8acce7 Binary files /dev/null and b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/beeline.imageset/beeline.png differ diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_satellite.imageset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_satellite.imageset/Contents.json new file mode 100644 index 0000000..62d99fa --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_satellite.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_satellite.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_satellite.imageset/icon_satellite.pdf b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_satellite.imageset/icon_satellite.pdf new file mode 100644 index 0000000..dadc9d0 Binary files /dev/null and b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_satellite.imageset/icon_satellite.pdf differ diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_big.imageset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_big.imageset/Contents.json new file mode 100644 index 0000000..e5c19f9 --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_big.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_wave_big.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_big.imageset/icon_wave_big.pdf b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_big.imageset/icon_wave_big.pdf new file mode 100644 index 0000000..6406faf Binary files /dev/null and b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_big.imageset/icon_wave_big.pdf differ diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_big_right.imageset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_big_right.imageset/Contents.json new file mode 100644 index 0000000..488be80 --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_big_right.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_wave_big_right.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_big_right.imageset/icon_wave_big_right.pdf b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_big_right.imageset/icon_wave_big_right.pdf new file mode 100644 index 0000000..b68dc52 Binary files /dev/null and b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_big_right.imageset/icon_wave_big_right.pdf differ diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_medium.imageset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_medium.imageset/Contents.json new file mode 100644 index 0000000..af686e4 --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_medium.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_wave_medium.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_medium.imageset/icon_wave_medium.pdf b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_medium.imageset/icon_wave_medium.pdf new file mode 100644 index 0000000..cba9d85 Binary files /dev/null and b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_medium.imageset/icon_wave_medium.pdf differ diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_medium_right.imageset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_medium_right.imageset/Contents.json new file mode 100644 index 0000000..deefab1 --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_medium_right.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_wave_medium_right.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_medium_right.imageset/icon_wave_medium_right.pdf b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_medium_right.imageset/icon_wave_medium_right.pdf new file mode 100644 index 0000000..11d8a33 Binary files /dev/null and b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_medium_right.imageset/icon_wave_medium_right.pdf differ diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_small.imageset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_small.imageset/Contents.json new file mode 100644 index 0000000..0e2122c --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_small.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_wave_small_right.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_small.imageset/icon_wave_small_right.pdf b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_small.imageset/icon_wave_small_right.pdf new file mode 100644 index 0000000..8097e4b Binary files /dev/null and b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_small.imageset/icon_wave_small_right.pdf differ diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_small_right.imageset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_small_right.imageset/Contents.json new file mode 100644 index 0000000..680dbda --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_small_right.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon_wave_small.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_small_right.imageset/icon_wave_small.pdf b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_small_right.imageset/icon_wave_small.pdf new file mode 100644 index 0000000..93fa3dd Binary files /dev/null and b/Example/RMRPullToRefresh/Assets.xcassets/Beeline/icon_wave_small_right.imageset/icon_wave_small.pdf differ diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Perekrestok/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Perekrestok/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Perekrestok/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Perekrestok/example_perekrestok.imageset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Perekrestok/example_perekrestok.imageset/Contents.json new file mode 100644 index 0000000..a550cf6 --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Perekrestok/example_perekrestok.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "ico-logo-loader2.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Perekrestok/example_perekrestok.imageset/ico-logo-loader2.pdf b/Example/RMRPullToRefresh/Assets.xcassets/Perekrestok/example_perekrestok.imageset/ico-logo-loader2.pdf new file mode 100644 index 0000000..458e9e6 --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Perekrestok/example_perekrestok.imageset/ico-logo-loader2.pdf @@ -0,0 +1,233 @@ +%PDF-1.5 % +10 0 obj <>/OCGs[14 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 13 0 obj <>stream + + + + + 2015-10-14T08:13:22Z + 2015-10-14T13:01:03+04:00 + 2015-10-14T13:01:03+04:00 + + + + 256 + 256 + JPEG + /9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAAEAAwER AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE 1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp 0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo +DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7 FXYq7FXYq7FXYq7FXYq7FXYq7FWP6t500yzLR2/+lzjYhDRAfd/6ZqNV2xix7R9cvs+bEyYte+ct cuSQkot0P7MQof8AgjVvxzR5u188+R4R5I4komvLuc1nnklJ682Zv1nNfPLOX1En4oUsrQrwX99A QYLiSKn8jsv6jlsM+SH0yI+KU4sfO2tW5AldbmMfsyCh/wCCWh+/Njh7Zzw5niHmniZTpPnDSr8r G5NrcHokhHEn/Jfp99M3ul7WxZdj6Zef62QKe5tEuxV2KuxV2KuxV2KuxV2KuxV2KuxV2KuxV2Ku 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 7FXYq7FXYq7FX//Z + + + + Mac OS X 10.11 Quartz PDFContext + 1 + False + False + + 36.000000 + 36.000000 + Pixels + + + + Cyan + Magenta + Yellow + Black + + + + + + Default Swatch Group + 0 + + + + application/pdf + proof:pdf + uuid:c5304f43-e229-3247-b9a4-d8c7436817da + uuid:67b8cc9c-8c1e-844c-810c-8723ee004a78 + + + + + + + + + + + + + + + + + + + + + + + + + endstream endobj 3 0 obj <> endobj 2 0 obj <>/Resources<>/Properties<>>>/Thumb 19 0 R/TrimBox[0.0 0.0 36.0 36.0]/Type/Page>> endobj 16 0 obj <>stream +HV1$7 +}`")R`.=ȿw53 \X`5ݒb맷-I{iee-IVŋjGZ,Rdc)&WiSj6ZVKe6ϷtX K5φ[ڄ*]U{-C߮XG޳!4Yf Ƒ | LO'RF#;+ZmzE$c+c72إ#dx[pZ?spH-^g}Af}9y듈k A +H#7y60H*}Hp_&t~(BPguyt"VZ`!Hu'BEU(YC RD+>xN5=rQ6>l +ic%7ID{o ~8TTXwuf@N2(XF/LmUC \GuҔڅ>P;3#FeѦ<| Z&48\(-A FöXU%!IkeQiQ#-,zR6z۰7Lz @"tKW {||aq=Ra`5JD~R}ꛙH97q]`uQ$O}jacʶ ݰ5o},AĦ.0ej ?ADv9j鉢 +?yfyJF4#z. G>1'.<=p r"}V[cǓJL1 $-??u<:O c B endstream endobj 19 0 obj <>stream +8;Xp,I:_a;l`I95]W9\1KmD>P!Xo'&n-5?~> endstream endobj 20 0 obj [/Indexed/DeviceRGB 255 21 0 R] endobj 21 0 obj <>stream +8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0 +b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup` +E1r!/,*0[*9.aFIR2&b-C#soRZ7Dl%MLY\.?d>Mn +6%Q2oYfNRF$$+ON<+]RUJmC0InDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j$XKrcYp0n+Xl_nU*O( +l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 14 0 obj <> endobj 22 0 obj [/View/Design] endobj 23 0 obj <>>> endobj 18 0 obj <> endobj 17 0 obj <> endobj 24 0 obj <> endobj 25 0 obj <>stream +%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 17.0 %%AI8_CreatorVersion: 19.1.0 %%For: (Katrin) () %%Title: (ico-logo-loader2.pdf) %%CreationDate: 14/10/15 13:01 %%Canvassize: 16383 %%BoundingBox: 2 -2 34 32 %%HiResBoundingBox: 2 -1.00000000000182 34 31.0000000000027 %%DocumentProcessColors: Cyan Magenta Yellow Black %AI5_FileFormat 13.0 %AI12_BuildNumber: 29 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%RGBProcessColor: 0 0 0 ([Registration]) %AI3_Cropmarks: 0 -3 36 33 %AI3_TemplateBox: 15.5 16.5 15.5 16.5 %AI3_TileBox: -261.5 -365 297.5 418 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 6 %AI9_ColorModel: 1 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI17_Begin_Content_if_version_gt:17 1 %AI9_OpenToView: -136.666666666667 108.666666666667 6 1829 1003 26 0 0 46 133 0 0 0 1 1 0 1 1 0 1 %AI17_Alternate_Content %AI9_OpenToView: -136.666666666667 108.666666666667 6 1829 1003 26 0 0 46 133 0 0 0 1 1 0 1 1 0 1 %AI17_End_Versioned_Content %AI5_OpenViewLayers: 7 %%PageOrigin:-484 -484 %AI7_GridSettings: 8 4 8 4 0 0 0.800000011920929 0.800000011920929 0.800000011920929 0.899999976158142 0.899999976158142 0.899999976158142 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 26 0 obj <>stream +%%BoundingBox: 2 -2 34 32 %%HiResBoundingBox: 2 -1.00000000000182 34 31.0000000000027 %AI7_Thumbnail: 128 128 8 %%BeginData: 13748 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FD4FFFAECEA6A681A681A681ACA6ADA7FD70FFA7A781817BA58181 %81A6818181A5818181A6A6CFFD69FFCFAD81A581A681A681A681A681A681 %A681A681A681A581A6A7FD66FFA7817B8181817BA581817BA581817BA581 %817BA581817BA5818181CFFD63FFA6A581A681A681A681A681A681A681A6 %81A681A681A681A681A681A681ADCFFD5FFFAD81A5818181A6818181A681 %8181A6818181A6818181A6818181A6818181A68181A7FD5DFFAD81A581A6 %81A681A681A681A681A681A681A681A681A681A681A681A681A681A681A5 %A7FD5BFFA77AA581817BA581817BA581817BA581817BA581817BA581817B %A581817BA581817BA5818182FD59FFAD81A681A681A681A681A681A681A6 %81A681A681A681A681A681A681A681A681A681A681A681A5A7FD57FFAD81 %8181A6818181A6818181A6818181A6818181A6818181A6818181A6818181 %A6818181A6FD0481A7FD55FFCF81A681A681A681A681A681A681A681A681 %A581A581A581A581A681A681A681A681A681A681A681A681A5ADFD54FF81 %817BA581817BA581817BA581817B8181A682ADA7AEA7ADA6A67B8181817B %A581817BA581817BA581817BA5A8FD52FFA7A581A681A681A681A681A681 %A681A6A6CFFD0AFFA7A681A681A681A681A681A681A681A681ACFD51FFA8 %A5818181A6818181A6818181A681A6A8FD0DFFCFA781A5818181A6818181 %A6818181A681AEFD50FFAD81A681A681A681A681A681A681ADFD11FFCF82 %A581A681A681A681A681A681A682FD4FFFCF81817BA581817BA581817BA5 %81A7FD14FF828181817BA581817BA581817B81A7FD4EFFA7A581A681A681 %A681A681A681ADFD16FFA6A581A681A681A681A681A681A6FD4DFFA8A681 %8181A6818181A681817BA6FD18FF828181A6818181A6818181A681CFFD4C %FFCF81A681A681A681A681A681A6AEFD19FF81A681A681A681A681A681A5 %A7FD4CFF82817BA581817BA581817B81A6FD1AFFAD81817BA581817BA581 %817BA6FD4CFFA681A681A681A681A681A681FD1CFFA681A681A681A681A6 %81A681FD4BFFCF818181A6818181A681817BADFD1CFFA68181A6818181A6 %FD0481A7FD4AFFA7A581A681A681A681A681A5A7FD1CFFCF81A681A681A6 %81A681A681CEFD4AFFAD7BA581817BA581817BA581CFFD1CFFA8A681817B %A581817BA5818182FD4AFFA7A581A681A681A681A681A6FD1EFFA6A681A6 %81A681A681A681ADFD4AFFA77BA6818181A6818181A582FD1EFFA7818181 %A6818181A6818182FD4AFFA7A581A681A681A681A681ACFD1EFFA6A581A6 %81A681A681A681ADFD4AFFAD81817BA581817BA5818181FD1EFFA67BA581 %817BA581817B8182FD4AFFA7A581A681A681A681A681ACFD1EFF82A681A6 %81A681A681A681ADFD4AFFAD818181A6818181A6818181FD1DFFAE8181A6 %818181A6FD0481A7FD4AFFA7A581A681A681A681A681A5A7FD1CFFCF81A6 %81A681A681A681A681CFFD4AFFCF7BA581817BA581817BA581A7FD1CFF82 %8181817BA581817BA58181A8FD4AFFCFA681A681A681A681A681A682FD1B %FFCFA681A681A681A681A681A681FD4CFF82A5818181A6818181A68181A8 %FD1AFFA67BA6818181A6818181A681A6FD4CFFAD81A681A681A681A681A6 %81CFFD19FFCF81A681A681A681A681A681A5A7FD4CFFA7817BA581817BA5 %81817B81A6FD19FFFD04817BA581817BA5818181FD4EFF81A681A681A681 %A681A681A6FD18FF82A681A681A681A681A681A681ADFD4EFFA681A68181 %81A6818181A681CFFD16FF828181A6818181A6818181A68181A8FD4EFFA7 %A581A681A681A681A681A5A7FD14FFCF81A581A681A681A681A681A681A5 %A7FD4FFFCF81817BA581817BA581817BA7FD12FFA8AD81817BA581817BA5 %81817BA581817BFD51FFA681A681A681A681A681A682FD10FFCFA6A681A6 %81A681A681A681A681A681A681CFFD51FFA68181A6818181A6818181A5AE %FD0BFFAEAEA6A6818181A6818181A6818181A6818181A681A6FD52FFCF81 %A681A681A681A681A681CFFD08FFAEAD82A681A581A681A681A681A681A6 %81A681A681A681A6FD53FFA8A681817BA581817BA5818182FFFFFFAECFA7 %A6FD04817BA581817BA581817BA581817BA581817BA68181A8FD54FFA6A5 %81A681A681A681A681ACCFCFA7AC81A581A681A681A681A681A681A681A6 %81A681A681A681A681A6A8FD55FFAD818181A6818181A6818181A6818181 %A6818181A6818181A6818181A6818181A6818181A6818181A5A7FD56FFA8 %A681A681A681A681A681A681A681A681A681A681A681A681A681A681A681 %A681A681A681A681A6A8FD58FFFD04817BA581817BA581817BA581817BA5 %81817BA581817BA581817BA581817BA581817BA6AEFD59FFAD81A681A681 %A681A681A681A681A681A681A681A681A681A681A681A681A681A681A581 %CFFD5BFFA7FD0481A6818181A6818181A6818181A6818181A6818181A681 %8181A681817BA5A6FD5EFF81A681A681A681A681A681A681A681A681A681 %A681A681A681A681A681A581ADAEFD5FFFA67BA581817BA581817BA58181 %7BA581817BA581817BA581817B8181A6A7FD62FFA7A581A681A681A681A6 %81A681A681A681A681A681A581A682ADAEFD65FFCF81A6818181A6818181 %A6818181A681817B8181A6A6CFAEFD69FFA681A681A681A681A681A681A5 %81A682ADA7FD6EFF82817BA581817B8181817BA6A6ADA8FD71FFCF81A681 %A581A682ADA7FD76FFAE8181A682ADA8FD7AFFA7CFCFFD1DFFA8AFA8A8A8 %FD76FF847D522EFD04050405050527597DA8FD6DFF7D59050504FD060527 %FD0405040505527DFD67FFA8592E0505F805040505050405050504050505 %04050505F8050559A8FD60FFA8A8522EFD05052705050527050505270505 %052705050527FD0405042759FD5CFFA87D2E05F805040504050505040505 %05040505050405050504050505040505050405040505A8FD57FF84592727 %040505270505052D0505052D0505052D0505052D0505052D0505052D0505 %052DFD05057DFD52FFAF59520505F8050405050504050505040505050405 %05050405050504050505040505050405050504FD0505F858FD4DFFAEA859 %2EFD05052705050527050505270505052705050527050505270505052705 %0505270505052705050527FD04050459FD4CFF7DF8050405040505050405 %050504050505040505050405050504050505040505050405050504050505 %04050505040505050405F852FD4BFF83FD04052D0505052D0505052D0505 %052D0505052D0505052D0505052D050505270505052D0505052D0505052D %0505052D0505047DFD3DFFAFAE838359FD09FFFD04050405050504050505 %04050505040505050405050504050505F80504050405F805040505050405 %05050405050504050505F8A8FD39FFA88334340B110B11A8FD08FF2E0427 %05050527050505270505052705050527FD060504272E5959A8A8A87D7D2E %2DF8FD0405270505052705050527050505FD34FFAEAE83580B110B0B0B33 %0B110B83FD08FF5205040505050405050504050505040505050405F805F8 %2D527DA8FD09FFA87D0505040504050505040505050405050552FD31FFAE %59580B110B340B340B340B340B3458FD08FFA805270505052D0505052D05 %0505270505040505527DAFFD10FF7D2D042D0505052D0505052DFD0405A8 %FD2CFFA88334340B0B0B340B330B340B330B340B330B34AEFD07FFA80504 %0505050405050504050505F8052D597DFD15FFA82EF80505050405050504 %050505F858FD29FFA88334340B110B340B340B340B340B340B340B340B34 %0BAEFD08FF2E050527050505270505052D5284A8FD1AFF58F82705050527 %05050527050505FD26FF83590B110B0B0B330B110B330B110B330B110B33 %0B110B330B0B58FD08FF59F805040505050405050504FD1EFF2EF8050505 %040505050405050558FD22FF835F11110B340B340B340B340B340B340B34 %0B340B340B340B340B340B58FD08FF8405052D0505052DFD04057DFD1DFF %A82E0505052D0505052D0505052EFD1FFFA85F0B0B0B330B330B340B330B %340B330B340B330B340B330B340B330B340B110BAFFD08FF050504050505 %04050505F859FD1EFF7D050505040505050405050504AFFD1DFF58330B34 %0B340B340B340B340B340B340B340B340B340B340B340B340B340B340B11 %83FD08FF2E0505052705050527050527FD1FFF27FD040527050505270505 %7DFD1BFF830B0B0B110B330B110B330B110B330B110B330B110B330B110B %330B110B330B110B330B59FD08FF52050505040505050405040584FD1EFF %7DF8050505040505050405F859FD19FFAE580B340B340B340B340B340B34 %0B340B340B340B340B340B340B340B340B340B340B340B3433FD08FFA805 %05052D0505052D05050484FD1EFFA82D0505052D0505052D05052EFD18FF %84340B330B340B330B340B330B340B330B340B330B340B330B340B110B34 %0B330B340B330B340B0B84FD07FFA805050504050505040505052EFD1FFF %270505050405050504050527FD17FF84330B340B340B340B340B340B340B %340B340B340B340B340B340B110B340B340B340B340B340B340B83FD08FF %2DFD04052705050527052DFD1FFF590427050505270505052705FD16FF83 %110B330B330B110B330B110B330B110B330B110B33FD050B345884A8340B %330B110B330B110B1134FD08FF59F805050504050505040504A8FD1EFF58 %0504050505040505050405FD15FFA8340B340B340B340B340B340B340B34 %0B340B340B340B332D5F83AFFD04FF58340B340B340B340B340B34AEFD07 %FF7DFD04052D0505052D050559FD1EFF7DF82D0505052D0505052D05FD14 %FFA8340B340B330B340B330B340B330B340B110B110B33348384FD08FF83 %0B340B330B340B330B340B84FD07FFAFFD0405040505050405042EFD1EFF %590504050505040505050405FD14FF590B340B340B340B340B340B340B34 %0B110B3458A8AEFD0BFFA8340B340B340B340B340B1159FD08FF2E042705 %050527FD0505FD1EFF590405052705050527050505FD13FF830B330B110B %330B110B330B110B330B1134A8AEFD0FFF2D0B0B330B110B330B110B34FD %08FF5205040505050405050504057DFD1DFF2D050505040505050405042D %FD13FF0B340B340B340B340B340B340B340B5FA8FD12FF5F0B340B340B34 %0B340B340BAFFD07FF8404270505052D0505052D047DFD1CFFAF2E050505 %2D0505052D05052EFD12FF580B0B340B330B340B330B340B0B0BAEFD14FF %830B0B340B330B340B330B117DFD07FFA8050405050504050505040527FD %1CFF84F8050505040505050405F859FD11FFA8340B340B340B340B340B34 %0B1134FD17FF0B340B340B340B340B340B5FFD08FF2D05052705050527FD %0405A8FD1BFF5205052705050527FD04057DFD11FF590B330B110B330B11 %0B330B0B2DFD17FFA8340B110B330B110B330B0B0BFD08FF59F805040505 %0504050505F859FD1AFFA8050405040505050405050504AEFD11FF0B340B %340B340B340B340B340BFD19FF59110B340B340B340B340B3484FD07FF83 %05052D0505052DFD0505FD1AFF590505052D0505052D05050452FD11FF83 %0B0B340B330B340B330B340B84FD19FF840B330B340B330B340B330B83FD %08FF05050405050504050505040552FD18FFA8F805050504050505040505 %0559FD11FF5F0B340B340B340B340B340B5FFD1AFFA8340B340B340B340B %340B1134FD08FF590405052705050527FD040584FD17FF05050527050505 %27FD0505FD12FF0B110B110B330B110B330B0BA8FD1BFF2D110B110B330B %110B330B33A8FD07FF7D0505050405050504050505F805A8FD15FF270505 %050405050504050505F852FD11FFA8340B340B340B340B340B1134FD1CFF %830B340B340B340B340B340BAFFD08FF2D05052D0505052D0505052D052E %A8FD13FF2EFD04052D0505052DFD0405A8FD11FF830B340B330B340B330B %340B84FD1CFF83110B330B340B330B340B0B83FD08FF83F8050405050504 %050505040504057DFD10FFA805050405050504050505040505052EFD12FF %59110B340B340B340B340B34AEFD1CFFAF0B340B340B340B340B340B83FD %09FF2E05050527050505270505052705052EFD0EFF7DFD05052705050527 %FD0505AFFD12FF590B110B330B110B330B0B2DFD1DFFA8340B330B110B33 %0B110B0B58FD09FF7D050405040505050405050504050405045984FD08FF %A85227F805040505050405050504050505F87DFD13FF58330B340B340B34 %0B340B5FFD1EFF34340B340B340B340B340B83FD0AFF5205052D0505052D %0505052DFD040504050559597D597D522EFD05052D0505052D0505052D05 %050452FD14FF590B330B340B330B340B0B34FD1EFF340B340B330B340B33 %0B1158FD0BFFFD0605040505050405050504050505F805F805F805040504 %050505040505050405050504050405A8FD14FF34330B340B340B340B340B %59FD1EFF34330B340B340B340B340B83FD0BFFA805050527050505270505 %0527050505270505052705050527050505270505052705050527FD040584 %FD15FF580B330B110B330B110B1134FD1DFFA8340B110B330B110B330B0B %58FD0CFF84F8050405050504050505040505050405050504050505040505 %050405050504050505040504057DFD16FF58340B340B340B340B340B34FD %1EFF0B340B340B340B340B340B84FD0DFF84FD05052D0505052D0505052D %0505052D0505052D0505052D0505052D0505052D05057DFD17FF830B340B %330B340B330B340BA8FD1CFF83110B330B340B330B340B0B83FD0EFF8404 %050505040505050405050504050505040505050405050504050505040505 %05F8057DFD18FF83110B340B340B340B340B1159FD1CFF5F0B340B340B34 %0B340B340BAEFD0FFFAFFD05052705050527050505270505052705050527 %05050527FD0405042EA8FD19FFAE0B110B330B110B330B110B34A8FD1AFF %AF0B110B330B110B330B110B34AEFD11FF2E05F805040505050405050504 %050505040505050405050504050505F859A8FD1BFF340B340B340B340B34 %0B340B83FD1AFF59110B340B340B340B340B3458FD13FFA82E04FD04052D %0505052D0505052D0505052D0505052705052DA8FD1DFF580B0B340B330B %340B330B330BAEFD18FFA8340B330B340B330B340B330B84FD15FF842705 %F80504050505040505050405050504050405F82E7DFD1FFFAE0B340B340B %340B340B340B3334FD18FF580B340B340B340B340B340B34A8FD17FF8459 %0505F8FD09050405052E58A8FD21FFA8340B110B330B110B330B110B0B34 %FD16FF5F0B110B330B110B330B110B0B58FD1BFF847D2E2E050505270527 %275859A8A8FD24FF83110B340B340B340B340B340B1134FD14FF830B340B %340B340B340B340B340BAEFD4FFF2D0B0B340B330B340B330B340B0B2DAE %FD11FF5F0B340B330B340B330B340B330B59FD50FF840B340B340B340B34 %0B340B340B110B83AFFD0DFFA8580B340B340B340B340B340B340B33A8FD %51FF580B330B330B110B330B110B330B110B3458A8A8FD07FFA8A8340B0B %330B110B330B110B330B110B0B58FD52FFA8340B340B340B340B340B340B %340B340B110B34598383AE838358340B110B340B340B340B340B340B340B %3434FD54FF830B0B340B330B340B330B340B330B340B110B110B0B0B110B %0B0B340B330B340B330B340B330B340B110BA8FD55FF59110B340B340B34 %0B340B340B340B340B340B340B340B340B340B340B340B340B340B340B34 %0B340B83FD57FF580B0B330B110B330B110B330B110B330B110B330B110B %330B110B330B110B330B110B330B110B5FFD59FF58110B340B340B340B34 %0B340B340B340B340B340B340B340B340B340B340B340B340B340B5FFD5B %FF59110B330B340B330B340B330B340B330B340B330B340B330B340B330B %340B330B330B5FFD5DFF83340B340B340B340B340B340B340B340B340B34 %0B340B340B340B340B340B110B84FD5FFFA8580B0B0B330B110B330B110B %330B110B330B110B330B110B330B110B0B34A8FD62FFA834110B340B340B %340B340B340B340B340B340B340B340B340B3483FD66FF83340B0B0B340B %330B340B330B340B330B340B110B110B83A8FD69FFAE59340B110B330B34 %0B340B340B110B34335983FD6EFFAFA8595F34340B330B110B34348383FD %4EFFFF %%EndData endstream endobj 27 0 obj <>stream +HWn:;p"jGK_NҴٓaAEa&r>e'Ӟ]us8s0jc1!mc֛7ǒ`%!2RtX*E{}d:gRvl<իJRAtM# h31_8&$~`0{`[lв9NSU+}7pAv$2S>=OAm]:H$]WChˏӃ'"fIcLst迄1Z@7>@3 dAvGee6 R0Vo-f  di~8GBoL ~aVd^.r}亹&lU h; {t~v ,!sJѥ$g/(ߞnײ\38UEa |ag/s5S`c˔dٽPWލyp|~-nL*m; +X&"7vAU/ix\M׽{ƻ] w%)v] iu+JB]$ JDA>;ڙ:#?3]nAuoY ٺ4`<`>H%gN8H~=:Yz`V*Rk\`25/3F'4z _] .@%YZ1ݫGėb]UU +7D3|ܐbt5е,x0 jTp:/È!Cc +m3z*?tsʟkdXG!4i1٢>p,\J΁\ l"MgҫI(-REf;ȣ*=&aq ec禶0\ KH6;aE*=b qBL%rT%^WUk0?x>8c>:3޶FCRB,tղjSn1-,+po{~x7r; nwZZߵ mUx𰀇?AS@X(e[9Z&_ hN@Li}07 ~m=QkpT[-{ +d[*?? +1Zn0^Z,+nPdF ,%|f WI4ڗ?~ û$<8 K-t_ڽt<2}vt:,+Znq89$]yMٙ@ׄT0_v3TG}95ȏMr+?h3{{k #M +NNpk+WN/R%f:j5C®0ib`)pzYZzBp-3Bw -DD9AbNd tEBOH)YJ~זH*"s)!3̣^>_f34$`{6:)j%2?)(T&*7 ޣ~E[ʊL%ڱ1fxJ@$YaqjMpYr`@p'VwU 01tD&AI1UxBUEaX?;+ -sz~aAx<ԃ̇ef6QG,EU*{#SFv6qC#MG- ?C㡠۵;׺U?(7޹(epHcVcIU-:MX}Y z A2!dbU.f'AJ8co +V'V ]--玔K r0v 3*6ಿ8( +FlH3<FAH{#b{LdQNPx(ם}wwgv[skQp`E=1.H"Լ+y``hj#k&CJ,cxޫ5B1WaFqڌxO1ۭ tav7qӇ+-MZCAi5uW'S͢3ϔ.W{-pX?v9Majz7Д淰D/lrK,m]^-\mLm I + nm%qq,c7[v{Np;FsXkQMG.~-8Ǥ:j;j*l|Jj5`hjyJTjЮ3Uʭv*j&{#,hǛ~j*&>7T)ӈv%uV>q=ؗRE0Nt>]lHF*d<];g+ A?`P3]qbqcE! +W[ _`푩cX#amcΕ="z*hQݎaM3+m^-`? H#3@iALdGa P3Cըg +"j Ug/EQk.u{=wsH_ XhjB\cd.Be*]u}bs3rE3.dGgQxF .ƢRjVy5tkEXf$)WZIPU/H]1(fOyoj0~W1v}`tIp)6^Zy3$ɍ\r -9f_%^16yɮa$֍'^c 9j$;Q� 4>Wn[}~W4AĘ1qx<}S3]*&֍\SgtWW)M2.avWe0廆G62^AF +~YVsvZr˵KhJrL$Qui9mzI깢&F*&Ջb!canHMh6v@ ({tzv_ JV䎔BML0Ȯ@m02涸=_8}8\N +MAzF"_{]nO[H͟#skƌ/D<h6@{C%9zgʨsB [ l:K>ڄ#<Rd=Jւ31Ƅ^_mx$L~LMlOgS"^*]RgBT4gz'UBcQ(l;WUe`lJi` X-&r[ +9WЗr#!^(+HP$L9W7W)Ĝ35_>r٬Kd*FKq#%_C}5FoIy-Ot0nͼBX>f|%7Qa$˲\0`I]k.ۮWP"P:זE#`YH'OVKdQv"Ǯ40g0ؘf;[}UtPhWTLg`o.]I#>SdRex@9pUnX6XG9BrƱ-H‘1Vߪ&VL+2]P)(^QEi~UlW&Q~F[ R0i˚0xu>'[uqU[.G΋*ܛc-N͡0:$lʀpZɀ1Of /(6l=j^rؑ1ɡ4r4r`ci$5C>6JCIRC;D]h8]xF`|C۰da ?w:U2) +*MćDA!!Jkb@t_fÌ6Hh*:Aw 8+ތ,)jppr\j~}¾ݕw۫A@m҈|>^-OgRp6NMd}T;* {TG{Lӆs r~*9Qv],knaPK˩q9 )+'|Ck%x|$̊%?kjyU TL{ fy><-|*nۧw3ܹؾ}ǾGR} gFa|'1y,5hTH +oV?Mֻq~OK˼A7\K WChA M:bC^vCQ63sf̌W!]=7HPoi*`ARz%H{li4`ʖ^hPsM+T,s 昝`n0LA-U嫷$= +->*XPXP.X7D|X @kkW@zY[ŋe0n< <-/7 !PluaP :e_6JjmJ5Q +Бvn a߮Jvww-ۛ4h-Ide>Dz?ʇ`T`n } L1v1@xRs ACip7!gX5)dJY{+rt);M3Z4lNl|[fgxf}6bB&TŬJl-AШt{x$=I h`<Ȱx5bv*gx6O{_Њ oŐUߖS}şϷԩB 5^j=e/amk˵HSgZ3s8}y|Ɵ=_o1.'K&Q +cli>̩MMتMltBc{o;^Czx1 +O'K:U2BmO^dX<}OsIAec&u:EW3쩇 +/Ƙ_,'y8= ]sU3&f58ftv\@ߢ.dCο:&X|?.n-H+|w} E -nnnFvޠi5iiםT~4:VCt -;k(+ʌP$Z t0F쫷Q*ołҷO7T2^{Hp3PO JOSz`/ ('F_͠<v nz7* f +7 4+'9wWA?&{[K&@Pn5=E "MRp=UyV 4JFtc+$?2k楣=z႗7 >4ʱ0`TtY#|&S$GšR1s4waI|&ͮ,SZ(W3.=4>_UkCiAl`}>00E#dxq,57Kw<|tt284KO*=.G߃DfYz(%ev!sU4zXp7-rCmLU ++t "]˦Jq1@I51$* TUJ>"݋Bl$ژZ6Lk;Bnq9FIt=:3y//V+US:Z(C<LeWJ +R|qPrcneZEoьRʀb2ޜCLkZhɩ .7LVe*di^WͣiKݺA9.v{6="#7:^Us|E3d{̊V~d{ZgRepx>vliZnM2}ݛRfafA)gx˜"+X/Üp0bY\PyIc~6hHPR2 0t سX69j=4en[Vʴ򻱔\!.:F55} EwSދ՛IpC7̊1$'Y̰9ޡL0HIU7H1`)H E~xi8[~;'9v/e4'{Xnc1rrx8U'TpsU$9mCR;K]6B0mahiHM6cݕVWV~V7j\D\yZQwt [rsr^dDT_dȝ~* C- q,mQ6"q\-\4E,5'8 Ȇs8UuNZxq><6h6Λdw0^Y "rž9j]uǥzXaZl':'Ж+K"ACb6M]ufi$JPNÇ?A1V&,/> *ۀ36@5aT+:p,ƺ+o㉆?/^6ǵ6B1ƨRE|,9> ƒƒe&HGK9*0r%Dk; 56SXb1ɲI`\:womߖ+ `W)aaL^WSe\B)+`ĊŇ9YhӎijaX!Nun-vMS--+7 waqYOWZPrd0qB|9C:qi V;a^ ;a[`d1O;liO =uȘfMfk6دe&k 1 d^#HB2rit^DH6»u߁쌾{}V ΄[Lѷ%3e~)e޶H $S5{NU4/ i |;d' u= + +w\Ae|< +ZLtb'0 r_w{X$c&'J\K.T<o{?sWNb6r,r<,1i) AH`ԉ0o|44Z[Vxx3r=[r +ë^ sƞv.bJTc?aĠӬn +T*x29@ Q8f7V enY e~CΙL~RCqJR(ݸ}x}ul~jaST]ȒbV,u>i.UNb\eӴp{; Ê{fy nIN =ZiI}:݄2iv3Н +Xʝ4 8= Ѩ;n7^EG/֑O+_iB:s5s=P3ũDr +6Y/ĕ ?A%$\xг"u]EP`kIIHfI?-ۯk?(Vf >j7ɣx8Gfוh~늩L:80*Ȟܾ|paW6 s~*:k(wD=:ű4_ +%X[TLoKUk_֠=|jWCA0, k SQeP U1cy1nG2KF,'v(u}c(':H,`-;zu5vxWbcZÓ:)^ډ/S'wkɓŲL-]B [1"NGh;B=AZ11"څe74B3L.8.j\uJ4;E^FYLW +^@Z\@ִ'fd3dʄ/Laj%M.`9/bLȭb°B62"qTRDž9lqc~g)sq*qf ,zƏQ:ȟRp!SM"?,20\^(ތ 7"o!i9 'o4Y ᄁ븜!.,nmSי򦄔4О8 O +*IP~z=@~c*Mlq[%YƤT-CvmS.}vnNeK(=Q&*͋J e2b2srlHjOK}U>+$;{2&!P@RDJȩ2dy=O0PGJB4Pcvb" )K0(dJ"5Yۙ)+qHVh1E 9r }GK #r!!I[ބ9uVD=mB_DUqrmǽ5weg^fvh !y+\8cO {uh累:g;W; f02fHT@_֜*OD:-GhU\L}lb8n&wp*(7*d`cT)Ko&C7L>0oDwV@pF.+Q$YK.1ehz_<#-**7E3p_z#N|H>PKMn%h0s96s=$E¼N.7T9;DU;9- o<wpcބmkL-3lvuO%y\X,*29[[ ~1ÌRdw|wBКb?W?L.L#PP|3V BZ$)XeK*נ} 1wD@}qtN8*X b`z"DC;e +_y[XeTr < 9P2Op՚R1i_Șr -"c{1|66Zdz(vd(^2r",CW 'ƞgVL +Qۋ5te(}I w0nFair9KZ9Paa9`W^S_Ill.+0'W{o$ +~ K endstream endobj 28 0 obj <>stream +HW{_J<+V`!ZB~z.Fg<̜9S1dIV*YhʫREpeJk{ynUS6r*z + +ɶXT+9^ßt)/ӗpB.ߢE +$g Njm[_lj mex H2Bm{뗕i!Ɇ!!f_9Pa]X`RIua$ rܺc0<W!z־B$?b'\ĴVI#X-'ɩ}Ze +k$A '<:B($#bUY&-xy?HC?0/ziCl}b~,9nrhckzyQX`B(0&V*#Jv0.V1oPgEﯢ>ӵ"K}c[3.ٮb5^piL֚]ʛ< ÀZjɸ'hjl.5Xxo=P@#y`=,tWUk(>˅z!?݅PW'T5I㒖Ͽث|1kF_q-{߭BL7iBJ|d5:,NGK|E +q/ݔ^hwOi1׭Tk'7'{lq:xZwkJ|8N ӯd7;5$w[^t1/Xu8-.RK)ȅuwnѸNƨ8=kq0pjjeO+:SI #'=W1p4Ƚ$Bؽp&2]<~J/׻\$@t[5AN016!u}!JxNХ5AAekcz,܉- %Q$AP+|c n1;wPv){.Nj%q ߉98uB)spW:~\:11o3%N)rOw|'u2a2!,T9 @H.vPgtUR!!9t(4][c# u-piN&f8 o ~P]܃1Ğh)K2q@a += !:%_lǸ"ԼMHYղke{A1 ܍, Pw,ɼqMYu': }.0p=΍W: 0TH.ø݃INU' Aygˮ>ek2#$/ meE*zlĦ3vU 0ĠIp=spI  X +zq#[ 1iz.5Z1#b~ǃWdH!I4귴9;PJ w[Q,{˺/>$#QIWxv$b3&K zCn++W%|R +HPJcҼu[ s!fRXz?%~zK}fh*\Ji&-=M0 8!ƭ4SVL@&"4ݓa3w9(jb")!~ȐJEr,$҇W=/5:eډǙ6Ź&hIQs|(cKqi}xL=MZJ^ + ѐc1%'$>@AnH޿!9y_}\=[V-DOYmq\IsQpEY(/k>xы@/{Zp I2Zz#5V ,wȎլVg`zբ;v<^O?&xX`J\X$N[9rG(U`d;[W[V{r_c*ȱV*Kh^=N NG,.IyT>0jP>oǧ%71;[ס慣B^4KI  5.Yw%K::F:]h?'u;]u6*V<Z@ŕ7 ^Nug 5T=Цݏx!޽0dH5,+P)ƶ l3FJMm6KP{~q=HԠ1͛2$alYu{G`>jQA"%Tkw]<12qy5 +.,&rG&R,!ɾJ&v){:r,0P$ +ˡ\Jk#-+hcbwx~!ǐr-D1uf4Pc|nUuJiyz^Ykx 0cH sƎC#8D58j1هvCdCʊ$#8BB;c+iS0q Mlr&+LJ[i|Yrk"q&2X.,t9 +`2x=?RcD>3XFcoda'x-ɸ:عf^"gL[S1J\x1 77sa.Me|N!.\Cu׈bӵ"K}cs!V-^]9^kɸ'|Wrx}GWZA*tKBtsxώ]J_vT.Fe0* '<~PN7R`$iL˽vzo6U\uo=k_0ܭ)Ġ6lc0GGxd](<7,fqhg \.;x5 +rڌ9`?[:cE۾.61 $1`*œD3M5!>[:j|o1<&J1Ǯppvqt|cƗqHczm==(rDS: 8M$%w{èѕpn|mK{:\oݿz.oSI7bJfR&E1ovP[i9 ;w,l SDȺO^oٔfW\&2/N_A'/BC (W]U; C*VV[/N?G+]020EH 2_@1pXX9V00ir2*j ,so eJ Q f4㥋`.2*>r <0K'M!s +V+ +Ym^ Qi=:V!SG&a!q2WGL&UcE)CMzS'fRٳ]1WJFLU"?g icI;6ƈr\jP 0h>XK?ėaN^j˃iu]c>s@MlQjk-}J!lrM~pmoZ(w轐V> z?tE%#X?y&Z:MOo9Cpq +ԛKV[އJ̃lQқYF/PtLm_h'nFnꈇIfkoCaB낐zr{2vκ |HlmH5BP;ި`cm9'3:YY`1k/%@䕅c0_^Q|+g]GE] SgC24R}i–|}ˠd f`sǿ[79Tc׳rA'8@\Ebڧ1WB+/kj "!.OÐs^2.gW3vȠZ +ÐKe[XNwhvQ.Y~BKr#YҔQadx>o1lx@2ʗBK +3 m}o* lb](OYS'xIν>IruMOe<Xd4dP}>NS jٗ _ }2ז;|2-徜d +ߡ2PJWrI=} ,%%~9Y7˷;IY~m<%}/ + +VOm_o[o'<]>-KҴVV$KɻyHf\kЖ6TIO+$f;ENL_~ +=W/_W/,[AK+Ʊ3j} v.V; .hέ $$;T)TAA@Z};$@* !̙gfo)@t?1疃vq{,zb|:Ri-:m&ŅmmaN)3d^7ct>vbq4^^gd ŔyR]T'? <~@PH8Std|,>_BT_x"'\-CPC0DێJ:5xqYK(Bbg_~>2Y%Ѳ'ۦPĘ$Kz!:5K blFw(uM aܡ/9_X%WՋ`}N,&jcAj@` 9?*\BD;=dVWg]upk~,]?8U)قMA蘓~ab`WY Kk*K%%`ks//$K ̖˱ +x00#A}/v9;K#Gс0vXܕ.EF-0ԕn&С0ײiێ@OTz(ՙuIe5T0P]mvi-ZAX7 @o:r4Rw lB"nwk՚(\!UCHVS{$̩JX  Eq;h׈RHԛ ]KP.>**~W0Y/UO`^U5v*K

%IƺVGC(l^pO^`>Ӌp_'gy9CW+@2'B i2Niy.]Q8 D_K$ bfo ݳXkKƋe־>XSJG:Y,,~sBP;^`)R'MyBb!R[`*Cu]U-zk ;=J8 +`[y !/&jމT{dEe4%)c:%Rf]lCv(+Nm>;8u,rXguWx4[_RdY3uBP^QB)v?k%ĉm DDd 0ݪ! .;WC ?u:u`$߬X(Zsj rK$Ƣd{RS )vGRVܸV˧c ћW_װ?my6b׻= Ջ+=n-@~a@sr.ſݻt.60hJٰ[zA"ǸoZv-QFd@811O]B_|VaKx_tBCBt|;Y>(aAYQrN>%Z +<:,aNtoU(1O}z2X4q[AL3e1<Y%g`[;9xeݢةkH[Ai{AhsD͟gnNGt&\Jʄ 'g/*D7ׁՒωh:M,s|6Bζ2>I|'ųQHglο2'V5\'JQ =:Ro|X!nNlBMUo)!^!@Ps66.q?5+:fg ݪtN}4,XP*k)X=jhz5Q"2î]񬵢=qi3JJME_,rN::'j}r2n%LMͺu9[iDiL +KJv,;Lsl.Ώymcbl(bӶſٯ*`$*oKIDW$RcX噤To..s8:N]n3fë҃8}˒Z? d-s vV3/FxkзAr!wr:egQFE|עiv:=Kٝxawp'ǯY~f9#<6h"CLdf='. Zw KC~;>$QL rY'1v'3(ۢ\:{E@*+/{Olu RE-uu~pt= !`_ φp;NPe T @.7Nx\uA{[ Α|+7aauًqA'\tp9җ[ $8@`鯇iI(} q? lb |CnVtwXgf$MZ;UUs +}߅p:ʏIK\Vap'>fD^HnΕ-,~}4GBp*qeEPnwe.~\@%v@C [ʁ o{ %\YW:^=b\Gx~/mD@2he^K=I;Ͱ=`^F "z *߶&Vao33Z801)[Bh6ĠO&s2U`pBNj. h3L= +uxѩP[ m2J|8Ijޣh28/ tӨ*s 1~}8uvGIKe*LOsF[8.o%k576,&2:xɫgT$SJn3),(/G$R>^mz~ +M `) MWM躩")aBJaGN1%PBU0+(j`Uu8T0@0t 6D#1s+Js&-Z\zr]Zh3X̖4QY&QDi?oPZk]B'Wj4c:)jyN.|4 Ǖ-F Wtv?A`bA ,`;% +]:^J9'uO6׶˷j;87.&]7 X_ OKöΓǔYDIJEu־z]`VWpHaMho_ mgVC:N>B@,51UphVG99AvlG~ 4gQE SPr:MLqI="P>cSPq2 T Rp[kF8EC[E4S "(ݴ?ˠ|̶ 5&S0KUy4`]A/<0 '~a(x5h٪.҆u,C>iT=㶡S0gp|)\=bꫜ,>Tʼ&\Ȉ̝& uR#)#."gZTY(DrRgp Gf2 W7@LMtٝQcm)`ChZqP9L4iOCC(4YJ}3l^Ee_O@Dr?}62/϶D% dw#l $ ItLޛ_ngv,xL#kCG56RtIo(I1գz#-gkPL]C@ 28#,Ü6WI-l !⨌`5ńdw3ajB18R2@tak {TGdmNl;\MS(N +#v0)BSͬRX%lJƋEU̓AjZ˛ASY#}<˃'6\K;;r9Atef:=8̺EIa[s7uRHBz>~dL܂G!ZS9rS [@\nkOOٲ;;7.du#f +OR\ȝ89 dtÒ %z%ädmSL +0kC}B8"-YnqU{]csEγXSIPUy1ߺqgs8fZ#N?>/S>d"#xqQ@n +نFĘA0Nބ8Dɨ7a ˺߰ 4M#V4#гBK)cR^QH>G.AcPu&6T-?ker,.HѪ3,f%DhO^NV@AHK 6FpjfKdm^! QB&֞ w$L{@2095eߺǒ0zt~'=b!P/FFoߏOlWY1{yNavwáO&clqϴďhK6 ++G4r-oRw lx81RΝJ5j P#o3eiHxnA]UpSos ;IxgSS#mdk6|fh[㌀5R~AQƞB&=}+8THN}9DIρ씷DŽkKfl/wHNn[NN x5r ;JHߊ|]36AfTbg]4W fK.{KC+#}D( O/s_}?=w=o޼ջ޾{:'}#& endstream endobj 15 0 obj [14 0 R] endobj 29 0 obj <> endobj xref 0 30 0000000000 65535 f +0000000000 00000 f +0000019348 00000 n +0000019277 00000 n +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000000 00000 f +0000000016 00000 n +0000000000 00000 f +0000000000 00000 f +0000000149 00000 n +0000021735 00000 n +0000063696 00000 n +0000019665 00000 n +0000022035 00000 n +0000021922 00000 n +0000021000 00000 n +0000021174 00000 n +0000021222 00000 n +0000021806 00000 n +0000021837 00000 n +0000022109 00000 n +0000022292 00000 n +0000023590 00000 n +0000037541 00000 n +0000050456 00000 n +0000063721 00000 n +trailer <<3018DD0F63534B0C9CFB17B4527165AB>]>> startxref 63850 %%EOF \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Perekrestok/perekrestok.imageset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Perekrestok/perekrestok.imageset/Contents.json new file mode 100644 index 0000000..3465db9 --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Perekrestok/perekrestok.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "perekrestok.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Perekrestok/perekrestok.imageset/perekrestok.png b/Example/RMRPullToRefresh/Assets.xcassets/Perekrestok/perekrestok.imageset/perekrestok.png new file mode 100644 index 0000000..a9168c7 Binary files /dev/null and b/Example/RMRPullToRefresh/Assets.xcassets/Perekrestok/perekrestok.imageset/perekrestok.png differ diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Robot/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Robot/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Robot/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-1.imageset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-1.imageset/Contents.json new file mode 100644 index 0000000..aa8f128 --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "redmadlogo-1.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-1.imageset/redmadlogo-1.png b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-1.imageset/redmadlogo-1.png new file mode 100644 index 0000000..c5a41e2 Binary files /dev/null and b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-1.imageset/redmadlogo-1.png differ diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-2.imageset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-2.imageset/Contents.json new file mode 100644 index 0000000..f94a8a3 --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-2.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "redmadlogo-2.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-2.imageset/redmadlogo-2.png b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-2.imageset/redmadlogo-2.png new file mode 100644 index 0000000..bf1d336 Binary files /dev/null and b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-2.imageset/redmadlogo-2.png differ diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-3.imageset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-3.imageset/Contents.json new file mode 100644 index 0000000..72be4b6 --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-3.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "redmadlogo-3.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-3.imageset/redmadlogo-3.png b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-3.imageset/redmadlogo-3.png new file mode 100644 index 0000000..ecd7ac2 Binary files /dev/null and b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-3.imageset/redmadlogo-3.png differ diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-4.imageset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-4.imageset/Contents.json new file mode 100644 index 0000000..8d0835e --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-4.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "redmadlogo-4.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-4.imageset/redmadlogo-4.png b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-4.imageset/redmadlogo-4.png new file mode 100644 index 0000000..f379c1e Binary files /dev/null and b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-4.imageset/redmadlogo-4.png differ diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-5.imageset/Contents.json b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-5.imageset/Contents.json new file mode 100644 index 0000000..c8302dc --- /dev/null +++ b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-5.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "redmadlogo-5.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-5.imageset/redmadlogo-5.png b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-5.imageset/redmadlogo-5.png new file mode 100644 index 0000000..ecd7ac2 Binary files /dev/null and b/Example/RMRPullToRefresh/Assets.xcassets/Robot/redmadlogo-5.imageset/redmadlogo-5.png differ diff --git a/Example/RMRPullToRefresh/Base.lproj/LaunchScreen.storyboard b/Example/RMRPullToRefresh/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..1fa91aa --- /dev/null +++ b/Example/RMRPullToRefresh/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/RMRPullToRefresh/Base.lproj/Main.storyboard b/Example/RMRPullToRefresh/Base.lproj/Main.storyboard new file mode 100644 index 0000000..d49d3ac --- /dev/null +++ b/Example/RMRPullToRefresh/Base.lproj/Main.storyboard @@ -0,0 +1,325 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/RMRPullToRefresh/BeelineView.swift b/Example/RMRPullToRefresh/BeelineView.swift new file mode 100644 index 0000000..c12f6df --- /dev/null +++ b/Example/RMRPullToRefresh/BeelineView.swift @@ -0,0 +1,85 @@ +// +// BeelineView.swift +// RMRPullToRefresh +// +// Created by Merkulov Ilya on 10.04.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit +import RMRPullToRefresh + +enum AnimationStage: Int { + case Stage1 // big medium small + case Stage2 // big medium + case Stage3 // big + case Stage4 // + case Stage5 // big + case Stage6 // big medium + + static var count: Int { return AnimationStage.Stage6.hashValue + 1} +} + +class BeelineView: RMRPullToRefreshView { + + @IBOutlet var bigIcons: [UIImageView]! + @IBOutlet var mediumIcons: [UIImageView]! + @IBOutlet var smallIcons: [UIImageView]! + + var animationIsCanceled = false + var animationStage: AnimationStage? + + class func XIB_VIEW() -> BeelineView? { + let subviewArray = NSBundle.mainBundle().loadNibNamed("BeelineView", owner: self, options: nil) + return subviewArray.first as? BeelineView + } + + // MARK: - Private + + func hideBigIcons(hide: Bool) { + for iV in bigIcons { iV.hidden = hide } + } + + func hideMediumIcons(hide: Bool) { + for iV in mediumIcons { iV.hidden = hide } + } + + func hideSmallIcons(hide: Bool) { + for iV in smallIcons { iV.hidden = hide } + } + + @objc func executeAnimation() { + + if animationIsCanceled { + return + } + + hideBigIcons(animationStage == .Stage4) + hideMediumIcons(animationStage == .Stage3 || animationStage == .Stage4 || animationStage == .Stage5) + hideSmallIcons(animationStage != .Stage1) + + if let stage = animationStage { + animationStage = AnimationStage(rawValue: (stage.rawValue+1)%AnimationStage.count) + } + + performSelector(#selector(executeAnimation), withObject: nil, afterDelay: 0.4) + } + + // MARK: - RMRPullToRefreshViewProtocol + + override func didChangeDraggingProgress(progress: CGFloat) { + hideBigIcons(progress < 0.33) + hideMediumIcons(progress < 0.66) + hideSmallIcons(progress < 0.99) + } + + override func beginLoadingAnimation() { + animationIsCanceled = false + animationStage = .Stage1 + executeAnimation() + } + + override func didEndLoadingAnimation(hidden: Bool) { + animationIsCanceled = true + } +} diff --git a/Example/RMRPullToRefresh/BeelineView.xib b/Example/RMRPullToRefresh/BeelineView.xib new file mode 100644 index 0000000..d9896b1 --- /dev/null +++ b/Example/RMRPullToRefresh/BeelineView.xib @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/RMRPullToRefresh/Info.plist b/Example/RMRPullToRefresh/Info.plist new file mode 100644 index 0000000..6c48029 --- /dev/null +++ b/Example/RMRPullToRefresh/Info.plist @@ -0,0 +1,38 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + + + diff --git a/Example/RMRPullToRefresh/PerekrestokView.swift b/Example/RMRPullToRefresh/PerekrestokView.swift new file mode 100644 index 0000000..3beab29 --- /dev/null +++ b/Example/RMRPullToRefresh/PerekrestokView.swift @@ -0,0 +1,52 @@ +// +// PerekrestokView.swift +// RMRPullToRefresh +// +// Created by Merkulov Ilya on 24.03.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit +import RMRPullToRefresh + +class PerekrestokView: RMRPullToRefreshView { + + @IBOutlet weak var logoImageView: UIImageView! + + var fromValue: CGFloat = 0.0 + + class func XIB_VIEW() -> PerekrestokView? { + let subviewArray = NSBundle.mainBundle().loadNibNamed("PerekrestokView", owner: self, options: nil) + return subviewArray.first as? PerekrestokView + } + + // MARK: - Private + + func angle(progress: CGFloat) -> CGFloat { + return -CGFloat(M_PI)/progress + } + + // MARK: - RMRPullToRefreshViewProtocol + + override func didChangeDraggingProgress(progress: CGFloat) { + logoImageView.transform = CGAffineTransformMakeRotation(angle(progress)); + } + + override func prepareForLoadingAnimation(startProgress: CGFloat) { + fromValue = angle(startProgress) + } + + override func beginLoadingAnimation() { + let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z") + rotationAnimation.fromValue = fromValue + rotationAnimation.byValue = 2*M_PI + rotationAnimation.duration = 0.9 + rotationAnimation.repeatCount = HUGE + + self.logoImageView.layer.addAnimation(rotationAnimation, forKey: "transformAnimation") + } + + override func didEndLoadingAnimation(hidden: Bool) { + self.logoImageView.layer.removeAnimationForKey("transformAnimation") + } +} diff --git a/Example/RMRPullToRefresh/PerekrestokView.xib b/Example/RMRPullToRefresh/PerekrestokView.xib new file mode 100644 index 0000000..8458bd6 --- /dev/null +++ b/Example/RMRPullToRefresh/PerekrestokView.xib @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/RMRPullToRefresh/TableViewController.swift b/Example/RMRPullToRefresh/TableViewController.swift new file mode 100644 index 0000000..2df29b9 --- /dev/null +++ b/Example/RMRPullToRefresh/TableViewController.swift @@ -0,0 +1,36 @@ +// +// TableViewController.swift +// RMRPullToRefresh +// +// Created by Merkulov Ilya on 10.04.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit + +class TableViewController: UITableViewController { + + + override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { + super.prepareForSegue(segue, sender: sender) + + if let identifier = segue.identifier, let controller = segue.destinationViewController as? ViewController { + switch identifier { + case "perekrestok_top": + controller.exampleType = .PerekrestokTop + case "perekrestok_bottom": + controller.exampleType = .PerekrestokBottom + case "beeline_top": + controller.exampleType = .BeelineTop + case "beeline_bottom": + controller.exampleType = .BeelineBottom + case "redmadrobot_top": + controller.exampleType = .RedmadrobotTop + case "redmadrobot_bottom": + controller.exampleType = .RedmadrobotBottom + default: + break + } + } + } +} diff --git a/Example/RMRPullToRefresh/ViewController.swift b/Example/RMRPullToRefresh/ViewController.swift new file mode 100644 index 0000000..d504910 --- /dev/null +++ b/Example/RMRPullToRefresh/ViewController.swift @@ -0,0 +1,165 @@ +// +// ViewController.swift +// RMRPullToRefresh +// +// Created by Merkulov Ilya on 19.03.16. +// Copyright © 2016 Merkulov Ilya. All rights reserved. +// + +import UIKit +import RMRPullToRefresh + +public enum ExampleType: Int { + case PerekrestokTop + case PerekrestokBottom + case BeelineTop + case BeelineBottom + case RedmadrobotTop + case RedmadrobotBottom +} + +class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UIActionSheetDelegate { + + @IBOutlet weak var tableView: UITableView! + + var exampleType: ExampleType = .BeelineBottom + + var pullToRefresh: RMRPullToRefresh? + + let formatter = NSDateFormatter() + + var items: [String] = [] + var count = 2 + + var result = RMRPullToRefreshResultType.Success + + override func viewDidLoad() { + super.viewDidLoad() + + someConfiguring() + loadData() + + configurePullToRefresh() + } + + // MARK: - Pull to Refresh + + func configurePullToRefresh() { + + pullToRefresh = RMRPullToRefresh(scrollView: tableView, position: position()) { [weak self] _ in + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(5.0 * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), { + if self?.result == .Success { + self?.loadMore() + } + if let result = self?.result { + self?.pullToRefresh?.stopLoading(result) + } + }) + } + + if exampleType == .PerekrestokTop || exampleType == .PerekrestokBottom { + perekrestok() + } else if exampleType == .BeelineTop || exampleType == .BeelineBottom { + beeline() + } else if exampleType == .RedmadrobotTop || exampleType == .RedmadrobotBottom { + redmadrobot() + } + } + + // MARK: - Build example values + + func perekrestok() { + + if let pullToRefreshView = PerekrestokView.XIB_VIEW() { + pullToRefresh?.configureView(pullToRefreshView, state: .Dragging, result: .Success) + pullToRefresh?.configureView(pullToRefreshView, state: .Loading, result: .Success) + } + pullToRefresh?.height = 90.0 + pullToRefresh?.backgroundColor = UIColor(red: 16.0/255.0, + green: 192.0/255.0, + blue: 119.0/255.0, + alpha: 1.0) + } + + func beeline() { + + if let pullToRefreshView = BeelineView.XIB_VIEW() { + pullToRefresh?.configureView(pullToRefreshView, state: .Dragging, result: .Success) + pullToRefresh?.configureView(pullToRefreshView, state: .Loading, result: .Success) + } + pullToRefresh?.height = 90.0 + pullToRefresh?.backgroundColor = UIColor.whiteColor() + } + + func redmadrobot() { + pullToRefresh?.setupDefaultSettings() + } + + func position() -> RMRPullToRefreshPosition { + if exampleType == .PerekrestokTop || exampleType == .BeelineTop || exampleType == .RedmadrobotTop { + return .Top + } + return .Bottom + } + + // MARK: - Configure + + func someConfiguring() { + formatter.dateStyle = NSDateFormatterStyle.LongStyle + formatter.timeStyle = .MediumStyle + } + + // MARK: - Action + + + @IBAction func settings(sender: AnyObject) { + UIActionSheet(title: "Result type", delegate: self, cancelButtonTitle: nil, destructiveButtonTitle: nil, otherButtonTitles: ".Success", ".NoUpdates", ".Error").showInView(self.view) + } + + // MARK: - UIActionSheetDelegate + + func actionSheet(actionSheet: UIActionSheet, clickedButtonAtIndex buttonIndex: Int) { + switch buttonIndex { + case 0: + self.result = .Success + case 1: + self.result = .NoUpdates + case 2: + self.result = .Error + default: + break; + } + } + + // MARK: - Test data + + func loadData() { + for _ in 0...count { + items.append(formatter.stringFromDate(NSDate())) + } + } + + func loadMore() { + for _ in 0...20 { + self.items.append(formatter.stringFromDate(NSDate(timeIntervalSinceNow: 20))) + } + self.tableView.reloadData() + } + + // MARK: - TableView + + func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) + cell.textLabel?.text = items[indexPath.row] + return cell + } + + func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return items.count + } + + func numberOfSectionsInTableView(tableView: UITableView) -> Int { + return 1; + } +} + diff --git a/Example/RMRPullToRefreshExample.xcodeproj/project.pbxproj b/Example/RMRPullToRefreshExample.xcodeproj/project.pbxproj new file mode 100644 index 0000000..b2e7f46 --- /dev/null +++ b/Example/RMRPullToRefreshExample.xcodeproj/project.pbxproj @@ -0,0 +1,404 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 8921D4F51CA425B4000D28E3 /* PerekrestokView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8921D4F41CA425B4000D28E3 /* PerekrestokView.swift */; }; + 8921D4F71CA425C0000D28E3 /* PerekrestokView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8921D4F61CA425C0000D28E3 /* PerekrestokView.xib */; }; + 8952BE3E1CBACA1D00D94689 /* TableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8952BE3D1CBACA1D00D94689 /* TableViewController.swift */; }; + 89B014751CBAE22F002AB1B7 /* Pods.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 89B014741CBAE22F002AB1B7 /* Pods.framework */; }; + 89B014771CBAE3D5002AB1B7 /* RMRPullToRefresh.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 89B014761CBAE3D5002AB1B7 /* RMRPullToRefresh.framework */; }; + 89B06BF01CBA8A4900485A08 /* BeelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89B06BEF1CBA8A4900485A08 /* BeelineView.swift */; }; + 89B06BF21CBA8B0700485A08 /* BeelineView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 89B06BF11CBA8B0700485A08 /* BeelineView.xib */; }; + 89CB12381C9DA07B00048E46 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CB12371C9DA07B00048E46 /* AppDelegate.swift */; }; + 89CB123A1C9DA07B00048E46 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89CB12391C9DA07B00048E46 /* ViewController.swift */; }; + 89CB123D1C9DA07B00048E46 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 89CB123B1C9DA07B00048E46 /* Main.storyboard */; }; + 89CB123F1C9DA07B00048E46 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 89CB123E1C9DA07B00048E46 /* Assets.xcassets */; }; + 89CB12421C9DA07B00048E46 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 89CB12401C9DA07B00048E46 /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 766D53F6605D8961328E54A1 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; + 8921D4F41CA425B4000D28E3 /* PerekrestokView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerekrestokView.swift; sourceTree = ""; }; + 8921D4F61CA425C0000D28E3 /* PerekrestokView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PerekrestokView.xib; sourceTree = ""; }; + 8952BE3D1CBACA1D00D94689 /* TableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewController.swift; sourceTree = ""; }; + 89B014741CBAE22F002AB1B7 /* Pods.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Pods.framework; path = "../../../../Library/Developer/Xcode/DerivedData/RMRPullToRefresh-fwnpioedcaituoahusazwcgryphj/Build/Products/Debug-iphonesimulator/Pods.framework"; sourceTree = ""; }; + 89B014761CBAE3D5002AB1B7 /* RMRPullToRefresh.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RMRPullToRefresh.framework; path = "../../../../Library/Developer/Xcode/DerivedData/RMRPullToRefresh-fwnpioedcaituoahusazwcgryphj/Build/Products/Debug-iphonesimulator/RMRPullToRefresh.framework"; sourceTree = ""; }; + 89B06BEF1CBA8A4900485A08 /* BeelineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BeelineView.swift; sourceTree = ""; }; + 89B06BF11CBA8B0700485A08 /* BeelineView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = BeelineView.xib; sourceTree = ""; }; + 89CB12341C9DA07B00048E46 /* RMRPullToRefreshExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RMRPullToRefreshExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 89CB12371C9DA07B00048E46 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 89CB12391C9DA07B00048E46 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 89CB123C1C9DA07B00048E46 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 89CB123E1C9DA07B00048E46 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 89CB12411C9DA07B00048E46 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 89CB12431C9DA07B00048E46 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D48C26E126E3942BBDFD40CF /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 89CB12311C9DA07B00048E46 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 89B014771CBAE3D5002AB1B7 /* RMRPullToRefresh.framework in Frameworks */, + 89B014751CBAE22F002AB1B7 /* Pods.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 23AE0A3F7B76C576CCD778D3 /* Pods */ = { + isa = PBXGroup; + children = ( + 766D53F6605D8961328E54A1 /* Pods.debug.xcconfig */, + D48C26E126E3942BBDFD40CF /* Pods.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + 8952BE3C1CBAC64800D94689 /* Views */ = { + isa = PBXGroup; + children = ( + 8921D4F41CA425B4000D28E3 /* PerekrestokView.swift */, + 8921D4F61CA425C0000D28E3 /* PerekrestokView.xib */, + 89B06BEF1CBA8A4900485A08 /* BeelineView.swift */, + 89B06BF11CBA8B0700485A08 /* BeelineView.xib */, + ); + name = Views; + sourceTree = ""; + }; + 89CB122B1C9DA07B00048E46 = { + isa = PBXGroup; + children = ( + 89CB12361C9DA07B00048E46 /* RMRPullToRefreshExample */, + 89CB12351C9DA07B00048E46 /* Products */, + 23AE0A3F7B76C576CCD778D3 /* Pods */, + E22D98D3A06A61AA44D86794 /* Frameworks */, + ); + sourceTree = ""; + }; + 89CB12351C9DA07B00048E46 /* Products */ = { + isa = PBXGroup; + children = ( + 89CB12341C9DA07B00048E46 /* RMRPullToRefreshExample.app */, + ); + name = Products; + sourceTree = ""; + }; + 89CB12361C9DA07B00048E46 /* RMRPullToRefreshExample */ = { + isa = PBXGroup; + children = ( + 8952BE3C1CBAC64800D94689 /* Views */, + 89CB12371C9DA07B00048E46 /* AppDelegate.swift */, + 8952BE3D1CBACA1D00D94689 /* TableViewController.swift */, + 89CB12391C9DA07B00048E46 /* ViewController.swift */, + 89CB123B1C9DA07B00048E46 /* Main.storyboard */, + 89CB12401C9DA07B00048E46 /* LaunchScreen.storyboard */, + 89CB123E1C9DA07B00048E46 /* Assets.xcassets */, + 89CB12431C9DA07B00048E46 /* Info.plist */, + ); + name = RMRPullToRefreshExample; + path = RMRPullToRefresh; + sourceTree = ""; + }; + E22D98D3A06A61AA44D86794 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 89B014761CBAE3D5002AB1B7 /* RMRPullToRefresh.framework */, + 89B014741CBAE22F002AB1B7 /* Pods.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 89CB12331C9DA07B00048E46 /* RMRPullToRefreshExample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 89CB12461C9DA07B00048E46 /* Build configuration list for PBXNativeTarget "RMRPullToRefreshExample" */; + buildPhases = ( + 00D4D85E4DF2FF039A017773 /* Check Pods Manifest.lock */, + 89CB12301C9DA07B00048E46 /* Sources */, + 89CB12311C9DA07B00048E46 /* Frameworks */, + 89CB12321C9DA07B00048E46 /* Resources */, + 2BE863C51DEA329C1234F1B0 /* Embed Pods Frameworks */, + C137BE069515EFF1A69455DF /* Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = RMRPullToRefreshExample; + productName = RMRPullToRefresh; + productReference = 89CB12341C9DA07B00048E46 /* RMRPullToRefreshExample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 89CB122C1C9DA07B00048E46 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0720; + ORGANIZATIONNAME = "Merkulov Ilya"; + TargetAttributes = { + 89CB12331C9DA07B00048E46 = { + CreatedOnToolsVersion = 7.2.1; + }; + }; + }; + buildConfigurationList = 89CB122F1C9DA07B00048E46 /* Build configuration list for PBXProject "RMRPullToRefreshExample" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 89CB122B1C9DA07B00048E46; + productRefGroup = 89CB12351C9DA07B00048E46 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 89CB12331C9DA07B00048E46 /* RMRPullToRefreshExample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 89CB12321C9DA07B00048E46 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 89CB12421C9DA07B00048E46 /* LaunchScreen.storyboard in Resources */, + 89CB123F1C9DA07B00048E46 /* Assets.xcassets in Resources */, + 8921D4F71CA425C0000D28E3 /* PerekrestokView.xib in Resources */, + 89CB123D1C9DA07B00048E46 /* Main.storyboard in Resources */, + 89B06BF21CBA8B0700485A08 /* BeelineView.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 00D4D85E4DF2FF039A017773 /* Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Check Pods Manifest.lock"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; + showEnvVarsInLog = 0; + }; + 2BE863C51DEA329C1234F1B0 /* Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Embed Pods Frameworks"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + C137BE069515EFF1A69455DF /* Copy Pods Resources */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Copy Pods Resources"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 89CB12301C9DA07B00048E46 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 89CB123A1C9DA07B00048E46 /* ViewController.swift in Sources */, + 8921D4F51CA425B4000D28E3 /* PerekrestokView.swift in Sources */, + 89B06BF01CBA8A4900485A08 /* BeelineView.swift in Sources */, + 89CB12381C9DA07B00048E46 /* AppDelegate.swift in Sources */, + 8952BE3E1CBACA1D00D94689 /* TableViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 89CB123B1C9DA07B00048E46 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 89CB123C1C9DA07B00048E46 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 89CB12401C9DA07B00048E46 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 89CB12411C9DA07B00048E46 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 89CB12441C9DA07B00048E46 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 89CB12451C9DA07B00048E46 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.2; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 89CB12471C9DA07B00048E46 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 766D53F6605D8961328E54A1 /* Pods.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + FRAMEWORK_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = RMRPullToRefresh/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.redmadrobot.RMRPullToRefresh; + PRODUCT_NAME = RMRPullToRefreshExample; + }; + name = Debug; + }; + 89CB12481C9DA07B00048E46 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D48C26E126E3942BBDFD40CF /* Pods.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + FRAMEWORK_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = RMRPullToRefresh/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.redmadrobot.RMRPullToRefresh; + PRODUCT_NAME = RMRPullToRefreshExample; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 89CB122F1C9DA07B00048E46 /* Build configuration list for PBXProject "RMRPullToRefreshExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 89CB12441C9DA07B00048E46 /* Debug */, + 89CB12451C9DA07B00048E46 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 89CB12461C9DA07B00048E46 /* Build configuration list for PBXNativeTarget "RMRPullToRefreshExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 89CB12471C9DA07B00048E46 /* Debug */, + 89CB12481C9DA07B00048E46 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 89CB122C1C9DA07B00048E46 /* Project object */; +} diff --git a/Example/RMRPullToRefreshExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Example/RMRPullToRefreshExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..15162e1 --- /dev/null +++ b/Example/RMRPullToRefreshExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Example/RMRPullToRefreshExample.xcodeproj/project.xcworkspace/xcuserdata/im.xcuserdatad/UserInterfaceState.xcuserstate b/Example/RMRPullToRefreshExample.xcodeproj/project.xcworkspace/xcuserdata/im.xcuserdatad/UserInterfaceState.xcuserstate new file mode 100644 index 0000000..020f07a Binary files /dev/null and b/Example/RMRPullToRefreshExample.xcodeproj/project.xcworkspace/xcuserdata/im.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Example/RMRPullToRefreshExample.xcodeproj/xcuserdata/im.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Example/RMRPullToRefreshExample.xcodeproj/xcuserdata/im.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist new file mode 100644 index 0000000..e9c3f30 --- /dev/null +++ b/Example/RMRPullToRefreshExample.xcodeproj/xcuserdata/im.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -0,0 +1,28 @@ + + + + + + + + + + + + + diff --git a/Example/RMRPullToRefreshExample.xcodeproj/xcuserdata/im.xcuserdatad/xcschemes/RMRPullToRefresh.xcscheme b/Example/RMRPullToRefreshExample.xcodeproj/xcuserdata/im.xcuserdatad/xcschemes/RMRPullToRefresh.xcscheme new file mode 100644 index 0000000..6dcc2f3 --- /dev/null +++ b/Example/RMRPullToRefreshExample.xcodeproj/xcuserdata/im.xcuserdatad/xcschemes/RMRPullToRefresh.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/RMRPullToRefreshExample.xcodeproj/xcuserdata/im.xcuserdatad/xcschemes/xcschememanagement.plist b/Example/RMRPullToRefreshExample.xcodeproj/xcuserdata/im.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..74cfa1d --- /dev/null +++ b/Example/RMRPullToRefreshExample.xcodeproj/xcuserdata/im.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + RMRPullToRefresh.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 89CB12331C9DA07B00048E46 + + primary + + + + + diff --git a/RMRPullToRefresh.podspec b/RMRPullToRefresh.podspec new file mode 100644 index 0000000..bf37a19 --- /dev/null +++ b/RMRPullToRefresh.podspec @@ -0,0 +1,12 @@ +Pod::Spec.new do |spec| + spec.name = "RMRPullToRefresh" + spec.version = "0.1" + spec.platform = :ios, "8.0" + spec.license = { :type => "MIT", :file => "LICENSE" } + spec.summary = "A pull to refresh control for UIScrollView (UITableView and UICollectionView)" + spec.homepage = "http://redmadrobot.com/" + spec.author = "Ilya Merkulov" + spec.source = { :git => :"https://git.redmadrobot.com/im/RMRPullToRefresh", :tag => "v0.1" } + spec.source_files = "Classes/*.{swift}", "Classes/Default/*.{swift}" + spec.resources = ['Images/*.png'] +end \ No newline at end of file