Repository: keygx/GradientCircularProgress Branch: master Commit: 9e2dc60d335e Files: 60 Total size: 185.9 KB Directory structure: gitextract_v1j42pdv/ ├── .gitignore ├── GCProgressSample/ │ ├── GCProgressSample/ │ │ ├── AlertHelperKit.swift │ │ ├── AppDelegate.swift │ │ ├── AsyncUtil.swift │ │ ├── BackgroundTransparentStyle.swift │ │ ├── Base.lproj/ │ │ │ ├── LaunchScreen.xib │ │ │ └── Main.storyboard │ │ ├── Images.xcassets/ │ │ │ └── AppIcon.appiconset/ │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── MyButton.swift │ │ ├── MyStyle.swift │ │ └── ViewController.swift │ ├── GCProgressSample.xcodeproj/ │ │ ├── project.pbxproj │ │ ├── project.xcworkspace/ │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata/ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata/ │ │ └── xcschemes/ │ │ └── GradientCircularProgress.xcscheme │ ├── GCProgressSampleTests/ │ │ ├── GCProgressSampleTests.swift │ │ └── Info.plist │ └── GradientCircularProgress/ │ ├── GradientCircularProgress.h │ ├── GradientCircularProgress.swift │ ├── Info.plist │ ├── Progress/ │ │ ├── Core/ │ │ │ ├── CircularProgressView.swift │ │ │ └── ProgressAtRatioView.swift │ │ ├── Elements/ │ │ │ ├── ArcView.swift │ │ │ ├── Background.swift │ │ │ ├── GradientArcView.swift │ │ │ ├── GradientArcWithClearColorView.swift │ │ │ └── WindowBuilder.swift │ │ ├── ProgressView.swift │ │ ├── ProgressViewController.swift │ │ └── Property.swift │ ├── Styles/ │ │ ├── BlueDarkStyle.swift │ │ ├── BlueIndicatorStyle.swift │ │ ├── GreenLightStyle.swift │ │ ├── OrangeClearStyle.swift │ │ └── Style.swift │ └── Utils/ │ └── ColorUtil.swift ├── GradientCircularProgress.podspec ├── LICENSE ├── README.md ├── Sample/ │ ├── BackgroundTransparentStyle.swift │ └── MyStyle.swift └── source/ ├── GradientCircularProgress.h ├── GradientCircularProgress.swift ├── Progress/ │ ├── Core/ │ │ ├── CircularProgressView.swift │ │ └── ProgressAtRatioView.swift │ ├── Elements/ │ │ ├── ArcView.swift │ │ ├── Background.swift │ │ ├── GradientArcView.swift │ │ ├── GradientArcWithClearColorView.swift │ │ └── WindowBuilder.swift │ ├── ProgressView.swift │ ├── ProgressViewController.swift │ └── Property.swift ├── Styles/ │ ├── BlueDarkStyle.swift │ ├── BlueIndicatorStyle.swift │ ├── GreenLightStyle.swift │ ├── OrangeClearStyle.swift │ └── Style.swift └── Utils/ └── ColorUtil.swift ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Created by https://www.gitignore.io ### Swift ### # Xcode # build/ *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata *.xccheckout *.moved-aside DerivedData *.hmap *.ipa *.xcuserstate # CocoaPods # # We recommend against adding the Pods directory to your .gitignore. However # you should judge for yourself, the pros and cons are mentioned at: # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control # Pods/ # Carthage # # Add this line if you want to avoid checking in source code from Carthage dependencies. Carthage/Checkouts Carthage/Build ================================================ FILE: GCProgressSample/GCProgressSample/AlertHelperKit.swift ================================================ // // AlertHelperKit.swift // // Created by keygx on 2015/07/21. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit public enum ActionSheetPopoverStyle: Int { case normal = 0 case barButton } public struct Parameters { var title: String? var message: String? var cancelButton: String? var destructiveButtons: [String]? var otherButtons: [String]? var disabledButtons: [String]? var inputFields: [InputField]? var sender: AnyObject? var arrowDirection: UIPopoverArrowDirection? var popoverStyle: ActionSheetPopoverStyle = .normal public init( title: String? = nil, message: String? = nil, cancelButton: String? = nil, destructiveButtons: [String]? = nil, otherButtons: [String]? = nil, disabledButtons: [String]? = nil, inputFields: [InputField]? = nil, sender: AnyObject? = nil, arrowDirection: UIPopoverArrowDirection? = nil, popoverStyle: ActionSheetPopoverStyle = .normal ) { self.title = title self.message = message self.cancelButton = cancelButton self.destructiveButtons = destructiveButtons self.otherButtons = otherButtons self.disabledButtons = disabledButtons self.inputFields = inputFields self.sender = sender self.arrowDirection = arrowDirection self.popoverStyle = popoverStyle } } public struct InputField { var placeholder: String var secure: Bool? public init(placeholder: String, secure: Bool?) { self.placeholder = placeholder self.secure = secure } } public class AlertHelperKit { public var animated: Bool = true public var completionHandler: (() -> Void)? public var textFields: [AnyObject]? public init() { initialize() } private func initialize() { animated = true completionHandler = nil textFields = nil } // Alert public func showAlert(_ parent: UIViewController, title: String?, message: String?, button: String) { let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) // cancel let cancelAction = UIAlertAction(title: button, style: .cancel, handler: nil) alertController.addAction(cancelAction) show(parent, ac: alertController) } // Alert with Callback Handler public func showAlertWithHandler(_ parent: UIViewController, parameters: Parameters, handler: @escaping (Int) -> ()) { let alertController: UIAlertController = buildAlertController(.alert, params: parameters) { buttonIndex in handler(buttonIndex) } buttonDisabled(alertController, params: parameters) show(parent, ac: alertController) } // ActionSheet public func showActionSheet(_ parent: UIViewController, parameters: Parameters, handler: @escaping (Int) -> ()) { let alertController: UIAlertController = buildAlertController(.actionSheet, params: parameters) { buttonIndex in handler(buttonIndex) } buttonDisabled(alertController, params: parameters) if let popover = alertController.popoverPresentationController, let sender: AnyObject = parameters.sender, let arrowDirection = parameters.arrowDirection { popover.sourceView = parent.view switch parameters.popoverStyle { case .barButton: guard let barButton = sender as? UIBarButtonItem else { return } popover.barButtonItem = barButton default: guard let button = sender as? UIButton else { return } popover.sourceRect = button.frame } popover.permittedArrowDirections = arrowDirection } show(parent, ac: alertController) } // Build AlertController private func buildAlertController(_ style: UIAlertController.Style, params: Parameters, handler: @escaping (Int) -> ()) -> UIAlertController { let alertController = UIAlertController(title: params.title, message: params.message, preferredStyle: style) let destructivOffset = 1 var othersOffset = destructivOffset // cancel if let cancel = params.cancelButton { let cancelAction = UIAlertAction(title: cancel, style: .cancel) { _ in handler(0) } alertController.addAction(cancelAction) } // destructive if let destructive = params.destructiveButtons { for i in 0.. Bool { // Override point for customization after application launch. return true } func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } } ================================================ FILE: GCProgressSample/GCProgressSample/AsyncUtil.swift ================================================ // // AsyncUtil.swift // GCProgressSample // // Created by keygx on 2016/02/20. // Copyright (c) 2015年 keygx. All rights reserved. // import Foundation class AsyncUtil { func dispatchOnMainThread(_ block: @escaping () -> (), delay: Double) { if delay == 0 { DispatchQueue.main.async { block() } return } let d = DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC) DispatchQueue.main.asyncAfter(deadline: d) { block() } } } ================================================ FILE: GCProgressSample/GCProgressSample/BackgroundTransparentStyle.swift ================================================ // // BackgroundTransparentStyle.swift // GradientCircularProgress // // Created by keygx on 2016/12/03. // Copyright (c) 2015年 keygx. All rights reserved. // import GradientCircularProgress public struct BackgroundTransparentStyle: StyleProperty { /*** style properties **********************************************************************************/ // Progress Size public var progressSize: CGFloat = 200 // Gradient Circular public var arcLineWidth: CGFloat = 4.0 public var startArcColor: UIColor = ColorUtil.toUIColor(r: 0.0, g: 122.0, b: 255.0, a: 1.0) public var endArcColor: UIColor = UIColor.cyan // Base Circular public var baseLineWidth: CGFloat? = 6.0 public var baseArcColor: UIColor? = UIColor(red:0.0, green: 0.0, blue: 0.0, alpha: 0.2) // Ratio public var ratioLabelFont: UIFont? = UIFont.systemFont(ofSize: 16.0) public var ratioLabelFontColor: UIColor? = UIColor.black // Message public var messageLabelFont: UIFont? = UIFont.systemFont(ofSize: 16.0) public var messageLabelFontColor: UIColor? = UIColor.black // Background public var backgroundStyle: BackgroundStyles = .transparent // Dismiss public var dismissTimeInterval: Double? = nil // 'nil' for default setting. /*** style properties **********************************************************************************/ public init() {} } ================================================ FILE: GCProgressSample/GCProgressSample/Base.lproj/LaunchScreen.xib ================================================ ================================================ FILE: GCProgressSample/GCProgressSample/Base.lproj/Main.storyboard ================================================ ================================================ FILE: GCProgressSample/GCProgressSample/Images.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "idiom" : "iphone", "size" : "20x20", "scale" : "2x" }, { "idiom" : "iphone", "size" : "20x20", "scale" : "3x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "2x" }, { "idiom" : "iphone", "size" : "29x29", "scale" : "3x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, { "idiom" : "iphone", "size" : "40x40", "scale" : "3x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, { "idiom" : "iphone", "size" : "60x60", "scale" : "3x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "1x" }, { "idiom" : "ipad", "size" : "20x20", "scale" : "2x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "1x" }, { "idiom" : "ipad", "size" : "29x29", "scale" : "2x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "1x" }, { "idiom" : "ipad", "size" : "40x40", "scale" : "2x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "1x" }, { "idiom" : "ipad", "size" : "76x76", "scale" : "2x" }, { "idiom" : "ipad", "size" : "83.5x83.5", "scale" : "2x" } ], "info" : { "version" : 1, "author" : "xcode" } } ================================================ FILE: GCProgressSample/GCProgressSample/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString $(MARKETING_VERSION) CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) LSRequiresIPhoneOS UILaunchStoryboardName LaunchScreen UIMainStoryboardFile Main UIRequiredDeviceCapabilities armv7 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight ================================================ FILE: GCProgressSample/GCProgressSample/MyButton.swift ================================================ // // MyButton.swift // GCProgressSample // // Created by keygx on 2016/03/12. // Copyright © 2016年 keygx. All rights reserved. // import UIKit class MyButton: UIButton { enum ButtonStatus { case normal case highlighted case selected case disabled } var status: ButtonStatus = .normal { didSet { switch status { case .disabled: isEnabled = false default: isEnabled = true } apply() } } private let defaultColor: UIColor = UIColor(red: 0.0/255.0, green: 122.0/255.0, blue: 255.0/255.0, alpha: 1.0) private let disabledColor: UIColor = UIColor.lightGray override init(frame: CGRect) { super.init(frame: frame) initialize() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) initialize() } private func initialize() { status = .normal layer.cornerRadius = 4.0 layer.borderWidth = 1.0 } func apply() { switch status { case .disabled: setTitleColor(disabledColor, for: .disabled) layer.borderColor = disabledColor.cgColor default: setTitleColor(defaultColor, for: UIControl.State()) layer.borderColor = defaultColor.cgColor } } } ================================================ FILE: GCProgressSample/GCProgressSample/MyStyle.swift ================================================ // // MyStyle.swift // GradientCircularProgress // // Created by keygx on 2015/11/25. // Copyright (c) 2015年 keygx. All rights reserved. // import GradientCircularProgress public struct MyStyle: StyleProperty { /*** style properties **********************************************************************************/ // Progress Size public var progressSize: CGFloat = 200 // Gradient Circular public var arcLineWidth: CGFloat = 18.0 public var startArcColor: UIColor = UIColor.clear public var endArcColor: UIColor = UIColor.orange // Base Circular public var baseLineWidth: CGFloat? = 19.0 public var baseArcColor: UIColor? = UIColor.darkGray // Ratio public var ratioLabelFont: UIFont? = UIFont(name: "Verdana-Bold", size: 16.0) public var ratioLabelFontColor: UIColor? = UIColor.white // Message public var messageLabelFont: UIFont? = UIFont.systemFont(ofSize: 16.0) public var messageLabelFontColor: UIColor? = UIColor.white // Background public var backgroundStyle: BackgroundStyles = .dark // Dismiss public var dismissTimeInterval: Double? = 0.0 // 'nil' for default setting. /*** style properties **********************************************************************************/ public init() {} } ================================================ FILE: GCProgressSample/GCProgressSample/ViewController.swift ================================================ // // ViewController.swift // GCProgressSample // // Created by keygx on 2016/03/12. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit import GradientCircularProgress class ViewController: UIViewController { // UI enum UsageType { case window case subView } let styleList: [(String, StyleProperty)] = [ ("Style.swift", Style()), ("BlueDarkStyle.swift", BlueDarkStyle()), ("OrangeClearStyle.swift", OrangeClearStyle()), ("GreenLightStyle.swift", GreenLightStyle()), ("BlueIndicatorStyle.swift", BlueIndicatorStyle()), ("MyStyle.swift", MyStyle()), ("BackgroundTransparentStyle", BackgroundTransparentStyle()), ] var usageType: UsageType = .window var seletedStyleIndex: Int = 0 { willSet { styleLabel.text = styleList[newValue].0 } } @IBOutlet weak var segmentedControl: UISegmentedControl! @IBOutlet weak var styleLabel: UILabel! @IBOutlet weak var btnAtRatio: MyButton! @IBOutlet weak var btnBasic: MyButton! @IBOutlet weak var btnUpdateMessage: MyButton! // Progress let progress = GradientCircularProgress() var progressView: UIView? // Demo var timer: Timer? var v: Double = 0.0 override func viewDidLoad() { super.viewDidLoad() usageType = .window seletedStyleIndex = 0 } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } @IBAction func segmentedControlAction(_ sender: AnyObject) { switch sender.selectedSegmentIndex { case 0: usageType = .window case 1: usageType = .subView default: break } } @IBAction func btnChooseStyleAction(_ sender: AnyObject) { let styleTitleList: [String] = styleList.map {$0.0} let params = Parameters( title: nil, message: nil, cancelButton: "Cancel", otherButtons: styleTitleList ) AlertHelperKit().showAlertWithHandler(self, parameters: params) { buttonIndex in switch buttonIndex { case 1: self.seletedStyleIndex = buttonIndex - 1 self.btnUpdateMessage.status = .normal case 2: self.seletedStyleIndex = buttonIndex - 1 self.btnUpdateMessage.status = .normal case 3: self.seletedStyleIndex = buttonIndex - 1 self.btnUpdateMessage.status = .disabled case 4: self.seletedStyleIndex = buttonIndex - 1 self.btnUpdateMessage.status = .normal case 5: self.seletedStyleIndex = buttonIndex - 1 self.btnUpdateMessage.status = .disabled case 6: self.seletedStyleIndex = buttonIndex - 1 self.btnUpdateMessage.status = .normal case 7: self.seletedStyleIndex = buttonIndex - 1 self.btnUpdateMessage.status = .normal default: break // Cancel } } } @IBAction func btnAtRatioAction(_ sender: AnyObject) { if progress.isAvailable { return } if usageType == .window { showAtRatio() } else { showAtRatioTypeSubView() } } @IBAction func btnBasicAction(_ sender: AnyObject) { if progress.isAvailable { return } if usageType == .window { showBasic() } else { showBasicTypeSubView() } } @IBAction func btnUpdateMessageAction(_ sender: AnyObject) { if progress.isAvailable { return } if usageType == .window { showUpdateMessage() } else { showUpdateMessageTypeSubView() } } } // UIWindow extension ViewController { func showAtRatio() { var displayFlag: Bool switch seletedStyleIndex { case 4: displayFlag = false default: displayFlag = true } progress.showAtRatio(display: displayFlag, style: styleList[seletedStyleIndex].1) startProgressAtRatio() } func showBasic() { progress.show(message: "Loading...", style: styleList[seletedStyleIndex].1) delayCloseProgress() } func showUpdateMessage() { progress.show(message: "Download\n0 / 4", style: styleList[seletedStyleIndex].1) startProgressBasic() } } // SubView extension ViewController { func showAtRatioTypeSubView() { var displayFlag: Bool switch seletedStyleIndex { case 4: displayFlag = false default: displayFlag = true } progressView = progress.showAtRatio(frame: getRect(), display: displayFlag, style: styleList[seletedStyleIndex].1) progressView?.layer.cornerRadius = 12.0 view.addSubview(progressView!) startProgressAtRatio() } func showBasicTypeSubView() { progressView = progress.show(frame: getRect(), message: "Loading...", style: styleList[seletedStyleIndex].1) progressView?.layer.cornerRadius = 12.0 view.addSubview(progressView!) delayCloseProgress() } func showUpdateMessageTypeSubView() { progressView = progress.show(frame: getRect(), message: "Download\n0 / 4", style: styleList[seletedStyleIndex].1) progressView?.layer.cornerRadius = 12.0 view.addSubview(progressView!) startProgressBasic() } } // for demo extension ViewController { func delayCloseProgress() { AsyncUtil().dispatchOnMainThread({ switch self.usageType { case .window: self.progress.dismiss() case .subView: self.progress.dismiss(progress: self.progressView!) } }, delay: 2.0) } func startProgressBasic() { v = 0.0 timer = Timer.scheduledTimer( timeInterval: 0.01, target: self, selector: #selector(updateMessage), userInfo: nil, repeats: true ) RunLoop.main.add(timer!, forMode: RunLoop.Mode.common) } @objc func updateMessage() { v += 0.002 if v > 1.00 { progress.updateMessage(message: "Download\n4 / 4") timer!.invalidate() AsyncUtil().dispatchOnMainThread({ self.progress.updateMessage(message: "Completed!") switch self.usageType { case .window: self.progress.dismiss() case .subView: self.progress.dismiss(progress: self.progressView!) } }, delay: 0.8) return } else if v > 0.75 { progress.updateMessage(message: "Download\n3 / 4") } else if v > 0.5 { progress.updateMessage(message: "Download\n2 / 4") } else if v > 0.25 { progress.updateMessage(message: "Download\n1 / 4") } } func startProgressAtRatio() { v = 0.0 timer = Timer.scheduledTimer( timeInterval: 0.01, target: self, selector: #selector(updateProgressAtRatio), userInfo: nil, repeats: true ) RunLoop.main.add(timer!, forMode: RunLoop.Mode.common) } @objc func updateProgressAtRatio() { v += 0.01 progress.updateRatio(CGFloat(v)) if v > 1.00 { timer!.invalidate() switch usageType { case .window: progress.dismiss() case .subView: progress.dismiss(progress: progressView!) } return } } func getRect() -> CGRect { return CGRect( x: view.frame.origin.x + 15, y: (view.frame.size.height - view.frame.size.width) / 2, width: view.frame.size.width - 30, height: view.frame.size.width - 30) } } ================================================ FILE: GCProgressSample/GCProgressSample.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ 360F44AB1DF27B2800835EA0 /* BackgroundTransparentStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 360F44AA1DF27B2800835EA0 /* BackgroundTransparentStyle.swift */; }; 362C51F91C9AB926008C1C81 /* AlertHelperKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 362C51F81C9AB926008C1C81 /* AlertHelperKit.swift */; }; 3632ED251C7833CD006484E5 /* AsyncUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3632ED241C7833CD006484E5 /* AsyncUtil.swift */; }; 366555DE1C9D900F00767B90 /* MyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 366555DD1C9D900F00767B90 /* MyButton.swift */; }; 3667E0ED23392FEC002CCD9C /* WindowBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3667E0EC23392FEC002CCD9C /* WindowBuilder.swift */; }; 368F0E4E1C35319E008B1AC4 /* MyStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 368F0E4D1C35319E008B1AC4 /* MyStyle.swift */; }; 36CC1C821B37083E009DE1F8 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CC1C811B37083E009DE1F8 /* AppDelegate.swift */; }; 36CC1C841B37083E009DE1F8 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CC1C831B37083E009DE1F8 /* ViewController.swift */; }; 36CC1C871B37083E009DE1F8 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 36CC1C851B37083E009DE1F8 /* Main.storyboard */; }; 36CC1C891B37083E009DE1F8 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 36CC1C881B37083E009DE1F8 /* Images.xcassets */; }; 36CC1C8C1B37083E009DE1F8 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 36CC1C8A1B37083E009DE1F8 /* LaunchScreen.xib */; }; 36CC1C981B37083E009DE1F8 /* GCProgressSampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CC1C971B37083E009DE1F8 /* GCProgressSampleTests.swift */; }; 36CE2B5D1C93EA740084CE64 /* GradientCircularProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B471C93EA740084CE64 /* GradientCircularProgress.swift */; }; 36CE2B5E1C93EA740084CE64 /* CircularProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B4A1C93EA740084CE64 /* CircularProgressView.swift */; }; 36CE2B5F1C93EA740084CE64 /* ProgressAtRatioView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B4B1C93EA740084CE64 /* ProgressAtRatioView.swift */; }; 36CE2B601C93EA740084CE64 /* ArcView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B4D1C93EA740084CE64 /* ArcView.swift */; }; 36CE2B611C93EA740084CE64 /* Background.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B4E1C93EA740084CE64 /* Background.swift */; }; 36CE2B631C93EA740084CE64 /* GradientArcView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B501C93EA740084CE64 /* GradientArcView.swift */; }; 36CE2B641C93EA740084CE64 /* GradientArcWithClearColorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B511C93EA740084CE64 /* GradientArcWithClearColorView.swift */; }; 36CE2B651C93EA740084CE64 /* ProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B521C93EA740084CE64 /* ProgressView.swift */; }; 36CE2B661C93EA740084CE64 /* ProgressViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B531C93EA740084CE64 /* ProgressViewController.swift */; }; 36CE2B671C93EA740084CE64 /* Property.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B541C93EA740084CE64 /* Property.swift */; }; 36CE2B681C93EA740084CE64 /* BlueDarkStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B561C93EA740084CE64 /* BlueDarkStyle.swift */; }; 36CE2B691C93EA740084CE64 /* BlueIndicatorStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B571C93EA740084CE64 /* BlueIndicatorStyle.swift */; }; 36CE2B6A1C93EA740084CE64 /* GreenLightStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B581C93EA740084CE64 /* GreenLightStyle.swift */; }; 36CE2B6B1C93EA740084CE64 /* OrangeClearStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B591C93EA740084CE64 /* OrangeClearStyle.swift */; }; 36CE2B6C1C93EA740084CE64 /* Style.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B5A1C93EA740084CE64 /* Style.swift */; }; 36CE2B6D1C93EA740084CE64 /* ColorUtil.swift in Sources */ = {isa = PBXBuildFile; fileRef = 36CE2B5C1C93EA740084CE64 /* ColorUtil.swift */; }; 36F742C01B3A7016003D799C /* GradientCircularProgress.h in Headers */ = {isa = PBXBuildFile; fileRef = 36F742BF1B3A7016003D799C /* GradientCircularProgress.h */; settings = {ATTRIBUTES = (Public, ); }; }; 36F742D21B3A7016003D799C /* GradientCircularProgress.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 36F742BB1B3A7016003D799C /* GradientCircularProgress.framework */; }; 36F742D31B3A7016003D799C /* GradientCircularProgress.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 36F742BB1B3A7016003D799C /* GradientCircularProgress.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ 36CC1C921B37083E009DE1F8 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 36CC1C741B37083E009DE1F8 /* Project object */; proxyType = 1; remoteGlobalIDString = 36CC1C7B1B37083E009DE1F8; remoteInfo = GCProgressSample; }; 36F742D01B3A7016003D799C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 36CC1C741B37083E009DE1F8 /* Project object */; proxyType = 1; remoteGlobalIDString = 36F742BA1B3A7016003D799C; remoteInfo = GradientCircularProgress; }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ 36F742D91B3A7016003D799C /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( 36F742D31B3A7016003D799C /* GradientCircularProgress.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 360F44AA1DF27B2800835EA0 /* BackgroundTransparentStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BackgroundTransparentStyle.swift; sourceTree = ""; }; 362C51F81C9AB926008C1C81 /* AlertHelperKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertHelperKit.swift; sourceTree = ""; }; 3632ED241C7833CD006484E5 /* AsyncUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AsyncUtil.swift; sourceTree = ""; }; 366555DD1C9D900F00767B90 /* MyButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyButton.swift; sourceTree = ""; }; 3667E0EC23392FEC002CCD9C /* WindowBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WindowBuilder.swift; sourceTree = ""; }; 368F0E4D1C35319E008B1AC4 /* MyStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyStyle.swift; sourceTree = ""; }; 36CC1C7C1B37083E009DE1F8 /* GCProgressSample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GCProgressSample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 36CC1C801B37083E009DE1F8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 36CC1C811B37083E009DE1F8 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 36CC1C831B37083E009DE1F8 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 36CC1C861B37083E009DE1F8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 36CC1C881B37083E009DE1F8 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 36CC1C8B1B37083E009DE1F8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; 36CC1C911B37083E009DE1F8 /* GCProgressSampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GCProgressSampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 36CC1C961B37083E009DE1F8 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 36CC1C971B37083E009DE1F8 /* GCProgressSampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GCProgressSampleTests.swift; sourceTree = ""; }; 36CE2B471C93EA740084CE64 /* GradientCircularProgress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientCircularProgress.swift; sourceTree = ""; }; 36CE2B4A1C93EA740084CE64 /* CircularProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CircularProgressView.swift; sourceTree = ""; }; 36CE2B4B1C93EA740084CE64 /* ProgressAtRatioView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressAtRatioView.swift; sourceTree = ""; }; 36CE2B4D1C93EA740084CE64 /* ArcView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ArcView.swift; sourceTree = ""; }; 36CE2B4E1C93EA740084CE64 /* Background.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Background.swift; sourceTree = ""; }; 36CE2B501C93EA740084CE64 /* GradientArcView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientArcView.swift; sourceTree = ""; }; 36CE2B511C93EA740084CE64 /* GradientArcWithClearColorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GradientArcWithClearColorView.swift; sourceTree = ""; }; 36CE2B521C93EA740084CE64 /* ProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressView.swift; sourceTree = ""; }; 36CE2B531C93EA740084CE64 /* ProgressViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressViewController.swift; sourceTree = ""; }; 36CE2B541C93EA740084CE64 /* Property.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Property.swift; sourceTree = ""; }; 36CE2B561C93EA740084CE64 /* BlueDarkStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlueDarkStyle.swift; sourceTree = ""; }; 36CE2B571C93EA740084CE64 /* BlueIndicatorStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlueIndicatorStyle.swift; sourceTree = ""; }; 36CE2B581C93EA740084CE64 /* GreenLightStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GreenLightStyle.swift; sourceTree = ""; }; 36CE2B591C93EA740084CE64 /* OrangeClearStyle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrangeClearStyle.swift; sourceTree = ""; }; 36CE2B5A1C93EA740084CE64 /* Style.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Style.swift; sourceTree = ""; }; 36CE2B5C1C93EA740084CE64 /* ColorUtil.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorUtil.swift; sourceTree = ""; }; 36F742BB1B3A7016003D799C /* GradientCircularProgress.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = GradientCircularProgress.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 36F742BE1B3A7016003D799C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 36F742BF1B3A7016003D799C /* GradientCircularProgress.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GradientCircularProgress.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 36CC1C791B37083E009DE1F8 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 36F742D21B3A7016003D799C /* GradientCircularProgress.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 36CC1C8E1B37083E009DE1F8 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 36F742B71B3A7016003D799C /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 366555DA1C9D8BB600767B90 /* libs */ = { isa = PBXGroup; children = ( 362C51F81C9AB926008C1C81 /* AlertHelperKit.swift */, 3632ED241C7833CD006484E5 /* AsyncUtil.swift */, 366555DD1C9D900F00767B90 /* MyButton.swift */, ); name = libs; sourceTree = ""; }; 36CC1C731B37083E009DE1F8 = { isa = PBXGroup; children = ( 36CC1C7E1B37083E009DE1F8 /* GCProgressSample */, 36CC1C941B37083E009DE1F8 /* GCProgressSampleTests */, 36F742BC1B3A7016003D799C /* GradientCircularProgress */, 36CC1C7D1B37083E009DE1F8 /* Products */, ); sourceTree = ""; }; 36CC1C7D1B37083E009DE1F8 /* Products */ = { isa = PBXGroup; children = ( 36CC1C7C1B37083E009DE1F8 /* GCProgressSample.app */, 36CC1C911B37083E009DE1F8 /* GCProgressSampleTests.xctest */, 36F742BB1B3A7016003D799C /* GradientCircularProgress.framework */, ); name = Products; sourceTree = ""; }; 36CC1C7E1B37083E009DE1F8 /* GCProgressSample */ = { isa = PBXGroup; children = ( 366555DA1C9D8BB600767B90 /* libs */, 36CC1C811B37083E009DE1F8 /* AppDelegate.swift */, 36CC1C831B37083E009DE1F8 /* ViewController.swift */, 368F0E4D1C35319E008B1AC4 /* MyStyle.swift */, 360F44AA1DF27B2800835EA0 /* BackgroundTransparentStyle.swift */, 36CC1C851B37083E009DE1F8 /* Main.storyboard */, 36CC1C881B37083E009DE1F8 /* Images.xcassets */, 36CC1C8A1B37083E009DE1F8 /* LaunchScreen.xib */, 36CC1C7F1B37083E009DE1F8 /* Supporting Files */, ); path = GCProgressSample; sourceTree = ""; }; 36CC1C7F1B37083E009DE1F8 /* Supporting Files */ = { isa = PBXGroup; children = ( 36CC1C801B37083E009DE1F8 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; 36CC1C941B37083E009DE1F8 /* GCProgressSampleTests */ = { isa = PBXGroup; children = ( 36CC1C971B37083E009DE1F8 /* GCProgressSampleTests.swift */, 36CC1C951B37083E009DE1F8 /* Supporting Files */, ); path = GCProgressSampleTests; sourceTree = ""; }; 36CC1C951B37083E009DE1F8 /* Supporting Files */ = { isa = PBXGroup; children = ( 36CC1C961B37083E009DE1F8 /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; 36CE2B481C93EA740084CE64 /* Progress */ = { isa = PBXGroup; children = ( 36CE2B491C93EA740084CE64 /* Core */, 36CE2B4C1C93EA740084CE64 /* Elements */, 36CE2B521C93EA740084CE64 /* ProgressView.swift */, 36CE2B531C93EA740084CE64 /* ProgressViewController.swift */, 36CE2B541C93EA740084CE64 /* Property.swift */, ); path = Progress; sourceTree = ""; }; 36CE2B491C93EA740084CE64 /* Core */ = { isa = PBXGroup; children = ( 36CE2B4A1C93EA740084CE64 /* CircularProgressView.swift */, 36CE2B4B1C93EA740084CE64 /* ProgressAtRatioView.swift */, ); path = Core; sourceTree = ""; }; 36CE2B4C1C93EA740084CE64 /* Elements */ = { isa = PBXGroup; children = ( 36CE2B4D1C93EA740084CE64 /* ArcView.swift */, 36CE2B4E1C93EA740084CE64 /* Background.swift */, 3667E0EC23392FEC002CCD9C /* WindowBuilder.swift */, 36CE2B501C93EA740084CE64 /* GradientArcView.swift */, 36CE2B511C93EA740084CE64 /* GradientArcWithClearColorView.swift */, ); path = Elements; sourceTree = ""; }; 36CE2B551C93EA740084CE64 /* Styles */ = { isa = PBXGroup; children = ( 36CE2B561C93EA740084CE64 /* BlueDarkStyle.swift */, 36CE2B571C93EA740084CE64 /* BlueIndicatorStyle.swift */, 36CE2B581C93EA740084CE64 /* GreenLightStyle.swift */, 36CE2B591C93EA740084CE64 /* OrangeClearStyle.swift */, 36CE2B5A1C93EA740084CE64 /* Style.swift */, ); path = Styles; sourceTree = ""; }; 36CE2B5B1C93EA740084CE64 /* Utils */ = { isa = PBXGroup; children = ( 36CE2B5C1C93EA740084CE64 /* ColorUtil.swift */, ); path = Utils; sourceTree = ""; }; 36F742BC1B3A7016003D799C /* GradientCircularProgress */ = { isa = PBXGroup; children = ( 36CE2B471C93EA740084CE64 /* GradientCircularProgress.swift */, 36CE2B481C93EA740084CE64 /* Progress */, 36CE2B551C93EA740084CE64 /* Styles */, 36CE2B5B1C93EA740084CE64 /* Utils */, 36F742BF1B3A7016003D799C /* GradientCircularProgress.h */, 36F742BD1B3A7016003D799C /* Supporting Files */, ); path = GradientCircularProgress; sourceTree = ""; }; 36F742BD1B3A7016003D799C /* Supporting Files */ = { isa = PBXGroup; children = ( 36F742BE1B3A7016003D799C /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ 36F742B81B3A7016003D799C /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( 36F742C01B3A7016003D799C /* GradientCircularProgress.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ 36CC1C7B1B37083E009DE1F8 /* GCProgressSample */ = { isa = PBXNativeTarget; buildConfigurationList = 36CC1C9B1B37083E009DE1F8 /* Build configuration list for PBXNativeTarget "GCProgressSample" */; buildPhases = ( 36CC1C781B37083E009DE1F8 /* Sources */, 36CC1C791B37083E009DE1F8 /* Frameworks */, 36CC1C7A1B37083E009DE1F8 /* Resources */, 36F742D91B3A7016003D799C /* Embed Frameworks */, ); buildRules = ( ); dependencies = ( 36F742D11B3A7016003D799C /* PBXTargetDependency */, ); name = GCProgressSample; productName = GCProgressSample; productReference = 36CC1C7C1B37083E009DE1F8 /* GCProgressSample.app */; productType = "com.apple.product-type.application"; }; 36CC1C901B37083E009DE1F8 /* GCProgressSampleTests */ = { isa = PBXNativeTarget; buildConfigurationList = 36CC1C9E1B37083E009DE1F8 /* Build configuration list for PBXNativeTarget "GCProgressSampleTests" */; buildPhases = ( 36CC1C8D1B37083E009DE1F8 /* Sources */, 36CC1C8E1B37083E009DE1F8 /* Frameworks */, 36CC1C8F1B37083E009DE1F8 /* Resources */, ); buildRules = ( ); dependencies = ( 36CC1C931B37083E009DE1F8 /* PBXTargetDependency */, ); name = GCProgressSampleTests; productName = GCProgressSampleTests; productReference = 36CC1C911B37083E009DE1F8 /* GCProgressSampleTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 36F742BA1B3A7016003D799C /* GradientCircularProgress */ = { isa = PBXNativeTarget; buildConfigurationList = 36F742D81B3A7016003D799C /* Build configuration list for PBXNativeTarget "GradientCircularProgress" */; buildPhases = ( 36F742B61B3A7016003D799C /* Sources */, 36F742B71B3A7016003D799C /* Frameworks */, 36F742B81B3A7016003D799C /* Headers */, 36F742B91B3A7016003D799C /* Resources */, ); buildRules = ( ); dependencies = ( ); name = GradientCircularProgress; productName = GradientCircularProgress; productReference = 36F742BB1B3A7016003D799C /* GradientCircularProgress.framework */; productType = "com.apple.product-type.framework"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 36CC1C741B37083E009DE1F8 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftMigration = 0700; LastSwiftUpdateCheck = 0720; LastUpgradeCheck = 1100; ORGANIZATIONNAME = keygx; TargetAttributes = { 36CC1C7B1B37083E009DE1F8 = { CreatedOnToolsVersion = 6.3.2; DevelopmentTeam = 3CCNMX7TC9; DevelopmentTeamName = "Yukihiko Kagiyama"; LastSwiftMigration = 1020; ProvisioningStyle = Automatic; }; 36CC1C901B37083E009DE1F8 = { CreatedOnToolsVersion = 6.3.2; LastSwiftMigration = 0800; TestTargetID = 36CC1C7B1B37083E009DE1F8; }; 36F742BA1B3A7016003D799C = { CreatedOnToolsVersion = 6.3.2; DevelopmentTeamName = "Yukihiko Kagiyama"; LastSwiftMigration = 1020; }; }; }; buildConfigurationList = 36CC1C771B37083E009DE1F8 /* Build configuration list for PBXProject "GCProgressSample" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 36CC1C731B37083E009DE1F8; productRefGroup = 36CC1C7D1B37083E009DE1F8 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 36CC1C7B1B37083E009DE1F8 /* GCProgressSample */, 36CC1C901B37083E009DE1F8 /* GCProgressSampleTests */, 36F742BA1B3A7016003D799C /* GradientCircularProgress */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 36CC1C7A1B37083E009DE1F8 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 36CC1C871B37083E009DE1F8 /* Main.storyboard in Resources */, 36CC1C8C1B37083E009DE1F8 /* LaunchScreen.xib in Resources */, 36CC1C891B37083E009DE1F8 /* Images.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 36CC1C8F1B37083E009DE1F8 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; 36F742B91B3A7016003D799C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 36CC1C781B37083E009DE1F8 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 36CC1C841B37083E009DE1F8 /* ViewController.swift in Sources */, 362C51F91C9AB926008C1C81 /* AlertHelperKit.swift in Sources */, 360F44AB1DF27B2800835EA0 /* BackgroundTransparentStyle.swift in Sources */, 36CC1C821B37083E009DE1F8 /* AppDelegate.swift in Sources */, 3632ED251C7833CD006484E5 /* AsyncUtil.swift in Sources */, 368F0E4E1C35319E008B1AC4 /* MyStyle.swift in Sources */, 366555DE1C9D900F00767B90 /* MyButton.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 36CC1C8D1B37083E009DE1F8 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 36CC1C981B37083E009DE1F8 /* GCProgressSampleTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 36F742B61B3A7016003D799C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 36CE2B5F1C93EA740084CE64 /* ProgressAtRatioView.swift in Sources */, 3667E0ED23392FEC002CCD9C /* WindowBuilder.swift in Sources */, 36CE2B681C93EA740084CE64 /* BlueDarkStyle.swift in Sources */, 36CE2B601C93EA740084CE64 /* ArcView.swift in Sources */, 36CE2B671C93EA740084CE64 /* Property.swift in Sources */, 36CE2B5E1C93EA740084CE64 /* CircularProgressView.swift in Sources */, 36CE2B5D1C93EA740084CE64 /* GradientCircularProgress.swift in Sources */, 36CE2B631C93EA740084CE64 /* GradientArcView.swift in Sources */, 36CE2B6C1C93EA740084CE64 /* Style.swift in Sources */, 36CE2B661C93EA740084CE64 /* ProgressViewController.swift in Sources */, 36CE2B611C93EA740084CE64 /* Background.swift in Sources */, 36CE2B641C93EA740084CE64 /* GradientArcWithClearColorView.swift in Sources */, 36CE2B6B1C93EA740084CE64 /* OrangeClearStyle.swift in Sources */, 36CE2B651C93EA740084CE64 /* ProgressView.swift in Sources */, 36CE2B6A1C93EA740084CE64 /* GreenLightStyle.swift in Sources */, 36CE2B691C93EA740084CE64 /* BlueIndicatorStyle.swift in Sources */, 36CE2B6D1C93EA740084CE64 /* ColorUtil.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ 36CC1C931B37083E009DE1F8 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 36CC1C7B1B37083E009DE1F8 /* GCProgressSample */; targetProxy = 36CC1C921B37083E009DE1F8 /* PBXContainerItemProxy */; }; 36F742D11B3A7016003D799C /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 36F742BA1B3A7016003D799C /* GradientCircularProgress */; targetProxy = 36F742D01B3A7016003D799C /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ 36CC1C851B37083E009DE1F8 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 36CC1C861B37083E009DE1F8 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 36CC1C8A1B37083E009DE1F8 /* LaunchScreen.xib */ = { isa = PBXVariantGroup; children = ( 36CC1C8B1B37083E009DE1F8 /* Base */, ); name = LaunchScreen.xib; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 36CC1C991B37083E009DE1F8 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; BITCODE_GENERATION_MODE = marker; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = ""; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 36CC1C9A1B37083E009DE1F8 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; BITCODE_GENERATION_MODE = bitcode; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IPHONEOS_DEPLOYMENT_TARGET = 8.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_VERSION = ""; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 36CC1C9C1B37083E009DE1F8 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CURRENT_PROJECT_VERSION = 3.13.0; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/GCProgressSample", ); INFOPLIST_FILE = GCProgressSample/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MARKETING_VERSION = 3.13.0; PRODUCT_BUNDLE_IDENTIFIER = "com.keygraphix.ios.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; name = Debug; }; 36CC1C9D1B37083E009DE1F8 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_IDENTITY = "iPhone Distribution"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CURRENT_PROJECT_VERSION = 3.13.0; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/GCProgressSample", ); INFOPLIST_FILE = GCProgressSample/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MARKETING_VERSION = 3.13.0; PRODUCT_BUNDLE_IDENTIFIER = "com.keygraphix.ios.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; }; name = Release; }; 36CC1C9F1B37083E009DE1F8 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = GCProgressSampleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.keygraphix.ios.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/GCProgressSample.app/GCProgressSample"; }; name = Debug; }; 36CC1CA01B37083E009DE1F8 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; INFOPLIST_FILE = GCProgressSampleTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.keygraphix.ios.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/GCProgressSample.app/GCProgressSample"; }; name = Release; }; 36F742D41B3A7016003D799C /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; CURRENT_PROJECT_VERSION = 3.13.0; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = GradientCircularProgress/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MARKETING_VERSION = 3.13.0; PRODUCT_BUNDLE_IDENTIFIER = "com.keygraphix.ios.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Debug; }; 36F742D51B3A7016003D799C /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = ""; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; CURRENT_PROJECT_VERSION = 3.13.0; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = GradientCircularProgress/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; MARKETING_VERSION = 3.13.0; PRODUCT_BUNDLE_IDENTIFIER = "com.keygraphix.ios.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 36CC1C771B37083E009DE1F8 /* Build configuration list for PBXProject "GCProgressSample" */ = { isa = XCConfigurationList; buildConfigurations = ( 36CC1C991B37083E009DE1F8 /* Debug */, 36CC1C9A1B37083E009DE1F8 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 36CC1C9B1B37083E009DE1F8 /* Build configuration list for PBXNativeTarget "GCProgressSample" */ = { isa = XCConfigurationList; buildConfigurations = ( 36CC1C9C1B37083E009DE1F8 /* Debug */, 36CC1C9D1B37083E009DE1F8 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 36CC1C9E1B37083E009DE1F8 /* Build configuration list for PBXNativeTarget "GCProgressSampleTests" */ = { isa = XCConfigurationList; buildConfigurations = ( 36CC1C9F1B37083E009DE1F8 /* Debug */, 36CC1CA01B37083E009DE1F8 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 36F742D81B3A7016003D799C /* Build configuration list for PBXNativeTarget "GradientCircularProgress" */ = { isa = XCConfigurationList; buildConfigurations = ( 36F742D41B3A7016003D799C /* Debug */, 36F742D51B3A7016003D799C /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 36CC1C741B37083E009DE1F8 /* Project object */; } ================================================ FILE: GCProgressSample/GCProgressSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: GCProgressSample/GCProgressSample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: GCProgressSample/GCProgressSample.xcodeproj/xcshareddata/xcschemes/GradientCircularProgress.xcscheme ================================================ ================================================ FILE: GCProgressSample/GCProgressSampleTests/GCProgressSampleTests.swift ================================================ // // GCProgressSampleTests.swift // GCProgressSampleTests // // Created by keygx on 2015/06/21. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit import XCTest class GCProgressSampleTests: XCTestCase { override func setUp() { super.setUp() // Put setup code here. This method is called before the invocation of each test method in the class. } override func tearDown() { // Put teardown code here. This method is called after the invocation of each test method in the class. super.tearDown() } func testExample() { // This is an example of a functional test case. XCTAssert(true, "Pass") } func testPerformanceExample() { // This is an example of a performance test case. self.measure() { // Put the code you want to measure the time of here. } } } ================================================ FILE: GCProgressSample/GCProgressSampleTests/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType BNDL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 ================================================ FILE: GCProgressSample/GradientCircularProgress/GradientCircularProgress.h ================================================ // // GradientCircularProgress.h // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // #import //! Project version number for GradientCircularProgress. FOUNDATION_EXPORT double GradientCircularProgressVersionNumber; //! Project version string for GradientCircularProgress. FOUNDATION_EXPORT const unsigned char GradientCircularProgressVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import ================================================ FILE: GCProgressSample/GradientCircularProgress/GradientCircularProgress.swift ================================================ // // GradientCircularProgress.swift // GradientCircularProgress // // Created by keygx on 2015/07/29. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit public class GradientCircularProgress { private var baseWindow: UIWindow? private var progressViewController: ProgressViewController? private var progressView: ProgressView? private var property: Property? public var isAvailable: Bool = false public init() {} } // MARK: Common extension GradientCircularProgress { public func updateMessage(message: String) { if !isAvailable { return } // Use addSubView if let v = progressView { v.updateMessage(message) } // Use UIWindow if let vc = progressViewController { vc.updateMessage(message: message) } } public func updateRatio(_ ratio: CGFloat) { if !isAvailable { return } // Use addSubView if let v = progressView { v.ratio = ratio } // Use UIWindow if let vc = progressViewController { vc.ratio = ratio } } } // MARK: Use UIWindow extension GradientCircularProgress { public func showAtRatio(display: Bool = true, style: StyleProperty = Style()) { if isAvailable { return } isAvailable = true property = Property(style: style) getProgressAtRatio(display: display, style: style) } private func getProgressAtRatio(display: Bool, style: StyleProperty) { baseWindow = WindowBuilder.build() progressViewController = ProgressViewController() guard let win = baseWindow, let vc = progressViewController else { return } win.rootViewController = vc win.backgroundColor = UIColor.clear vc.arc(display: display, style: style, baseWindow: baseWindow) } public func show(style: StyleProperty = Style()) { if isAvailable { return } isAvailable = true property = Property(style: style) getProgress(message: nil, style: style) } public func show(message: String, style: StyleProperty = Style()) { if isAvailable { return } isAvailable = true property = Property(style: style) getProgress(message: message, style: style) } private func getProgress(message: String?, style: StyleProperty) { baseWindow = WindowBuilder.build() progressViewController = ProgressViewController() guard let win = baseWindow, let vc = progressViewController else { return } win.rootViewController = vc win.backgroundColor = UIColor.clear vc.circle(message: message, style: style, baseWindow: baseWindow) } public func dismiss() { if !isAvailable { return } guard let prop = property else { return } if let vc = progressViewController { vc.dismiss(prop.dismissTimeInterval!) } cleanup(prop.dismissTimeInterval!, completionHandler: nil) } public func dismiss(_ completionHandler: @escaping () -> Void) -> () { if !isAvailable { return } guard let prop = property else { return } if let vc = progressViewController { vc.dismiss(prop.dismissTimeInterval!) } cleanup(prop.dismissTimeInterval!) { completionHandler() } } private func cleanup(_ t: Double, completionHandler: (() -> Void)?) { let delay = t * Double(NSEC_PER_SEC) let time = DispatchTime.now() + Double(Int64(delay)) / Double(NSEC_PER_SEC) DispatchQueue.main.asyncAfter(deadline: time) { [weak self] in guard let win = self?.baseWindow else { return } UIView.animate( withDuration: 0.3, animations: { win.alpha = 0 }, completion: { finished in self?.progressViewController = nil win.isHidden = true win.rootViewController = nil self?.baseWindow = nil self?.property = nil self?.isAvailable = false guard let completionHandler = completionHandler else { return } completionHandler() } ) } } } // MARK: Use addSubView extension GradientCircularProgress { public func showAtRatio(frame: CGRect, display: Bool = true, style: StyleProperty = Style()) -> UIView? { if isAvailable { return nil } isAvailable = true property = Property(style: style) progressView = ProgressView(frame: frame) guard let v = progressView else { return nil } v.arc(display, style: style) return v } public func show(frame: CGRect, style: StyleProperty = Style()) -> UIView? { if isAvailable { return nil } isAvailable = true property = Property(style: style) return getProgress(frame: frame, message: nil, style: style) } public func show(frame: CGRect, message: String, style: StyleProperty = Style()) -> UIView? { if isAvailable { return nil } isAvailable = true property = Property(style: style) return getProgress(frame: frame, message: message, style: style) } private func getProgress(frame: CGRect, message: String?, style: StyleProperty) -> UIView? { progressView = ProgressView(frame: frame) guard let v = progressView else { return nil } v.circle(message, style: style) return v } public func dismiss(progress view: UIView) { if !isAvailable { return } guard let prop = property else { return } cleanup(prop.dismissTimeInterval!, view: view, completionHandler: nil) } public func dismiss(progress view: UIView, completionHandler: @escaping () -> Void) -> () { if !isAvailable { return } guard let prop = property else { return } cleanup(prop.dismissTimeInterval!, view: view) { completionHandler() } } private func cleanup(_ t: Double, view: UIView, completionHandler: (() -> Void)?) { let delay = t * Double(NSEC_PER_SEC) let time = DispatchTime.now() + Double(Int64(delay)) / Double(NSEC_PER_SEC) DispatchQueue.main.asyncAfter(deadline: time) { UIView.animate( withDuration: 0.3, animations: { view.alpha = 0 }, completion: { [weak self] finished in view.removeFromSuperview() self?.property = nil self?.isAvailable = false guard let completionHandler = completionHandler else { return } completionHandler() } ) } } } ================================================ FILE: GCProgressSample/GradientCircularProgress/Info.plist ================================================ CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName $(PRODUCT_NAME) CFBundlePackageType FMWK CFBundleShortVersionString $(MARKETING_VERSION) CFBundleSignature ???? CFBundleVersion $(CURRENT_PROJECT_VERSION) NSPrincipalClass ================================================ FILE: GCProgressSample/GradientCircularProgress/Progress/Core/CircularProgressView.swift ================================================ // // CircularProgressView.swift // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit class CircularProgressView: UIView { var prop: Property? var messageLabel = UILabel() var centerPoint: CGPoint? var message: String? { willSet { messageLabel.frame = frame messageLabel.text = newValue guard let message = messageLabel.text else { return } // Attribute let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineHeightMultiple = 1.2 paragraphStyle.alignment = NSTextAlignment.center let attr = [NSAttributedString.Key.paragraphStyle: paragraphStyle] let attributedString = NSMutableAttributedString(string: message, attributes: attr) messageLabel.attributedText = attributedString messageLabel.sizeToFit() if centerPoint == nil { centerPoint = center } if let center = centerPoint { messageLabel.center = center } } } var gradientLayer = CALayer() private struct Animation { var rotationZ: CABasicAnimation { let animation: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z") animation.duration = 0.8 animation.repeatCount = HUGE animation.fromValue = NSNumber(value: 0.0) animation.toValue = NSNumber(value: 2 * Float.pi) return animation } init() {} func start(_ layer: CALayer) { layer.add(rotationZ, forKey: "rotate") } func stop(_ layer: CALayer) { layer.removeAllAnimations() } } override init(frame: CGRect) { super.init(frame: frame) backgroundColor = UIColor.clear layer.masksToBounds = true NotificationCenter.default.addObserver(self, selector: #selector(viewDidEnterBackground(_:)), name: UIApplication.didEnterBackgroundNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(viewWillEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } deinit { NotificationCenter.default.removeObserver(self) } override func didMoveToWindow() { super.didMoveToWindow() if window != nil { Animation().start(gradientLayer) } else { Animation().stop(gradientLayer) } } @objc private func viewDidEnterBackground(_ notification: Notification?) { Animation().stop(gradientLayer) } @objc private func viewWillEnterForeground(_ notification: Notification?) { Animation().start(gradientLayer) } internal func initialize(frame: CGRect) { guard let prop = prop else { return } let rect: CGRect = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height) // Base Circular if let baseLineWidth = prop.baseLineWidth, let baseArcColor = prop.baseArcColor { let circular: ArcView = ArcView(frame: rect, lineWidth: baseLineWidth) circular.color = baseArcColor circular.prop = prop addSubview(circular) } // Gradient Circular if ColorUtil.toRGBA(color: prop.startArcColor).a < 1.0 || ColorUtil.toRGBA(color: prop.endArcColor).a < 1.0 { // Clear Color let gradient: UIView = GradientArcWithClearColorView().draw(rect: rect, prop: prop) addSubview(gradient) gradientLayer = gradient.layer Animation().start(gradientLayer) } else { // Opaque Color let gradient: GradientArcView = GradientArcView(frame: rect) gradient.prop = prop addSubview(gradient) gradientLayer = gradient.layer Animation().start(gradientLayer) } } internal func showMessage(_ message: String) { guard let prop = prop else { return } // Message messageLabel.font = prop.messageLabelFont messageLabel.textAlignment = NSTextAlignment.center messageLabel.textColor = prop.messageLabelFontColor messageLabel.numberOfLines = 0 addSubview(messageLabel) self.message = message } } ================================================ FILE: GCProgressSample/GradientCircularProgress/Progress/Core/ProgressAtRatioView.swift ================================================ // // ProgressAtRatioView.swift // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit class ProgressAtRatioView: UIView { internal var arcView: ArcView? internal var prop: Property? internal var ratioLabel: UILabel = UILabel() internal var ratio: CGFloat = 0.0 { didSet { ratioLabel.text = String(format:"%.0f", ratio * 100) + "%" } } override init(frame: CGRect) { super.init(frame: frame) backgroundColor = UIColor.clear layer.masksToBounds = true } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } internal func initialize(frame: CGRect) { guard let prop = prop else { return } let rect: CGRect = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height) // Base Circular if let baseLineWidth = prop.baseLineWidth, let baseArcColor = prop.baseArcColor { let circular: ArcView = ArcView(frame: rect, lineWidth: baseLineWidth) circular.prop = prop circular.ratio = 1.0 circular.color = baseArcColor circular.lineWidth = baseLineWidth addSubview(circular) } // Gradient Circular if ColorUtil.toRGBA(color: prop.startArcColor).a < 1.0 || ColorUtil.toRGBA(color: prop.endArcColor).a < 1.0 { // Clear Color let gradient: UIView = GradientArcWithClearColorView().draw(rect: rect, prop: prop) addSubview(gradient) masking(rect: rect, prop: prop, gradient: gradient) } else { // Opaque Color let gradient: GradientArcView = GradientArcView(frame: rect) gradient.prop = prop addSubview(gradient) masking(rect: rect, prop: prop, gradient: gradient) } } private func masking(rect: CGRect, prop: Property, gradient: UIView) { // Mask arcView = ArcView(frame: rect, lineWidth: prop.arcLineWidth) guard let mask = arcView else { return } mask.prop = prop gradient.layer.mask = mask.layer } override func draw(_ rect: CGRect) { guard let mask = arcView else { return } if ratio > 1.0 { mask.ratio = 1.0 } else { mask.ratio = ratio } mask.setNeedsDisplay() } func showRatio() { guard let prop = prop else { return } // Progress Ratio ratioLabel.text = " " ratioLabel.font = prop.ratioLabelFont ratioLabel.textAlignment = NSTextAlignment.right ratioLabel.textColor = prop.ratioLabelFontColor ratioLabel.sizeToFit() ratioLabel.center = center addSubview(ratioLabel) } } ================================================ FILE: GCProgressSample/GradientCircularProgress/Progress/Elements/ArcView.swift ================================================ // // Arc.swift // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit class ArcView: UIView { var prop: Property? var ratio: CGFloat = 1.0 var color: UIColor = UIColor.black var lineWidth: CGFloat = 0.0 required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } init(frame: CGRect, lineWidth: CGFloat) { super.init(frame: frame) backgroundColor = UIColor.clear layer.masksToBounds = true self.lineWidth = lineWidth } override func draw(_ rect: CGRect) { drawArc(rect: rect) } private func drawArc(rect: CGRect) { guard let prop = prop else { return } let circularRect: CGRect = prop.progressRect let arcPoint: CGPoint = CGPoint(x: rect.width/2, y: rect.height/2) let arcRadius: CGFloat = circularRect.width/2 + prop.arcLineWidth/2 let arcStartAngle: CGFloat = -CGFloat.pi/2 let arcEndAngle: CGFloat = ratio * 2.0 * CGFloat.pi - CGFloat.pi/2 let arc: UIBezierPath = UIBezierPath(arcCenter: arcPoint, radius: arcRadius, startAngle: arcStartAngle, endAngle: arcEndAngle, clockwise: true) color.setStroke() arc.lineWidth = lineWidth arc.lineCapStyle = prop.arcLineCapStyle arc.stroke() } } ================================================ FILE: GCProgressSample/GradientCircularProgress/Progress/Elements/Background.swift ================================================ // // Background.swift // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // struct Background { internal func blurEffectView(fromBlurStyle style: BackgroundStyles, frame: CGRect) -> UIVisualEffectView? { var blurView: UIVisualEffectView? // return (blurEffectStyle: UIBlurEffectStyle?, isUserInteraction: Bool) let backgroundStyle = getStyle(style) if let blur = backgroundStyle.blurEffectStyle { // UIBlurEffectStyle (.extraLight, .light, .dark) let effect = UIBlurEffect(style: blur) blurView = UIVisualEffectView(effect: effect) } else { if !backgroundStyle.isUserInteraction { // .transparent blurView = UIVisualEffectView(effect: nil) } } blurView?.frame = frame return blurView } private func getStyle(_ style: BackgroundStyles) -> (blurEffectStyle: UIBlurEffect.Style?, isUserInteraction: Bool) { switch style { case .extraLight: return (.extraLight, false) case .light: return (.light, false) case .dark: return (.dark, false) case .transparent: return (nil, false) default: // .none return (nil, true) } } } ================================================ FILE: GCProgressSample/GradientCircularProgress/Progress/Elements/GradientArcView.swift ================================================ // // GradientArcView.swift // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit class GradientArcView: UIView { internal var prop: Property? override init(frame: CGRect) { super.init(frame: frame) backgroundColor = UIColor.clear layer.masksToBounds = true } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func getGradientPointColor(ratio: CGFloat, startColor: UIColor, endColor: UIColor) -> UIColor { let sColor = ColorUtil.toRGBA(color: startColor) let eColor = ColorUtil.toRGBA(color: endColor) let r = (eColor.r - sColor.r) * ratio + sColor.r let g = (eColor.g - sColor.g) * ratio + sColor.g let b = (eColor.b - sColor.b) * ratio + sColor.b let a = (eColor.a - sColor.a) * ratio + sColor.a return UIColor(red: r, green: g, blue: b, alpha: a) } override func draw(_ rect: CGRect) { guard let prop = prop else { return } let circularRect: CGRect = prop.progressRect var currentAngle: CGFloat = 0.0 for i in stride(from:CGFloat(0.0), through: CGFloat(1.0), by: CGFloat(0.005)) { let arcPoint: CGPoint = CGPoint(x: rect.width/2, y: rect.height/2) let arcRadius: CGFloat = circularRect.width/2 + prop.arcLineWidth/2 let arcStartAngle: CGFloat = -CGFloat.pi/2 let arcEndAngle: CGFloat = i * 2.0 * CGFloat.pi - CGFloat.pi/2 if currentAngle == 0.0 { currentAngle = arcStartAngle } else { currentAngle = arcEndAngle - 0.05 } let arc: UIBezierPath = UIBezierPath(arcCenter: arcPoint, radius: arcRadius, startAngle: currentAngle, endAngle: arcEndAngle, clockwise: true) let strokeColor: UIColor = getGradientPointColor(ratio: i, startColor: prop.startArcColor, endColor: prop.endArcColor) strokeColor.setStroke() arc.lineWidth = prop.arcLineWidth arc.lineCapStyle = prop.arcLineCapStyle arc.stroke() } } } ================================================ FILE: GCProgressSample/GradientCircularProgress/Progress/Elements/GradientArcWithClearColorView.swift ================================================ // // GradientArcWithClearColorView.swift // GradientCircularProgress // // Created by keygx on 2015/11/20. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit class GradientArcWithClearColorView: UIView { internal func draw(rect: CGRect, prop: Property) -> UIImageView { // Gradient Clear Circular /* Prop */ var startArcColorProp = prop var endArcColorProp = prop var startGradientMaskProp = prop var endGradientMaskProp = prop var solidMaskProp = prop // StartArc startArcColorProp.endArcColor = ColorUtil.toNotOpacityColor(color: startArcColorProp.startArcColor) // EndArc endArcColorProp.startArcColor = ColorUtil.toNotOpacityColor(color: endArcColorProp.endArcColor) // StartGradientMask startGradientMaskProp.startArcColor = UIColor.black startGradientMaskProp.endArcColor = UIColor.white startGradientMaskProp.progressSize += 10.0 startGradientMaskProp.arcLineWidth += 20.0 // EndGradientMask endGradientMaskProp.startArcColor = UIColor.white endGradientMaskProp.endArcColor = UIColor.black endGradientMaskProp.progressSize += 10.0 endGradientMaskProp.arcLineWidth += 20.0 // SolidMask solidMaskProp.startArcColor = UIColor.black solidMaskProp.endArcColor = UIColor.black /* Mask Image */ // StartArcColorImage let startArcColorView = ArcView(frame: rect, lineWidth: startArcColorProp.arcLineWidth) startArcColorView.color = startArcColorProp.startArcColor startArcColorView.prop = startArcColorProp let startArcColorImage = viewToUIImage(view: startArcColorView)! // StartGradientMaskImage let startGradientMaskView = GradientArcView(frame: rect) startGradientMaskView.prop = startGradientMaskProp let startGradientMaskImage = viewToUIImage(view: startGradientMaskView)! // EndArcColorImage let endArcColorView = ArcView(frame: rect, lineWidth: endArcColorProp.arcLineWidth) endArcColorView.color = endArcColorProp.startArcColor endArcColorView.prop = endArcColorProp let endArcColorImage = viewToUIImage(view: endArcColorView)! // EndGradientMaskImage let endGradientMaskView = GradientArcView(frame: rect) endGradientMaskView.prop = endGradientMaskProp let endGradientMaskImage = viewToUIImage(view: endGradientMaskView)! // SolidMaskImage let solidMaskView = ArcView(frame: rect, lineWidth: solidMaskProp.arcLineWidth) solidMaskView.prop = solidMaskProp let solidMaskImage = viewToUIImage(view: solidMaskView)! /* Masking */ var startArcImage = mask(image: startGradientMaskImage, maskImage: solidMaskImage) startArcImage = mask(image: startArcColorImage, maskImage: startArcImage) var endArcImage = mask(image: endGradientMaskImage, maskImage: solidMaskImage) endArcImage = mask(image: endArcColorImage, maskImage: endArcImage) /* Composite */ let image: UIImage = composite(image1: startArcImage, image2: endArcImage, prop: prop) /* UIImageView */ let imageView = UIImageView(image: image) imageView.contentMode = .scaleAspectFill imageView.clipsToBounds = true return imageView } internal func mask(image: UIImage, maskImage: UIImage) -> UIImage { let maskRef: CGImage = maskImage.cgImage! let mask: CGImage = CGImage( maskWidth: maskRef.width, height: maskRef.height, bitsPerComponent: maskRef.bitsPerComponent, bitsPerPixel: maskRef.bitsPerPixel, bytesPerRow: maskRef.bytesPerRow, provider: maskRef.dataProvider!, decode: nil, shouldInterpolate: false)! let maskedImageRef: CGImage = image.cgImage!.masking(mask)! let scale = UIScreen.main.scale let maskedImage: UIImage = UIImage(cgImage: maskedImageRef, scale: scale, orientation: .up) return maskedImage } internal func viewToUIImage(view: UIView) -> UIImage? { let scale = UIScreen.main.scale UIGraphicsBeginImageContextWithOptions(view.frame.size, false, scale) view.layer.render(in: UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } internal func composite(image1: UIImage, image2: UIImage, prop: Property) -> UIImage { let scale = UIScreen.main.scale UIGraphicsBeginImageContextWithOptions(image1.size, false, scale) image1.draw( in: CGRect(x: 0, y: 0, width: image1.size.width, height: image1.size.height), blendMode: .overlay, alpha: ColorUtil.toRGBA(color: prop.startArcColor).a) image2.draw( in: CGRect(x: 0, y: 0, width: image2.size.width, height: image2.size.height), blendMode: .overlay, alpha: ColorUtil.toRGBA(color: prop.endArcColor).a) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image! } } ================================================ FILE: GCProgressSample/GradientCircularProgress/Progress/Elements/WindowBuilder.swift ================================================ // // WindowBuilder.swift // GradientCircularProgress // // Created by keygx on 2019/09/24. // Copyright © 2019 keygx. All rights reserved. // import UIKit class WindowBuilder { static func build() -> UIWindow? { var baseWindow: UIWindow? if #available(iOS 13.0, *) { let windowScene = UIApplication.shared.connectedScenes .filter { $0.activationState == .foregroundActive }.first if let windowScene = windowScene as? UIWindowScene { baseWindow = UIWindow(windowScene: windowScene) } else { baseWindow = UIWindow() } } else { baseWindow = UIWindow() } baseWindow?.bounds = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height) baseWindow?.backgroundColor = UIColor.clear baseWindow?.windowLevel = UIWindow.Level.alert + 1 baseWindow?.makeKeyAndVisible() return baseWindow } } ================================================ FILE: GCProgressSample/GradientCircularProgress/Progress/ProgressView.swift ================================================ // // ProgressView.swift // GradientCircularProgress // // Created by keygx on 2016/03/07. // Copyright (c) 2016年 keygx. All rights reserved. // import UIKit class ProgressView: UIView { private var viewRect: CGRect? private var blurView: UIVisualEffectView? private var progressAtRatioView: ProgressAtRatioView? private var circularProgressView: CircularProgressView? internal var prop: Property? internal var ratio: CGFloat = 0.0 { didSet { progressAtRatioView?.ratio = ratio progressAtRatioView?.setNeedsDisplay() } } override init(frame: CGRect) { super.init(frame: frame) initialize(frame: frame) } required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder)! } private func initialize(frame: CGRect) { viewRect = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height) clipsToBounds = true } internal func arc(_ display: Bool, style: StyleProperty) { prop = Property(style: style) guard let prop = prop else { return } isUserInteractionEnabled = !(prop.backgroundStyle.rawValue == 0) ? true : false getBlurView() progressAtRatioView = ProgressAtRatioView(frame: CGRect(x: 0, y: 0, width: prop.progressSize, height: prop.progressSize)) guard let progressAtRatioView = progressAtRatioView else { return } progressAtRatioView.prop = prop progressAtRatioView.initialize(frame: progressAtRatioView.frame) if display { progressAtRatioView.showRatio() } progressAtRatioView.frame = CGRect( x: (frame.size.width - progressAtRatioView.frame.size.width) / 2, y: (frame.size.height - progressAtRatioView.frame.size.height) / 2, width: progressAtRatioView.frame.size.width, height: progressAtRatioView.frame.size.height) addSubview(progressAtRatioView) } internal func circle(_ message: String?, style: StyleProperty) { prop = Property(style: style) guard let prop = prop else { return } isUserInteractionEnabled = !(prop.backgroundStyle.rawValue == 0) ? true : false getBlurView() circularProgressView = CircularProgressView(frame: CGRect(x: 0, y: 0, width: prop.progressSize, height: prop.progressSize)) guard let circularProgressView = circularProgressView else { return } circularProgressView.prop = prop circularProgressView.initialize(frame: circularProgressView.frame) if let message = message { circularProgressView.showMessage(message) } circularProgressView.frame = CGRect( x: (frame.size.width - circularProgressView.frame.size.width) / 2, y: (frame.size.height - circularProgressView.frame.size.height) / 2, width: circularProgressView.frame.size.width, height: circularProgressView.frame.size.height) addSubview(circularProgressView) } internal func updateMessage(_ message: String) { guard let circularProgressView = circularProgressView else { return } circularProgressView.message = message } private func getBlurView() { guard let rect = viewRect, let prop = prop else { return } blurView = Background().blurEffectView(fromBlurStyle: prop.backgroundStyle, frame: rect) guard let blurView = blurView else { return } backgroundColor = UIColor.clear addSubview(blurView) } } ================================================ FILE: GCProgressSample/GradientCircularProgress/Progress/ProgressViewController.swift ================================================ // // ProgressViewController.swift // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit class ProgressViewController: UIViewController { private var viewRect: CGRect? private var blurView: UIVisualEffectView? private var progressAtRatioView: ProgressAtRatioView? private var circularProgressView: CircularProgressView? internal var prop: Property? internal var ratio: CGFloat = 0.0 { didSet { progressAtRatioView?.ratio = ratio progressAtRatioView?.setNeedsDisplay() } } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = UIColor.clear } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } override var shouldAutorotate: Bool { return false } override var prefersStatusBarHidden: Bool { let orientation: UIInterfaceOrientation if #available(iOS 13.0, *) { orientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation ?? .portrait } else { orientation = UIApplication.shared.statusBarOrientation } switch orientation { case .landscapeLeft, .landscapeRight: // LandscapeLeft | LandscapeRight return true default: // Unknown | Portrait | PortraitUpsideDown return false } } private func getViewRect() { let window = UIWindow(frame: UIScreen.main.bounds) viewRect = window.frame } private func getBlurView() { guard let rect = viewRect, let prop = prop else { return } blurView = Background().blurEffectView(fromBlurStyle: prop.backgroundStyle, frame: rect) guard let blurView = blurView else { return } view.backgroundColor = UIColor.clear view.addSubview(blurView) } internal func arc(display: Bool, style: StyleProperty, baseWindow: UIWindow?) { prop = Property(style: style) guard let win = baseWindow, let prop = prop else { return } win.isUserInteractionEnabled = !(prop.backgroundStyle.rawValue == 0) ? true : false // 0 == .None getViewRect() getBlurView() progressAtRatioView = ProgressAtRatioView(frame: CGRect(x: 0, y: 0, width: prop.progressSize, height: prop.progressSize)) guard let progressAtRatioView = progressAtRatioView else { return } progressAtRatioView.prop = prop progressAtRatioView.initialize(frame: progressAtRatioView.frame) if display { progressAtRatioView.showRatio() } progressAtRatioView.center = view.center view.addSubview(progressAtRatioView) } internal func circle(message: String?, style: StyleProperty, baseWindow: UIWindow?) { prop = Property(style: style) guard let win = baseWindow, let prop = prop else { return } win.isUserInteractionEnabled = !(prop.backgroundStyle.rawValue == 0) ? true : false // 0 == .None getViewRect() getBlurView() circularProgressView = CircularProgressView(frame: CGRect(x: 0, y: 0, width: prop.progressSize, height: prop.progressSize)) guard let circularProgressView = circularProgressView else { return } circularProgressView.prop = prop circularProgressView.initialize(frame: circularProgressView.frame) if message != nil { circularProgressView.showMessage(message!) } circularProgressView.center = view.center view.addSubview(circularProgressView) } internal func updateMessage(message: String) { guard let circularProgressView = circularProgressView else { return } circularProgressView.message = message } internal func dismiss(_ t: Double) { let delay = t * Double(NSEC_PER_SEC) let time = DispatchTime.now() + Double(Int64(delay)) / Double(NSEC_PER_SEC) DispatchQueue.main.asyncAfter(deadline: time) { guard let blurView = self.blurView, let progressAtRatioView = self.progressAtRatioView, let circularProgressView = self.circularProgressView else { return } UIView.animate( withDuration: 0.3, animations: { progressAtRatioView.alpha = 0.0 circularProgressView.alpha = 0.0 }, completion: { finished in progressAtRatioView.removeFromSuperview() circularProgressView.removeFromSuperview() blurView.removeFromSuperview() } ) } } } ================================================ FILE: GCProgressSample/GradientCircularProgress/Progress/Property.swift ================================================ // // Property.swift // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // public protocol StyleProperty { // Progress Size var progressSize: CGFloat { get set } // Gradient Circular var arcLineWidth: CGFloat { get set } var startArcColor: UIColor { get set } var endArcColor: UIColor { get set } // Base Circular var baseLineWidth: CGFloat? { get set } var baseArcColor: UIColor? { get set } // Ratio var ratioLabelFont: UIFont? { get set } var ratioLabelFontColor: UIColor? { get set } // Message var messageLabelFont: UIFont? { get set } var messageLabelFontColor: UIColor? { get set } // Background var backgroundStyle: BackgroundStyles { get set } // Dismiss var dismissTimeInterval: Double? { get set } // Initialize init() } public enum BackgroundStyles: Int { case none = 0 case extraLight case light case dark case transparent } internal struct Property { let margin: CGFloat = 5.0 let arcLineCapStyle: CGLineCap = CGLineCap.butt // Progress Size var progressSize: CGFloat // Gradient Circular var arcLineWidth: CGFloat var startArcColor: UIColor var endArcColor: UIColor // Base Circular var baseLineWidth: CGFloat? var baseArcColor: UIColor? // Ratio let ratioLabelFont: UIFont? let ratioLabelFontColor: UIColor? // Message let messageLabelFont: UIFont? let messageLabelFontColor: UIColor? // Background let backgroundStyle: BackgroundStyles // Dismiss let dismissTimeInterval: Double? // Progress Rect var progressRect: CGRect { let lineWidth: CGFloat = (arcLineWidth > baseLineWidth!) ? arcLineWidth : baseLineWidth! return CGRect(x: 0, y: 0, width: progressSize - lineWidth * 2, height: progressSize - lineWidth * 2) } init(style: StyleProperty) { let styles: StyleProperty = style progressSize = styles.progressSize arcLineWidth = styles.arcLineWidth startArcColor = styles.startArcColor endArcColor = styles.endArcColor baseLineWidth = styles.baseLineWidth ?? 0.0 baseArcColor = styles.baseArcColor ?? UIColor.clear ratioLabelFont = styles.ratioLabelFont ?? UIFont.systemFont(ofSize: 16.0) ratioLabelFontColor = styles.ratioLabelFontColor ?? UIColor.clear messageLabelFont = styles.messageLabelFont ?? UIFont.systemFont(ofSize: 16.0) messageLabelFontColor = styles.messageLabelFontColor ?? UIColor.clear backgroundStyle = styles.backgroundStyle dismissTimeInterval = styles.dismissTimeInterval ?? 0.8 } } ================================================ FILE: GCProgressSample/GradientCircularProgress/Styles/BlueDarkStyle.swift ================================================ // // BlueDarkStyle.swift // GradientCircularProgress // // Created by keygx on 2015/08/31. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit public struct BlueDarkStyle: StyleProperty { // Progress Size public var progressSize: CGFloat = 260 // Gradient Circular public var arcLineWidth: CGFloat = 4.0 public var startArcColor: UIColor = ColorUtil.toUIColor(r: 0.0, g: 122.0, b: 255.0, a: 1.0) public var endArcColor: UIColor = UIColor.cyan // Base Circular public var baseLineWidth: CGFloat? = 5.0 public var baseArcColor: UIColor? = UIColor(red:0.0, green: 0.0, blue: 0.0, alpha: 0.2) // Ratio public var ratioLabelFont: UIFont? = UIFont(name: "Verdana-Bold", size: 16.0) public var ratioLabelFontColor: UIColor? = UIColor.white // Message public var messageLabelFont: UIFont? = UIFont.systemFont(ofSize: 16.0) public var messageLabelFontColor: UIColor? = UIColor.white // Background public var backgroundStyle: BackgroundStyles = .dark // Dismiss public var dismissTimeInterval: Double? = nil // 'nil' for default setting. public init() {} } ================================================ FILE: GCProgressSample/GradientCircularProgress/Styles/BlueIndicatorStyle.swift ================================================ // // BlueIndicatorStyle.swift // GradientCircularProgress // // Created by keygx on 2015/08/31. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit public struct BlueIndicatorStyle: StyleProperty { // Progress Size public var progressSize: CGFloat = 44 // Gradient Circular public var arcLineWidth: CGFloat = 4.0 public var startArcColor: UIColor = ColorUtil.toUIColor(r: 235.0, g: 245.0, b: 255.0, a: 1.0) public var endArcColor: UIColor = ColorUtil.toUIColor(r: 0.0, g: 122.0, b: 255.0, a: 1.0) // Base Circular public var baseLineWidth: CGFloat? = 4.0 public var baseArcColor: UIColor? = ColorUtil.toUIColor(r: 215.0, g: 215.0, b: 215.0, a: 0.4) // Ratio public var ratioLabelFont: UIFont? = nil public var ratioLabelFontColor: UIColor? = nil // Message public var messageLabelFont: UIFont? = nil public var messageLabelFontColor: UIColor? = nil // Background public var backgroundStyle: BackgroundStyles = .none // Dismiss public var dismissTimeInterval: Double? = nil // 'nil' for default setting. public init() {} } ================================================ FILE: GCProgressSample/GradientCircularProgress/Styles/GreenLightStyle.swift ================================================ // // GreenLightStyle.swift // GradientCircularProgress // // Created by keygx on 2015/11/24. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit public struct GreenLightStyle: StyleProperty { // Progress Size public var progressSize: CGFloat = 200 // Gradient Circular public var arcLineWidth: CGFloat = 32.0 public var startArcColor: UIColor = ColorUtil.toUIColor(r: 40.0, g: 110.0, b: 60.0, a: 1.0) public var endArcColor: UIColor = UIColor.green // Base Circular public var baseLineWidth: CGFloat? = 1.0 public var baseArcColor: UIColor? = UIColor(red:0.0, green: 0.0, blue: 0.0, alpha: 0.1) // Ratio public var ratioLabelFont: UIFont? = UIFont(name: "Verdana-Bold", size: 18.0) public var ratioLabelFontColor: UIColor? = UIColor.darkGray // Message public var messageLabelFont: UIFont? = UIFont(name: "Verdana", size: 18.0) public var messageLabelFontColor: UIColor? = UIColor.darkGray // Background public var backgroundStyle: BackgroundStyles = .light // Dismiss public var dismissTimeInterval: Double? = nil // 'nil' for default setting. public init() {} } ================================================ FILE: GCProgressSample/GradientCircularProgress/Styles/OrangeClearStyle.swift ================================================ // // OrangeClearStyle.swift // GradientCircularProgress // // Created by keygx on 2015/11/24. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit public struct OrangeClearStyle: StyleProperty { // Progress Size public var progressSize: CGFloat = 80 // Gradient Circular public var arcLineWidth: CGFloat = 6.0 public var startArcColor: UIColor = UIColor.clear public var endArcColor: UIColor = UIColor.orange // Base Circular public var baseLineWidth: CGFloat? = nil public var baseArcColor: UIColor? = nil // Ratio public var ratioLabelFont: UIFont? = UIFont.systemFont(ofSize: 13.0) public var ratioLabelFontColor: UIColor? = UIColor.black // Message public var messageLabelFont: UIFont? = nil public var messageLabelFontColor: UIColor? = nil // Background public var backgroundStyle: BackgroundStyles = .none // Dismiss public var dismissTimeInterval: Double? = nil // 'nil' for default setting. public init() {} } ================================================ FILE: GCProgressSample/GradientCircularProgress/Styles/Style.swift ================================================ // // DefaultStyle.swift // GradientCircularProgress // // Created by keygx on 2015/08/31. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit public struct Style: StyleProperty { // Progress Size public var progressSize: CGFloat = 220 // Gradient Circular public var arcLineWidth: CGFloat = 16.0 public var startArcColor: UIColor = ColorUtil.toUIColor(r: 230.0, g: 230.0, b: 230.0, a: 0.6) public var endArcColor: UIColor = ColorUtil.toUIColor(r: 90.0, g: 90.0, b: 90.0, a: 1.0) // Base Circular public var baseLineWidth: CGFloat? = 16.0 public var baseArcColor: UIColor? = UIColor(red:1.0, green: 1.0, blue: 1.0, alpha: 0.8) // Ratio public var ratioLabelFont: UIFont? = UIFont.systemFont(ofSize: 18.0) public var ratioLabelFontColor: UIColor? = UIColor.black // Message public var messageLabelFont: UIFont? = UIFont.systemFont(ofSize: 18.0) public var messageLabelFontColor: UIColor? = UIColor.black // Background public var backgroundStyle: BackgroundStyles = .extraLight // Dismiss public var dismissTimeInterval: Double? = nil // 'nil' for default setting. public init() {} } ================================================ FILE: GCProgressSample/GradientCircularProgress/Utils/ColorUtil.swift ================================================ // // ColorUtil.swift // GradientCircularProgress // // Created by keygx on 2015/11/23. // Copyright © 2015年 keygx. All rights reserved. // import UIKit public class ColorUtil { public class func toUIColor(r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat) -> UIColor { return UIColor(red: r/255.0, green: g/255.0, blue: b/255.0, alpha: a) } internal class func toRGBA(color: UIColor) -> (r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat) { var r: CGFloat = 0.0 var g: CGFloat = 0.0 var b: CGFloat = 0.0 var a: CGFloat = 0.0 color.getRed(&r, green: &g, blue: &b, alpha: &a) return (r, g, b, a) } internal class func toNotOpacityColor(color: UIColor) -> UIColor { if color == UIColor.clear { return UIColor.white } else { return UIColor( red: ColorUtil.toRGBA(color: color).r, green: ColorUtil.toRGBA(color: color).g, blue: ColorUtil.toRGBA(color: color).b, alpha: 1.0) } } } ================================================ FILE: GradientCircularProgress.podspec ================================================ Pod::Spec.new do |s| s.name = "GradientCircularProgress" s.version = "3.13.0" s.summary = "Customizable progress indicator library in Swift" s.homepage = "https://github.com/keygx/GradientCircularProgress" s.license = { :type => "MIT", :file => "LICENSE" } s.author = { "keygx" => "y.kagiyama@gmail.com" } s.social_media_url = "http://twitter.com/keygx" s.platform = :ios s.ios.deployment_target = '8.0' s.source = { :git => "https://github.com/keygx/GradientCircularProgress.git", :tag => "#{s.version}" } s.source_files = "source/**/*" s.requires_arc = true end ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 Yukihiko Kagiyama Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Gradient Circular Progress Customizable progress indicator library in Swift ## Requirements - Swift 5.1 - iOS 8.0 or later ## Screen Shots - Preset style: [BlueDarkStyle.swift](https://github.com/keygx/GradientCircularProgress/blob/master/Source/BlueDarkStyle.swift) ![](images/scr_BlueDarkStyle_01.png) ![](images/scr_BlueDarkStyle_02.png) - All preset styles ![](images/styles_01.png) ![](images/styles_02.png) - Example Use AddSubView ![](images/scr_AddSubViewEx_01.png) ![](images/scr_AddSubViewEx_02.png) ## Installation ### Carthage ```Cartfile github "keygx/GradientCircularProgress" ``` ### CocoaPods ```PodFile pod 'GradientCircularProgress', :git => 'https://github.com/keygx/GradientCircularProgress' ``` ### Swift versions support - Swift 5.1, tag "swift5.1" - Swift 5, tag "swift5" - Swift 4.2, tag "swift4.2" - Swift 4.1, tag "swift4.1" - Swift 4.0, tag "swift4.0" ## Style Settings Please make your original styles ![](images/properties.png) - Define custom style structs that implements the StyleProperty Protocol [MyStyle.swift](https://github.com/keygx/GradientCircularProgress/blob/master/Sample/MyStyle.swift) ```swift import GradientCircularProgress public struct MyStyle : StyleProperty { /*** style properties **********************************************************************************/ // Progress Size public var progressSize: CGFloat = 200 // Gradient Circular public var arcLineWidth: CGFloat = 18.0 public var startArcColor: UIColor = UIColor.clear() public var endArcColor: UIColor = UIColor.orange() // Base Circular public var baseLineWidth: CGFloat? = 19.0 public var baseArcColor: UIColor? = UIColor.darkGray() // Ratio public var ratioLabelFont: UIFont? = UIFont(name: "Verdana-Bold", size: 16.0) public var ratioLabelFontColor: UIColor? = UIColor.white() // Message public var messageLabelFont: UIFont? = UIFont.systemFont(ofSize: 16.0) public var messageLabelFontColor: UIColor? = UIColor.white() // Background public var backgroundStyle: BackgroundStyles = .dark // Dismiss public var dismissTimeInterval: Double? = 0.0 // 'nil' for default setting. /*** style properties **********************************************************************************/ public init() {} } ``` ![](images/scr_MyStyle.png) ## Usage ```swift import GradientCircularProgress ``` ### Basic #### UIWindow ```swift let progress = GradientCircularProgress() progress.show(message: "Loading...", MyStyle()) progress.dismiss() ``` #### addSubView ```swift let progress = GradientCircularProgress() let progressView = progress.show(frame: rect, message: "Loading...", style: MyStyle()) view.addSubview(progressView!) progress.dismiss(progress: progressView!) ``` ### at Rtio #### UIWindow ```swift let progress = GradientCircularProgress() let ratio: CGFloat = CGFloat(totalBytesWritten) / CGFloat(totalBytesExpectedToWrite) progress.showAtRatio(style: MyStyle()) progress.updateRatio(ratio) progress.dismiss() ``` #### addSubView ```swift let progress = GradientCircularProgress() let progressView = progress.showAtRatio(frame: rect, display: true, style: MyStyle()) view.addSubview(progressView!) progress.updateRatio(ratio) progress.dismiss(progress: progressView!) ``` ### Update Message #### UIWindow ```swift let progress = GradientCircularProgress() progress.show(message: "Download\n0 / 4", MyStyle()) progress.updateMessage(message: "Download\n1 / 4") progress.updateMessage(message: "Download\n2 / 4") progress.updateMessage(message: "Download\n3 / 4") progress.updateMessage(message: "Download\n4 / 4") progress.updateMessage(message: "Completed!") progress.dismiss() ``` #### addSubView ```swift let progress = GradientCircularProgress() let progressView = progress.show(frame: rect, message: "Download\n0 / 4", style: MyStyle()) view.addSubview(progressView!) progress.updateMessage(message: "Download\n1 / 4") progress.updateMessage(message: "Download\n2 / 4") progress.updateMessage(message: "Download\n3 / 4") progress.updateMessage(message: "Download\n4 / 4") progress.updateMessage(message: "Completed!") progress.dismiss(progress: progressView!) ``` ## API ### Use UIWindow ```swift public func showAtRatio(display: Bool = true, style: StyleProperty = Style()) public func show(style: StyleProperty = Style()) public func show(message: String, style: StyleProperty = Style()) public func dismiss() public func dismiss(_ completionHandler: () -> Void) -> () ``` ### Use addSubView ```swift public func showAtRatio(frame: CGRect, display: Bool = true, style: StyleProperty = Style()) -> UIView? public func show(frame: CGRect, style: StyleProperty = Style()) -> UIView? public func show(frame: CGRect, message: String, style: StyleProperty = Style()) -> UIView? public func dismiss(progress view: UIView) public func dismiss(progress view: UIView, completionHandler: () -> Void) -> () ``` ### Common ```swift public func updateMessage(message message: String) public func updateRatio(_ ratio: CGFloat) ``` ## License Gradient Circular Progress is released under the MIT license. See LICENSE for details. ## Author Yukihiko Kagiyama (keygx) ================================================ FILE: Sample/BackgroundTransparentStyle.swift ================================================ // // BackgroundTransparentStyle.swift // GradientCircularProgress // // Created by keygx on 2016/12/03. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit import GradientCircularProgress public struct BackgroundTransparentStyle: StyleProperty { /*** style properties **********************************************************************************/ // Progress Size public var progressSize: CGFloat = 200 // Gradient Circular public var arcLineWidth: CGFloat = 4.0 public var startArcColor: UIColor = ColorUtil.toUIColor(r: 0.0, g: 122.0, b: 255.0, a: 1.0) public var endArcColor: UIColor = UIColor.cyan // Base Circular public var baseLineWidth: CGFloat? = 6.0 public var baseArcColor: UIColor? = UIColor(red:0.0, green: 0.0, blue: 0.0, alpha: 0.2) // Ratio public var ratioLabelFont: UIFont? = UIFont.systemFont(ofSize: 16.0) public var ratioLabelFontColor: UIColor? = UIColor.black // Message public var messageLabelFont: UIFont? = UIFont.systemFont(ofSize: 16.0) public var messageLabelFontColor: UIColor? = UIColor.black // Background public var backgroundStyle: BackgroundStyles = .transparent // Dismiss public var dismissTimeInterval: Double? = nil // 'nil' for default setting. /*** style properties **********************************************************************************/ public init() {} } ================================================ FILE: Sample/MyStyle.swift ================================================ // // MyStyle.swift // GradientCircularProgress // // Created by keygx on 2015/11/25. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit import GradientCircularProgress public struct MyStyle: StyleProperty { /*** style properties **********************************************************************************/ // Progress Size public var progressSize: CGFloat = 200 // Gradient Circular public var arcLineWidth: CGFloat = 18.0 public var startArcColor: UIColor = UIColor.clear public var endArcColor: UIColor = UIColor.orange // Base Circular public var baseLineWidth: CGFloat? = 19.0 public var baseArcColor: UIColor? = UIColor.darkGray // Ratio public var ratioLabelFont: UIFont? = UIFont(name: "Verdana-Bold", size: 16.0) public var ratioLabelFontColor: UIColor? = UIColor.white // Message public var messageLabelFont: UIFont? = UIFont.systemFont(ofSize: 16.0) public var messageLabelFontColor: UIColor? = UIColor.white // Background public var backgroundStyle: BackgroundStyles = .dark // Dismiss public var dismissTimeInterval: Double? = 0.0 // 'nil' for default setting. /*** style properties **********************************************************************************/ public init() {} } ================================================ FILE: source/GradientCircularProgress.h ================================================ // // GradientCircularProgress.h // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // #import //! Project version number for GradientCircularProgress. FOUNDATION_EXPORT double GradientCircularProgressVersionNumber; //! Project version string for GradientCircularProgress. FOUNDATION_EXPORT const unsigned char GradientCircularProgressVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import ================================================ FILE: source/GradientCircularProgress.swift ================================================ // // GradientCircularProgress.swift // GradientCircularProgress // // Created by keygx on 2015/07/29. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit public class GradientCircularProgress { private var baseWindow: UIWindow? private var progressViewController: ProgressViewController? private var progressView: ProgressView? private var property: Property? public var isAvailable: Bool = false public init() {} } // MARK: Common extension GradientCircularProgress { public func updateMessage(message: String) { if !isAvailable { return } // Use addSubView if let v = progressView { v.updateMessage(message) } // Use UIWindow if let vc = progressViewController { vc.updateMessage(message: message) } } public func updateRatio(_ ratio: CGFloat) { if !isAvailable { return } // Use addSubView if let v = progressView { v.ratio = ratio } // Use UIWindow if let vc = progressViewController { vc.ratio = ratio } } } // MARK: Use UIWindow extension GradientCircularProgress { public func showAtRatio(display: Bool = true, style: StyleProperty = Style()) { if isAvailable { return } isAvailable = true property = Property(style: style) getProgressAtRatio(display: display, style: style) } private func getProgressAtRatio(display: Bool, style: StyleProperty) { baseWindow = WindowBuilder.build() progressViewController = ProgressViewController() guard let win = baseWindow, let vc = progressViewController else { return } win.rootViewController = vc win.backgroundColor = UIColor.clear vc.arc(display: display, style: style, baseWindow: baseWindow) } public func show(style: StyleProperty = Style()) { if isAvailable { return } isAvailable = true property = Property(style: style) getProgress(message: nil, style: style) } public func show(message: String, style: StyleProperty = Style()) { if isAvailable { return } isAvailable = true property = Property(style: style) getProgress(message: message, style: style) } private func getProgress(message: String?, style: StyleProperty) { baseWindow = WindowBuilder.build() progressViewController = ProgressViewController() guard let win = baseWindow, let vc = progressViewController else { return } win.rootViewController = vc win.backgroundColor = UIColor.clear vc.circle(message: message, style: style, baseWindow: baseWindow) } public func dismiss() { if !isAvailable { return } guard let prop = property else { return } if let vc = progressViewController { vc.dismiss(prop.dismissTimeInterval!) } cleanup(prop.dismissTimeInterval!, completionHandler: nil) } public func dismiss(_ completionHandler: @escaping () -> Void) -> () { if !isAvailable { return } guard let prop = property else { return } if let vc = progressViewController { vc.dismiss(prop.dismissTimeInterval!) } cleanup(prop.dismissTimeInterval!) { completionHandler() } } private func cleanup(_ t: Double, completionHandler: (() -> Void)?) { let delay = t * Double(NSEC_PER_SEC) let time = DispatchTime.now() + Double(Int64(delay)) / Double(NSEC_PER_SEC) DispatchQueue.main.asyncAfter(deadline: time) { [weak self] in guard let win = self?.baseWindow else { return } UIView.animate( withDuration: 0.3, animations: { win.alpha = 0 }, completion: { finished in self?.progressViewController = nil win.isHidden = true win.rootViewController = nil self?.baseWindow = nil self?.property = nil self?.isAvailable = false guard let completionHandler = completionHandler else { return } completionHandler() } ) } } } // MARK: Use addSubView extension GradientCircularProgress { public func showAtRatio(frame: CGRect, display: Bool = true, style: StyleProperty = Style()) -> UIView? { if isAvailable { return nil } isAvailable = true property = Property(style: style) progressView = ProgressView(frame: frame) guard let v = progressView else { return nil } v.arc(display, style: style) return v } public func show(frame: CGRect, style: StyleProperty = Style()) -> UIView? { if isAvailable { return nil } isAvailable = true property = Property(style: style) return getProgress(frame: frame, message: nil, style: style) } public func show(frame: CGRect, message: String, style: StyleProperty = Style()) -> UIView? { if isAvailable { return nil } isAvailable = true property = Property(style: style) return getProgress(frame: frame, message: message, style: style) } private func getProgress(frame: CGRect, message: String?, style: StyleProperty) -> UIView? { progressView = ProgressView(frame: frame) guard let v = progressView else { return nil } v.circle(message, style: style) return v } public func dismiss(progress view: UIView) { if !isAvailable { return } guard let prop = property else { return } cleanup(prop.dismissTimeInterval!, view: view, completionHandler: nil) } public func dismiss(progress view: UIView, completionHandler: @escaping () -> Void) -> () { if !isAvailable { return } guard let prop = property else { return } cleanup(prop.dismissTimeInterval!, view: view) { completionHandler() } } private func cleanup(_ t: Double, view: UIView, completionHandler: (() -> Void)?) { let delay = t * Double(NSEC_PER_SEC) let time = DispatchTime.now() + Double(Int64(delay)) / Double(NSEC_PER_SEC) DispatchQueue.main.asyncAfter(deadline: time) { UIView.animate( withDuration: 0.3, animations: { view.alpha = 0 }, completion: { [weak self] finished in view.removeFromSuperview() self?.property = nil self?.isAvailable = false guard let completionHandler = completionHandler else { return } completionHandler() } ) } } } ================================================ FILE: source/Progress/Core/CircularProgressView.swift ================================================ // // CircularProgressView.swift // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit class CircularProgressView: UIView { var prop: Property? var messageLabel = UILabel() var centerPoint: CGPoint? var message: String? { willSet { messageLabel.frame = frame messageLabel.text = newValue guard let message = messageLabel.text else { return } // Attribute let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineHeightMultiple = 1.2 paragraphStyle.alignment = NSTextAlignment.center let attr = [NSAttributedString.Key.paragraphStyle: paragraphStyle] let attributedString = NSMutableAttributedString(string: message, attributes: attr) messageLabel.attributedText = attributedString messageLabel.sizeToFit() if centerPoint == nil { centerPoint = center } if let center = centerPoint { messageLabel.center = center } } } var gradientLayer = CALayer() private struct Animation { var rotationZ: CABasicAnimation { let animation: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z") animation.duration = 0.8 animation.repeatCount = HUGE animation.fromValue = NSNumber(value: 0.0) animation.toValue = NSNumber(value: 2 * Float.pi) return animation } init() {} func start(_ layer: CALayer) { layer.add(rotationZ, forKey: "rotate") } func stop(_ layer: CALayer) { layer.removeAllAnimations() } } override init(frame: CGRect) { super.init(frame: frame) backgroundColor = UIColor.clear layer.masksToBounds = true NotificationCenter.default.addObserver(self, selector: #selector(viewDidEnterBackground(_:)), name: UIApplication.didEnterBackgroundNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(viewWillEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } deinit { NotificationCenter.default.removeObserver(self) } override func didMoveToWindow() { super.didMoveToWindow() if window != nil { Animation().start(gradientLayer) } else { Animation().stop(gradientLayer) } } @objc private func viewDidEnterBackground(_ notification: Notification?) { Animation().stop(gradientLayer) } @objc private func viewWillEnterForeground(_ notification: Notification?) { Animation().start(gradientLayer) } internal func initialize(frame: CGRect) { guard let prop = prop else { return } let rect: CGRect = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height) // Base Circular if let baseLineWidth = prop.baseLineWidth, let baseArcColor = prop.baseArcColor { let circular: ArcView = ArcView(frame: rect, lineWidth: baseLineWidth) circular.color = baseArcColor circular.prop = prop addSubview(circular) } // Gradient Circular if ColorUtil.toRGBA(color: prop.startArcColor).a < 1.0 || ColorUtil.toRGBA(color: prop.endArcColor).a < 1.0 { // Clear Color let gradient: UIView = GradientArcWithClearColorView().draw(rect: rect, prop: prop) addSubview(gradient) gradientLayer = gradient.layer Animation().start(gradientLayer) } else { // Opaque Color let gradient: GradientArcView = GradientArcView(frame: rect) gradient.prop = prop addSubview(gradient) gradientLayer = gradient.layer Animation().start(gradientLayer) } } internal func showMessage(_ message: String) { guard let prop = prop else { return } // Message messageLabel.font = prop.messageLabelFont messageLabel.textAlignment = NSTextAlignment.center messageLabel.textColor = prop.messageLabelFontColor messageLabel.numberOfLines = 0 addSubview(messageLabel) self.message = message } } ================================================ FILE: source/Progress/Core/ProgressAtRatioView.swift ================================================ // // ProgressAtRatioView.swift // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit class ProgressAtRatioView: UIView { internal var arcView: ArcView? internal var prop: Property? internal var ratioLabel: UILabel = UILabel() internal var ratio: CGFloat = 0.0 { didSet { ratioLabel.text = String(format:"%.0f", ratio * 100) + "%" } } override init(frame: CGRect) { super.init(frame: frame) backgroundColor = UIColor.clear layer.masksToBounds = true } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } internal func initialize(frame: CGRect) { guard let prop = prop else { return } let rect: CGRect = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height) // Base Circular if let baseLineWidth = prop.baseLineWidth, let baseArcColor = prop.baseArcColor { let circular: ArcView = ArcView(frame: rect, lineWidth: baseLineWidth) circular.prop = prop circular.ratio = 1.0 circular.color = baseArcColor circular.lineWidth = baseLineWidth addSubview(circular) } // Gradient Circular if ColorUtil.toRGBA(color: prop.startArcColor).a < 1.0 || ColorUtil.toRGBA(color: prop.endArcColor).a < 1.0 { // Clear Color let gradient: UIView = GradientArcWithClearColorView().draw(rect: rect, prop: prop) addSubview(gradient) masking(rect: rect, prop: prop, gradient: gradient) } else { // Opaque Color let gradient: GradientArcView = GradientArcView(frame: rect) gradient.prop = prop addSubview(gradient) masking(rect: rect, prop: prop, gradient: gradient) } } private func masking(rect: CGRect, prop: Property, gradient: UIView) { // Mask arcView = ArcView(frame: rect, lineWidth: prop.arcLineWidth) guard let mask = arcView else { return } mask.prop = prop gradient.layer.mask = mask.layer } override func draw(_ rect: CGRect) { guard let mask = arcView else { return } if ratio > 1.0 { mask.ratio = 1.0 } else { mask.ratio = ratio } mask.setNeedsDisplay() } func showRatio() { guard let prop = prop else { return } // Progress Ratio ratioLabel.text = " " ratioLabel.font = prop.ratioLabelFont ratioLabel.textAlignment = NSTextAlignment.right ratioLabel.textColor = prop.ratioLabelFontColor ratioLabel.sizeToFit() ratioLabel.center = center addSubview(ratioLabel) } } ================================================ FILE: source/Progress/Elements/ArcView.swift ================================================ // // Arc.swift // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit class ArcView: UIView { var prop: Property? var ratio: CGFloat = 1.0 var color: UIColor = UIColor.black var lineWidth: CGFloat = 0.0 required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } init(frame: CGRect, lineWidth: CGFloat) { super.init(frame: frame) backgroundColor = UIColor.clear layer.masksToBounds = true self.lineWidth = lineWidth } override func draw(_ rect: CGRect) { drawArc(rect: rect) } private func drawArc(rect: CGRect) { guard let prop = prop else { return } let circularRect: CGRect = prop.progressRect let arcPoint: CGPoint = CGPoint(x: rect.width/2, y: rect.height/2) let arcRadius: CGFloat = circularRect.width/2 + prop.arcLineWidth/2 let arcStartAngle: CGFloat = -CGFloat.pi/2 let arcEndAngle: CGFloat = ratio * 2.0 * CGFloat.pi - CGFloat.pi/2 let arc: UIBezierPath = UIBezierPath(arcCenter: arcPoint, radius: arcRadius, startAngle: arcStartAngle, endAngle: arcEndAngle, clockwise: true) color.setStroke() arc.lineWidth = lineWidth arc.lineCapStyle = prop.arcLineCapStyle arc.stroke() } } ================================================ FILE: source/Progress/Elements/Background.swift ================================================ // // Background.swift // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // struct Background { internal func blurEffectView(fromBlurStyle style: BackgroundStyles, frame: CGRect) -> UIVisualEffectView? { var blurView: UIVisualEffectView? // return (blurEffectStyle: UIBlurEffectStyle?, isUserInteraction: Bool) let backgroundStyle = getStyle(style) if let blur = backgroundStyle.blurEffectStyle { // UIBlurEffectStyle (.extraLight, .light, .dark) let effect = UIBlurEffect(style: blur) blurView = UIVisualEffectView(effect: effect) } else { if !backgroundStyle.isUserInteraction { // .transparent blurView = UIVisualEffectView(effect: nil) } } blurView?.frame = frame return blurView } private func getStyle(_ style: BackgroundStyles) -> (blurEffectStyle: UIBlurEffect.Style?, isUserInteraction: Bool) { switch style { case .extraLight: return (.extraLight, false) case .light: return (.light, false) case .dark: return (.dark, false) case .transparent: return (nil, false) default: // .none return (nil, true) } } } ================================================ FILE: source/Progress/Elements/GradientArcView.swift ================================================ // // GradientArcView.swift // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit class GradientArcView: UIView { internal var prop: Property? override init(frame: CGRect) { super.init(frame: frame) backgroundColor = UIColor.clear layer.masksToBounds = true } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func getGradientPointColor(ratio: CGFloat, startColor: UIColor, endColor: UIColor) -> UIColor { let sColor = ColorUtil.toRGBA(color: startColor) let eColor = ColorUtil.toRGBA(color: endColor) let r = (eColor.r - sColor.r) * ratio + sColor.r let g = (eColor.g - sColor.g) * ratio + sColor.g let b = (eColor.b - sColor.b) * ratio + sColor.b let a = (eColor.a - sColor.a) * ratio + sColor.a return UIColor(red: r, green: g, blue: b, alpha: a) } override func draw(_ rect: CGRect) { guard let prop = prop else { return } let circularRect: CGRect = prop.progressRect var currentAngle: CGFloat = 0.0 for i in stride(from:CGFloat(0.0), through: CGFloat(1.0), by: CGFloat(0.005)) { let arcPoint: CGPoint = CGPoint(x: rect.width/2, y: rect.height/2) let arcRadius: CGFloat = circularRect.width/2 + prop.arcLineWidth/2 let arcStartAngle: CGFloat = -CGFloat.pi/2 let arcEndAngle: CGFloat = i * 2.0 * CGFloat.pi - CGFloat.pi/2 if currentAngle == 0.0 { currentAngle = arcStartAngle } else { currentAngle = arcEndAngle - 0.05 } let arc: UIBezierPath = UIBezierPath(arcCenter: arcPoint, radius: arcRadius, startAngle: currentAngle, endAngle: arcEndAngle, clockwise: true) let strokeColor: UIColor = getGradientPointColor(ratio: i, startColor: prop.startArcColor, endColor: prop.endArcColor) strokeColor.setStroke() arc.lineWidth = prop.arcLineWidth arc.lineCapStyle = prop.arcLineCapStyle arc.stroke() } } } ================================================ FILE: source/Progress/Elements/GradientArcWithClearColorView.swift ================================================ // // GradientArcWithClearColorView.swift // GradientCircularProgress // // Created by keygx on 2015/11/20. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit class GradientArcWithClearColorView: UIView { internal func draw(rect: CGRect, prop: Property) -> UIImageView { // Gradient Clear Circular /* Prop */ var startArcColorProp = prop var endArcColorProp = prop var startGradientMaskProp = prop var endGradientMaskProp = prop var solidMaskProp = prop // StartArc startArcColorProp.endArcColor = ColorUtil.toNotOpacityColor(color: startArcColorProp.startArcColor) // EndArc endArcColorProp.startArcColor = ColorUtil.toNotOpacityColor(color: endArcColorProp.endArcColor) // StartGradientMask startGradientMaskProp.startArcColor = UIColor.black startGradientMaskProp.endArcColor = UIColor.white startGradientMaskProp.progressSize += 10.0 startGradientMaskProp.arcLineWidth += 20.0 // EndGradientMask endGradientMaskProp.startArcColor = UIColor.white endGradientMaskProp.endArcColor = UIColor.black endGradientMaskProp.progressSize += 10.0 endGradientMaskProp.arcLineWidth += 20.0 // SolidMask solidMaskProp.startArcColor = UIColor.black solidMaskProp.endArcColor = UIColor.black /* Mask Image */ // StartArcColorImage let startArcColorView = ArcView(frame: rect, lineWidth: startArcColorProp.arcLineWidth) startArcColorView.color = startArcColorProp.startArcColor startArcColorView.prop = startArcColorProp let startArcColorImage = viewToUIImage(view: startArcColorView)! // StartGradientMaskImage let startGradientMaskView = GradientArcView(frame: rect) startGradientMaskView.prop = startGradientMaskProp let startGradientMaskImage = viewToUIImage(view: startGradientMaskView)! // EndArcColorImage let endArcColorView = ArcView(frame: rect, lineWidth: endArcColorProp.arcLineWidth) endArcColorView.color = endArcColorProp.startArcColor endArcColorView.prop = endArcColorProp let endArcColorImage = viewToUIImage(view: endArcColorView)! // EndGradientMaskImage let endGradientMaskView = GradientArcView(frame: rect) endGradientMaskView.prop = endGradientMaskProp let endGradientMaskImage = viewToUIImage(view: endGradientMaskView)! // SolidMaskImage let solidMaskView = ArcView(frame: rect, lineWidth: solidMaskProp.arcLineWidth) solidMaskView.prop = solidMaskProp let solidMaskImage = viewToUIImage(view: solidMaskView)! /* Masking */ var startArcImage = mask(image: startGradientMaskImage, maskImage: solidMaskImage) startArcImage = mask(image: startArcColorImage, maskImage: startArcImage) var endArcImage = mask(image: endGradientMaskImage, maskImage: solidMaskImage) endArcImage = mask(image: endArcColorImage, maskImage: endArcImage) /* Composite */ let image: UIImage = composite(image1: startArcImage, image2: endArcImage, prop: prop) /* UIImageView */ let imageView = UIImageView(image: image) imageView.contentMode = .scaleAspectFill imageView.clipsToBounds = true return imageView } internal func mask(image: UIImage, maskImage: UIImage) -> UIImage { let maskRef: CGImage = maskImage.cgImage! let mask: CGImage = CGImage( maskWidth: maskRef.width, height: maskRef.height, bitsPerComponent: maskRef.bitsPerComponent, bitsPerPixel: maskRef.bitsPerPixel, bytesPerRow: maskRef.bytesPerRow, provider: maskRef.dataProvider!, decode: nil, shouldInterpolate: false)! let maskedImageRef: CGImage = image.cgImage!.masking(mask)! let scale = UIScreen.main.scale let maskedImage: UIImage = UIImage(cgImage: maskedImageRef, scale: scale, orientation: .up) return maskedImage } internal func viewToUIImage(view: UIView) -> UIImage? { let scale = UIScreen.main.scale UIGraphicsBeginImageContextWithOptions(view.frame.size, false, scale) view.layer.render(in: UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image } internal func composite(image1: UIImage, image2: UIImage, prop: Property) -> UIImage { let scale = UIScreen.main.scale UIGraphicsBeginImageContextWithOptions(image1.size, false, scale) image1.draw( in: CGRect(x: 0, y: 0, width: image1.size.width, height: image1.size.height), blendMode: .overlay, alpha: ColorUtil.toRGBA(color: prop.startArcColor).a) image2.draw( in: CGRect(x: 0, y: 0, width: image2.size.width, height: image2.size.height), blendMode: .overlay, alpha: ColorUtil.toRGBA(color: prop.endArcColor).a) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return image! } } ================================================ FILE: source/Progress/Elements/WindowBuilder.swift ================================================ // // WindowBuilder.swift // GradientCircularProgress // // Created by keygx on 2019/09/24. // Copyright © 2019 keygx. All rights reserved. // import UIKit class WindowBuilder { static func build() -> UIWindow? { var baseWindow: UIWindow? if #available(iOS 13.0, *) { let windowScene = UIApplication.shared.connectedScenes .filter { $0.activationState == .foregroundActive }.first if let windowScene = windowScene as? UIWindowScene { baseWindow = UIWindow(windowScene: windowScene) } else { baseWindow = UIWindow() } } else { baseWindow = UIWindow() } baseWindow?.bounds = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height) baseWindow?.backgroundColor = UIColor.clear baseWindow?.windowLevel = UIWindow.Level.alert + 1 baseWindow?.makeKeyAndVisible() return baseWindow } } ================================================ FILE: source/Progress/ProgressView.swift ================================================ // // ProgressView.swift // GradientCircularProgress // // Created by keygx on 2016/03/07. // Copyright (c) 2016年 keygx. All rights reserved. // import UIKit class ProgressView: UIView { private var viewRect: CGRect? private var blurView: UIVisualEffectView? private var progressAtRatioView: ProgressAtRatioView? private var circularProgressView: CircularProgressView? internal var prop: Property? internal var ratio: CGFloat = 0.0 { didSet { progressAtRatioView?.ratio = ratio progressAtRatioView?.setNeedsDisplay() } } override init(frame: CGRect) { super.init(frame: frame) initialize(frame: frame) } required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder)! } private func initialize(frame: CGRect) { viewRect = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height) clipsToBounds = true } internal func arc(_ display: Bool, style: StyleProperty) { prop = Property(style: style) guard let prop = prop else { return } isUserInteractionEnabled = !(prop.backgroundStyle.rawValue == 0) ? true : false getBlurView() progressAtRatioView = ProgressAtRatioView(frame: CGRect(x: 0, y: 0, width: prop.progressSize, height: prop.progressSize)) guard let progressAtRatioView = progressAtRatioView else { return } progressAtRatioView.prop = prop progressAtRatioView.initialize(frame: progressAtRatioView.frame) if display { progressAtRatioView.showRatio() } progressAtRatioView.frame = CGRect( x: (frame.size.width - progressAtRatioView.frame.size.width) / 2, y: (frame.size.height - progressAtRatioView.frame.size.height) / 2, width: progressAtRatioView.frame.size.width, height: progressAtRatioView.frame.size.height) addSubview(progressAtRatioView) } internal func circle(_ message: String?, style: StyleProperty) { prop = Property(style: style) guard let prop = prop else { return } isUserInteractionEnabled = !(prop.backgroundStyle.rawValue == 0) ? true : false getBlurView() circularProgressView = CircularProgressView(frame: CGRect(x: 0, y: 0, width: prop.progressSize, height: prop.progressSize)) guard let circularProgressView = circularProgressView else { return } circularProgressView.prop = prop circularProgressView.initialize(frame: circularProgressView.frame) if let message = message { circularProgressView.showMessage(message) } circularProgressView.frame = CGRect( x: (frame.size.width - circularProgressView.frame.size.width) / 2, y: (frame.size.height - circularProgressView.frame.size.height) / 2, width: circularProgressView.frame.size.width, height: circularProgressView.frame.size.height) addSubview(circularProgressView) } internal func updateMessage(_ message: String) { guard let circularProgressView = circularProgressView else { return } circularProgressView.message = message } private func getBlurView() { guard let rect = viewRect, let prop = prop else { return } blurView = Background().blurEffectView(fromBlurStyle: prop.backgroundStyle, frame: rect) guard let blurView = blurView else { return } backgroundColor = UIColor.clear addSubview(blurView) } } ================================================ FILE: source/Progress/ProgressViewController.swift ================================================ // // ProgressViewController.swift // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit class ProgressViewController: UIViewController { private var viewRect: CGRect? private var blurView: UIVisualEffectView? private var progressAtRatioView: ProgressAtRatioView? private var circularProgressView: CircularProgressView? internal var prop: Property? internal var ratio: CGFloat = 0.0 { didSet { progressAtRatioView?.ratio = ratio progressAtRatioView?.setNeedsDisplay() } } override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = UIColor.clear } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } override var shouldAutorotate: Bool { return false } override var prefersStatusBarHidden: Bool { let orientation: UIInterfaceOrientation if #available(iOS 13.0, *) { orientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation ?? .portrait } else { orientation = UIApplication.shared.statusBarOrientation } switch orientation { case .landscapeLeft, .landscapeRight: // LandscapeLeft | LandscapeRight return true default: // Unknown | Portrait | PortraitUpsideDown return false } } private func getViewRect() { let window = UIWindow(frame: UIScreen.main.bounds) viewRect = window.frame } private func getBlurView() { guard let rect = viewRect, let prop = prop else { return } blurView = Background().blurEffectView(fromBlurStyle: prop.backgroundStyle, frame: rect) guard let blurView = blurView else { return } view.backgroundColor = UIColor.clear view.addSubview(blurView) } internal func arc(display: Bool, style: StyleProperty, baseWindow: UIWindow?) { prop = Property(style: style) guard let win = baseWindow, let prop = prop else { return } win.isUserInteractionEnabled = !(prop.backgroundStyle.rawValue == 0) ? true : false // 0 == .None getViewRect() getBlurView() progressAtRatioView = ProgressAtRatioView(frame: CGRect(x: 0, y: 0, width: prop.progressSize, height: prop.progressSize)) guard let progressAtRatioView = progressAtRatioView else { return } progressAtRatioView.prop = prop progressAtRatioView.initialize(frame: progressAtRatioView.frame) if display { progressAtRatioView.showRatio() } progressAtRatioView.center = view.center view.addSubview(progressAtRatioView) } internal func circle(message: String?, style: StyleProperty, baseWindow: UIWindow?) { prop = Property(style: style) guard let win = baseWindow, let prop = prop else { return } win.isUserInteractionEnabled = !(prop.backgroundStyle.rawValue == 0) ? true : false // 0 == .None getViewRect() getBlurView() circularProgressView = CircularProgressView(frame: CGRect(x: 0, y: 0, width: prop.progressSize, height: prop.progressSize)) guard let circularProgressView = circularProgressView else { return } circularProgressView.prop = prop circularProgressView.initialize(frame: circularProgressView.frame) if message != nil { circularProgressView.showMessage(message!) } circularProgressView.center = view.center view.addSubview(circularProgressView) } internal func updateMessage(message: String) { guard let circularProgressView = circularProgressView else { return } circularProgressView.message = message } internal func dismiss(_ t: Double) { let delay = t * Double(NSEC_PER_SEC) let time = DispatchTime.now() + Double(Int64(delay)) / Double(NSEC_PER_SEC) DispatchQueue.main.asyncAfter(deadline: time) { guard let blurView = self.blurView, let progressAtRatioView = self.progressAtRatioView, let circularProgressView = self.circularProgressView else { return } UIView.animate( withDuration: 0.3, animations: { progressAtRatioView.alpha = 0.0 circularProgressView.alpha = 0.0 }, completion: { finished in progressAtRatioView.removeFromSuperview() circularProgressView.removeFromSuperview() blurView.removeFromSuperview() } ) } } } ================================================ FILE: source/Progress/Property.swift ================================================ // // Property.swift // GradientCircularProgress // // Created by keygx on 2015/06/24. // Copyright (c) 2015年 keygx. All rights reserved. // public protocol StyleProperty { // Progress Size var progressSize: CGFloat { get set } // Gradient Circular var arcLineWidth: CGFloat { get set } var startArcColor: UIColor { get set } var endArcColor: UIColor { get set } // Base Circular var baseLineWidth: CGFloat? { get set } var baseArcColor: UIColor? { get set } // Ratio var ratioLabelFont: UIFont? { get set } var ratioLabelFontColor: UIColor? { get set } // Message var messageLabelFont: UIFont? { get set } var messageLabelFontColor: UIColor? { get set } // Background var backgroundStyle: BackgroundStyles { get set } // Dismiss var dismissTimeInterval: Double? { get set } // Initialize init() } public enum BackgroundStyles: Int { case none = 0 case extraLight case light case dark case transparent } internal struct Property { let margin: CGFloat = 5.0 let arcLineCapStyle: CGLineCap = CGLineCap.butt // Progress Size var progressSize: CGFloat // Gradient Circular var arcLineWidth: CGFloat var startArcColor: UIColor var endArcColor: UIColor // Base Circular var baseLineWidth: CGFloat? var baseArcColor: UIColor? // Ratio let ratioLabelFont: UIFont? let ratioLabelFontColor: UIColor? // Message let messageLabelFont: UIFont? let messageLabelFontColor: UIColor? // Background let backgroundStyle: BackgroundStyles // Dismiss let dismissTimeInterval: Double? // Progress Rect var progressRect: CGRect { let lineWidth: CGFloat = (arcLineWidth > baseLineWidth!) ? arcLineWidth : baseLineWidth! return CGRect(x: 0, y: 0, width: progressSize - lineWidth * 2, height: progressSize - lineWidth * 2) } init(style: StyleProperty) { let styles: StyleProperty = style progressSize = styles.progressSize arcLineWidth = styles.arcLineWidth startArcColor = styles.startArcColor endArcColor = styles.endArcColor baseLineWidth = styles.baseLineWidth ?? 0.0 baseArcColor = styles.baseArcColor ?? UIColor.clear ratioLabelFont = styles.ratioLabelFont ?? UIFont.systemFont(ofSize: 16.0) ratioLabelFontColor = styles.ratioLabelFontColor ?? UIColor.clear messageLabelFont = styles.messageLabelFont ?? UIFont.systemFont(ofSize: 16.0) messageLabelFontColor = styles.messageLabelFontColor ?? UIColor.clear backgroundStyle = styles.backgroundStyle dismissTimeInterval = styles.dismissTimeInterval ?? 0.8 } } ================================================ FILE: source/Styles/BlueDarkStyle.swift ================================================ // // BlueDarkStyle.swift // GradientCircularProgress // // Created by keygx on 2015/08/31. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit public struct BlueDarkStyle: StyleProperty { // Progress Size public var progressSize: CGFloat = 260 // Gradient Circular public var arcLineWidth: CGFloat = 4.0 public var startArcColor: UIColor = ColorUtil.toUIColor(r: 0.0, g: 122.0, b: 255.0, a: 1.0) public var endArcColor: UIColor = UIColor.cyan // Base Circular public var baseLineWidth: CGFloat? = 5.0 public var baseArcColor: UIColor? = UIColor(red:0.0, green: 0.0, blue: 0.0, alpha: 0.2) // Ratio public var ratioLabelFont: UIFont? = UIFont(name: "Verdana-Bold", size: 16.0) public var ratioLabelFontColor: UIColor? = UIColor.white // Message public var messageLabelFont: UIFont? = UIFont.systemFont(ofSize: 16.0) public var messageLabelFontColor: UIColor? = UIColor.white // Background public var backgroundStyle: BackgroundStyles = .dark // Dismiss public var dismissTimeInterval: Double? = nil // 'nil' for default setting. public init() {} } ================================================ FILE: source/Styles/BlueIndicatorStyle.swift ================================================ // // BlueIndicatorStyle.swift // GradientCircularProgress // // Created by keygx on 2015/08/31. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit public struct BlueIndicatorStyle: StyleProperty { // Progress Size public var progressSize: CGFloat = 44 // Gradient Circular public var arcLineWidth: CGFloat = 4.0 public var startArcColor: UIColor = ColorUtil.toUIColor(r: 235.0, g: 245.0, b: 255.0, a: 1.0) public var endArcColor: UIColor = ColorUtil.toUIColor(r: 0.0, g: 122.0, b: 255.0, a: 1.0) // Base Circular public var baseLineWidth: CGFloat? = 4.0 public var baseArcColor: UIColor? = ColorUtil.toUIColor(r: 215.0, g: 215.0, b: 215.0, a: 0.4) // Ratio public var ratioLabelFont: UIFont? = nil public var ratioLabelFontColor: UIColor? = nil // Message public var messageLabelFont: UIFont? = nil public var messageLabelFontColor: UIColor? = nil // Background public var backgroundStyle: BackgroundStyles = .none // Dismiss public var dismissTimeInterval: Double? = nil // 'nil' for default setting. public init() {} } ================================================ FILE: source/Styles/GreenLightStyle.swift ================================================ // // GreenLightStyle.swift // GradientCircularProgress // // Created by keygx on 2015/11/24. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit public struct GreenLightStyle: StyleProperty { // Progress Size public var progressSize: CGFloat = 200 // Gradient Circular public var arcLineWidth: CGFloat = 32.0 public var startArcColor: UIColor = ColorUtil.toUIColor(r: 40.0, g: 110.0, b: 60.0, a: 1.0) public var endArcColor: UIColor = UIColor.green // Base Circular public var baseLineWidth: CGFloat? = 1.0 public var baseArcColor: UIColor? = UIColor(red:0.0, green: 0.0, blue: 0.0, alpha: 0.1) // Ratio public var ratioLabelFont: UIFont? = UIFont(name: "Verdana-Bold", size: 18.0) public var ratioLabelFontColor: UIColor? = UIColor.darkGray // Message public var messageLabelFont: UIFont? = UIFont(name: "Verdana", size: 18.0) public var messageLabelFontColor: UIColor? = UIColor.darkGray // Background public var backgroundStyle: BackgroundStyles = .light // Dismiss public var dismissTimeInterval: Double? = nil // 'nil' for default setting. public init() {} } ================================================ FILE: source/Styles/OrangeClearStyle.swift ================================================ // // OrangeClearStyle.swift // GradientCircularProgress // // Created by keygx on 2015/11/24. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit public struct OrangeClearStyle: StyleProperty { // Progress Size public var progressSize: CGFloat = 80 // Gradient Circular public var arcLineWidth: CGFloat = 6.0 public var startArcColor: UIColor = UIColor.clear public var endArcColor: UIColor = UIColor.orange // Base Circular public var baseLineWidth: CGFloat? = nil public var baseArcColor: UIColor? = nil // Ratio public var ratioLabelFont: UIFont? = UIFont.systemFont(ofSize: 13.0) public var ratioLabelFontColor: UIColor? = UIColor.black // Message public var messageLabelFont: UIFont? = nil public var messageLabelFontColor: UIColor? = nil // Background public var backgroundStyle: BackgroundStyles = .none // Dismiss public var dismissTimeInterval: Double? = nil // 'nil' for default setting. public init() {} } ================================================ FILE: source/Styles/Style.swift ================================================ // // DefaultStyle.swift // GradientCircularProgress // // Created by keygx on 2015/08/31. // Copyright (c) 2015年 keygx. All rights reserved. // import UIKit public struct Style: StyleProperty { // Progress Size public var progressSize: CGFloat = 220 // Gradient Circular public var arcLineWidth: CGFloat = 16.0 public var startArcColor: UIColor = ColorUtil.toUIColor(r: 230.0, g: 230.0, b: 230.0, a: 0.6) public var endArcColor: UIColor = ColorUtil.toUIColor(r: 90.0, g: 90.0, b: 90.0, a: 1.0) // Base Circular public var baseLineWidth: CGFloat? = 16.0 public var baseArcColor: UIColor? = UIColor(red:1.0, green: 1.0, blue: 1.0, alpha: 0.8) // Ratio public var ratioLabelFont: UIFont? = UIFont.systemFont(ofSize: 18.0) public var ratioLabelFontColor: UIColor? = UIColor.black // Message public var messageLabelFont: UIFont? = UIFont.systemFont(ofSize: 18.0) public var messageLabelFontColor: UIColor? = UIColor.black // Background public var backgroundStyle: BackgroundStyles = .extraLight // Dismiss public var dismissTimeInterval: Double? = nil // 'nil' for default setting. public init() {} } ================================================ FILE: source/Utils/ColorUtil.swift ================================================ // // ColorUtil.swift // GradientCircularProgress // // Created by keygx on 2015/11/23. // Copyright © 2015年 keygx. All rights reserved. // import UIKit public class ColorUtil { public class func toUIColor(r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat) -> UIColor { return UIColor(red: r/255.0, green: g/255.0, blue: b/255.0, alpha: a) } internal class func toRGBA(color: UIColor) -> (r: CGFloat, g: CGFloat, b: CGFloat, a: CGFloat) { var r: CGFloat = 0.0 var g: CGFloat = 0.0 var b: CGFloat = 0.0 var a: CGFloat = 0.0 color.getRed(&r, green: &g, blue: &b, alpha: &a) return (r, g, b, a) } internal class func toNotOpacityColor(color: UIColor) -> UIColor { if color == UIColor.clear { return UIColor.white } else { return UIColor( red: ColorUtil.toRGBA(color: color).r, green: ColorUtil.toRGBA(color: color).g, blue: ColorUtil.toRGBA(color: color).b, alpha: 1.0) } } }