├── .swift-version ├── graphics ├── Logo.gif ├── logo.pcvd ├── Activity.pcvd ├── Progress.pcvd ├── example.gif ├── tripleGears.gif ├── OrbitIndicator.gif ├── OrbitIndicator2.gif ├── OrbitIndicator3.gif ├── ProgressBarDisplay.gif ├── ProgressCircleDisplay.gif ├── anotated_storyboard_screenshot.png └── anotated_storyboard_screenshot.afdesign ├── Example ├── Resources │ ├── Assets.xcassets │ │ ├── Contents.json │ │ └── AppIcon.appiconset │ │ │ ├── Icon-76.png │ │ │ ├── Icon-167.png │ │ │ ├── Icon-60@2x.png │ │ │ ├── Icon-60@3x.png │ │ │ ├── Icon-76@2x.png │ │ │ ├── Icon-Small.png │ │ │ ├── Icon-Small@2x.png │ │ │ ├── Icon-Small@3x.png │ │ │ ├── Icon-Small-40@2x.png │ │ │ ├── Icon-Small-40@3x.png │ │ │ ├── iTunesArtwork@2x.png │ │ │ └── Contents.json │ ├── Info.plist │ └── Base.lproj │ │ └── LaunchScreen.storyboard ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── ViewController.swift └── AppDelegate.swift ├── .jazzy.yaml ├── .gitlab-ci.yml ├── Tests └── ShowSomeProgressTests.swift ├── .github └── ISSUE_TEMPLATE │ ├── feature-request.md │ ├── bug-report.md │ ├── feature_request.md │ └── bug_report.md ├── .swiftlint.yml ├── Sources ├── Extensions.swift ├── ActivityAnimationHelper.swift ├── BarProgressView.swift ├── CircleProgressView.swift ├── OrbitActivityIndicatorView.swift ├── AnimationHelper.swift └── stylekit │ ├── ProgressStyleKit.swift │ └── ActivityStyleKit.swift ├── Package.swift ├── ShowSomeProgress.podspec ├── Configs ├── ShowSomeProgressTests.plist └── ShowSomeProgress.plist ├── LICENSE ├── .gitignore ├── fastlane └── Fastfile ├── CODE_OF_CONDUCT.md └── README.md /.swift-version: -------------------------------------------------------------------------------- 1 | 5.0 2 | -------------------------------------------------------------------------------- /graphics/Logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/graphics/Logo.gif -------------------------------------------------------------------------------- /graphics/logo.pcvd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/graphics/logo.pcvd -------------------------------------------------------------------------------- /graphics/Activity.pcvd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/graphics/Activity.pcvd -------------------------------------------------------------------------------- /graphics/Progress.pcvd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/graphics/Progress.pcvd -------------------------------------------------------------------------------- /graphics/example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/graphics/example.gif -------------------------------------------------------------------------------- /graphics/tripleGears.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/graphics/tripleGears.gif -------------------------------------------------------------------------------- /graphics/OrbitIndicator.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/graphics/OrbitIndicator.gif -------------------------------------------------------------------------------- /graphics/OrbitIndicator2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/graphics/OrbitIndicator2.gif -------------------------------------------------------------------------------- /graphics/OrbitIndicator3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/graphics/OrbitIndicator3.gif -------------------------------------------------------------------------------- /graphics/ProgressBarDisplay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/graphics/ProgressBarDisplay.gif -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /graphics/ProgressCircleDisplay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/graphics/ProgressCircleDisplay.gif -------------------------------------------------------------------------------- /graphics/anotated_storyboard_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/graphics/anotated_storyboard_screenshot.png -------------------------------------------------------------------------------- /graphics/anotated_storyboard_screenshot.afdesign: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/graphics/anotated_storyboard_screenshot.afdesign -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-167.png -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small.png -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small@2x.png -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small@3x.png -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@2x.png -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/Example/Resources/Assets.xcassets/AppIcon.appiconset/Icon-Small-40@3x.png -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/AppIcon.appiconset/iTunesArtwork@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/stoneburner/ShowSomeProgress/HEAD/Example/Resources/Assets.xcassets/AppIcon.appiconset/iTunesArtwork@2x.png -------------------------------------------------------------------------------- /.jazzy.yaml: -------------------------------------------------------------------------------- 1 | # ShowSomeProgress document generator jazzy settings 2 | 3 | copyright: Copyright 2019 ShowSomeProgress 4 | author: Alexander Kasimir 5 | xcodebuild_arguments: [-target, ShowSomeProgress-iOS] 6 | clean: true 7 | output: ./Documentation 8 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | stages: 2 | - Tests 3 | - Compatibility 4 | 5 | UnitTests: 6 | stage: Tests 7 | only: 8 | - master 9 | - develop 10 | - /^hotfix.*$/ 11 | - /^feature.*$/ 12 | script: 13 | fastlane ios tests 14 | 15 | DependencyManagerCompatibility: 16 | stage: Compatibility 17 | only: 18 | - master 19 | - develop 20 | - /^hotfix.*$/ 21 | - /^feature.*$/ 22 | script: 23 | fastlane ios compatibilityTests -------------------------------------------------------------------------------- /Tests/ShowSomeProgressTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShowSomeProgressTests.swift 3 | // ShowSomeProgressTests 4 | // 5 | // Created by Alexander Kasimir on 04.08.2019. 6 | // Copyright © 2019 ShowSomeProgress. All rights reserved. 7 | // 8 | 9 | @testable import ShowSomeProgress 10 | import XCTest 11 | 12 | class ShowSomeProgressTests: XCTestCase { 13 | 14 | static var allTests = [ 15 | ("testExample", testExample), 16 | ] 17 | 18 | func testExample() {} 19 | 20 | } 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for ShowSomeProgress 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | # Motivation 11 | > ℹ Please replace this with your motivation. For example if your feature request is related to a problem. 12 | 13 | # Solution 14 | > ℹ Please replace this with your proposed solution. 15 | 16 | # Additional context 17 | > ℹ Please replace this with any other context or screenshots about your feature request (optional). 18 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | opt_in_rules: # some rules are only opt-in 2 | - empty_count 3 | - redundant_nil_coalescing 4 | - switch_case_on_newline 5 | - force_unwrapping 6 | - closure_spacing 7 | - implicitly_unwrapped_optional 8 | - sorted_imports 9 | - valid_docs 10 | - nslocalizedstring_require_bundle 11 | 12 | included: 13 | - Sources 14 | 15 | excluded: # paths to ignore during linting. Takes precedence over `included`. 16 | - Tests 17 | - Example 18 | - Sources/stylekit # stylekits are auto generated 19 | disabled_rules: # rule identifiers to exclude from running 20 | - line_length 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a bug report 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## ShowSomeProgress Environment 11 | 12 | - ShowSomeProgress version: 13 | - macOS version: 14 | - Xcode version: 15 | - Dependency manager (Carthage, CocoaPods, SPM, Manually): 16 | 17 | ## What did you do? 18 | 19 | > ℹ Please replace this with what you did. 20 | 21 | ## What did you expect to happen? 22 | 23 | > ℹ Please replace this with what you expected to happen. 24 | 25 | ## What happened instead? 26 | 27 | > ℹ Please replace this with of what happened instead. 28 | -------------------------------------------------------------------------------- /Sources/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // ShowSomeProgress-iOS 4 | // 5 | // Created by Alexander Kasimir on 04.08.19. 6 | // Copyright © 2019 ShowSomeProgress. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIColor { 12 | 13 | //swiftlint:disable:next large_tuple 14 | var components: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) { 15 | var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0 16 | self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) 17 | return (red: red, green: green, blue: blue, alpha: alpha) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.0 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "ShowSomeProgress", 7 | products: [ 8 | .library( 9 | name: "ShowSomeProgress", 10 | targets: ["ShowSomeProgress"] 11 | ), 12 | ], 13 | dependencies: [], 14 | targets: [ 15 | .target( 16 | name: "ShowSomeProgress", 17 | dependencies: [], 18 | path: "Sources" 19 | ), 20 | .testTarget( 21 | name: "ShowSomeProgressTests", 22 | dependencies: ["ShowSomeProgress"], 23 | path: "Tests" 24 | ), 25 | ] 26 | ) 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /ShowSomeProgress.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "ShowSomeProgress" 3 | s.version = "1.0.0" 4 | s.summary = "ShowSomeProgress" 5 | s.homepage = "https://github.com/AlexanderKasimir/ShowSomeProgress" 6 | s.license = { :type => "MIT", :file => "LICENSE" } 7 | s.author = { "Alexander Kasimir" => "alexander@kasimir.at" } 8 | s.source = { :git => "https://github.com/AlexanderKasimir/ShowSomeProgress.git", :tag => s.version.to_s } 9 | s.ios.deployment_target = "8.0" 10 | s.tvos.deployment_target = "9.0" 11 | s.watchos.deployment_target = "2.0" 12 | s.osx.deployment_target = "10.10" 13 | s.source_files = "Sources/**/*" 14 | s.frameworks = "Foundation" 15 | end 16 | -------------------------------------------------------------------------------- /Configs/ShowSomeProgressTests.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /Configs/ShowSomeProgress.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ShowSomeProgress 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | NSHumanReadableCopyright 26 | Copyright © 2019 ShowSomeProgress. All rights reserved. 27 | NSPrincipalClass 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Alexander Kasimir 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Sources/ActivityAnimationHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ActivityAnimationHelper.swift 3 | // ShowSomeProgress-iOS 4 | // 5 | // Created by Alexander Kasimir on 06.08.19. 6 | // Copyright © 2019 ShowSomeProgress. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public protocol AnimatedActivityUIView: UIView { 12 | var timer: Timer? { get set } 13 | var animationProgress: CGFloat { get set } 14 | var frameRate: TimeInterval { get set } 15 | func startAnimation() 16 | func stopAnimation() 17 | func animationStep() 18 | } 19 | 20 | extension AnimatedActivityUIView { 21 | 22 | public func startAnimation() { 23 | guard timer == nil else { return } // if timer is not nill, the animation is already running 24 | timer = Timer.scheduledTimer(withTimeInterval: frameRate, repeats: true) { _ in self.animationStep() } 25 | } 26 | 27 | public func stopAnimation() { 28 | timer?.invalidate() 29 | timer = nil 30 | setNeedsDisplay() 31 | } 32 | 33 | public func animationStep() { 34 | animationProgress += 0.01 35 | if animationProgress >= 1 { 36 | animationProgress = 0 37 | } 38 | setNeedsDisplay() 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Sources/BarProgressView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BarProgressView.swift 3 | // AnimationTest 4 | // 5 | // Created by Alexander Kasimir on 31.07.19. 6 | // Copyright © 2019 Alexander Kasimir. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @IBDesignable public class BarProgressView: UIView, AnimatedUIView { 12 | @IBInspectable public var progress: CGFloat = 0.5 { didSet { updateValue() } } 13 | @IBInspectable public var progressColor: UIColor = UIColor.blue { didSet { updateValue() } } 14 | @IBInspectable public var showTriangle: Bool = false 15 | 16 | var animatedLayer: Progressable = ProgressBarAnimationLayer() 17 | var stateKeyName = "state" 18 | 19 | override public func layoutSubviews() { 20 | setupAnimationLayer(progressColor: progressColor, showTriangle: showTriangle) 21 | updateValue() 22 | animatedLayer.frame = self.bounds 23 | } 24 | } 25 | 26 | public class ProgressBarAnimationLayer: ProgressAnimationLayer { 27 | 28 | override public func draw(in ctx: CGContext) { 29 | UIGraphicsPushContext(ctx) 30 | let size = ctx.convertToUserSpace(CGSize(width: ctx.width, height: ctx.height)) 31 | let rect = CGRect(origin: CGPoint.zero, size: size) 32 | 33 | let color = progressColor.components 34 | ProgressStyleKit.drawProgressBarDisplay(frame: rect, resizing: .aspectFit, progress: progress, showTriangle: showTriangle, progressColorRed: color.red, progressColorGreen: color.green, progressColorBlue: color.blue) 35 | 36 | UIGraphicsPopContext() 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Sources/CircleProgressView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomProgressView.swift 3 | // AnimationTest 4 | // 5 | // Created by Alexander Kasimir on 28.07.19. 6 | // Copyright © 2019 Alexander Kasimir. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public class CircleProgressAnimationLayer: ProgressAnimationLayer { 12 | 13 | override public func draw(in ctx: CGContext) { 14 | UIGraphicsPushContext(ctx) 15 | let size = ctx.convertToUserSpace(CGSize(width: ctx.width, height: ctx.height)) 16 | let rect = CGRect(origin: CGPoint.zero, size: size) 17 | 18 | let colors = progressColor.components 19 | ProgressStyleKit.drawProgressCircleDisplay(frame: rect, resizing: .aspectFit, progress: progress, showTriangle: showTriangle, progressColorRed: colors.red, progressColorGreen: colors.green, progressColorBlue: colors.blue) 20 | UIGraphicsPopContext() 21 | } 22 | } 23 | 24 | @IBDesignable public class CircleProgressView: UIView, AnimatedUIView { 25 | @IBInspectable public var progress: CGFloat = 0.5 { didSet { updateValue() } } 26 | @IBInspectable public var progressColor: UIColor = UIColor.blue { didSet { updateValue() } } 27 | @IBInspectable public var showTriangle: Bool = false { didSet { updateValue() } } 28 | 29 | var animatedLayer: Progressable = CircleProgressAnimationLayer() 30 | var stateKeyName = "state" 31 | 32 | override public func layoutSubviews() { 33 | setupAnimationLayer(progressColor: progressColor, showTriangle: showTriangle) 34 | animatedLayer.frame = self.bounds 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Example/Resources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | ShowSomeProgress 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeRight 37 | UIInterfaceOrientationLandscapeLeft 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Example/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Example/Resources/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Example/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // AnimationTest 4 | // 5 | // Created by Alexander Kasimir on 28.07.19. 6 | // Copyright © 2019 Alexander Kasimir. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import ShowSomeProgress 11 | 12 | class ViewController: UIViewController { 13 | 14 | @IBOutlet weak var gearView: GearActivityIndicatorView! 15 | 16 | @IBOutlet weak var smallCircleView: CircleProgressView! 17 | @IBOutlet weak var smallCircleView2: CircleProgressView! 18 | @IBOutlet weak var smallCircleView3: CircleProgressView! 19 | @IBOutlet weak var smallCircleView4: CircleProgressView! 20 | 21 | @IBOutlet weak var barProgressView: BarProgressView! 22 | @IBOutlet weak var barProgressView2: BarProgressView! 23 | 24 | @IBOutlet weak var orbitActivityIndicator: OrbitActivityIndicatorView! 25 | @IBOutlet weak var orbitActivityIndicator2: OrbitActivityIndicatorView2! 26 | @IBOutlet weak var orbitActivityIndicator3: OrbitActivityIndicatorView3! 27 | @IBAction func setRandomValueTapped(_ sender: Any) { 28 | smallCircleView.progress = CGFloat(Double.random(in: 0...1)) 29 | smallCircleView2.progress = CGFloat(Double.random(in: 0...1)) 30 | smallCircleView3.progress = CGFloat(Double.random(in: 0...1)) 31 | smallCircleView4.progress = CGFloat(Double.random(in: 0...1)) 32 | barProgressView.progress = CGFloat(Double.random(in: 0...1)) 33 | barProgressView2.progress = CGFloat(Double.random(in: 0...1)) 34 | } 35 | 36 | override func viewDidAppear(_ animated: Bool) { 37 | super.viewDidAppear(animated) 38 | gearView.startAnimation() 39 | orbitActivityIndicator.startAnimation() 40 | orbitActivityIndicator2.startAnimation() 41 | orbitActivityIndicator3.startAnimation() 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Example 4 | // 5 | // Created by Alexander Kasimir on 04.08.2019. 6 | // Copyright © 2019 ShowSomeProgress. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | // MARK: - AppDelegate 12 | 13 | /// The AppDelegate 14 | @UIApplicationMain 15 | class AppDelegate: UIResponder, UIApplicationDelegate { 16 | 17 | var window: UIWindow? 18 | 19 | 20 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 21 | // Override point for customization after application launch. 22 | return true 23 | } 24 | 25 | func applicationWillResignActive(_ application: UIApplication) { 26 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 27 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 28 | } 29 | 30 | func applicationDidEnterBackground(_ application: UIApplication) { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | func applicationWillEnterForeground(_ application: UIApplication) { 36 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 37 | } 38 | 39 | func applicationDidBecomeActive(_ application: UIApplication) { 40 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 41 | } 42 | 43 | func applicationWillTerminate(_ application: UIApplication) { 44 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Example/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "size" : "29x29", 15 | "idiom" : "iphone", 16 | "filename" : "Icon-Small@2x.png", 17 | "scale" : "2x" 18 | }, 19 | { 20 | "size" : "29x29", 21 | "idiom" : "iphone", 22 | "filename" : "Icon-Small@3x.png", 23 | "scale" : "3x" 24 | }, 25 | { 26 | "size" : "40x40", 27 | "idiom" : "iphone", 28 | "filename" : "Icon-Small-40@2x.png", 29 | "scale" : "2x" 30 | }, 31 | { 32 | "size" : "40x40", 33 | "idiom" : "iphone", 34 | "filename" : "Icon-Small-40@3x.png", 35 | "scale" : "3x" 36 | }, 37 | { 38 | "size" : "60x60", 39 | "idiom" : "iphone", 40 | "filename" : "Icon-60@2x.png", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "size" : "60x60", 45 | "idiom" : "iphone", 46 | "filename" : "Icon-60@3x.png", 47 | "scale" : "3x" 48 | }, 49 | { 50 | "idiom" : "ipad", 51 | "size" : "20x20", 52 | "scale" : "1x" 53 | }, 54 | { 55 | "idiom" : "ipad", 56 | "size" : "20x20", 57 | "scale" : "2x" 58 | }, 59 | { 60 | "size" : "29x29", 61 | "idiom" : "ipad", 62 | "filename" : "Icon-Small.png", 63 | "scale" : "1x" 64 | }, 65 | { 66 | "size" : "29x29", 67 | "idiom" : "ipad", 68 | "filename" : "Icon-Small@2x.png", 69 | "scale" : "2x" 70 | }, 71 | { 72 | "idiom" : "ipad", 73 | "size" : "40x40", 74 | "scale" : "1x" 75 | }, 76 | { 77 | "idiom" : "ipad", 78 | "size" : "40x40", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "76x76", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-76.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "76x76", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-76@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "83.5x83.5", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-167.png", 97 | "scale" : "2x" 98 | }, 99 | { 100 | "size" : "1024x1024", 101 | "idiom" : "ios-marketing", 102 | "filename" : "iTunesArtwork@2x.png", 103 | "scale" : "1x" 104 | } 105 | ], 106 | "info" : { 107 | "version" : 1, 108 | "author" : "xcode" 109 | }, 110 | "properties" : { 111 | "pre-rendered" : true 112 | } 113 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/xcode,swift,swiftpackagemanager 3 | # Edit at https://www.gitignore.io/?templates=xcode,swift,swiftpackagemanager 4 | 5 | ### Swift ### 6 | # Xcode 7 | # 8 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 9 | 10 | ## Build generated 11 | build/ 12 | DerivedData/ 13 | 14 | ## Various settings 15 | *.pbxuser 16 | !default.pbxuser 17 | *.mode1v3 18 | !default.mode1v3 19 | *.mode2v3 20 | !default.mode2v3 21 | *.perspectivev3 22 | !default.perspectivev3 23 | xcuserdata/ 24 | 25 | ## Other 26 | *.moved-aside 27 | *.xccheckout 28 | *.xcscmblueprint 29 | 30 | ## Obj-C/Swift specific 31 | *.hmap 32 | *.ipa 33 | *.dSYM.zip 34 | *.dSYM 35 | 36 | ## Playgrounds 37 | timeline.xctimeline 38 | playground.xcworkspace 39 | 40 | # Swift Package Manager 41 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 42 | # Packages/ 43 | # Package.pins 44 | # Package.resolved 45 | .build/ 46 | 47 | # CocoaPods 48 | # We recommend against adding the Pods directory to your .gitignore. However 49 | # you should judge for yourself, the pros and cons are mentioned at: 50 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 51 | # Pods/ 52 | # Add this line if you want to avoid checking in source code from the Xcode workspace 53 | # *.xcworkspace 54 | 55 | # Carthage 56 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 57 | # Carthage/Checkouts 58 | 59 | Carthage/Build 60 | 61 | # Accio dependency management 62 | Dependencies/ 63 | .accio/ 64 | 65 | # fastlane 66 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 67 | # screenshots whenever they are needed. 68 | # For more information about the recommended setup visit: 69 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 70 | 71 | fastlane/report.xml 72 | fastlane/Preview.html 73 | fastlane/screenshots/**/*.png 74 | fastlane/test_output 75 | 76 | # Code Injection 77 | # After new code Injection tools there's a generated folder /iOSInjectionProject 78 | # https://github.com/johnno1962/injectionforxcode 79 | 80 | iOSInjectionProject/ 81 | 82 | ### SwiftPackageManager ### 83 | Packages 84 | xcuserdata 85 | *.xcodeproj 86 | 87 | 88 | ### Xcode ### 89 | # Xcode 90 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 91 | 92 | ## User settings 93 | 94 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 95 | 96 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 97 | 98 | ## Xcode Patch 99 | *.xcodeproj/* 100 | !*.xcodeproj/project.pbxproj 101 | !*.xcodeproj/xcshareddata/ 102 | !*.xcworkspace/contents.xcworkspacedata 103 | /*.gcno 104 | 105 | ### Xcode Patch ### 106 | **/xcshareddata/WorkspaceSettings.xcsettings 107 | 108 | # End of https://www.gitignore.io/api/xcode,swift,swiftpackagemanager 109 | -------------------------------------------------------------------------------- /fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | fastlane_version "2.120.0" 2 | 3 | default_platform :ios 4 | 5 | platform :ios do 6 | 7 | desc "Release a new version of ShowSomeProgress" 8 | lane :release do |options| 9 | # Ensure Git status is clean 10 | ensure_git_status_clean 11 | # Ensure Git branch is master 12 | ensure_git_branch(branch: 'master') 13 | # Perform Dependency-Manager compatibility tests 14 | compatibilityTests 15 | # Perform Tests 16 | tests 17 | # Retrieve Version from options 18 | version = options[:version] 19 | # Increment Version 20 | increment(version: version) 21 | # Add Git Tag 22 | add_git_tag(tag: version) 23 | # Push Git Tag 24 | push_git_tags() 25 | # Push Git commit 26 | push_to_git_remote() 27 | # Pod push / Pod trunk 28 | pod_push() 29 | end 30 | 31 | desc "Increment Version" 32 | lane :increment do |options| 33 | # Retrieve Version from options 34 | version = options[:version] 35 | # Set Podspec version 36 | version_bump_podspec( 37 | path: "ShowSomeProgress.podspec", 38 | version_number: version 39 | ) 40 | # Set Framework plist version 41 | set_info_plist_value( 42 | path: "Configs/ShowSomeProgress.plist", 43 | key: "CFBundleShortVersionString", 44 | value: version 45 | ) 46 | # Set Framework Tests plist version 47 | set_info_plist_value( 48 | path: "Configs/ShowSomeProgressTests.plist", 49 | key: "CFBundleShortVersionString", 50 | value: version 51 | ) 52 | # Set Example plist version 53 | set_info_plist_value( 54 | path: "Example/Resources/Info.plist", 55 | key: "CFBundleShortVersionString", 56 | value: version 57 | ) 58 | # Commit modified files 59 | git_commit( 60 | path: [ 61 | "ShowSomeProgress.podspec", 62 | "Configs/ShowSomeProgress.plist", 63 | "Configs/ShowSomeProgressTests.plist", 64 | "Example/Resources/Info.plist" 65 | ], 66 | message: "ShowSomeProgress Version #{version} 🚀" 67 | ) 68 | end 69 | 70 | desc "Runs tests" 71 | lane :tests do 72 | # Perform iOS Tests 73 | scan( 74 | project: "ShowSomeProgress.xcodeproj", 75 | scheme: "ShowSomeProgress-iOS", 76 | clean: true 77 | ) 78 | # Perform tvOS Tests 79 | scan( 80 | project: "ShowSomeProgress.xcodeproj", 81 | scheme: "ShowSomeProgress-tvOS", 82 | clean: true 83 | ) 84 | # Perform macOS Tests 85 | spm(command: "test") 86 | # Delete SPM build artifacts 87 | spm(command: "clean") 88 | end 89 | 90 | desc "Run Dependency-Manager compatibility tests" 91 | lane :compatibilityTests do 92 | # Carthage build to ensure Carthage compatibility 93 | carthage( 94 | command: "build", 95 | no_skip_current: true, 96 | cache_builds: true 97 | ) 98 | # Pod lib lint to ensure CocoaPods compatibility 99 | pod_lib_lint(allow_warnings: true) 100 | # SPM Build to ensure Swift Package Manager compatibility 101 | spm(command: "build") 102 | # Delete SPM build artifacts 103 | spm(command: "clean") 104 | end 105 | 106 | end 107 | -------------------------------------------------------------------------------- /Sources/OrbitActivityIndicatorView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // OrbitActivityIndicatorView.swift 3 | // ShowSomeProgress-iOS 4 | // 5 | // Created by Alexander Kasimir on 06.08.19. 6 | // Copyright © 2019 ShowSomeProgress. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @IBDesignable public class OrbitActivityIndicatorView: UIView, AnimatedActivityUIView { 12 | 13 | public var timer: Timer? 14 | public var frameRate: TimeInterval = 1/30 15 | public var animationProgress: CGFloat = 0.0 16 | 17 | override public func draw(_ rect: CGRect) { 18 | let colorParts = tintColor.components 19 | ActivityStyleKit.drawOrbitIndicator(frame: rect, 20 | resizing: .aspectFit, 21 | animationProgress: animationProgress, 22 | progressColorRed: colorParts.red, 23 | progressColorGreen: colorParts.green, 24 | progressColorBlue: colorParts.blue) 25 | } 26 | 27 | } 28 | 29 | @IBDesignable public class OrbitActivityIndicatorView2: UIView, AnimatedActivityUIView { 30 | 31 | public var timer: Timer? 32 | public var frameRate: TimeInterval = 1/30 33 | public var animationProgress: CGFloat = 0.0 34 | 35 | override public func draw(_ rect: CGRect) { 36 | let colorParts = tintColor.components 37 | ActivityStyleKit.drawOrbitIndicator2(frame: rect, 38 | resizing: .aspectFit, 39 | animationProgress: animationProgress, 40 | progressColorRed: colorParts.red, 41 | progressColorGreen: colorParts.green, 42 | progressColorBlue: colorParts.blue) 43 | } 44 | } 45 | 46 | @IBDesignable public class OrbitActivityIndicatorView3: UIView, AnimatedActivityUIView { 47 | 48 | public var timer: Timer? 49 | public var frameRate: TimeInterval = 1/30 50 | public var animationProgress: CGFloat = 0.0 51 | 52 | override public func draw(_ rect: CGRect) { 53 | let colorParts = tintColor.components 54 | ActivityStyleKit.drawOrbitIndicator3(frame: rect, 55 | resizing: .aspectFit, 56 | animationProgress: animationProgress, 57 | progressColorRed: colorParts.red, 58 | progressColorGreen: colorParts.green, 59 | progressColorBlue: colorParts.blue) 60 | } 61 | } 62 | 63 | @IBDesignable public class GearActivityIndicatorView: UIView, AnimatedActivityUIView { 64 | 65 | public var timer: Timer? 66 | public var frameRate: TimeInterval = 1/30 67 | public var animationProgress: CGFloat = 0.0 68 | 69 | override public func draw(_ rect: CGRect) { 70 | let colorParts = tintColor.components 71 | ActivityStyleKit.drawTripleGears(frame: rect, 72 | resizing: .aspectFit, 73 | animationProgress: animationProgress, 74 | progressColorRed: colorParts.red, 75 | progressColorGreen: colorParts.green, 76 | progressColorBlue: colorParts.blue) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at alexander@kasimir.at. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /Sources/AnimationHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AnimationHelper.swift 3 | // AnimationTest 4 | // 5 | // Created by Alexander Kasimir on 29.07.19. 6 | // Copyright © 2019 Alexander Kasimir. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | protocol Progressable: CALayer { 12 | var progress: CGFloat { get set } 13 | var progressColor: UIColor { get set } 14 | var showTriangle: Bool { get set } 15 | } 16 | 17 | public class ProgressAnimationLayer: CALayer, Progressable { 18 | @NSManaged var progress: CGFloat 19 | private static let keyName = "progress" 20 | var progressColor: UIColor = UIColor.blue 21 | var showTriangle: Bool = false 22 | 23 | override init() { 24 | super.init() 25 | progress = 0 26 | needsDisplayOnBoundsChange = true 27 | } 28 | 29 | override init(layer: Any) { 30 | super.init(layer: layer) 31 | if let layer = layer as? Progressable { 32 | progress = layer.progress 33 | progressColor = layer.progressColor 34 | showTriangle = layer.showTriangle 35 | } 36 | } 37 | 38 | override public class func needsDisplay(forKey key: (String?)) -> Bool { 39 | guard let key = key else { return false } 40 | if key == keyName { 41 | return true 42 | } else { 43 | return super.needsDisplay(forKey: key) 44 | } 45 | } 46 | 47 | override public func action(forKey event: String) -> CAAction? { 48 | if event == ProgressAnimationLayer.keyName { 49 | let animation = CABasicAnimation(keyPath: event) 50 | animation.fromValue = self.presentation()?.value(forKey: event) 51 | return animation 52 | } else { 53 | return super.action(forKey: event) 54 | } 55 | } 56 | 57 | required init?(coder aDecoder: NSCoder) { 58 | super.init(coder: aDecoder) 59 | fatalError("init(coder:) has not been implemented") 60 | } 61 | } 62 | 63 | protocol AnimatedUIView: UIView { 64 | var animatedLayer: Progressable { get set } 65 | var progress: CGFloat { get set } 66 | var progressColor: UIColor { get set } 67 | var showTriangle: Bool { get set } 68 | var stateKeyName: String { get set } 69 | } 70 | 71 | extension AnimatedUIView { 72 | 73 | func setupAnimationLayer(progressColor: UIColor, showTriangle: Bool = false) { 74 | guard self.layer.sublayers == nil || self.layer.sublayers?.contains(animatedLayer) == false else { return } 75 | animatedLayer.contentsScale = UIScreen.main.scale 76 | animatedLayer.frame = self.bounds 77 | animatedLayer.setValue(false, forKey: stateKeyName) 78 | animatedLayer.progressColor = progressColor 79 | animatedLayer.showTriangle = showTriangle 80 | 81 | self.layer.addSublayer(animatedLayer) 82 | animatedLayer.setNeedsDisplay() 83 | } 84 | 85 | internal func updateValue() { 86 | // in the storyboard preview the state is not set 87 | guard let layerState = ((animatedLayer.value(forKey: stateKeyName) as AnyObject).boolValue) else { 88 | animatedLayer.progress = progress 89 | animatedLayer.progressColor = self.progressColor 90 | animatedLayer.showTriangle = self.showTriangle 91 | animatedLayer.setValue(false, forKey: stateKeyName) 92 | return 93 | } 94 | 95 | let timing: CAMediaTimingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut) 96 | CATransaction.begin() 97 | CATransaction.setAnimationTimingFunction(timing) 98 | animatedLayer.progress = progress 99 | animatedLayer.progressColor = self.progressColor 100 | animatedLayer.showTriangle = self.showTriangle 101 | 102 | CATransaction.commit() 103 | animatedLayer.setValue(!layerState, forKey: stateKeyName) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | ShowSomeProgress Logo 3 |

4 | 5 |

6 | 7 | Swift 5.0 8 | 9 | 16 | 17 | Carthage Compatible 18 | 19 | 20 | SPM 21 | 22 |

23 | 24 |

25 | Progress Indicators and Activity Views for iOS Apps 26 |

27 | 28 | ## Features 29 | 30 | - [x] Storyboard compatible, configure apprearance with the property inspector. 31 | - [x] fully animated, just set a new progress value and the view will update itself smoothly 32 | 33 | ## Currenty Implemented Progress Indicators 34 | 35 | `CircleProgressView` - A circular indicator 36 | 37 | ![CircleProgressView](graphics/ProgressCircleDisplay.gif) 38 | 39 | `BarProgressView` - A bar indicator 40 | 41 | ![BarProgressView](graphics/ProgressBarDisplay.gif) 42 | 43 | ### Configurable properties: 44 | * `progress` - progress value - 0.0 - 1.0 45 | * `progressColor` - UIColor of the progress indicator 46 | * `showTriangle` - Bool, selects visibility of the small triangle 47 | 48 | ## Currently Implemented Activity Indicators 49 | 50 | `OrbitActivityIndicatorView` - Shows a simplifed planetary system during Activity 51 | 52 | ![OrbitActivityIndicatorView](graphics/OrbitIndicator.gif) 53 | 54 | `OrbitActivityIndicatorView2` - Shows a planetary system during Activity 55 | 56 | ![OrbitActivityIndicatorView](graphics/OrbitIndicator2.gif) 57 | 58 | `OrbitActivityIndicatorView3` - Shows chasing dots system during Activity 59 | 60 | ![OrbitActivityIndicatorView](graphics/OrbitIndicator3.gif) 61 | 62 | `GearActivityIndicatorView` - Shows three gears during Activity 63 | 64 | ![GearActivityIndicatorView](graphics/tripleGears.gif) 65 | 66 | ### Configurable properties: 67 | * `tintColor` - color of the view 68 | 69 | ## Usage 70 | 71 | ![Storyboard](graphics/anotated_storyboard_screenshot.png) 72 | 73 | Just import the framework and use the views like you would use `UIProgressView` 74 | 75 | ```swift 76 | import UIKit 77 | import ShowSomeProgress 78 | 79 | class ViewController: UIViewController { 80 | 81 | @IBOutlet weak var circleProgressView: CircleProgressView! 82 | 83 | @IBAction func setRandomValueTapped(_ sender: Any) { 84 | circleProgressView.progress = CGFloat(Double.random(in: 0...1)) 85 | } 86 | } 87 | ``` 88 | 89 | ## Example 90 | 91 | The example application is the best way to see `ShowSomeProgress` in action. Simply open the `ShowSomeProgress.xcodeproj` and run the `Example` scheme. 92 | 93 | ![Example app](graphics/example.gif) 94 | 95 | 96 | ## Installation 97 | 107 | 108 | ### Carthage 109 | 110 | [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. 111 | 112 | To integrate ShowSomeProgress into your Xcode project using Carthage, specify it in your `Cartfile`: 113 | 114 | ```ogdl 115 | github "stoneburner/ShowSomeProgress" 116 | ``` 117 | 118 | Run `carthage update` to build the framework and drag the built `ShowSomeProgress.framework` into your Xcode project. 119 | 120 | On your application targets’ “Build Phases” settings tab, click the “+” icon and choose “New Run Script Phase” and add the Framework path as mentioned in [Carthage Getting started Step 4, 5 and 6](https://github.com/Carthage/Carthage/blob/master/README.md#if-youre-building-for-ios-tvos-or-watchos) 121 | 122 | ### Swift Package Manager 123 | 124 | To integrate using Apple's [Swift Package Manager](https://swift.org/package-manager/), add the following as a dependency to your `Package.swift`: 125 | 126 | ```swift 127 | dependencies: [ 128 | .package(url: "https://github.com/stoneburner/ShowSomeProgress.git", from: "1.0.0") 129 | ] 130 | ``` 131 | 132 | ### Manually 133 | 134 | If you prefer not to use any of the aforementioned dependency managers, you can integrate ShowSomeProgress into your project manually. Simply drag the `Sources` Folder into your Xcode project. 135 | 136 | ## Contributing 137 | Contributions are very welcome 🙌 138 | 139 | ## License 140 | 141 | ``` 142 | ShowSomeProgress 143 | Copyright (c) 2019 ShowSomeProgress alexander@kasimir.at 144 | 145 | Permission is hereby granted, free of charge, to any person obtaining a copy 146 | of this software and associated documentation files (the "Software"), to deal 147 | in the Software without restriction, including without limitation the rights 148 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 149 | copies of the Software, and to permit persons to whom the Software is 150 | furnished to do so, subject to the following conditions: 151 | 152 | The above copyright notice and this permission notice shall be included in 153 | all copies or substantial portions of the Software. 154 | 155 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 156 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 157 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 158 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 159 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 160 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 161 | THE SOFTWARE. 162 | ``` 163 | -------------------------------------------------------------------------------- /Sources/stylekit/ProgressStyleKit.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ProgressStyleKit.swift 3 | // ShowSomeProgress 4 | // 5 | // Created by Alexander Kasimir on 04.08.19. 6 | // Copyright © 2019 Alexander Kasimir. All rights reserved. 7 | // 8 | // Generated by PaintCode 9 | // http://www.paintcodeapp.com 10 | // 11 | 12 | 13 | 14 | import UIKit 15 | 16 | public class ProgressStyleKit : NSObject { 17 | 18 | //// Drawing Methods 19 | 20 | @objc dynamic public class func drawProgressBarDisplay(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 136, height: 16), resizing: ResizingBehavior = .aspectFit, progress: CGFloat = 0.723, showTriangle: Bool = true, progressColorRed: CGFloat = 0, progressColorGreen: CGFloat = 0.475, progressColorBlue: CGFloat = 1) { 21 | //// General Declarations 22 | let context = UIGraphicsGetCurrentContext()! 23 | 24 | //// Resize to Target Frame 25 | context.saveGState() 26 | let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 136, height: 16), target: targetFrame) 27 | context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) 28 | context.scaleBy(x: resizedFrame.width / 136, y: resizedFrame.height / 16) 29 | let resizedShadowScale: CGFloat = min(resizedFrame.width / 136, resizedFrame.height / 16) 30 | 31 | 32 | 33 | //// Shadow Declarations 34 | let shadow = NSShadow() 35 | shadow.shadowColor = UIColor.black.withAlphaComponent(0.23) 36 | shadow.shadowOffset = CGSize(width: 1, height: 1) 37 | shadow.shadowBlurRadius = 1 38 | 39 | //// Variable Declarations 40 | let percentText = "\(Int(round(round(progress * 100))))" + "%" 41 | let progressWidth: CGFloat = 136 * progress 42 | let progressWidthOffset: CGFloat = progressWidth - 3.5 43 | let progressVisible = progress > 0 44 | let progressBarColor = UIColor(red: progressColorRed, green: progressColorGreen, blue: progressColorBlue, alpha: 1) 45 | 46 | //// Rectangle 2 Drawing 47 | context.saveGState() 48 | context.setAlpha(0.2) 49 | context.beginTransparencyLayer(auxiliaryInfo: nil) 50 | 51 | let rectangle2Path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 136, height: 9), cornerRadius: 3) 52 | context.saveGState() 53 | context.setShadow(offset: CGSize(width: shadow.shadowOffset.width * resizedShadowScale, height: shadow.shadowOffset.height * resizedShadowScale), blur: shadow.shadowBlurRadius * resizedShadowScale, color: (shadow.shadowColor as! UIColor).cgColor) 54 | progressBarColor.setFill() 55 | rectangle2Path.fill() 56 | context.restoreGState() 57 | 58 | 59 | context.endTransparencyLayer() 60 | context.restoreGState() 61 | 62 | 63 | //// Group 64 | context.saveGState() 65 | context.beginTransparencyLayer(auxiliaryInfo: nil) 66 | 67 | //// Clip Rectangle 3 68 | let rectangle3Path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 136, height: 9), cornerRadius: 3) 69 | rectangle3Path.addClip() 70 | 71 | 72 | if (progressVisible) { 73 | //// Rectangle Drawing 74 | let rectanglePath = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: progressWidth, height: 9), cornerRadius: 3) 75 | progressBarColor.setFill() 76 | rectanglePath.fill() 77 | } 78 | 79 | 80 | context.endTransparencyLayer() 81 | context.restoreGState() 82 | 83 | 84 | //// Text Drawing 85 | let textRect = CGRect(x: 3, y: 0, width: 130, height: 9) 86 | let textStyle = NSMutableParagraphStyle() 87 | textStyle.alignment = .center 88 | let textFontAttributes = [ 89 | .font: UIFont.systemFont(ofSize: 7), 90 | .foregroundColor: UIColor.black, 91 | .paragraphStyle: textStyle, 92 | ] as [NSAttributedString.Key: Any] 93 | 94 | let textTextHeight: CGFloat = percentText.boundingRect(with: CGSize(width: textRect.width, height: CGFloat.infinity), options: .usesLineFragmentOrigin, attributes: textFontAttributes, context: nil).height 95 | context.saveGState() 96 | context.clip(to: textRect) 97 | percentText.draw(in: CGRect(x: textRect.minX, y: textRect.minY + (textRect.height - textTextHeight) / 2, width: textRect.width, height: textTextHeight), withAttributes: textFontAttributes) 98 | context.restoreGState() 99 | 100 | 101 | if (showTriangle) { 102 | //// Polygon Drawing 103 | context.saveGState() 104 | context.translateBy(x: progressWidthOffset, y: 9.5) 105 | 106 | let polygonPath = UIBezierPath() 107 | polygonPath.move(to: CGPoint(x: 3.5, y: 0)) 108 | polygonPath.addLine(to: CGPoint(x: 6.53, y: 5.25)) 109 | polygonPath.addLine(to: CGPoint(x: 0.47, y: 5.25)) 110 | polygonPath.close() 111 | progressBarColor.setFill() 112 | polygonPath.fill() 113 | 114 | context.restoreGState() 115 | } 116 | 117 | context.restoreGState() 118 | 119 | } 120 | 121 | @objc dynamic public class func drawProgressCircleDisplay(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 140, height: 140), resizing: ResizingBehavior = .aspectFit, progress: CGFloat = 0.723, showTriangle: Bool = true, progressColorRed: CGFloat = 0, progressColorGreen: CGFloat = 0.475, progressColorBlue: CGFloat = 1) { 122 | //// General Declarations 123 | let context = UIGraphicsGetCurrentContext()! 124 | 125 | //// Resize to Target Frame 126 | context.saveGState() 127 | let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 140, height: 140), target: targetFrame) 128 | context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) 129 | context.scaleBy(x: resizedFrame.width / 140, y: resizedFrame.height / 140) 130 | let resizedShadowScale: CGFloat = min(resizedFrame.width / 140, resizedFrame.height / 140) 131 | 132 | 133 | 134 | //// Shadow Declarations 135 | let shadow = NSShadow() 136 | shadow.shadowColor = UIColor.black.withAlphaComponent(0.23) 137 | shadow.shadowOffset = CGSize(width: 1, height: 1) 138 | shadow.shadowBlurRadius = 1 139 | 140 | //// Variable Declarations 141 | let progressEndAngle: CGFloat = progress == 1 ? 0.001 : 360 * (1 - progress) 142 | let percentText = "\(Int(round(round(progress * 100))))" + "%" 143 | let progressBarColor = UIColor(red: progressColorRed, green: progressColorGreen, blue: progressColorBlue, alpha: 1) 144 | 145 | //// Text Drawing 146 | let textRect = CGRect(x: 10, y: 56, width: 130, height: 28) 147 | let textStyle = NSMutableParagraphStyle() 148 | textStyle.alignment = .center 149 | let textFontAttributes = [ 150 | .font: UIFont.systemFont(ofSize: 31), 151 | .foregroundColor: UIColor.black, 152 | .paragraphStyle: textStyle, 153 | ] as [NSAttributedString.Key: Any] 154 | 155 | let textTextHeight: CGFloat = percentText.boundingRect(with: CGSize(width: textRect.width, height: CGFloat.infinity), options: .usesLineFragmentOrigin, attributes: textFontAttributes, context: nil).height 156 | context.saveGState() 157 | context.clip(to: textRect) 158 | percentText.draw(in: CGRect(x: textRect.minX, y: textRect.minY + (textRect.height - textTextHeight) / 2, width: textRect.width, height: textTextHeight), withAttributes: textFontAttributes) 159 | context.restoreGState() 160 | 161 | 162 | //// progressRingBackground Drawing 163 | context.saveGState() 164 | context.translateBy(x: 70, y: 70) 165 | context.rotate(by: -90 * CGFloat.pi/180) 166 | 167 | context.saveGState() 168 | context.setAlpha(0.2) 169 | context.beginTransparencyLayer(auxiliaryInfo: nil) 170 | 171 | let progressRingBackgroundPath = UIBezierPath(ovalIn: CGRect(x: -60, y: -60, width: 120, height: 120)) 172 | context.saveGState() 173 | context.setShadow(offset: CGSize(width: shadow.shadowOffset.width * resizedShadowScale, height: shadow.shadowOffset.height * resizedShadowScale), blur: shadow.shadowBlurRadius * resizedShadowScale, color: (shadow.shadowColor as! UIColor).cgColor) 174 | progressBarColor.setStroke() 175 | progressRingBackgroundPath.lineWidth = 7.5 176 | progressRingBackgroundPath.stroke() 177 | context.restoreGState() 178 | 179 | context.endTransparencyLayer() 180 | context.restoreGState() 181 | 182 | context.restoreGState() 183 | 184 | 185 | //// Oval Drawing 186 | context.saveGState() 187 | context.translateBy(x: 70, y: 70) 188 | context.rotate(by: -90 * CGFloat.pi/180) 189 | 190 | let ovalRect = CGRect(x: -60, y: -60, width: 120, height: 120) 191 | let ovalPath = UIBezierPath() 192 | ovalPath.addArc(withCenter: CGPoint(x: ovalRect.midX, y: ovalRect.midY), radius: ovalRect.width / 2, startAngle: 0 * CGFloat.pi/180, endAngle: -progressEndAngle * CGFloat.pi/180, clockwise: true) 193 | 194 | context.saveGState() 195 | context.setShadow(offset: CGSize(width: shadow.shadowOffset.width * resizedShadowScale, height: shadow.shadowOffset.height * resizedShadowScale), blur: shadow.shadowBlurRadius * resizedShadowScale, color: (shadow.shadowColor as! UIColor).cgColor) 196 | progressBarColor.setStroke() 197 | ovalPath.lineWidth = 7.5 198 | ovalPath.lineCapStyle = .round 199 | ovalPath.stroke() 200 | context.restoreGState() 201 | 202 | context.restoreGState() 203 | 204 | 205 | if (showTriangle) { 206 | //// Polygon Drawing 207 | context.saveGState() 208 | context.translateBy(x: 70, y: 70) 209 | context.rotate(by: -progressEndAngle * CGFloat.pi/180) 210 | 211 | let polygonPath = UIBezierPath() 212 | polygonPath.move(to: CGPoint(x: 0, y: -54)) 213 | polygonPath.addLine(to: CGPoint(x: 5.63, y: -43.5)) 214 | polygonPath.addLine(to: CGPoint(x: -5.63, y: -43.5)) 215 | polygonPath.close() 216 | progressBarColor.setFill() 217 | polygonPath.fill() 218 | 219 | context.restoreGState() 220 | } 221 | 222 | context.restoreGState() 223 | 224 | } 225 | 226 | @objc dynamic public class func drawProgressCircleDisplayWithTicks(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 140, height: 140), resizing: ResizingBehavior = .aspectFit, progress: CGFloat = 0.723, showTriangle: Bool = true, progressColorRed: CGFloat = 0, progressColorGreen: CGFloat = 0.475, progressColorBlue: CGFloat = 1) { 227 | //// General Declarations 228 | let context = UIGraphicsGetCurrentContext()! 229 | 230 | //// Resize to Target Frame 231 | context.saveGState() 232 | let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 140, height: 140), target: targetFrame) 233 | context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) 234 | context.scaleBy(x: resizedFrame.width / 140, y: resizedFrame.height / 140) 235 | let resizedShadowScale: CGFloat = min(resizedFrame.width / 140, resizedFrame.height / 140) 236 | 237 | 238 | 239 | //// Shadow Declarations 240 | let shadow = NSShadow() 241 | shadow.shadowColor = UIColor.black.withAlphaComponent(0.23) 242 | shadow.shadowOffset = CGSize(width: 1, height: 1) 243 | shadow.shadowBlurRadius = 1 244 | 245 | //// Variable Declarations 246 | let progressEndAngle: CGFloat = progress == 1 ? 0.001 : 360 * (1 - progress) 247 | let percentText = "\(Int(round(round(progress * 100))))" + "%" 248 | let progressBarColor = UIColor(red: progressColorRed, green: progressColorGreen, blue: progressColorBlue, alpha: 1) 249 | 250 | //// Text Drawing 251 | let textRect = CGRect(x: 10, y: 56, width: 130, height: 28) 252 | let textStyle = NSMutableParagraphStyle() 253 | textStyle.alignment = .center 254 | let textFontAttributes = [ 255 | .font: UIFont.systemFont(ofSize: 31), 256 | .foregroundColor: UIColor.black, 257 | .paragraphStyle: textStyle, 258 | ] as [NSAttributedString.Key: Any] 259 | 260 | let textTextHeight: CGFloat = percentText.boundingRect(with: CGSize(width: textRect.width, height: CGFloat.infinity), options: .usesLineFragmentOrigin, attributes: textFontAttributes, context: nil).height 261 | context.saveGState() 262 | context.clip(to: textRect) 263 | percentText.draw(in: CGRect(x: textRect.minX, y: textRect.minY + (textRect.height - textTextHeight) / 2, width: textRect.width, height: textTextHeight), withAttributes: textFontAttributes) 264 | context.restoreGState() 265 | 266 | 267 | //// progressRingBackground Drawing 268 | context.saveGState() 269 | context.translateBy(x: 70, y: 70) 270 | context.rotate(by: -90 * CGFloat.pi/180) 271 | 272 | let progressRingBackgroundPath = UIBezierPath(ovalIn: CGRect(x: -60, y: -60, width: 120, height: 120)) 273 | context.saveGState() 274 | context.setShadow(offset: CGSize(width: shadow.shadowOffset.width * resizedShadowScale, height: shadow.shadowOffset.height * resizedShadowScale), blur: shadow.shadowBlurRadius * resizedShadowScale, color: (shadow.shadowColor as! UIColor).cgColor) 275 | UIColor.black.setStroke() 276 | progressRingBackgroundPath.lineWidth = 5.5 277 | context.saveGState() 278 | context.setLineDash(phase: 0, lengths: [1, 5]) 279 | progressRingBackgroundPath.stroke() 280 | context.restoreGState() 281 | context.restoreGState() 282 | 283 | context.restoreGState() 284 | 285 | 286 | //// Oval Drawing 287 | context.saveGState() 288 | context.translateBy(x: 70, y: 70) 289 | context.rotate(by: -90 * CGFloat.pi/180) 290 | 291 | let ovalRect = CGRect(x: -60, y: -60, width: 120, height: 120) 292 | let ovalPath = UIBezierPath() 293 | ovalPath.addArc(withCenter: CGPoint(x: ovalRect.midX, y: ovalRect.midY), radius: ovalRect.width / 2, startAngle: 0 * CGFloat.pi/180, endAngle: -progressEndAngle * CGFloat.pi/180, clockwise: true) 294 | 295 | context.saveGState() 296 | context.setShadow(offset: CGSize(width: shadow.shadowOffset.width * resizedShadowScale, height: shadow.shadowOffset.height * resizedShadowScale), blur: shadow.shadowBlurRadius * resizedShadowScale, color: (shadow.shadowColor as! UIColor).cgColor) 297 | progressBarColor.setStroke() 298 | ovalPath.lineWidth = 7.5 299 | ovalPath.lineCapStyle = .round 300 | ovalPath.stroke() 301 | context.restoreGState() 302 | 303 | context.restoreGState() 304 | 305 | 306 | if (showTriangle) { 307 | //// Polygon Drawing 308 | context.saveGState() 309 | context.translateBy(x: 70, y: 70) 310 | context.rotate(by: -progressEndAngle * CGFloat.pi/180) 311 | 312 | let polygonPath = UIBezierPath() 313 | polygonPath.move(to: CGPoint(x: 0, y: -54)) 314 | polygonPath.addLine(to: CGPoint(x: 5.63, y: -43.5)) 315 | polygonPath.addLine(to: CGPoint(x: -5.63, y: -43.5)) 316 | polygonPath.close() 317 | progressBarColor.setFill() 318 | polygonPath.fill() 319 | 320 | context.restoreGState() 321 | } 322 | 323 | context.restoreGState() 324 | 325 | } 326 | 327 | 328 | 329 | 330 | @objc(ProgressStyleKitResizingBehavior) 331 | public enum ResizingBehavior: Int { 332 | case aspectFit /// The content is proportionally resized to fit into the target rectangle. 333 | case aspectFill /// The content is proportionally resized to completely fill the target rectangle. 334 | case stretch /// The content is stretched to match the entire target rectangle. 335 | case center /// The content is centered in the target rectangle, but it is NOT resized. 336 | 337 | public func apply(rect: CGRect, target: CGRect) -> CGRect { 338 | if rect == target || target == CGRect.zero { 339 | return rect 340 | } 341 | 342 | var scales = CGSize.zero 343 | scales.width = abs(target.width / rect.width) 344 | scales.height = abs(target.height / rect.height) 345 | 346 | switch self { 347 | case .aspectFit: 348 | scales.width = min(scales.width, scales.height) 349 | scales.height = scales.width 350 | case .aspectFill: 351 | scales.width = max(scales.width, scales.height) 352 | scales.height = scales.width 353 | case .stretch: 354 | break 355 | case .center: 356 | scales.width = 1 357 | scales.height = 1 358 | } 359 | 360 | var result = rect.standardized 361 | result.size.width *= scales.width 362 | result.size.height *= scales.height 363 | result.origin.x = target.minX + (target.width - result.width) / 2 364 | result.origin.y = target.minY + (target.height - result.height) / 2 365 | return result 366 | } 367 | } 368 | } 369 | -------------------------------------------------------------------------------- /Example/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /Sources/stylekit/ActivityStyleKit.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ActivityStyleKit.swift 3 | // ShowSomeProgress 4 | // 5 | // Created by Alexander Kasimir on 06.08.19. 6 | // Copyright © 2019 Alexander Kasimir. All rights reserved. 7 | // 8 | // Generated by PaintCode 9 | // http://www.paintcodeapp.com 10 | // 11 | 12 | 13 | 14 | import UIKit 15 | 16 | public class ActivityStyleKit : NSObject { 17 | 18 | //// Drawing Methods 19 | 20 | @objc dynamic public class func drawOrbitIndicator(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 78, height: 78), resizing: ResizingBehavior = .aspectFit, animationProgress: CGFloat = 0, progressColorRed: CGFloat = 0, progressColorGreen: CGFloat = 0.475, progressColorBlue: CGFloat = 1) { 21 | //// General Declarations 22 | let context = UIGraphicsGetCurrentContext()! 23 | 24 | //// Resize to Target Frame 25 | context.saveGState() 26 | let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 78, height: 78), target: targetFrame) 27 | context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) 28 | context.scaleBy(x: resizedFrame.width / 78, y: resizedFrame.height / 78) 29 | 30 | 31 | 32 | //// Variable Declarations 33 | let rotationOnce: CGFloat = 360 * animationProgress 34 | let rotationTwice: CGFloat = 360 * 2 * animationProgress 35 | let rotationThrice: CGFloat = 360 * 3 * animationProgress 36 | let progressBarColor = UIColor(red: progressColorRed, green: progressColorGreen, blue: progressColorBlue, alpha: 1) 37 | 38 | //// Outer Drawing 39 | context.saveGState() 40 | context.translateBy(x: 38.5, y: 38.5) 41 | context.rotate(by: -rotationOnce * CGFloat.pi/180) 42 | 43 | let outerPath = UIBezierPath(ovalIn: CGRect(x: -3.57, y: -33.42, width: 7, height: 7)) 44 | progressBarColor.setFill() 45 | outerPath.fill() 46 | 47 | context.restoreGState() 48 | 49 | 50 | //// Middle Drawing 51 | context.saveGState() 52 | context.translateBy(x: 38.5, y: 38.5) 53 | context.rotate(by: -rotationTwice * CGFloat.pi/180) 54 | 55 | let middlePath = UIBezierPath(ovalIn: CGRect(x: -3.5, y: -23.5, width: 7, height: 7)) 56 | progressBarColor.setFill() 57 | middlePath.fill() 58 | 59 | context.restoreGState() 60 | 61 | 62 | //// Inner Drawing 63 | context.saveGState() 64 | context.translateBy(x: 38.5, y: 38.5) 65 | context.rotate(by: -rotationThrice * CGFloat.pi/180) 66 | 67 | let innerPath = UIBezierPath(ovalIn: CGRect(x: -3.5, y: -13.5, width: 7, height: 7)) 68 | progressBarColor.setFill() 69 | innerPath.fill() 70 | 71 | context.restoreGState() 72 | 73 | 74 | //// Group 75 | //// OuterRing Drawing 76 | let outerRingPath = UIBezierPath(ovalIn: CGRect(x: 8.5, y: 8.5, width: 60, height: 60)) 77 | progressBarColor.setStroke() 78 | outerRingPath.lineWidth = 1 79 | outerRingPath.stroke() 80 | 81 | 82 | //// MiddleRing Drawing 83 | let middleRingPath = UIBezierPath(ovalIn: CGRect(x: 18.5, y: 18.5, width: 40, height: 40)) 84 | progressBarColor.setStroke() 85 | middleRingPath.lineWidth = 1 86 | middleRingPath.stroke() 87 | 88 | 89 | //// InnerRing Drawing 90 | let innerRingPath = UIBezierPath(ovalIn: CGRect(x: 28.5, y: 28.5, width: 20, height: 20)) 91 | progressBarColor.setStroke() 92 | innerRingPath.lineWidth = 1 93 | innerRingPath.stroke() 94 | 95 | context.restoreGState() 96 | 97 | } 98 | 99 | @objc dynamic public class func drawOrbitIndicator2(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 78, height: 78), resizing: ResizingBehavior = .aspectFit, animationProgress: CGFloat = 0, progressColorRed: CGFloat = 0, progressColorGreen: CGFloat = 0.475, progressColorBlue: CGFloat = 1) { 100 | //// General Declarations 101 | let context = UIGraphicsGetCurrentContext()! 102 | 103 | //// Resize to Target Frame 104 | context.saveGState() 105 | let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 78, height: 78), target: targetFrame) 106 | context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) 107 | context.scaleBy(x: resizedFrame.width / 78, y: resizedFrame.height / 78) 108 | 109 | 110 | 111 | //// Variable Declarations 112 | let rotationOnce: CGFloat = 360 * animationProgress 113 | let rotationTwice: CGFloat = 360 * 2 * animationProgress 114 | let rotationThrice: CGFloat = 360 * 3 * animationProgress 115 | let progressBarColor = UIColor(red: progressColorRed, green: progressColorGreen, blue: progressColorBlue, alpha: 1) 116 | 117 | //// Outer Drawing 118 | context.saveGState() 119 | context.translateBy(x: 39.01, y: 38.89) 120 | context.rotate(by: -rotationOnce * CGFloat.pi/180) 121 | 122 | let outerPath = UIBezierPath(ovalIn: CGRect(x: -3.52, y: -36.26, width: 7, height: 7)) 123 | progressBarColor.setFill() 124 | outerPath.fill() 125 | 126 | context.restoreGState() 127 | 128 | 129 | //// Inner Drawing 130 | context.saveGState() 131 | context.translateBy(x: 39.01, y: 38.89) 132 | context.rotate(by: -rotationThrice * CGFloat.pi/180) 133 | 134 | let innerPath = UIBezierPath(ovalIn: CGRect(x: -2.51, y: -14.52, width: 5, height: 5)) 135 | progressBarColor.setFill() 136 | innerPath.fill() 137 | 138 | context.restoreGState() 139 | 140 | 141 | //// Group 2 142 | context.saveGState() 143 | context.translateBy(x: 39.01, y: 38.89) 144 | context.rotate(by: -rotationTwice * CGFloat.pi/180) 145 | 146 | 147 | 148 | //// Middle Drawing 149 | context.saveGState() 150 | context.translateBy(x: 0.02, y: -0.26) 151 | context.rotate(by: -720 * CGFloat.pi/180) 152 | 153 | let middlePath = UIBezierPath(ovalIn: CGRect(x: -2.5, y: -22.5, width: 5, height: 5)) 154 | progressBarColor.setFill() 155 | middlePath.fill() 156 | 157 | context.restoreGState() 158 | 159 | 160 | //// Moon Drawing 161 | context.saveGState() 162 | context.translateBy(x: 0.1, y: -20.38) 163 | context.rotate(by: -rotationThrice * CGFloat.pi/180) 164 | 165 | let moonPath = UIBezierPath(ovalIn: CGRect(x: -1.14, y: -5.47, width: 2, height: 2)) 166 | progressBarColor.setFill() 167 | moonPath.fill() 168 | 169 | context.restoreGState() 170 | 171 | 172 | 173 | context.restoreGState() 174 | 175 | 176 | //// Center Drawing 177 | let centerPath = UIBezierPath(ovalIn: CGRect(x: 34.5, y: 34.5, width: 9, height: 9)) 178 | progressBarColor.setFill() 179 | centerPath.fill() 180 | 181 | 182 | //// Group 183 | //// OuterRing Drawing 184 | let outerRingPath = UIBezierPath(ovalIn: CGRect(x: 5.9, y: 6.29, width: 66.12, height: 65.62)) 185 | progressBarColor.setStroke() 186 | outerRingPath.lineWidth = 1 187 | outerRingPath.stroke() 188 | 189 | 190 | //// MiddleRing Drawing 191 | let middleRingPath = UIBezierPath(ovalIn: CGRect(x: 18.47, y: 18.66, width: 40.87, height: 40.87)) 192 | progressBarColor.setStroke() 193 | middleRingPath.lineWidth = 1 194 | middleRingPath.stroke() 195 | 196 | 197 | //// InnerRing Drawing 198 | let innerRingPath = UIBezierPath(ovalIn: CGRect(x: 27, y: 27, width: 24, height: 24)) 199 | progressBarColor.setStroke() 200 | innerRingPath.lineWidth = 1 201 | innerRingPath.stroke() 202 | 203 | context.restoreGState() 204 | 205 | } 206 | 207 | @objc dynamic public class func drawOrbitIndicator3(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 78, height: 78), resizing: ResizingBehavior = .aspectFit, animationProgress: CGFloat = 0, progressColorRed: CGFloat = 0, progressColorGreen: CGFloat = 0.475, progressColorBlue: CGFloat = 1) { 208 | //// General Declarations 209 | let context = UIGraphicsGetCurrentContext()! 210 | 211 | //// Resize to Target Frame 212 | context.saveGState() 213 | let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 78, height: 78), target: targetFrame) 214 | context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) 215 | context.scaleBy(x: resizedFrame.width / 78, y: resizedFrame.height / 78) 216 | 217 | 218 | 219 | //// Variable Declarations 220 | let rotationOnce: CGFloat = 360 * animationProgress 221 | let rotationTwice: CGFloat = 360 * 2 * animationProgress 222 | let rotationThrice: CGFloat = 360 * 3 * animationProgress 223 | let progressBarColor = UIColor(red: progressColorRed, green: progressColorGreen, blue: progressColorBlue, alpha: 1) 224 | 225 | //// OuterRing Drawing 226 | let outerRingPath = UIBezierPath(ovalIn: CGRect(x: 9, y: 8.5, width: 60, height: 60)) 227 | progressBarColor.setStroke() 228 | outerRingPath.lineWidth = 2 229 | outerRingPath.stroke() 230 | 231 | 232 | //// Outer Drawing 233 | context.saveGState() 234 | context.translateBy(x: 38.5, y: 38.5) 235 | context.rotate(by: -rotationOnce * CGFloat.pi/180) 236 | 237 | let outerPath = UIBezierPath(ovalIn: CGRect(x: -2.78, y: -33.3, width: 7, height: 7)) 238 | progressBarColor.setFill() 239 | outerPath.fill() 240 | 241 | context.restoreGState() 242 | 243 | 244 | //// Outer 2 Drawing 245 | context.saveGState() 246 | context.translateBy(x: 38.5, y: 38.5) 247 | context.rotate(by: -rotationTwice * CGFloat.pi/180) 248 | 249 | let outer2Path = UIBezierPath(ovalIn: CGRect(x: -2.78, y: -33.3, width: 7, height: 7)) 250 | progressBarColor.setFill() 251 | outer2Path.fill() 252 | 253 | context.restoreGState() 254 | 255 | 256 | //// Outer 3 Drawing 257 | context.saveGState() 258 | context.translateBy(x: 38.5, y: 38.5) 259 | context.rotate(by: -rotationThrice * CGFloat.pi/180) 260 | 261 | let outer3Path = UIBezierPath(ovalIn: CGRect(x: -2.78, y: -33.3, width: 7, height: 7)) 262 | progressBarColor.setFill() 263 | outer3Path.fill() 264 | 265 | context.restoreGState() 266 | 267 | context.restoreGState() 268 | 269 | } 270 | 271 | @objc dynamic public class func drawTripleGears(frame targetFrame: CGRect = CGRect(x: 0, y: 0, width: 168, height: 177), resizing: ResizingBehavior = .aspectFit, animationProgress: CGFloat = 0, progressColorRed: CGFloat = 0, progressColorGreen: CGFloat = 0.475, progressColorBlue: CGFloat = 1) { 272 | //// General Declarations 273 | let context = UIGraphicsGetCurrentContext()! 274 | 275 | //// Resize to Target Frame 276 | context.saveGState() 277 | let resizedFrame: CGRect = resizing.apply(rect: CGRect(x: 0, y: 0, width: 168, height: 177), target: targetFrame) 278 | context.translateBy(x: resizedFrame.minX, y: resizedFrame.minY) 279 | context.scaleBy(x: resizedFrame.width / 168, y: resizedFrame.height / 177) 280 | 281 | 282 | 283 | //// Variable Declarations 284 | let gear1Rotation: CGFloat = animationProgress * 360 * 2 285 | let gear2Rotation: CGFloat = -(animationProgress * 360) 286 | let progressBarColor = UIColor(red: progressColorRed, green: progressColorGreen, blue: progressColorBlue, alpha: 1) 287 | let lightProgressBarColor = UIColor(red: progressColorRed + 0.2, green: progressColorGreen + 0.2, blue: progressColorBlue + 0.2, alpha: 1) 288 | 289 | //// Small Top Gear Drawing 290 | context.saveGState() 291 | context.translateBy(x: 36.02, y: 38.27) 292 | context.rotate(by: -gear1Rotation * CGFloat.pi/180) 293 | 294 | let smallTopGearPath = UIBezierPath() 295 | smallTopGearPath.move(to: CGPoint(x: -2.49, y: -33.46)) 296 | smallTopGearPath.addCurve(to: CGPoint(x: 3.07, y: -24.18), controlPoint1: CGPoint(x: -2.5, y: -33.47), controlPoint2: CGPoint(x: 3.02, y: -28.06)) 297 | smallTopGearPath.addCurve(to: CGPoint(x: 2.24, y: -18.71), controlPoint1: CGPoint(x: 3.09, y: -22.77), controlPoint2: CGPoint(x: 2.57, y: -20.17)) 298 | smallTopGearPath.addCurve(to: CGPoint(x: 8.37, y: -16.87), controlPoint1: CGPoint(x: 4.37, y: -18.45), controlPoint2: CGPoint(x: 6.44, y: -17.83)) 299 | smallTopGearPath.addCurve(to: CGPoint(x: 11.63, y: -22.88), controlPoint1: CGPoint(x: 8.86, y: -18.34), controlPoint2: CGPoint(x: 10.05, y: -21.52)) 300 | smallTopGearPath.addCurve(to: CGPoint(x: 20.66, y: -26.7), controlPoint1: CGPoint(x: 14.71, y: -25.57), controlPoint2: CGPoint(x: 20.66, y: -26.7)) 301 | smallTopGearPath.addLine(to: CGPoint(x: 22.07, y: -25.28)) 302 | smallTopGearPath.addCurve(to: CGPoint(x: 19.37, y: -14.8), controlPoint1: CGPoint(x: 22.07, y: -25.28), controlPoint2: CGPoint(x: 22.09, y: -17.55)) 303 | smallTopGearPath.addCurve(to: CGPoint(x: 14.9, y: -11.55), controlPoint1: CGPoint(x: 18.38, y: -13.79), controlPoint2: CGPoint(x: 16.16, y: -12.34)) 304 | smallTopGearPath.addCurve(to: CGPoint(x: 16.03, y: -9.92), controlPoint1: CGPoint(x: 15.3, y: -11.03), controlPoint2: CGPoint(x: 15.68, y: -10.49)) 305 | smallTopGearPath.addCurve(to: CGPoint(x: 17.86, y: -6.1), controlPoint1: CGPoint(x: 16.8, y: -8.7), controlPoint2: CGPoint(x: 17.41, y: -7.42)) 306 | smallTopGearPath.addCurve(to: CGPoint(x: 24.37, y: -8.06), controlPoint1: CGPoint(x: 19.27, y: -6.81), controlPoint2: CGPoint(x: 22.31, y: -8.19)) 307 | smallTopGearPath.addCurve(to: CGPoint(x: 33.47, y: -4.41), controlPoint1: CGPoint(x: 28.45, y: -7.79), controlPoint2: CGPoint(x: 33.47, y: -4.41)) 308 | smallTopGearPath.addLine(to: CGPoint(x: 33.47, y: -2.41)) 309 | smallTopGearPath.addCurve(to: CGPoint(x: 24.17, y: 3.14), controlPoint1: CGPoint(x: 33.47, y: -2.41), controlPoint2: CGPoint(x: 28.05, y: 3.1)) 310 | smallTopGearPath.addCurve(to: CGPoint(x: 18.79, y: 2.31), controlPoint1: CGPoint(x: 22.78, y: 3.15), controlPoint2: CGPoint(x: 20.27, y: 2.64)) 311 | smallTopGearPath.addCurve(to: CGPoint(x: 17.09, y: 8.3), controlPoint1: CGPoint(x: 18.56, y: 4.38), controlPoint2: CGPoint(x: 17.98, y: 6.41)) 312 | smallTopGearPath.addCurve(to: CGPoint(x: 22.97, y: 11.46), controlPoint1: CGPoint(x: 18.62, y: 8.81), controlPoint2: CGPoint(x: 21.63, y: 9.95)) 313 | smallTopGearPath.addCurve(to: CGPoint(x: 26.84, y: 20.47), controlPoint1: CGPoint(x: 25.67, y: 14.53), controlPoint2: CGPoint(x: 26.84, y: 20.47)) 314 | smallTopGearPath.addLine(to: CGPoint(x: 25.44, y: 21.89)) 315 | smallTopGearPath.addCurve(to: CGPoint(x: 14.94, y: 19.26), controlPoint1: CGPoint(x: 25.44, y: 21.89), controlPoint2: CGPoint(x: 17.71, y: 21.97)) 316 | smallTopGearPath.addCurve(to: CGPoint(x: 11.78, y: 15.01), controlPoint1: CGPoint(x: 13.97, y: 18.33), controlPoint2: CGPoint(x: 12.6, y: 16.29)) 317 | smallTopGearPath.addCurve(to: CGPoint(x: 9.98, y: 16.28), controlPoint1: CGPoint(x: 11.21, y: 15.46), controlPoint2: CGPoint(x: 10.61, y: 15.88)) 318 | smallTopGearPath.addCurve(to: CGPoint(x: 6.26, y: 18.07), controlPoint1: CGPoint(x: 8.79, y: 17.02), controlPoint2: CGPoint(x: 7.54, y: 17.62)) 319 | smallTopGearPath.addCurve(to: CGPoint(x: 8.12, y: 24.35), controlPoint1: CGPoint(x: 7, y: 19.56), controlPoint2: CGPoint(x: 8.24, y: 22.39)) 320 | smallTopGearPath.addCurve(to: CGPoint(x: 4.49, y: 33.46), controlPoint1: CGPoint(x: 7.87, y: 28.43), controlPoint2: CGPoint(x: 4.49, y: 33.46)) 321 | smallTopGearPath.addLine(to: CGPoint(x: 2.5, y: 33.47)) 322 | smallTopGearPath.addCurve(to: CGPoint(x: -3.07, y: 24.18), controlPoint1: CGPoint(x: 2.5, y: 33.47), controlPoint2: CGPoint(x: -3.02, y: 28.06)) 323 | smallTopGearPath.addCurve(to: CGPoint(x: -2.31, y: 19.03), controlPoint1: CGPoint(x: -3.09, y: 22.86), controlPoint2: CGPoint(x: -2.64, y: 20.52)) 324 | smallTopGearPath.addCurve(to: CGPoint(x: -8.49, y: 17.21), controlPoint1: CGPoint(x: -4.45, y: 18.78), controlPoint2: CGPoint(x: -6.54, y: 18.16)) 325 | smallTopGearPath.addCurve(to: CGPoint(x: -11.63, y: 22.88), controlPoint1: CGPoint(x: -9.03, y: 18.79), controlPoint2: CGPoint(x: -10.17, y: 21.61)) 326 | smallTopGearPath.addCurve(to: CGPoint(x: -20.66, y: 26.7), controlPoint1: CGPoint(x: -14.71, y: 25.57), controlPoint2: CGPoint(x: -20.66, y: 26.7)) 327 | smallTopGearPath.addLine(to: CGPoint(x: -22.07, y: 25.28)) 328 | smallTopGearPath.addCurve(to: CGPoint(x: -19.37, y: 14.8), controlPoint1: CGPoint(x: -22.07, y: 25.28), controlPoint2: CGPoint(x: -22.09, y: 17.55)) 329 | smallTopGearPath.addCurve(to: CGPoint(x: -15.18, y: 11.73), controlPoint1: CGPoint(x: -18.45, y: 13.86), controlPoint2: CGPoint(x: -16.47, y: 12.54)) 330 | smallTopGearPath.addCurve(to: CGPoint(x: -16.22, y: 10.23), controlPoint1: CGPoint(x: -15.54, y: 11.25), controlPoint2: CGPoint(x: -15.89, y: 10.75)) 331 | smallTopGearPath.addCurve(to: CGPoint(x: -18.11, y: 6.23), controlPoint1: CGPoint(x: -17.02, y: 8.94), controlPoint2: CGPoint(x: -17.65, y: 7.6)) 332 | smallTopGearPath.addCurve(to: CGPoint(x: -24.37, y: 8.06), controlPoint1: CGPoint(x: -19.6, y: 6.96), controlPoint2: CGPoint(x: -22.42, y: 8.19)) 333 | smallTopGearPath.addCurve(to: CGPoint(x: -33.47, y: 4.41), controlPoint1: CGPoint(x: -28.45, y: 7.79), controlPoint2: CGPoint(x: -33.47, y: 4.41)) 334 | smallTopGearPath.addLine(to: CGPoint(x: -33.47, y: 2.41)) 335 | smallTopGearPath.addCurve(to: CGPoint(x: -24.17, y: -3.14), controlPoint1: CGPoint(x: -33.47, y: 2.41), controlPoint2: CGPoint(x: -28.05, y: -3.1)) 336 | smallTopGearPath.addCurve(to: CGPoint(x: -18.94, y: -2.34), controlPoint1: CGPoint(x: -22.83, y: -3.15), controlPoint2: CGPoint(x: -20.42, y: -2.67)) 337 | smallTopGearPath.addCurve(to: CGPoint(x: -17.12, y: -8.31), controlPoint1: CGPoint(x: -18.66, y: -4.41), controlPoint2: CGPoint(x: -18.05, y: -6.43)) 338 | smallTopGearPath.addCurve(to: CGPoint(x: -22.97, y: -11.46), controlPoint1: CGPoint(x: -18.66, y: -8.82), controlPoint2: CGPoint(x: -21.64, y: -9.96)) 339 | smallTopGearPath.addCurve(to: CGPoint(x: -26.84, y: -20.47), controlPoint1: CGPoint(x: -25.67, y: -14.53), controlPoint2: CGPoint(x: -26.84, y: -20.47)) 340 | smallTopGearPath.addCurve(to: CGPoint(x: -26.58, y: -20.74), controlPoint1: CGPoint(x: -26.84, y: -20.47), controlPoint2: CGPoint(x: -26.73, y: -20.58)) 341 | smallTopGearPath.addCurve(to: CGPoint(x: -25.44, y: -21.89), controlPoint1: CGPoint(x: -26.17, y: -21.15), controlPoint2: CGPoint(x: -25.44, y: -21.89)) 342 | smallTopGearPath.addCurve(to: CGPoint(x: -14.94, y: -19.27), controlPoint1: CGPoint(x: -25.44, y: -21.89), controlPoint2: CGPoint(x: -17.71, y: -21.97)) 343 | smallTopGearPath.addCurve(to: CGPoint(x: -11.71, y: -14.9), controlPoint1: CGPoint(x: -13.94, y: -18.3), controlPoint2: CGPoint(x: -12.52, y: -16.17)) 344 | smallTopGearPath.addCurve(to: CGPoint(x: -10.17, y: -15.97), controlPoint1: CGPoint(x: -11.22, y: -15.28), controlPoint2: CGPoint(x: -10.7, y: -15.64)) 345 | smallTopGearPath.addCurve(to: CGPoint(x: -6.16, y: -17.87), controlPoint1: CGPoint(x: -8.88, y: -16.77), controlPoint2: CGPoint(x: -7.54, y: -17.41)) 346 | smallTopGearPath.addCurve(to: CGPoint(x: -8.12, y: -24.35), controlPoint1: CGPoint(x: -6.87, y: -19.28), controlPoint2: CGPoint(x: -8.25, y: -22.3)) 347 | smallTopGearPath.addCurve(to: CGPoint(x: -4.49, y: -33.46), controlPoint1: CGPoint(x: -7.87, y: -28.43), controlPoint2: CGPoint(x: -4.49, y: -33.46)) 348 | smallTopGearPath.addLine(to: CGPoint(x: -2.5, y: -33.47)) 349 | smallTopGearPath.addLine(to: CGPoint(x: -2.49, y: -33.46)) 350 | smallTopGearPath.close() 351 | smallTopGearPath.move(to: CGPoint(x: 0, y: -10)) 352 | smallTopGearPath.addCurve(to: CGPoint(x: -2.41, y: -9.71), controlPoint1: CGPoint(x: -0.83, y: -10), controlPoint2: CGPoint(x: -1.64, y: -9.9)) 353 | smallTopGearPath.addCurve(to: CGPoint(x: -10, y: 0), controlPoint1: CGPoint(x: -6.77, y: -8.63), controlPoint2: CGPoint(x: -10, y: -4.69)) 354 | smallTopGearPath.addCurve(to: CGPoint(x: 0, y: 10), controlPoint1: CGPoint(x: -10, y: 5.52), controlPoint2: CGPoint(x: -5.52, y: 10)) 355 | smallTopGearPath.addCurve(to: CGPoint(x: 10, y: 0), controlPoint1: CGPoint(x: 5.52, y: 10), controlPoint2: CGPoint(x: 10, y: 5.52)) 356 | smallTopGearPath.addCurve(to: CGPoint(x: 0, y: -10), controlPoint1: CGPoint(x: 10, y: -5.52), controlPoint2: CGPoint(x: 5.52, y: -10)) 357 | smallTopGearPath.close() 358 | lightProgressBarColor.setFill() 359 | smallTopGearPath.fill() 360 | progressBarColor.setStroke() 361 | smallTopGearPath.lineWidth = 1.5 362 | smallTopGearPath.stroke() 363 | 364 | context.restoreGState() 365 | 366 | 367 | //// Small Bottom Gear Drawing 368 | context.saveGState() 369 | context.translateBy(x: 41.79, y: 139.2) 370 | context.rotate(by: -(gear1Rotation - 360) * CGFloat.pi/180) 371 | 372 | let smallBottomGearPath = UIBezierPath() 373 | smallBottomGearPath.move(to: CGPoint(x: -2.49, y: -33.46)) 374 | smallBottomGearPath.addCurve(to: CGPoint(x: 3.07, y: -24.18), controlPoint1: CGPoint(x: -2.5, y: -33.47), controlPoint2: CGPoint(x: 3.02, y: -28.06)) 375 | smallBottomGearPath.addCurve(to: CGPoint(x: 2.24, y: -18.71), controlPoint1: CGPoint(x: 3.09, y: -22.77), controlPoint2: CGPoint(x: 2.57, y: -20.17)) 376 | smallBottomGearPath.addCurve(to: CGPoint(x: 8.37, y: -16.87), controlPoint1: CGPoint(x: 4.37, y: -18.45), controlPoint2: CGPoint(x: 6.44, y: -17.83)) 377 | smallBottomGearPath.addCurve(to: CGPoint(x: 11.63, y: -22.88), controlPoint1: CGPoint(x: 8.86, y: -18.34), controlPoint2: CGPoint(x: 10.05, y: -21.52)) 378 | smallBottomGearPath.addCurve(to: CGPoint(x: 20.66, y: -26.7), controlPoint1: CGPoint(x: 14.71, y: -25.57), controlPoint2: CGPoint(x: 20.66, y: -26.7)) 379 | smallBottomGearPath.addLine(to: CGPoint(x: 22.07, y: -25.28)) 380 | smallBottomGearPath.addCurve(to: CGPoint(x: 19.37, y: -14.8), controlPoint1: CGPoint(x: 22.07, y: -25.28), controlPoint2: CGPoint(x: 22.09, y: -17.55)) 381 | smallBottomGearPath.addCurve(to: CGPoint(x: 14.9, y: -11.55), controlPoint1: CGPoint(x: 18.38, y: -13.79), controlPoint2: CGPoint(x: 16.16, y: -12.34)) 382 | smallBottomGearPath.addCurve(to: CGPoint(x: 16.03, y: -9.92), controlPoint1: CGPoint(x: 15.3, y: -11.03), controlPoint2: CGPoint(x: 15.68, y: -10.49)) 383 | smallBottomGearPath.addCurve(to: CGPoint(x: 17.86, y: -6.1), controlPoint1: CGPoint(x: 16.8, y: -8.7), controlPoint2: CGPoint(x: 17.41, y: -7.42)) 384 | smallBottomGearPath.addCurve(to: CGPoint(x: 24.37, y: -8.06), controlPoint1: CGPoint(x: 19.27, y: -6.81), controlPoint2: CGPoint(x: 22.31, y: -8.19)) 385 | smallBottomGearPath.addCurve(to: CGPoint(x: 33.47, y: -4.41), controlPoint1: CGPoint(x: 28.45, y: -7.79), controlPoint2: CGPoint(x: 33.47, y: -4.41)) 386 | smallBottomGearPath.addLine(to: CGPoint(x: 33.47, y: -2.41)) 387 | smallBottomGearPath.addCurve(to: CGPoint(x: 24.17, y: 3.14), controlPoint1: CGPoint(x: 33.47, y: -2.41), controlPoint2: CGPoint(x: 28.05, y: 3.1)) 388 | smallBottomGearPath.addCurve(to: CGPoint(x: 18.79, y: 2.31), controlPoint1: CGPoint(x: 22.78, y: 3.15), controlPoint2: CGPoint(x: 20.27, y: 2.64)) 389 | smallBottomGearPath.addCurve(to: CGPoint(x: 17.09, y: 8.3), controlPoint1: CGPoint(x: 18.56, y: 4.38), controlPoint2: CGPoint(x: 17.98, y: 6.41)) 390 | smallBottomGearPath.addCurve(to: CGPoint(x: 22.97, y: 11.46), controlPoint1: CGPoint(x: 18.62, y: 8.81), controlPoint2: CGPoint(x: 21.63, y: 9.95)) 391 | smallBottomGearPath.addCurve(to: CGPoint(x: 26.84, y: 20.47), controlPoint1: CGPoint(x: 25.67, y: 14.53), controlPoint2: CGPoint(x: 26.84, y: 20.47)) 392 | smallBottomGearPath.addLine(to: CGPoint(x: 25.44, y: 21.89)) 393 | smallBottomGearPath.addCurve(to: CGPoint(x: 14.94, y: 19.26), controlPoint1: CGPoint(x: 25.44, y: 21.89), controlPoint2: CGPoint(x: 17.71, y: 21.97)) 394 | smallBottomGearPath.addCurve(to: CGPoint(x: 11.78, y: 15.01), controlPoint1: CGPoint(x: 13.97, y: 18.33), controlPoint2: CGPoint(x: 12.6, y: 16.29)) 395 | smallBottomGearPath.addCurve(to: CGPoint(x: 9.98, y: 16.28), controlPoint1: CGPoint(x: 11.21, y: 15.46), controlPoint2: CGPoint(x: 10.61, y: 15.88)) 396 | smallBottomGearPath.addCurve(to: CGPoint(x: 6.26, y: 18.07), controlPoint1: CGPoint(x: 8.79, y: 17.02), controlPoint2: CGPoint(x: 7.54, y: 17.62)) 397 | smallBottomGearPath.addCurve(to: CGPoint(x: 8.12, y: 24.35), controlPoint1: CGPoint(x: 7, y: 19.56), controlPoint2: CGPoint(x: 8.24, y: 22.39)) 398 | smallBottomGearPath.addCurve(to: CGPoint(x: 4.49, y: 33.46), controlPoint1: CGPoint(x: 7.87, y: 28.43), controlPoint2: CGPoint(x: 4.49, y: 33.46)) 399 | smallBottomGearPath.addLine(to: CGPoint(x: 2.5, y: 33.47)) 400 | smallBottomGearPath.addCurve(to: CGPoint(x: -3.07, y: 24.18), controlPoint1: CGPoint(x: 2.5, y: 33.47), controlPoint2: CGPoint(x: -3.02, y: 28.06)) 401 | smallBottomGearPath.addCurve(to: CGPoint(x: -2.31, y: 19.03), controlPoint1: CGPoint(x: -3.09, y: 22.86), controlPoint2: CGPoint(x: -2.64, y: 20.52)) 402 | smallBottomGearPath.addCurve(to: CGPoint(x: -8.49, y: 17.21), controlPoint1: CGPoint(x: -4.45, y: 18.78), controlPoint2: CGPoint(x: -6.54, y: 18.16)) 403 | smallBottomGearPath.addCurve(to: CGPoint(x: -11.63, y: 22.88), controlPoint1: CGPoint(x: -9.03, y: 18.79), controlPoint2: CGPoint(x: -10.17, y: 21.61)) 404 | smallBottomGearPath.addCurve(to: CGPoint(x: -20.66, y: 26.7), controlPoint1: CGPoint(x: -14.71, y: 25.57), controlPoint2: CGPoint(x: -20.66, y: 26.7)) 405 | smallBottomGearPath.addLine(to: CGPoint(x: -22.07, y: 25.28)) 406 | smallBottomGearPath.addCurve(to: CGPoint(x: -19.37, y: 14.8), controlPoint1: CGPoint(x: -22.07, y: 25.28), controlPoint2: CGPoint(x: -22.09, y: 17.55)) 407 | smallBottomGearPath.addCurve(to: CGPoint(x: -15.18, y: 11.73), controlPoint1: CGPoint(x: -18.45, y: 13.86), controlPoint2: CGPoint(x: -16.47, y: 12.54)) 408 | smallBottomGearPath.addCurve(to: CGPoint(x: -16.22, y: 10.23), controlPoint1: CGPoint(x: -15.54, y: 11.25), controlPoint2: CGPoint(x: -15.89, y: 10.75)) 409 | smallBottomGearPath.addCurve(to: CGPoint(x: -18.11, y: 6.23), controlPoint1: CGPoint(x: -17.02, y: 8.94), controlPoint2: CGPoint(x: -17.65, y: 7.6)) 410 | smallBottomGearPath.addCurve(to: CGPoint(x: -24.37, y: 8.06), controlPoint1: CGPoint(x: -19.6, y: 6.96), controlPoint2: CGPoint(x: -22.42, y: 8.19)) 411 | smallBottomGearPath.addCurve(to: CGPoint(x: -33.47, y: 4.41), controlPoint1: CGPoint(x: -28.45, y: 7.79), controlPoint2: CGPoint(x: -33.47, y: 4.41)) 412 | smallBottomGearPath.addLine(to: CGPoint(x: -33.47, y: 2.41)) 413 | smallBottomGearPath.addCurve(to: CGPoint(x: -24.17, y: -3.14), controlPoint1: CGPoint(x: -33.47, y: 2.41), controlPoint2: CGPoint(x: -28.05, y: -3.1)) 414 | smallBottomGearPath.addCurve(to: CGPoint(x: -18.94, y: -2.34), controlPoint1: CGPoint(x: -22.83, y: -3.15), controlPoint2: CGPoint(x: -20.42, y: -2.67)) 415 | smallBottomGearPath.addCurve(to: CGPoint(x: -17.12, y: -8.31), controlPoint1: CGPoint(x: -18.66, y: -4.41), controlPoint2: CGPoint(x: -18.05, y: -6.43)) 416 | smallBottomGearPath.addCurve(to: CGPoint(x: -22.97, y: -11.46), controlPoint1: CGPoint(x: -18.66, y: -8.82), controlPoint2: CGPoint(x: -21.64, y: -9.96)) 417 | smallBottomGearPath.addCurve(to: CGPoint(x: -26.84, y: -20.47), controlPoint1: CGPoint(x: -25.67, y: -14.53), controlPoint2: CGPoint(x: -26.84, y: -20.47)) 418 | smallBottomGearPath.addCurve(to: CGPoint(x: -26.58, y: -20.74), controlPoint1: CGPoint(x: -26.84, y: -20.47), controlPoint2: CGPoint(x: -26.73, y: -20.58)) 419 | smallBottomGearPath.addCurve(to: CGPoint(x: -25.44, y: -21.89), controlPoint1: CGPoint(x: -26.17, y: -21.15), controlPoint2: CGPoint(x: -25.44, y: -21.89)) 420 | smallBottomGearPath.addCurve(to: CGPoint(x: -14.94, y: -19.27), controlPoint1: CGPoint(x: -25.44, y: -21.89), controlPoint2: CGPoint(x: -17.71, y: -21.97)) 421 | smallBottomGearPath.addCurve(to: CGPoint(x: -11.71, y: -14.9), controlPoint1: CGPoint(x: -13.94, y: -18.3), controlPoint2: CGPoint(x: -12.52, y: -16.17)) 422 | smallBottomGearPath.addCurve(to: CGPoint(x: -10.17, y: -15.97), controlPoint1: CGPoint(x: -11.22, y: -15.28), controlPoint2: CGPoint(x: -10.7, y: -15.64)) 423 | smallBottomGearPath.addCurve(to: CGPoint(x: -6.16, y: -17.87), controlPoint1: CGPoint(x: -8.88, y: -16.77), controlPoint2: CGPoint(x: -7.54, y: -17.41)) 424 | smallBottomGearPath.addCurve(to: CGPoint(x: -8.12, y: -24.35), controlPoint1: CGPoint(x: -6.87, y: -19.28), controlPoint2: CGPoint(x: -8.25, y: -22.3)) 425 | smallBottomGearPath.addCurve(to: CGPoint(x: -4.49, y: -33.46), controlPoint1: CGPoint(x: -7.87, y: -28.43), controlPoint2: CGPoint(x: -4.49, y: -33.46)) 426 | smallBottomGearPath.addLine(to: CGPoint(x: -2.5, y: -33.47)) 427 | smallBottomGearPath.addLine(to: CGPoint(x: -2.49, y: -33.46)) 428 | smallBottomGearPath.close() 429 | smallBottomGearPath.move(to: CGPoint(x: 0, y: -10)) 430 | smallBottomGearPath.addCurve(to: CGPoint(x: -2.41, y: -9.71), controlPoint1: CGPoint(x: -0.83, y: -10), controlPoint2: CGPoint(x: -1.64, y: -9.9)) 431 | smallBottomGearPath.addCurve(to: CGPoint(x: -10, y: 0), controlPoint1: CGPoint(x: -6.77, y: -8.63), controlPoint2: CGPoint(x: -10, y: -4.69)) 432 | smallBottomGearPath.addCurve(to: CGPoint(x: 0, y: 10), controlPoint1: CGPoint(x: -10, y: 5.52), controlPoint2: CGPoint(x: -5.52, y: 10)) 433 | smallBottomGearPath.addCurve(to: CGPoint(x: 10, y: 0), controlPoint1: CGPoint(x: 5.52, y: 10), controlPoint2: CGPoint(x: 10, y: 5.52)) 434 | smallBottomGearPath.addCurve(to: CGPoint(x: 0, y: -10), controlPoint1: CGPoint(x: 10, y: -5.52), controlPoint2: CGPoint(x: 5.52, y: -10)) 435 | smallBottomGearPath.close() 436 | lightProgressBarColor.setFill() 437 | smallBottomGearPath.fill() 438 | progressBarColor.setStroke() 439 | smallBottomGearPath.lineWidth = 1.5 440 | smallBottomGearPath.stroke() 441 | 442 | context.restoreGState() 443 | 444 | 445 | //// Big Gear Drawing 446 | context.saveGState() 447 | context.translateBy(x: 104.86, y: 85.15) 448 | context.rotate(by: -gear2Rotation * CGFloat.pi/180) 449 | 450 | let bigGearPath = UIBezierPath() 451 | bigGearPath.move(to: CGPoint(x: 4.44, y: -51)) 452 | bigGearPath.addCurve(to: CGPoint(x: 4.69, y: -45.99), controlPoint1: CGPoint(x: 4.86, y: -49.62), controlPoint2: CGPoint(x: 4.95, y: -47.74)) 453 | bigGearPath.addCurve(to: CGPoint(x: 10.17, y: -45.08), controlPoint1: CGPoint(x: 6.55, y: -45.8), controlPoint2: CGPoint(x: 8.38, y: -45.49)) 454 | bigGearPath.addCurve(to: CGPoint(x: 12.47, y: -50.32), controlPoint1: CGPoint(x: 10.37, y: -46.61), controlPoint2: CGPoint(x: 11.03, y: -48.7)) 455 | bigGearPath.addCurve(to: CGPoint(x: 20.09, y: -57.19), controlPoint1: CGPoint(x: 15.05, y: -53.2), controlPoint2: CGPoint(x: 16.89, y: -55.29)) 456 | bigGearPath.addLine(to: CGPoint(x: 22.36, y: -56.29)) 457 | bigGearPath.addCurve(to: CGPoint(x: 23.42, y: -45.49), controlPoint1: CGPoint(x: 23.25, y: -52.48), controlPoint2: CGPoint(x: 23.7, y: -48.32)) 458 | bigGearPath.addCurve(to: CGPoint(x: 21.72, y: -40.7), controlPoint1: CGPoint(x: 23.28, y: -44.04), controlPoint2: CGPoint(x: 22.64, y: -42.23)) 459 | bigGearPath.addCurve(to: CGPoint(x: 26.6, y: -37.64), controlPoint1: CGPoint(x: 23.41, y: -39.78), controlPoint2: CGPoint(x: 25.04, y: -38.76)) 460 | bigGearPath.addCurve(to: CGPoint(x: 30.77, y: -41.67), controlPoint1: CGPoint(x: 27.36, y: -38.99), controlPoint2: CGPoint(x: 28.78, y: -40.71)) 461 | bigGearPath.addCurve(to: CGPoint(x: 40.44, y: -45.08), controlPoint1: CGPoint(x: 34.25, y: -43.34), controlPoint2: CGPoint(x: 36.75, y: -44.56)) 462 | bigGearPath.addLine(to: CGPoint(x: 42.18, y: -43.37)) 463 | bigGearPath.addCurve(to: CGPoint(x: 39.03, y: -32.99), controlPoint1: CGPoint(x: 41.55, y: -39.51), controlPoint2: CGPoint(x: 40.37, y: -35.5)) 464 | bigGearPath.addCurve(to: CGPoint(x: 35.57, y: -29.18), controlPoint1: CGPoint(x: 38.34, y: -31.69), controlPoint2: CGPoint(x: 37.04, y: -30.25)) 465 | bigGearPath.addCurve(to: CGPoint(x: 38.91, y: -24.51), controlPoint1: CGPoint(x: 36.78, y: -27.7), controlPoint2: CGPoint(x: 37.89, y: -26.14)) 466 | bigGearPath.addCurve(to: CGPoint(x: 44.34, y: -26.66), controlPoint1: CGPoint(x: 40.13, y: -25.47), controlPoint2: CGPoint(x: 42.11, y: -26.54)) 467 | bigGearPath.addCurve(to: CGPoint(x: 54.58, y: -26.1), controlPoint1: CGPoint(x: 48.2, y: -26.87), controlPoint2: CGPoint(x: 50.97, y: -27.03)) 468 | bigGearPath.addLine(to: CGPoint(x: 55.54, y: -23.85)) 469 | bigGearPath.addCurve(to: CGPoint(x: 48.66, y: -15.47), controlPoint1: CGPoint(x: 53.48, y: -20.52), controlPoint2: CGPoint(x: 50.85, y: -17.27)) 470 | bigGearPath.addCurve(to: CGPoint(x: 43.98, y: -13.28), controlPoint1: CGPoint(x: 47.51, y: -14.52), controlPoint2: CGPoint(x: 45.74, y: -13.69)) 471 | bigGearPath.addCurve(to: CGPoint(x: 45.27, y: -7.65), controlPoint1: CGPoint(x: 44.52, y: -11.44), controlPoint2: CGPoint(x: 44.96, y: -9.57)) 472 | bigGearPath.addCurve(to: CGPoint(x: 51.15, y: -7.55), controlPoint1: CGPoint(x: 46.77, y: -8.07), controlPoint2: CGPoint(x: 49.02, y: -8.3)) 473 | bigGearPath.addCurve(to: CGPoint(x: 60.38, y: -3.09), controlPoint1: CGPoint(x: 54.79, y: -6.26), controlPoint2: CGPoint(x: 57.41, y: -5.34)) 474 | bigGearPath.addLine(to: CGPoint(x: 60.41, y: -0.64)) 475 | bigGearPath.addCurve(to: CGPoint(x: 50.85, y: 4.45), controlPoint1: CGPoint(x: 57.23, y: 1.63), controlPoint2: CGPoint(x: 53.57, y: 3.62)) 476 | bigGearPath.addCurve(to: CGPoint(x: 45.66, y: 4.66), controlPoint1: CGPoint(x: 49.42, y: 4.88), controlPoint2: CGPoint(x: 47.46, y: 4.96)) 477 | bigGearPath.addCurve(to: CGPoint(x: 44.76, y: 10.18), controlPoint1: CGPoint(x: 45.47, y: 6.54), controlPoint2: CGPoint(x: 45.16, y: 8.38)) 478 | bigGearPath.addCurve(to: CGPoint(x: 50.17, y: 12.51), controlPoint1: CGPoint(x: 46.3, y: 10.35), controlPoint2: CGPoint(x: 48.48, y: 11)) 479 | bigGearPath.addCurve(to: CGPoint(x: 57.02, y: 20.15), controlPoint1: CGPoint(x: 53.05, y: 15.09), controlPoint2: CGPoint(x: 55.13, y: 16.94)) 480 | bigGearPath.addLine(to: CGPoint(x: 56.12, y: 22.43)) 481 | bigGearPath.addCurve(to: CGPoint(x: 45.35, y: 23.5), controlPoint1: CGPoint(x: 52.32, y: 23.33), controlPoint2: CGPoint(x: 48.18, y: 23.77)) 482 | bigGearPath.addCurve(to: CGPoint(x: 40.46, y: 21.71), controlPoint1: CGPoint(x: 43.87, y: 23.35), controlPoint2: CGPoint(x: 42.01, y: 22.68)) 483 | bigGearPath.addCurve(to: CGPoint(x: 37.42, y: 26.64), controlPoint1: CGPoint(x: 39.55, y: 23.42), controlPoint2: CGPoint(x: 38.53, y: 25.07)) 484 | bigGearPath.addCurve(to: CGPoint(x: 41.53, y: 30.88), controlPoint1: CGPoint(x: 38.78, y: 27.39), controlPoint2: CGPoint(x: 40.55, y: 28.84)) 485 | bigGearPath.addCurve(to: CGPoint(x: 44.93, y: 40.58), controlPoint1: CGPoint(x: 43.2, y: 34.37), controlPoint2: CGPoint(x: 44.41, y: 36.88)) 486 | bigGearPath.addLine(to: CGPoint(x: 43.22, y: 42.33)) 487 | bigGearPath.addCurve(to: CGPoint(x: 32.87, y: 39.17), controlPoint1: CGPoint(x: 39.37, y: 41.7), controlPoint2: CGPoint(x: 35.38, y: 40.51)) 488 | bigGearPath.addCurve(to: CGPoint(x: 29.05, y: 35.65), controlPoint1: CGPoint(x: 31.56, y: 38.46), controlPoint2: CGPoint(x: 30.11, y: 37.13)) 489 | bigGearPath.addCurve(to: CGPoint(x: 24.3, y: 39.08), controlPoint1: CGPoint(x: 27.54, y: 36.89), controlPoint2: CGPoint(x: 25.96, y: 38.03)) 490 | bigGearPath.addCurve(to: CGPoint(x: 26.44, y: 44.56), controlPoint1: CGPoint(x: 25.26, y: 40.3), controlPoint2: CGPoint(x: 26.32, y: 42.31)) 491 | bigGearPath.addCurve(to: CGPoint(x: 25.85, y: 54.82), controlPoint1: CGPoint(x: 26.64, y: 48.42), controlPoint2: CGPoint(x: 26.79, y: 51.21)) 492 | bigGearPath.addLine(to: CGPoint(x: 23.6, y: 55.77)) 493 | bigGearPath.addCurve(to: CGPoint(x: 15.27, y: 48.85), controlPoint1: CGPoint(x: 20.29, y: 53.7), controlPoint2: CGPoint(x: 17.06, y: 51.06)) 494 | bigGearPath.addCurve(to: CGPoint(x: 13.11, y: 44.19), controlPoint1: CGPoint(x: 14.34, y: 47.71), controlPoint2: CGPoint(x: 13.52, y: 45.95)) 495 | bigGearPath.addCurve(to: CGPoint(x: 7.64, y: 45.47), controlPoint1: CGPoint(x: 11.33, y: 44.72), controlPoint2: CGPoint(x: 9.5, y: 45.15)) 496 | bigGearPath.addCurve(to: CGPoint(x: 7.52, y: 51.3), controlPoint1: CGPoint(x: 8.05, y: 46.97), controlPoint2: CGPoint(x: 8.26, y: 49.2)) 497 | bigGearPath.addCurve(to: CGPoint(x: 3.08, y: 60.56), controlPoint1: CGPoint(x: 6.23, y: 54.95), controlPoint2: CGPoint(x: 5.32, y: 57.58)) 498 | bigGearPath.addLine(to: CGPoint(x: 0.63, y: 60.59)) 499 | bigGearPath.addCurve(to: CGPoint(x: -4.44, y: 51), controlPoint1: CGPoint(x: -1.64, y: 57.4), controlPoint2: CGPoint(x: -3.62, y: 53.73)) 500 | bigGearPath.addCurve(to: CGPoint(x: -4.67, y: 45.92), controlPoint1: CGPoint(x: -4.86, y: 49.6), controlPoint2: CGPoint(x: -4.95, y: 47.69)) 501 | bigGearPath.addCurve(to: CGPoint(x: -10.16, y: 45.04), controlPoint1: CGPoint(x: -6.54, y: 45.73), controlPoint2: CGPoint(x: -8.37, y: 45.44)) 502 | bigGearPath.addCurve(to: CGPoint(x: -12.47, y: 50.32), controlPoint1: CGPoint(x: -10.36, y: 46.58), controlPoint2: CGPoint(x: -11.02, y: 48.68)) 503 | bigGearPath.addCurve(to: CGPoint(x: -20.09, y: 57.19), controlPoint1: CGPoint(x: -15.05, y: 53.2), controlPoint2: CGPoint(x: -16.89, y: 55.29)) 504 | bigGearPath.addLine(to: CGPoint(x: -22.36, y: 56.29)) 505 | bigGearPath.addCurve(to: CGPoint(x: -23.42, y: 45.49), controlPoint1: CGPoint(x: -23.25, y: 52.48), controlPoint2: CGPoint(x: -23.7, y: 48.32)) 506 | bigGearPath.addCurve(to: CGPoint(x: -21.75, y: 40.75), controlPoint1: CGPoint(x: -23.29, y: 44.05), controlPoint2: CGPoint(x: -22.66, y: 42.27)) 507 | bigGearPath.addCurve(to: CGPoint(x: -26.65, y: 37.73), controlPoint1: CGPoint(x: -23.45, y: 39.84), controlPoint2: CGPoint(x: -25.08, y: 38.83)) 508 | bigGearPath.addCurve(to: CGPoint(x: -30.77, y: 41.67), controlPoint1: CGPoint(x: -27.42, y: 39.06), controlPoint2: CGPoint(x: -28.82, y: 40.73)) 509 | bigGearPath.addCurve(to: CGPoint(x: -40.44, y: 45.08), controlPoint1: CGPoint(x: -34.25, y: 43.34), controlPoint2: CGPoint(x: -36.75, y: 44.56)) 510 | bigGearPath.addLine(to: CGPoint(x: -42.18, y: 43.37)) 511 | bigGearPath.addCurve(to: CGPoint(x: -39.03, y: 32.99), controlPoint1: CGPoint(x: -41.55, y: 39.51), controlPoint2: CGPoint(x: -40.37, y: 35.5)) 512 | bigGearPath.addCurve(to: CGPoint(x: -35.72, y: 29.29), controlPoint1: CGPoint(x: -38.36, y: 31.73), controlPoint2: CGPoint(x: -37.12, y: 30.34)) 513 | bigGearPath.addCurve(to: CGPoint(x: -39.08, y: 24.64), controlPoint1: CGPoint(x: -36.93, y: 27.81), controlPoint2: CGPoint(x: -38.05, y: 26.26)) 514 | bigGearPath.addCurve(to: CGPoint(x: -44.34, y: 26.66), controlPoint1: CGPoint(x: -40.31, y: 25.57), controlPoint2: CGPoint(x: -42.21, y: 26.54)) 515 | bigGearPath.addCurve(to: CGPoint(x: -54.58, y: 26.1), controlPoint1: CGPoint(x: -48.2, y: 26.87), controlPoint2: CGPoint(x: -50.97, y: 27.03)) 516 | bigGearPath.addLine(to: CGPoint(x: -55.54, y: 23.85)) 517 | bigGearPath.addCurve(to: CGPoint(x: -48.66, y: 15.47), controlPoint1: CGPoint(x: -53.48, y: 20.52), controlPoint2: CGPoint(x: -50.85, y: 17.27)) 518 | bigGearPath.addCurve(to: CGPoint(x: -44.24, y: 13.34), controlPoint1: CGPoint(x: -47.57, y: 14.57), controlPoint2: CGPoint(x: -45.92, y: 13.78)) 519 | bigGearPath.addCurve(to: CGPoint(x: -45.56, y: 7.73), controlPoint1: CGPoint(x: -44.8, y: 11.52), controlPoint2: CGPoint(x: -45.24, y: 9.64)) 520 | bigGearPath.addCurve(to: CGPoint(x: -51.15, y: 7.55), controlPoint1: CGPoint(x: -47.05, y: 8.1), controlPoint2: CGPoint(x: -49.16, y: 8.25)) 521 | bigGearPath.addCurve(to: CGPoint(x: -60.38, y: 3.09), controlPoint1: CGPoint(x: -54.79, y: 6.26), controlPoint2: CGPoint(x: -57.41, y: 5.34)) 522 | bigGearPath.addLine(to: CGPoint(x: -60.41, y: 0.64)) 523 | bigGearPath.addCurve(to: CGPoint(x: -50.85, y: -4.45), controlPoint1: CGPoint(x: -57.23, y: -1.63), controlPoint2: CGPoint(x: -53.57, y: -3.62)) 524 | bigGearPath.addCurve(to: CGPoint(x: -45.98, y: -4.71), controlPoint1: CGPoint(x: -49.51, y: -4.85), controlPoint2: CGPoint(x: -47.69, y: -4.95)) 525 | bigGearPath.addCurve(to: CGPoint(x: -45.09, y: -10.22), controlPoint1: CGPoint(x: -45.8, y: -6.58), controlPoint2: CGPoint(x: -45.5, y: -8.42)) 526 | bigGearPath.addCurve(to: CGPoint(x: -50.17, y: -12.51), controlPoint1: CGPoint(x: -46.61, y: -10.45), controlPoint2: CGPoint(x: -48.6, y: -11.11)) 527 | bigGearPath.addCurve(to: CGPoint(x: -57.02, y: -20.15), controlPoint1: CGPoint(x: -53.05, y: -15.09), controlPoint2: CGPoint(x: -55.13, y: -16.94)) 528 | bigGearPath.addLine(to: CGPoint(x: -56.12, y: -22.43)) 529 | bigGearPath.addCurve(to: CGPoint(x: -45.35, y: -23.5), controlPoint1: CGPoint(x: -52.32, y: -23.33), controlPoint2: CGPoint(x: -48.18, y: -23.77)) 530 | bigGearPath.addCurve(to: CGPoint(x: -40.75, y: -21.89), controlPoint1: CGPoint(x: -43.96, y: -23.36), controlPoint2: CGPoint(x: -42.24, y: -22.76)) 531 | bigGearPath.addCurve(to: CGPoint(x: -37.7, y: -26.8), controlPoint1: CGPoint(x: -39.83, y: -23.59), controlPoint2: CGPoint(x: -38.82, y: -25.23)) 532 | bigGearPath.addCurve(to: CGPoint(x: -41.53, y: -30.88), controlPoint1: CGPoint(x: -39.01, y: -27.59), controlPoint2: CGPoint(x: -40.61, y: -28.98)) 533 | bigGearPath.addCurve(to: CGPoint(x: -44.93, y: -40.58), controlPoint1: CGPoint(x: -43.2, y: -34.37), controlPoint2: CGPoint(x: -44.41, y: -36.88)) 534 | bigGearPath.addLine(to: CGPoint(x: -43.22, y: -42.33)) 535 | bigGearPath.addCurve(to: CGPoint(x: -32.87, y: -39.17), controlPoint1: CGPoint(x: -39.37, y: -41.69), controlPoint2: CGPoint(x: -35.38, y: -40.51)) 536 | bigGearPath.addCurve(to: CGPoint(x: -29.22, y: -35.88), controlPoint1: CGPoint(x: -31.63, y: -38.5), controlPoint2: CGPoint(x: -30.26, y: -37.27)) 537 | bigGearPath.addCurve(to: CGPoint(x: -24.46, y: -39.29), controlPoint1: CGPoint(x: -27.71, y: -37.11), controlPoint2: CGPoint(x: -26.12, y: -38.25)) 538 | bigGearPath.addCurve(to: CGPoint(x: -26.44, y: -44.56), controlPoint1: CGPoint(x: -25.37, y: -40.53), controlPoint2: CGPoint(x: -26.33, y: -42.43)) 539 | bigGearPath.addCurve(to: CGPoint(x: -26.18, y: -53.36), controlPoint1: CGPoint(x: -26.61, y: -47.89), controlPoint2: CGPoint(x: -26.75, y: -50.42)) 540 | bigGearPath.addCurve(to: CGPoint(x: -25.85, y: -54.82), controlPoint1: CGPoint(x: -26.09, y: -53.84), controlPoint2: CGPoint(x: -25.98, y: -54.32)) 541 | bigGearPath.addLine(to: CGPoint(x: -23.6, y: -55.77)) 542 | bigGearPath.addCurve(to: CGPoint(x: -15.4, y: -49.01), controlPoint1: CGPoint(x: -20.37, y: -53.75), controlPoint2: CGPoint(x: -17.22, y: -51.18)) 543 | bigGearPath.addLine(to: CGPoint(x: -15.27, y: -48.85)) 544 | bigGearPath.addCurve(to: CGPoint(x: -13.15, y: -44.38), controlPoint1: CGPoint(x: -14.37, y: -47.75), controlPoint2: CGPoint(x: -13.58, y: -46.07)) 545 | bigGearPath.addCurve(to: CGPoint(x: -7.68, y: -45.63), controlPoint1: CGPoint(x: -11.37, y: -44.9), controlPoint2: CGPoint(x: -9.55, y: -45.32)) 546 | bigGearPath.addCurve(to: CGPoint(x: -7.52, y: -51.3), controlPoint1: CGPoint(x: -8.06, y: -47.13), controlPoint2: CGPoint(x: -8.23, y: -49.27)) 547 | bigGearPath.addCurve(to: CGPoint(x: -3.08, y: -60.56), controlPoint1: CGPoint(x: -6.23, y: -54.95), controlPoint2: CGPoint(x: -5.32, y: -57.58)) 548 | bigGearPath.addLine(to: CGPoint(x: -0.63, y: -60.59)) 549 | bigGearPath.addCurve(to: CGPoint(x: 4.44, y: -51), controlPoint1: CGPoint(x: 1.64, y: -57.4), controlPoint2: CGPoint(x: 3.62, y: -53.73)) 550 | bigGearPath.close() 551 | bigGearPath.move(to: CGPoint(x: -10.72, y: -35.9)) 552 | bigGearPath.addCurve(to: CGPoint(x: -37.38, y: 0), controlPoint1: CGPoint(x: -26.16, y: -31.27), controlPoint2: CGPoint(x: -37.38, y: -16.94)) 553 | bigGearPath.addCurve(to: CGPoint(x: -36.33, y: 8.85), controlPoint1: CGPoint(x: -37.38, y: 3.05), controlPoint2: CGPoint(x: -37.02, y: 6.01)) 554 | bigGearPath.addCurve(to: CGPoint(x: -36.27, y: 8.84), controlPoint1: CGPoint(x: -36.28, y: 8.88), controlPoint2: CGPoint(x: -36.27, y: 8.84)) 555 | bigGearPath.addCurve(to: CGPoint(x: -30.89, y: 13.86), controlPoint1: CGPoint(x: -35.89, y: 9.75), controlPoint2: CGPoint(x: -33.47, y: 15.3)) 556 | bigGearPath.addLine(to: CGPoint(x: -8.41, y: 0.84)) 557 | bigGearPath.addCurve(to: CGPoint(x: -8.45, y: 0), controlPoint1: CGPoint(x: -8.44, y: 0.57), controlPoint2: CGPoint(x: -8.45, y: 0.28)) 558 | bigGearPath.addCurve(to: CGPoint(x: -3.77, y: -7.59), controlPoint1: CGPoint(x: -8.45, y: -3.32), controlPoint2: CGPoint(x: -6.54, y: -6.2)) 559 | bigGearPath.addLine(to: CGPoint(x: -3.77, y: -33.72)) 560 | bigGearPath.addCurve(to: CGPoint(x: -10.77, y: -35.89), controlPoint1: CGPoint(x: -3.81, y: -36.8), controlPoint2: CGPoint(x: -10.3, y: -35.96)) 561 | bigGearPath.addLine(to: CGPoint(x: -10.72, y: -35.9)) 562 | bigGearPath.close() 563 | bigGearPath.move(to: CGPoint(x: 0, y: -4.5)) 564 | bigGearPath.addCurve(to: CGPoint(x: -1.32, y: -4.3), controlPoint1: CGPoint(x: -0.46, y: -4.5), controlPoint2: CGPoint(x: -0.9, y: -4.43)) 565 | bigGearPath.addCurve(to: CGPoint(x: -4.5, y: 0), controlPoint1: CGPoint(x: -3.16, y: -3.74), controlPoint2: CGPoint(x: -4.5, y: -2.03)) 566 | bigGearPath.addCurve(to: CGPoint(x: 0, y: 4.5), controlPoint1: CGPoint(x: -4.5, y: 2.49), controlPoint2: CGPoint(x: -2.49, y: 4.5)) 567 | bigGearPath.addCurve(to: CGPoint(x: 4.5, y: 0), controlPoint1: CGPoint(x: 2.49, y: 4.5), controlPoint2: CGPoint(x: 4.5, y: 2.49)) 568 | bigGearPath.addCurve(to: CGPoint(x: 0, y: -4.5), controlPoint1: CGPoint(x: 4.5, y: -2.49), controlPoint2: CGPoint(x: 2.49, y: -4.5)) 569 | bigGearPath.close() 570 | bigGearPath.move(to: CGPoint(x: 4.39, y: 7.24)) 571 | bigGearPath.addCurve(to: CGPoint(x: 0, y: 8.48), controlPoint1: CGPoint(x: 3.11, y: 8.02), controlPoint2: CGPoint(x: 1.61, y: 8.48)) 572 | bigGearPath.addCurve(to: CGPoint(x: -4.39, y: 7.24), controlPoint1: CGPoint(x: -1.61, y: 8.48), controlPoint2: CGPoint(x: -3.11, y: 8.02)) 573 | bigGearPath.addLine(to: CGPoint(x: -27.12, y: 20.4)) 574 | bigGearPath.addCurve(to: CGPoint(x: -25.87, y: 27.05), controlPoint1: CGPoint(x: -29.34, y: 21.73), controlPoint2: CGPoint(x: -26.88, y: 25.62)) 575 | bigGearPath.addCurve(to: CGPoint(x: 0, y: 37.49), controlPoint1: CGPoint(x: -19.16, y: 33.52), controlPoint2: CGPoint(x: -10.04, y: 37.49)) 576 | bigGearPath.addCurve(to: CGPoint(x: 25.88, y: 27.05), controlPoint1: CGPoint(x: 10.04, y: 37.49), controlPoint2: CGPoint(x: 19.16, y: 33.52)) 577 | bigGearPath.addCurve(to: CGPoint(x: 27.13, y: 20.4), controlPoint1: CGPoint(x: 26.89, y: 25.62), controlPoint2: CGPoint(x: 29.34, y: 21.73)) 578 | bigGearPath.addLine(to: CGPoint(x: 4.39, y: 7.24)) 579 | bigGearPath.close() 580 | bigGearPath.move(to: CGPoint(x: 3.77, y: -33.72)) 581 | bigGearPath.addLine(to: CGPoint(x: 3.77, y: -7.59)) 582 | bigGearPath.addCurve(to: CGPoint(x: 8.45, y: 0), controlPoint1: CGPoint(x: 6.54, y: -6.2), controlPoint2: CGPoint(x: 8.45, y: -3.32)) 583 | bigGearPath.addCurve(to: CGPoint(x: 8.41, y: 0.84), controlPoint1: CGPoint(x: 8.45, y: 0.28), controlPoint2: CGPoint(x: 8.44, y: 0.56)) 584 | bigGearPath.addLine(to: CGPoint(x: 30.89, y: 13.85)) 585 | bigGearPath.addCurve(to: CGPoint(x: 36.23, y: 8.93), controlPoint1: CGPoint(x: 33.47, y: 15.29), controlPoint2: CGPoint(x: 35.89, y: 9.75)) 586 | bigGearPath.addCurve(to: CGPoint(x: 36.31, y: 8.96), controlPoint1: CGPoint(x: 36.27, y: 8.83), controlPoint2: CGPoint(x: 36.28, y: 8.88)) 587 | bigGearPath.addCurve(to: CGPoint(x: 37.38, y: 0), controlPoint1: CGPoint(x: 37.02, y: 6.01), controlPoint2: CGPoint(x: 37.38, y: 3.05)) 588 | bigGearPath.addCurve(to: CGPoint(x: 10.77, y: -35.91), controlPoint1: CGPoint(x: 37.38, y: -16.94), controlPoint2: CGPoint(x: 26.16, y: -31.27)) 589 | bigGearPath.addCurve(to: CGPoint(x: 3.77, y: -33.72), controlPoint1: CGPoint(x: 10.3, y: -35.96), controlPoint2: CGPoint(x: 3.81, y: -36.8)) 590 | bigGearPath.close() 591 | lightProgressBarColor.setFill() 592 | bigGearPath.fill() 593 | progressBarColor.setStroke() 594 | bigGearPath.lineWidth = 1.5 595 | bigGearPath.stroke() 596 | 597 | context.restoreGState() 598 | 599 | context.restoreGState() 600 | 601 | } 602 | 603 | 604 | 605 | 606 | @objc(ActivityStyleKitResizingBehavior) 607 | public enum ResizingBehavior: Int { 608 | case aspectFit /// The content is proportionally resized to fit into the target rectangle. 609 | case aspectFill /// The content is proportionally resized to completely fill the target rectangle. 610 | case stretch /// The content is stretched to match the entire target rectangle. 611 | case center /// The content is centered in the target rectangle, but it is NOT resized. 612 | 613 | public func apply(rect: CGRect, target: CGRect) -> CGRect { 614 | if rect == target || target == CGRect.zero { 615 | return rect 616 | } 617 | 618 | var scales = CGSize.zero 619 | scales.width = abs(target.width / rect.width) 620 | scales.height = abs(target.height / rect.height) 621 | 622 | switch self { 623 | case .aspectFit: 624 | scales.width = min(scales.width, scales.height) 625 | scales.height = scales.width 626 | case .aspectFill: 627 | scales.width = max(scales.width, scales.height) 628 | scales.height = scales.width 629 | case .stretch: 630 | break 631 | case .center: 632 | scales.width = 1 633 | scales.height = 1 634 | } 635 | 636 | var result = rect.standardized 637 | result.size.width *= scales.width 638 | result.size.height *= scales.height 639 | result.origin.x = target.minX + (target.width - result.width) / 2 640 | result.origin.y = target.minY + (target.height - result.height) / 2 641 | return result 642 | } 643 | } 644 | } 645 | --------------------------------------------------------------------------------