├── Images ├── AppIcon.png ├── Banner.png ├── Hierarchy.png ├── SVUploader.png ├── demo1.gif └── demo2.gif ├── LICENSE ├── README.md ├── SVUploader Design.sketch └── SVUploader ├── Assets ├── Check.png ├── Check@2x.png ├── Check@3x.png ├── X.png ├── X@2x.png └── X@3x.png ├── SVUploader.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── Kiran.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── Kiran.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── SVUploader.xcscheme │ └── xcschememanagement.plist └── SVUploader ├── AppDelegate.swift ├── Assets.xcassets ├── AppIcon.appiconset │ ├── Contents.json │ ├── iPad-Pro-appIcon@2x.png │ ├── iPad-appIcon.png │ ├── iPad-appIcon@2x.png │ ├── iPad-settings.png │ ├── iPad-settings@2x.png │ ├── iPad-spotlight.png │ ├── iPad-spotlight@2x.png │ ├── iPhone-appIcon@2x.png │ ├── iPhone-appIcon@3x.png │ ├── iPhone-small@2x.png │ ├── iPhone-small@3x.png │ ├── iPhone-spotlight@2x.png │ ├── iPhone-spotlight@3x.png │ ├── watch-appLauncher-38mm@2x.png │ ├── watch-companionSettings@2x.png │ ├── watch-companionSettings@3x.png │ ├── watch-longLook-42mm@2x.png │ ├── watch-notificationCenter-38mm@2x.png │ ├── watch-notificationCenter-42mm@2x.png │ ├── watch-quickLook-38mm@2x.png │ └── watch-quickLook-42mm@2x.png ├── Check.imageset │ ├── Check.png │ ├── Check@2x.png │ ├── Check@3x.png │ └── Contents.json ├── Contents.json ├── X.imageset │ ├── Contents.json │ ├── X.png │ ├── X@2x.png │ └── X@3x.png ├── anubis.imageset │ ├── Contents.json │ └── anubis.jpg ├── example.imageset │ ├── Contents.json │ └── baymax.jpg ├── galaxy.imageset │ ├── Contents.json │ └── galaxy.jpg └── trooper.imageset │ ├── Contents.json │ └── trooper.jpg ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── CodeViewController.swift ├── Info.plist ├── SVUploader-Bridging-Header.h ├── SVUploader.swift └── StoryboardViewController.swift /Images/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/Images/AppIcon.png -------------------------------------------------------------------------------- /Images/Banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/Images/Banner.png -------------------------------------------------------------------------------- /Images/Hierarchy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/Images/Hierarchy.png -------------------------------------------------------------------------------- /Images/SVUploader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/Images/SVUploader.png -------------------------------------------------------------------------------- /Images/demo1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/Images/demo1.gif -------------------------------------------------------------------------------- /Images/demo2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/Images/demo2.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Kiran 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Upload](Images/Banner.png) 2 | 3 | # SVUploader ![Platform](https://img.shields.io/badge/platform-iOS-677cf4.svg) 4 | ![License MIT](https://img.shields.io/badge/license-MIT-blue.svg) 5 | ![Build Passing](https://img.shields.io/badge/build-passing-brightgreen.svg) 6 | 7 | A view class for iOS that makes uploading easy and beautiful. 8 | 9 | ## Demo 10 | 11 | SVUploader is fully customizable - check out 2 demos. 12 | 13 | ![Demo 1](Images/demo1.gif) 14 | ![Demo 2](Images/demo2.gif) 15 | 16 | ## Installation 17 | 18 | Just drag the SVUploader.swift file to your project, and you'll be all set to go. 19 | 20 | ## Guide 21 | 22 | SVUploader takes care of the visual part of the upload part of process for you; all you have to do is instantiate an SVUploader, place it on the screen, and give it the progress of your upload. It's that simple! Let's go ahead and start with an example. 23 | 24 | 25 | ### Use it! (Quick and Simple) 26 | 27 | Now, if you just want to use it straight out of the box, it's extremely simple. 28 | 29 | ```swift 30 | // Create the uploader view 31 | let uploaderView = SVUploader(frame: uploaderFrame) 32 | 33 | // Set the image you want to upload 34 | uploaderView.image = imageThatIWantToUpload 35 | 36 | // Start the upload 37 | uploaderView.startUpload() 38 | 39 | // Update the progress in your update code 40 | uploaderView.progress = newProgress 41 | 42 | // End the upload, and specify whether it succeeded or failed 43 | self.uploaderView.endUpload(success: true) 44 | ``` 45 | SVUploader will automatically present the appropriate view depending on whether or not there was an error. 46 | 47 | The following are about the more detailed parts of SVUploader that you can customize to create a unique experience. 48 | 49 | 50 | ### Properties 51 | 52 | SVUploader has several properties that you can change. The default values are specified, and they're set to one variation of what I think looks nice. Some of these variables can only be set using the initializers and cannot be changed later, so check out that section next. 53 | 54 | `isUploading (read-only)` - Whether or not the UI is currently uploading. This is internally managed and should only be read by the user. 55 | 56 | `progressAnimationSpeed (2)` - The speed of the circular animation between progress value changes. This number should be changed depending on the length of intervals between each progress percentage update (the time it takes to receive an update on how much of the upload has been finished). For larger intervals, a lower speed is recommended for a smoother animation. For shorter intervals, a higher speed is recommended to prevent slow animation and lag. This default value of 2 should work fine for most default intervals. 57 | 58 | `useSmoothAnimation (true) (initializer-only)` - iOS automatically animates the path changes to make things look smooth. You can disable this effect, although it would probably just make it looks worse (but hey, I don't judge). 59 | 60 | `useBlur (false) (initializer-only)` - Whether the overlay uses a blur effect or a dark overlay effect. Can only be set using the initializer. 61 | 62 | `useShadow (false) (initializer-only)` - Whether the uploader uses the shadow effect. Can only be set using the initializer. 63 | 64 | `lineColor (dark purple)` - The color of the circular loader. 65 | 66 | `lineWidth (12)` - The line width of the circular loader. 67 | 68 | `borderColor (dark gray)` - The border color. 69 | 70 | `borderWidth (0)` - The border width. 71 | 72 | `overlayOpacity (0.6)` - The opacity of the dark overlay effect (only applicable if `useBlur` is false). 73 | 74 | `mainFont (Avenir-Medium Size 30)` - The font of the percentage text in the uploader. 75 | 76 | `messageDuration (2 seconds)` - The duration of the message to be displayed at the end of the upload. 77 | 78 | `successImage (Green check)` - The image to present when an upload is successful. 79 | 80 | `errorImage (Red X)` - The image to present when an upload has failed. 81 | 82 | `progress` - The progress percentage of the upload. Update this variable with a decimal to update the uploader. 83 | 84 | 85 | 86 | 87 | ### Initializers 88 | 89 | There are several different initializers for different needs. Not all properties can be set using an initializer, so be sure to check them above and change any if needed after initializing a view. Use the last one if you want to change variables that can only be set with the initializer. 90 | 91 | `init(frame: CGRect)` - The standard initalizer. It sets everything up but you can still change some properties later. 92 | 93 | `init(lineColor: UIColor, lineWidth: CGFloat)` - The most commonly used one. You can customize the most important part of the loader - the circular loader. 94 | 95 | `init(lineColor: UIColor, lineWidth: CGFloat, borderColor: UIColor, borderWidth: CGFloat` - A little fancier. You can now add in a border as well. 96 | 97 | `init(useBlur: Bool, useShadow: Bool, useSmoothAnimation: Bool)` - The initializer only variables can be set here. To keep it short, I've only included those, but you can still change the rest of the properties later. 98 | 99 | ### Use it! (Advanced Customization) 100 | 101 | Now, let's take a look at how to customize this experience. SVUploader is extremely modular; take a look at its view structure. The following views can be swapped out with your own for a custom look - just set the property equal to your own custom view. 102 | 103 | Here's a hierarchy view of SVUploader. 104 | 105 | ![Upload](Images/Hierarchy.png) 106 | 107 | `contentView` - The "content" or image of the uploader view. If you want more than just a thumbnail picture to show up, you can customize it by replacing it with your own view. 108 | 109 | `overlayView` - The view that overlays the `contentView`. By default, it is a dark overlay or blur. 110 | 111 | `loadingLabel` - The text that describes the progress of the upload. By default, it displays the percentage, but you can edit its text or create your own new label. 112 | 113 | `endView` - The view that shows up after the upload has finished. By default, it shows an error/success image. 114 | 115 | If you don't want to create a brand new view from scratch, and just want to modify some of the details such as the blur effect or image size, you can take a look at all of the views the class uses by reading the source code. 116 | 117 | ## Coming Soon 118 | 119 | SVUploader still has a lot more potential with more customizability and cooler features, such as: 120 | 121 | - Specify a text message (not just image) after the upload 122 | - Pick from several different animation options 123 | - Anything else you can think of. Feel free to open an issue for a feature request, or contribute to the project! 124 | 125 | 126 | ## Contribute 127 | Feel free to to contribute to the project with any features you think would be cool or bug fixes. You can also help by simply opening up an issue if you find a bug or would like a new feature to be added. I'll try my best to continue and update the project. -------------------------------------------------------------------------------- /SVUploader Design.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader Design.sketch -------------------------------------------------------------------------------- /SVUploader/Assets/Check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/Assets/Check.png -------------------------------------------------------------------------------- /SVUploader/Assets/Check@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/Assets/Check@2x.png -------------------------------------------------------------------------------- /SVUploader/Assets/Check@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/Assets/Check@3x.png -------------------------------------------------------------------------------- /SVUploader/Assets/X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/Assets/X.png -------------------------------------------------------------------------------- /SVUploader/Assets/X@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/Assets/X@2x.png -------------------------------------------------------------------------------- /SVUploader/Assets/X@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/Assets/X@3x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9F2921BF1DEA4A070043EE66 /* StoryboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2921BE1DEA4A070043EE66 /* StoryboardViewController.swift */; }; 11 | 9F2CF3771DB4606E00CA06FC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2CF3761DB4606E00CA06FC /* AppDelegate.swift */; }; 12 | 9F2CF3791DB4606E00CA06FC /* CodeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F2CF3781DB4606E00CA06FC /* CodeViewController.swift */; }; 13 | 9F2CF37C1DB4606E00CA06FC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9F2CF37A1DB4606E00CA06FC /* Main.storyboard */; }; 14 | 9F2CF37E1DB4606E00CA06FC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9F2CF37D1DB4606E00CA06FC /* Assets.xcassets */; }; 15 | 9F2CF3811DB4606E00CA06FC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9F2CF37F1DB4606E00CA06FC /* LaunchScreen.storyboard */; }; 16 | 9F65C8FE1DB460AE00EA89E9 /* SVUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F65C8FD1DB460AE00EA89E9 /* SVUploader.swift */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | 9F2921BE1DEA4A070043EE66 /* StoryboardViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StoryboardViewController.swift; sourceTree = ""; }; 21 | 9F2CF3731DB4606E00CA06FC /* SVUploader.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SVUploader.app; sourceTree = BUILT_PRODUCTS_DIR; }; 22 | 9F2CF3761DB4606E00CA06FC /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 23 | 9F2CF3781DB4606E00CA06FC /* CodeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CodeViewController.swift; sourceTree = ""; }; 24 | 9F2CF37B1DB4606E00CA06FC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 25 | 9F2CF37D1DB4606E00CA06FC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 26 | 9F2CF3801DB4606E00CA06FC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 27 | 9F2CF3821DB4606E00CA06FC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 28 | 9F65C8FD1DB460AE00EA89E9 /* SVUploader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SVUploader.swift; sourceTree = ""; }; 29 | 9FE588711DB4A5EC00783E15 /* SVUploader-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SVUploader-Bridging-Header.h"; sourceTree = ""; }; 30 | /* End PBXFileReference section */ 31 | 32 | /* Begin PBXFrameworksBuildPhase section */ 33 | 9F2CF3701DB4606E00CA06FC /* Frameworks */ = { 34 | isa = PBXFrameworksBuildPhase; 35 | buildActionMask = 2147483647; 36 | files = ( 37 | ); 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXFrameworksBuildPhase section */ 41 | 42 | /* Begin PBXGroup section */ 43 | 9F2CF36A1DB4606E00CA06FC = { 44 | isa = PBXGroup; 45 | children = ( 46 | 9F2CF3751DB4606E00CA06FC /* SVUploader */, 47 | 9F2CF3741DB4606E00CA06FC /* Products */, 48 | ); 49 | sourceTree = ""; 50 | }; 51 | 9F2CF3741DB4606E00CA06FC /* Products */ = { 52 | isa = PBXGroup; 53 | children = ( 54 | 9F2CF3731DB4606E00CA06FC /* SVUploader.app */, 55 | ); 56 | name = Products; 57 | sourceTree = ""; 58 | }; 59 | 9F2CF3751DB4606E00CA06FC /* SVUploader */ = { 60 | isa = PBXGroup; 61 | children = ( 62 | 9F2CF3761DB4606E00CA06FC /* AppDelegate.swift */, 63 | 9F2CF3781DB4606E00CA06FC /* CodeViewController.swift */, 64 | 9F2921BE1DEA4A070043EE66 /* StoryboardViewController.swift */, 65 | 9F65C8FD1DB460AE00EA89E9 /* SVUploader.swift */, 66 | 9F2CF37A1DB4606E00CA06FC /* Main.storyboard */, 67 | 9F2CF37D1DB4606E00CA06FC /* Assets.xcassets */, 68 | 9F2CF37F1DB4606E00CA06FC /* LaunchScreen.storyboard */, 69 | 9F2CF3821DB4606E00CA06FC /* Info.plist */, 70 | 9FE588711DB4A5EC00783E15 /* SVUploader-Bridging-Header.h */, 71 | ); 72 | path = SVUploader; 73 | sourceTree = ""; 74 | }; 75 | /* End PBXGroup section */ 76 | 77 | /* Begin PBXNativeTarget section */ 78 | 9F2CF3721DB4606E00CA06FC /* SVUploader */ = { 79 | isa = PBXNativeTarget; 80 | buildConfigurationList = 9F2CF3851DB4606E00CA06FC /* Build configuration list for PBXNativeTarget "SVUploader" */; 81 | buildPhases = ( 82 | 9F2CF36F1DB4606E00CA06FC /* Sources */, 83 | 9F2CF3701DB4606E00CA06FC /* Frameworks */, 84 | 9F2CF3711DB4606E00CA06FC /* Resources */, 85 | ); 86 | buildRules = ( 87 | ); 88 | dependencies = ( 89 | ); 90 | name = SVUploader; 91 | productName = SVUploader; 92 | productReference = 9F2CF3731DB4606E00CA06FC /* SVUploader.app */; 93 | productType = "com.apple.product-type.application"; 94 | }; 95 | /* End PBXNativeTarget section */ 96 | 97 | /* Begin PBXProject section */ 98 | 9F2CF36B1DB4606E00CA06FC /* Project object */ = { 99 | isa = PBXProject; 100 | attributes = { 101 | LastSwiftUpdateCheck = 0800; 102 | LastUpgradeCheck = 0900; 103 | ORGANIZATIONNAME = Kiran; 104 | TargetAttributes = { 105 | 9F2CF3721DB4606E00CA06FC = { 106 | CreatedOnToolsVersion = 8.0; 107 | DevelopmentTeam = Y9Y96CV7VP; 108 | LastSwiftMigration = 0900; 109 | ProvisioningStyle = Automatic; 110 | }; 111 | }; 112 | }; 113 | buildConfigurationList = 9F2CF36E1DB4606E00CA06FC /* Build configuration list for PBXProject "SVUploader" */; 114 | compatibilityVersion = "Xcode 3.2"; 115 | developmentRegion = English; 116 | hasScannedForEncodings = 0; 117 | knownRegions = ( 118 | en, 119 | Base, 120 | ); 121 | mainGroup = 9F2CF36A1DB4606E00CA06FC; 122 | productRefGroup = 9F2CF3741DB4606E00CA06FC /* Products */; 123 | projectDirPath = ""; 124 | projectRoot = ""; 125 | targets = ( 126 | 9F2CF3721DB4606E00CA06FC /* SVUploader */, 127 | ); 128 | }; 129 | /* End PBXProject section */ 130 | 131 | /* Begin PBXResourcesBuildPhase section */ 132 | 9F2CF3711DB4606E00CA06FC /* Resources */ = { 133 | isa = PBXResourcesBuildPhase; 134 | buildActionMask = 2147483647; 135 | files = ( 136 | 9F2CF3811DB4606E00CA06FC /* LaunchScreen.storyboard in Resources */, 137 | 9F2CF37E1DB4606E00CA06FC /* Assets.xcassets in Resources */, 138 | 9F2CF37C1DB4606E00CA06FC /* Main.storyboard in Resources */, 139 | ); 140 | runOnlyForDeploymentPostprocessing = 0; 141 | }; 142 | /* End PBXResourcesBuildPhase section */ 143 | 144 | /* Begin PBXSourcesBuildPhase section */ 145 | 9F2CF36F1DB4606E00CA06FC /* Sources */ = { 146 | isa = PBXSourcesBuildPhase; 147 | buildActionMask = 2147483647; 148 | files = ( 149 | 9F65C8FE1DB460AE00EA89E9 /* SVUploader.swift in Sources */, 150 | 9F2921BF1DEA4A070043EE66 /* StoryboardViewController.swift in Sources */, 151 | 9F2CF3791DB4606E00CA06FC /* CodeViewController.swift in Sources */, 152 | 9F2CF3771DB4606E00CA06FC /* AppDelegate.swift in Sources */, 153 | ); 154 | runOnlyForDeploymentPostprocessing = 0; 155 | }; 156 | /* End PBXSourcesBuildPhase section */ 157 | 158 | /* Begin PBXVariantGroup section */ 159 | 9F2CF37A1DB4606E00CA06FC /* Main.storyboard */ = { 160 | isa = PBXVariantGroup; 161 | children = ( 162 | 9F2CF37B1DB4606E00CA06FC /* Base */, 163 | ); 164 | name = Main.storyboard; 165 | sourceTree = ""; 166 | }; 167 | 9F2CF37F1DB4606E00CA06FC /* LaunchScreen.storyboard */ = { 168 | isa = PBXVariantGroup; 169 | children = ( 170 | 9F2CF3801DB4606E00CA06FC /* Base */, 171 | ); 172 | name = LaunchScreen.storyboard; 173 | sourceTree = ""; 174 | }; 175 | /* End PBXVariantGroup section */ 176 | 177 | /* Begin XCBuildConfiguration section */ 178 | 9F2CF3831DB4606E00CA06FC /* Debug */ = { 179 | isa = XCBuildConfiguration; 180 | buildSettings = { 181 | ALWAYS_SEARCH_USER_PATHS = NO; 182 | CLANG_ANALYZER_NONNULL = YES; 183 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 184 | CLANG_CXX_LIBRARY = "libc++"; 185 | CLANG_ENABLE_MODULES = YES; 186 | CLANG_ENABLE_OBJC_ARC = YES; 187 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 188 | CLANG_WARN_BOOL_CONVERSION = YES; 189 | CLANG_WARN_COMMA = YES; 190 | CLANG_WARN_CONSTANT_CONVERSION = YES; 191 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 192 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 193 | CLANG_WARN_EMPTY_BODY = YES; 194 | CLANG_WARN_ENUM_CONVERSION = YES; 195 | CLANG_WARN_INFINITE_RECURSION = YES; 196 | CLANG_WARN_INT_CONVERSION = YES; 197 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 198 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 199 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 200 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 201 | CLANG_WARN_STRICT_PROTOTYPES = YES; 202 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 203 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 204 | CLANG_WARN_UNREACHABLE_CODE = YES; 205 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 206 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 207 | COPY_PHASE_STRIP = NO; 208 | DEBUG_INFORMATION_FORMAT = dwarf; 209 | ENABLE_STRICT_OBJC_MSGSEND = YES; 210 | ENABLE_TESTABILITY = YES; 211 | GCC_C_LANGUAGE_STANDARD = gnu99; 212 | GCC_DYNAMIC_NO_PIC = NO; 213 | GCC_NO_COMMON_BLOCKS = YES; 214 | GCC_OPTIMIZATION_LEVEL = 0; 215 | GCC_PREPROCESSOR_DEFINITIONS = ( 216 | "DEBUG=1", 217 | "$(inherited)", 218 | ); 219 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 220 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 221 | GCC_WARN_UNDECLARED_SELECTOR = YES; 222 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 223 | GCC_WARN_UNUSED_FUNCTION = YES; 224 | GCC_WARN_UNUSED_VARIABLE = YES; 225 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 226 | MTL_ENABLE_DEBUG_INFO = YES; 227 | ONLY_ACTIVE_ARCH = YES; 228 | SDKROOT = iphoneos; 229 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 230 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 231 | TARGETED_DEVICE_FAMILY = "1,2"; 232 | }; 233 | name = Debug; 234 | }; 235 | 9F2CF3841DB4606E00CA06FC /* Release */ = { 236 | isa = XCBuildConfiguration; 237 | buildSettings = { 238 | ALWAYS_SEARCH_USER_PATHS = NO; 239 | CLANG_ANALYZER_NONNULL = YES; 240 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 241 | CLANG_CXX_LIBRARY = "libc++"; 242 | CLANG_ENABLE_MODULES = YES; 243 | CLANG_ENABLE_OBJC_ARC = YES; 244 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 245 | CLANG_WARN_BOOL_CONVERSION = YES; 246 | CLANG_WARN_COMMA = YES; 247 | CLANG_WARN_CONSTANT_CONVERSION = YES; 248 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 249 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 250 | CLANG_WARN_EMPTY_BODY = YES; 251 | CLANG_WARN_ENUM_CONVERSION = YES; 252 | CLANG_WARN_INFINITE_RECURSION = YES; 253 | CLANG_WARN_INT_CONVERSION = YES; 254 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 257 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 258 | CLANG_WARN_STRICT_PROTOTYPES = YES; 259 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 260 | CLANG_WARN_SUSPICIOUS_MOVES = YES; 261 | CLANG_WARN_UNREACHABLE_CODE = YES; 262 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 263 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 264 | COPY_PHASE_STRIP = NO; 265 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 266 | ENABLE_NS_ASSERTIONS = NO; 267 | ENABLE_STRICT_OBJC_MSGSEND = YES; 268 | GCC_C_LANGUAGE_STANDARD = gnu99; 269 | GCC_NO_COMMON_BLOCKS = YES; 270 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 271 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 272 | GCC_WARN_UNDECLARED_SELECTOR = YES; 273 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 274 | GCC_WARN_UNUSED_FUNCTION = YES; 275 | GCC_WARN_UNUSED_VARIABLE = YES; 276 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 277 | MTL_ENABLE_DEBUG_INFO = NO; 278 | SDKROOT = iphoneos; 279 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 280 | TARGETED_DEVICE_FAMILY = "1,2"; 281 | VALIDATE_PRODUCT = YES; 282 | }; 283 | name = Release; 284 | }; 285 | 9F2CF3861DB4606E00CA06FC /* Debug */ = { 286 | isa = XCBuildConfiguration; 287 | buildSettings = { 288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 289 | CLANG_ENABLE_MODULES = YES; 290 | DEVELOPMENT_TEAM = Y9Y96CV7VP; 291 | INFOPLIST_FILE = SVUploader/Info.plist; 292 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 293 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 294 | PRODUCT_BUNDLE_IDENTIFIER = self.edu.SVUploader; 295 | PRODUCT_NAME = "$(TARGET_NAME)"; 296 | SWIFT_OBJC_BRIDGING_HEADER = "SVUploader/SVUploader-Bridging-Header.h"; 297 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 298 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 299 | SWIFT_VERSION = 4.0; 300 | }; 301 | name = Debug; 302 | }; 303 | 9F2CF3871DB4606E00CA06FC /* Release */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 307 | CLANG_ENABLE_MODULES = YES; 308 | DEVELOPMENT_TEAM = Y9Y96CV7VP; 309 | INFOPLIST_FILE = SVUploader/Info.plist; 310 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 311 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 312 | PRODUCT_BUNDLE_IDENTIFIER = self.edu.SVUploader; 313 | PRODUCT_NAME = "$(TARGET_NAME)"; 314 | SWIFT_OBJC_BRIDGING_HEADER = "SVUploader/SVUploader-Bridging-Header.h"; 315 | SWIFT_SWIFT3_OBJC_INFERENCE = On; 316 | SWIFT_VERSION = 4.0; 317 | }; 318 | name = Release; 319 | }; 320 | /* End XCBuildConfiguration section */ 321 | 322 | /* Begin XCConfigurationList section */ 323 | 9F2CF36E1DB4606E00CA06FC /* Build configuration list for PBXProject "SVUploader" */ = { 324 | isa = XCConfigurationList; 325 | buildConfigurations = ( 326 | 9F2CF3831DB4606E00CA06FC /* Debug */, 327 | 9F2CF3841DB4606E00CA06FC /* Release */, 328 | ); 329 | defaultConfigurationIsVisible = 0; 330 | defaultConfigurationName = Release; 331 | }; 332 | 9F2CF3851DB4606E00CA06FC /* Build configuration list for PBXNativeTarget "SVUploader" */ = { 333 | isa = XCConfigurationList; 334 | buildConfigurations = ( 335 | 9F2CF3861DB4606E00CA06FC /* Debug */, 336 | 9F2CF3871DB4606E00CA06FC /* Release */, 337 | ); 338 | defaultConfigurationIsVisible = 0; 339 | defaultConfigurationName = Release; 340 | }; 341 | /* End XCConfigurationList section */ 342 | }; 343 | rootObject = 9F2CF36B1DB4606E00CA06FC /* Project object */; 344 | } 345 | -------------------------------------------------------------------------------- /SVUploader/SVUploader.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SVUploader/SVUploader.xcodeproj/project.xcworkspace/xcuserdata/Kiran.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader.xcodeproj/project.xcworkspace/xcuserdata/Kiran.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /SVUploader/SVUploader.xcodeproj/xcuserdata/Kiran.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /SVUploader/SVUploader.xcodeproj/xcuserdata/Kiran.xcuserdatad/xcschemes/SVUploader.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /SVUploader/SVUploader.xcodeproj/xcuserdata/Kiran.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SVUploader.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 9F2CF3721DB4606E00CA06FC 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /SVUploader/SVUploader/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SVUploader 4 | // 5 | // Created by Kiran Kunigiri on 10/16/16. 6 | // Copyright © 2016 Kiran. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // 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. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // 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. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // 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. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "size" : "29x29", 15 | "idiom" : "iphone", 16 | "filename" : "iPhone-small@2x.png", 17 | "scale" : "2x" 18 | }, 19 | { 20 | "size" : "29x29", 21 | "idiom" : "iphone", 22 | "filename" : "iPhone-small@3x.png", 23 | "scale" : "3x" 24 | }, 25 | { 26 | "size" : "40x40", 27 | "idiom" : "iphone", 28 | "filename" : "iPhone-spotlight@2x.png", 29 | "scale" : "2x" 30 | }, 31 | { 32 | "size" : "40x40", 33 | "idiom" : "iphone", 34 | "filename" : "iPhone-spotlight@3x.png", 35 | "scale" : "3x" 36 | }, 37 | { 38 | "size" : "60x60", 39 | "idiom" : "iphone", 40 | "filename" : "iPhone-appIcon@2x.png", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "size" : "60x60", 45 | "idiom" : "iphone", 46 | "filename" : "iPhone-appIcon@3x.png", 47 | "scale" : "3x" 48 | }, 49 | { 50 | "idiom" : "ipad", 51 | "size" : "20x20", 52 | "scale" : "1x" 53 | }, 54 | { 55 | "idiom" : "ipad", 56 | "size" : "20x20", 57 | "scale" : "2x" 58 | }, 59 | { 60 | "size" : "29x29", 61 | "idiom" : "ipad", 62 | "filename" : "iPad-settings.png", 63 | "scale" : "1x" 64 | }, 65 | { 66 | "size" : "29x29", 67 | "idiom" : "ipad", 68 | "filename" : "iPad-settings@2x.png", 69 | "scale" : "2x" 70 | }, 71 | { 72 | "size" : "40x40", 73 | "idiom" : "ipad", 74 | "filename" : "iPad-spotlight.png", 75 | "scale" : "1x" 76 | }, 77 | { 78 | "size" : "40x40", 79 | "idiom" : "ipad", 80 | "filename" : "iPad-spotlight@2x.png", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "size" : "76x76", 85 | "idiom" : "ipad", 86 | "filename" : "iPad-appIcon.png", 87 | "scale" : "1x" 88 | }, 89 | { 90 | "size" : "76x76", 91 | "idiom" : "ipad", 92 | "filename" : "iPad-appIcon@2x.png", 93 | "scale" : "2x" 94 | }, 95 | { 96 | "size" : "83.5x83.5", 97 | "idiom" : "ipad", 98 | "filename" : "iPad-Pro-appIcon@2x.png", 99 | "scale" : "2x" 100 | }, 101 | { 102 | "size" : "24x24", 103 | "idiom" : "watch", 104 | "filename" : "watch-notificationCenter-38mm@2x.png", 105 | "scale" : "2x", 106 | "role" : "notificationCenter", 107 | "subtype" : "38mm" 108 | }, 109 | { 110 | "size" : "27.5x27.5", 111 | "idiom" : "watch", 112 | "filename" : "watch-notificationCenter-42mm@2x.png", 113 | "scale" : "2x", 114 | "role" : "notificationCenter", 115 | "subtype" : "42mm" 116 | }, 117 | { 118 | "size" : "29x29", 119 | "idiom" : "watch", 120 | "filename" : "watch-companionSettings@2x.png", 121 | "role" : "companionSettings", 122 | "scale" : "2x" 123 | }, 124 | { 125 | "size" : "29x29", 126 | "idiom" : "watch", 127 | "filename" : "watch-companionSettings@3x.png", 128 | "role" : "companionSettings", 129 | "scale" : "3x" 130 | }, 131 | { 132 | "size" : "40x40", 133 | "idiom" : "watch", 134 | "filename" : "watch-appLauncher-38mm@2x.png", 135 | "scale" : "2x", 136 | "role" : "appLauncher", 137 | "subtype" : "38mm" 138 | }, 139 | { 140 | "size" : "44x44", 141 | "idiom" : "watch", 142 | "filename" : "watch-longLook-42mm@2x.png", 143 | "scale" : "2x", 144 | "role" : "longLook", 145 | "subtype" : "42mm" 146 | }, 147 | { 148 | "size" : "86x86", 149 | "idiom" : "watch", 150 | "filename" : "watch-quickLook-38mm@2x.png", 151 | "scale" : "2x", 152 | "role" : "quickLook", 153 | "subtype" : "38mm" 154 | }, 155 | { 156 | "size" : "98x98", 157 | "idiom" : "watch", 158 | "filename" : "watch-quickLook-42mm@2x.png", 159 | "scale" : "2x", 160 | "role" : "quickLook", 161 | "subtype" : "42mm" 162 | } 163 | ], 164 | "info" : { 165 | "version" : 1, 166 | "author" : "xcode" 167 | } 168 | } -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPad-Pro-appIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPad-Pro-appIcon@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPad-appIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPad-appIcon.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPad-appIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPad-appIcon@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPad-settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPad-settings.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPad-settings@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPad-settings@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPad-spotlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPad-spotlight.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPad-spotlight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPad-spotlight@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPhone-appIcon@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPhone-appIcon@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPhone-appIcon@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPhone-appIcon@3x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPhone-small@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPhone-small@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPhone-small@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPhone-small@3x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPhone-spotlight@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPhone-spotlight@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPhone-spotlight@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/iPhone-spotlight@3x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-appLauncher-38mm@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-appLauncher-38mm@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-companionSettings@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-companionSettings@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-companionSettings@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-companionSettings@3x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-longLook-42mm@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-longLook-42mm@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-notificationCenter-38mm@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-notificationCenter-38mm@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-notificationCenter-42mm@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-notificationCenter-42mm@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-quickLook-38mm@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-quickLook-38mm@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-quickLook-42mm@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/AppIcon.appiconset/watch-quickLook-42mm@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/Check.imageset/Check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/Check.imageset/Check.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/Check.imageset/Check@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/Check.imageset/Check@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/Check.imageset/Check@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/Check.imageset/Check@3x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/Check.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Check.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "Check@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "Check@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/X.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "X.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "X@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "X@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/X.imageset/X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/X.imageset/X.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/X.imageset/X@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/X.imageset/X@2x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/X.imageset/X@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/X.imageset/X@3x.png -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/anubis.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "anubis.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/anubis.imageset/anubis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/anubis.imageset/anubis.jpg -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/example.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "baymax.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/example.imageset/baymax.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/example.imageset/baymax.jpg -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/galaxy.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "galaxy.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/galaxy.imageset/galaxy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/galaxy.imageset/galaxy.jpg -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/trooper.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "trooper.jpg", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /SVUploader/SVUploader/Assets.xcassets/trooper.imageset/trooper.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kirankunigiri/SVUploader/57f387e843bd3a0b259d020b58404d0a38409288/SVUploader/SVUploader/Assets.xcassets/trooper.imageset/trooper.jpg -------------------------------------------------------------------------------- /SVUploader/SVUploader/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /SVUploader/SVUploader/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /SVUploader/SVUploader/CodeViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // SVUploader 4 | // 5 | // Created by Kiran Kunigiri on 10/11/16. 6 | // Copyright © 2016 Kiran. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | /** 13 | CODE EXAMPLE 14 | 15 | This class is an example that shows how to create an SVUploader view from code. 16 | It has multiple initializers that you can uncomment and play around with. 17 | */ 18 | 19 | class CodeViewController: UIViewController { 20 | 21 | var uploaderView: SVUploader! 22 | var percent = 0 23 | var timer: Timer! 24 | 25 | override func viewDidLoad() { 26 | super.viewDidLoad() 27 | 28 | // Create the frame for the uploader view 29 | let uploaderFrame = CGRect(x: 0, y: 0, width: 200, height: 200) 30 | 31 | // Example of the default initializer setup 32 | // uploaderView = SVUploader(frame: uploaderFrame) 33 | 34 | // Example of the common initialzer setup 35 | // let customLineColor = UIColor(red:0.30, green:0.49, blue:0.95, alpha:1.0) 36 | // uploaderView = SVUploader(lineColor: customLineColor, lineWidth: 15) 37 | 38 | // Example of the detailed initializer setup 39 | // uploaderView = SVUploader(lineColor: customLineColor, lineWidth: 12, borderColor: UIColor.lightGray, borderWidth: 5) 40 | 41 | // Example of the initializer-only variable setup. 42 | uploaderView = SVUploader(useBlur: true, useShadow: true, useSmoothAnimation: true) 43 | 44 | // Set the frame, center the view, and add it to the superview 45 | uploaderView.frame = uploaderFrame 46 | uploaderView.center = self.view.center 47 | self.view.addSubview(uploaderView) 48 | 49 | // Set the image 50 | uploaderView.image = UIImage(named: "galaxy") 51 | } 52 | 53 | @IBAction func uploadButtonPressed(_ sender: UIButton) { 54 | if uploaderView.isAnimating { return } 55 | 56 | uploaderView.startUpload() 57 | timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(time), userInfo: nil, repeats: true) 58 | } 59 | 60 | // Updates the progress bar of the uploader view. In reality you would want to connect this to your backend and update it. 61 | @objc func time() { 62 | self.uploaderView.progress += 0.003 63 | if self.uploaderView.progress == 1 { 64 | self.timer.invalidate() 65 | self.uploaderView.endUpload(success: true) 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /SVUploader/SVUploader/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /SVUploader/SVUploader/SVUploader-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | -------------------------------------------------------------------------------- /SVUploader/SVUploader/SVUploader.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SVUploader.swift 3 | // SVUploader 4 | // 5 | // Created by Kiran Kunigiri on 10/16/16. 6 | // Copyright © 2016 Kiran. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | class SVUploader: UIView { 13 | 14 | // ============================================================================================== 15 | // MARK: - Properties 16 | // ============================================================================================== 17 | 18 | 19 | 20 | // ============================================================================================== 21 | // MARK: Views 22 | // ============================================================================================== 23 | 24 | // The container view will hold all views inside the circle 25 | var containerView = UIView() 26 | var contentView = UIView() 27 | var shadowView = UIView() 28 | var endView = UIView() 29 | var contentImageView = UIImageView() 30 | var endImageView = UIImageView() 31 | var overlayView = UIView() 32 | var blurEffect = UIBlurEffect() 33 | var blurView = UIVisualEffectView() 34 | var loadingLabel = UILabel() 35 | 36 | // Image assets 37 | var successImage = UIImage(named: "Check") 38 | var errorImage = UIImage(named: "X") 39 | 40 | // The circle is separate and is outside the container view 41 | var circlePathLayer = CAShapeLayer() 42 | var circleBorderLayer = CAShapeLayer() 43 | 44 | /** The image of the uploader. Can be set to nil if an image is not being used. */ 45 | var image: UIImage? { 46 | didSet { 47 | if image != nil { 48 | self.contentImageView.image = image 49 | self.contentImageView.isHidden = false 50 | } else { 51 | self.contentImageView.isHidden = true 52 | } 53 | } 54 | } 55 | 56 | 57 | 58 | // ============================================================================================== 59 | // MARK: Variables 60 | // ============================================================================================== 61 | 62 | /** Whether or not the uploader is currently uploading. Read only. */ 63 | var isUploading: Bool = false 64 | /** Whether or not the uploader is currently animating. Read only. Different from `isUploading` because it includes the end animation duration. */ 65 | var isAnimating: Bool = false 66 | 67 | /** The speed of the animation between progress value changes. This number should be changed depending on the length of intervals between each progress percentage update. For larger intervals, a lower speed is recommended for a smoother animation. For shorter intervals, a higher speed is recommended to prevent slow animation and lag. Default value = 1 */ 68 | var progressAnimationSpeed: Float = 2 { 69 | didSet { circlePathLayer.speed = progressAnimationSpeed } 70 | } 71 | 72 | /** Whether or not the uploader uses the blur effect. Private and set only by the constructor. */ 73 | private var useBlur: Bool = false 74 | 75 | /** Whether or not the uploader uses the shadow effect. Private and set only by the constructor. */ 76 | private var useShadow: Bool = false 77 | 78 | /** The color of the circular loader */ 79 | var lineColor = UIColor(red:0.40, green:0.47, blue:0.97, alpha:1.0) { 80 | didSet { circlePathLayer.strokeColor = lineColor.cgColor } 81 | } 82 | 83 | /** The width of the circular loader */ 84 | var lineWidth: CGFloat = 12 { 85 | didSet { circlePathLayer.lineWidth = lineWidth } 86 | } 87 | 88 | /** The color of the border */ 89 | var borderColor = UIColor(red:0.55, green:0.55, blue:0.55, alpha:1.0) { 90 | didSet { circleBorderLayer.strokeColor = borderColor.cgColor } 91 | } 92 | 93 | /** The width of the border */ 94 | var borderWidth: CGFloat = 0 { 95 | didSet { circleBorderLayer.lineWidth = borderWidth } 96 | } 97 | 98 | /** The overlay opacity of the view during uploading */ 99 | var overlayOpacity: CGFloat = 0.6 100 | 101 | /** The main font used. Changing this font will automatically change the font for all labels */ 102 | var mainFont = UIFont(name: "Avenir-Medium", size: 30.0)! { 103 | didSet { loadingLabel.font = mainFont } 104 | } 105 | 106 | /** The duration of the message to be displayed at the end of the upload */ 107 | var messageDuration: Double = 1 108 | 109 | /* The progress percentage of the upload. Update this variable with a decimal to update the uploader */ 110 | var progress: CGFloat { 111 | get { 112 | return circlePathLayer.strokeEnd 113 | } 114 | set { 115 | if !isUploading { 116 | return 117 | } 118 | if (newValue > 1.0) { 119 | circlePathLayer.strokeEnd = 1 120 | } else if (newValue < 0) { 121 | circlePathLayer.strokeEnd = 0 122 | } else { 123 | circlePathLayer.strokeEnd = newValue 124 | } 125 | loadingLabel.text = "\(Int(circlePathLayer.strokeEnd*100))%" 126 | } 127 | } 128 | 129 | /** Set success to easily modify the endView properties */ 130 | private var success: Bool = true { 131 | didSet { 132 | if success { endImageView.image = successImage } 133 | else { endImageView.image = errorImage } 134 | } 135 | } 136 | 137 | 138 | // ============================================================================================== 139 | // MARK: - Initializers 140 | // ============================================================================================== 141 | 142 | override init(frame: CGRect) { 143 | super.init(frame: frame) 144 | setup() 145 | } 146 | 147 | required init?(coder aDecoder: NSCoder) { 148 | super.init(coder: aDecoder) 149 | print("using storyboard") 150 | setup() 151 | layoutSubviews() 152 | } 153 | 154 | init(lineColor: UIColor, lineWidth: CGFloat) { 155 | super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) 156 | 157 | self.lineColor = lineColor 158 | self.lineWidth = lineWidth 159 | 160 | setup() 161 | } 162 | 163 | init(lineColor: UIColor, lineWidth: CGFloat, borderColor: UIColor, borderWidth: CGFloat) { 164 | super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) 165 | 166 | self.lineColor = lineColor 167 | self.lineWidth = lineWidth 168 | self.borderColor = borderColor 169 | self.borderWidth = borderWidth 170 | 171 | setup() 172 | } 173 | 174 | init(useBlur: Bool, useShadow: Bool, useSmoothAnimation: Bool) { 175 | super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0)) 176 | 177 | self.useBlur = useBlur 178 | self.useShadow = useShadow 179 | if !useSmoothAnimation { 180 | circlePathLayer.actions = ["strokeEnd" : NSNull()] 181 | } 182 | 183 | setup() 184 | } 185 | 186 | func setup() { 187 | 188 | // Blur 189 | if useBlur { 190 | blurEffect = UIBlurEffect(style: .dark) 191 | blurView = UIVisualEffectView(effect: blurEffect) 192 | blurView.alpha = 0 193 | } 194 | 195 | // Add all views and layers in order 196 | self.layer.addSublayer(circlePathLayer) 197 | self.layer.addSublayer(circleBorderLayer) 198 | 199 | if useShadow { self.addSubview(shadowView) } 200 | 201 | self.addSubview(containerView) 202 | containerView.addSubview(contentView) 203 | if useBlur { 204 | containerView.addSubview(blurView) 205 | } else { 206 | containerView.addSubview(overlayView) 207 | } 208 | containerView.addSubview(loadingLabel) 209 | containerView.addSubview(endView) 210 | contentView.addSubview(contentImageView) 211 | endView.addSubview(endImageView) 212 | 213 | // View setup 214 | containerView.clipsToBounds = true 215 | contentImageView.contentMode = .scaleAspectFill 216 | 217 | contentImageView.autoresizingMask = [.flexibleWidth, .flexibleHeight] 218 | if useBlur { blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight] } 219 | for view in containerView.subviews { 220 | view.autoresizingMask = [.flexibleWidth, .flexibleHeight] 221 | } 222 | 223 | // Overlay 224 | overlayView.backgroundColor = UIColor.black 225 | overlayView.alpha = 0 226 | 227 | // Loading Label 228 | loadingLabel.textColor = UIColor.white 229 | loadingLabel.textAlignment = .center 230 | loadingLabel.alpha = 0 231 | 232 | // End view 233 | endImageView.image = errorImage 234 | endImageView.contentMode = .scaleAspectFit 235 | endView.alpha = 0 236 | 237 | // Circle Path Layer 238 | circlePathLayer.strokeStart = 0 239 | circlePathLayer.strokeEnd = 0 240 | circlePathLayer.lineWidth = lineWidth 241 | circlePathLayer.strokeColor = lineColor.cgColor 242 | circlePathLayer.fillColor = UIColor.clear.cgColor 243 | circlePathLayer.speed = progressAnimationSpeed 244 | 245 | // Circle Path Layer 246 | circleBorderLayer.strokeStart = 0 247 | circleBorderLayer.strokeEnd = 1 248 | circleBorderLayer.lineWidth = borderWidth 249 | circleBorderLayer.strokeColor = borderColor.cgColor 250 | circleBorderLayer.fillColor = UIColor.clear.cgColor 251 | } 252 | 253 | override func layoutSubviews() { 254 | super.layoutSubviews() 255 | 256 | // Important: To center a view, set its frame.center to superview!.bounds.center 257 | 258 | // Offset the loader ring by lineWidth/2 259 | self.circlePathLayer.frame = self.bounds 260 | let circleFrame = circlePathLayer.frame.insetBy(dx: lineWidth/2, dy: lineWidth/2) 261 | circlePathLayer.path = UIBezierPath(ovalIn: circleFrame).cgPath 262 | 263 | // Offset the border ring by (lineWidth + borderWidth/20 264 | self.circleBorderLayer.frame = self.bounds 265 | let borderFrame = circleBorderLayer.frame.insetBy(dx: lineWidth + borderWidth/2, dy: lineWidth + borderWidth/2) 266 | circleBorderLayer.path = UIBezierPath(ovalIn: borderFrame).cgPath 267 | 268 | // Offset the content view by (lineWidth + borderWidth) 269 | containerView.frame = self.frame.insetBy(dx: lineWidth + borderWidth, dy: lineWidth + borderWidth) 270 | containerView.frame.center = containerView.superview!.bounds.center 271 | 272 | // Offset the image view by a scale factor 273 | let scale = (60.0/180.0)*containerView.frame.width 274 | endImageView.frame = containerView.frame.insetBy(dx: scale, dy: scale) 275 | endImageView.frame.center = endImageView.superview!.bounds.center 276 | 277 | // Transform container view back into a circle (Uses UIView extension listed at the bottom of the file) 278 | containerView.transformToCircle() 279 | 280 | // Scale font size 281 | mainFont = UIFont(name: mainFont.fontName, size: (30.0/150.0) * self.frame.width)! 282 | 283 | // Content shadow 284 | if useShadow { 285 | shadowView.layer.masksToBounds = false 286 | shadowView.layer.shadowColor = UIColor.black.cgColor 287 | shadowView.layer.shadowOpacity = 0.4 288 | shadowView.layer.shadowOffset = CGSize.zero 289 | shadowView.layer.shadowRadius = 6 290 | shadowView.layer.shadowPath = UIBezierPath(ovalIn: containerView.frame).cgPath 291 | } 292 | } 293 | 294 | 295 | 296 | // ============================================================================================== 297 | // MARK: - Methods 298 | // ============================================================================================== 299 | 300 | /** Starts the upload animation. You should now consistently update the progress property to advanced the animation. Use endUplad() when you are finished. */ 301 | func startUpload() { 302 | // Set the initial properties 303 | isUploading = true 304 | isAnimating = true 305 | progress = 0 306 | 307 | // Animate the loading views in 308 | UIView.animate(withDuration: 0.5) { 309 | self.circlePathLayer.isHidden = false 310 | self.overlayView.alpha = self.overlayOpacity 311 | self.loadingLabel.alpha = 1 312 | self.blurView.alpha = 1 313 | } 314 | } 315 | 316 | /** Ends the upload. Use the success parameter to specify whether the success or error view should be shown. */ 317 | func endUpload(success: Bool) { 318 | // Set the initial properties 319 | isUploading = false 320 | self.success = success 321 | 322 | // Prepare the circle path for the animation 323 | let originalPath = circlePathLayer.path 324 | self.circlePathLayer.frame = self.bounds 325 | let circleFrame = circlePathLayer.frame.insetBy(dx: lineWidth*2, dy: lineWidth*2) 326 | let toPath = UIBezierPath(ovalIn: circleFrame).cgPath 327 | 328 | // Wrap animation in a CATransaction 329 | CATransaction.begin() 330 | // Use another CABasicAnimation in the completion block with a duration of 0 to change the frame back to the original, because changing the property itself does not work 331 | CATransaction.setCompletionBlock { 332 | let anim = CABasicAnimation(keyPath: "path") 333 | anim.toValue = originalPath 334 | anim.duration = 0 335 | anim.fillMode = kCAFillModeForwards 336 | anim.isRemovedOnCompletion = false 337 | self.circlePathLayer.add(anim, forKey: "path") 338 | self.circlePathLayer.isHidden = true 339 | self.circlePathLayer.strokeEnd = 0 340 | } 341 | 342 | // Shrink the path of the circle layer 343 | let anim = CABasicAnimation(keyPath: "path") 344 | anim.toValue = toPath 345 | anim.duration = 1.5 346 | anim.fillMode = kCAFillModeForwards 347 | anim.isRemovedOnCompletion = false 348 | circlePathLayer.add(anim, forKey: "path") 349 | CATransaction.commit() 350 | 351 | // Animate the endView out and return to the original state 352 | UIView.animate(withDuration: 1, animations: { 353 | self.loadingLabel.alpha = 0 354 | self.endView.alpha = 1 355 | }) { (completion) in 356 | UIView.animate(withDuration: 1, delay: self.messageDuration, options: [], animations: { 357 | self.overlayView.alpha = 0 358 | self.blurView.alpha = 0 359 | self.endView.alpha = 0 360 | }, completion: { (completion) in 361 | self.isAnimating = false 362 | }) 363 | } 364 | 365 | } 366 | 367 | } 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | // ============================================================================================== 384 | // MARK: - Extensions 385 | // ============================================================================================== 386 | extension CGRect { 387 | 388 | /** The center point of the rectangle. It is mutable. */ 389 | var center: CGPoint { 390 | get { 391 | return CGPoint(x: self.midX, y: self.midY) 392 | } 393 | set { 394 | self.origin.x = newValue.x - width/2 395 | self.origin.y = newValue.y - height/2 396 | } 397 | } 398 | 399 | } 400 | 401 | extension UIView { 402 | 403 | /** Caches a shadow to prevent lag */ 404 | func cacheShadow() { 405 | self.layer.shadowPath = UIBezierPath(roundedRect: self.bounds, cornerRadius: self.layer.cornerRadius).cgPath 406 | } 407 | 408 | /** Turns a square view into a circle by changing the corner radius */ 409 | func transformToCircle() { 410 | self.layer.cornerRadius = self.frame.height/2 411 | } 412 | } 413 | 414 | 415 | -------------------------------------------------------------------------------- /SVUploader/SVUploader/StoryboardViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StoryboardViewController.swift 3 | // SVUploader 4 | // 5 | // Created by Kiran Kunigiri on 11/26/16. 6 | // Copyright © 2016 Kiran. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | /** 13 | STORYBOARD EXAMPLE 14 | 15 | This class is an example that shows how to create an SVUploader view from Storyboard. 16 | Check out the storyboard to see how it works. All you have to do is drag in a UIView and change its class to SVUploader. 17 | */ 18 | 19 | class StoryboardViewController: UIViewController { 20 | 21 | @IBOutlet weak var uploaderView: SVUploader! 22 | var percent = 0 23 | var timer: Timer! 24 | 25 | override func viewDidLoad() { 26 | super.viewDidLoad() 27 | 28 | // Set the image 29 | uploaderView.image = UIImage(named: "galaxy") 30 | } 31 | 32 | @IBAction func uploadButtonPressed(_ sender: UIButton) { 33 | if uploaderView.isAnimating { return } 34 | 35 | uploaderView.startUpload() 36 | timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(time), userInfo: nil, repeats: true) 37 | } 38 | 39 | // Updates the progress bar of the uploader view. In reality you would want to connect this to your backend and update it. 40 | @objc func time() { 41 | self.uploaderView.progress += 0.003 42 | if self.uploaderView.progress == 1 { 43 | self.timer.invalidate() 44 | self.uploaderView.endUpload(success: true) 45 | } 46 | } 47 | } 48 | --------------------------------------------------------------------------------