From ce868e2430834143de02484d99f206703a756268 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 6 Oct 2020 13:04:12 +0500 Subject: [PATCH 01/21] Update README.md Change pod linc --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 34f1430..ac6a29f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Drop in the Spring folder to your Xcode project (make sure to enable "Copy items Or via CocoaPods: ``` use_frameworks! -pod 'Spring', :git => 'https://github.com/MengTo/Spring.git' +pod 'Spring', :git => 'https://github.com/LexDeBash/Spring.git' ``` ## Usage with Storyboard From 029adbe11ab9401061f8f0f14bb050918e855d68 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 6 Oct 2020 11:59:13 +0500 Subject: [PATCH 02/21] Change var to let --- Spring/DesignableTabBarController.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Spring/DesignableTabBarController.swift b/Spring/DesignableTabBarController.swift index 6c81095..c3ab5f3 100644 --- a/Spring/DesignableTabBarController.swift +++ b/Spring/DesignableTabBarController.swift @@ -47,7 +47,7 @@ import UIKit @IBInspectable var firstSelectedImage: UIImage? { didSet { if let image = firstSelectedImage { - var tabBarItems = self.tabBar.items as [UITabBarItem]? + let tabBarItems = self.tabBar.items as [UITabBarItem]? tabBarItems?[0].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) } } @@ -56,7 +56,7 @@ import UIKit @IBInspectable var secondSelectedImage: UIImage? { didSet { if let image = secondSelectedImage { - var tabBarItems = self.tabBar.items as [UITabBarItem]? + let tabBarItems = self.tabBar.items as [UITabBarItem]? tabBarItems?[1].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) } } @@ -65,7 +65,7 @@ import UIKit @IBInspectable var thirdSelectedImage: UIImage? { didSet { if let image = thirdSelectedImage { - var tabBarItems = self.tabBar.items as [UITabBarItem]? + let tabBarItems = self.tabBar.items as [UITabBarItem]? tabBarItems?[2].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) } } @@ -74,7 +74,7 @@ import UIKit @IBInspectable var fourthSelectedImage: UIImage? { didSet { if let image = fourthSelectedImage { - var tabBarItems = self.tabBar.items as [UITabBarItem]? + let tabBarItems = self.tabBar.items as [UITabBarItem]? tabBarItems?[3].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) } } @@ -83,7 +83,7 @@ import UIKit @IBInspectable var fifthSelectedImage: UIImage? { didSet { if let image = fifthSelectedImage { - var tabBarItems = self.tabBar.items as [UITabBarItem]? + let tabBarItems = self.tabBar.items as [UITabBarItem]? tabBarItems?[4].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) } } From f2da82cb196ac93b2cfc9ce6c83970a4f174e970 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 6 Oct 2020 12:00:12 +0500 Subject: [PATCH 03/21] Remove 'public' modifier --- Spring/LoadingView.swift | 4 ++-- Spring/UnwindSegue.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Spring/LoadingView.swift b/Spring/LoadingView.swift index 5f62ce8..55e5e2c 100644 --- a/Spring/LoadingView.swift +++ b/Spring/LoadingView.swift @@ -50,7 +50,7 @@ public extension UIView { static let Tag = 1000 } - public func showLoading() { + func showLoading() { if self.viewWithTag(LoadingViewConstants.Tag) != nil { // If loading view is already found in current view hierachy, do nothing @@ -68,7 +68,7 @@ public extension UIView { }) } - public func hideLoading() { + func hideLoading() { if let loadingXibView = self.viewWithTag(LoadingViewConstants.Tag) { loadingXibView.alpha = 1 diff --git a/Spring/UnwindSegue.swift b/Spring/UnwindSegue.swift index 53a71cb..2080094 100644 --- a/Spring/UnwindSegue.swift +++ b/Spring/UnwindSegue.swift @@ -23,5 +23,5 @@ import UIKit public extension UIViewController { - @IBAction public func unwindToViewController (_ segue: UIStoryboardSegue){} + @IBAction func unwindToViewController (_ segue: UIStoryboardSegue){} } From e53d98e7267d4b4af6efd1be4335ba6d8d501af9 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 6 Oct 2020 12:04:13 +0500 Subject: [PATCH 04/21] Change Capital letters to Uppercase letters in AnimationPreset enum and AnimationCurve enum --- Spring/Spring.swift | 230 ++++++++++++++++++++++---------------------- 1 file changed, 115 insertions(+), 115 deletions(-) diff --git a/Spring/Spring.swift b/Spring/Spring.swift index cf86e1a..12f4b81 100644 --- a/Spring/Spring.swift +++ b/Spring/Spring.swift @@ -104,97 +104,97 @@ public class Spring : NSObject { private var alpha: CGFloat { get { return view.alpha } set { view.alpha = newValue } } public enum AnimationPreset: String { - case SlideLeft = "slideLeft" - case SlideRight = "slideRight" - case SlideDown = "slideDown" - case SlideUp = "slideUp" - case SqueezeLeft = "squeezeLeft" - case SqueezeRight = "squeezeRight" - case SqueezeDown = "squeezeDown" - case SqueezeUp = "squeezeUp" - case FadeIn = "fadeIn" - case FadeOut = "fadeOut" - case FadeOutIn = "fadeOutIn" - case FadeInLeft = "fadeInLeft" - case FadeInRight = "fadeInRight" - case FadeInDown = "fadeInDown" - case FadeInUp = "fadeInUp" - case ZoomIn = "zoomIn" - case ZoomOut = "zoomOut" - case Fall = "fall" - case Shake = "shake" - case Pop = "pop" - case FlipX = "flipX" - case FlipY = "flipY" - case Morph = "morph" - case Squeeze = "squeeze" - case Flash = "flash" - case Wobble = "wobble" - case Swing = "swing" + case slideLeft + case slideRight + case slideDown + case slideUp + case squeezeLeft + case squeezeRight + case squeezeDown + case squeezeUp + case fadeIn + case fadeOut + case fadeOutIn + case fadeInLeft + case fadeInRight + case fadeInDown + case fadeInUp + case zoomIn + case zoomOut + case fall + case shake + case pop + case flipX + case flipY + case morph + case squeeze + case flash + case wobble + case swing } public enum AnimationCurve: String { - case EaseIn = "easeIn" - case EaseOut = "easeOut" - case EaseInOut = "easeInOut" - case Linear = "linear" - case Spring = "spring" - case EaseInSine = "easeInSine" - case EaseOutSine = "easeOutSine" - case EaseInOutSine = "easeInOutSine" - case EaseInQuad = "easeInQuad" - case EaseOutQuad = "easeOutQuad" - case EaseInOutQuad = "easeInOutQuad" - case EaseInCubic = "easeInCubic" - case EaseOutCubic = "easeOutCubic" - case EaseInOutCubic = "easeInOutCubic" - case EaseInQuart = "easeInQuart" - case EaseOutQuart = "easeOutQuart" - case EaseInOutQuart = "easeInOutQuart" - case EaseInQuint = "easeInQuint" - case EaseOutQuint = "easeOutQuint" - case EaseInOutQuint = "easeInOutQuint" - case EaseInExpo = "easeInExpo" - case EaseOutExpo = "easeOutExpo" - case EaseInOutExpo = "easeInOutExpo" - case EaseInCirc = "easeInCirc" - case EaseOutCirc = "easeOutCirc" - case EaseInOutCirc = "easeInOutCirc" - case EaseInBack = "easeInBack" - case EaseOutBack = "easeOutBack" - case EaseInOutBack = "easeInOutBack" + case easeIn + case easeOut + case easeInOut + case linear + case spring + case easeInSine + case easeOutSine + case easeInOutSine + case easeInQuad + case easeOutQuad + case easeInOutQuad + case easeInCubic + case easeOutCubic + case easeInOutCubic + case easeInQuart + case easeOutQuart + case easeInOutQuart + case easeInQuint + case easeOutQuint + case easeInOutQuint + case easeInExpo + case easeOutExpo + case easeInOutExpo + case easeInCirc + case easeOutCirc + case easeInOutCirc + case easeInBack + case easeOutBack + case easeInOutBack } func animatePreset() { alpha = 0.99 if let animation = AnimationPreset(rawValue: animation) { switch animation { - case .SlideLeft: + case .slideLeft: x = 300*force - case .SlideRight: + case .slideRight: x = -300*force - case .SlideDown: + case .slideDown: y = -300*force - case .SlideUp: + case .slideUp: y = 300*force - case .SqueezeLeft: + case .squeezeLeft: x = 300 scaleX = 3*force - case .SqueezeRight: + case .squeezeRight: x = -300 scaleX = 3*force - case .SqueezeDown: + case .squeezeDown: y = -300 scaleY = 3*force - case .SqueezeUp: + case .squeezeUp: y = 300 scaleY = 3*force - case .FadeIn: + case .fadeIn: opacity = 0 - case .FadeOut: + case .fadeOut: animateFrom = false opacity = 0 - case .FadeOutIn: + case .fadeOutIn: let animation = CABasicAnimation() animation.keyPath = "opacity" animation.fromValue = 1 @@ -204,32 +204,32 @@ public class Spring : NSObject { animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) animation.autoreverses = true layer.add(animation, forKey: "fade") - case .FadeInLeft: + case .fadeInLeft: opacity = 0 x = 300*force - case .FadeInRight: + case .fadeInRight: x = -300*force opacity = 0 - case .FadeInDown: + case .fadeInDown: y = -300*force opacity = 0 - case .FadeInUp: + case .fadeInUp: y = 300*force opacity = 0 - case .ZoomIn: + case .zoomIn: opacity = 0 scaleX = 2*force scaleY = 2*force - case .ZoomOut: + case .zoomOut: animateFrom = false opacity = 0 scaleX = 2*force scaleY = 2*force - case .Fall: + case .fall: animateFrom = false rotate = 15 * CGFloat(CGFloat.pi/180) y = 600*force - case .Shake: + case .shake: let animation = CAKeyframeAnimation() animation.keyPath = "position.x" animation.values = [0, 30*force, -30*force, 30*force, 0] @@ -240,7 +240,7 @@ public class Spring : NSObject { animation.repeatCount = repeatCount animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) layer.add(animation, forKey: "shake") - case .Pop: + case .pop: let animation = CAKeyframeAnimation() animation.keyPath = "transform.scale" animation.values = [0, 0.2*force, -0.2*force, 0.2*force, 0] @@ -251,7 +251,7 @@ public class Spring : NSObject { animation.repeatCount = repeatCount animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) layer.add(animation, forKey: "pop") - case .FlipX: + case .flipX: rotate = 0 scaleX = 1 scaleY = 1 @@ -268,7 +268,7 @@ public class Spring : NSObject { animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) animation.timingFunction = getTimingFunction(curve: curve) layer.add(animation, forKey: "3d") - case .FlipY: + case .flipY: var perspective = CATransform3DIdentity perspective.m34 = -1.0 / layer.frame.size.width/2 @@ -283,7 +283,7 @@ public class Spring : NSObject { animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) animation.timingFunction = getTimingFunction(curve: curve) layer.add(animation, forKey: "3d") - case .Morph: + case .morph: let morphX = CAKeyframeAnimation() morphX.keyPath = "transform.scale.x" morphX.values = [1, 1.3*force, 0.7, 1.3*force, 1] @@ -303,7 +303,7 @@ public class Spring : NSObject { morphY.repeatCount = repeatCount morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) layer.add(morphY, forKey: "morphY") - case .Squeeze: + case .squeeze: let morphX = CAKeyframeAnimation() morphX.keyPath = "transform.scale.x" morphX.values = [1, 1.5*force, 0.5, 1.5*force, 1] @@ -323,7 +323,7 @@ public class Spring : NSObject { morphY.repeatCount = repeatCount morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) layer.add(morphY, forKey: "morphY") - case .Flash: + case .flash: let animation = CABasicAnimation() animation.keyPath = "opacity" animation.fromValue = 1 @@ -333,7 +333,7 @@ public class Spring : NSObject { animation.autoreverses = true animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) layer.add(animation, forKey: "flash") - case .Wobble: + case .wobble: let animation = CAKeyframeAnimation() animation.keyPath = "transform.rotation" animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] @@ -353,7 +353,7 @@ public class Spring : NSObject { x.repeatCount = repeatCount x.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) layer.add(x, forKey: "x") - case .Swing: + case .swing: let animation = CAKeyframeAnimation() animation.keyPath = "transform.rotation" animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] @@ -370,35 +370,35 @@ public class Spring : NSObject { func getTimingFunction(curve: String) -> CAMediaTimingFunction { if let curve = AnimationCurve(rawValue: curve) { switch curve { - case .EaseIn: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn) - case .EaseOut: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut) - case .EaseInOut: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) - case .Linear: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear) - case .Spring: return CAMediaTimingFunction(controlPoints: 0.5, 1.1+Float(force/3), 1, 1) - case .EaseInSine: return CAMediaTimingFunction(controlPoints: 0.47, 0, 0.745, 0.715) - case .EaseOutSine: return CAMediaTimingFunction(controlPoints: 0.39, 0.575, 0.565, 1) - case .EaseInOutSine: return CAMediaTimingFunction(controlPoints: 0.445, 0.05, 0.55, 0.95) - case .EaseInQuad: return CAMediaTimingFunction(controlPoints: 0.55, 0.085, 0.68, 0.53) - case .EaseOutQuad: return CAMediaTimingFunction(controlPoints: 0.25, 0.46, 0.45, 0.94) - case .EaseInOutQuad: return CAMediaTimingFunction(controlPoints: 0.455, 0.03, 0.515, 0.955) - case .EaseInCubic: return CAMediaTimingFunction(controlPoints: 0.55, 0.055, 0.675, 0.19) - case .EaseOutCubic: return CAMediaTimingFunction(controlPoints: 0.215, 0.61, 0.355, 1) - case .EaseInOutCubic: return CAMediaTimingFunction(controlPoints: 0.645, 0.045, 0.355, 1) - case .EaseInQuart: return CAMediaTimingFunction(controlPoints: 0.895, 0.03, 0.685, 0.22) - case .EaseOutQuart: return CAMediaTimingFunction(controlPoints: 0.165, 0.84, 0.44, 1) - case .EaseInOutQuart: return CAMediaTimingFunction(controlPoints: 0.77, 0, 0.175, 1) - case .EaseInQuint: return CAMediaTimingFunction(controlPoints: 0.755, 0.05, 0.855, 0.06) - case .EaseOutQuint: return CAMediaTimingFunction(controlPoints: 0.23, 1, 0.32, 1) - case .EaseInOutQuint: return CAMediaTimingFunction(controlPoints: 0.86, 0, 0.07, 1) - case .EaseInExpo: return CAMediaTimingFunction(controlPoints: 0.95, 0.05, 0.795, 0.035) - case .EaseOutExpo: return CAMediaTimingFunction(controlPoints: 0.19, 1, 0.22, 1) - case .EaseInOutExpo: return CAMediaTimingFunction(controlPoints: 1, 0, 0, 1) - case .EaseInCirc: return CAMediaTimingFunction(controlPoints: 0.6, 0.04, 0.98, 0.335) - case .EaseOutCirc: return CAMediaTimingFunction(controlPoints: 0.075, 0.82, 0.165, 1) - case .EaseInOutCirc: return CAMediaTimingFunction(controlPoints: 0.785, 0.135, 0.15, 0.86) - case .EaseInBack: return CAMediaTimingFunction(controlPoints: 0.6, -0.28, 0.735, 0.045) - case .EaseOutBack: return CAMediaTimingFunction(controlPoints: 0.175, 0.885, 0.32, 1.275) - case .EaseInOutBack: return CAMediaTimingFunction(controlPoints: 0.68, -0.55, 0.265, 1.55) + case .easeIn: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn) + case .easeOut: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut) + case .easeInOut: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) + case .linear: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear) + case .spring: return CAMediaTimingFunction(controlPoints: 0.5, 1.1+Float(force/3), 1, 1) + case .easeInSine: return CAMediaTimingFunction(controlPoints: 0.47, 0, 0.745, 0.715) + case .easeOutSine: return CAMediaTimingFunction(controlPoints: 0.39, 0.575, 0.565, 1) + case .easeInOutSine: return CAMediaTimingFunction(controlPoints: 0.445, 0.05, 0.55, 0.95) + case .easeInQuad: return CAMediaTimingFunction(controlPoints: 0.55, 0.085, 0.68, 0.53) + case .easeOutQuad: return CAMediaTimingFunction(controlPoints: 0.25, 0.46, 0.45, 0.94) + case .easeInOutQuad: return CAMediaTimingFunction(controlPoints: 0.455, 0.03, 0.515, 0.955) + case .easeInCubic: return CAMediaTimingFunction(controlPoints: 0.55, 0.055, 0.675, 0.19) + case .easeOutCubic: return CAMediaTimingFunction(controlPoints: 0.215, 0.61, 0.355, 1) + case .easeInOutCubic: return CAMediaTimingFunction(controlPoints: 0.645, 0.045, 0.355, 1) + case .easeInQuart: return CAMediaTimingFunction(controlPoints: 0.895, 0.03, 0.685, 0.22) + case .easeOutQuart: return CAMediaTimingFunction(controlPoints: 0.165, 0.84, 0.44, 1) + case .easeInOutQuart: return CAMediaTimingFunction(controlPoints: 0.77, 0, 0.175, 1) + case .easeInQuint: return CAMediaTimingFunction(controlPoints: 0.755, 0.05, 0.855, 0.06) + case .easeOutQuint: return CAMediaTimingFunction(controlPoints: 0.23, 1, 0.32, 1) + case .easeInOutQuint: return CAMediaTimingFunction(controlPoints: 0.86, 0, 0.07, 1) + case .easeInExpo: return CAMediaTimingFunction(controlPoints: 0.95, 0.05, 0.795, 0.035) + case .easeOutExpo: return CAMediaTimingFunction(controlPoints: 0.19, 1, 0.22, 1) + case .easeInOutExpo: return CAMediaTimingFunction(controlPoints: 1, 0, 0, 1) + case .easeInCirc: return CAMediaTimingFunction(controlPoints: 0.6, 0.04, 0.98, 0.335) + case .easeOutCirc: return CAMediaTimingFunction(controlPoints: 0.075, 0.82, 0.165, 1) + case .easeInOutCirc: return CAMediaTimingFunction(controlPoints: 0.785, 0.135, 0.15, 0.86) + case .easeInBack: return CAMediaTimingFunction(controlPoints: 0.6, -0.28, 0.735, 0.045) + case .easeOutBack: return CAMediaTimingFunction(controlPoints: 0.175, 0.885, 0.32, 1.275) + case .easeInOutBack: return CAMediaTimingFunction(controlPoints: 0.68, -0.55, 0.265, 1.55) } } return CAMediaTimingFunction(name: CAMediaTimingFunctionName.default) @@ -407,9 +407,9 @@ public class Spring : NSObject { func getAnimationOptions(curve: String) -> UIView.AnimationOptions { if let curve = AnimationCurve(rawValue: curve) { switch curve { - case .EaseIn: return UIView.AnimationOptions.curveEaseIn - case .EaseOut: return UIView.AnimationOptions.curveEaseOut - case .EaseInOut: return UIView.AnimationOptions() + case .easeIn: return UIView.AnimationOptions.curveEaseIn + case .easeOut: return UIView.AnimationOptions.curveEaseOut + case .easeInOut: return UIView.AnimationOptions() default: break } } From 3575dc2985710d62ba220ae9d3d2892811509016 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 6 Oct 2020 12:05:21 +0500 Subject: [PATCH 05/21] Change Capital letters to Uppercase letters in animations and curves --- SpringApp/SpringViewController.swift | 110 +++++++++++++-------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/SpringApp/SpringViewController.swift b/SpringApp/SpringViewController.swift index 6a4ea1b..a007581 100644 --- a/SpringApp/SpringViewController.swift +++ b/SpringApp/SpringViewController.swift @@ -117,64 +117,64 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView } let animations: [Spring.AnimationPreset] = [ - .Shake, - .Pop, - .Morph, - .Squeeze, - .Wobble, - .Swing, - .FlipX, - .FlipY, - .Fall, - .SqueezeLeft, - .SqueezeRight, - .SqueezeDown, - .SqueezeUp, - .SlideLeft, - .SlideRight, - .SlideDown, - .SlideUp, - .FadeIn, - .FadeOut, - .FadeInLeft, - .FadeInRight, - .FadeInDown, - .FadeInUp, - .ZoomIn, - .ZoomOut, - .Flash + .shake, + .pop, + .morph, + .squeeze, + .wobble, + .swing, + .flipX, + .flipY, + .fall, + .squeezeLeft, + .squeezeRight, + .squeezeDown, + .squeezeUp, + .slideLeft, + .slideRight, + .slideDown, + .slideUp, + .fadeIn, + .fadeOut, + .fadeInLeft, + .fadeInRight, + .fadeInDown, + .fadeInUp, + .zoomIn, + .zoomOut, + .flash ] var animationCurves: [Spring.AnimationCurve] = [ - .EaseIn, - .EaseOut, - .EaseInOut, - .Linear, - .Spring, - .EaseInSine, - .EaseOutSine, - .EaseInOutSine, - .EaseInQuad, - .EaseOutQuad, - .EaseInOutQuad, - .EaseInCubic, - .EaseOutCubic, - .EaseInOutCubic, - .EaseInQuart, - .EaseOutQuart, - .EaseInOutQuart, - .EaseInQuint, - .EaseOutQuint, - .EaseInOutQuint, - .EaseInExpo, - .EaseOutExpo, - .EaseInOutExpo, - .EaseInCirc, - .EaseOutCirc, - .EaseInOutCirc, - .EaseInBack, - .EaseOutBack, - .EaseInOutBack + .easeIn, + .easeOut, + .easeInOut, + .linear, + .spring, + .easeInSine, + .easeOutSine, + .easeInOutSine, + .easeInQuad, + .easeOutQuad, + .easeInOutQuad, + .easeInCubic, + .easeOutCubic, + .easeInOutCubic, + .easeInQuart, + .easeOutQuart, + .easeInOutQuart, + .easeInQuint, + .easeOutQuint, + .easeInOutQuint, + .easeInExpo, + .easeOutExpo, + .easeInOutExpo, + .easeInCirc, + .easeOutCirc, + .easeInOutCirc, + .easeInBack, + .easeOutBack, + .easeInOutBack ] override func viewDidLoad() { From ada3dc630bdbc298e43ace5e846ff2480ff12269 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 6 Oct 2020 13:17:42 +0500 Subject: [PATCH 06/21] Update iOS Deployment Target --- SpringApp.xcodeproj/project.pbxproj | 26 ++++++++++++------- .../xcshareddata/xcschemes/Spring.xcscheme | 6 +---- .../xcshareddata/xcschemes/SpringApp.xcscheme | 24 +++++++---------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/SpringApp.xcodeproj/project.pbxproj b/SpringApp.xcodeproj/project.pbxproj index a0e8956..9ab9368 100644 --- a/SpringApp.xcodeproj/project.pbxproj +++ b/SpringApp.xcodeproj/project.pbxproj @@ -408,7 +408,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0700; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1200; ORGANIZATIONNAME = "Meng To"; TargetAttributes = { 1A4FDA321A6E44780099D309 = { @@ -611,7 +611,7 @@ ); INFOPLIST_FILE = Spring/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -634,7 +634,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Spring/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -655,7 +655,7 @@ "$(inherited)", ); INFOPLIST_FILE = SpringTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.1; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jamztang.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -668,7 +668,7 @@ isa = XCBuildConfiguration; buildSettings = { INFOPLIST_FILE = SpringTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.1; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.jamztang.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -682,6 +682,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -690,14 +691,17 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -722,7 +726,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.2; + IPHONEOS_DEPLOYMENT_TARGET = 13.1; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -735,6 +739,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -743,14 +748,17 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -768,7 +776,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 8.2; + IPHONEOS_DEPLOYMENT_TARGET = 13.1; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_SWIFT3_OBJC_INFERENCE = Off; @@ -781,7 +789,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = SpringApp/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -795,7 +803,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = SpringApp/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 8.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/SpringApp.xcodeproj/xcshareddata/xcschemes/Spring.xcscheme b/SpringApp.xcodeproj/xcshareddata/xcschemes/Spring.xcscheme index ecfaae8..89b2628 100644 --- a/SpringApp.xcodeproj/xcshareddata/xcschemes/Spring.xcscheme +++ b/SpringApp.xcodeproj/xcshareddata/xcschemes/Spring.xcscheme @@ -1,6 +1,6 @@ - - - - + + + + @@ -77,17 +86,6 @@ - - - - - - - - Date: Tue, 6 Oct 2020 15:25:26 +0500 Subject: [PATCH 07/21] Change UIViewControllerBasedStatusBarAppearance to true --- SpringApp/Info.plist | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SpringApp/Info.plist b/SpringApp/Info.plist index 01aa7f4..10f480a 100644 --- a/SpringApp/Info.plist +++ b/SpringApp/Info.plist @@ -30,6 +30,8 @@ armv7 + UIStatusBarStyle + UIStatusBarStyleDefault UISupportedInterfaceOrientations UIInterfaceOrientationPortrait @@ -37,6 +39,6 @@ UIInterfaceOrientationLandscapeRight UIViewControllerBasedStatusBarAppearance - + From b3bcc7d08cba7766c8b6ac161fee86349b8f6567 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 6 Oct 2020 15:27:39 +0500 Subject: [PATCH 08/21] Update status bar style with current syntax of lang --- SpringApp/CodeViewController.swift | 12 ++++++++---- SpringApp/OptionsViewController.swift | 4 ++++ SpringApp/SpringViewController.swift | 27 +++++++++++++++------------ 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/SpringApp/CodeViewController.swift b/SpringApp/CodeViewController.swift index 9aa8327..6889822 100644 --- a/SpringApp/CodeViewController.swift +++ b/SpringApp/CodeViewController.swift @@ -17,6 +17,10 @@ class CodeViewController: UIViewController { var codeText: String = "" var data: SpringView! + override var preferredStatusBarStyle: UIStatusBarStyle { + .lightContent + } + override func viewDidLoad() { super.viewDidLoad() @@ -58,13 +62,13 @@ class CodeViewController: UIViewController { } @IBAction func closeButtonPressed(_ sender: AnyObject) { - UIApplication.shared.sendAction(#selector(SpringViewController.maximizeView(_:)), to: nil, from: self, for: nil) + UIApplication.shared.sendAction(#selector(SpringViewController.maximizeView), to: nil, from: self, for: nil) modalView.animation = "slideRight" modalView.animateFrom = false - modalView.animateToNext(completion: { + modalView.animateToNext { self.dismiss(animated: false, completion: nil) - }) + } } override func viewDidAppear(_ animated: Bool) { @@ -72,7 +76,7 @@ class CodeViewController: UIViewController { modalView.animate() - UIApplication.shared.sendAction(#selector(SpringViewController.minimizeView(_:)), to: nil, from: self, for: nil) + UIApplication.shared.sendAction(#selector(SpringViewController.minimizeView), to: nil, from: self, for: nil) } } diff --git a/SpringApp/OptionsViewController.swift b/SpringApp/OptionsViewController.swift index be62011..0695573 100644 --- a/SpringApp/OptionsViewController.swift +++ b/SpringApp/OptionsViewController.swift @@ -47,6 +47,10 @@ class OptionsViewController: UIViewController { weak var delegate: OptionsViewControllerDelegate? var data: SpringView! + override var preferredStatusBarStyle: UIStatusBarStyle { + .lightContent + } + override func viewDidLoad() { super.viewDidLoad() diff --git a/SpringApp/SpringViewController.swift b/SpringApp/SpringViewController.swift index a007581..5d99448 100644 --- a/SpringApp/SpringViewController.swift +++ b/SpringApp/SpringViewController.swift @@ -10,7 +10,7 @@ import UIKit import Spring class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource, OptionsViewControllerDelegate { - + @IBOutlet weak var delayLabel: UILabel! @IBOutlet weak var durationLabel: UILabel! @IBOutlet weak var forceLabel: UILabel! @@ -34,6 +34,11 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView var selectedY: CGFloat = 0 var selectedRotate: CGFloat = 0 + override var preferredStatusBarStyle: UIStatusBarStyle { + print("preferredStatusBarStyle") + return .default + } + @IBAction func forceSliderChanged(_ sender: AnyObject) { selectedForce = sender.value(forKey: "value") as! CGFloat animateView() @@ -49,7 +54,7 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView animateView() delayLabel.text = String(format: "Delay: %.1f", Double(selectedDelay)) } - + func dampingSliderChanged(_ sender: AnyObject) { selectedDamping = sender.value(forKey: "value") as! CGFloat animateView() @@ -102,20 +107,18 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView ballView.curve = animationCurves[selectedEasing].rawValue } - @objc func minimizeView(_ sender: AnyObject) { - SpringAnimation.spring(duration: 0.7, animations: { + @objc func minimizeView(_ sender: AnyObject) { + SpringAnimation.spring(duration: 0.7) { self.view.transform = CGAffineTransform(scaleX: 0.935, y: 0.935) - }) - UIApplication.shared.setStatusBarStyle(UIStatusBarStyle.lightContent, animated: true) + } } - @objc func maximizeView(_ sender: AnyObject) { - SpringAnimation.spring(duration: 0.7, animations: { + @objc func maximizeView(_ sender: AnyObject) { + SpringAnimation.spring(duration: 0.7) { self.view.transform = CGAffineTransform(scaleX: 1, y: 1) - }) - UIApplication.shared.setStatusBarStyle(UIStatusBarStyle.default, animated: true) + } } - + let animations: [Spring.AnimationPreset] = [ .shake, .pop, @@ -144,7 +147,7 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView .zoomOut, .flash ] - + var animationCurves: [Spring.AnimationCurve] = [ .easeIn, .easeOut, From 84d272b473f889f5fa3e82e738beca9ff134c866 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 27 Apr 2021 15:06:01 +0500 Subject: [PATCH 09/21] ViewController refactoring --- Spring/Spring.swift | 4 +- SpringApp/SpringViewController.swift | 102 ++++++--------------------- 2 files changed, 23 insertions(+), 83 deletions(-) diff --git a/Spring/Spring.swift b/Spring/Spring.swift index 12f4b81..4e6c156 100644 --- a/Spring/Spring.swift +++ b/Spring/Spring.swift @@ -103,7 +103,7 @@ public class Spring : NSObject { private var transform : CGAffineTransform { get { return view.transform } set { view.transform = newValue }} private var alpha: CGFloat { get { return view.alpha } set { view.alpha = newValue } } - public enum AnimationPreset: String { + public enum AnimationPreset: String, CaseIterable { case slideLeft case slideRight case slideDown @@ -133,7 +133,7 @@ public class Spring : NSObject { case swing } - public enum AnimationCurve: String { + public enum AnimationCurve: String, CaseIterable { case easeIn case easeOut case easeInOut diff --git a/SpringApp/SpringViewController.swift b/SpringApp/SpringViewController.swift index 5d99448..c0d4155 100644 --- a/SpringApp/SpringViewController.swift +++ b/SpringApp/SpringViewController.swift @@ -20,8 +20,8 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView @IBOutlet weak var ballView: SpringView! @IBOutlet weak var animationPicker: UIPickerView! - var selectedRow: Int = 0 - var selectedEasing: Int = 0 + var selectedRow = 0 + var selectedEasing = 0 var selectedForce: CGFloat = 1 var selectedDuration: CGFloat = 1 @@ -34,9 +34,20 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView var selectedY: CGFloat = 0 var selectedRotate: CGFloat = 0 + var isBall = false + + let animations = Spring.AnimationPreset.allCases + let animationCurves = Spring.AnimationCurve.allCases + + override func viewDidLoad() { + super.viewDidLoad() + animationPicker.delegate = self + animationPicker.dataSource = self + animationPicker.showsSelectionIndicator = true + } + override var preferredStatusBarStyle: UIStatusBarStyle { - print("preferredStatusBarStyle") - return .default + .default } @IBAction func forceSliderChanged(_ sender: AnyObject) { @@ -85,12 +96,12 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView animateView() } - func animateView() { + private func animateView() { setOptions() ballView.animate() } - func setOptions() { + private func setOptions() { ballView.force = selectedForce ballView.duration = selectedDuration ballView.delay = selectedDelay @@ -107,87 +118,18 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView ballView.curve = animationCurves[selectedEasing].rawValue } - @objc func minimizeView(_ sender: AnyObject) { + @objc private func minimizeView(_ sender: AnyObject) { SpringAnimation.spring(duration: 0.7) { self.view.transform = CGAffineTransform(scaleX: 0.935, y: 0.935) } } - @objc func maximizeView(_ sender: AnyObject) { + @objc private func maximizeView(_ sender: AnyObject) { SpringAnimation.spring(duration: 0.7) { self.view.transform = CGAffineTransform(scaleX: 1, y: 1) } } - let animations: [Spring.AnimationPreset] = [ - .shake, - .pop, - .morph, - .squeeze, - .wobble, - .swing, - .flipX, - .flipY, - .fall, - .squeezeLeft, - .squeezeRight, - .squeezeDown, - .squeezeUp, - .slideLeft, - .slideRight, - .slideDown, - .slideUp, - .fadeIn, - .fadeOut, - .fadeInLeft, - .fadeInRight, - .fadeInDown, - .fadeInUp, - .zoomIn, - .zoomOut, - .flash - ] - - var animationCurves: [Spring.AnimationCurve] = [ - .easeIn, - .easeOut, - .easeInOut, - .linear, - .spring, - .easeInSine, - .easeOutSine, - .easeInOutSine, - .easeInQuad, - .easeOutQuad, - .easeInOutQuad, - .easeInCubic, - .easeOutCubic, - .easeInOutCubic, - .easeInQuart, - .easeOutQuart, - .easeInOutQuart, - .easeInQuint, - .easeOutQuint, - .easeInOutQuint, - .easeInExpo, - .easeOutExpo, - .easeInOutExpo, - .easeInCirc, - .easeOutCirc, - .easeInOutCirc, - .easeInBack, - .easeOutBack, - .easeInOutBack - ] - - override func viewDidLoad() { - super.viewDidLoad() - - animationPicker.delegate = self - animationPicker.dataSource = self - animationPicker.showsSelectionIndicator = true - } - @IBAction func ballButtonPressed(_ sender: AnyObject) { UIView.animate(withDuration: 0.1, animations: { @@ -201,9 +143,8 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView animateView() } - var isBall = false func changeBall() { - isBall = !isBall + isBall.toggle() let animation = CABasicAnimation() let halfWidth = ballView.frame.width / 2 let cornerRadius: CGFloat = isBall ? halfWidth : 10 @@ -268,8 +209,7 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView optionsViewController.delegate = self setOptions() optionsViewController.data = ballView - } - else if let codeViewController = segue.destination as? CodeViewController { + } else if let codeViewController = segue.destination as? CodeViewController { setOptions() codeViewController.data = ballView } From b63dd23b3c59e2ffbd592c38622c07a99a78b3fa Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 27 Apr 2021 15:08:21 +0500 Subject: [PATCH 10/21] Bug fixes --- SpringApp/OptionsViewController.swift | 6 +++--- SpringApp/SpringViewController.swift | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/SpringApp/OptionsViewController.swift b/SpringApp/OptionsViewController.swift index 0695573..eb27613 100644 --- a/SpringApp/OptionsViewController.swift +++ b/SpringApp/OptionsViewController.swift @@ -111,19 +111,19 @@ class OptionsViewController: UIViewController { delegate?.resetButtonPressed(sender) dismiss(animated: true, completion: nil) - UIApplication.shared.sendAction(#selector(SpringViewController.maximizeView(_:)), to: nil, from: self, for: nil) + UIApplication.shared.sendAction(#selector(SpringViewController.maximizeView), to: nil, from: self, for: nil) } @IBAction func closeButtonPressed(_ sender: AnyObject) { dismiss(animated: true, completion: nil) - UIApplication.shared.sendAction(#selector(SpringViewController.maximizeView(_:)), to: nil, from: self, for: nil) + UIApplication.shared.sendAction(#selector(SpringViewController.maximizeView), to: nil, from: self, for: nil) } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(true) - UIApplication.shared.sendAction(#selector(SpringViewController.minimizeView(_:)), to: nil, from: self, for: nil) + UIApplication.shared.sendAction(#selector(SpringViewController.minimizeView), to: nil, from: self, for: nil) modalView.animate() } diff --git a/SpringApp/SpringViewController.swift b/SpringApp/SpringViewController.swift index c0d4155..be3e630 100644 --- a/SpringApp/SpringViewController.swift +++ b/SpringApp/SpringViewController.swift @@ -118,13 +118,13 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView ballView.curve = animationCurves[selectedEasing].rawValue } - @objc private func minimizeView(_ sender: AnyObject) { + @objc func minimizeView(_ sender: AnyObject) { SpringAnimation.spring(duration: 0.7) { self.view.transform = CGAffineTransform(scaleX: 0.935, y: 0.935) } } - @objc private func maximizeView(_ sender: AnyObject) { + @objc func maximizeView(_ sender: AnyObject) { SpringAnimation.spring(duration: 0.7) { self.view.transform = CGAffineTransform(scaleX: 1, y: 1) } From c08359bb350296feb878752b28ba0923d97b0832 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 27 Apr 2021 15:33:06 +0500 Subject: [PATCH 11/21] Refactoring Spring class --- Spring/Spring.swift | 291 ++++++++++++------ SpringApp.xcodeproj/project.pbxproj | 3 +- .../AppIcon.appiconset/Contents.json | 105 ++++--- 3 files changed, 267 insertions(+), 132 deletions(-) diff --git a/Spring/Spring.swift b/Spring/Spring.swift index 4e6c156..be4e91b 100644 --- a/Spring/Spring.swift +++ b/Spring/Spring.swift @@ -22,7 +22,7 @@ import UIKit -@objc public protocol Springable { +public protocol Springable: class { var autostart: Bool { get set } var autohide: Bool { get set } var animation: String { get set } @@ -54,21 +54,153 @@ import UIKit public class Spring : NSObject { - private unowned var view : Springable + private unowned var view: Springable private var shouldAnimateAfterActive = false private var shouldAnimateInLayoutSubviews = true + private var autostart: Bool { + set { + view.autostart = newValue + } get { + view.autostart + } + } + private var autohide: Bool { + set { + view.autohide = newValue + } get { + view.autohide + } + } + private var animation: String { + set { + view.animation = newValue + } get { + view.animation + } + } + private var force: CGFloat { + set { + view.force = newValue + } get { + view.force + } + } + private var delay: CGFloat { + set { + view.delay = newValue + } get { + view.delay + + } + } + private var duration: CGFloat { + set { + view.duration = newValue + } get { + view.duration + } + } + private var damping: CGFloat { + set { + view.damping = newValue + } get { + view.damping + } + } + private var velocity: CGFloat { + set { + view.velocity = newValue + } get { + view.velocity + } + } + private var repeatCount: Float { + set { + view.repeatCount = newValue + } get { + view.repeatCount + } + } + private var x: CGFloat { + set { + view.x = newValue + } get { + view.x + } + } + private var y: CGFloat { + set { + view.y = newValue + } get { + view.y + } + } + private var scaleX: CGFloat { + set { + view.scaleX = newValue + } get { + view.scaleX + } + } + private var scaleY: CGFloat { + set { + view.scaleY = newValue + } get { + view.scaleY + } + } + + private var rotate: CGFloat { + set { + view.rotate = newValue + } get { + view.rotate + } + } + private var opacity: CGFloat { + set { + view.opacity = newValue + } get { + view.opacity + } + } + private var animateFrom: Bool { + set { + view.animateFrom = newValue + } get { + view.animateFrom + } + } + private var curve: String { + set { + view.curve = newValue + } get { + view.curve + } + } + + // UIView + private var layer : CALayer { return view.layer } + private var transform : CGAffineTransform { get { return view.transform } set { view.transform = newValue }} + private var alpha: CGFloat { get { return view.alpha } set { view.alpha = newValue } } + init(_ view: Springable) { self.view = view super.init() commonInit() } - func commonInit() { - NotificationCenter.default.addObserver(self, selector: #selector(Spring.didBecomeActiveNotification(_:)), name: UIApplication.didBecomeActiveNotification, object: nil) + private func commonInit() { + NotificationCenter.default.addObserver( + self, + selector: #selector(didBecomeActiveNotification), + name: UIApplication.didBecomeActiveNotification, + object: nil + ) } - @objc func didBecomeActiveNotification(_ notification: NSNotification) { + @objc private func didBecomeActiveNotification(_ notification: NSNotification) { if shouldAnimateAfterActive { alpha = 0 animate() @@ -80,91 +212,6 @@ public class Spring : NSObject { NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil) } - private var autostart: Bool { set { self.view.autostart = newValue } get { return self.view.autostart }} - private var autohide: Bool { set { self.view.autohide = newValue } get { return self.view.autohide }} - private var animation: String { set { self.view.animation = newValue } get { return self.view.animation }} - private var force: CGFloat { set { self.view.force = newValue } get { return self.view.force }} - private var delay: CGFloat { set { self.view.delay = newValue } get { return self.view.delay }} - private var duration: CGFloat { set { self.view.duration = newValue } get { return self.view.duration }} - private var damping: CGFloat { set { self.view.damping = newValue } get { return self.view.damping }} - private var velocity: CGFloat { set { self.view.velocity = newValue } get { return self.view.velocity }} - private var repeatCount: Float { set { self.view.repeatCount = newValue } get { return self.view.repeatCount }} - private var x: CGFloat { set { self.view.x = newValue } get { return self.view.x }} - private var y: CGFloat { set { self.view.y = newValue } get { return self.view.y }} - private var scaleX: CGFloat { set { self.view.scaleX = newValue } get { return self.view.scaleX }} - private var scaleY: CGFloat { set { self.view.scaleY = newValue } get { return self.view.scaleY }} - private var rotate: CGFloat { set { self.view.rotate = newValue } get { return self.view.rotate }} - private var opacity: CGFloat { set { self.view.opacity = newValue } get { return self.view.opacity }} - private var animateFrom: Bool { set { self.view.animateFrom = newValue } get { return self.view.animateFrom }} - private var curve: String { set { self.view.curve = newValue } get { return self.view.curve }} - - // UIView - private var layer : CALayer { return view.layer } - private var transform : CGAffineTransform { get { return view.transform } set { view.transform = newValue }} - private var alpha: CGFloat { get { return view.alpha } set { view.alpha = newValue } } - - public enum AnimationPreset: String, CaseIterable { - case slideLeft - case slideRight - case slideDown - case slideUp - case squeezeLeft - case squeezeRight - case squeezeDown - case squeezeUp - case fadeIn - case fadeOut - case fadeOutIn - case fadeInLeft - case fadeInRight - case fadeInDown - case fadeInUp - case zoomIn - case zoomOut - case fall - case shake - case pop - case flipX - case flipY - case morph - case squeeze - case flash - case wobble - case swing - } - - public enum AnimationCurve: String, CaseIterable { - case easeIn - case easeOut - case easeInOut - case linear - case spring - case easeInSine - case easeOutSine - case easeInOutSine - case easeInQuad - case easeOutQuad - case easeInOutQuad - case easeInCubic - case easeOutCubic - case easeInOutCubic - case easeInQuart - case easeOutQuart - case easeInOutQuart - case easeInQuint - case easeOutQuint - case easeInOutQuint - case easeInExpo - case easeOutExpo - case easeInOutExpo - case easeInCirc - case easeOutCirc - case easeInOutCirc - case easeInBack - case easeOutBack - case easeInOutBack - } - func animatePreset() { alpha = 0.99 if let animation = AnimationPreset(rawValue: animation) { @@ -530,3 +577,67 @@ public class Spring : NSObject { } } + +extension Spring { + public enum AnimationPreset: String, CaseIterable { + case slideLeft + case slideRight + case slideDown + case slideUp + case squeezeLeft + case squeezeRight + case squeezeDown + case squeezeUp + case fadeIn + case fadeOut + case fadeOutIn + case fadeInLeft + case fadeInRight + case fadeInDown + case fadeInUp + case zoomIn + case zoomOut + case fall + case shake + case pop + case flipX + case flipY + case morph + case squeeze + case flash + case wobble + case swing + } + + public enum AnimationCurve: String, CaseIterable { + case easeIn + case easeOut + case easeInOut + case linear + case spring + case easeInSine + case easeOutSine + case easeInOutSine + case easeInQuad + case easeOutQuad + case easeInOutQuad + case easeInCubic + case easeOutCubic + case easeInOutCubic + case easeInQuart + case easeOutQuart + case easeInOutQuart + case easeInQuint + case easeOutQuint + case easeInOutQuint + case easeInExpo + case easeOutExpo + case easeInOutExpo + case easeInCirc + case easeOutCirc + case easeInOutCirc + case easeInBack + case easeOutBack + case easeInOutBack + } +} diff --git a/SpringApp.xcodeproj/project.pbxproj b/SpringApp.xcodeproj/project.pbxproj index 9ab9368..678cdfe 100644 --- a/SpringApp.xcodeproj/project.pbxproj +++ b/SpringApp.xcodeproj/project.pbxproj @@ -433,10 +433,9 @@ }; buildConfigurationList = 964117361A5BE90A000E3A5A /* Build configuration list for PBXProject "SpringApp" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( - English, en, Base, ); diff --git a/SpringApp/Images.xcassets/AppIcon.appiconset/Contents.json b/SpringApp/Images.xcassets/AppIcon.appiconset/Contents.json index 1acc2b0..f7f2119 100644 --- a/SpringApp/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/SpringApp/Images.xcassets/AppIcon.appiconset/Contents.json @@ -1,86 +1,111 @@ { "images" : [ { - "size" : "29x29", "idiom" : "iphone", - "filename" : "appicon@58.png", - "scale" : "2x" + "scale" : "2x", + "size" : "20x20" }, { - "size" : "29x29", "idiom" : "iphone", - "filename" : "appicon@87.png", - "scale" : "3x" + "scale" : "3x", + "size" : "20x20" }, { - "size" : "40x40", + "filename" : "appicon@58.png", "idiom" : "iphone", - "filename" : "appicon@80.png", - "scale" : "2x" + "scale" : "2x", + "size" : "29x29" }, { - "size" : "40x40", + "filename" : "appicon@87.png", "idiom" : "iphone", - "filename" : "appicon@120.png", - "scale" : "3x" + "scale" : "3x", + "size" : "29x29" }, { - "size" : "60x60", + "filename" : "appicon@80.png", "idiom" : "iphone", - "filename" : "appicon@120-1.png", - "scale" : "2x" + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "appicon@120.png", + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" }, { - "size" : "60x60", + "filename" : "appicon@120-1.png", "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { "filename" : "appicon@180.png", - "scale" : "3x" + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" }, { - "size" : "29x29", "idiom" : "ipad", - "filename" : "appicon@29.png", - "scale" : "1x" + "scale" : "1x", + "size" : "20x20" }, { - "size" : "29x29", "idiom" : "ipad", - "filename" : "appicon@58-1.png", - "scale" : "2x" + "scale" : "2x", + "size" : "20x20" }, { - "size" : "40x40", + "filename" : "appicon@29.png", "idiom" : "ipad", - "filename" : "appicon@40.png", - "scale" : "1x" + "scale" : "1x", + "size" : "29x29" }, { - "size" : "40x40", + "filename" : "appicon@58-1.png", "idiom" : "ipad", - "filename" : "appicon@80-1.png", - "scale" : "2x" + "scale" : "2x", + "size" : "29x29" }, { - "size" : "76x76", + "filename" : "appicon@40.png", "idiom" : "ipad", - "filename" : "appicon@76.png", - "scale" : "1x" + "scale" : "1x", + "size" : "40x40" }, { - "size" : "76x76", + "filename" : "appicon@80-1.png", "idiom" : "ipad", - "filename" : "appicon@152.png", - "scale" : "2x" + "scale" : "2x", + "size" : "40x40" + }, + { + "filename" : "appicon@76.png", + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" }, { - "size" : "83.5x83.5", + "filename" : "appicon@152.png", "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { "filename" : "appicon@167.png", - "scale" : "2x" + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} From 05fa00fbbec7167ab1d333ced8b22871a9c179c5 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 27 Apr 2021 15:34:14 +0500 Subject: [PATCH 12/21] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ac6a29f..1a14ae4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -## Updated for Swift 4.2 -Requires Xcode 10 and Swift 4.2. +## Updated for Swift 5 +Requires Xcode 12 and Swift 5.3 ## Installation Drop in the Spring folder to your Xcode project (make sure to enable "Copy items if needed" and "Create groups"). From 97b88b7c0c9303ca8910c51e9d77c5b24c05009d Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 21 Sep 2021 18:34:52 +0300 Subject: [PATCH 13/21] Swift 5.5 support --- README.md | 2 +- Spring.podspec | 8 +- Spring/LoadingView.xib | 18 +- Spring/Spring.swift | 2 +- SpringApp.xcodeproj/project.pbxproj | 265 +------------------------- SpringApp/OptionsViewController.swift | 3 +- SpringAppTests/Info.plist | 24 --- SpringAppTests/SpringAppTests.swift | 36 ---- SpringTests/Info.plist | 24 --- SpringTests/SpringTests.swift | 36 ---- 10 files changed, 22 insertions(+), 396 deletions(-) delete mode 100644 SpringAppTests/Info.plist delete mode 100644 SpringAppTests/SpringAppTests.swift delete mode 100644 SpringTests/Info.plist delete mode 100644 SpringTests/SpringTests.swift diff --git a/README.md b/README.md index 1a14ae4..debd466 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ ## Updated for Swift 5 -Requires Xcode 12 and Swift 5.3 +Requires Xcode 13 and Swift 5.5 ## Installation Drop in the Spring folder to your Xcode project (make sure to enable "Copy items if needed" and "Create groups"). diff --git a/Spring.podspec b/Spring.podspec index a43ed30..d1a28e6 100644 --- a/Spring.podspec +++ b/Spring.podspec @@ -1,13 +1,13 @@ Pod::Spec.new do |s| s.name = 'Spring' - s.version = '1.0.6' + s.version = '1.0.9' s.license = 'MIT' s.summary = 'A library to simplify iOS animations in Swift.' - s.homepage = 'https://github.com/MengTo/Spring' + s.homepage = 'https://github.com/LexDeBash/Spring' s.authors = { 'Meng To' => 'meng@designcode.io' } - s.source = { :git => 'https://github.com/MengTo/Spring.git', :tag => s.version.to_s } + s.source = { :git => 'https://github.com/LexDeBash/Spring.git', :tag => s.version.to_s } s.requires_arc = true - s.ios.deployment_target = '8.0' + s.ios.deployment_target = '14.0' s.tvos.deployment_target = '11.0' s.source_files = 'Spring/*.swift' s.ios.resources = ['Spring/*.xib', 'SpringApp/*.xcassets'] diff --git a/Spring/LoadingView.xib b/Spring/LoadingView.xib index 58a95a6..48a0901 100644 --- a/Spring/LoadingView.xib +++ b/Spring/LoadingView.xib @@ -1,17 +1,20 @@ - - + + + - + + + - + - + @@ -21,7 +24,7 @@ - + @@ -30,7 +33,7 @@ - + @@ -38,6 +41,7 @@ + diff --git a/Spring/Spring.swift b/Spring/Spring.swift index be4e91b..c74c0af 100644 --- a/Spring/Spring.swift +++ b/Spring/Spring.swift @@ -22,7 +22,7 @@ import UIKit -public protocol Springable: class { +public protocol Springable: AnyObject { var autostart: Bool { get set } var autohide: Bool { get set } var animation: String { get set } diff --git a/SpringApp.xcodeproj/project.pbxproj b/SpringApp.xcodeproj/project.pbxproj index 678cdfe..968738c 100644 --- a/SpringApp.xcodeproj/project.pbxproj +++ b/SpringApp.xcodeproj/project.pbxproj @@ -8,8 +8,6 @@ /* Begin PBXBuildFile section */ 1A4FDA381A6E44780099D309 /* Spring.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A4FDA371A6E44780099D309 /* Spring.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1A4FDA3E1A6E44780099D309 /* Spring.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A4FDA331A6E44780099D309 /* Spring.framework */; }; - 1A4FDA471A6E44780099D309 /* SpringTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A4FDA461A6E44780099D309 /* SpringTests.swift */; }; 1A4FDA4A1A6E44780099D309 /* Spring.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A4FDA331A6E44780099D309 /* Spring.framework */; }; 1A4FDA4B1A6E44780099D309 /* Spring.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 1A4FDA331A6E44780099D309 /* Spring.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 1A4FDA531A6E44A70099D309 /* LoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A4FDA2A1A6E44270099D309 /* LoadingView.swift */; }; @@ -44,7 +42,6 @@ 964117461A5BE90A000E3A5A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 964117441A5BE90A000E3A5A /* Main.storyboard */; }; 964117481A5BE90A000E3A5A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 964117471A5BE90A000E3A5A /* Images.xcassets */; }; 9641174B1A5BE90A000E3A5A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 964117491A5BE90A000E3A5A /* LaunchScreen.xib */; }; - 964117571A5BE90A000E3A5A /* SpringAppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 964117561A5BE90A000E3A5A /* SpringAppTests.swift */; }; 9641178B1A5BEC6F000E3A5A /* SpringViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 964117881A5BEC6F000E3A5A /* SpringViewController.swift */; }; 9641178C1A5BEC6F000E3A5A /* OptionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 964117891A5BEC6F000E3A5A /* OptionsViewController.swift */; }; 9641178D1A5BEC6F000E3A5A /* CodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9641178A1A5BEC6F000E3A5A /* CodeViewController.swift */; }; @@ -52,20 +49,6 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 1A4FDA3F1A6E44780099D309 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 964117331A5BE90A000E3A5A /* Project object */; - proxyType = 1; - remoteGlobalIDString = 1A4FDA321A6E44780099D309; - remoteInfo = Spring; - }; - 1A4FDA411A6E44780099D309 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 964117331A5BE90A000E3A5A /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9641173A1A5BE90A000E3A5A; - remoteInfo = SpringApp; - }; 1A4FDA481A6E44780099D309 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 964117331A5BE90A000E3A5A /* Project object */; @@ -73,13 +56,6 @@ remoteGlobalIDString = 1A4FDA321A6E44780099D309; remoteInfo = Spring; }; - 964117511A5BE90A000E3A5A /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 964117331A5BE90A000E3A5A /* Project object */; - proxyType = 1; - remoteGlobalIDString = 9641173A1A5BE90A000E3A5A; - remoteInfo = SpringApp; - }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -102,9 +78,6 @@ 1A4FDA331A6E44780099D309 /* Spring.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Spring.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1A4FDA361A6E44780099D309 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 1A4FDA371A6E44780099D309 /* Spring.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Spring.h; sourceTree = ""; }; - 1A4FDA3D1A6E44780099D309 /* SpringTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SpringTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 1A4FDA451A6E44780099D309 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 1A4FDA461A6E44780099D309 /* SpringTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpringTests.swift; sourceTree = ""; }; 1A585F3F1A7B9530007EEB7D /* KeyboardLayoutConstraint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardLayoutConstraint.swift; sourceTree = ""; }; 1A9F866C1A83C5640098BE6C /* SoundPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SoundPlayer.swift; sourceTree = ""; }; 1AA7E1811AA36EFF00762D75 /* AsyncImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsyncImageView.swift; sourceTree = ""; }; @@ -135,9 +108,6 @@ 964117451A5BE90A000E3A5A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 964117471A5BE90A000E3A5A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 9641174A1A5BE90A000E3A5A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; - 964117501A5BE90A000E3A5A /* SpringAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SpringAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 964117551A5BE90A000E3A5A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 964117561A5BE90A000E3A5A /* SpringAppTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpringAppTests.swift; sourceTree = ""; }; 964117881A5BEC6F000E3A5A /* SpringViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpringViewController.swift; sourceTree = ""; }; 964117891A5BEC6F000E3A5A /* OptionsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OptionsViewController.swift; sourceTree = ""; }; 9641178A1A5BEC6F000E3A5A /* CodeViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CodeViewController.swift; sourceTree = ""; }; @@ -153,14 +123,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 1A4FDA3A1A6E44780099D309 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 1A4FDA3E1A6E44780099D309 /* Spring.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 964117381A5BE90A000E3A5A /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -169,13 +131,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 9641174D1A5BE90A000E3A5A /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -196,23 +151,6 @@ name = "Supporting Files"; sourceTree = ""; }; - 1A4FDA431A6E44780099D309 /* SpringTests */ = { - isa = PBXGroup; - children = ( - 1A4FDA461A6E44780099D309 /* SpringTests.swift */, - 1A4FDA441A6E44780099D309 /* Supporting Files */, - ); - path = SpringTests; - sourceTree = ""; - }; - 1A4FDA441A6E44780099D309 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 1A4FDA451A6E44780099D309 /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; 961888D21A66BF9000295A64 /* Spring */ = { isa = PBXGroup; children = ( @@ -252,9 +190,7 @@ isa = PBXGroup; children = ( 9641173D1A5BE90A000E3A5A /* SpringApp */, - 964117531A5BE90A000E3A5A /* SpringAppTests */, 1A4FDA341A6E44780099D309 /* Spring */, - 1A4FDA431A6E44780099D309 /* SpringTests */, 9641173C1A5BE90A000E3A5A /* Products */, ); indentWidth = 4; @@ -265,9 +201,7 @@ isa = PBXGroup; children = ( 9641173B1A5BE90A000E3A5A /* SpringApp.app */, - 964117501A5BE90A000E3A5A /* SpringAppTests.xctest */, 1A4FDA331A6E44780099D309 /* Spring.framework */, - 1A4FDA3D1A6E44780099D309 /* SpringTests.xctest */, ); name = Products; sourceTree = ""; @@ -296,23 +230,6 @@ name = "Supporting Files"; sourceTree = ""; }; - 964117531A5BE90A000E3A5A /* SpringAppTests */ = { - isa = PBXGroup; - children = ( - 964117561A5BE90A000E3A5A /* SpringAppTests.swift */, - 964117541A5BE90A000E3A5A /* Supporting Files */, - ); - path = SpringAppTests; - sourceTree = ""; - }; - 964117541A5BE90A000E3A5A /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 964117551A5BE90A000E3A5A /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -345,25 +262,6 @@ productReference = 1A4FDA331A6E44780099D309 /* Spring.framework */; productType = "com.apple.product-type.framework"; }; - 1A4FDA3C1A6E44780099D309 /* SpringTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1A4FDA501A6E44780099D309 /* Build configuration list for PBXNativeTarget "SpringTests" */; - buildPhases = ( - 1A4FDA391A6E44780099D309 /* Sources */, - 1A4FDA3A1A6E44780099D309 /* Frameworks */, - 1A4FDA3B1A6E44780099D309 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 1A4FDA401A6E44780099D309 /* PBXTargetDependency */, - 1A4FDA421A6E44780099D309 /* PBXTargetDependency */, - ); - name = SpringTests; - productName = SpringTests; - productReference = 1A4FDA3D1A6E44780099D309 /* SpringTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; 9641173A1A5BE90A000E3A5A /* SpringApp */ = { isa = PBXNativeTarget; buildConfigurationList = 9641175A1A5BE90A000E3A5A /* Build configuration list for PBXNativeTarget "SpringApp" */; @@ -383,24 +281,6 @@ productReference = 9641173B1A5BE90A000E3A5A /* SpringApp.app */; productType = "com.apple.product-type.application"; }; - 9641174F1A5BE90A000E3A5A /* SpringAppTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 9641175D1A5BE90A000E3A5A /* Build configuration list for PBXNativeTarget "SpringAppTests" */; - buildPhases = ( - 9641174C1A5BE90A000E3A5A /* Sources */, - 9641174D1A5BE90A000E3A5A /* Frameworks */, - 9641174E1A5BE90A000E3A5A /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 964117521A5BE90A000E3A5A /* PBXTargetDependency */, - ); - name = SpringAppTests; - productName = SpringAppTests; - productReference = 964117501A5BE90A000E3A5A /* SpringAppTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -415,20 +295,10 @@ CreatedOnToolsVersion = 6.1.1; LastSwiftMigration = 1020; }; - 1A4FDA3C1A6E44780099D309 = { - CreatedOnToolsVersion = 6.1.1; - LastSwiftMigration = 1020; - TestTargetID = 9641173A1A5BE90A000E3A5A; - }; 9641173A1A5BE90A000E3A5A = { CreatedOnToolsVersion = 6.2; LastSwiftMigration = 1020; }; - 9641174F1A5BE90A000E3A5A = { - CreatedOnToolsVersion = 6.2; - LastSwiftMigration = 1020; - TestTargetID = 9641173A1A5BE90A000E3A5A; - }; }; }; buildConfigurationList = 964117361A5BE90A000E3A5A /* Build configuration list for PBXProject "SpringApp" */; @@ -445,9 +315,7 @@ projectRoot = ""; targets = ( 9641173A1A5BE90A000E3A5A /* SpringApp */, - 9641174F1A5BE90A000E3A5A /* SpringAppTests */, 1A4FDA321A6E44780099D309 /* Spring */, - 1A4FDA3C1A6E44780099D309 /* SpringTests */, ); }; /* End PBXProject section */ @@ -462,13 +330,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 1A4FDA3B1A6E44780099D309 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 964117391A5BE90A000E3A5A /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -479,13 +340,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 9641174E1A5BE90A000E3A5A /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -522,14 +376,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 1A4FDA391A6E44780099D309 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 1A4FDA471A6E44780099D309 /* SpringTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 964117371A5BE90A000E3A5A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -542,37 +388,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 9641174C1A5BE90A000E3A5A /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 964117571A5BE90A000E3A5A /* SpringAppTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 1A4FDA401A6E44780099D309 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 1A4FDA321A6E44780099D309 /* Spring */; - targetProxy = 1A4FDA3F1A6E44780099D309 /* PBXContainerItemProxy */; - }; - 1A4FDA421A6E44780099D309 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9641173A1A5BE90A000E3A5A /* SpringApp */; - targetProxy = 1A4FDA411A6E44780099D309 /* PBXContainerItemProxy */; - }; 1A4FDA491A6E44780099D309 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1A4FDA321A6E44780099D309 /* Spring */; targetProxy = 1A4FDA481A6E44780099D309 /* PBXContainerItemProxy */; }; - 964117521A5BE90A000E3A5A /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 9641173A1A5BE90A000E3A5A /* SpringApp */; - targetProxy = 964117511A5BE90A000E3A5A /* PBXContainerItemProxy */; - }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -610,7 +433,7 @@ ); INFOPLIST_FILE = Spring/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -633,7 +456,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = Spring/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -646,37 +469,6 @@ }; name = Release; }; - 1A4FDA511A6E44780099D309 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = SpringTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.jamztang.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SpringApp.app/SpringApp"; - }; - name = Debug; - }; - 1A4FDA521A6E44780099D309 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - INFOPLIST_FILE = SpringTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.jamztang.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SpringApp.app/SpringApp"; - }; - name = Release; - }; 964117581A5BE90A000E3A5A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -788,7 +580,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = SpringApp/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -802,7 +594,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; INFOPLIST_FILE = SpringApp/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -812,37 +604,6 @@ }; name = Release; }; - 9641175E1A5BE90A000E3A5A /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = SpringAppTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SpringApp.app/SpringApp"; - }; - name = Debug; - }; - 9641175F1A5BE90A000E3A5A /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - INFOPLIST_FILE = SpringAppTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SpringApp.app/SpringApp"; - }; - name = Release; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -855,15 +616,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 1A4FDA501A6E44780099D309 /* Build configuration list for PBXNativeTarget "SpringTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1A4FDA511A6E44780099D309 /* Debug */, - 1A4FDA521A6E44780099D309 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 964117361A5BE90A000E3A5A /* Build configuration list for PBXProject "SpringApp" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -882,15 +634,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 9641175D1A5BE90A000E3A5A /* Build configuration list for PBXNativeTarget "SpringAppTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 9641175E1A5BE90A000E3A5A /* Debug */, - 9641175F1A5BE90A000E3A5A /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ }; rootObject = 964117331A5BE90A000E3A5A /* Project object */; diff --git a/SpringApp/OptionsViewController.swift b/SpringApp/OptionsViewController.swift index eb27613..5ae2c28 100644 --- a/SpringApp/OptionsViewController.swift +++ b/SpringApp/OptionsViewController.swift @@ -6,10 +6,9 @@ // Copyright (c) 2015 Meng To. All rights reserved. // -import UIKit import Spring -protocol OptionsViewControllerDelegate: class { +protocol OptionsViewControllerDelegate: AnyObject { func dampingSliderChanged(_ sender: AnyObject) func velocitySliderChanged(_ sender: AnyObject) func scaleSliderChanged(_ sender: AnyObject) diff --git a/SpringAppTests/Info.plist b/SpringAppTests/Info.plist deleted file mode 100644 index ba72822..0000000 --- a/SpringAppTests/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - - diff --git a/SpringAppTests/SpringAppTests.swift b/SpringAppTests/SpringAppTests.swift deleted file mode 100644 index ac2484b..0000000 --- a/SpringAppTests/SpringAppTests.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// SpringAppTests.swift -// SpringAppTests -// -// Created by Meng To on 2015-01-06. -// Copyright (c) 2015 Meng To. All rights reserved. -// - -import UIKit -import XCTest - -class SpringAppTests: XCTestCase { - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func testExample() { - // This is an example of a functional test case. - XCTAssert(true, "Pass") - } - - func testPerformanceExample() { - // This is an example of a performance test case. - self.measure() { - // Put the code you want to measure the time of here. - } - } - -} diff --git a/SpringTests/Info.plist b/SpringTests/Info.plist deleted file mode 100644 index ba72822..0000000 --- a/SpringTests/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - - diff --git a/SpringTests/SpringTests.swift b/SpringTests/SpringTests.swift deleted file mode 100644 index 938737d..0000000 --- a/SpringTests/SpringTests.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// SpringTests.swift -// SpringTests -// -// Created by James Tang on 20/1/15. -// Copyright (c) 2015 Meng To. All rights reserved. -// - -import UIKit -import XCTest - -class SpringTests: XCTestCase { - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func testExample() { - // This is an example of a functional test case. - XCTAssert(true, "Pass") - } - - func testPerformanceExample() { - // This is an example of a performance test case. - self.measure() { - // Put the code you want to measure the time of here. - } - } - -} From 053e7d2ba3106aaebbbc29c6c27075dcc8dbef92 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 21 Sep 2021 18:59:59 +0300 Subject: [PATCH 14/21] KeyboardLayoutConstraint refactoring --- Spring/KeyboardLayoutConstraint.swift | 42 ++++++++++++++------------- SpringApp/SpringViewController.swift | 1 - 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/Spring/KeyboardLayoutConstraint.swift b/Spring/KeyboardLayoutConstraint.swift index 1b45a56..f918a13 100644 --- a/Spring/KeyboardLayoutConstraint.swift +++ b/Spring/KeyboardLayoutConstraint.swift @@ -26,8 +26,8 @@ import UIKit @available(tvOS, unavailable) public class KeyboardLayoutConstraint: NSLayoutConstraint { - private var offset : CGFloat = 0 - private var keyboardVisibleHeight : CGFloat = 0 + private var offset: CGFloat = 0 + private var keyboardVisibleHeight: CGFloat = 0 @available(tvOS, unavailable) override public func awakeFromNib() { @@ -35,8 +35,18 @@ public class KeyboardLayoutConstraint: NSLayoutConstraint { offset = constant - NotificationCenter.default.addObserver(self, selector: #selector(KeyboardLayoutConstraint.keyboardWillShowNotification(_:)), name: UIWindow.keyboardWillShowNotification, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(KeyboardLayoutConstraint.keyboardWillHideNotification(_:)), name: UIWindow.keyboardWillHideNotification, object: nil) + NotificationCenter.default.addObserver( + self, + selector: #selector(KeyboardLayoutConstraint.keyboardWillShowNotification), + name: UIWindow.keyboardWillShowNotification, + object: nil + ) + NotificationCenter.default.addObserver( + self, + selector: #selector(KeyboardLayoutConstraint.keyboardWillHideNotification), + name: UIWindow.keyboardWillHideNotification, + object: nil + ) } deinit { @@ -44,7 +54,6 @@ public class KeyboardLayoutConstraint: NSLayoutConstraint { } // MARK: Notification - @objc func keyboardWillShowNotification(_ notification: Notification) { if let userInfo = notification.userInfo { if let frameValue = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue { @@ -61,24 +70,19 @@ public class KeyboardLayoutConstraint: NSLayoutConstraint { UIView.animate( withDuration: TimeInterval(duration.doubleValue), delay: 0, - options: options, - animations: { - UIApplication.shared.keyWindow?.layoutIfNeeded() + options: options) { + UIApplication.shared.windows.first?.layoutIfNeeded() return - }, completion: { finished in - }) + } default: - break } - } - } @objc func keyboardWillHideNotification(_ notification: NSNotification) { keyboardVisibleHeight = 0 - self.updateConstant() + updateConstant() if let userInfo = notification.userInfo { @@ -90,12 +94,10 @@ public class KeyboardLayoutConstraint: NSLayoutConstraint { UIView.animate( withDuration: TimeInterval(duration.doubleValue), delay: 0, - options: options, - animations: { - UIApplication.shared.keyWindow?.layoutIfNeeded() + options: options) { + UIApplication.shared.windows.first?.layoutIfNeeded() return - }, completion: { finished in - }) + } default: break } @@ -103,7 +105,7 @@ public class KeyboardLayoutConstraint: NSLayoutConstraint { } func updateConstant() { - self.constant = offset + keyboardVisibleHeight + constant = offset + keyboardVisibleHeight } } diff --git a/SpringApp/SpringViewController.swift b/SpringApp/SpringViewController.swift index be3e630..78371e3 100644 --- a/SpringApp/SpringViewController.swift +++ b/SpringApp/SpringViewController.swift @@ -43,7 +43,6 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView super.viewDidLoad() animationPicker.delegate = self animationPicker.dataSource = self - animationPicker.showsSelectionIndicator = true } override var preferredStatusBarStyle: UIStatusBarStyle { From bea1940f08abb8cc47f7a7a420f36876d3c35c1d Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 12 Apr 2022 13:31:16 +0300 Subject: [PATCH 15/21] Create Package.swift manifest --- Spring/.gitignore | 9 +++++++ Spring/Package.swift | 28 ++++++++++++++++++++++ Spring/Sources/Spring/Spring.swift | 6 +++++ Spring/Tests/SpringTests/SpringTests.swift | 11 +++++++++ 4 files changed, 54 insertions(+) create mode 100644 Spring/.gitignore create mode 100644 Spring/Package.swift create mode 100644 Spring/Sources/Spring/Spring.swift create mode 100644 Spring/Tests/SpringTests/SpringTests.swift diff --git a/Spring/.gitignore b/Spring/.gitignore new file mode 100644 index 0000000..3b29812 --- /dev/null +++ b/Spring/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc diff --git a/Spring/Package.swift b/Spring/Package.swift new file mode 100644 index 0000000..96d13f5 --- /dev/null +++ b/Spring/Package.swift @@ -0,0 +1,28 @@ +// swift-tools-version: 5.6 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "Spring", + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "Spring", + targets: ["Spring"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + // .package(url: /* package url */, from: "1.0.0"), + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "Spring", + dependencies: []), + .testTarget( + name: "SpringTests", + dependencies: ["Spring"]), + ] +) diff --git a/Spring/Sources/Spring/Spring.swift b/Spring/Sources/Spring/Spring.swift new file mode 100644 index 0000000..2129481 --- /dev/null +++ b/Spring/Sources/Spring/Spring.swift @@ -0,0 +1,6 @@ +public struct Spring { + public private(set) var text = "Hello, World!" + + public init() { + } +} diff --git a/Spring/Tests/SpringTests/SpringTests.swift b/Spring/Tests/SpringTests/SpringTests.swift new file mode 100644 index 0000000..e2fd3a1 --- /dev/null +++ b/Spring/Tests/SpringTests/SpringTests.swift @@ -0,0 +1,11 @@ +import XCTest +@testable import Spring + +final class SpringTests: XCTestCase { + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct + // results. + XCTAssertEqual(Spring().text, "Hello, World!") + } +} From e544f16615570b3b42c3796c9ffda4a4f2b898d5 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 12 Apr 2022 13:41:26 +0300 Subject: [PATCH 16/21] Create Package.swift manifest --- Spring/Package.swift => Package.swift | 0 {Spring/Sources => Sources}/Spring/Spring.swift | 0 Spring/.gitignore | 9 --------- {Spring/Tests => Tests}/SpringTests/SpringTests.swift | 0 4 files changed, 9 deletions(-) rename Spring/Package.swift => Package.swift (100%) rename {Spring/Sources => Sources}/Spring/Spring.swift (100%) delete mode 100644 Spring/.gitignore rename {Spring/Tests => Tests}/SpringTests/SpringTests.swift (100%) diff --git a/Spring/Package.swift b/Package.swift similarity index 100% rename from Spring/Package.swift rename to Package.swift diff --git a/Spring/Sources/Spring/Spring.swift b/Sources/Spring/Spring.swift similarity index 100% rename from Spring/Sources/Spring/Spring.swift rename to Sources/Spring/Spring.swift diff --git a/Spring/.gitignore b/Spring/.gitignore deleted file mode 100644 index 3b29812..0000000 --- a/Spring/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -.DS_Store -/.build -/Packages -/*.xcodeproj -xcuserdata/ -DerivedData/ -.swiftpm/config/registries.json -.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata -.netrc diff --git a/Spring/Tests/SpringTests/SpringTests.swift b/Tests/SpringTests/SpringTests.swift similarity index 100% rename from Spring/Tests/SpringTests/SpringTests.swift rename to Tests/SpringTests/SpringTests.swift From e52dff83a6878086b3f87ea188247fa5d47250a0 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 12 Apr 2022 15:06:18 +0300 Subject: [PATCH 17/21] Add sources files --- .../contents.xcworkspacedata | 7 + Sources/Spring/AsyncButton.swift | 51 ++ Sources/Spring/AsyncImageView.swift | 51 ++ Sources/Spring/AutoTextView.swift | 27 + Sources/Spring/BlurView.swift | 33 + Sources/Spring/DesignableButton.swift | 69 ++ Sources/Spring/DesignableImageView.swift | 45 ++ Sources/Spring/DesignableLabel.swift | 43 ++ .../Spring/DesignableTabBarController.swift | 123 ++++ Sources/Spring/DesignableTextField.swift | 100 +++ Sources/Spring/DesignableTextView.swift | 61 ++ Sources/Spring/DesignableView.swift | 68 ++ Sources/Spring/ImageLoader.swift | 86 +++ Sources/Spring/Info.plist | 26 + Sources/Spring/KeyboardLayoutConstraint.swift | 112 +++ Sources/Spring/LoadingView.swift | 86 +++ Sources/Spring/LoadingView.xib | 50 ++ Sources/Spring/Misc.swift | 263 +++++++ Sources/Spring/SoundPlayer.swift | 60 ++ Sources/Spring/Spring.h | 19 + Sources/Spring/Spring.swift | 643 +++++++++++++++++- Sources/Spring/SpringAnimation.swift | 112 +++ Sources/Spring/SpringButton.swift | 71 ++ Sources/Spring/SpringImageView.swift | 72 ++ Sources/Spring/SpringLabel.swift | 72 ++ Sources/Spring/SpringTextField.swift | 71 ++ Sources/Spring/SpringTextView.swift | 72 ++ Sources/Spring/SpringView.swift | 71 ++ Sources/Spring/TransitionManager.swift | 86 +++ Sources/Spring/TransitionZoom.swift | 79 +++ Sources/Spring/UnwindSegue.swift | 27 + Spring.podspec | 2 +- 32 files changed, 2754 insertions(+), 4 deletions(-) create mode 100644 .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata create mode 100644 Sources/Spring/AsyncButton.swift create mode 100644 Sources/Spring/AsyncImageView.swift create mode 100644 Sources/Spring/AutoTextView.swift create mode 100644 Sources/Spring/BlurView.swift create mode 100644 Sources/Spring/DesignableButton.swift create mode 100644 Sources/Spring/DesignableImageView.swift create mode 100644 Sources/Spring/DesignableLabel.swift create mode 100644 Sources/Spring/DesignableTabBarController.swift create mode 100644 Sources/Spring/DesignableTextField.swift create mode 100644 Sources/Spring/DesignableTextView.swift create mode 100644 Sources/Spring/DesignableView.swift create mode 100755 Sources/Spring/ImageLoader.swift create mode 100644 Sources/Spring/Info.plist create mode 100644 Sources/Spring/KeyboardLayoutConstraint.swift create mode 100644 Sources/Spring/LoadingView.swift create mode 100644 Sources/Spring/LoadingView.xib create mode 100644 Sources/Spring/Misc.swift create mode 100644 Sources/Spring/SoundPlayer.swift create mode 100644 Sources/Spring/Spring.h create mode 100644 Sources/Spring/SpringAnimation.swift create mode 100644 Sources/Spring/SpringButton.swift create mode 100644 Sources/Spring/SpringImageView.swift create mode 100644 Sources/Spring/SpringLabel.swift create mode 100644 Sources/Spring/SpringTextField.swift create mode 100644 Sources/Spring/SpringTextView.swift create mode 100644 Sources/Spring/SpringView.swift create mode 100644 Sources/Spring/TransitionManager.swift create mode 100644 Sources/Spring/TransitionZoom.swift create mode 100644 Sources/Spring/UnwindSegue.swift diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Sources/Spring/AsyncButton.swift b/Sources/Spring/AsyncButton.swift new file mode 100644 index 0000000..6e03ac9 --- /dev/null +++ b/Sources/Spring/AsyncButton.swift @@ -0,0 +1,51 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 James Tang (j@jamztang.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +public class AsyncButton: UIButton { + + private var imageURL = [UInt:NSURL]() + private var placeholderImage = [UInt:UIImage]() + + + public func setImageURL(url: NSURL?, placeholderImage placeholder:UIImage?, forState state:UIControl.State) { + + imageURL[state.rawValue] = url + placeholderImage[state.rawValue] = placeholder + + if let urlString = url?.absoluteString { + ImageLoader.sharedLoader.imageForUrl(urlString: urlString) { [weak self] image, url in + + if let strongSelf = self { + + DispatchQueue.main.async(execute: { () -> Void in + if strongSelf.imageURL[state.rawValue]?.absoluteString == url { + strongSelf.setImage(image, for: state) + } + }) + } + } + } + } + +} diff --git a/Sources/Spring/AsyncImageView.swift b/Sources/Spring/AsyncImageView.swift new file mode 100644 index 0000000..aa2f7e8 --- /dev/null +++ b/Sources/Spring/AsyncImageView.swift @@ -0,0 +1,51 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 James Tang (j@jamztang.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +public class AsyncImageView: UIImageView { + + public var placeholderImage : UIImage? + + public var url : NSURL? { + didSet { + self.image = placeholderImage + if let urlString = url?.absoluteString { + ImageLoader.sharedLoader.imageForUrl(urlString: urlString) { [weak self] image, url in + if let strongSelf = self { + DispatchQueue.main.async(execute: { () -> Void in + if strongSelf.url?.absoluteString == url { + strongSelf.image = image ?? strongSelf.placeholderImage + } + }) + } + } + } + } + } + + public func setURL(url: NSURL?, placeholderImage: UIImage?) { + self.placeholderImage = placeholderImage + self.url = url + } + +} diff --git a/Sources/Spring/AutoTextView.swift b/Sources/Spring/AutoTextView.swift new file mode 100644 index 0000000..1d0c7e6 --- /dev/null +++ b/Sources/Spring/AutoTextView.swift @@ -0,0 +1,27 @@ +// +// AutoTextView.swift +// SpringApp +// +// Created by Meng To on 2015-03-27. +// Copyright (c) 2015 Meng To. All rights reserved. +// + +import UIKit + +public class AutoTextView: UITextView { + + public override var intrinsicContentSize: CGSize { + get { + var size = self.sizeThatFits(CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude)) + size.width = self.frame.size.width + if text.length == 0 { + size.height = 0 + } + + contentInset = UIEdgeInsets(top: -4, left: -4, bottom: -4, right: -4) + layoutIfNeeded() + + return size + } + } +} diff --git a/Sources/Spring/BlurView.swift b/Sources/Spring/BlurView.swift new file mode 100644 index 0000000..8de1611 --- /dev/null +++ b/Sources/Spring/BlurView.swift @@ -0,0 +1,33 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +public func insertBlurView (view: UIView, style: UIBlurEffect.Style) -> UIVisualEffectView { + view.backgroundColor = UIColor.clear + + let blurEffect = UIBlurEffect(style: style) + let blurEffectView = UIVisualEffectView(effect: blurEffect) + blurEffectView.frame = view.bounds + view.insertSubview(blurEffectView, at: 0) + return blurEffectView +} diff --git a/Sources/Spring/DesignableButton.swift b/Sources/Spring/DesignableButton.swift new file mode 100644 index 0000000..0612083 --- /dev/null +++ b/Sources/Spring/DesignableButton.swift @@ -0,0 +1,69 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +@IBDesignable public class DesignableButton: SpringButton { + + @IBInspectable public var borderColor: UIColor = UIColor.clear { + didSet { + layer.borderColor = borderColor.cgColor + } + } + + @IBInspectable public var borderWidth: CGFloat = 0 { + didSet { + layer.borderWidth = borderWidth + } + } + + @IBInspectable public var cornerRadius: CGFloat = 0 { + didSet { + layer.cornerRadius = cornerRadius + } + } + + @IBInspectable public var shadowColor: UIColor = UIColor.clear { + didSet { + layer.shadowColor = shadowColor.cgColor + } + } + + @IBInspectable public var shadowRadius: CGFloat = 0 { + didSet { + layer.shadowRadius = shadowRadius + } + } + + @IBInspectable public var shadowOpacity: CGFloat = 0 { + didSet { + layer.shadowOpacity = Float(shadowOpacity) + } + } + + @IBInspectable public var shadowOffsetY: CGFloat = 0 { + didSet { + layer.shadowOffset.height = shadowOffsetY + } + } + +} diff --git a/Sources/Spring/DesignableImageView.swift b/Sources/Spring/DesignableImageView.swift new file mode 100644 index 0000000..32a90a2 --- /dev/null +++ b/Sources/Spring/DesignableImageView.swift @@ -0,0 +1,45 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +@IBDesignable public class DesignableImageView: SpringImageView { + + @IBInspectable public var borderColor: UIColor = UIColor.clear { + didSet { + layer.borderColor = borderColor.cgColor + } + } + + @IBInspectable public var borderWidth: CGFloat = 0 { + didSet { + layer.borderWidth = borderWidth + } + } + + @IBInspectable public var cornerRadius: CGFloat = 0 { + didSet { + layer.cornerRadius = cornerRadius + } + } + +} diff --git a/Sources/Spring/DesignableLabel.swift b/Sources/Spring/DesignableLabel.swift new file mode 100644 index 0000000..8d6994b --- /dev/null +++ b/Sources/Spring/DesignableLabel.swift @@ -0,0 +1,43 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +@IBDesignable public class DesignableLabel: SpringLabel { + + @IBInspectable public var lineHeight: CGFloat = 1.5 { + didSet { + let font = UIFont(name: self.font.fontName, size: self.font.pointSize) + guard let text = self.text else { return } + + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.lineSpacing = lineHeight + + let attributedString = NSMutableAttributedString(string: text) + attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, attributedString.length)) + attributedString.addAttribute(NSAttributedString.Key.font, value: font!, range: NSMakeRange(0, attributedString.length)) + + self.attributedText = attributedString + } + } + +} diff --git a/Sources/Spring/DesignableTabBarController.swift b/Sources/Spring/DesignableTabBarController.swift new file mode 100644 index 0000000..c3ab5f3 --- /dev/null +++ b/Sources/Spring/DesignableTabBarController.swift @@ -0,0 +1,123 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +@IBDesignable class DesignableTabBarController: UITabBarController { + + @IBInspectable var normalTint: UIColor = UIColor.clear { + didSet { + UITabBar.appearance().tintColor = normalTint + UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: normalTint], for: UIControl.State()) + } + } + + @IBInspectable var selectedTint: UIColor = UIColor.clear { + didSet { + UITabBar.appearance().tintColor = selectedTint + UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: selectedTint], for:UIControl.State.selected) + } + } + + @IBInspectable var fontName: String = "" { + didSet { + UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: normalTint, NSAttributedString.Key.font: UIFont(name: fontName, size: 11)!], for: UIControl.State()) + } + } + + @IBInspectable var firstSelectedImage: UIImage? { + didSet { + if let image = firstSelectedImage { + let tabBarItems = self.tabBar.items as [UITabBarItem]? + tabBarItems?[0].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) + } + } + } + + @IBInspectable var secondSelectedImage: UIImage? { + didSet { + if let image = secondSelectedImage { + let tabBarItems = self.tabBar.items as [UITabBarItem]? + tabBarItems?[1].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) + } + } + } + + @IBInspectable var thirdSelectedImage: UIImage? { + didSet { + if let image = thirdSelectedImage { + let tabBarItems = self.tabBar.items as [UITabBarItem]? + tabBarItems?[2].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) + } + } + } + + @IBInspectable var fourthSelectedImage: UIImage? { + didSet { + if let image = fourthSelectedImage { + let tabBarItems = self.tabBar.items as [UITabBarItem]? + tabBarItems?[3].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) + } + } + } + + @IBInspectable var fifthSelectedImage: UIImage? { + didSet { + if let image = fifthSelectedImage { + let tabBarItems = self.tabBar.items as [UITabBarItem]? + tabBarItems?[4].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) + } + } + } + + override func viewDidLoad() { + super.viewDidLoad() + if let items = self.tabBar.items { + for item in items { + if let image = item.image { + item.image = image.imageWithColor(tintColor: self.normalTint).withRenderingMode(UIImage.RenderingMode.alwaysOriginal) + } + } + } + } +} + +extension UIImage { + func imageWithColor(tintColor: UIColor) -> UIImage { + UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale) + + let context = UIGraphicsGetCurrentContext() + context!.translateBy(x: 0, y: self.size.height) + context!.scaleBy(x: 1.0, y: -1.0); + context!.setBlendMode(CGBlendMode.normal) + + let rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height) + context?.clip(to: rect, mask: self.cgImage!) + tintColor.setFill() + context!.fill(rect) + + let newImage = UIGraphicsGetImageFromCurrentImageContext()! as UIImage + UIGraphicsEndImageContext() + + return newImage + } +} diff --git a/Sources/Spring/DesignableTextField.swift b/Sources/Spring/DesignableTextField.swift new file mode 100644 index 0000000..e334a8e --- /dev/null +++ b/Sources/Spring/DesignableTextField.swift @@ -0,0 +1,100 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +@IBDesignable public class DesignableTextField: SpringTextField { + + @IBInspectable public var placeholderColor: UIColor = UIColor.clear { + didSet { + guard let placeholder = placeholder else { return } + attributedPlaceholder = NSAttributedString(string: placeholder, attributes: [NSAttributedString.Key.foregroundColor: placeholderColor]) + layoutSubviews() + + } + } + + @IBInspectable public var sidePadding: CGFloat = 0 { + didSet { + let padding = UIView(frame: CGRect(x: 0, y: 0, width: sidePadding, height: sidePadding)) + + leftViewMode = UITextField.ViewMode.always + leftView = padding + + rightViewMode = UITextField.ViewMode.always + rightView = padding + } + } + + @IBInspectable public var leftPadding: CGFloat = 0 { + didSet { + let padding = UIView(frame: CGRect(x: 0, y: 0, width: leftPadding, height: 0)) + + leftViewMode = UITextField.ViewMode.always + leftView = padding + } + } + + @IBInspectable public var rightPadding: CGFloat = 0 { + didSet { + let padding = UIView(frame: CGRect(x: 0, y: 0, width: rightPadding, height: 0)) + + rightViewMode = UITextField.ViewMode.always + rightView = padding + } + } + + @IBInspectable public var borderColor: UIColor = UIColor.clear { + didSet { + layer.borderColor = borderColor.cgColor + } + } + + @IBInspectable public var borderWidth: CGFloat = 0 { + didSet { + layer.borderWidth = borderWidth + } + } + + @IBInspectable public var cornerRadius: CGFloat = 0 { + didSet { + layer.cornerRadius = cornerRadius + } + } + + @IBInspectable public var lineHeight: CGFloat = 1.5 { + didSet { + let font = UIFont(name: self.font!.fontName, size: self.font!.pointSize) + guard let text = self.text else { return } + + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.lineSpacing = lineHeight + + let attributedString = NSMutableAttributedString(string: text) + attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedString.length)) + attributedString.addAttribute(NSAttributedString.Key.font, value: font!, range: NSRange(location: 0, length: attributedString.length)) + + self.attributedText = attributedString + } + } + +} diff --git a/Sources/Spring/DesignableTextView.swift b/Sources/Spring/DesignableTextView.swift new file mode 100644 index 0000000..779298a --- /dev/null +++ b/Sources/Spring/DesignableTextView.swift @@ -0,0 +1,61 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +@IBDesignable public class DesignableTextView: SpringTextView { + + @IBInspectable public var borderColor: UIColor = UIColor.clear { + didSet { + layer.borderColor = borderColor.cgColor + } + } + + @IBInspectable public var borderWidth: CGFloat = 0 { + didSet { + layer.borderWidth = borderWidth + } + } + + @IBInspectable public var cornerRadius: CGFloat = 0 { + didSet { + layer.cornerRadius = cornerRadius + } + } + + @IBInspectable public var lineHeight: CGFloat = 1.5 { + didSet { + let font = UIFont(name: self.font!.fontName, size: self.font!.pointSize) + guard let text = self.text else { return } + + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.lineSpacing = lineHeight + + let attributedString = NSMutableAttributedString(string: text) + attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedString.length)) + attributedString.addAttribute(NSAttributedString.Key.font, value: font!, range: NSRange(location: 0, length: attributedString.length)) + + self.attributedText = attributedString + } + } + +} diff --git a/Sources/Spring/DesignableView.swift b/Sources/Spring/DesignableView.swift new file mode 100644 index 0000000..a82d23f --- /dev/null +++ b/Sources/Spring/DesignableView.swift @@ -0,0 +1,68 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +@IBDesignable public class DesignableView: SpringView { + + @IBInspectable public var borderColor: UIColor = UIColor.clear { + didSet { + layer.borderColor = borderColor.cgColor + } + } + + @IBInspectable public var borderWidth: CGFloat = 0 { + didSet { + layer.borderWidth = borderWidth + } + } + + @IBInspectable public var cornerRadius: CGFloat = 0 { + didSet { + layer.cornerRadius = cornerRadius + } + } + + @IBInspectable public var shadowColor: UIColor = UIColor.clear { + didSet { + layer.shadowColor = shadowColor.cgColor + } + } + + @IBInspectable public var shadowRadius: CGFloat = 0 { + didSet { + layer.shadowRadius = shadowRadius + } + } + + @IBInspectable public var shadowOpacity: CGFloat = 0 { + didSet { + layer.shadowOpacity = Float(shadowOpacity) + } + } + + @IBInspectable public var shadowOffsetY: CGFloat = 0 { + didSet { + layer.shadowOffset.height = shadowOffsetY + } + } +} diff --git a/Sources/Spring/ImageLoader.swift b/Sources/Spring/ImageLoader.swift new file mode 100755 index 0000000..bcb626d --- /dev/null +++ b/Sources/Spring/ImageLoader.swift @@ -0,0 +1,86 @@ +// The MIT License (MIT) +// +// Copyright (c) 2014 Nate Lyman (https://github.com/natelyman/SwiftImageLoader) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit +import Foundation + + +public class ImageLoader { + + var cache = NSCache() + + public class var sharedLoader : ImageLoader { + struct Static { + static let instance : ImageLoader = ImageLoader() + } + return Static.instance + } + + public func imageForUrl(urlString: String, completionHandler: @escaping(_ image: UIImage?, _ url: String) -> ()) { + DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async { + var data: NSData? + + if let dataCache = self.cache.object(forKey: urlString as NSString){ + data = (dataCache) as NSData + + }else{ + if (URL(string: urlString) != nil) + { + data = NSData(contentsOf: URL(string: urlString)!) + if data != nil { + self.cache.setObject(data!, forKey: urlString as NSString) + } + }else{ + return + } + } + + if let goodData = data { + let image = UIImage(data: goodData as Data) + DispatchQueue.main.async(execute: {() in + completionHandler(image, urlString) + }) + return + } + + let downloadTask: URLSessionDataTask = URLSession.shared.dataTask(with: URL(string: urlString)!, completionHandler: { (data, response, error) -> Void in + + if (error != nil) { + completionHandler(nil, urlString) + return + } + + if data != nil { + let image = UIImage(data: data!) + self.cache.setObject(data! as NSData, forKey: urlString as NSString) + DispatchQueue.main.async(execute: {() in + completionHandler(image, urlString) + }) + return + } + }) + downloadTask.resume() + + } + + } +} diff --git a/Sources/Spring/Info.plist b/Sources/Spring/Info.plist new file mode 100644 index 0000000..d3de8ee --- /dev/null +++ b/Sources/Spring/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/Sources/Spring/KeyboardLayoutConstraint.swift b/Sources/Spring/KeyboardLayoutConstraint.swift new file mode 100644 index 0000000..f918a13 --- /dev/null +++ b/Sources/Spring/KeyboardLayoutConstraint.swift @@ -0,0 +1,112 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 James Tang (j@jamztang.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +#if !os(tvOS) +@available(tvOS, unavailable) +public class KeyboardLayoutConstraint: NSLayoutConstraint { + + private var offset: CGFloat = 0 + private var keyboardVisibleHeight: CGFloat = 0 + + @available(tvOS, unavailable) + override public func awakeFromNib() { + super.awakeFromNib() + + offset = constant + + NotificationCenter.default.addObserver( + self, + selector: #selector(KeyboardLayoutConstraint.keyboardWillShowNotification), + name: UIWindow.keyboardWillShowNotification, + object: nil + ) + NotificationCenter.default.addObserver( + self, + selector: #selector(KeyboardLayoutConstraint.keyboardWillHideNotification), + name: UIWindow.keyboardWillHideNotification, + object: nil + ) + } + + deinit { + NotificationCenter.default.removeObserver(self) + } + + // MARK: Notification + @objc func keyboardWillShowNotification(_ notification: Notification) { + if let userInfo = notification.userInfo { + if let frameValue = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue { + let frame = frameValue.cgRectValue + keyboardVisibleHeight = frame.size.height + } + + self.updateConstant() + switch (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber) { + case let (.some(duration), .some(curve)): + + let options = UIView.AnimationOptions(rawValue: curve.uintValue) + + UIView.animate( + withDuration: TimeInterval(duration.doubleValue), + delay: 0, + options: options) { + UIApplication.shared.windows.first?.layoutIfNeeded() + return + } + default: + break + } + } + } + + @objc func keyboardWillHideNotification(_ notification: NSNotification) { + keyboardVisibleHeight = 0 + updateConstant() + + if let userInfo = notification.userInfo { + + switch (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber) { + case let (.some(duration), .some(curve)): + + let options = UIView.AnimationOptions(rawValue: curve.uintValue) + + UIView.animate( + withDuration: TimeInterval(duration.doubleValue), + delay: 0, + options: options) { + UIApplication.shared.windows.first?.layoutIfNeeded() + return + } + default: + break + } + } + } + + func updateConstant() { + constant = offset + keyboardVisibleHeight + } + +} +#endif diff --git a/Sources/Spring/LoadingView.swift b/Sources/Spring/LoadingView.swift new file mode 100644 index 0000000..55e5e2c --- /dev/null +++ b/Sources/Spring/LoadingView.swift @@ -0,0 +1,86 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +#if !os(tvOS) +@available(tvOS, unavailable) +public class LoadingView: UIView { + + @IBOutlet public weak var indicatorView: SpringView! + + override public func awakeFromNib() { + let animation = CABasicAnimation() + animation.keyPath = "transform.rotation.z" + animation.fromValue = degreesToRadians(degrees: 0) + animation.toValue = degreesToRadians(degrees: 360) + animation.duration = 0.9 + animation.repeatCount = HUGE + indicatorView.layer.add(animation, forKey: "") + } + + class func designCodeLoadingView() -> UIView { + + return Bundle(for: self).loadNibNamed("LoadingView", owner: self, options: nil)![0] as! UIView + } +} + +public extension UIView { + + struct LoadingViewConstants { + static let Tag = 1000 + } + + func showLoading() { + + if self.viewWithTag(LoadingViewConstants.Tag) != nil { + // If loading view is already found in current view hierachy, do nothing + return + } + + let loadingXibView = LoadingView.designCodeLoadingView() + loadingXibView.frame = self.bounds + loadingXibView.tag = LoadingViewConstants.Tag + self.addSubview(loadingXibView) + + loadingXibView.alpha = 0 + SpringAnimation.spring(duration: 0.7, animations: { + loadingXibView.alpha = 1 + }) + } + + func hideLoading() { + + if let loadingXibView = self.viewWithTag(LoadingViewConstants.Tag) { + loadingXibView.alpha = 1 + + SpringAnimation.springWithCompletion(duration: 0.7, animations: { + loadingXibView.alpha = 0 + loadingXibView.transform = CGAffineTransform(scaleX: 3, y: 3) + }, completion: { (completed) -> Void in + loadingXibView.removeFromSuperview() + }) + } + } + +} +#endif diff --git a/Sources/Spring/LoadingView.xib b/Sources/Spring/LoadingView.xib new file mode 100644 index 0000000..48a0901 --- /dev/null +++ b/Sources/Spring/LoadingView.xib @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Sources/Spring/Misc.swift b/Sources/Spring/Misc.swift new file mode 100644 index 0000000..96024b8 --- /dev/null +++ b/Sources/Spring/Misc.swift @@ -0,0 +1,263 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +public extension String { + var length: Int { return self.count } + + func toURL() -> NSURL? { + return NSURL(string: self) + } +} + +public func htmlToAttributedString(text: String) -> NSAttributedString! { + guard let htmlData = text.data(using: String.Encoding.utf8, allowLossyConversion: false) else { + return NSAttributedString() } + let htmlString: NSAttributedString? + do { + htmlString = try NSAttributedString(data: htmlData, options: [NSAttributedString.DocumentReadingOptionKey.documentType:NSAttributedString.DocumentType.html], documentAttributes: nil) + } catch _ { + htmlString = nil + } + + return htmlString +} + +public func degreesToRadians(degrees: CGFloat) -> CGFloat { + return degrees * CGFloat(CGFloat.pi / 180) +} + +public func delay(delay:Double, closure: @escaping ()->()) { + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure) +} + +public func imageFromURL(_ Url: String) -> UIImage { + let url = Foundation.URL(string: Url) + let data = try? Data(contentsOf: url!) + return UIImage(data: data!)! +} + +public extension UIColor { + convenience init(hex: String) { + var red: CGFloat = 0.0 + var green: CGFloat = 0.0 + var blue: CGFloat = 0.0 + var alpha: CGFloat = 1.0 + var hex: String = hex + + if hex.hasPrefix("#") { + let index = hex.index(hex.startIndex, offsetBy: 1) + hex = String(hex[index...]) + } + + let scanner = Scanner(string: hex) + var hexValue: CUnsignedLongLong = 0 + if scanner.scanHexInt64(&hexValue) { + switch (hex.count) { + case 3: + red = CGFloat((hexValue & 0xF00) >> 8) / 15.0 + green = CGFloat((hexValue & 0x0F0) >> 4) / 15.0 + blue = CGFloat(hexValue & 0x00F) / 15.0 + case 4: + red = CGFloat((hexValue & 0xF000) >> 12) / 15.0 + green = CGFloat((hexValue & 0x0F00) >> 8) / 15.0 + blue = CGFloat((hexValue & 0x00F0) >> 4) / 15.0 + alpha = CGFloat(hexValue & 0x000F) / 15.0 + case 6: + red = CGFloat((hexValue & 0xFF0000) >> 16) / 255.0 + green = CGFloat((hexValue & 0x00FF00) >> 8) / 255.0 + blue = CGFloat(hexValue & 0x0000FF) / 255.0 + case 8: + red = CGFloat((hexValue & 0xFF000000) >> 24) / 255.0 + green = CGFloat((hexValue & 0x00FF0000) >> 16) / 255.0 + blue = CGFloat((hexValue & 0x0000FF00) >> 8) / 255.0 + alpha = CGFloat(hexValue & 0x000000FF) / 255.0 + default: + print("Invalid RGB string, number of characters after '#' should be either 3, 4, 6 or 8", terminator: "") + } + } else { + print("Scan hex error") + } + self.init(red:red, green:green, blue:blue, alpha:alpha) + } +} + +public func rgbaToUIColor(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) -> UIColor { + + return UIColor(red: red, green: green, blue: blue, alpha: alpha) +} + +public func UIColorFromRGB(rgbValue: UInt) -> UIColor { + return UIColor( + red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, + green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0, + blue: CGFloat(rgbValue & 0x0000FF) / 255.0, + alpha: CGFloat(1.0) + ) +} + +public func stringFromDate(date: NSDate, format: String) -> String { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = format + return dateFormatter.string(from: date as Date) +} + +public func dateFromString(date: String, format: String) -> Date { + let dateFormatter = DateFormatter() + dateFormatter.dateFormat = format + if let date = dateFormatter.date(from: date) { + return date + } else { + return Date(timeIntervalSince1970: 0) + } +} + +public func randomStringWithLength (len : Int) -> NSString { + + let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + + let randomString : NSMutableString = NSMutableString(capacity: len) + + for _ in 0 ..< len { + let length = UInt32 (letters.length) + let rand = arc4random_uniform(length) + randomString.appendFormat("%C", letters.character(at: Int(rand))) + } + + return randomString +} + +public func timeAgoSinceDate(date: Date, numericDates: Bool) -> String { + let calendar = Calendar.current + let unitFlags = Set(arrayLiteral: Calendar.Component.minute, Calendar.Component.hour, Calendar.Component.day, Calendar.Component.weekOfYear, Calendar.Component.month, Calendar.Component.year, Calendar.Component.second) + let now = Date() + let dateComparison = now.compare(date) + var earliest: Date + var latest: Date + + switch dateComparison { + case .orderedAscending: + earliest = now + latest = date + default: + earliest = date + latest = now + } + + let components: DateComponents = calendar.dateComponents(unitFlags, from: earliest, to: latest) + + guard + let year = components.year, + let month = components.month, + let weekOfYear = components.weekOfYear, + let day = components.day, + let hour = components.hour, + let minute = components.minute, + let second = components.second + else { + fatalError() + } + + if (year >= 2) { + return "\(year)y" + } else if (year >= 1) { + if (numericDates){ + return "1y" + } else { + return "1y" + } + } else if (month >= 2) { + return "\(month * 4)w" + } else if (month >= 1) { + if (numericDates){ + return "4w" + } else { + return "4w" + } + } else if (weekOfYear >= 2) { + return "\(weekOfYear)w" + } else if (weekOfYear >= 1){ + if (numericDates){ + return "1w" + } else { + return "1w" + } + } else if (day >= 2) { + return "\(components.day ?? 2)d" + } else if (day >= 1){ + if (numericDates){ + return "1d" + } else { + return "1d" + } + } else if (hour >= 2) { + return "\(hour)h" + } else if (hour >= 1){ + if (numericDates){ + return "1h" + } else { + return "1h" + } + } else if (minute >= 2) { + return "\(minute)m" + } else if (minute >= 1){ + if (numericDates){ + return "1m" + } else { + return "1m" + } + } else if (second >= 3) { + return "\(second)s" + } else { + return "now" + } + +} + +extension UIImageView { + func setImage(url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit, placeholderImage: UIImage?) { + contentMode = mode + URLSession.shared.dataTask(with: url) { (data, response, error) in + guard + let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200, + let mimeType = response?.mimeType, mimeType.hasPrefix("image"), + let data = data, error == nil, + let image = UIImage(data: data) + else { + self.image = placeholderImage + return + } + DispatchQueue.main.async() { () -> Void in + self.image = image + + } + }.resume() + } + func setImage(urlString: String, contentMode mode: UIView.ContentMode = .scaleAspectFit, placeholderImage: UIImage?) { + guard let url = URL(string: urlString) else { + image = placeholderImage + return + } + setImage(url: url, contentMode: mode, placeholderImage: placeholderImage) + } +} diff --git a/Sources/Spring/SoundPlayer.swift b/Sources/Spring/SoundPlayer.swift new file mode 100644 index 0000000..d2451d9 --- /dev/null +++ b/Sources/Spring/SoundPlayer.swift @@ -0,0 +1,60 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 James Tang (j@jamztang.com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit +import AudioToolbox + +public struct SoundPlayer { + + static var filename : String? + static var enabled : Bool = true + + private struct Internal { + static var cache = [URL:SystemSoundID]() + } + + public static func playSound(soundFile: String) { + + if !enabled { + return + } + + if let url = Bundle.main.url(forResource: soundFile, withExtension: nil) { + + var soundID : SystemSoundID = Internal.cache[url] ?? 0 + + if soundID == 0 { + AudioServicesCreateSystemSoundID(url as CFURL, &soundID) + Internal.cache[url] = soundID + } + + AudioServicesPlaySystemSound(soundID) + + } else { + print("Could not find sound file name `\(soundFile)`") + } + } + + static func play(file: String) { + self.playSound(soundFile: file) + } +} diff --git a/Sources/Spring/Spring.h b/Sources/Spring/Spring.h new file mode 100644 index 0000000..1a11dfe --- /dev/null +++ b/Sources/Spring/Spring.h @@ -0,0 +1,19 @@ +// +// Spring.h +// Spring +// +// Created by James Tang on 20/1/15. +// Copyright (c) 2015 Meng To. All rights reserved. +// + +#import + +//! Project version number for Spring. +FOUNDATION_EXPORT double SpringVersionNumber; + +//! Project version string for Spring. +FOUNDATION_EXPORT const unsigned char SpringVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/Sources/Spring/Spring.swift b/Sources/Spring/Spring.swift index 2129481..c74c0af 100644 --- a/Sources/Spring/Spring.swift +++ b/Sources/Spring/Spring.swift @@ -1,6 +1,643 @@ -public struct Spring { - public private(set) var text = "Hello, World!" +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. - public init() { +import UIKit + +public protocol Springable: AnyObject { + var autostart: Bool { get set } + var autohide: Bool { get set } + var animation: String { get set } + var force: CGFloat { get set } + var delay: CGFloat { get set } + var duration: CGFloat { get set } + var damping: CGFloat { get set } + var velocity: CGFloat { get set } + var repeatCount: Float { get set } + var x: CGFloat { get set } + var y: CGFloat { get set } + var scaleX: CGFloat { get set } + var scaleY: CGFloat { get set } + var rotate: CGFloat { get set } + var opacity: CGFloat { get set } + var animateFrom: Bool { get set } + var curve: String { get set } + + // UIView + var layer : CALayer { get } + var transform : CGAffineTransform { get set } + var alpha : CGFloat { get set } + + func animate() + func animateNext(completion: @escaping () -> ()) + func animateTo() + func animateToNext(completion: @escaping () -> ()) +} + +public class Spring : NSObject { + + private unowned var view: Springable + private var shouldAnimateAfterActive = false + private var shouldAnimateInLayoutSubviews = true + + private var autostart: Bool { + set { + view.autostart = newValue + } get { + view.autostart + } + } + private var autohide: Bool { + set { + view.autohide = newValue + } get { + view.autohide + } + } + private var animation: String { + set { + view.animation = newValue + } get { + view.animation + } + } + private var force: CGFloat { + set { + view.force = newValue + } get { + view.force + } + } + private var delay: CGFloat { + set { + view.delay = newValue + } get { + view.delay + + } + } + private var duration: CGFloat { + set { + view.duration = newValue + } get { + view.duration + } + } + private var damping: CGFloat { + set { + view.damping = newValue + } get { + view.damping + } + } + private var velocity: CGFloat { + set { + view.velocity = newValue + } get { + view.velocity + } + } + private var repeatCount: Float { + set { + view.repeatCount = newValue + } get { + view.repeatCount + } + } + private var x: CGFloat { + set { + view.x = newValue + } get { + view.x + } + } + private var y: CGFloat { + set { + view.y = newValue + } get { + view.y + } + } + private var scaleX: CGFloat { + set { + view.scaleX = newValue + } get { + view.scaleX + } + } + private var scaleY: CGFloat { + set { + view.scaleY = newValue + } get { + view.scaleY + } + } + + private var rotate: CGFloat { + set { + view.rotate = newValue + } get { + view.rotate + } + } + private var opacity: CGFloat { + set { + view.opacity = newValue + } get { + view.opacity + } + } + private var animateFrom: Bool { + set { + view.animateFrom = newValue + } get { + view.animateFrom + } + } + private var curve: String { + set { + view.curve = newValue + } get { + view.curve + } + } + + // UIView + private var layer : CALayer { return view.layer } + private var transform : CGAffineTransform { get { return view.transform } set { view.transform = newValue }} + private var alpha: CGFloat { get { return view.alpha } set { view.alpha = newValue } } + + init(_ view: Springable) { + self.view = view + super.init() + commonInit() + } + + private func commonInit() { + NotificationCenter.default.addObserver( + self, + selector: #selector(didBecomeActiveNotification), + name: UIApplication.didBecomeActiveNotification, + object: nil + ) + } + + @objc private func didBecomeActiveNotification(_ notification: NSNotification) { + if shouldAnimateAfterActive { + alpha = 0 + animate() + shouldAnimateAfterActive = false + } + } + + deinit { + NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil) + } + + func animatePreset() { + alpha = 0.99 + if let animation = AnimationPreset(rawValue: animation) { + switch animation { + case .slideLeft: + x = 300*force + case .slideRight: + x = -300*force + case .slideDown: + y = -300*force + case .slideUp: + y = 300*force + case .squeezeLeft: + x = 300 + scaleX = 3*force + case .squeezeRight: + x = -300 + scaleX = 3*force + case .squeezeDown: + y = -300 + scaleY = 3*force + case .squeezeUp: + y = 300 + scaleY = 3*force + case .fadeIn: + opacity = 0 + case .fadeOut: + animateFrom = false + opacity = 0 + case .fadeOutIn: + let animation = CABasicAnimation() + animation.keyPath = "opacity" + animation.fromValue = 1 + animation.toValue = 0 + animation.timingFunction = getTimingFunction(curve: curve) + animation.duration = CFTimeInterval(duration) + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + animation.autoreverses = true + layer.add(animation, forKey: "fade") + case .fadeInLeft: + opacity = 0 + x = 300*force + case .fadeInRight: + x = -300*force + opacity = 0 + case .fadeInDown: + y = -300*force + opacity = 0 + case .fadeInUp: + y = 300*force + opacity = 0 + case .zoomIn: + opacity = 0 + scaleX = 2*force + scaleY = 2*force + case .zoomOut: + animateFrom = false + opacity = 0 + scaleX = 2*force + scaleY = 2*force + case .fall: + animateFrom = false + rotate = 15 * CGFloat(CGFloat.pi/180) + y = 600*force + case .shake: + let animation = CAKeyframeAnimation() + animation.keyPath = "position.x" + animation.values = [0, 30*force, -30*force, 30*force, 0] + animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + animation.timingFunction = getTimingFunction(curve: curve) + animation.duration = CFTimeInterval(duration) + animation.isAdditive = true + animation.repeatCount = repeatCount + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(animation, forKey: "shake") + case .pop: + let animation = CAKeyframeAnimation() + animation.keyPath = "transform.scale" + animation.values = [0, 0.2*force, -0.2*force, 0.2*force, 0] + animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + animation.timingFunction = getTimingFunction(curve: curve) + animation.duration = CFTimeInterval(duration) + animation.isAdditive = true + animation.repeatCount = repeatCount + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(animation, forKey: "pop") + case .flipX: + rotate = 0 + scaleX = 1 + scaleY = 1 + var perspective = CATransform3DIdentity + perspective.m34 = -1.0 / layer.frame.size.width/2 + + let animation = CABasicAnimation() + animation.keyPath = "transform" + animation.fromValue = NSValue(caTransform3D: CATransform3DMakeRotation(0, 0, 0, 0)) + animation.toValue = NSValue(caTransform3D: + CATransform3DConcat(perspective, CATransform3DMakeRotation(CGFloat(CGFloat.pi), 0, 1, 0))) + animation.duration = CFTimeInterval(duration) + animation.repeatCount = repeatCount + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + animation.timingFunction = getTimingFunction(curve: curve) + layer.add(animation, forKey: "3d") + case .flipY: + var perspective = CATransform3DIdentity + perspective.m34 = -1.0 / layer.frame.size.width/2 + + let animation = CABasicAnimation() + animation.keyPath = "transform" + animation.fromValue = NSValue(caTransform3D: + CATransform3DMakeRotation(0, 0, 0, 0)) + animation.toValue = NSValue(caTransform3D: + CATransform3DConcat(perspective,CATransform3DMakeRotation(CGFloat(CGFloat.pi), 1, 0, 0))) + animation.duration = CFTimeInterval(duration) + animation.repeatCount = repeatCount + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + animation.timingFunction = getTimingFunction(curve: curve) + layer.add(animation, forKey: "3d") + case .morph: + let morphX = CAKeyframeAnimation() + morphX.keyPath = "transform.scale.x" + morphX.values = [1, 1.3*force, 0.7, 1.3*force, 1] + morphX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + morphX.timingFunction = getTimingFunction(curve: curve) + morphX.duration = CFTimeInterval(duration) + morphX.repeatCount = repeatCount + morphX.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(morphX, forKey: "morphX") + + let morphY = CAKeyframeAnimation() + morphY.keyPath = "transform.scale.y" + morphY.values = [1, 0.7, 1.3*force, 0.7, 1] + morphY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + morphY.timingFunction = getTimingFunction(curve: curve) + morphY.duration = CFTimeInterval(duration) + morphY.repeatCount = repeatCount + morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(morphY, forKey: "morphY") + case .squeeze: + let morphX = CAKeyframeAnimation() + morphX.keyPath = "transform.scale.x" + morphX.values = [1, 1.5*force, 0.5, 1.5*force, 1] + morphX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + morphX.timingFunction = getTimingFunction(curve: curve) + morphX.duration = CFTimeInterval(duration) + morphX.repeatCount = repeatCount + morphX.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(morphX, forKey: "morphX") + + let morphY = CAKeyframeAnimation() + morphY.keyPath = "transform.scale.y" + morphY.values = [1, 0.5, 1, 0.5, 1] + morphY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + morphY.timingFunction = getTimingFunction(curve: curve) + morphY.duration = CFTimeInterval(duration) + morphY.repeatCount = repeatCount + morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(morphY, forKey: "morphY") + case .flash: + let animation = CABasicAnimation() + animation.keyPath = "opacity" + animation.fromValue = 1 + animation.toValue = 0 + animation.duration = CFTimeInterval(duration) + animation.repeatCount = repeatCount * 2.0 + animation.autoreverses = true + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(animation, forKey: "flash") + case .wobble: + let animation = CAKeyframeAnimation() + animation.keyPath = "transform.rotation" + animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] + animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + animation.duration = CFTimeInterval(duration) + animation.isAdditive = true + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(animation, forKey: "wobble") + + let x = CAKeyframeAnimation() + x.keyPath = "position.x" + x.values = [0, 30*force, -30*force, 30*force, 0] + x.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + x.timingFunction = getTimingFunction(curve: curve) + x.duration = CFTimeInterval(duration) + x.isAdditive = true + x.repeatCount = repeatCount + x.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(x, forKey: "x") + case .swing: + let animation = CAKeyframeAnimation() + animation.keyPath = "transform.rotation" + animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] + animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + animation.duration = CFTimeInterval(duration) + animation.isAdditive = true + animation.repeatCount = repeatCount + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(animation, forKey: "swing") + } + } + } + + func getTimingFunction(curve: String) -> CAMediaTimingFunction { + if let curve = AnimationCurve(rawValue: curve) { + switch curve { + case .easeIn: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn) + case .easeOut: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut) + case .easeInOut: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) + case .linear: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear) + case .spring: return CAMediaTimingFunction(controlPoints: 0.5, 1.1+Float(force/3), 1, 1) + case .easeInSine: return CAMediaTimingFunction(controlPoints: 0.47, 0, 0.745, 0.715) + case .easeOutSine: return CAMediaTimingFunction(controlPoints: 0.39, 0.575, 0.565, 1) + case .easeInOutSine: return CAMediaTimingFunction(controlPoints: 0.445, 0.05, 0.55, 0.95) + case .easeInQuad: return CAMediaTimingFunction(controlPoints: 0.55, 0.085, 0.68, 0.53) + case .easeOutQuad: return CAMediaTimingFunction(controlPoints: 0.25, 0.46, 0.45, 0.94) + case .easeInOutQuad: return CAMediaTimingFunction(controlPoints: 0.455, 0.03, 0.515, 0.955) + case .easeInCubic: return CAMediaTimingFunction(controlPoints: 0.55, 0.055, 0.675, 0.19) + case .easeOutCubic: return CAMediaTimingFunction(controlPoints: 0.215, 0.61, 0.355, 1) + case .easeInOutCubic: return CAMediaTimingFunction(controlPoints: 0.645, 0.045, 0.355, 1) + case .easeInQuart: return CAMediaTimingFunction(controlPoints: 0.895, 0.03, 0.685, 0.22) + case .easeOutQuart: return CAMediaTimingFunction(controlPoints: 0.165, 0.84, 0.44, 1) + case .easeInOutQuart: return CAMediaTimingFunction(controlPoints: 0.77, 0, 0.175, 1) + case .easeInQuint: return CAMediaTimingFunction(controlPoints: 0.755, 0.05, 0.855, 0.06) + case .easeOutQuint: return CAMediaTimingFunction(controlPoints: 0.23, 1, 0.32, 1) + case .easeInOutQuint: return CAMediaTimingFunction(controlPoints: 0.86, 0, 0.07, 1) + case .easeInExpo: return CAMediaTimingFunction(controlPoints: 0.95, 0.05, 0.795, 0.035) + case .easeOutExpo: return CAMediaTimingFunction(controlPoints: 0.19, 1, 0.22, 1) + case .easeInOutExpo: return CAMediaTimingFunction(controlPoints: 1, 0, 0, 1) + case .easeInCirc: return CAMediaTimingFunction(controlPoints: 0.6, 0.04, 0.98, 0.335) + case .easeOutCirc: return CAMediaTimingFunction(controlPoints: 0.075, 0.82, 0.165, 1) + case .easeInOutCirc: return CAMediaTimingFunction(controlPoints: 0.785, 0.135, 0.15, 0.86) + case .easeInBack: return CAMediaTimingFunction(controlPoints: 0.6, -0.28, 0.735, 0.045) + case .easeOutBack: return CAMediaTimingFunction(controlPoints: 0.175, 0.885, 0.32, 1.275) + case .easeInOutBack: return CAMediaTimingFunction(controlPoints: 0.68, -0.55, 0.265, 1.55) + } + } + return CAMediaTimingFunction(name: CAMediaTimingFunctionName.default) + } + + func getAnimationOptions(curve: String) -> UIView.AnimationOptions { + if let curve = AnimationCurve(rawValue: curve) { + switch curve { + case .easeIn: return UIView.AnimationOptions.curveEaseIn + case .easeOut: return UIView.AnimationOptions.curveEaseOut + case .easeInOut: return UIView.AnimationOptions() + default: break + } + } + return UIView.AnimationOptions.curveLinear + } + + public func animate() { + animateFrom = true + animatePreset() + setView {} + } + + public func animateNext(completion: @escaping () -> ()) { + animateFrom = true + animatePreset() + setView { + completion() + } + } + + public func animateTo() { + animateFrom = false + animatePreset() + setView {} + } + + public func animateToNext(completion: @escaping () -> ()) { + animateFrom = false + animatePreset() + setView { + completion() + } + } + + public func customAwakeFromNib() { + if autohide { + alpha = 0 + } + } + + public func customLayoutSubviews() { + if shouldAnimateInLayoutSubviews { + shouldAnimateInLayoutSubviews = false + if autostart { + if UIApplication.shared.applicationState != .active { + shouldAnimateAfterActive = true + return + } + alpha = 0 + animate() + } + } + } + + func setView(completion: @escaping () -> ()) { + if animateFrom { + let translate = CGAffineTransform(translationX: self.x, y: self.y) + let scale = CGAffineTransform(scaleX: self.scaleX, y: self.scaleY) + let rotate = CGAffineTransform(rotationAngle: self.rotate) + let translateAndScale = translate.concatenating(scale) + self.transform = rotate.concatenating(translateAndScale) + + self.alpha = self.opacity + } + + UIView.animate( withDuration: TimeInterval(duration), + delay: TimeInterval(delay), + usingSpringWithDamping: damping, + initialSpringVelocity: velocity, + options: [getAnimationOptions(curve: curve), UIView.AnimationOptions.allowUserInteraction], + animations: { [weak self] in + if let _self = self + { + if _self.animateFrom { + _self.transform = CGAffineTransform.identity + _self.alpha = 1 + } + else { + let translate = CGAffineTransform(translationX: _self.x, y: _self.y) + let scale = CGAffineTransform(scaleX: _self.scaleX, y: _self.scaleY) + let rotate = CGAffineTransform(rotationAngle: _self.rotate) + let translateAndScale = translate.concatenating(scale) + _self.transform = rotate.concatenating(translateAndScale) + + _self.alpha = _self.opacity + } + + } + + }, completion: { [weak self] finished in + + completion() + self?.resetAll() + + }) + + } + + func reset() { + x = 0 + y = 0 + opacity = 1 + } + + func resetAll() { + x = 0 + y = 0 + animation = "" + opacity = 1 + scaleX = 1 + scaleY = 1 + rotate = 0 + damping = 0.7 + velocity = 0.7 + repeatCount = 1 + delay = 0 + duration = 0.7 + } + +} + +extension Spring { + public enum AnimationPreset: String, CaseIterable { + case slideLeft + case slideRight + case slideDown + case slideUp + case squeezeLeft + case squeezeRight + case squeezeDown + case squeezeUp + case fadeIn + case fadeOut + case fadeOutIn + case fadeInLeft + case fadeInRight + case fadeInDown + case fadeInUp + case zoomIn + case zoomOut + case fall + case shake + case pop + case flipX + case flipY + case morph + case squeeze + case flash + case wobble + case swing + } + + public enum AnimationCurve: String, CaseIterable { + case easeIn + case easeOut + case easeInOut + case linear + case spring + case easeInSine + case easeOutSine + case easeInOutSine + case easeInQuad + case easeOutQuad + case easeInOutQuad + case easeInCubic + case easeOutCubic + case easeInOutCubic + case easeInQuart + case easeOutQuart + case easeInOutQuart + case easeInQuint + case easeOutQuint + case easeInOutQuint + case easeInExpo + case easeOutExpo + case easeInOutExpo + case easeInCirc + case easeOutCirc + case easeInOutCirc + case easeInBack + case easeOutBack + case easeInOutBack } } diff --git a/Sources/Spring/SpringAnimation.swift b/Sources/Spring/SpringAnimation.swift new file mode 100644 index 0000000..998882b --- /dev/null +++ b/Sources/Spring/SpringAnimation.swift @@ -0,0 +1,112 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +@objc public class SpringAnimation: NSObject { + public class func spring(duration: TimeInterval, animations: @escaping () -> Void) { + UIView.animate( + withDuration: duration, + delay: 0, + usingSpringWithDamping: 0.7, + initialSpringVelocity: 0.7, + options: [], + animations: { + animations() + }, + completion: nil + ) + } + + public class func springEaseIn(duration: TimeInterval, animations: (() -> Void)!) { + UIView.animate( + withDuration: duration, + delay: 0, + options: .curveEaseIn, + animations: { + animations() + }, + completion: nil + ) + } + + public class func springEaseOut(duration: TimeInterval, animations: (() -> Void)!) { + UIView.animate( + withDuration: duration, + delay: 0, + options: .curveEaseOut, + animations: { + animations() + }, completion: nil + ) + } + + public class func springEaseInOut(duration: TimeInterval, animations: (() -> Void)!) { + UIView.animate( + withDuration: duration, + delay: 0, + options: UIView.AnimationOptions(), + animations: { + animations() + }, completion: nil + ) + } + + public class func springLinear(duration: TimeInterval, animations: (() -> Void)!) { + UIView.animate( + withDuration: duration, + delay: 0, + options: .curveLinear, + animations: { + animations() + }, completion: nil + ) + } + + public class func springWithDelay(duration: TimeInterval, delay: TimeInterval, animations: (() -> Void)!) { + UIView.animate( + withDuration: duration, + delay: delay, + usingSpringWithDamping: 0.7, + initialSpringVelocity: 0.7, + options: [], + animations: { + animations() + }, completion: nil + ) + } + + public class func springWithCompletion(duration: TimeInterval, animations: (() -> Void)!, completion: ((Bool) -> Void)!) { + UIView.animate( + withDuration: duration, + delay: 0, + usingSpringWithDamping: 0.7, + initialSpringVelocity: 0.7, + options: [], + animations: { + animations() + }, completion: { finished in + completion(finished) + } + ) + } +} diff --git a/Sources/Spring/SpringButton.swift b/Sources/Spring/SpringButton.swift new file mode 100644 index 0000000..92124ea --- /dev/null +++ b/Sources/Spring/SpringButton.swift @@ -0,0 +1,71 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +open class SpringButton: UIButton, Springable { + @IBInspectable public var autostart: Bool = false + @IBInspectable public var autohide: Bool = false + @IBInspectable public var animation: String = "" + @IBInspectable public var force: CGFloat = 1 + @IBInspectable public var delay: CGFloat = 0 + @IBInspectable public var duration: CGFloat = 0.7 + @IBInspectable public var damping: CGFloat = 0.7 + @IBInspectable public var velocity: CGFloat = 0.7 + @IBInspectable public var repeatCount: Float = 1 + @IBInspectable public var x: CGFloat = 0 + @IBInspectable public var y: CGFloat = 0 + @IBInspectable public var scaleX: CGFloat = 1 + @IBInspectable public var scaleY: CGFloat = 1 + @IBInspectable public var rotate: CGFloat = 0 + @IBInspectable public var curve: String = "" + public var opacity: CGFloat = 1 + public var animateFrom: Bool = false + + lazy private var spring : Spring = Spring(self) + + override open func awakeFromNib() { + super.awakeFromNib() + self.spring.customAwakeFromNib() + } + + open override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() + } + + public func animate() { + self.spring.animate() + } + + public func animateNext(completion: @escaping () -> ()) { + self.spring.animateNext(completion: completion) + } + + public func animateTo() { + self.spring.animateTo() + } + + public func animateToNext(completion: @escaping () -> ()) { + self.spring.animateToNext(completion: completion) + } +} diff --git a/Sources/Spring/SpringImageView.swift b/Sources/Spring/SpringImageView.swift new file mode 100644 index 0000000..85ad61f --- /dev/null +++ b/Sources/Spring/SpringImageView.swift @@ -0,0 +1,72 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +open class SpringImageView: UIImageView, Springable { + @IBInspectable public var autostart: Bool = false + @IBInspectable public var autohide: Bool = false + @IBInspectable public var animation: String = "" + @IBInspectable public var force: CGFloat = 1 + @IBInspectable public var delay: CGFloat = 0 + @IBInspectable public var duration: CGFloat = 0.7 + @IBInspectable public var damping: CGFloat = 0.7 + @IBInspectable public var velocity: CGFloat = 0.7 + @IBInspectable public var repeatCount: Float = 1 + @IBInspectable public var x: CGFloat = 0 + @IBInspectable public var y: CGFloat = 0 + @IBInspectable public var scaleX: CGFloat = 1 + @IBInspectable public var scaleY: CGFloat = 1 + @IBInspectable public var rotate: CGFloat = 0 + @IBInspectable public var curve: String = "" + public var opacity: CGFloat = 1 + public var animateFrom: Bool = false + + lazy private var spring : Spring = Spring(self) + + override open func awakeFromNib() { + super.awakeFromNib() + self.spring.customAwakeFromNib() + } + + open override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() + } + + public func animate() { + self.spring.animate() + } + + public func animateNext(completion: @escaping () -> ()) { + self.spring.animateNext(completion: completion) + } + + public func animateTo() { + self.spring.animateTo() + } + + public func animateToNext(completion: @escaping () -> ()) { + self.spring.animateToNext(completion: completion) + } + +} diff --git a/Sources/Spring/SpringLabel.swift b/Sources/Spring/SpringLabel.swift new file mode 100644 index 0000000..c105a48 --- /dev/null +++ b/Sources/Spring/SpringLabel.swift @@ -0,0 +1,72 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +open class SpringLabel: UILabel, Springable { + @IBInspectable public var autostart: Bool = false + @IBInspectable public var autohide: Bool = false + @IBInspectable public var animation: String = "" + @IBInspectable public var force: CGFloat = 1 + @IBInspectable public var delay: CGFloat = 0 + @IBInspectable public var duration: CGFloat = 0.7 + @IBInspectable public var damping: CGFloat = 0.7 + @IBInspectable public var velocity: CGFloat = 0.7 + @IBInspectable public var repeatCount: Float = 1 + @IBInspectable public var x: CGFloat = 0 + @IBInspectable public var y: CGFloat = 0 + @IBInspectable public var scaleX: CGFloat = 1 + @IBInspectable public var scaleY: CGFloat = 1 + @IBInspectable public var rotate: CGFloat = 0 + @IBInspectable public var curve: String = "" + public var opacity: CGFloat = 1 + public var animateFrom: Bool = false + + lazy private var spring : Spring = Spring(self) + + override open func awakeFromNib() { + super.awakeFromNib() + self.spring.customAwakeFromNib() + } + + open override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() + } + + public func animate() { + self.spring.animate() + } + + public func animateNext(completion: @escaping () -> ()) { + self.spring.animateNext(completion: completion) + } + + public func animateTo() { + self.spring.animateTo() + } + + public func animateToNext(completion: @escaping () -> ()) { + self.spring.animateToNext(completion: completion) + } + +} diff --git a/Sources/Spring/SpringTextField.swift b/Sources/Spring/SpringTextField.swift new file mode 100644 index 0000000..966b6f7 --- /dev/null +++ b/Sources/Spring/SpringTextField.swift @@ -0,0 +1,71 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +open class SpringTextField: UITextField, Springable { + @IBInspectable public var autostart: Bool = false + @IBInspectable public var autohide: Bool = false + @IBInspectable public var animation: String = "" + @IBInspectable public var force: CGFloat = 1 + @IBInspectable public var delay: CGFloat = 0 + @IBInspectable public var duration: CGFloat = 0.7 + @IBInspectable public var damping: CGFloat = 0.7 + @IBInspectable public var velocity: CGFloat = 0.7 + @IBInspectable public var repeatCount: Float = 1 + @IBInspectable public var x: CGFloat = 0 + @IBInspectable public var y: CGFloat = 0 + @IBInspectable public var scaleX: CGFloat = 1 + @IBInspectable public var scaleY: CGFloat = 1 + @IBInspectable public var rotate: CGFloat = 0 + @IBInspectable public var curve: String = "" + public var opacity: CGFloat = 1 + public var animateFrom: Bool = false + + lazy private var spring : Spring = Spring(self) + + override open func awakeFromNib() { + super.awakeFromNib() + self.spring.customAwakeFromNib() + } + + open override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() + } + + public func animate() { + self.spring.animate() + } + + public func animateNext(completion: @escaping () -> ()) { + self.spring.animateNext(completion: completion) + } + + public func animateTo() { + self.spring.animateTo() + } + + public func animateToNext(completion: @escaping () -> ()) { + self.spring.animateToNext(completion: completion) + } +} diff --git a/Sources/Spring/SpringTextView.swift b/Sources/Spring/SpringTextView.swift new file mode 100644 index 0000000..55d4e4a --- /dev/null +++ b/Sources/Spring/SpringTextView.swift @@ -0,0 +1,72 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +open class SpringTextView: UITextView, Springable { + @IBInspectable public var autostart: Bool = false + @IBInspectable public var autohide: Bool = false + @IBInspectable public var animation: String = "" + @IBInspectable public var force: CGFloat = 1 + @IBInspectable public var delay: CGFloat = 0 + @IBInspectable public var duration: CGFloat = 0.7 + @IBInspectable public var damping: CGFloat = 0.7 + @IBInspectable public var velocity: CGFloat = 0.7 + @IBInspectable public var repeatCount: Float = 1 + @IBInspectable public var x: CGFloat = 0 + @IBInspectable public var y: CGFloat = 0 + @IBInspectable public var scaleX: CGFloat = 1 + @IBInspectable public var scaleY: CGFloat = 1 + @IBInspectable public var rotate: CGFloat = 0 + @IBInspectable public var curve: String = "" + public var opacity: CGFloat = 1 + public var animateFrom: Bool = false + + lazy private var spring : Spring = Spring(self) + + override open func awakeFromNib() { + super.awakeFromNib() + self.spring.customAwakeFromNib() + } + + open override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() + } + + public func animate() { + self.spring.animate() + } + + public func animateNext(completion: @escaping () -> ()) { + self.spring.animateNext(completion: completion) + } + + public func animateTo() { + self.spring.animateTo() + } + + public func animateToNext(completion: @escaping () -> ()) { + self.spring.animateToNext(completion: completion) + } + +} diff --git a/Sources/Spring/SpringView.swift b/Sources/Spring/SpringView.swift new file mode 100644 index 0000000..a00c12a --- /dev/null +++ b/Sources/Spring/SpringView.swift @@ -0,0 +1,71 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +open class SpringView: UIView, Springable { + @IBInspectable public var autostart: Bool = false + @IBInspectable public var autohide: Bool = false + @IBInspectable public var animation: String = "" + @IBInspectable public var force: CGFloat = 1 + @IBInspectable public var delay: CGFloat = 0 + @IBInspectable public var duration: CGFloat = 0.7 + @IBInspectable public var damping: CGFloat = 0.7 + @IBInspectable public var velocity: CGFloat = 0.7 + @IBInspectable public var repeatCount: Float = 1 + @IBInspectable public var x: CGFloat = 0 + @IBInspectable public var y: CGFloat = 0 + @IBInspectable public var scaleX: CGFloat = 1 + @IBInspectable public var scaleY: CGFloat = 1 + @IBInspectable public var rotate: CGFloat = 0 + @IBInspectable public var curve: String = "" + public var opacity: CGFloat = 1 + public var animateFrom: Bool = false + + lazy private var spring : Spring = Spring(self) + + override open func awakeFromNib() { + super.awakeFromNib() + self.spring.customAwakeFromNib() + } + + open override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() + } + + public func animate() { + self.spring.animate() + } + + public func animateNext(completion: @escaping () -> ()) { + self.spring.animateNext(completion: completion) + } + + public func animateTo() { + self.spring.animateTo() + } + + public func animateToNext(completion: @escaping () -> ()) { + self.spring.animateToNext(completion: completion) + } +} diff --git a/Sources/Spring/TransitionManager.swift b/Sources/Spring/TransitionManager.swift new file mode 100644 index 0000000..388edac --- /dev/null +++ b/Sources/Spring/TransitionManager.swift @@ -0,0 +1,86 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +public class TransitionManager: NSObject, UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning { + + var isPresenting = true + var duration = 0.3 + + public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + let container = transitionContext.containerView + let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)! + let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)! + + if isPresenting { + toView.frame = container.bounds + toView.transform = CGAffineTransform(translationX: 0, y: container.frame.size.height) + container.addSubview(fromView) + container.addSubview(toView) + SpringAnimation.springEaseInOut(duration: duration) { + fromView.transform = CGAffineTransform(scaleX: 0.8, y: 0.8) + fromView.alpha = 0.5 + toView.transform = CGAffineTransform.identity + } + } + else { + + // 1. Rotating will change the bounds + // 2. we have to properly reset toView + // to the actual container's bounds, at + // the same time take consideration of + // previous transformation when presenting + let transform = toView.transform + toView.transform = CGAffineTransform.identity + toView.frame = container.bounds + toView.transform = transform + + container.addSubview(toView) + container.addSubview(fromView) + + SpringAnimation.springEaseInOut(duration: duration) { + fromView.transform = CGAffineTransform(translationX: 0, y: fromView.frame.size.height) + toView.transform = CGAffineTransform.identity + toView.alpha = 1 + } + } + + delay(delay: duration, closure: { + transitionContext.completeTransition(true) + }) + } + + public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + return duration + } + + public func animationController(forPresentedController presented: UIViewController, presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { + isPresenting = true + return self + } + + public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { + isPresenting = false + return self + } +} diff --git a/Sources/Spring/TransitionZoom.swift b/Sources/Spring/TransitionZoom.swift new file mode 100644 index 0000000..6cf5301 --- /dev/null +++ b/Sources/Spring/TransitionZoom.swift @@ -0,0 +1,79 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +public class TransitionZoom: NSObject, UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning { + + var isPresenting = true + var duration = 0.4 + + public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + let container = transitionContext.containerView + let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)! + let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)! + + if isPresenting { + container.addSubview(fromView) + container.addSubview(toView) + + toView.alpha = 0 + toView.transform = CGAffineTransform(scaleX: 2, y: 2) + + SpringAnimation.springEaseInOut(duration: duration) { + fromView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5) + fromView.alpha = 0 + toView.transform = CGAffineTransform.identity + toView.alpha = 1 + } + } + else { + container.addSubview(toView) + container.addSubview(fromView) + + SpringAnimation.springEaseInOut(duration: duration) { + fromView.transform = CGAffineTransform(scaleX: 2, y: 2) + fromView.alpha = 0 + toView.transform = CGAffineTransform(scaleX: 1, y: 1) + toView.alpha = 1 + } + } + + delay(delay: duration, closure: { + transitionContext.completeTransition(true) + }) + } + + public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + return duration + } + + public func animationController(forPresentedController presented: UIViewController, presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { + isPresenting = true + return self + } + + public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { + isPresenting = false + return self + } +} diff --git a/Sources/Spring/UnwindSegue.swift b/Sources/Spring/UnwindSegue.swift new file mode 100644 index 0000000..2080094 --- /dev/null +++ b/Sources/Spring/UnwindSegue.swift @@ -0,0 +1,27 @@ +// The MIT License (MIT) +// +// Copyright (c) 2015 Meng To (meng@designcode.io) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +import UIKit + +public extension UIViewController { + @IBAction func unwindToViewController (_ segue: UIStoryboardSegue){} +} diff --git a/Spring.podspec b/Spring.podspec index d1a28e6..1f516d6 100644 --- a/Spring.podspec +++ b/Spring.podspec @@ -9,7 +9,7 @@ Pod::Spec.new do |s| s.requires_arc = true s.ios.deployment_target = '14.0' s.tvos.deployment_target = '11.0' - s.source_files = 'Spring/*.swift' + s.source_files = 'Sources/Spring/*.swift' s.ios.resources = ['Spring/*.xib', 'SpringApp/*.xcassets'] s.tvos.resources = ['SpringApp/*.xcassets'] end From e4974ac8ea1bd5c1b8fda94e12683f7baa170857 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 12 Apr 2022 15:14:25 +0300 Subject: [PATCH 18/21] Delete Spring dir --- Spring.podspec | 2 +- Spring/AsyncButton.swift | 51 -- Spring/AsyncImageView.swift | 51 -- Spring/AutoTextView.swift | 27 - Spring/BlurView.swift | 33 -- Spring/DesignableButton.swift | 69 --- Spring/DesignableImageView.swift | 45 -- Spring/DesignableLabel.swift | 43 -- Spring/DesignableTabBarController.swift | 123 ----- Spring/DesignableTextField.swift | 100 ---- Spring/DesignableTextView.swift | 61 --- Spring/DesignableView.swift | 68 --- Spring/ImageLoader.swift | 86 ---- Spring/Info.plist | 26 - Spring/KeyboardLayoutConstraint.swift | 112 ----- Spring/LoadingView.swift | 86 ---- Spring/LoadingView.xib | 50 -- Spring/Misc.swift | 263 ---------- Spring/SoundPlayer.swift | 60 --- Spring/Spring.h | 19 - Spring/Spring.swift | 643 ------------------------ Spring/SpringAnimation.swift | 112 ----- Spring/SpringButton.swift | 71 --- Spring/SpringImageView.swift | 72 --- Spring/SpringLabel.swift | 72 --- Spring/SpringTextField.swift | 71 --- Spring/SpringTextView.swift | 72 --- Spring/SpringView.swift | 71 --- Spring/TransitionManager.swift | 86 ---- Spring/TransitionZoom.swift | 79 --- Spring/UnwindSegue.swift | 27 - 31 files changed, 1 insertion(+), 2750 deletions(-) delete mode 100644 Spring/AsyncButton.swift delete mode 100644 Spring/AsyncImageView.swift delete mode 100644 Spring/AutoTextView.swift delete mode 100644 Spring/BlurView.swift delete mode 100644 Spring/DesignableButton.swift delete mode 100644 Spring/DesignableImageView.swift delete mode 100644 Spring/DesignableLabel.swift delete mode 100644 Spring/DesignableTabBarController.swift delete mode 100644 Spring/DesignableTextField.swift delete mode 100644 Spring/DesignableTextView.swift delete mode 100644 Spring/DesignableView.swift delete mode 100755 Spring/ImageLoader.swift delete mode 100644 Spring/Info.plist delete mode 100644 Spring/KeyboardLayoutConstraint.swift delete mode 100644 Spring/LoadingView.swift delete mode 100644 Spring/LoadingView.xib delete mode 100644 Spring/Misc.swift delete mode 100644 Spring/SoundPlayer.swift delete mode 100644 Spring/Spring.h delete mode 100644 Spring/Spring.swift delete mode 100644 Spring/SpringAnimation.swift delete mode 100644 Spring/SpringButton.swift delete mode 100644 Spring/SpringImageView.swift delete mode 100644 Spring/SpringLabel.swift delete mode 100644 Spring/SpringTextField.swift delete mode 100644 Spring/SpringTextView.swift delete mode 100644 Spring/SpringView.swift delete mode 100644 Spring/TransitionManager.swift delete mode 100644 Spring/TransitionZoom.swift delete mode 100644 Spring/UnwindSegue.swift diff --git a/Spring.podspec b/Spring.podspec index 1f516d6..04f48f8 100644 --- a/Spring.podspec +++ b/Spring.podspec @@ -10,6 +10,6 @@ Pod::Spec.new do |s| s.ios.deployment_target = '14.0' s.tvos.deployment_target = '11.0' s.source_files = 'Sources/Spring/*.swift' - s.ios.resources = ['Spring/*.xib', 'SpringApp/*.xcassets'] + s.ios.resources = ['Sources/Spring/*.xib', 'SpringApp/*.xcassets'] s.tvos.resources = ['SpringApp/*.xcassets'] end diff --git a/Spring/AsyncButton.swift b/Spring/AsyncButton.swift deleted file mode 100644 index 6e03ac9..0000000 --- a/Spring/AsyncButton.swift +++ /dev/null @@ -1,51 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 James Tang (j@jamztang.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -public class AsyncButton: UIButton { - - private var imageURL = [UInt:NSURL]() - private var placeholderImage = [UInt:UIImage]() - - - public func setImageURL(url: NSURL?, placeholderImage placeholder:UIImage?, forState state:UIControl.State) { - - imageURL[state.rawValue] = url - placeholderImage[state.rawValue] = placeholder - - if let urlString = url?.absoluteString { - ImageLoader.sharedLoader.imageForUrl(urlString: urlString) { [weak self] image, url in - - if let strongSelf = self { - - DispatchQueue.main.async(execute: { () -> Void in - if strongSelf.imageURL[state.rawValue]?.absoluteString == url { - strongSelf.setImage(image, for: state) - } - }) - } - } - } - } - -} diff --git a/Spring/AsyncImageView.swift b/Spring/AsyncImageView.swift deleted file mode 100644 index aa2f7e8..0000000 --- a/Spring/AsyncImageView.swift +++ /dev/null @@ -1,51 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 James Tang (j@jamztang.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -public class AsyncImageView: UIImageView { - - public var placeholderImage : UIImage? - - public var url : NSURL? { - didSet { - self.image = placeholderImage - if let urlString = url?.absoluteString { - ImageLoader.sharedLoader.imageForUrl(urlString: urlString) { [weak self] image, url in - if let strongSelf = self { - DispatchQueue.main.async(execute: { () -> Void in - if strongSelf.url?.absoluteString == url { - strongSelf.image = image ?? strongSelf.placeholderImage - } - }) - } - } - } - } - } - - public func setURL(url: NSURL?, placeholderImage: UIImage?) { - self.placeholderImage = placeholderImage - self.url = url - } - -} diff --git a/Spring/AutoTextView.swift b/Spring/AutoTextView.swift deleted file mode 100644 index 1d0c7e6..0000000 --- a/Spring/AutoTextView.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// AutoTextView.swift -// SpringApp -// -// Created by Meng To on 2015-03-27. -// Copyright (c) 2015 Meng To. All rights reserved. -// - -import UIKit - -public class AutoTextView: UITextView { - - public override var intrinsicContentSize: CGSize { - get { - var size = self.sizeThatFits(CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude)) - size.width = self.frame.size.width - if text.length == 0 { - size.height = 0 - } - - contentInset = UIEdgeInsets(top: -4, left: -4, bottom: -4, right: -4) - layoutIfNeeded() - - return size - } - } -} diff --git a/Spring/BlurView.swift b/Spring/BlurView.swift deleted file mode 100644 index 8de1611..0000000 --- a/Spring/BlurView.swift +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -public func insertBlurView (view: UIView, style: UIBlurEffect.Style) -> UIVisualEffectView { - view.backgroundColor = UIColor.clear - - let blurEffect = UIBlurEffect(style: style) - let blurEffectView = UIVisualEffectView(effect: blurEffect) - blurEffectView.frame = view.bounds - view.insertSubview(blurEffectView, at: 0) - return blurEffectView -} diff --git a/Spring/DesignableButton.swift b/Spring/DesignableButton.swift deleted file mode 100644 index 0612083..0000000 --- a/Spring/DesignableButton.swift +++ /dev/null @@ -1,69 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -@IBDesignable public class DesignableButton: SpringButton { - - @IBInspectable public var borderColor: UIColor = UIColor.clear { - didSet { - layer.borderColor = borderColor.cgColor - } - } - - @IBInspectable public var borderWidth: CGFloat = 0 { - didSet { - layer.borderWidth = borderWidth - } - } - - @IBInspectable public var cornerRadius: CGFloat = 0 { - didSet { - layer.cornerRadius = cornerRadius - } - } - - @IBInspectable public var shadowColor: UIColor = UIColor.clear { - didSet { - layer.shadowColor = shadowColor.cgColor - } - } - - @IBInspectable public var shadowRadius: CGFloat = 0 { - didSet { - layer.shadowRadius = shadowRadius - } - } - - @IBInspectable public var shadowOpacity: CGFloat = 0 { - didSet { - layer.shadowOpacity = Float(shadowOpacity) - } - } - - @IBInspectable public var shadowOffsetY: CGFloat = 0 { - didSet { - layer.shadowOffset.height = shadowOffsetY - } - } - -} diff --git a/Spring/DesignableImageView.swift b/Spring/DesignableImageView.swift deleted file mode 100644 index 32a90a2..0000000 --- a/Spring/DesignableImageView.swift +++ /dev/null @@ -1,45 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -@IBDesignable public class DesignableImageView: SpringImageView { - - @IBInspectable public var borderColor: UIColor = UIColor.clear { - didSet { - layer.borderColor = borderColor.cgColor - } - } - - @IBInspectable public var borderWidth: CGFloat = 0 { - didSet { - layer.borderWidth = borderWidth - } - } - - @IBInspectable public var cornerRadius: CGFloat = 0 { - didSet { - layer.cornerRadius = cornerRadius - } - } - -} diff --git a/Spring/DesignableLabel.swift b/Spring/DesignableLabel.swift deleted file mode 100644 index 8d6994b..0000000 --- a/Spring/DesignableLabel.swift +++ /dev/null @@ -1,43 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -@IBDesignable public class DesignableLabel: SpringLabel { - - @IBInspectable public var lineHeight: CGFloat = 1.5 { - didSet { - let font = UIFont(name: self.font.fontName, size: self.font.pointSize) - guard let text = self.text else { return } - - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.lineSpacing = lineHeight - - let attributedString = NSMutableAttributedString(string: text) - attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, attributedString.length)) - attributedString.addAttribute(NSAttributedString.Key.font, value: font!, range: NSMakeRange(0, attributedString.length)) - - self.attributedText = attributedString - } - } - -} diff --git a/Spring/DesignableTabBarController.swift b/Spring/DesignableTabBarController.swift deleted file mode 100644 index c3ab5f3..0000000 --- a/Spring/DesignableTabBarController.swift +++ /dev/null @@ -1,123 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -@IBDesignable class DesignableTabBarController: UITabBarController { - - @IBInspectable var normalTint: UIColor = UIColor.clear { - didSet { - UITabBar.appearance().tintColor = normalTint - UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: normalTint], for: UIControl.State()) - } - } - - @IBInspectable var selectedTint: UIColor = UIColor.clear { - didSet { - UITabBar.appearance().tintColor = selectedTint - UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: selectedTint], for:UIControl.State.selected) - } - } - - @IBInspectable var fontName: String = "" { - didSet { - UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: normalTint, NSAttributedString.Key.font: UIFont(name: fontName, size: 11)!], for: UIControl.State()) - } - } - - @IBInspectable var firstSelectedImage: UIImage? { - didSet { - if let image = firstSelectedImage { - let tabBarItems = self.tabBar.items as [UITabBarItem]? - tabBarItems?[0].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) - } - } - } - - @IBInspectable var secondSelectedImage: UIImage? { - didSet { - if let image = secondSelectedImage { - let tabBarItems = self.tabBar.items as [UITabBarItem]? - tabBarItems?[1].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) - } - } - } - - @IBInspectable var thirdSelectedImage: UIImage? { - didSet { - if let image = thirdSelectedImage { - let tabBarItems = self.tabBar.items as [UITabBarItem]? - tabBarItems?[2].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) - } - } - } - - @IBInspectable var fourthSelectedImage: UIImage? { - didSet { - if let image = fourthSelectedImage { - let tabBarItems = self.tabBar.items as [UITabBarItem]? - tabBarItems?[3].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) - } - } - } - - @IBInspectable var fifthSelectedImage: UIImage? { - didSet { - if let image = fifthSelectedImage { - let tabBarItems = self.tabBar.items as [UITabBarItem]? - tabBarItems?[4].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) - } - } - } - - override func viewDidLoad() { - super.viewDidLoad() - if let items = self.tabBar.items { - for item in items { - if let image = item.image { - item.image = image.imageWithColor(tintColor: self.normalTint).withRenderingMode(UIImage.RenderingMode.alwaysOriginal) - } - } - } - } -} - -extension UIImage { - func imageWithColor(tintColor: UIColor) -> UIImage { - UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale) - - let context = UIGraphicsGetCurrentContext() - context!.translateBy(x: 0, y: self.size.height) - context!.scaleBy(x: 1.0, y: -1.0); - context!.setBlendMode(CGBlendMode.normal) - - let rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height) - context?.clip(to: rect, mask: self.cgImage!) - tintColor.setFill() - context!.fill(rect) - - let newImage = UIGraphicsGetImageFromCurrentImageContext()! as UIImage - UIGraphicsEndImageContext() - - return newImage - } -} diff --git a/Spring/DesignableTextField.swift b/Spring/DesignableTextField.swift deleted file mode 100644 index e334a8e..0000000 --- a/Spring/DesignableTextField.swift +++ /dev/null @@ -1,100 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -@IBDesignable public class DesignableTextField: SpringTextField { - - @IBInspectable public var placeholderColor: UIColor = UIColor.clear { - didSet { - guard let placeholder = placeholder else { return } - attributedPlaceholder = NSAttributedString(string: placeholder, attributes: [NSAttributedString.Key.foregroundColor: placeholderColor]) - layoutSubviews() - - } - } - - @IBInspectable public var sidePadding: CGFloat = 0 { - didSet { - let padding = UIView(frame: CGRect(x: 0, y: 0, width: sidePadding, height: sidePadding)) - - leftViewMode = UITextField.ViewMode.always - leftView = padding - - rightViewMode = UITextField.ViewMode.always - rightView = padding - } - } - - @IBInspectable public var leftPadding: CGFloat = 0 { - didSet { - let padding = UIView(frame: CGRect(x: 0, y: 0, width: leftPadding, height: 0)) - - leftViewMode = UITextField.ViewMode.always - leftView = padding - } - } - - @IBInspectable public var rightPadding: CGFloat = 0 { - didSet { - let padding = UIView(frame: CGRect(x: 0, y: 0, width: rightPadding, height: 0)) - - rightViewMode = UITextField.ViewMode.always - rightView = padding - } - } - - @IBInspectable public var borderColor: UIColor = UIColor.clear { - didSet { - layer.borderColor = borderColor.cgColor - } - } - - @IBInspectable public var borderWidth: CGFloat = 0 { - didSet { - layer.borderWidth = borderWidth - } - } - - @IBInspectable public var cornerRadius: CGFloat = 0 { - didSet { - layer.cornerRadius = cornerRadius - } - } - - @IBInspectable public var lineHeight: CGFloat = 1.5 { - didSet { - let font = UIFont(name: self.font!.fontName, size: self.font!.pointSize) - guard let text = self.text else { return } - - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.lineSpacing = lineHeight - - let attributedString = NSMutableAttributedString(string: text) - attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedString.length)) - attributedString.addAttribute(NSAttributedString.Key.font, value: font!, range: NSRange(location: 0, length: attributedString.length)) - - self.attributedText = attributedString - } - } - -} diff --git a/Spring/DesignableTextView.swift b/Spring/DesignableTextView.swift deleted file mode 100644 index 779298a..0000000 --- a/Spring/DesignableTextView.swift +++ /dev/null @@ -1,61 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -@IBDesignable public class DesignableTextView: SpringTextView { - - @IBInspectable public var borderColor: UIColor = UIColor.clear { - didSet { - layer.borderColor = borderColor.cgColor - } - } - - @IBInspectable public var borderWidth: CGFloat = 0 { - didSet { - layer.borderWidth = borderWidth - } - } - - @IBInspectable public var cornerRadius: CGFloat = 0 { - didSet { - layer.cornerRadius = cornerRadius - } - } - - @IBInspectable public var lineHeight: CGFloat = 1.5 { - didSet { - let font = UIFont(name: self.font!.fontName, size: self.font!.pointSize) - guard let text = self.text else { return } - - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.lineSpacing = lineHeight - - let attributedString = NSMutableAttributedString(string: text) - attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedString.length)) - attributedString.addAttribute(NSAttributedString.Key.font, value: font!, range: NSRange(location: 0, length: attributedString.length)) - - self.attributedText = attributedString - } - } - -} diff --git a/Spring/DesignableView.swift b/Spring/DesignableView.swift deleted file mode 100644 index a82d23f..0000000 --- a/Spring/DesignableView.swift +++ /dev/null @@ -1,68 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -@IBDesignable public class DesignableView: SpringView { - - @IBInspectable public var borderColor: UIColor = UIColor.clear { - didSet { - layer.borderColor = borderColor.cgColor - } - } - - @IBInspectable public var borderWidth: CGFloat = 0 { - didSet { - layer.borderWidth = borderWidth - } - } - - @IBInspectable public var cornerRadius: CGFloat = 0 { - didSet { - layer.cornerRadius = cornerRadius - } - } - - @IBInspectable public var shadowColor: UIColor = UIColor.clear { - didSet { - layer.shadowColor = shadowColor.cgColor - } - } - - @IBInspectable public var shadowRadius: CGFloat = 0 { - didSet { - layer.shadowRadius = shadowRadius - } - } - - @IBInspectable public var shadowOpacity: CGFloat = 0 { - didSet { - layer.shadowOpacity = Float(shadowOpacity) - } - } - - @IBInspectable public var shadowOffsetY: CGFloat = 0 { - didSet { - layer.shadowOffset.height = shadowOffsetY - } - } -} diff --git a/Spring/ImageLoader.swift b/Spring/ImageLoader.swift deleted file mode 100755 index bcb626d..0000000 --- a/Spring/ImageLoader.swift +++ /dev/null @@ -1,86 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2014 Nate Lyman (https://github.com/natelyman/SwiftImageLoader) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit -import Foundation - - -public class ImageLoader { - - var cache = NSCache() - - public class var sharedLoader : ImageLoader { - struct Static { - static let instance : ImageLoader = ImageLoader() - } - return Static.instance - } - - public func imageForUrl(urlString: String, completionHandler: @escaping(_ image: UIImage?, _ url: String) -> ()) { - DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async { - var data: NSData? - - if let dataCache = self.cache.object(forKey: urlString as NSString){ - data = (dataCache) as NSData - - }else{ - if (URL(string: urlString) != nil) - { - data = NSData(contentsOf: URL(string: urlString)!) - if data != nil { - self.cache.setObject(data!, forKey: urlString as NSString) - } - }else{ - return - } - } - - if let goodData = data { - let image = UIImage(data: goodData as Data) - DispatchQueue.main.async(execute: {() in - completionHandler(image, urlString) - }) - return - } - - let downloadTask: URLSessionDataTask = URLSession.shared.dataTask(with: URL(string: urlString)!, completionHandler: { (data, response, error) -> Void in - - if (error != nil) { - completionHandler(nil, urlString) - return - } - - if data != nil { - let image = UIImage(data: data!) - self.cache.setObject(data! as NSData, forKey: urlString as NSString) - DispatchQueue.main.async(execute: {() in - completionHandler(image, urlString) - }) - return - } - }) - downloadTask.resume() - - } - - } -} diff --git a/Spring/Info.plist b/Spring/Info.plist deleted file mode 100644 index d3de8ee..0000000 --- a/Spring/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - - - diff --git a/Spring/KeyboardLayoutConstraint.swift b/Spring/KeyboardLayoutConstraint.swift deleted file mode 100644 index f918a13..0000000 --- a/Spring/KeyboardLayoutConstraint.swift +++ /dev/null @@ -1,112 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 James Tang (j@jamztang.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -#if !os(tvOS) -@available(tvOS, unavailable) -public class KeyboardLayoutConstraint: NSLayoutConstraint { - - private var offset: CGFloat = 0 - private var keyboardVisibleHeight: CGFloat = 0 - - @available(tvOS, unavailable) - override public func awakeFromNib() { - super.awakeFromNib() - - offset = constant - - NotificationCenter.default.addObserver( - self, - selector: #selector(KeyboardLayoutConstraint.keyboardWillShowNotification), - name: UIWindow.keyboardWillShowNotification, - object: nil - ) - NotificationCenter.default.addObserver( - self, - selector: #selector(KeyboardLayoutConstraint.keyboardWillHideNotification), - name: UIWindow.keyboardWillHideNotification, - object: nil - ) - } - - deinit { - NotificationCenter.default.removeObserver(self) - } - - // MARK: Notification - @objc func keyboardWillShowNotification(_ notification: Notification) { - if let userInfo = notification.userInfo { - if let frameValue = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue { - let frame = frameValue.cgRectValue - keyboardVisibleHeight = frame.size.height - } - - self.updateConstant() - switch (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber) { - case let (.some(duration), .some(curve)): - - let options = UIView.AnimationOptions(rawValue: curve.uintValue) - - UIView.animate( - withDuration: TimeInterval(duration.doubleValue), - delay: 0, - options: options) { - UIApplication.shared.windows.first?.layoutIfNeeded() - return - } - default: - break - } - } - } - - @objc func keyboardWillHideNotification(_ notification: NSNotification) { - keyboardVisibleHeight = 0 - updateConstant() - - if let userInfo = notification.userInfo { - - switch (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber) { - case let (.some(duration), .some(curve)): - - let options = UIView.AnimationOptions(rawValue: curve.uintValue) - - UIView.animate( - withDuration: TimeInterval(duration.doubleValue), - delay: 0, - options: options) { - UIApplication.shared.windows.first?.layoutIfNeeded() - return - } - default: - break - } - } - } - - func updateConstant() { - constant = offset + keyboardVisibleHeight - } - -} -#endif diff --git a/Spring/LoadingView.swift b/Spring/LoadingView.swift deleted file mode 100644 index 55e5e2c..0000000 --- a/Spring/LoadingView.swift +++ /dev/null @@ -1,86 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -#if !os(tvOS) -@available(tvOS, unavailable) -public class LoadingView: UIView { - - @IBOutlet public weak var indicatorView: SpringView! - - override public func awakeFromNib() { - let animation = CABasicAnimation() - animation.keyPath = "transform.rotation.z" - animation.fromValue = degreesToRadians(degrees: 0) - animation.toValue = degreesToRadians(degrees: 360) - animation.duration = 0.9 - animation.repeatCount = HUGE - indicatorView.layer.add(animation, forKey: "") - } - - class func designCodeLoadingView() -> UIView { - - return Bundle(for: self).loadNibNamed("LoadingView", owner: self, options: nil)![0] as! UIView - } -} - -public extension UIView { - - struct LoadingViewConstants { - static let Tag = 1000 - } - - func showLoading() { - - if self.viewWithTag(LoadingViewConstants.Tag) != nil { - // If loading view is already found in current view hierachy, do nothing - return - } - - let loadingXibView = LoadingView.designCodeLoadingView() - loadingXibView.frame = self.bounds - loadingXibView.tag = LoadingViewConstants.Tag - self.addSubview(loadingXibView) - - loadingXibView.alpha = 0 - SpringAnimation.spring(duration: 0.7, animations: { - loadingXibView.alpha = 1 - }) - } - - func hideLoading() { - - if let loadingXibView = self.viewWithTag(LoadingViewConstants.Tag) { - loadingXibView.alpha = 1 - - SpringAnimation.springWithCompletion(duration: 0.7, animations: { - loadingXibView.alpha = 0 - loadingXibView.transform = CGAffineTransform(scaleX: 3, y: 3) - }, completion: { (completed) -> Void in - loadingXibView.removeFromSuperview() - }) - } - } - -} -#endif diff --git a/Spring/LoadingView.xib b/Spring/LoadingView.xib deleted file mode 100644 index 48a0901..0000000 --- a/Spring/LoadingView.xib +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Spring/Misc.swift b/Spring/Misc.swift deleted file mode 100644 index 96024b8..0000000 --- a/Spring/Misc.swift +++ /dev/null @@ -1,263 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -public extension String { - var length: Int { return self.count } - - func toURL() -> NSURL? { - return NSURL(string: self) - } -} - -public func htmlToAttributedString(text: String) -> NSAttributedString! { - guard let htmlData = text.data(using: String.Encoding.utf8, allowLossyConversion: false) else { - return NSAttributedString() } - let htmlString: NSAttributedString? - do { - htmlString = try NSAttributedString(data: htmlData, options: [NSAttributedString.DocumentReadingOptionKey.documentType:NSAttributedString.DocumentType.html], documentAttributes: nil) - } catch _ { - htmlString = nil - } - - return htmlString -} - -public func degreesToRadians(degrees: CGFloat) -> CGFloat { - return degrees * CGFloat(CGFloat.pi / 180) -} - -public func delay(delay:Double, closure: @escaping ()->()) { - DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure) -} - -public func imageFromURL(_ Url: String) -> UIImage { - let url = Foundation.URL(string: Url) - let data = try? Data(contentsOf: url!) - return UIImage(data: data!)! -} - -public extension UIColor { - convenience init(hex: String) { - var red: CGFloat = 0.0 - var green: CGFloat = 0.0 - var blue: CGFloat = 0.0 - var alpha: CGFloat = 1.0 - var hex: String = hex - - if hex.hasPrefix("#") { - let index = hex.index(hex.startIndex, offsetBy: 1) - hex = String(hex[index...]) - } - - let scanner = Scanner(string: hex) - var hexValue: CUnsignedLongLong = 0 - if scanner.scanHexInt64(&hexValue) { - switch (hex.count) { - case 3: - red = CGFloat((hexValue & 0xF00) >> 8) / 15.0 - green = CGFloat((hexValue & 0x0F0) >> 4) / 15.0 - blue = CGFloat(hexValue & 0x00F) / 15.0 - case 4: - red = CGFloat((hexValue & 0xF000) >> 12) / 15.0 - green = CGFloat((hexValue & 0x0F00) >> 8) / 15.0 - blue = CGFloat((hexValue & 0x00F0) >> 4) / 15.0 - alpha = CGFloat(hexValue & 0x000F) / 15.0 - case 6: - red = CGFloat((hexValue & 0xFF0000) >> 16) / 255.0 - green = CGFloat((hexValue & 0x00FF00) >> 8) / 255.0 - blue = CGFloat(hexValue & 0x0000FF) / 255.0 - case 8: - red = CGFloat((hexValue & 0xFF000000) >> 24) / 255.0 - green = CGFloat((hexValue & 0x00FF0000) >> 16) / 255.0 - blue = CGFloat((hexValue & 0x0000FF00) >> 8) / 255.0 - alpha = CGFloat(hexValue & 0x000000FF) / 255.0 - default: - print("Invalid RGB string, number of characters after '#' should be either 3, 4, 6 or 8", terminator: "") - } - } else { - print("Scan hex error") - } - self.init(red:red, green:green, blue:blue, alpha:alpha) - } -} - -public func rgbaToUIColor(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) -> UIColor { - - return UIColor(red: red, green: green, blue: blue, alpha: alpha) -} - -public func UIColorFromRGB(rgbValue: UInt) -> UIColor { - return UIColor( - red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, - green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0, - blue: CGFloat(rgbValue & 0x0000FF) / 255.0, - alpha: CGFloat(1.0) - ) -} - -public func stringFromDate(date: NSDate, format: String) -> String { - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = format - return dateFormatter.string(from: date as Date) -} - -public func dateFromString(date: String, format: String) -> Date { - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = format - if let date = dateFormatter.date(from: date) { - return date - } else { - return Date(timeIntervalSince1970: 0) - } -} - -public func randomStringWithLength (len : Int) -> NSString { - - let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - - let randomString : NSMutableString = NSMutableString(capacity: len) - - for _ in 0 ..< len { - let length = UInt32 (letters.length) - let rand = arc4random_uniform(length) - randomString.appendFormat("%C", letters.character(at: Int(rand))) - } - - return randomString -} - -public func timeAgoSinceDate(date: Date, numericDates: Bool) -> String { - let calendar = Calendar.current - let unitFlags = Set(arrayLiteral: Calendar.Component.minute, Calendar.Component.hour, Calendar.Component.day, Calendar.Component.weekOfYear, Calendar.Component.month, Calendar.Component.year, Calendar.Component.second) - let now = Date() - let dateComparison = now.compare(date) - var earliest: Date - var latest: Date - - switch dateComparison { - case .orderedAscending: - earliest = now - latest = date - default: - earliest = date - latest = now - } - - let components: DateComponents = calendar.dateComponents(unitFlags, from: earliest, to: latest) - - guard - let year = components.year, - let month = components.month, - let weekOfYear = components.weekOfYear, - let day = components.day, - let hour = components.hour, - let minute = components.minute, - let second = components.second - else { - fatalError() - } - - if (year >= 2) { - return "\(year)y" - } else if (year >= 1) { - if (numericDates){ - return "1y" - } else { - return "1y" - } - } else if (month >= 2) { - return "\(month * 4)w" - } else if (month >= 1) { - if (numericDates){ - return "4w" - } else { - return "4w" - } - } else if (weekOfYear >= 2) { - return "\(weekOfYear)w" - } else if (weekOfYear >= 1){ - if (numericDates){ - return "1w" - } else { - return "1w" - } - } else if (day >= 2) { - return "\(components.day ?? 2)d" - } else if (day >= 1){ - if (numericDates){ - return "1d" - } else { - return "1d" - } - } else if (hour >= 2) { - return "\(hour)h" - } else if (hour >= 1){ - if (numericDates){ - return "1h" - } else { - return "1h" - } - } else if (minute >= 2) { - return "\(minute)m" - } else if (minute >= 1){ - if (numericDates){ - return "1m" - } else { - return "1m" - } - } else if (second >= 3) { - return "\(second)s" - } else { - return "now" - } - -} - -extension UIImageView { - func setImage(url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit, placeholderImage: UIImage?) { - contentMode = mode - URLSession.shared.dataTask(with: url) { (data, response, error) in - guard - let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200, - let mimeType = response?.mimeType, mimeType.hasPrefix("image"), - let data = data, error == nil, - let image = UIImage(data: data) - else { - self.image = placeholderImage - return - } - DispatchQueue.main.async() { () -> Void in - self.image = image - - } - }.resume() - } - func setImage(urlString: String, contentMode mode: UIView.ContentMode = .scaleAspectFit, placeholderImage: UIImage?) { - guard let url = URL(string: urlString) else { - image = placeholderImage - return - } - setImage(url: url, contentMode: mode, placeholderImage: placeholderImage) - } -} diff --git a/Spring/SoundPlayer.swift b/Spring/SoundPlayer.swift deleted file mode 100644 index d2451d9..0000000 --- a/Spring/SoundPlayer.swift +++ /dev/null @@ -1,60 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 James Tang (j@jamztang.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit -import AudioToolbox - -public struct SoundPlayer { - - static var filename : String? - static var enabled : Bool = true - - private struct Internal { - static var cache = [URL:SystemSoundID]() - } - - public static func playSound(soundFile: String) { - - if !enabled { - return - } - - if let url = Bundle.main.url(forResource: soundFile, withExtension: nil) { - - var soundID : SystemSoundID = Internal.cache[url] ?? 0 - - if soundID == 0 { - AudioServicesCreateSystemSoundID(url as CFURL, &soundID) - Internal.cache[url] = soundID - } - - AudioServicesPlaySystemSound(soundID) - - } else { - print("Could not find sound file name `\(soundFile)`") - } - } - - static func play(file: String) { - self.playSound(soundFile: file) - } -} diff --git a/Spring/Spring.h b/Spring/Spring.h deleted file mode 100644 index 1a11dfe..0000000 --- a/Spring/Spring.h +++ /dev/null @@ -1,19 +0,0 @@ -// -// Spring.h -// Spring -// -// Created by James Tang on 20/1/15. -// Copyright (c) 2015 Meng To. All rights reserved. -// - -#import - -//! Project version number for Spring. -FOUNDATION_EXPORT double SpringVersionNumber; - -//! Project version string for Spring. -FOUNDATION_EXPORT const unsigned char SpringVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/Spring/Spring.swift b/Spring/Spring.swift deleted file mode 100644 index c74c0af..0000000 --- a/Spring/Spring.swift +++ /dev/null @@ -1,643 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -public protocol Springable: AnyObject { - var autostart: Bool { get set } - var autohide: Bool { get set } - var animation: String { get set } - var force: CGFloat { get set } - var delay: CGFloat { get set } - var duration: CGFloat { get set } - var damping: CGFloat { get set } - var velocity: CGFloat { get set } - var repeatCount: Float { get set } - var x: CGFloat { get set } - var y: CGFloat { get set } - var scaleX: CGFloat { get set } - var scaleY: CGFloat { get set } - var rotate: CGFloat { get set } - var opacity: CGFloat { get set } - var animateFrom: Bool { get set } - var curve: String { get set } - - // UIView - var layer : CALayer { get } - var transform : CGAffineTransform { get set } - var alpha : CGFloat { get set } - - func animate() - func animateNext(completion: @escaping () -> ()) - func animateTo() - func animateToNext(completion: @escaping () -> ()) -} - -public class Spring : NSObject { - - private unowned var view: Springable - private var shouldAnimateAfterActive = false - private var shouldAnimateInLayoutSubviews = true - - private var autostart: Bool { - set { - view.autostart = newValue - } get { - view.autostart - } - } - private var autohide: Bool { - set { - view.autohide = newValue - } get { - view.autohide - } - } - private var animation: String { - set { - view.animation = newValue - } get { - view.animation - } - } - private var force: CGFloat { - set { - view.force = newValue - } get { - view.force - } - } - private var delay: CGFloat { - set { - view.delay = newValue - } get { - view.delay - - } - } - private var duration: CGFloat { - set { - view.duration = newValue - } get { - view.duration - } - } - private var damping: CGFloat { - set { - view.damping = newValue - } get { - view.damping - } - } - private var velocity: CGFloat { - set { - view.velocity = newValue - } get { - view.velocity - } - } - private var repeatCount: Float { - set { - view.repeatCount = newValue - } get { - view.repeatCount - } - } - private var x: CGFloat { - set { - view.x = newValue - } get { - view.x - } - } - private var y: CGFloat { - set { - view.y = newValue - } get { - view.y - } - } - private var scaleX: CGFloat { - set { - view.scaleX = newValue - } get { - view.scaleX - } - } - private var scaleY: CGFloat { - set { - view.scaleY = newValue - } get { - view.scaleY - } - } - - private var rotate: CGFloat { - set { - view.rotate = newValue - } get { - view.rotate - } - } - private var opacity: CGFloat { - set { - view.opacity = newValue - } get { - view.opacity - } - } - private var animateFrom: Bool { - set { - view.animateFrom = newValue - } get { - view.animateFrom - } - } - private var curve: String { - set { - view.curve = newValue - } get { - view.curve - } - } - - // UIView - private var layer : CALayer { return view.layer } - private var transform : CGAffineTransform { get { return view.transform } set { view.transform = newValue }} - private var alpha: CGFloat { get { return view.alpha } set { view.alpha = newValue } } - - init(_ view: Springable) { - self.view = view - super.init() - commonInit() - } - - private func commonInit() { - NotificationCenter.default.addObserver( - self, - selector: #selector(didBecomeActiveNotification), - name: UIApplication.didBecomeActiveNotification, - object: nil - ) - } - - @objc private func didBecomeActiveNotification(_ notification: NSNotification) { - if shouldAnimateAfterActive { - alpha = 0 - animate() - shouldAnimateAfterActive = false - } - } - - deinit { - NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil) - } - - func animatePreset() { - alpha = 0.99 - if let animation = AnimationPreset(rawValue: animation) { - switch animation { - case .slideLeft: - x = 300*force - case .slideRight: - x = -300*force - case .slideDown: - y = -300*force - case .slideUp: - y = 300*force - case .squeezeLeft: - x = 300 - scaleX = 3*force - case .squeezeRight: - x = -300 - scaleX = 3*force - case .squeezeDown: - y = -300 - scaleY = 3*force - case .squeezeUp: - y = 300 - scaleY = 3*force - case .fadeIn: - opacity = 0 - case .fadeOut: - animateFrom = false - opacity = 0 - case .fadeOutIn: - let animation = CABasicAnimation() - animation.keyPath = "opacity" - animation.fromValue = 1 - animation.toValue = 0 - animation.timingFunction = getTimingFunction(curve: curve) - animation.duration = CFTimeInterval(duration) - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - animation.autoreverses = true - layer.add(animation, forKey: "fade") - case .fadeInLeft: - opacity = 0 - x = 300*force - case .fadeInRight: - x = -300*force - opacity = 0 - case .fadeInDown: - y = -300*force - opacity = 0 - case .fadeInUp: - y = 300*force - opacity = 0 - case .zoomIn: - opacity = 0 - scaleX = 2*force - scaleY = 2*force - case .zoomOut: - animateFrom = false - opacity = 0 - scaleX = 2*force - scaleY = 2*force - case .fall: - animateFrom = false - rotate = 15 * CGFloat(CGFloat.pi/180) - y = 600*force - case .shake: - let animation = CAKeyframeAnimation() - animation.keyPath = "position.x" - animation.values = [0, 30*force, -30*force, 30*force, 0] - animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - animation.timingFunction = getTimingFunction(curve: curve) - animation.duration = CFTimeInterval(duration) - animation.isAdditive = true - animation.repeatCount = repeatCount - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.add(animation, forKey: "shake") - case .pop: - let animation = CAKeyframeAnimation() - animation.keyPath = "transform.scale" - animation.values = [0, 0.2*force, -0.2*force, 0.2*force, 0] - animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - animation.timingFunction = getTimingFunction(curve: curve) - animation.duration = CFTimeInterval(duration) - animation.isAdditive = true - animation.repeatCount = repeatCount - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.add(animation, forKey: "pop") - case .flipX: - rotate = 0 - scaleX = 1 - scaleY = 1 - var perspective = CATransform3DIdentity - perspective.m34 = -1.0 / layer.frame.size.width/2 - - let animation = CABasicAnimation() - animation.keyPath = "transform" - animation.fromValue = NSValue(caTransform3D: CATransform3DMakeRotation(0, 0, 0, 0)) - animation.toValue = NSValue(caTransform3D: - CATransform3DConcat(perspective, CATransform3DMakeRotation(CGFloat(CGFloat.pi), 0, 1, 0))) - animation.duration = CFTimeInterval(duration) - animation.repeatCount = repeatCount - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - animation.timingFunction = getTimingFunction(curve: curve) - layer.add(animation, forKey: "3d") - case .flipY: - var perspective = CATransform3DIdentity - perspective.m34 = -1.0 / layer.frame.size.width/2 - - let animation = CABasicAnimation() - animation.keyPath = "transform" - animation.fromValue = NSValue(caTransform3D: - CATransform3DMakeRotation(0, 0, 0, 0)) - animation.toValue = NSValue(caTransform3D: - CATransform3DConcat(perspective,CATransform3DMakeRotation(CGFloat(CGFloat.pi), 1, 0, 0))) - animation.duration = CFTimeInterval(duration) - animation.repeatCount = repeatCount - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - animation.timingFunction = getTimingFunction(curve: curve) - layer.add(animation, forKey: "3d") - case .morph: - let morphX = CAKeyframeAnimation() - morphX.keyPath = "transform.scale.x" - morphX.values = [1, 1.3*force, 0.7, 1.3*force, 1] - morphX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - morphX.timingFunction = getTimingFunction(curve: curve) - morphX.duration = CFTimeInterval(duration) - morphX.repeatCount = repeatCount - morphX.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.add(morphX, forKey: "morphX") - - let morphY = CAKeyframeAnimation() - morphY.keyPath = "transform.scale.y" - morphY.values = [1, 0.7, 1.3*force, 0.7, 1] - morphY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - morphY.timingFunction = getTimingFunction(curve: curve) - morphY.duration = CFTimeInterval(duration) - morphY.repeatCount = repeatCount - morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.add(morphY, forKey: "morphY") - case .squeeze: - let morphX = CAKeyframeAnimation() - morphX.keyPath = "transform.scale.x" - morphX.values = [1, 1.5*force, 0.5, 1.5*force, 1] - morphX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - morphX.timingFunction = getTimingFunction(curve: curve) - morphX.duration = CFTimeInterval(duration) - morphX.repeatCount = repeatCount - morphX.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.add(morphX, forKey: "morphX") - - let morphY = CAKeyframeAnimation() - morphY.keyPath = "transform.scale.y" - morphY.values = [1, 0.5, 1, 0.5, 1] - morphY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - morphY.timingFunction = getTimingFunction(curve: curve) - morphY.duration = CFTimeInterval(duration) - morphY.repeatCount = repeatCount - morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.add(morphY, forKey: "morphY") - case .flash: - let animation = CABasicAnimation() - animation.keyPath = "opacity" - animation.fromValue = 1 - animation.toValue = 0 - animation.duration = CFTimeInterval(duration) - animation.repeatCount = repeatCount * 2.0 - animation.autoreverses = true - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.add(animation, forKey: "flash") - case .wobble: - let animation = CAKeyframeAnimation() - animation.keyPath = "transform.rotation" - animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] - animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - animation.duration = CFTimeInterval(duration) - animation.isAdditive = true - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.add(animation, forKey: "wobble") - - let x = CAKeyframeAnimation() - x.keyPath = "position.x" - x.values = [0, 30*force, -30*force, 30*force, 0] - x.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - x.timingFunction = getTimingFunction(curve: curve) - x.duration = CFTimeInterval(duration) - x.isAdditive = true - x.repeatCount = repeatCount - x.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.add(x, forKey: "x") - case .swing: - let animation = CAKeyframeAnimation() - animation.keyPath = "transform.rotation" - animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] - animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - animation.duration = CFTimeInterval(duration) - animation.isAdditive = true - animation.repeatCount = repeatCount - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.add(animation, forKey: "swing") - } - } - } - - func getTimingFunction(curve: String) -> CAMediaTimingFunction { - if let curve = AnimationCurve(rawValue: curve) { - switch curve { - case .easeIn: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn) - case .easeOut: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut) - case .easeInOut: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) - case .linear: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear) - case .spring: return CAMediaTimingFunction(controlPoints: 0.5, 1.1+Float(force/3), 1, 1) - case .easeInSine: return CAMediaTimingFunction(controlPoints: 0.47, 0, 0.745, 0.715) - case .easeOutSine: return CAMediaTimingFunction(controlPoints: 0.39, 0.575, 0.565, 1) - case .easeInOutSine: return CAMediaTimingFunction(controlPoints: 0.445, 0.05, 0.55, 0.95) - case .easeInQuad: return CAMediaTimingFunction(controlPoints: 0.55, 0.085, 0.68, 0.53) - case .easeOutQuad: return CAMediaTimingFunction(controlPoints: 0.25, 0.46, 0.45, 0.94) - case .easeInOutQuad: return CAMediaTimingFunction(controlPoints: 0.455, 0.03, 0.515, 0.955) - case .easeInCubic: return CAMediaTimingFunction(controlPoints: 0.55, 0.055, 0.675, 0.19) - case .easeOutCubic: return CAMediaTimingFunction(controlPoints: 0.215, 0.61, 0.355, 1) - case .easeInOutCubic: return CAMediaTimingFunction(controlPoints: 0.645, 0.045, 0.355, 1) - case .easeInQuart: return CAMediaTimingFunction(controlPoints: 0.895, 0.03, 0.685, 0.22) - case .easeOutQuart: return CAMediaTimingFunction(controlPoints: 0.165, 0.84, 0.44, 1) - case .easeInOutQuart: return CAMediaTimingFunction(controlPoints: 0.77, 0, 0.175, 1) - case .easeInQuint: return CAMediaTimingFunction(controlPoints: 0.755, 0.05, 0.855, 0.06) - case .easeOutQuint: return CAMediaTimingFunction(controlPoints: 0.23, 1, 0.32, 1) - case .easeInOutQuint: return CAMediaTimingFunction(controlPoints: 0.86, 0, 0.07, 1) - case .easeInExpo: return CAMediaTimingFunction(controlPoints: 0.95, 0.05, 0.795, 0.035) - case .easeOutExpo: return CAMediaTimingFunction(controlPoints: 0.19, 1, 0.22, 1) - case .easeInOutExpo: return CAMediaTimingFunction(controlPoints: 1, 0, 0, 1) - case .easeInCirc: return CAMediaTimingFunction(controlPoints: 0.6, 0.04, 0.98, 0.335) - case .easeOutCirc: return CAMediaTimingFunction(controlPoints: 0.075, 0.82, 0.165, 1) - case .easeInOutCirc: return CAMediaTimingFunction(controlPoints: 0.785, 0.135, 0.15, 0.86) - case .easeInBack: return CAMediaTimingFunction(controlPoints: 0.6, -0.28, 0.735, 0.045) - case .easeOutBack: return CAMediaTimingFunction(controlPoints: 0.175, 0.885, 0.32, 1.275) - case .easeInOutBack: return CAMediaTimingFunction(controlPoints: 0.68, -0.55, 0.265, 1.55) - } - } - return CAMediaTimingFunction(name: CAMediaTimingFunctionName.default) - } - - func getAnimationOptions(curve: String) -> UIView.AnimationOptions { - if let curve = AnimationCurve(rawValue: curve) { - switch curve { - case .easeIn: return UIView.AnimationOptions.curveEaseIn - case .easeOut: return UIView.AnimationOptions.curveEaseOut - case .easeInOut: return UIView.AnimationOptions() - default: break - } - } - return UIView.AnimationOptions.curveLinear - } - - public func animate() { - animateFrom = true - animatePreset() - setView {} - } - - public func animateNext(completion: @escaping () -> ()) { - animateFrom = true - animatePreset() - setView { - completion() - } - } - - public func animateTo() { - animateFrom = false - animatePreset() - setView {} - } - - public func animateToNext(completion: @escaping () -> ()) { - animateFrom = false - animatePreset() - setView { - completion() - } - } - - public func customAwakeFromNib() { - if autohide { - alpha = 0 - } - } - - public func customLayoutSubviews() { - if shouldAnimateInLayoutSubviews { - shouldAnimateInLayoutSubviews = false - if autostart { - if UIApplication.shared.applicationState != .active { - shouldAnimateAfterActive = true - return - } - alpha = 0 - animate() - } - } - } - - func setView(completion: @escaping () -> ()) { - if animateFrom { - let translate = CGAffineTransform(translationX: self.x, y: self.y) - let scale = CGAffineTransform(scaleX: self.scaleX, y: self.scaleY) - let rotate = CGAffineTransform(rotationAngle: self.rotate) - let translateAndScale = translate.concatenating(scale) - self.transform = rotate.concatenating(translateAndScale) - - self.alpha = self.opacity - } - - UIView.animate( withDuration: TimeInterval(duration), - delay: TimeInterval(delay), - usingSpringWithDamping: damping, - initialSpringVelocity: velocity, - options: [getAnimationOptions(curve: curve), UIView.AnimationOptions.allowUserInteraction], - animations: { [weak self] in - if let _self = self - { - if _self.animateFrom { - _self.transform = CGAffineTransform.identity - _self.alpha = 1 - } - else { - let translate = CGAffineTransform(translationX: _self.x, y: _self.y) - let scale = CGAffineTransform(scaleX: _self.scaleX, y: _self.scaleY) - let rotate = CGAffineTransform(rotationAngle: _self.rotate) - let translateAndScale = translate.concatenating(scale) - _self.transform = rotate.concatenating(translateAndScale) - - _self.alpha = _self.opacity - } - - } - - }, completion: { [weak self] finished in - - completion() - self?.resetAll() - - }) - - } - - func reset() { - x = 0 - y = 0 - opacity = 1 - } - - func resetAll() { - x = 0 - y = 0 - animation = "" - opacity = 1 - scaleX = 1 - scaleY = 1 - rotate = 0 - damping = 0.7 - velocity = 0.7 - repeatCount = 1 - delay = 0 - duration = 0.7 - } - -} - -extension Spring { - public enum AnimationPreset: String, CaseIterable { - case slideLeft - case slideRight - case slideDown - case slideUp - case squeezeLeft - case squeezeRight - case squeezeDown - case squeezeUp - case fadeIn - case fadeOut - case fadeOutIn - case fadeInLeft - case fadeInRight - case fadeInDown - case fadeInUp - case zoomIn - case zoomOut - case fall - case shake - case pop - case flipX - case flipY - case morph - case squeeze - case flash - case wobble - case swing - } - - public enum AnimationCurve: String, CaseIterable { - case easeIn - case easeOut - case easeInOut - case linear - case spring - case easeInSine - case easeOutSine - case easeInOutSine - case easeInQuad - case easeOutQuad - case easeInOutQuad - case easeInCubic - case easeOutCubic - case easeInOutCubic - case easeInQuart - case easeOutQuart - case easeInOutQuart - case easeInQuint - case easeOutQuint - case easeInOutQuint - case easeInExpo - case easeOutExpo - case easeInOutExpo - case easeInCirc - case easeOutCirc - case easeInOutCirc - case easeInBack - case easeOutBack - case easeInOutBack - } -} diff --git a/Spring/SpringAnimation.swift b/Spring/SpringAnimation.swift deleted file mode 100644 index 998882b..0000000 --- a/Spring/SpringAnimation.swift +++ /dev/null @@ -1,112 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -@objc public class SpringAnimation: NSObject { - public class func spring(duration: TimeInterval, animations: @escaping () -> Void) { - UIView.animate( - withDuration: duration, - delay: 0, - usingSpringWithDamping: 0.7, - initialSpringVelocity: 0.7, - options: [], - animations: { - animations() - }, - completion: nil - ) - } - - public class func springEaseIn(duration: TimeInterval, animations: (() -> Void)!) { - UIView.animate( - withDuration: duration, - delay: 0, - options: .curveEaseIn, - animations: { - animations() - }, - completion: nil - ) - } - - public class func springEaseOut(duration: TimeInterval, animations: (() -> Void)!) { - UIView.animate( - withDuration: duration, - delay: 0, - options: .curveEaseOut, - animations: { - animations() - }, completion: nil - ) - } - - public class func springEaseInOut(duration: TimeInterval, animations: (() -> Void)!) { - UIView.animate( - withDuration: duration, - delay: 0, - options: UIView.AnimationOptions(), - animations: { - animations() - }, completion: nil - ) - } - - public class func springLinear(duration: TimeInterval, animations: (() -> Void)!) { - UIView.animate( - withDuration: duration, - delay: 0, - options: .curveLinear, - animations: { - animations() - }, completion: nil - ) - } - - public class func springWithDelay(duration: TimeInterval, delay: TimeInterval, animations: (() -> Void)!) { - UIView.animate( - withDuration: duration, - delay: delay, - usingSpringWithDamping: 0.7, - initialSpringVelocity: 0.7, - options: [], - animations: { - animations() - }, completion: nil - ) - } - - public class func springWithCompletion(duration: TimeInterval, animations: (() -> Void)!, completion: ((Bool) -> Void)!) { - UIView.animate( - withDuration: duration, - delay: 0, - usingSpringWithDamping: 0.7, - initialSpringVelocity: 0.7, - options: [], - animations: { - animations() - }, completion: { finished in - completion(finished) - } - ) - } -} diff --git a/Spring/SpringButton.swift b/Spring/SpringButton.swift deleted file mode 100644 index 92124ea..0000000 --- a/Spring/SpringButton.swift +++ /dev/null @@ -1,71 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -open class SpringButton: UIButton, Springable { - @IBInspectable public var autostart: Bool = false - @IBInspectable public var autohide: Bool = false - @IBInspectable public var animation: String = "" - @IBInspectable public var force: CGFloat = 1 - @IBInspectable public var delay: CGFloat = 0 - @IBInspectable public var duration: CGFloat = 0.7 - @IBInspectable public var damping: CGFloat = 0.7 - @IBInspectable public var velocity: CGFloat = 0.7 - @IBInspectable public var repeatCount: Float = 1 - @IBInspectable public var x: CGFloat = 0 - @IBInspectable public var y: CGFloat = 0 - @IBInspectable public var scaleX: CGFloat = 1 - @IBInspectable public var scaleY: CGFloat = 1 - @IBInspectable public var rotate: CGFloat = 0 - @IBInspectable public var curve: String = "" - public var opacity: CGFloat = 1 - public var animateFrom: Bool = false - - lazy private var spring : Spring = Spring(self) - - override open func awakeFromNib() { - super.awakeFromNib() - self.spring.customAwakeFromNib() - } - - open override func layoutSubviews() { - super.layoutSubviews() - spring.customLayoutSubviews() - } - - public func animate() { - self.spring.animate() - } - - public func animateNext(completion: @escaping () -> ()) { - self.spring.animateNext(completion: completion) - } - - public func animateTo() { - self.spring.animateTo() - } - - public func animateToNext(completion: @escaping () -> ()) { - self.spring.animateToNext(completion: completion) - } -} diff --git a/Spring/SpringImageView.swift b/Spring/SpringImageView.swift deleted file mode 100644 index 85ad61f..0000000 --- a/Spring/SpringImageView.swift +++ /dev/null @@ -1,72 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -open class SpringImageView: UIImageView, Springable { - @IBInspectable public var autostart: Bool = false - @IBInspectable public var autohide: Bool = false - @IBInspectable public var animation: String = "" - @IBInspectable public var force: CGFloat = 1 - @IBInspectable public var delay: CGFloat = 0 - @IBInspectable public var duration: CGFloat = 0.7 - @IBInspectable public var damping: CGFloat = 0.7 - @IBInspectable public var velocity: CGFloat = 0.7 - @IBInspectable public var repeatCount: Float = 1 - @IBInspectable public var x: CGFloat = 0 - @IBInspectable public var y: CGFloat = 0 - @IBInspectable public var scaleX: CGFloat = 1 - @IBInspectable public var scaleY: CGFloat = 1 - @IBInspectable public var rotate: CGFloat = 0 - @IBInspectable public var curve: String = "" - public var opacity: CGFloat = 1 - public var animateFrom: Bool = false - - lazy private var spring : Spring = Spring(self) - - override open func awakeFromNib() { - super.awakeFromNib() - self.spring.customAwakeFromNib() - } - - open override func layoutSubviews() { - super.layoutSubviews() - spring.customLayoutSubviews() - } - - public func animate() { - self.spring.animate() - } - - public func animateNext(completion: @escaping () -> ()) { - self.spring.animateNext(completion: completion) - } - - public func animateTo() { - self.spring.animateTo() - } - - public func animateToNext(completion: @escaping () -> ()) { - self.spring.animateToNext(completion: completion) - } - -} diff --git a/Spring/SpringLabel.swift b/Spring/SpringLabel.swift deleted file mode 100644 index c105a48..0000000 --- a/Spring/SpringLabel.swift +++ /dev/null @@ -1,72 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -open class SpringLabel: UILabel, Springable { - @IBInspectable public var autostart: Bool = false - @IBInspectable public var autohide: Bool = false - @IBInspectable public var animation: String = "" - @IBInspectable public var force: CGFloat = 1 - @IBInspectable public var delay: CGFloat = 0 - @IBInspectable public var duration: CGFloat = 0.7 - @IBInspectable public var damping: CGFloat = 0.7 - @IBInspectable public var velocity: CGFloat = 0.7 - @IBInspectable public var repeatCount: Float = 1 - @IBInspectable public var x: CGFloat = 0 - @IBInspectable public var y: CGFloat = 0 - @IBInspectable public var scaleX: CGFloat = 1 - @IBInspectable public var scaleY: CGFloat = 1 - @IBInspectable public var rotate: CGFloat = 0 - @IBInspectable public var curve: String = "" - public var opacity: CGFloat = 1 - public var animateFrom: Bool = false - - lazy private var spring : Spring = Spring(self) - - override open func awakeFromNib() { - super.awakeFromNib() - self.spring.customAwakeFromNib() - } - - open override func layoutSubviews() { - super.layoutSubviews() - spring.customLayoutSubviews() - } - - public func animate() { - self.spring.animate() - } - - public func animateNext(completion: @escaping () -> ()) { - self.spring.animateNext(completion: completion) - } - - public func animateTo() { - self.spring.animateTo() - } - - public func animateToNext(completion: @escaping () -> ()) { - self.spring.animateToNext(completion: completion) - } - -} diff --git a/Spring/SpringTextField.swift b/Spring/SpringTextField.swift deleted file mode 100644 index 966b6f7..0000000 --- a/Spring/SpringTextField.swift +++ /dev/null @@ -1,71 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -open class SpringTextField: UITextField, Springable { - @IBInspectable public var autostart: Bool = false - @IBInspectable public var autohide: Bool = false - @IBInspectable public var animation: String = "" - @IBInspectable public var force: CGFloat = 1 - @IBInspectable public var delay: CGFloat = 0 - @IBInspectable public var duration: CGFloat = 0.7 - @IBInspectable public var damping: CGFloat = 0.7 - @IBInspectable public var velocity: CGFloat = 0.7 - @IBInspectable public var repeatCount: Float = 1 - @IBInspectable public var x: CGFloat = 0 - @IBInspectable public var y: CGFloat = 0 - @IBInspectable public var scaleX: CGFloat = 1 - @IBInspectable public var scaleY: CGFloat = 1 - @IBInspectable public var rotate: CGFloat = 0 - @IBInspectable public var curve: String = "" - public var opacity: CGFloat = 1 - public var animateFrom: Bool = false - - lazy private var spring : Spring = Spring(self) - - override open func awakeFromNib() { - super.awakeFromNib() - self.spring.customAwakeFromNib() - } - - open override func layoutSubviews() { - super.layoutSubviews() - spring.customLayoutSubviews() - } - - public func animate() { - self.spring.animate() - } - - public func animateNext(completion: @escaping () -> ()) { - self.spring.animateNext(completion: completion) - } - - public func animateTo() { - self.spring.animateTo() - } - - public func animateToNext(completion: @escaping () -> ()) { - self.spring.animateToNext(completion: completion) - } -} diff --git a/Spring/SpringTextView.swift b/Spring/SpringTextView.swift deleted file mode 100644 index 55d4e4a..0000000 --- a/Spring/SpringTextView.swift +++ /dev/null @@ -1,72 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -open class SpringTextView: UITextView, Springable { - @IBInspectable public var autostart: Bool = false - @IBInspectable public var autohide: Bool = false - @IBInspectable public var animation: String = "" - @IBInspectable public var force: CGFloat = 1 - @IBInspectable public var delay: CGFloat = 0 - @IBInspectable public var duration: CGFloat = 0.7 - @IBInspectable public var damping: CGFloat = 0.7 - @IBInspectable public var velocity: CGFloat = 0.7 - @IBInspectable public var repeatCount: Float = 1 - @IBInspectable public var x: CGFloat = 0 - @IBInspectable public var y: CGFloat = 0 - @IBInspectable public var scaleX: CGFloat = 1 - @IBInspectable public var scaleY: CGFloat = 1 - @IBInspectable public var rotate: CGFloat = 0 - @IBInspectable public var curve: String = "" - public var opacity: CGFloat = 1 - public var animateFrom: Bool = false - - lazy private var spring : Spring = Spring(self) - - override open func awakeFromNib() { - super.awakeFromNib() - self.spring.customAwakeFromNib() - } - - open override func layoutSubviews() { - super.layoutSubviews() - spring.customLayoutSubviews() - } - - public func animate() { - self.spring.animate() - } - - public func animateNext(completion: @escaping () -> ()) { - self.spring.animateNext(completion: completion) - } - - public func animateTo() { - self.spring.animateTo() - } - - public func animateToNext(completion: @escaping () -> ()) { - self.spring.animateToNext(completion: completion) - } - -} diff --git a/Spring/SpringView.swift b/Spring/SpringView.swift deleted file mode 100644 index a00c12a..0000000 --- a/Spring/SpringView.swift +++ /dev/null @@ -1,71 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -open class SpringView: UIView, Springable { - @IBInspectable public var autostart: Bool = false - @IBInspectable public var autohide: Bool = false - @IBInspectable public var animation: String = "" - @IBInspectable public var force: CGFloat = 1 - @IBInspectable public var delay: CGFloat = 0 - @IBInspectable public var duration: CGFloat = 0.7 - @IBInspectable public var damping: CGFloat = 0.7 - @IBInspectable public var velocity: CGFloat = 0.7 - @IBInspectable public var repeatCount: Float = 1 - @IBInspectable public var x: CGFloat = 0 - @IBInspectable public var y: CGFloat = 0 - @IBInspectable public var scaleX: CGFloat = 1 - @IBInspectable public var scaleY: CGFloat = 1 - @IBInspectable public var rotate: CGFloat = 0 - @IBInspectable public var curve: String = "" - public var opacity: CGFloat = 1 - public var animateFrom: Bool = false - - lazy private var spring : Spring = Spring(self) - - override open func awakeFromNib() { - super.awakeFromNib() - self.spring.customAwakeFromNib() - } - - open override func layoutSubviews() { - super.layoutSubviews() - spring.customLayoutSubviews() - } - - public func animate() { - self.spring.animate() - } - - public func animateNext(completion: @escaping () -> ()) { - self.spring.animateNext(completion: completion) - } - - public func animateTo() { - self.spring.animateTo() - } - - public func animateToNext(completion: @escaping () -> ()) { - self.spring.animateToNext(completion: completion) - } -} diff --git a/Spring/TransitionManager.swift b/Spring/TransitionManager.swift deleted file mode 100644 index 388edac..0000000 --- a/Spring/TransitionManager.swift +++ /dev/null @@ -1,86 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -public class TransitionManager: NSObject, UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning { - - var isPresenting = true - var duration = 0.3 - - public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { - let container = transitionContext.containerView - let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)! - let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)! - - if isPresenting { - toView.frame = container.bounds - toView.transform = CGAffineTransform(translationX: 0, y: container.frame.size.height) - container.addSubview(fromView) - container.addSubview(toView) - SpringAnimation.springEaseInOut(duration: duration) { - fromView.transform = CGAffineTransform(scaleX: 0.8, y: 0.8) - fromView.alpha = 0.5 - toView.transform = CGAffineTransform.identity - } - } - else { - - // 1. Rotating will change the bounds - // 2. we have to properly reset toView - // to the actual container's bounds, at - // the same time take consideration of - // previous transformation when presenting - let transform = toView.transform - toView.transform = CGAffineTransform.identity - toView.frame = container.bounds - toView.transform = transform - - container.addSubview(toView) - container.addSubview(fromView) - - SpringAnimation.springEaseInOut(duration: duration) { - fromView.transform = CGAffineTransform(translationX: 0, y: fromView.frame.size.height) - toView.transform = CGAffineTransform.identity - toView.alpha = 1 - } - } - - delay(delay: duration, closure: { - transitionContext.completeTransition(true) - }) - } - - public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { - return duration - } - - public func animationController(forPresentedController presented: UIViewController, presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { - isPresenting = true - return self - } - - public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { - isPresenting = false - return self - } -} diff --git a/Spring/TransitionZoom.swift b/Spring/TransitionZoom.swift deleted file mode 100644 index 6cf5301..0000000 --- a/Spring/TransitionZoom.swift +++ /dev/null @@ -1,79 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -public class TransitionZoom: NSObject, UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning { - - var isPresenting = true - var duration = 0.4 - - public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { - let container = transitionContext.containerView - let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)! - let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)! - - if isPresenting { - container.addSubview(fromView) - container.addSubview(toView) - - toView.alpha = 0 - toView.transform = CGAffineTransform(scaleX: 2, y: 2) - - SpringAnimation.springEaseInOut(duration: duration) { - fromView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5) - fromView.alpha = 0 - toView.transform = CGAffineTransform.identity - toView.alpha = 1 - } - } - else { - container.addSubview(toView) - container.addSubview(fromView) - - SpringAnimation.springEaseInOut(duration: duration) { - fromView.transform = CGAffineTransform(scaleX: 2, y: 2) - fromView.alpha = 0 - toView.transform = CGAffineTransform(scaleX: 1, y: 1) - toView.alpha = 1 - } - } - - delay(delay: duration, closure: { - transitionContext.completeTransition(true) - }) - } - - public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { - return duration - } - - public func animationController(forPresentedController presented: UIViewController, presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { - isPresenting = true - return self - } - - public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { - isPresenting = false - return self - } -} diff --git a/Spring/UnwindSegue.swift b/Spring/UnwindSegue.swift deleted file mode 100644 index 2080094..0000000 --- a/Spring/UnwindSegue.swift +++ /dev/null @@ -1,27 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015 Meng To (meng@designcode.io) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -import UIKit - -public extension UIViewController { - @IBAction func unwindToViewController (_ segue: UIStoryboardSegue){} -} From 56da74db2ec99a0bd064b461836d849433de7610 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 12 Apr 2022 15:19:56 +0300 Subject: [PATCH 19/21] Create platform targer --- Package.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Package.swift b/Package.swift index 96d13f5..89e8c20 100644 --- a/Package.swift +++ b/Package.swift @@ -5,6 +5,7 @@ import PackageDescription let package = Package( name: "Spring", + platforms: [.iOS(.v14)], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( From c5a47fc4cd9d97f7bf4de3cb3d8d7a8caa9e36c6 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 12 Apr 2022 15:22:56 +0300 Subject: [PATCH 20/21] Delete SPM --- Package.swift | 29 ------------------- Spring.podspec | 4 +-- {Sources/Spring => Spring}/AsyncButton.swift | 0 .../Spring => Spring}/AsyncImageView.swift | 0 {Sources/Spring => Spring}/AutoTextView.swift | 0 {Sources/Spring => Spring}/BlurView.swift | 0 .../Spring => Spring}/DesignableButton.swift | 0 .../DesignableImageView.swift | 0 .../Spring => Spring}/DesignableLabel.swift | 0 .../DesignableTabBarController.swift | 0 .../DesignableTextField.swift | 0 .../DesignableTextView.swift | 0 .../Spring => Spring}/DesignableView.swift | 0 {Sources/Spring => Spring}/ImageLoader.swift | 0 {Sources/Spring => Spring}/Info.plist | 0 .../KeyboardLayoutConstraint.swift | 0 {Sources/Spring => Spring}/LoadingView.swift | 0 {Sources/Spring => Spring}/LoadingView.xib | 0 {Sources/Spring => Spring}/Misc.swift | 0 {Sources/Spring => Spring}/SoundPlayer.swift | 0 {Sources/Spring => Spring}/Spring.h | 0 {Sources/Spring => Spring}/Spring.swift | 0 .../Spring => Spring}/SpringAnimation.swift | 0 {Sources/Spring => Spring}/SpringButton.swift | 0 .../Spring => Spring}/SpringImageView.swift | 0 {Sources/Spring => Spring}/SpringLabel.swift | 0 .../Spring => Spring}/SpringTextField.swift | 0 .../Spring => Spring}/SpringTextView.swift | 0 {Sources/Spring => Spring}/SpringView.swift | 0 .../Spring => Spring}/TransitionManager.swift | 0 .../Spring => Spring}/TransitionZoom.swift | 0 {Sources/Spring => Spring}/UnwindSegue.swift | 0 Tests/SpringTests/SpringTests.swift | 11 ------- 33 files changed, 2 insertions(+), 42 deletions(-) delete mode 100644 Package.swift rename {Sources/Spring => Spring}/AsyncButton.swift (100%) rename {Sources/Spring => Spring}/AsyncImageView.swift (100%) rename {Sources/Spring => Spring}/AutoTextView.swift (100%) rename {Sources/Spring => Spring}/BlurView.swift (100%) rename {Sources/Spring => Spring}/DesignableButton.swift (100%) rename {Sources/Spring => Spring}/DesignableImageView.swift (100%) rename {Sources/Spring => Spring}/DesignableLabel.swift (100%) rename {Sources/Spring => Spring}/DesignableTabBarController.swift (100%) rename {Sources/Spring => Spring}/DesignableTextField.swift (100%) rename {Sources/Spring => Spring}/DesignableTextView.swift (100%) rename {Sources/Spring => Spring}/DesignableView.swift (100%) rename {Sources/Spring => Spring}/ImageLoader.swift (100%) rename {Sources/Spring => Spring}/Info.plist (100%) rename {Sources/Spring => Spring}/KeyboardLayoutConstraint.swift (100%) rename {Sources/Spring => Spring}/LoadingView.swift (100%) rename {Sources/Spring => Spring}/LoadingView.xib (100%) rename {Sources/Spring => Spring}/Misc.swift (100%) rename {Sources/Spring => Spring}/SoundPlayer.swift (100%) rename {Sources/Spring => Spring}/Spring.h (100%) rename {Sources/Spring => Spring}/Spring.swift (100%) rename {Sources/Spring => Spring}/SpringAnimation.swift (100%) rename {Sources/Spring => Spring}/SpringButton.swift (100%) rename {Sources/Spring => Spring}/SpringImageView.swift (100%) rename {Sources/Spring => Spring}/SpringLabel.swift (100%) rename {Sources/Spring => Spring}/SpringTextField.swift (100%) rename {Sources/Spring => Spring}/SpringTextView.swift (100%) rename {Sources/Spring => Spring}/SpringView.swift (100%) rename {Sources/Spring => Spring}/TransitionManager.swift (100%) rename {Sources/Spring => Spring}/TransitionZoom.swift (100%) rename {Sources/Spring => Spring}/UnwindSegue.swift (100%) delete mode 100644 Tests/SpringTests/SpringTests.swift diff --git a/Package.swift b/Package.swift deleted file mode 100644 index 89e8c20..0000000 --- a/Package.swift +++ /dev/null @@ -1,29 +0,0 @@ -// swift-tools-version: 5.6 -// The swift-tools-version declares the minimum version of Swift required to build this package. - -import PackageDescription - -let package = Package( - name: "Spring", - platforms: [.iOS(.v14)], - products: [ - // Products define the executables and libraries a package produces, and make them visible to other packages. - .library( - name: "Spring", - targets: ["Spring"]), - ], - dependencies: [ - // Dependencies declare other packages that this package depends on. - // .package(url: /* package url */, from: "1.0.0"), - ], - targets: [ - // Targets are the basic building blocks of a package. A target can define a module or a test suite. - // Targets can depend on other targets in this package, and on products in packages this package depends on. - .target( - name: "Spring", - dependencies: []), - .testTarget( - name: "SpringTests", - dependencies: ["Spring"]), - ] -) diff --git a/Spring.podspec b/Spring.podspec index 04f48f8..d1a28e6 100644 --- a/Spring.podspec +++ b/Spring.podspec @@ -9,7 +9,7 @@ Pod::Spec.new do |s| s.requires_arc = true s.ios.deployment_target = '14.0' s.tvos.deployment_target = '11.0' - s.source_files = 'Sources/Spring/*.swift' - s.ios.resources = ['Sources/Spring/*.xib', 'SpringApp/*.xcassets'] + s.source_files = 'Spring/*.swift' + s.ios.resources = ['Spring/*.xib', 'SpringApp/*.xcassets'] s.tvos.resources = ['SpringApp/*.xcassets'] end diff --git a/Sources/Spring/AsyncButton.swift b/Spring/AsyncButton.swift similarity index 100% rename from Sources/Spring/AsyncButton.swift rename to Spring/AsyncButton.swift diff --git a/Sources/Spring/AsyncImageView.swift b/Spring/AsyncImageView.swift similarity index 100% rename from Sources/Spring/AsyncImageView.swift rename to Spring/AsyncImageView.swift diff --git a/Sources/Spring/AutoTextView.swift b/Spring/AutoTextView.swift similarity index 100% rename from Sources/Spring/AutoTextView.swift rename to Spring/AutoTextView.swift diff --git a/Sources/Spring/BlurView.swift b/Spring/BlurView.swift similarity index 100% rename from Sources/Spring/BlurView.swift rename to Spring/BlurView.swift diff --git a/Sources/Spring/DesignableButton.swift b/Spring/DesignableButton.swift similarity index 100% rename from Sources/Spring/DesignableButton.swift rename to Spring/DesignableButton.swift diff --git a/Sources/Spring/DesignableImageView.swift b/Spring/DesignableImageView.swift similarity index 100% rename from Sources/Spring/DesignableImageView.swift rename to Spring/DesignableImageView.swift diff --git a/Sources/Spring/DesignableLabel.swift b/Spring/DesignableLabel.swift similarity index 100% rename from Sources/Spring/DesignableLabel.swift rename to Spring/DesignableLabel.swift diff --git a/Sources/Spring/DesignableTabBarController.swift b/Spring/DesignableTabBarController.swift similarity index 100% rename from Sources/Spring/DesignableTabBarController.swift rename to Spring/DesignableTabBarController.swift diff --git a/Sources/Spring/DesignableTextField.swift b/Spring/DesignableTextField.swift similarity index 100% rename from Sources/Spring/DesignableTextField.swift rename to Spring/DesignableTextField.swift diff --git a/Sources/Spring/DesignableTextView.swift b/Spring/DesignableTextView.swift similarity index 100% rename from Sources/Spring/DesignableTextView.swift rename to Spring/DesignableTextView.swift diff --git a/Sources/Spring/DesignableView.swift b/Spring/DesignableView.swift similarity index 100% rename from Sources/Spring/DesignableView.swift rename to Spring/DesignableView.swift diff --git a/Sources/Spring/ImageLoader.swift b/Spring/ImageLoader.swift similarity index 100% rename from Sources/Spring/ImageLoader.swift rename to Spring/ImageLoader.swift diff --git a/Sources/Spring/Info.plist b/Spring/Info.plist similarity index 100% rename from Sources/Spring/Info.plist rename to Spring/Info.plist diff --git a/Sources/Spring/KeyboardLayoutConstraint.swift b/Spring/KeyboardLayoutConstraint.swift similarity index 100% rename from Sources/Spring/KeyboardLayoutConstraint.swift rename to Spring/KeyboardLayoutConstraint.swift diff --git a/Sources/Spring/LoadingView.swift b/Spring/LoadingView.swift similarity index 100% rename from Sources/Spring/LoadingView.swift rename to Spring/LoadingView.swift diff --git a/Sources/Spring/LoadingView.xib b/Spring/LoadingView.xib similarity index 100% rename from Sources/Spring/LoadingView.xib rename to Spring/LoadingView.xib diff --git a/Sources/Spring/Misc.swift b/Spring/Misc.swift similarity index 100% rename from Sources/Spring/Misc.swift rename to Spring/Misc.swift diff --git a/Sources/Spring/SoundPlayer.swift b/Spring/SoundPlayer.swift similarity index 100% rename from Sources/Spring/SoundPlayer.swift rename to Spring/SoundPlayer.swift diff --git a/Sources/Spring/Spring.h b/Spring/Spring.h similarity index 100% rename from Sources/Spring/Spring.h rename to Spring/Spring.h diff --git a/Sources/Spring/Spring.swift b/Spring/Spring.swift similarity index 100% rename from Sources/Spring/Spring.swift rename to Spring/Spring.swift diff --git a/Sources/Spring/SpringAnimation.swift b/Spring/SpringAnimation.swift similarity index 100% rename from Sources/Spring/SpringAnimation.swift rename to Spring/SpringAnimation.swift diff --git a/Sources/Spring/SpringButton.swift b/Spring/SpringButton.swift similarity index 100% rename from Sources/Spring/SpringButton.swift rename to Spring/SpringButton.swift diff --git a/Sources/Spring/SpringImageView.swift b/Spring/SpringImageView.swift similarity index 100% rename from Sources/Spring/SpringImageView.swift rename to Spring/SpringImageView.swift diff --git a/Sources/Spring/SpringLabel.swift b/Spring/SpringLabel.swift similarity index 100% rename from Sources/Spring/SpringLabel.swift rename to Spring/SpringLabel.swift diff --git a/Sources/Spring/SpringTextField.swift b/Spring/SpringTextField.swift similarity index 100% rename from Sources/Spring/SpringTextField.swift rename to Spring/SpringTextField.swift diff --git a/Sources/Spring/SpringTextView.swift b/Spring/SpringTextView.swift similarity index 100% rename from Sources/Spring/SpringTextView.swift rename to Spring/SpringTextView.swift diff --git a/Sources/Spring/SpringView.swift b/Spring/SpringView.swift similarity index 100% rename from Sources/Spring/SpringView.swift rename to Spring/SpringView.swift diff --git a/Sources/Spring/TransitionManager.swift b/Spring/TransitionManager.swift similarity index 100% rename from Sources/Spring/TransitionManager.swift rename to Spring/TransitionManager.swift diff --git a/Sources/Spring/TransitionZoom.swift b/Spring/TransitionZoom.swift similarity index 100% rename from Sources/Spring/TransitionZoom.swift rename to Spring/TransitionZoom.swift diff --git a/Sources/Spring/UnwindSegue.swift b/Spring/UnwindSegue.swift similarity index 100% rename from Sources/Spring/UnwindSegue.swift rename to Spring/UnwindSegue.swift diff --git a/Tests/SpringTests/SpringTests.swift b/Tests/SpringTests/SpringTests.swift deleted file mode 100644 index e2fd3a1..0000000 --- a/Tests/SpringTests/SpringTests.swift +++ /dev/null @@ -1,11 +0,0 @@ -import XCTest -@testable import Spring - -final class SpringTests: XCTestCase { - func testExample() throws { - // This is an example of a functional test case. - // Use XCTAssert and related functions to verify your tests produce the correct - // results. - XCTAssertEqual(Spring().text, "Hello, World!") - } -} From 90cc6f0b6e45e8815d24377f2f7b5d49c3f1a463 Mon Sep 17 00:00:00 2001 From: Alexey Efimov Date: Tue, 12 Apr 2022 18:37:56 +0300 Subject: [PATCH 21/21] Delete .swiftpm --- .../xcode/package.xcworkspace/contents.xcworkspacedata | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a..0000000 --- a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - -