├── .gitignore ├── Artworks ├── 128.png ├── 16.png ├── 256.png ├── 32.png ├── 512.png ├── 64.png └── cocoacontrols.psd ├── CocoaControls.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── CocoaControls.xccheckout │ │ └── WorkspaceSettings.xcsettings ├── xcshareddata │ └── xcschemes │ │ └── CocoaControls.xcscheme └── xcuserdata │ └── R0CKSTAR.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── CocoaControls ├── AFNetworking │ ├── AFNetworking │ │ ├── AFHTTPRequestOperation.h │ │ ├── AFHTTPRequestOperation.m │ │ ├── AFHTTPRequestOperationManager.h │ │ ├── AFHTTPRequestOperationManager.m │ │ ├── AFHTTPSessionManager.h │ │ ├── AFHTTPSessionManager.m │ │ ├── AFNetworkReachabilityManager.h │ │ ├── AFNetworkReachabilityManager.m │ │ ├── AFNetworking.h │ │ ├── AFSecurityPolicy.h │ │ ├── AFSecurityPolicy.m │ │ ├── AFURLConnectionOperation.h │ │ ├── AFURLConnectionOperation.m │ │ ├── AFURLRequestSerialization.h │ │ ├── AFURLRequestSerialization.m │ │ ├── AFURLResponseSerialization.h │ │ ├── AFURLResponseSerialization.m │ │ ├── AFURLSessionManager.h │ │ └── AFURLSessionManager.m │ ├── LICENSE │ └── README.md ├── Base.lproj │ └── MainMenu.xib ├── CocoaControls-Info.plist ├── CocoaControls-Prefix.pch ├── ITPullToRefreshScrollView │ ├── ITPullToRefreshScrollView │ │ └── Classes │ │ │ ├── DuxScrollViewAnimation.h │ │ │ ├── DuxScrollViewAnimation.m │ │ │ ├── ITPullToRefreshClipView.h │ │ │ ├── ITPullToRefreshClipView.m │ │ │ ├── ITPullToRefreshEdgeView.h │ │ │ ├── ITPullToRefreshEdgeView.m │ │ │ ├── ITPullToRefreshScrollView.h │ │ │ └── ITPullToRefreshScrollView.m │ ├── LICENSE │ ├── Modules │ │ ├── ITProgressIndicator │ │ │ └── ITProgressIndicator │ │ │ │ └── Classes │ │ │ │ ├── ITProgressIndicator.h │ │ │ │ ├── ITProgressIndicator.m │ │ │ │ ├── NSBezierPath+Geometry.h │ │ │ │ └── NSBezierPath+Geometry.m │ │ └── NSBKeyframeAnimation │ │ │ └── NSBKeyframeAnimation │ │ │ └── Classes │ │ │ └── NSBKeyframeAnimation │ │ │ ├── NSBKeyframeAnimation.h │ │ │ ├── NSBKeyframeAnimation.m │ │ │ ├── NSBKeyframeAnimationFunctions.c │ │ │ └── NSBKeyframeAnimationFunctions.h │ └── README.md ├── Images.xcassets │ ├── AppIcon.appiconset │ │ ├── 128.png │ │ ├── 16.png │ │ ├── 256.png │ │ ├── 32.png │ │ ├── 512.png │ │ ├── 64.png │ │ └── Contents.json │ ├── cocoapods.imageset │ │ ├── Contents.json │ │ └── cocoapods.png │ ├── desktop-button.imageset │ │ ├── Contents.json │ │ └── desktop-button.png │ ├── filter.imageset │ │ ├── Contents.json │ │ └── filter.png │ ├── more.imageset │ │ ├── Contents.json │ │ └── more.png │ ├── placeholder.imageset │ │ ├── Contents.json │ │ └── placeholder.png │ ├── refresh.imageset │ │ ├── Contents.json │ │ └── refresh.png │ ├── star-half-o.imageset │ │ ├── Contents.json │ │ └── star-half-o.png │ ├── star-o.imageset │ │ ├── Contents.json │ │ └── star-o.png │ └── star.imageset │ │ ├── Contents.json │ │ └── star.png ├── RSCCAPI.h ├── RSCCAPI.m ├── RSCCAppDelegate.h ├── RSCCAppDelegate.m ├── RSCCControl.h ├── RSCCControl.m ├── RSCCControlCellView.h ├── RSCCControlCellView.m ├── RSCCCore.h ├── RSCCCore.m ├── RSCCHTMLResponseSerializer.h ├── RSCCHTMLResponseSerializer.m ├── RSCCImageRequestSerializer.h ├── RSCCImageRequestSerializer.m ├── RSCCImageResponseSerializer.h ├── RSCCImageResponseSerializer.m ├── en.lproj │ └── Credits.rtf └── hpple │ ├── LICENSE.txt │ ├── README.markdown │ ├── TFHpple.h │ ├── TFHpple.m │ ├── TFHppleElement.h │ ├── TFHppleElement.m │ ├── XPathQuery.h │ └── XPathQuery.m ├── CocoaControlsPlugin ├── CocoaControlsPlugin.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── CocoaControlsPlugin.xccheckout │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── xcschemes │ │ └── CocoaControlsPlugin.xcscheme └── CocoaControlsPlugin │ ├── CocoaControlsPlugin-Info.plist │ ├── CocoaControlsPlugin-Prefix.pch │ ├── Helpers │ ├── CCPProject.h │ ├── CCPProject.m │ ├── CCPWorkspaceManager.h │ └── CCPWorkspaceManager.m │ ├── RSCCPCocoaControlsPlugin.h │ └── RSCCPCocoaControlsPlugin.m ├── LICENSE.md ├── README.md ├── app_screenshot.png └── plugin_screenshot.png /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | CocoaControlsPlugin/CocoaControlsPlugin.xcodeproj/project.xcworkspace/xcuserdata/* 3 | 4 | CocoaControlsPlugin/CocoaControlsPlugin.xcodeproj/xcuserdata/* 5 | 6 | CocoaControls.xcodeproj/project.xcworkspace/xcuserdata/* 7 | -------------------------------------------------------------------------------- /Artworks/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/Artworks/128.png -------------------------------------------------------------------------------- /Artworks/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/Artworks/16.png -------------------------------------------------------------------------------- /Artworks/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/Artworks/256.png -------------------------------------------------------------------------------- /Artworks/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/Artworks/32.png -------------------------------------------------------------------------------- /Artworks/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/Artworks/512.png -------------------------------------------------------------------------------- /Artworks/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/Artworks/64.png -------------------------------------------------------------------------------- /Artworks/cocoacontrols.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/Artworks/cocoacontrols.psd -------------------------------------------------------------------------------- /CocoaControls.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CocoaControls.xcodeproj/project.xcworkspace/xcshareddata/CocoaControls.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 0DA30BB4-5281-4798-A541-003AA681DEF3 9 | IDESourceControlProjectName 10 | CocoaControls 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 69291726009AC4C9A421F4E062E482087A00300B 14 | https://github.com/mralexgray/CocoaControlsPlugin.git 15 | 16 | IDESourceControlProjectPath 17 | CocoaControls.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 69291726009AC4C9A421F4E062E482087A00300B 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/mralexgray/CocoaControlsPlugin.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 69291726009AC4C9A421F4E062E482087A00300B 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 69291726009AC4C9A421F4E062E482087A00300B 36 | IDESourceControlWCCName 37 | CocoaControlsPlugin 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /CocoaControls.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CocoaControls.xcodeproj/xcshareddata/xcschemes/CocoaControls.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 85 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /CocoaControls.xcodeproj/xcuserdata/R0CKSTAR.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /CocoaControls.xcodeproj/xcuserdata/R0CKSTAR.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | CocoaControls.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | D0108A451913CCD500912C70 16 | 17 | primary 18 | 19 | 20 | D0108A661913CCD500912C70 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /CocoaControls/AFNetworking/AFNetworking/AFHTTPRequestOperation.h: -------------------------------------------------------------------------------- 1 | // AFHTTPRequestOperation.h 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #import 24 | #import "AFURLConnectionOperation.h" 25 | 26 | /** 27 | `AFHTTPRequestOperation` is a subclass of `AFURLConnectionOperation` for requests using the HTTP or HTTPS protocols. It encapsulates the concept of acceptable status codes and content types, which determine the success or failure of a request. 28 | */ 29 | @interface AFHTTPRequestOperation : AFURLConnectionOperation 30 | 31 | ///------------------------------------------------ 32 | /// @name Getting HTTP URL Connection Information 33 | ///------------------------------------------------ 34 | 35 | /** 36 | The last HTTP response received by the operation's connection. 37 | */ 38 | @property (readonly, nonatomic, strong) NSHTTPURLResponse *response; 39 | 40 | /** 41 | Responses sent from the server in data tasks created with `dataTaskWithRequest:success:failure:` and run using the `GET` / `POST` / et al. convenience methods are automatically validated and serialized by the response serializer. By default, this property is set to an AFHTTPResponse serializer, which uses the raw data as its response object. The serializer validates the status code to be in the `2XX` range, denoting success. If the response serializer generates an error in `-responseObjectForResponse:data:error:`, the `failure` callback of the session task or request operation will be executed; otherwise, the `success` callback will be executed. 42 | 43 | @warning `responseSerializer` must not be `nil`. Setting a response serializer will clear out any cached value 44 | */ 45 | @property (nonatomic, strong) AFHTTPResponseSerializer * responseSerializer; 46 | 47 | /** 48 | An object constructed by the `responseSerializer` from the response and response data. Returns `nil` unless the operation `isFinished`, has a `response`, and has `responseData` with non-zero content length. If an error occurs during serialization, `nil` will be returned, and the `error` property will be populated with the serialization error. 49 | */ 50 | @property (readonly, nonatomic, strong) id responseObject; 51 | 52 | ///----------------------------------------------------------- 53 | /// @name Setting Completion Block Success / Failure Callbacks 54 | ///----------------------------------------------------------- 55 | 56 | /** 57 | Sets the `completionBlock` property with a block that executes either the specified success or failure block, depending on the state of the request on completion. If `error` returns a value, which can be caused by an unacceptable status code or content type, then `failure` is executed. Otherwise, `success` is executed. 58 | 59 | This method should be overridden in subclasses in order to specify the response object passed into the success block. 60 | 61 | @param success The block to be executed on the completion of a successful request. This block has no return value and takes two arguments: the receiver operation and the object constructed from the response data of the request. 62 | @param failure The block to be executed on the completion of an unsuccessful request. This block has no return value and takes two arguments: the receiver operation and the error that occurred during the request. 63 | */ 64 | - (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 65 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /CocoaControls/AFNetworking/AFNetworking/AFHTTPRequestOperation.m: -------------------------------------------------------------------------------- 1 | // AFHTTPRequestOperation.m 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #import "AFHTTPRequestOperation.h" 24 | 25 | static dispatch_queue_t http_request_operation_processing_queue() { 26 | static dispatch_queue_t af_http_request_operation_processing_queue; 27 | static dispatch_once_t onceToken; 28 | dispatch_once(&onceToken, ^{ 29 | af_http_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.http-request.processing", DISPATCH_QUEUE_CONCURRENT); 30 | }); 31 | 32 | return af_http_request_operation_processing_queue; 33 | } 34 | 35 | static dispatch_group_t http_request_operation_completion_group() { 36 | static dispatch_group_t af_http_request_operation_completion_group; 37 | static dispatch_once_t onceToken; 38 | dispatch_once(&onceToken, ^{ 39 | af_http_request_operation_completion_group = dispatch_group_create(); 40 | }); 41 | 42 | return af_http_request_operation_completion_group; 43 | } 44 | 45 | #pragma mark - 46 | 47 | @interface AFURLConnectionOperation () 48 | @property (readwrite, nonatomic, strong) NSURLRequest *request; 49 | @property (readwrite, nonatomic, strong) NSURLResponse *response; 50 | @end 51 | 52 | @interface AFHTTPRequestOperation () 53 | @property (readwrite, nonatomic, strong) NSHTTPURLResponse *response; 54 | @property (readwrite, nonatomic, strong) id responseObject; 55 | @property (readwrite, nonatomic, strong) NSError *responseSerializationError; 56 | @property (readwrite, nonatomic, strong) NSRecursiveLock *lock; 57 | @end 58 | 59 | @implementation AFHTTPRequestOperation 60 | @dynamic lock; 61 | 62 | - (instancetype)initWithRequest:(NSURLRequest *)urlRequest { 63 | self = [super initWithRequest:urlRequest]; 64 | if (!self) { 65 | return nil; 66 | } 67 | 68 | self.responseSerializer = [AFHTTPResponseSerializer serializer]; 69 | 70 | return self; 71 | } 72 | 73 | - (void)setResponseSerializer:(AFHTTPResponseSerializer *)responseSerializer { 74 | NSParameterAssert(responseSerializer); 75 | 76 | [self.lock lock]; 77 | _responseSerializer = responseSerializer; 78 | self.responseObject = nil; 79 | self.responseSerializationError = nil; 80 | [self.lock unlock]; 81 | } 82 | 83 | - (id)responseObject { 84 | [self.lock lock]; 85 | if (!_responseObject && [self isFinished] && !self.error) { 86 | NSError *error = nil; 87 | self.responseObject = [self.responseSerializer responseObjectForResponse:self.response data:self.responseData error:&error]; 88 | if (error) { 89 | self.responseSerializationError = error; 90 | } 91 | } 92 | [self.lock unlock]; 93 | 94 | return _responseObject; 95 | } 96 | 97 | - (NSError *)error { 98 | if (_responseSerializationError) { 99 | return _responseSerializationError; 100 | } else { 101 | return [super error]; 102 | } 103 | } 104 | 105 | #pragma mark - AFHTTPRequestOperation 106 | 107 | - (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 108 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 109 | { 110 | // completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle. 111 | #pragma clang diagnostic push 112 | #pragma clang diagnostic ignored "-Warc-retain-cycles" 113 | #pragma clang diagnostic ignored "-Wgnu" 114 | self.completionBlock = ^{ 115 | if (self.completionGroup) { 116 | dispatch_group_enter(self.completionGroup); 117 | } 118 | 119 | dispatch_async(http_request_operation_processing_queue(), ^{ 120 | if (self.error) { 121 | if (failure) { 122 | dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{ 123 | failure(self, self.error); 124 | }); 125 | } 126 | } else { 127 | id responseObject = self.responseObject; 128 | if (self.error) { 129 | if (failure) { 130 | dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{ 131 | failure(self, self.error); 132 | }); 133 | } 134 | } else { 135 | if (success) { 136 | dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{ 137 | success(self, responseObject); 138 | }); 139 | } 140 | } 141 | } 142 | 143 | if (self.completionGroup) { 144 | dispatch_group_leave(self.completionGroup); 145 | } 146 | }); 147 | }; 148 | #pragma clang diagnostic pop 149 | } 150 | 151 | #pragma mark - AFURLRequestOperation 152 | 153 | - (void)pause { 154 | [super pause]; 155 | 156 | u_int64_t offset = 0; 157 | if ([self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey]) { 158 | offset = [(NSNumber *)[self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey] unsignedLongLongValue]; 159 | } else { 160 | offset = [(NSData *)[self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey] length]; 161 | } 162 | 163 | NSMutableURLRequest *mutableURLRequest = [self.request mutableCopy]; 164 | if ([self.response respondsToSelector:@selector(allHeaderFields)] && [[self.response allHeaderFields] valueForKey:@"ETag"]) { 165 | [mutableURLRequest setValue:[[self.response allHeaderFields] valueForKey:@"ETag"] forHTTPHeaderField:@"If-Range"]; 166 | } 167 | [mutableURLRequest setValue:[NSString stringWithFormat:@"bytes=%llu-", offset] forHTTPHeaderField:@"Range"]; 168 | self.request = mutableURLRequest; 169 | } 170 | 171 | #pragma mark - NSSecureCoding 172 | 173 | + (BOOL)supportsSecureCoding { 174 | return YES; 175 | } 176 | 177 | - (id)initWithCoder:(NSCoder *)decoder { 178 | self = [super initWithCoder:decoder]; 179 | if (!self) { 180 | return nil; 181 | } 182 | 183 | self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))]; 184 | 185 | return self; 186 | } 187 | 188 | - (void)encodeWithCoder:(NSCoder *)coder { 189 | [super encodeWithCoder:coder]; 190 | 191 | [coder encodeObject:self.responseSerializer forKey:NSStringFromSelector(@selector(responseSerializer))]; 192 | } 193 | 194 | #pragma mark - NSCopying 195 | 196 | - (id)copyWithZone:(NSZone *)zone { 197 | AFHTTPRequestOperation *operation = [super copyWithZone:zone]; 198 | 199 | operation.responseSerializer = [self.responseSerializer copyWithZone:zone]; 200 | operation.completionQueue = self.completionQueue; 201 | operation.completionGroup = self.completionGroup; 202 | 203 | return operation; 204 | } 205 | 206 | @end 207 | -------------------------------------------------------------------------------- /CocoaControls/AFNetworking/AFNetworking/AFHTTPRequestOperationManager.m: -------------------------------------------------------------------------------- 1 | // AFHTTPRequestOperationManager.m 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #import 24 | 25 | #import "AFHTTPRequestOperationManager.h" 26 | #import "AFHTTPRequestOperation.h" 27 | 28 | #import 29 | #import 30 | 31 | #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) 32 | #import 33 | #endif 34 | 35 | @interface AFHTTPRequestOperationManager () 36 | @property (readwrite, nonatomic, strong) NSURL *baseURL; 37 | @end 38 | 39 | @implementation AFHTTPRequestOperationManager 40 | 41 | + (instancetype)manager { 42 | return [[self alloc] initWithBaseURL:nil]; 43 | } 44 | 45 | - (instancetype)init { 46 | return [self initWithBaseURL:nil]; 47 | } 48 | 49 | - (instancetype)initWithBaseURL:(NSURL *)url { 50 | self = [super init]; 51 | if (!self) { 52 | return nil; 53 | } 54 | 55 | // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected 56 | if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) { 57 | url = [url URLByAppendingPathComponent:@""]; 58 | } 59 | 60 | self.baseURL = url; 61 | 62 | self.requestSerializer = [AFHTTPRequestSerializer serializer]; 63 | self.responseSerializer = [AFJSONResponseSerializer serializer]; 64 | 65 | self.securityPolicy = [AFSecurityPolicy defaultPolicy]; 66 | 67 | self.reachabilityManager = [AFNetworkReachabilityManager sharedManager]; 68 | 69 | self.operationQueue = [[NSOperationQueue alloc] init]; 70 | 71 | self.shouldUseCredentialStorage = YES; 72 | 73 | return self; 74 | } 75 | 76 | #pragma mark - 77 | 78 | #ifdef _SYSTEMCONFIGURATION_H 79 | #endif 80 | 81 | - (void)setRequestSerializer:(AFHTTPRequestSerializer *)requestSerializer { 82 | NSParameterAssert(requestSerializer); 83 | 84 | _requestSerializer = requestSerializer; 85 | } 86 | 87 | - (void)setResponseSerializer:(AFHTTPResponseSerializer *)responseSerializer { 88 | NSParameterAssert(responseSerializer); 89 | 90 | _responseSerializer = responseSerializer; 91 | } 92 | 93 | #pragma mark - 94 | 95 | - (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)request 96 | success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 97 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 98 | { 99 | AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 100 | operation.responseSerializer = self.responseSerializer; 101 | operation.shouldUseCredentialStorage = self.shouldUseCredentialStorage; 102 | operation.credential = self.credential; 103 | operation.securityPolicy = self.securityPolicy; 104 | 105 | [operation setCompletionBlockWithSuccess:success failure:failure]; 106 | operation.completionQueue = self.completionQueue; 107 | operation.completionGroup = self.completionGroup; 108 | 109 | return operation; 110 | } 111 | 112 | #pragma mark - 113 | 114 | - (AFHTTPRequestOperation *)GET:(NSString *)URLString 115 | parameters:(id)parameters 116 | success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 117 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 118 | { 119 | NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"GET" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; 120 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; 121 | 122 | [self.operationQueue addOperation:operation]; 123 | 124 | return operation; 125 | } 126 | 127 | - (AFHTTPRequestOperation *)HEAD:(NSString *)URLString 128 | parameters:(id)parameters 129 | success:(void (^)(AFHTTPRequestOperation *operation))success 130 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 131 | { 132 | NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"HEAD" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; 133 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *requestOperation, __unused id responseObject) { 134 | if (success) { 135 | success(requestOperation); 136 | } 137 | } failure:failure]; 138 | 139 | [self.operationQueue addOperation:operation]; 140 | 141 | return operation; 142 | } 143 | 144 | - (AFHTTPRequestOperation *)POST:(NSString *)URLString 145 | parameters:(id)parameters 146 | success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 147 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 148 | { 149 | NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; 150 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; 151 | 152 | [self.operationQueue addOperation:operation]; 153 | 154 | return operation; 155 | } 156 | 157 | - (AFHTTPRequestOperation *)POST:(NSString *)URLString 158 | parameters:(id)parameters 159 | constructingBodyWithBlock:(void (^)(id formData))block 160 | success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 161 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 162 | { 163 | NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:nil]; 164 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; 165 | 166 | [self.operationQueue addOperation:operation]; 167 | 168 | return operation; 169 | } 170 | 171 | - (AFHTTPRequestOperation *)PUT:(NSString *)URLString 172 | parameters:(id)parameters 173 | success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 174 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 175 | { 176 | NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"PUT" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; 177 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; 178 | 179 | [self.operationQueue addOperation:operation]; 180 | 181 | return operation; 182 | } 183 | 184 | - (AFHTTPRequestOperation *)PATCH:(NSString *)URLString 185 | parameters:(id)parameters 186 | success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 187 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 188 | { 189 | NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"PATCH" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; 190 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; 191 | 192 | [self.operationQueue addOperation:operation]; 193 | 194 | return operation; 195 | } 196 | 197 | - (AFHTTPRequestOperation *)DELETE:(NSString *)URLString 198 | parameters:(id)parameters 199 | success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 200 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 201 | { 202 | NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"DELETE" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; 203 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; 204 | 205 | [self.operationQueue addOperation:operation]; 206 | 207 | return operation; 208 | } 209 | 210 | #pragma mark - NSObject 211 | 212 | - (NSString *)description { 213 | return [NSString stringWithFormat:@"<%@: %p, baseURL: %@, operationQueue: %@>", NSStringFromClass([self class]), self, [self.baseURL absoluteString], self.operationQueue]; 214 | } 215 | 216 | #pragma mark - NSSecureCoding 217 | 218 | + (BOOL)supportsSecureCoding { 219 | return YES; 220 | } 221 | 222 | - (id)initWithCoder:(NSCoder *)decoder { 223 | NSURL *baseURL = [decoder decodeObjectForKey:NSStringFromSelector(@selector(baseURL))]; 224 | 225 | self = [self initWithBaseURL:baseURL]; 226 | if (!self) { 227 | return nil; 228 | } 229 | 230 | self.requestSerializer = [decoder decodeObjectOfClass:[AFHTTPRequestSerializer class] forKey:NSStringFromSelector(@selector(requestSerializer))]; 231 | self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))]; 232 | 233 | return self; 234 | } 235 | 236 | - (void)encodeWithCoder:(NSCoder *)coder { 237 | [coder encodeObject:self.baseURL forKey:NSStringFromSelector(@selector(baseURL))]; 238 | [coder encodeObject:self.requestSerializer forKey:NSStringFromSelector(@selector(requestSerializer))]; 239 | [coder encodeObject:self.responseSerializer forKey:NSStringFromSelector(@selector(responseSerializer))]; 240 | } 241 | 242 | #pragma mark - NSCopying 243 | 244 | - (id)copyWithZone:(NSZone *)zone { 245 | AFHTTPRequestOperationManager *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL]; 246 | 247 | HTTPClient.requestSerializer = [self.requestSerializer copyWithZone:zone]; 248 | HTTPClient.responseSerializer = [self.responseSerializer copyWithZone:zone]; 249 | 250 | return HTTPClient; 251 | } 252 | 253 | @end 254 | -------------------------------------------------------------------------------- /CocoaControls/AFNetworking/AFNetworking/AFNetworkReachabilityManager.h: -------------------------------------------------------------------------------- 1 | // AFNetworkReachabilityManager.h 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #import 24 | #import 25 | 26 | typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) { 27 | AFNetworkReachabilityStatusUnknown = -1, 28 | AFNetworkReachabilityStatusNotReachable = 0, 29 | AFNetworkReachabilityStatusReachableViaWWAN = 1, 30 | AFNetworkReachabilityStatusReachableViaWiFi = 2, 31 | }; 32 | 33 | /** 34 | `AFNetworkReachabilityManager` monitors the reachability of domains, and addresses for both WWAN and WiFi network interfaces. 35 | 36 | Reachability can be used to determine background information about why a network operation failed, or to trigger a network operation retrying when a connection is established. It should not be used to prevent a user from initiating a network request, as it's possible that an initial request may be required to establish reachability. 37 | 38 | See Apple's Reachability Sample Code (https://developer.apple.com/library/ios/samplecode/reachability/) 39 | 40 | @warning Instances of `AFNetworkReachabilityManager` must be started with `-startMonitoring` before reachability status can be determined. 41 | */ 42 | @interface AFNetworkReachabilityManager : NSObject 43 | 44 | /** 45 | The current network reachability status. 46 | */ 47 | @property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; 48 | 49 | /** 50 | Whether or not the network is currently reachable. 51 | */ 52 | @property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable; 53 | 54 | /** 55 | Whether or not the network is currently reachable via WWAN. 56 | */ 57 | @property (readonly, nonatomic, assign, getter = isReachableViaWWAN) BOOL reachableViaWWAN; 58 | 59 | /** 60 | Whether or not the network is currently reachable via WiFi. 61 | */ 62 | @property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi; 63 | 64 | ///--------------------- 65 | /// @name Initialization 66 | ///--------------------- 67 | 68 | /** 69 | Returns the shared network reachability manager. 70 | */ 71 | + (instancetype)sharedManager; 72 | 73 | /** 74 | Creates and returns a network reachability manager for the specified domain. 75 | 76 | @param domain The domain used to evaluate network reachability. 77 | 78 | @return An initialized network reachability manager, actively monitoring the specified domain. 79 | */ 80 | + (instancetype)managerForDomain:(NSString *)domain; 81 | 82 | /** 83 | Creates and returns a network reachability manager for the socket address. 84 | 85 | @param address The socket address (`sockaddr_in`) used to evaluate network reachability. 86 | 87 | @return An initialized network reachability manager, actively monitoring the specified socket address. 88 | */ 89 | + (instancetype)managerForAddress:(const void *)address; 90 | 91 | /** 92 | Initializes an instance of a network reachability manager from the specified reachability object. 93 | 94 | @param reachability The reachability object to monitor. 95 | 96 | @return An initialized network reachability manager, actively monitoring the specified reachability. 97 | */ 98 | - (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability; 99 | 100 | ///-------------------------------------------------- 101 | /// @name Starting & Stopping Reachability Monitoring 102 | ///-------------------------------------------------- 103 | 104 | /** 105 | Starts monitoring for changes in network reachability status. 106 | */ 107 | - (void)startMonitoring; 108 | 109 | /** 110 | Stops monitoring for changes in network reachability status. 111 | */ 112 | - (void)stopMonitoring; 113 | 114 | ///------------------------------------------------- 115 | /// @name Getting Localized Reachability Description 116 | ///------------------------------------------------- 117 | 118 | /** 119 | Returns a localized string representation of the current network reachability status. 120 | */ 121 | - (NSString *)localizedNetworkReachabilityStatusString; 122 | 123 | ///--------------------------------------------------- 124 | /// @name Setting Network Reachability Change Callback 125 | ///--------------------------------------------------- 126 | 127 | /** 128 | Sets a callback to be executed when the network availability of the `baseURL` host changes. 129 | 130 | @param block A block object to be executed when the network availability of the `baseURL` host changes.. This block has no return value and takes a single argument which represents the various reachability states from the device to the `baseURL`. 131 | */ 132 | - (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block; 133 | 134 | @end 135 | 136 | ///---------------- 137 | /// @name Constants 138 | ///---------------- 139 | 140 | /** 141 | ## Network Reachability 142 | 143 | The following constants are provided by `AFNetworkReachabilityManager` as possible network reachability statuses. 144 | 145 | enum { 146 | AFNetworkReachabilityStatusUnknown, 147 | AFNetworkReachabilityStatusNotReachable, 148 | AFNetworkReachabilityStatusReachableViaWWAN, 149 | AFNetworkReachabilityStatusReachableViaWiFi, 150 | } 151 | 152 | `AFNetworkReachabilityStatusUnknown` 153 | The `baseURL` host reachability is not known. 154 | 155 | `AFNetworkReachabilityStatusNotReachable` 156 | The `baseURL` host cannot be reached. 157 | 158 | `AFNetworkReachabilityStatusReachableViaWWAN` 159 | The `baseURL` host can be reached via a cellular connection, such as EDGE or GPRS. 160 | 161 | `AFNetworkReachabilityStatusReachableViaWiFi` 162 | The `baseURL` host can be reached via a Wi-Fi connection. 163 | 164 | ### Keys for Notification UserInfo Dictionary 165 | 166 | Strings that are used as keys in a `userInfo` dictionary in a network reachability status change notification. 167 | 168 | `AFNetworkingReachabilityNotificationStatusItem` 169 | A key in the userInfo dictionary in a `AFNetworkingReachabilityDidChangeNotification` notification. 170 | The corresponding value is an `NSNumber` object representing the `AFNetworkReachabilityStatus` value for the current reachability status. 171 | */ 172 | 173 | ///-------------------- 174 | /// @name Notifications 175 | ///-------------------- 176 | 177 | /** 178 | Posted when network reachability changes. 179 | This notification assigns no notification object. The `userInfo` dictionary contains an `NSNumber` object under the `AFNetworkingReachabilityNotificationStatusItem` key, representing the `AFNetworkReachabilityStatus` value for the current network reachability. 180 | 181 | @warning In order for network reachability to be monitored, include the `SystemConfiguration` framework in the active target's "Link Binary With Library" build phase, and add `#import ` to the header prefix of the project (`Prefix.pch`). 182 | */ 183 | extern NSString * const AFNetworkingReachabilityDidChangeNotification; 184 | extern NSString * const AFNetworkingReachabilityNotificationStatusItem; 185 | 186 | ///-------------------- 187 | /// @name Functions 188 | ///-------------------- 189 | 190 | /** 191 | Returns a localized string representation of an `AFNetworkReachabilityStatus` value. 192 | */ 193 | extern NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status); 194 | -------------------------------------------------------------------------------- /CocoaControls/AFNetworking/AFNetworking/AFNetworkReachabilityManager.m: -------------------------------------------------------------------------------- 1 | // AFNetworkReachabilityManager.m 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #import "AFNetworkReachabilityManager.h" 24 | 25 | #import 26 | #import 27 | #import 28 | #import 29 | #import 30 | 31 | NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change"; 32 | NSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworkingReachabilityNotificationStatusItem"; 33 | 34 | typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status); 35 | 36 | typedef NS_ENUM(NSUInteger, AFNetworkReachabilityAssociation) { 37 | AFNetworkReachabilityForAddress = 1, 38 | AFNetworkReachabilityForAddressPair = 2, 39 | AFNetworkReachabilityForName = 3, 40 | }; 41 | 42 | NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status) { 43 | switch (status) { 44 | case AFNetworkReachabilityStatusNotReachable: 45 | return NSLocalizedStringFromTable(@"Not Reachable", @"AFNetworking", nil); 46 | case AFNetworkReachabilityStatusReachableViaWWAN: 47 | return NSLocalizedStringFromTable(@"Reachable via WWAN", @"AFNetworking", nil); 48 | case AFNetworkReachabilityStatusReachableViaWiFi: 49 | return NSLocalizedStringFromTable(@"Reachable via WiFi", @"AFNetworking", nil); 50 | case AFNetworkReachabilityStatusUnknown: 51 | default: 52 | return NSLocalizedStringFromTable(@"Unknown", @"AFNetworking", nil); 53 | } 54 | } 55 | 56 | static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) { 57 | BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0); 58 | BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0); 59 | BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)); 60 | BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0); 61 | BOOL isNetworkReachable = (isReachable && (!needsConnection || canConnectWithoutUserInteraction)); 62 | 63 | AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown; 64 | if (isNetworkReachable == NO) { 65 | status = AFNetworkReachabilityStatusNotReachable; 66 | } 67 | #if TARGET_OS_IPHONE 68 | else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) { 69 | status = AFNetworkReachabilityStatusReachableViaWWAN; 70 | } 71 | #endif 72 | else { 73 | status = AFNetworkReachabilityStatusReachableViaWiFi; 74 | } 75 | 76 | return status; 77 | } 78 | 79 | static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) { 80 | AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags); 81 | AFNetworkReachabilityStatusBlock block = (__bridge AFNetworkReachabilityStatusBlock)info; 82 | if (block) { 83 | block(status); 84 | } 85 | 86 | 87 | dispatch_async(dispatch_get_main_queue(), ^{ 88 | NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 89 | [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:@{ AFNetworkingReachabilityNotificationStatusItem: @(status) }]; 90 | }); 91 | 92 | } 93 | 94 | static const void * AFNetworkReachabilityRetainCallback(const void *info) { 95 | return Block_copy(info); 96 | } 97 | 98 | static void AFNetworkReachabilityReleaseCallback(const void *info) { 99 | if (info) { 100 | Block_release(info); 101 | } 102 | } 103 | 104 | @interface AFNetworkReachabilityManager () 105 | @property (readwrite, nonatomic, assign) SCNetworkReachabilityRef networkReachability; 106 | @property (readwrite, nonatomic, assign) AFNetworkReachabilityAssociation networkReachabilityAssociation; 107 | @property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; 108 | @property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock; 109 | @end 110 | 111 | @implementation AFNetworkReachabilityManager 112 | 113 | + (instancetype)sharedManager { 114 | static AFNetworkReachabilityManager *_sharedManager = nil; 115 | static dispatch_once_t onceToken; 116 | dispatch_once(&onceToken, ^{ 117 | struct sockaddr_in address; 118 | bzero(&address, sizeof(address)); 119 | address.sin_len = sizeof(address); 120 | address.sin_family = AF_INET; 121 | 122 | _sharedManager = [self managerForAddress:&address]; 123 | }); 124 | 125 | return _sharedManager; 126 | } 127 | 128 | + (instancetype)managerForDomain:(NSString *)domain { 129 | SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]); 130 | 131 | AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability]; 132 | manager.networkReachabilityAssociation = AFNetworkReachabilityForName; 133 | 134 | return manager; 135 | } 136 | 137 | + (instancetype)managerForAddress:(const void *)address { 138 | SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address); 139 | 140 | AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability]; 141 | manager.networkReachabilityAssociation = AFNetworkReachabilityForAddress; 142 | 143 | return manager; 144 | } 145 | 146 | - (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability { 147 | self = [super init]; 148 | if (!self) { 149 | return nil; 150 | } 151 | 152 | self.networkReachability = reachability; 153 | self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown; 154 | 155 | return self; 156 | } 157 | 158 | - (void)dealloc { 159 | [self stopMonitoring]; 160 | 161 | if (_networkReachability) { 162 | CFRelease(_networkReachability); 163 | _networkReachability = NULL; 164 | } 165 | } 166 | 167 | #pragma mark - 168 | 169 | - (BOOL)isReachable { 170 | return [self isReachableViaWWAN] || [self isReachableViaWiFi]; 171 | } 172 | 173 | - (BOOL)isReachableViaWWAN { 174 | return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN; 175 | } 176 | 177 | - (BOOL)isReachableViaWiFi { 178 | return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi; 179 | } 180 | 181 | #pragma mark - 182 | 183 | - (void)startMonitoring { 184 | [self stopMonitoring]; 185 | 186 | if (!self.networkReachability) { 187 | return; 188 | } 189 | 190 | __weak __typeof(self)weakSelf = self; 191 | AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) { 192 | __strong __typeof(weakSelf)strongSelf = weakSelf; 193 | 194 | strongSelf.networkReachabilityStatus = status; 195 | if (strongSelf.networkReachabilityStatusBlock) { 196 | strongSelf.networkReachabilityStatusBlock(status); 197 | } 198 | 199 | }; 200 | 201 | SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL}; 202 | SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context); 203 | SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); 204 | 205 | switch (self.networkReachabilityAssociation) { 206 | case AFNetworkReachabilityForName: 207 | break; 208 | case AFNetworkReachabilityForAddress: 209 | case AFNetworkReachabilityForAddressPair: 210 | default: { 211 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{ 212 | SCNetworkReachabilityFlags flags; 213 | SCNetworkReachabilityGetFlags(self.networkReachability, &flags); 214 | AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags); 215 | dispatch_async(dispatch_get_main_queue(), ^{ 216 | callback(status); 217 | 218 | NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 219 | [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:@{ AFNetworkingReachabilityNotificationStatusItem: @(status) }]; 220 | 221 | 222 | }); 223 | }); 224 | } 225 | break; 226 | } 227 | } 228 | 229 | - (void)stopMonitoring { 230 | if (!self.networkReachability) { 231 | return; 232 | } 233 | 234 | SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); 235 | } 236 | 237 | #pragma mark - 238 | 239 | - (NSString *)localizedNetworkReachabilityStatusString { 240 | return AFStringFromNetworkReachabilityStatus(self.networkReachabilityStatus); 241 | } 242 | 243 | #pragma mark - 244 | 245 | - (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block { 246 | self.networkReachabilityStatusBlock = block; 247 | } 248 | 249 | #pragma mark - NSKeyValueObserving 250 | 251 | + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { 252 | if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) { 253 | return [NSSet setWithObject:@"networkReachabilityStatus"]; 254 | } 255 | 256 | return [super keyPathsForValuesAffectingValueForKey:key]; 257 | } 258 | 259 | @end 260 | -------------------------------------------------------------------------------- /CocoaControls/AFNetworking/AFNetworking/AFNetworking.h: -------------------------------------------------------------------------------- 1 | // AFNetworking.h 2 | // 3 | // Copyright (c) 2013 AFNetworking (http://afnetworking.com/) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #import 24 | #import 25 | 26 | #ifndef _AFNETWORKING_ 27 | #define _AFNETWORKING_ 28 | 29 | #import "AFURLRequestSerialization.h" 30 | #import "AFURLResponseSerialization.h" 31 | #import "AFSecurityPolicy.h" 32 | #import "AFNetworkReachabilityManager.h" 33 | 34 | #import "AFURLConnectionOperation.h" 35 | #import "AFHTTPRequestOperation.h" 36 | #import "AFHTTPRequestOperationManager.h" 37 | 38 | #if ( ( defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) || \ 39 | ( defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 ) ) 40 | #import "AFURLSessionManager.h" 41 | #import "AFHTTPSessionManager.h" 42 | #endif 43 | 44 | #endif /* _AFNETWORKING_ */ 45 | -------------------------------------------------------------------------------- /CocoaControls/AFNetworking/AFNetworking/AFSecurityPolicy.h: -------------------------------------------------------------------------------- 1 | // AFSecurity.h 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 13 | // all 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 21 | // THE SOFTWARE. 22 | 23 | #import 24 | #import 25 | 26 | typedef NS_ENUM(NSUInteger, AFSSLPinningMode) { 27 | AFSSLPinningModeNone, 28 | AFSSLPinningModePublicKey, 29 | AFSSLPinningModeCertificate, 30 | }; 31 | 32 | /** 33 | `AFSecurityPolicy` evaluates server trust against pinned X.509 certificates and public keys over secure connections. 34 | 35 | Adding pinned SSL certificates to your app helps prevent man-in-the-middle attacks and other vulnerabilities. Applications dealing with sensitive customer data or financial information are strongly encouraged to route all communication over an HTTPS connection with SSL pinning configured and enabled. 36 | */ 37 | @interface AFSecurityPolicy : NSObject 38 | 39 | /** 40 | The criteria by which server trust should be evaluated against the pinned SSL certificates. Defaults to `AFSSLPinningModeNone`. 41 | */ 42 | @property (nonatomic, assign) AFSSLPinningMode SSLPinningMode; 43 | 44 | /** 45 | Whether to evaluate an entire SSL certificate chain, or just the leaf certificate. Defaults to `YES`. 46 | */ 47 | @property (nonatomic, assign) BOOL validatesCertificateChain; 48 | 49 | /** 50 | The certificates used to evaluate server trust according to the SSL pinning mode. By default, this property is set to any (`.cer`) certificates included in the app bundle. 51 | */ 52 | @property (nonatomic, strong) NSArray *pinnedCertificates; 53 | 54 | /** 55 | Whether or not to trust servers with an invalid or expired SSL certificates. Defaults to `NO`. 56 | */ 57 | @property (nonatomic, assign) BOOL allowInvalidCertificates; 58 | 59 | /** 60 | Whether or not to validate the domain name in the certificates CN field. Defaults to `YES` for `AFSSLPinningModePublicKey` or `AFSSLPinningModeCertificate`, otherwise `NO`. 61 | */ 62 | @property (nonatomic, assign) BOOL validatesDomainName; 63 | 64 | ///----------------------------------------- 65 | /// @name Getting Specific Security Policies 66 | ///----------------------------------------- 67 | 68 | /** 69 | Returns the shared default security policy, which does not accept invalid certificates, and does not validate against pinned certificates or public keys. 70 | 71 | @return The default security policy. 72 | */ 73 | + (instancetype)defaultPolicy; 74 | 75 | ///--------------------- 76 | /// @name Initialization 77 | ///--------------------- 78 | 79 | /** 80 | Creates and returns a security policy with the specified pinning mode. 81 | 82 | @param pinningMode The SSL pinning mode. 83 | 84 | @return A new security policy. 85 | */ 86 | + (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode; 87 | 88 | ///------------------------------ 89 | /// @name Evaluating Server Trust 90 | ///------------------------------ 91 | 92 | /** 93 | Whether or not the specified server trust should be accepted, based on the security policy. 94 | 95 | This method should be used when responding to an authentication challenge from a server. 96 | 97 | @param serverTrust The X.509 certificate trust of the server. 98 | 99 | @return Whether or not to trust the server. 100 | 101 | @warning This method has been deprecated in favor of `-evaluateServerTrust:forDomain:`. 102 | */ 103 | - (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust DEPRECATED_ATTRIBUTE; 104 | 105 | /** 106 | Whether or not the specified server trust should be accepted, based on the security policy. 107 | 108 | This method should be used when responding to an authentication challenge from a server. 109 | 110 | @param serverTrust The X.509 certificate trust of the server. 111 | @param domain The domain of serverTrust. If `nil`, the domain will not be validated. 112 | 113 | @return Whether or not to trust the server. 114 | */ 115 | - (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust 116 | forDomain:(NSString *)domain; 117 | 118 | @end 119 | 120 | ///---------------- 121 | /// @name Constants 122 | ///---------------- 123 | 124 | /** 125 | ## SSL Pinning Modes 126 | 127 | The following constants are provided by `AFSSLPinningMode` as possible SSL pinning modes. 128 | 129 | enum { 130 | AFSSLPinningModeNone, 131 | AFSSLPinningModePublicKey, 132 | AFSSLPinningModeCertificate, 133 | } 134 | 135 | `AFSSLPinningModeNone` 136 | Do not used pinned certificates to validate servers. 137 | 138 | `AFSSLPinningModePublicKey` 139 | Validate host certificates against public keys of pinned certificates. 140 | 141 | `AFSSLPinningModeCertificate` 142 | Validate host certificates against pinned certificates. 143 | */ 144 | -------------------------------------------------------------------------------- /CocoaControls/AFNetworking/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com/) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /CocoaControls/CocoaControls-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSHumanReadableCopyright 28 | Copyright © 2012-2014 P.D.Q. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | NSAppTransportSecurity 34 | 35 | NSAllowsArbitraryLoads 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /CocoaControls/CocoaControls-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #import "RSCCCore.h" 10 | #define CORE [RSCCCore sharedCore] 11 | #endif 12 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/ITPullToRefreshScrollView/Classes/DuxScrollViewAnimation.h: -------------------------------------------------------------------------------- 1 | // 2 | // DuxScrollViewAnimation.h 3 | // Dux 4 | // 5 | // Created by Abhi Beckert on 2011-11-30. 6 | // 7 | // This is free and unencumbered software released into the public domain. 8 | // For more information, please refer to 9 | // 10 | 11 | #import 12 | 13 | @interface DuxScrollViewAnimation : NSAnimation 14 | 15 | @property (retain) NSScrollView *scrollView; 16 | @property NSPoint originPoint; 17 | @property NSPoint targetPoint; 18 | 19 | + (void)animatedScrollPointToCenter:(NSPoint)targetPoint inScrollView:(NSScrollView *)scrollView; 20 | + (void)animatedScrollToPoint:(NSPoint)targetPoint inScrollView:(NSScrollView *)scrollView; 21 | + (void)animatedScrollToPoint:(NSPoint)targetPoint inScrollView:(NSScrollView *)scrollView delegate:(id)delegate; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/ITPullToRefreshScrollView/Classes/DuxScrollViewAnimation.m: -------------------------------------------------------------------------------- 1 | // 2 | // DuxScrollViewAnimation.m 3 | // Dux 4 | // 5 | // Created by Abhi Beckert on 2011-11-30. 6 | // 7 | // This is free and unencumbered software released into the public domain. 8 | // For more information, please refer to 9 | // 10 | 11 | #import "DuxScrollViewAnimation.h" 12 | 13 | @implementation DuxScrollViewAnimation 14 | 15 | @synthesize scrollView; 16 | @synthesize originPoint; 17 | @synthesize targetPoint; 18 | 19 | + (void)animatedScrollPointToCenter:(NSPoint)targetPoint inScrollView:(NSScrollView *)scrollView 20 | { 21 | NSRect visibleRect = scrollView.documentVisibleRect; 22 | 23 | targetPoint = NSMakePoint(targetPoint.x - (NSWidth(visibleRect) / 2), targetPoint.y - (NSHeight(visibleRect) / 2)); 24 | 25 | [self animatedScrollToPoint:targetPoint inScrollView:scrollView]; 26 | } 27 | 28 | + (void)animatedScrollToPoint:(NSPoint)targetPoint inScrollView:(NSScrollView *)scrollView { 29 | [self animatedScrollToPoint:targetPoint inScrollView:scrollView delegate:nil]; 30 | } 31 | 32 | + (void)animatedScrollToPoint:(NSPoint)targetPoint inScrollView:(NSScrollView *)scrollView delegate:(id)delegate; 33 | { 34 | DuxScrollViewAnimation *animation = [[DuxScrollViewAnimation alloc] initWithDuration:0.2 animationCurve:NSAnimationEaseInOut]; 35 | 36 | animation.delegate = delegate; 37 | animation.scrollView = scrollView; 38 | animation.originPoint = scrollView.documentVisibleRect.origin; 39 | animation.targetPoint = targetPoint; 40 | 41 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 42 | [animation startAnimation]; 43 | }); 44 | } 45 | 46 | - (void)setCurrentProgress:(NSAnimationProgress)progress 47 | { 48 | typedef float (^MyAnimationCurveBlock)(float, float, float); 49 | MyAnimationCurveBlock cubicEaseInOut = ^ float (float t, float start, float end) { 50 | t *= 2.; 51 | if (t < 1.) return end/2 * t * t * t + start - 1.f; 52 | t -= 2; 53 | return end/2*(t * t * t + 2) + start - 1.f; 54 | }; 55 | 56 | dispatch_sync(dispatch_get_main_queue(), ^{ 57 | NSPoint progressPoint = self.originPoint; 58 | progressPoint.x += cubicEaseInOut(progress, 0, self.targetPoint.x - self.originPoint.x); 59 | progressPoint.y += cubicEaseInOut(progress, 0, self.targetPoint.y - self.originPoint.y); 60 | 61 | [self.scrollView.documentView scrollPoint:progressPoint]; 62 | [self.scrollView displayIfNeeded]; 63 | }); 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/ITPullToRefreshScrollView/Classes/ITPullToRefreshClipView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ITPullToRefreshClipView.h 3 | // ITPullToRefreshScrollView 4 | // 5 | // Created by Ilija Tovilo on 9/25/13. 6 | // Copyright (c) 2013 Ilija Tovilo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * This class is used by `ITPullToRefreshScrollView`. 13 | * You don't need to interact with it directly. 14 | */ 15 | @interface ITPullToRefreshClipView : NSClipView 16 | @end 17 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/ITPullToRefreshScrollView/Classes/ITPullToRefreshClipView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ITPullToRefreshClipView.m 3 | // ITPullToRefreshScrollView 4 | // 5 | // Created by Ilija Tovilo on 9/25/13. 6 | // Copyright (c) 2013 Ilija Tovilo. All rights reserved. 7 | // 8 | 9 | #import "ITPullToRefreshClipView.h" 10 | #import "ITPullToRefreshScrollView.h" 11 | #import "ITPullToRefreshEdgeView.h" 12 | 13 | @implementation ITPullToRefreshClipView 14 | 15 | #pragma mark - Properties 16 | 17 | -(NSView *) headerView { return [(ITPullToRefreshScrollView *)self.superview edgeViewForEdge:ITPullToRefreshEdgeTop]; } 18 | -(NSView*) footerView { return [(ITPullToRefreshScrollView *)self.superview edgeViewForEdge:ITPullToRefreshEdgeBottom]; } 19 | -(NSUInteger)refreshingSides { return [(ITPullToRefreshScrollView *)self.superview refreshingEdges]; } 20 | 21 | 22 | #pragma mark - NSClipView 23 | 24 | - (NSPoint)constrainScrollPoint:(NSPoint)proposedNewOrigin 25 | { 26 | NSPoint constrained = [super constrainScrollPoint:proposedNewOrigin]; 27 | const NSRect clipViewBounds = self.bounds; 28 | NSView* const documentView = self.documentView; 29 | const NSRect documentFrame = documentView.frame; 30 | 31 | const NSUInteger refreshingSides = [self refreshingSides]; 32 | 33 | if (refreshingSides & ITPullToRefreshEdgeTop && proposedNewOrigin.y <= 0) { 34 | const NSRect headerFrame = [self headerView].frame; 35 | constrained.y = MAX(-headerFrame.size.height, proposedNewOrigin.y); 36 | } 37 | 38 | if((refreshingSides & ITPullToRefreshEdgeBottom) ) { 39 | const NSRect footerFrame = [self footerView].frame; 40 | if (proposedNewOrigin.y > documentFrame.size.height - clipViewBounds.size.height) { 41 | const CGFloat maxHeight = documentFrame.size.height - clipViewBounds.size.height + footerFrame.size.height + 1; 42 | constrained.y = MIN(maxHeight, proposedNewOrigin.y); 43 | } 44 | } 45 | 46 | return constrained; 47 | } 48 | 49 | -(NSRect)documentRect 50 | { 51 | NSRect documentRect = [super documentRect]; 52 | 53 | const NSUInteger refreshingSides = [self refreshingSides]; 54 | 55 | if (refreshingSides & ITPullToRefreshEdgeTop) { 56 | const NSRect headerFrame = [self headerView].frame; 57 | documentRect.size.height += headerFrame.size.height; 58 | documentRect.origin.y -= headerFrame.size.height; 59 | } 60 | 61 | if(refreshingSides & ITPullToRefreshEdgeBottom) { 62 | const NSRect footerFrame = [self footerView].frame; 63 | documentRect.size.height += footerFrame.size.height ; 64 | } 65 | 66 | return documentRect; 67 | } 68 | 69 | 70 | #pragma mark - NSView 71 | 72 | -(BOOL)isFlipped 73 | { 74 | return YES; 75 | } 76 | 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/ITPullToRefreshScrollView/Classes/ITPullToRefreshEdgeView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ITPullToRefreshEdgeView.h 3 | // ITPullToRefreshScrollView 4 | // 5 | // Created by Ilija Tovilo on 9/25/13. 6 | // Copyright (c) 2013 Ilija Tovilo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ITPullToRefreshScrollView.h" 11 | 12 | /** 13 | * This view is used by the `ITPullToRefreshScrollView` to display the edges. 14 | * You can extend from this class to create custom edges. 15 | */ 16 | @interface ITPullToRefreshEdgeView : NSView 17 | 18 | /** 19 | * Use this method to initialise an edge view 20 | * 21 | * @param edge - The edge which will the edge view be used for 22 | * 23 | * @return A new instance of `ITPullToRefreshEdgeView` 24 | */ 25 | - (instancetype)initWithEdge:(ITPullToRefreshEdge)edge; 26 | 27 | 28 | 29 | // -------------------------- 30 | // ------------------- Events 31 | // -------------------------- 32 | 33 | /** 34 | * This method is called when the edge is triggered 35 | * 36 | * @param scrollView - The sender scroll view 37 | */ 38 | - (void)pullToRefreshScrollViewDidTriggerRefresh:(ITPullToRefreshScrollView *)scrollView; 39 | 40 | /** 41 | * This method is called when the edge is untriggered 42 | * 43 | * @param scrollView - The sender scroll view 44 | */ 45 | - (void)pullToRefreshScrollViewDidUntriggerRefresh:(ITPullToRefreshScrollView *)scrollView; 46 | 47 | /** 48 | * This method is called when the edge starts refreshing 49 | * 50 | * @param scrollView - The sender scroll view 51 | */ 52 | - (void)pullToRefreshScrollViewDidStartRefreshing:(ITPullToRefreshScrollView *)scrollView; 53 | 54 | /** 55 | * This method is called when the edge stops refreshing 56 | * 57 | * @param scrollView - The sender scroll view 58 | */ 59 | - (void)pullToRefreshScrollViewDidStopRefreshing:(ITPullToRefreshScrollView *)scrollView; 60 | 61 | /** 62 | * This is the final method called when the scroll view stopped animating 63 | * 64 | * @param scrollView - The sender scroll view 65 | */ 66 | - (void)pullToRefreshScrollViewDidStopAnimating:(ITPullToRefreshScrollView *)scrollView; 67 | 68 | /** 69 | * This method is called when part of the edge view becomes visible 70 | * 71 | * @param scrollView - The sender scroll view 72 | * @param progress - The amount of the edge view that is visible (from 0.0 to 1.0) 73 | */ 74 | - (void)pullToRefreshScrollView:(ITPullToRefreshScrollView *)scrollView didScrollWithProgress:(CGFloat)progress; 75 | 76 | 77 | 78 | // -------------------------- 79 | // ------------ Customisation 80 | // -------------------------- 81 | 82 | /** 83 | * Override this to remove the progress indicator and create other components 84 | */ 85 | - (void)installComponents; 86 | 87 | /** 88 | * The height of the edge view. 89 | * Override this method to achieve a custom edge view height. 90 | * 91 | * @return The height of the edge view 92 | */ 93 | - (CGFloat)edgeViewHeight; 94 | 95 | @property ITPullToRefreshEdge edgeViewEdge; 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/ITPullToRefreshScrollView/Classes/ITPullToRefreshEdgeView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ITPullToRefreshEdgeView.m 3 | // ITPullToRefreshScrollView 4 | // 5 | // Created by Ilija Tovilo on 9/25/13. 6 | // Copyright (c) 2013 Ilija Tovilo. All rights reserved. 7 | // 8 | 9 | #import "ITPullToRefreshEdgeView.h" 10 | #import 11 | #import "ITProgressIndicator.h" 12 | #import "NSBKeyframeAnimation.h" 13 | 14 | #define kDefaultEdgeViewHeight 30 15 | #define kSpinnerSize 30 16 | 17 | #define kMinSpinAnimationDuration 2.0 18 | #define kMaxSpinAnimationDuration 8.0 19 | #define kSpringRange 0.4 20 | 21 | @interface ITPullToRefreshEdgeView () { 22 | CGFloat _cachedProgress; 23 | } 24 | @property (strong) ITProgressIndicator *progressIndicator; 25 | @end 26 | 27 | @implementation ITPullToRefreshEdgeView 28 | 29 | 30 | #pragma mark - Init 31 | 32 | - (instancetype)initWithEdge:(ITPullToRefreshEdge)edge { 33 | if (self = [super init]) { 34 | _edgeViewEdge = edge; 35 | [self installComponents]; 36 | } 37 | 38 | return self; 39 | } 40 | 41 | - (void)installComponents { 42 | self.progressIndicator = [[ITProgressIndicator alloc] initWithFrame:NSMakeRect(0, 0, kSpinnerSize, kSpinnerSize)]; 43 | 44 | [self.progressIndicator setWantsLayer:YES]; 45 | self.progressIndicator.animates = NO; 46 | self.progressIndicator.hideWhenStopped = NO; 47 | self.progressIndicator.isIndeterminate = NO; 48 | self.progressIndicator.progress = 0.0; 49 | self.progressIndicator.numberOfLines = 12; 50 | self.progressIndicator.widthOfLine = 2.0; 51 | self.progressIndicator.innerMargin = 5; 52 | self.progressIndicator.color = [NSColor colorWithDeviceWhite:0.4 alpha:1.0]; 53 | self.progressIndicator.layer.contentsGravity = kCAGravityCenter; 54 | [self.progressIndicator.layer setAnchorPoint:CGPointMake(0.5, 0.5)]; 55 | 56 | [self addSubview:self.progressIndicator]; 57 | 58 | 59 | // Install Layout Constraints 60 | { 61 | [self.progressIndicator setTranslatesAutoresizingMaskIntoConstraints:NO]; 62 | 63 | [self.progressIndicator addConstraint:[NSLayoutConstraint constraintWithItem:self.progressIndicator 64 | attribute:NSLayoutAttributeWidth 65 | relatedBy:NSLayoutRelationEqual 66 | toItem:nil 67 | attribute:NSLayoutAttributeNotAnAttribute 68 | multiplier:1 69 | constant:kSpinnerSize]]; 70 | [self.progressIndicator addConstraint:[NSLayoutConstraint constraintWithItem:self.progressIndicator 71 | attribute:NSLayoutAttributeHeight 72 | relatedBy:NSLayoutRelationEqual 73 | toItem:nil 74 | attribute:NSLayoutAttributeNotAnAttribute 75 | multiplier:1 76 | constant:kSpinnerSize]]; 77 | 78 | [self addConstraint:[NSLayoutConstraint constraintWithItem:self.progressIndicator 79 | attribute:NSLayoutAttributeCenterY 80 | relatedBy:0 81 | toItem:self 82 | attribute:NSLayoutAttributeCenterY 83 | multiplier:1 84 | constant:0]]; 85 | [self addConstraint:[NSLayoutConstraint constraintWithItem:self.progressIndicator 86 | attribute:NSLayoutAttributeCenterX 87 | relatedBy:0 88 | toItem:self 89 | attribute:NSLayoutAttributeCenterX 90 | multiplier:1 91 | constant:0]]; 92 | } 93 | } 94 | 95 | 96 | #pragma mark - Constraints 97 | 98 | - (void)viewDidMoveToSuperview { 99 | [self setUpConstraints]; 100 | } 101 | 102 | - (void)setUpConstraints { 103 | [self setTranslatesAutoresizingMaskIntoConstraints:NO]; 104 | 105 | [self addConstraint:[NSLayoutConstraint constraintWithItem:self 106 | attribute:NSLayoutAttributeHeight 107 | relatedBy:NSLayoutRelationEqual 108 | toItem:nil 109 | attribute:NSLayoutAttributeNotAnAttribute 110 | multiplier:1 111 | constant:[self edgeViewHeight]]]; 112 | 113 | [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self 114 | attribute:NSLayoutAttributeLeft 115 | relatedBy:NSLayoutRelationEqual 116 | toItem:self.superview 117 | attribute:NSLayoutAttributeLeft 118 | multiplier:1.0 119 | constant:0.0]]; 120 | [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self 121 | attribute:NSLayoutAttributeRight 122 | relatedBy:NSLayoutRelationEqual 123 | toItem:self.superview 124 | attribute:NSLayoutAttributeRight 125 | multiplier:1.0 126 | constant:0.0]]; 127 | 128 | if (self.edgeViewEdge & ITPullToRefreshEdgeTop) 129 | { 130 | [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self 131 | attribute:NSLayoutAttributeBottom 132 | relatedBy:NSLayoutRelationEqual 133 | toItem:[(NSClipView *)self.superview documentView] 134 | attribute:NSLayoutAttributeTop 135 | multiplier:1.0 136 | constant:0.0]]; 137 | } 138 | else if (self.edgeViewEdge & ITPullToRefreshEdgeBottom) 139 | { 140 | [self.superview addConstraint:[NSLayoutConstraint constraintWithItem:self 141 | attribute:NSLayoutAttributeTop 142 | relatedBy:NSLayoutRelationEqual 143 | toItem:[(NSClipView *)self.superview documentView] 144 | attribute:NSLayoutAttributeBottom 145 | multiplier:1.0 146 | constant:0.0]]; 147 | } 148 | } 149 | 150 | 151 | #pragma mark - Customisation Methods 152 | 153 | - (CGFloat)edgeViewHeight { 154 | return kDefaultEdgeViewHeight; 155 | } 156 | 157 | - (void)pullToRefreshScrollView:(ITPullToRefreshScrollView *)scrollView didScrollWithProgress:(CGFloat)progress { 158 | _cachedProgress = progress; 159 | 160 | if (progress < 1.0) { 161 | self.progressIndicator.isIndeterminate = NO; 162 | self.progressIndicator.progress = progress; 163 | } 164 | } 165 | 166 | - (void)pullToRefreshScrollViewDidTriggerRefresh:(ITPullToRefreshScrollView *)scrollView { 167 | self.progressIndicator.isIndeterminate = NO; 168 | self.progressIndicator.progress = 1.0; 169 | } 170 | 171 | - (void)pullToRefreshScrollViewDidUntriggerRefresh:(ITPullToRefreshScrollView *)scrollView { 172 | 173 | } 174 | 175 | - (void)pullToRefreshScrollViewDidStartRefreshing:(ITPullToRefreshScrollView *)scrollView { 176 | CGFloat tension = (_cachedProgress - 1.0 <= kSpringRange)?_cachedProgress - 1:kSpringRange; 177 | CGFloat duration = kMaxSpinAnimationDuration - ((kMaxSpinAnimationDuration - kMinSpinAnimationDuration) * (1.0 / kSpringRange * tension)); 178 | 179 | [self.progressIndicator.layer addAnimation:[self rotationAnimationWithDuration:duration] forKey:@"rotation"]; 180 | self.progressIndicator.isIndeterminate = YES; 181 | self.progressIndicator.animates = YES; 182 | } 183 | 184 | - (void)pullToRefreshScrollViewDidStopRefreshing:(ITPullToRefreshScrollView *)scrollView { 185 | self.progressIndicator.animates = NO; 186 | self.progressIndicator.isIndeterminate = NO; 187 | 188 | [self.progressIndicator.layer addAnimation:[self shrinkAnimation] forKey:@"shrink"]; 189 | } 190 | 191 | - (void)pullToRefreshScrollViewDidStopAnimating:(ITPullToRefreshScrollView *)scrollView { 192 | [self.progressIndicator.layer removeAnimationForKey:@"rotation"]; 193 | } 194 | 195 | - (CAAnimation *)shrinkAnimation { 196 | NSBKeyframeAnimation *animation = [NSBKeyframeAnimation animationWithKeyPath:@"transform.scale" 197 | duration:0.3 198 | startValue:1 199 | endValue:0.0 200 | function:NSBKeyframeAnimationFunctionEaseOutCubic]; 201 | 202 | return animation; 203 | } 204 | 205 | - (CAAnimation *)rotationAnimationWithDuration:(CGFloat)duration { 206 | NSBKeyframeAnimation *animation = [NSBKeyframeAnimation animationWithKeyPath:@"transform" 207 | duration:duration 208 | startValue:0 209 | endValue:-2 * M_PI 210 | function:NSBKeyframeAnimationFunctionEaseOutCubic]; 211 | 212 | [animation setValueFunction:[CAValueFunction functionWithName: kCAValueFunctionRotateZ]]; 213 | 214 | return animation; 215 | } 216 | 217 | @end 218 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/ITPullToRefreshScrollView/Classes/ITPullToRefreshScrollView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ITPullToRefreshScrollView.h 3 | // ITPullToRefreshScrollView 4 | // 5 | // Created by Ilija Tovilo on 9/25/13. 6 | // Copyright (c) 2013 Ilija Tovilo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #ifndef ITPullToRefreshScrollViewConsts 12 | #define ITPullToRefreshScrollViewConsts 13 | 14 | 15 | /** 16 | * Enum that defines the edges of the ITPullToRefreshScrollView that can be refreshed 17 | */ 18 | typedef NS_ENUM(NSUInteger, ITPullToRefreshEdge) { 19 | ITPullToRefreshEdgeNone = 0, 20 | ITPullToRefreshEdgeTop = 1, 21 | ITPullToRefreshEdgeBottom = 1 << 1 22 | }; 23 | 24 | #endif 25 | 26 | @class ITPullToRefreshScrollView; 27 | 28 | /** 29 | * The delegate of the scroll view must implement this protocol. 30 | */ 31 | @protocol ITPullToRefreshScrollViewDelegate 32 | 33 | @optional 34 | /** 35 | * This method get's invoked when the scroll view started refreshing 36 | * 37 | * @param scrollView - The scroll view that started refreshing 38 | * @param edge - The edge that started refreshing 39 | */ 40 | - (void)pullToRefreshView:(ITPullToRefreshScrollView *)scrollView 41 | didStartRefreshingEdge:(ITPullToRefreshEdge)edge; 42 | 43 | /** 44 | * This method get's invoked when the scroll view stopped refreshing 45 | * 46 | * @param scrollView - The scroll view that stopped refreshing 47 | * @param edge - The edge that stopped refreshing 48 | */ 49 | - (void)pullToRefreshView:(ITPullToRefreshScrollView *)scrollView 50 | didStopRefreshingEdge:(ITPullToRefreshEdge)edge; 51 | 52 | /** 53 | * This method get's invoked when the scroll view reached the top&bottom edge 54 | * 55 | * @param scrollView - The scroll view that stopped refreshing 56 | * @param edge - The edge that reached 57 | */ 58 | - (void)pullToRefreshView:(ITPullToRefreshScrollView *)scrollView 59 | didReachRefreshingEdge:(ITPullToRefreshEdge)edge; 60 | 61 | @end 62 | 63 | 64 | @class ITPullToRefreshEdgeView; 65 | 66 | /** 67 | * ITPullToRefreshScrollView is subclass of the NSScrollView class. 68 | * It supports refreshing by scrolling. 69 | */ 70 | @interface ITPullToRefreshScrollView : NSScrollView 71 | 72 | /** 73 | * The delegate instance will receive notifications from the scroll view. 74 | * Look at the `ITPullToRefreshScrollViewDelegate` protocol for more information. 75 | */ 76 | @property (weak) IBOutlet id delegate; 77 | 78 | /** 79 | * Defines, which edges should be refreshable. 80 | * To assign multiple edges, simply add them with a bitwise OR operator: 81 | * 82 | * scrollView.refreshableEdges = ITPullToRefreshEdgeTop | ITPullToRefreshEdgeBottom 83 | */ 84 | @property (nonatomic) NSUInteger refreshableEdges; 85 | 86 | /** 87 | * A bitwise representation of the triggered edges. 88 | * 89 | * Edges are triggered, if the whole edge view is visible in the scroll view, 90 | * and the scroll gesture did not end yet. 91 | */ 92 | @property (readonly) NSUInteger triggeredEdges; 93 | 94 | /** 95 | * A bitwise representation of the refreshing edges. 96 | */ 97 | @property (readonly) NSUInteger refreshingEdges; 98 | 99 | /** 100 | * Get's the edge view for an edge 101 | * 102 | * @param edge - The edge for which the edge view should be returned 103 | * 104 | * @return The edge view for a specific edge 105 | */ 106 | - (ITPullToRefreshEdgeView *)edgeViewForEdge:(ITPullToRefreshEdge)edge; 107 | 108 | /** 109 | * Should be invoked by the delegate, when the refresh action is done. 110 | * 111 | * @param edge - The edge that should stop refreshing 112 | */ 113 | - (void)stopRefreshingEdge:(ITPullToRefreshEdge)edge; 114 | 115 | @end 116 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, and 10 | distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright 13 | owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities 16 | that control, are controlled by, or are under common control with that entity. 17 | For the purposes of this definition, "control" means (i) the power, direct or 18 | indirect, to cause the direction or management of such entity, whether by 19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the 20 | outstanding shares, or (iii) beneficial ownership of such entity. 21 | 22 | "You" (or "Your") shall mean an individual or Legal Entity exercising 23 | permissions granted by this License. 24 | 25 | "Source" form shall mean the preferred form for making modifications, including 26 | but not limited to software source code, documentation source, and configuration 27 | files. 28 | 29 | "Object" form shall mean any form resulting from mechanical transformation or 30 | translation of a Source form, including but not limited to compiled object code, 31 | generated documentation, and conversions to other media types. 32 | 33 | "Work" shall mean the work of authorship, whether in Source or Object form, made 34 | available under the License, as indicated by a copyright notice that is included 35 | in or attached to the work (an example is provided in the Appendix below). 36 | 37 | "Derivative Works" shall mean any work, whether in Source or Object form, that 38 | is based on (or derived from) the Work and for which the editorial revisions, 39 | annotations, elaborations, or other modifications represent, as a whole, an 40 | original work of authorship. For the purposes of this License, Derivative Works 41 | shall not include works that remain separable from, or merely link (or bind by 42 | name) to the interfaces of, the Work and Derivative Works thereof. 43 | 44 | "Contribution" shall mean any work of authorship, including the original version 45 | of the Work and any modifications or additions to that Work or Derivative Works 46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work 47 | by the copyright owner or by an individual or Legal Entity authorized to submit 48 | on behalf of the copyright owner. For the purposes of this definition, 49 | "submitted" means any form of electronic, verbal, or written communication sent 50 | to the Licensor or its representatives, including but not limited to 51 | communication on electronic mailing lists, source code control systems, and 52 | issue tracking systems that are managed by, or on behalf of, the Licensor for 53 | the purpose of discussing and improving the Work, but excluding communication 54 | that is conspicuously marked or otherwise designated in writing by the copyright 55 | owner as "Not a Contribution." 56 | 57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf 58 | of whom a Contribution has been received by Licensor and subsequently 59 | incorporated within the Work. 60 | 61 | 2. Grant of Copyright License. 62 | 63 | Subject to the terms and conditions of this License, each Contributor hereby 64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 65 | irrevocable copyright license to reproduce, prepare Derivative Works of, 66 | publicly display, publicly perform, sublicense, and distribute the Work and such 67 | Derivative Works in Source or Object form. 68 | 69 | 3. Grant of Patent License. 70 | 71 | Subject to the terms and conditions of this License, each Contributor hereby 72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, 73 | irrevocable (except as stated in this section) patent license to make, have 74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where 75 | such license applies only to those patent claims licensable by such Contributor 76 | that are necessarily infringed by their Contribution(s) alone or by combination 77 | of their Contribution(s) with the Work to which such Contribution(s) was 78 | submitted. If You institute patent litigation against any entity (including a 79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a 80 | Contribution incorporated within the Work constitutes direct or contributory 81 | patent infringement, then any patent licenses granted to You under this License 82 | for that Work shall terminate as of the date such litigation is filed. 83 | 84 | 4. Redistribution. 85 | 86 | You may reproduce and distribute copies of the Work or Derivative Works thereof 87 | in any medium, with or without modifications, and in Source or Object form, 88 | provided that You meet the following conditions: 89 | 90 | You must give any other recipients of the Work or Derivative Works a copy of 91 | this License; and 92 | You must cause any modified files to carry prominent notices stating that You 93 | changed the files; and 94 | You must retain, in the Source form of any Derivative Works that You distribute, 95 | all copyright, patent, trademark, and attribution notices from the Source form 96 | of the Work, excluding those notices that do not pertain to any part of the 97 | Derivative Works; and 98 | If the Work includes a "NOTICE" text file as part of its distribution, then any 99 | Derivative Works that You distribute must include a readable copy of the 100 | attribution notices contained within such NOTICE file, excluding those notices 101 | that do not pertain to any part of the Derivative Works, in at least one of the 102 | following places: within a NOTICE text file distributed as part of the 103 | Derivative Works; within the Source form or documentation, if provided along 104 | with the Derivative Works; or, within a display generated by the Derivative 105 | Works, if and wherever such third-party notices normally appear. The contents of 106 | the NOTICE file are for informational purposes only and do not modify the 107 | License. You may add Your own attribution notices within Derivative Works that 108 | You distribute, alongside or as an addendum to the NOTICE text from the Work, 109 | provided that such additional attribution notices cannot be construed as 110 | modifying the License. 111 | You may add Your own copyright statement to Your modifications and may provide 112 | additional or different license terms and conditions for use, reproduction, or 113 | distribution of Your modifications, or for any such Derivative Works as a whole, 114 | provided Your use, reproduction, and distribution of the Work otherwise complies 115 | with the conditions stated in this License. 116 | 117 | 5. Submission of Contributions. 118 | 119 | Unless You explicitly state otherwise, any Contribution intentionally submitted 120 | for inclusion in the Work by You to the Licensor shall be under the terms and 121 | conditions of this License, without any additional terms or conditions. 122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of 123 | any separate license agreement you may have executed with Licensor regarding 124 | such Contributions. 125 | 126 | 6. Trademarks. 127 | 128 | This License does not grant permission to use the trade names, trademarks, 129 | service marks, or product names of the Licensor, except as required for 130 | reasonable and customary use in describing the origin of the Work and 131 | reproducing the content of the NOTICE file. 132 | 133 | 7. Disclaimer of Warranty. 134 | 135 | Unless required by applicable law or agreed to in writing, Licensor provides the 136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, 137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, 138 | including, without limitation, any warranties or conditions of TITLE, 139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are 140 | solely responsible for determining the appropriateness of using or 141 | redistributing the Work and assume any risks associated with Your exercise of 142 | permissions under this License. 143 | 144 | 8. Limitation of Liability. 145 | 146 | In no event and under no legal theory, whether in tort (including negligence), 147 | contract, or otherwise, unless required by applicable law (such as deliberate 148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be 149 | liable to You for damages, including any direct, indirect, special, incidental, 150 | or consequential damages of any character arising as a result of this License or 151 | out of the use or inability to use the Work (including but not limited to 152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or 153 | any and all other commercial damages or losses), even if such Contributor has 154 | been advised of the possibility of such damages. 155 | 156 | 9. Accepting Warranty or Additional Liability. 157 | 158 | While redistributing the Work or Derivative Works thereof, You may choose to 159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or 160 | other liability obligations and/or rights consistent with this License. However, 161 | in accepting such obligations, You may act only on Your own behalf and on Your 162 | sole responsibility, not on behalf of any other Contributor, and only if You 163 | agree to indemnify, defend, and hold each Contributor harmless for any liability 164 | incurred by, or claims asserted against, such Contributor by reason of your 165 | accepting any such warranty or additional liability. 166 | 167 | END OF TERMS AND CONDITIONS 168 | 169 | APPENDIX: How to apply the Apache License to your work 170 | 171 | To apply the Apache License to your work, attach the following boilerplate 172 | notice, with the fields enclosed by brackets "[]" replaced with your own 173 | identifying information. (Don't include the brackets!) The text should be 174 | enclosed in the appropriate comment syntax for the file format. We also 175 | recommend that a file or class name and description of purpose be included on 176 | the same "printed page" as the copyright notice for easier identification within 177 | third-party archives. 178 | 179 | Copyright [yyyy] [name of copyright owner] 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/Modules/ITProgressIndicator/ITProgressIndicator/Classes/ITProgressIndicator.h: -------------------------------------------------------------------------------- 1 | // 2 | // ITProgressIndicatorView.h 3 | // ITProgressIndicator 4 | // 5 | // Created by Ilija Tovilo on 9/25/13. 6 | // Copyright (c) 2013 Ilija Tovilo. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | // 13 | // !!!IMPORTANT!!! - Embedd ITProgressIndicator in a layer-backed view to avoid side-effects! 14 | // 15 | 16 | /** 17 | * @class ITProgressIndicator 18 | * 19 | * A replacement for `NSProgressIndicator`. 20 | * It's a highly customizable control, driven by Core Animation, which makes it much more performant. 21 | * 22 | * So basically, it's awesome. 23 | * 24 | */ 25 | @interface ITProgressIndicator : NSView 26 | 27 | #pragma mark - Methods 28 | 29 | /** 30 | * Override this method to achieve a custom animation 31 | * 32 | * @return CAKeyframeAnimation - animation which will be put on the progress indicator layer 33 | */ 34 | - (CAKeyframeAnimation *)keyFrameAnimationForCurrentPreferences; 35 | 36 | #pragma mark - Properties 37 | 38 | 39 | /// @property isIndeterminate - Indicates if the view will show the progress, or just spin 40 | @property (nonatomic, setter = setIndeterminate:) BOOL isIndeterminate; 41 | 42 | 43 | /// @property progress - The amount that should be shown when `isIndeterminate` is set to `YES` 44 | @property (nonatomic) CGFloat progress; 45 | 46 | 47 | /// @property animates - Indicates if the view is animating 48 | @property (nonatomic) BOOL animates; 49 | 50 | 51 | /// @property hideWhenStopped - Indicates if the view will be hidden if it's stopped 52 | @property (nonatomic) BOOL hideWhenStopped; 53 | 54 | 55 | /// @property lengthOfLine - The length of a single line 56 | @property (nonatomic) CGFloat lengthOfLine; 57 | 58 | 59 | /// @property widthOfLine - The width of a single line 60 | @property (nonatomic) CGFloat widthOfLine; 61 | 62 | 63 | /// @property numberOfLines - The number of lines of the indicator 64 | @property (nonatomic) NSUInteger numberOfLines; 65 | 66 | 67 | /// @property innerMargin - The distance of the lines from the middle 68 | @property (nonatomic) CGFloat innerMargin; 69 | 70 | 71 | /// @property animationDuration - Duration of a single rotation 72 | @property (nonatomic) CGFloat animationDuration; 73 | 74 | 75 | /// @property gradualAnimation - Defines if the animation is smooth or gradual 76 | @property (nonatomic) BOOL steppedAnimation; 77 | 78 | /// @property color - The color of the progress indicator 79 | @property (nonatomic, strong) NSColor *color; 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/Modules/ITProgressIndicator/ITProgressIndicator/Classes/ITProgressIndicator.m: -------------------------------------------------------------------------------- 1 | // 2 | // ITProgressIndicatorView.m 3 | // ITProgressIndicator 4 | // 5 | // Created by Ilija Tovilo on 9/25/13. 6 | // Copyright (c) 2013 Ilija Tovilo. All rights reserved. 7 | // 8 | 9 | #import "ITProgressIndicator.h" 10 | #import "NSBezierPath+Geometry.h" 11 | 12 | 13 | #pragma mark - Consts 14 | #define kITSpinAnimationKey @"spinAnimation" 15 | #define kITProgressPropertyKey @"progress" 16 | 17 | #pragma mark - Private Interface 18 | 19 | @interface ITProgressIndicator () 20 | @property (nonatomic, strong, readonly) CALayer *progressIndicatorLayer; 21 | @end 22 | 23 | 24 | #pragma mark - Implementation 25 | 26 | @implementation ITProgressIndicator 27 | @synthesize progressIndicatorLayer = _progressIndicatorLayer; 28 | 29 | 30 | #pragma mark - Init 31 | 32 | - (id)initWithCoder:(NSCoder *)coder 33 | { 34 | self = [super initWithCoder:coder]; 35 | if (self) { 36 | [self initLayers]; 37 | } 38 | return self; 39 | } 40 | 41 | - (id)initWithFrame:(NSRect)frame 42 | { 43 | self = [super initWithFrame:frame]; 44 | if (self) { 45 | [self initLayers]; 46 | } 47 | return self; 48 | } 49 | 50 | - (void)initLayers { 51 | // Setting initial values 52 | self.color = [NSColor blackColor]; 53 | self.innerMargin = 4; 54 | self.widthOfLine = 3; 55 | self.lengthOfLine = 6; 56 | self.numberOfLines = 8; 57 | self.animationDuration = 0.6; 58 | self.isIndeterminate = NO; 59 | self.steppedAnimation = YES; 60 | self.hideWhenStopped = YES; 61 | self.animates = YES; 62 | 63 | // Init layers 64 | [self setWantsLayer:YES]; 65 | self.progressIndicatorLayer.frame = self.layer.bounds; 66 | [self.layer addSublayer:self.progressIndicatorLayer]; 67 | 68 | [self reloadIndicatorContent]; 69 | [self reloadAnimation]; 70 | } 71 | 72 | - (void)awakeFromNib { 73 | [self reloadAnimation]; 74 | } 75 | 76 | - (void)reloadIndicatorContent { 77 | self.progressIndicatorLayer.contents = [self progressImage]; 78 | } 79 | 80 | - (void)reloadAnimation { 81 | [self.progressIndicatorLayer removeAnimationForKey:kITSpinAnimationKey]; 82 | 83 | if (self.animates) { 84 | [self.progressIndicatorLayer addAnimation:[self keyFrameAnimationForCurrentPreferences] forKey:kITSpinAnimationKey]; 85 | } 86 | } 87 | 88 | 89 | #pragma mark - Drawing 90 | 91 | - (NSImage *)progressImage { 92 | NSImage *progressImage = [[NSImage alloc] initWithSize:self.bounds.size]; 93 | [progressImage setFlipped:NO]; 94 | [progressImage lockFocus]; 95 | { 96 | [NSGraphicsContext saveGraphicsState]; 97 | { 98 | [self.color set]; 99 | 100 | NSRect r = self.bounds; 101 | NSBezierPath *line = [NSBezierPath bezierPathWithRoundedRect: 102 | NSMakeRect((NSWidth(r) / 2) - (self.widthOfLine / 2), 103 | (NSHeight(r) / 2) - self.innerMargin - self.lengthOfLine, 104 | self.widthOfLine, self.lengthOfLine) 105 | xRadius:self.widthOfLine / 2 106 | yRadius:self.widthOfLine / 2]; 107 | 108 | void (^lineDrawingBlock)(NSUInteger line) = 109 | ^(NSUInteger lineNumber) { 110 | NSBezierPath *lineInstance = [line copy]; 111 | lineInstance = [lineInstance rotatedBezierPath:((2 * M_PI) / self.numberOfLines * lineNumber) + M_PI 112 | aboutPoint:NSMakePoint(NSWidth(r) / 2, NSHeight(r) / 2)]; 113 | 114 | if (!_isIndeterminate) [[self.color colorWithAlphaComponent:1.0 - (1.0 / self.numberOfLines * lineNumber)] set]; 115 | 116 | [lineInstance fill]; 117 | }; 118 | 119 | if (self.isIndeterminate) { 120 | for (NSUInteger i = self.numberOfLines; 121 | i > round(self.numberOfLines - (self.numberOfLines * self.progress)); 122 | i--) 123 | { 124 | lineDrawingBlock(i); 125 | } 126 | } else { 127 | for (NSUInteger i = 0; i < self.numberOfLines; i++) { 128 | lineDrawingBlock(i); 129 | } 130 | } 131 | } 132 | [NSGraphicsContext restoreGraphicsState]; 133 | } 134 | [progressImage unlockFocus]; 135 | 136 | return progressImage; 137 | } 138 | 139 | 140 | #pragma mark - Helpers 141 | 142 | - (CAKeyframeAnimation *)keyFrameAnimationForCurrentPreferences { 143 | NSMutableArray* keyFrameValues = [NSMutableArray array]; 144 | NSMutableArray* keyTimeValues; 145 | 146 | if (self.steppedAnimation) { 147 | { 148 | [keyFrameValues addObject:[NSNumber numberWithFloat:0.0]]; 149 | for (int i = 0; i < self.numberOfLines; i++) { 150 | [keyFrameValues addObject:[NSNumber numberWithFloat:-M_PI * (2.0 / self.numberOfLines * i)]]; 151 | [keyFrameValues addObject:[NSNumber numberWithFloat:-M_PI * (2.0 / self.numberOfLines * i)]]; 152 | } 153 | [keyFrameValues addObject:[NSNumber numberWithFloat:-M_PI*2.0]]; 154 | } 155 | 156 | keyTimeValues = [NSMutableArray array]; 157 | { 158 | [keyTimeValues addObject:[NSNumber numberWithFloat:0.0]]; 159 | for (int i = 0; i < (self.numberOfLines - 1); i++) { 160 | [keyTimeValues addObject:[NSNumber numberWithFloat:1.0 / self.numberOfLines * i]]; 161 | [keyTimeValues addObject:[NSNumber numberWithFloat:1.0 / self.numberOfLines * (i + 1)]]; 162 | } 163 | [keyTimeValues addObject:[NSNumber numberWithFloat:1.0 / self.numberOfLines * (self.numberOfLines - 1)]]; 164 | } 165 | } else { 166 | { 167 | [keyFrameValues addObject:[NSNumber numberWithFloat:-M_PI*0.0]]; 168 | [keyFrameValues addObject:[NSNumber numberWithFloat:-M_PI*0.5]]; 169 | [keyFrameValues addObject:[NSNumber numberWithFloat:-M_PI*1.0]]; 170 | [keyFrameValues addObject:[NSNumber numberWithFloat:-M_PI*1.5]]; 171 | [keyFrameValues addObject:[NSNumber numberWithFloat:-M_PI*2.0]]; 172 | } 173 | } 174 | 175 | 176 | CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; 177 | 178 | [animation setRepeatCount:HUGE_VALF]; 179 | [animation setValues:keyFrameValues]; 180 | [animation setKeyTimes:keyTimeValues]; 181 | [animation setValueFunction:[CAValueFunction functionWithName: kCAValueFunctionRotateZ]]; 182 | [animation setDuration:self.animationDuration]; 183 | 184 | return animation; 185 | } 186 | 187 | - (void)reloadVisibility { 188 | if (_hideWhenStopped && !_animates && !_isIndeterminate) { 189 | [self setHidden:YES]; 190 | } else { 191 | [self setHidden:NO]; 192 | } 193 | } 194 | 195 | 196 | #pragma mark - NSView methods 197 | 198 | // Animatible proxy 199 | + (id)defaultAnimationForKey:(NSString *)key 200 | { 201 | if ([key isEqualToString:kITProgressPropertyKey]) { 202 | return [CABasicAnimation animation]; 203 | } else { 204 | return [super defaultAnimationForKey:key]; 205 | } 206 | } 207 | 208 | 209 | #pragma mark - Setters & Getters 210 | 211 | - (void)setIndeterminate:(BOOL)isIndeterminate { 212 | _isIndeterminate = isIndeterminate; 213 | 214 | if (_isIndeterminate) { 215 | self.animates = NO; 216 | } 217 | } 218 | 219 | - (void)setProgress:(CGFloat)progress { 220 | if (progress < 0 || progress > 1) { 221 | @throw [NSException exceptionWithName:@"Invalid `progress` property value" 222 | reason:@"`progress` property needs to be between 0 and 1" 223 | userInfo:nil]; 224 | } 225 | 226 | _progress = progress; 227 | 228 | if (self.isIndeterminate) { 229 | [self reloadIndicatorContent]; 230 | } 231 | } 232 | 233 | - (void)setAnimates:(BOOL)animates { 234 | _animates = animates; 235 | [self reloadIndicatorContent]; 236 | [self reloadAnimation]; 237 | [self reloadVisibility]; 238 | } 239 | 240 | - (void)setHideWhenStopped:(BOOL)hideWhenStopped { 241 | _hideWhenStopped = hideWhenStopped; 242 | [self reloadVisibility]; 243 | } 244 | 245 | - (CALayer *)progressIndicatorLayer { 246 | if (!_progressIndicatorLayer) { 247 | _progressIndicatorLayer = [CALayer layer]; 248 | } 249 | 250 | return _progressIndicatorLayer; 251 | } 252 | 253 | - (void)setLengthOfLine:(CGFloat)lengthOfLine { 254 | _lengthOfLine = lengthOfLine; 255 | [self reloadIndicatorContent]; 256 | } 257 | 258 | - (void)setWidthOfLine:(CGFloat)widthOfLine { 259 | _widthOfLine = widthOfLine; 260 | [self reloadIndicatorContent]; 261 | } 262 | 263 | - (void)setInnerMargin:(CGFloat)innerMargin { 264 | _innerMargin = innerMargin; 265 | [self reloadIndicatorContent]; 266 | } 267 | 268 | - (void)setAnimationDuration:(CGFloat)animationDuration { 269 | _animationDuration = animationDuration; 270 | [self reloadAnimation]; 271 | } 272 | 273 | - (void)setNumberOfLines:(NSUInteger)numberOfLines { 274 | _numberOfLines = numberOfLines; 275 | [self reloadIndicatorContent]; 276 | [self reloadAnimation]; 277 | } 278 | 279 | - (void)setSteppedAnimation:(BOOL)steppedAnimation { 280 | _steppedAnimation = steppedAnimation; 281 | [self reloadAnimation]; 282 | } 283 | 284 | - (void)setColor:(NSColor *)color { 285 | _color = color; 286 | [self reloadIndicatorContent]; 287 | } 288 | 289 | @end 290 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/Modules/ITProgressIndicator/ITProgressIndicator/Classes/NSBezierPath+Geometry.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSBezierPath+Geometry.h 3 | // ITProgressIndicator 4 | // 5 | // Created by Ilija Tovilo on 9/25/13. 6 | // Copyright (c) 2013 Ilija Tovilo. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NSAffineTransform *RotationTransform(const float radians, const NSPoint aboutPoint); 12 | 13 | @interface NSBezierPath (Geometry) 14 | 15 | - (NSBezierPath*)rotatedBezierPath:(float) angle; 16 | - (NSBezierPath*)rotatedBezierPath:(float) angle aboutPoint:(NSPoint)point; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/Modules/ITProgressIndicator/ITProgressIndicator/Classes/NSBezierPath+Geometry.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSBezierPath+Geometry.m 3 | // ITProgressIndicator 4 | // 5 | // Created by Ilija Tovilo on 9/25/13. 6 | // Copyright (c) 2013 Ilija Tovilo. All rights reserved. 7 | // 8 | 9 | #import "NSBezierPath+Geometry.h" 10 | 11 | NSAffineTransform *RotationTransform(const float angle, const NSPoint aboutPoint) { 12 | NSAffineTransform *xfm = [NSAffineTransform transform]; 13 | [xfm translateXBy:aboutPoint.x yBy:aboutPoint.y]; 14 | [xfm rotateByRadians:angle]; 15 | [xfm translateXBy:-aboutPoint.x yBy:-aboutPoint.y]; 16 | 17 | return xfm; 18 | } 19 | 20 | @implementation NSBezierPath (Geometry) 21 | 22 | - (NSBezierPath *)rotatedBezierPath:(float)angle { 23 | return [self rotatedBezierPath:angle aboutPoint:[self centerOfBounds]]; 24 | } 25 | 26 | - (NSBezierPath*)rotatedBezierPath:(float)angle aboutPoint:(NSPoint)point { 27 | if(angle == 0.0) return self; 28 | else 29 | { 30 | NSBezierPath* copy = [self copy]; 31 | NSAffineTransform *xfm = RotationTransform(angle, point); 32 | [copy transformUsingAffineTransform:xfm]; 33 | 34 | return copy; 35 | } 36 | } 37 | 38 | - (NSPoint)centerOfBounds { 39 | return NSMakePoint(NSMidX(self.bounds), NSMidY(self.bounds)); 40 | } 41 | 42 | @end 43 | 44 | 45 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/Modules/NSBKeyframeAnimation/NSBKeyframeAnimation/Classes/NSBKeyframeAnimation/NSBKeyframeAnimation.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSBKeyframeAnimation.h 3 | // NSBKeyframeAnimation 4 | // 5 | // Created by Nacho Soto on 8/6/12. 6 | // Copyright (c) 2012 Nacho Soto. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "NSBKeyframeAnimationFunctions.h" 12 | 13 | typedef void(^NSBKeyframeAnimationCompletionBlock)(BOOL finished); 14 | 15 | @interface NSBKeyframeAnimation : CAKeyframeAnimation 16 | 17 | + (id)animationWithKeyPath:(NSString *)keypath 18 | duration:(NSTimeInterval)duration 19 | startValue:(double)startValue 20 | endValue:(double)endValue 21 | function:(NSBKeyframeAnimationFunction)function; 22 | 23 | @property (nonatomic, copy, readwrite) NSBKeyframeAnimationCompletionBlock completionBlock; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/Modules/NSBKeyframeAnimation/NSBKeyframeAnimation/Classes/NSBKeyframeAnimation/NSBKeyframeAnimation.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSBKeyframeAnimation.m 3 | // NSBKeyframeAnimation 4 | // 5 | // Created by Nacho Soto on 8/6/12. 6 | // Copyright (c) 2012 Nacho Soto. All rights reserved. 7 | // 8 | 9 | #import "NSBKeyframeAnimation.h" 10 | 11 | #define kFPS 60 12 | 13 | @interface NSBKeyframeAnimation () 14 | { 15 | NSBKeyframeAnimationFunction f; 16 | } 17 | 18 | @end 19 | 20 | @implementation NSBKeyframeAnimation 21 | 22 | - (id)initWithKeyPath:(NSString *)keypath 23 | duration:(NSTimeInterval)duration 24 | startValue:(double)startValue 25 | endValue:(double)endValue 26 | function:(NSBKeyframeAnimationFunction)function 27 | { 28 | if ((self = [super init])) 29 | { 30 | f = function; 31 | 32 | self.keyPath = keypath; 33 | self.duration = duration; 34 | self.values = [self generateValuesFrom:startValue to:endValue]; 35 | 36 | // we're already generating values at 60fps 37 | self.calculationMode = kCAAnimationLinear; 38 | } 39 | 40 | return self; 41 | } 42 | 43 | + (id)animationWithKeyPath:(NSString *)keypath 44 | duration:(NSTimeInterval)duration 45 | startValue:(double)startValue 46 | endValue:(double)endValue 47 | function:(NSBKeyframeAnimationFunction)function 48 | { 49 | return [[self alloc] initWithKeyPath:keypath duration:duration startValue:startValue endValue:endValue function:function]; 50 | } 51 | 52 | #pragma mark - 53 | 54 | - (NSArray *)generateValuesFrom:(double)startValue to:(double)endValue 55 | { 56 | NSUInteger steps = (NSUInteger)ceil(kFPS * self.duration) + 2; 57 | 58 | NSMutableArray *valueArray = [NSMutableArray arrayWithCapacity:steps]; 59 | 60 | const double increment = 1.0 / (double)(steps - 1); 61 | 62 | double progress = 0.0, 63 | v = 0.0, 64 | value = 0.0; 65 | 66 | NSUInteger i; 67 | for (i = 0; i < steps; i++) 68 | { 69 | v = f(self.duration * progress * 1000, 0, 1, self.duration * 1000); 70 | value = startValue + v * (endValue - startValue); 71 | 72 | [valueArray addObject:[NSNumber numberWithDouble:value]]; 73 | 74 | progress += increment; 75 | } 76 | 77 | return [NSArray arrayWithArray:valueArray]; 78 | } 79 | 80 | #pragma mark - 81 | 82 | - (void)setCompletionBlock:(NSBKeyframeAnimationCompletionBlock)completionBlock 83 | { 84 | if (_completionBlock != completionBlock) 85 | { 86 | _completionBlock = [completionBlock copy]; 87 | 88 | self.delegate = self; 89 | } 90 | } 91 | 92 | - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)finished 93 | { 94 | if (self.completionBlock != nil) 95 | { 96 | self.completionBlock(finished); 97 | self.completionBlock = nil; 98 | } 99 | } 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/Modules/NSBKeyframeAnimation/NSBKeyframeAnimation/Classes/NSBKeyframeAnimation/NSBKeyframeAnimationFunctions.c: -------------------------------------------------------------------------------- 1 | // 2 | // NSBKeyframeAnimationFunctions.c 3 | // NSBKeyframeAnimation 4 | // 5 | // Created by Nacho Soto on 8/6/12. 6 | // Copyright (c) 2012 Nacho Soto. All rights reserved. 7 | // 8 | 9 | #include 10 | #include 11 | 12 | #import "NSBKeyframeAnimationFunctions.h" 13 | 14 | // source: http://gsgd.co.uk/sandbox/jquery/easing/jquery.easing.1.3.js 15 | 16 | double NSBKeyframeAnimationFunctionEaseInQuad(double t,double b, double c, double d) 17 | { 18 | t/=d; 19 | return c*t*t + b; 20 | } 21 | 22 | double NSBKeyframeAnimationFunctionEaseOutQuad(double t,double b, double c, double d) 23 | { 24 | t/=d; 25 | return -c *t*(t-2) + b; 26 | } 27 | 28 | double NSBKeyframeAnimationFunctionEaseInOutQuad(double t,double b, double c, double d) 29 | { 30 | t/=d/2; 31 | if (t < 1) return c/2*t*t + b; 32 | --t; 33 | return -c/2 * (t*(t-2) - 1) + b; 34 | } 35 | 36 | double NSBKeyframeAnimationFunctionEaseInCubic(double t,double b, double c, double d) 37 | { 38 | t/=d; 39 | return c*t*t*t + b; 40 | } 41 | 42 | double NSBKeyframeAnimationFunctionEaseOutCubic(double t,double b, double c, double d) 43 | { 44 | t=t/d-1; 45 | return c*(t*t*t + 1) + b; 46 | } 47 | 48 | double NSBKeyframeAnimationFunctionEaseInOutCubic(double t, double b, double c, double d) 49 | { 50 | t/=d/2; 51 | if (t < 1) return c/2*t*t*t + b; 52 | 53 | t-=2; 54 | return c/2*(t*t*t + 2) + b; 55 | } 56 | 57 | double NSBKeyframeAnimationFunctionEaseInQuart(double t, double b, double c, double d) 58 | { 59 | t/=d; 60 | return c*t*t*t*t + b; 61 | } 62 | 63 | double NSBKeyframeAnimationFunctionEaseOutQuart(double t, double b, double c, double d) 64 | { 65 | t=t/d-1; 66 | return -c * (t*t*t*t - 1) + b; 67 | } 68 | 69 | double NSBKeyframeAnimationFunctionEaseInOutQuart(double t, double b, double c, double d) 70 | { 71 | t/=d/2; 72 | if (t < 1) return c/2*t*t*t*t + b; 73 | 74 | t-=2; 75 | return -c/2 * (t*t*t*t - 2) + b; 76 | } 77 | 78 | double NSBKeyframeAnimationFunctionEaseInQuint(double t, double b, double c, double d) 79 | { 80 | t/=d; 81 | return c*t*t*t*t*t + b; 82 | } 83 | 84 | double NSBKeyframeAnimationFunctionEaseOutQuint(double t, double b, double c, double d) 85 | { 86 | t=t/d-1; 87 | return c*(t*t*t*t*t + 1) + b; 88 | } 89 | 90 | double NSBKeyframeAnimationFunctionEaseInOutQuint(double t, double b, double c, double d) 91 | { 92 | t/=d/2; 93 | if (t < 1) return c/2*t*t*t*t*t + b; 94 | 95 | t-=2; 96 | return c/2*(t*t*t*t*t + 2) + b; 97 | } 98 | 99 | double NSBKeyframeAnimationFunctionEaseInSine(double t, double b, double c, double d) 100 | { 101 | return -c * cos(t/d * (M_PI_2)) + c + b; 102 | } 103 | 104 | double NSBKeyframeAnimationFunctionEaseOutSine(double t, double b, double c, double d) 105 | { 106 | return c * sin(t/d * (M_PI_2)) + b; 107 | } 108 | 109 | double NSBKeyframeAnimationFunctionEaseInOutSine(double t, double b, double c, double d) 110 | { 111 | return -c/2 * (cos(M_PI*t/d) - 1) + b; 112 | } 113 | 114 | double NSBKeyframeAnimationFunctionEaseInExpo(double t, double b, double c, double d) 115 | { 116 | return (t==0) ? b : c * pow(2, 10 * (t/d - 1)) + b; 117 | } 118 | 119 | double NSBKeyframeAnimationFunctionEaseOutExpo(double t, double b, double c, double d) 120 | { 121 | return (t==d) ? b+c : c * (-pow(2, -10 * t/d) + 1) + b; 122 | } 123 | 124 | double NSBKeyframeAnimationFunctionEaseInOutExpo(double t, double b, double c, double d) 125 | { 126 | if (t==0) return b; 127 | if (t==d) return b+c; 128 | if ((t/=d/2) < 1) return c/2 * pow(2, 10 * (t - 1)) + b; 129 | return c/2 * (-pow(2, -10 * --t) + 2) + b; 130 | } 131 | 132 | double NSBKeyframeAnimationFunctionEaseInCirc(double t, double b, double c, double d) 133 | { 134 | t/=d; 135 | return -c * (sqrt(1 - (t)*t) - 1) + b; 136 | } 137 | 138 | double NSBKeyframeAnimationFunctionEaseOutCirc(double t, double b, double c, double d) 139 | { 140 | t=t/d-1; 141 | return c * sqrt(1 - (t)*t) + b; 142 | } 143 | 144 | double NSBKeyframeAnimationFunctionEaseInOutCirc(double t, double b, double c, double d) 145 | { 146 | if ((t/=d/2) < 1) return -c/2 * (sqrt(1 - t*t) - 1) + b; 147 | 148 | t-=2; 149 | return c/2 * (sqrt(1 - (t)*t) + 1) + b; 150 | } 151 | 152 | double NSBKeyframeAnimationFunctionEaseInElastic(double t, double b, double c, double d) 153 | { 154 | double s = 1.70158; double p=0; double a=c; 155 | 156 | if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 157 | if (a < abs(c)) { a=c; s=p/4; } 158 | else s = p/(2*M_PI) * asin (c/a); 159 | 160 | t-=1; 161 | return -(a*pow(2,10*(t)) * sin( (t*d-s)*(2*M_PI)/p )) + b; 162 | } 163 | 164 | double NSBKeyframeAnimationFunctionEaseOutElastic(double t, double b, double c, double d) 165 | { 166 | double s=1.70158, p=0, a=c; 167 | if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3; 168 | if (a < abs(c)) { a=c; s=p/4; } 169 | else s = p/(2*M_PI) * asin (c/a); 170 | return a*pow(2,-10*t) * sin( (t*d-s)*(2*M_PI)/p ) + c + b; 171 | } 172 | 173 | double NSBKeyframeAnimationFunctionEaseInOutElastic(double t, double b, double c, double d) 174 | { 175 | double s=1.70158, p=0, a=c; 176 | if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5); 177 | if (a < abs(c)) { a=c; s=p/4; } 178 | else s = p/(2*M_PI) * asin(c/a); 179 | 180 | t-=1; 181 | if (t < 1) return -.5*(a*pow(2,10*(t)) * sin( (t*d-s)*(2*M_PI)/p )) + b; 182 | 183 | t-=1; 184 | return a*pow(2,-10*(t)) * sin( (t*d-s)*(2*M_PI)/p )*.5 + c + b; 185 | } 186 | 187 | double NSBKeyframeAnimationFunctionEaseInBack(double t, double b, double c, double d) 188 | { 189 | const double s = 1.70158; 190 | 191 | t/=d; 192 | return c*(t)*t*((s+1)*t - s) + b; 193 | } 194 | 195 | double NSBKeyframeAnimationFunctionEaseOutBack(double t, double b, double c, double d) 196 | { 197 | const double s = 1.70158; 198 | 199 | t=t/d-1; 200 | return c*((t)*t*((s+1)*t + s) + 1) + b; 201 | } 202 | 203 | double NSBKeyframeAnimationFunctionEaseInOutBack(double t, double b, double c, double d) 204 | { 205 | double s = 1.70158; 206 | s*=(1.525); 207 | t/=d/2; 208 | if ((t) < 1) return c/2*(t*t*(((s)+1)*t - s)) + b; 209 | 210 | t-=2; 211 | s*=(1.525); 212 | return c/2*((t)*t*(((s)+1)*t + s) + 2) + b; 213 | } 214 | 215 | double NSBKeyframeAnimationFunctionEaseInBounce(double t, double b, double c, double d) 216 | { 217 | return c - NSBKeyframeAnimationFunctionEaseOutBounce(d-t, 0, c, d) + b; 218 | } 219 | 220 | double NSBKeyframeAnimationFunctionEaseOutBounce(double t, double b, double c, double d) 221 | { 222 | if ((t/=d) < (1/2.75)) { 223 | return c*(7.5625*t*t) + b; 224 | } else if (t < (2/2.75)) { 225 | t-=(1.5/2.75); 226 | return c*(7.5625*(t)*t + .75) + b; 227 | } else if (t < (2.5/2.75)) { 228 | t-=(2.25/2.75); 229 | return c*(7.5625*(t)*t + .9375) + b; 230 | } else { 231 | t-=(2.625/2.75); 232 | return c*(7.5625*(t)*t + .984375) + b; 233 | } 234 | } 235 | 236 | double NSBKeyframeAnimationFunctionEaseInOutBounce(double t, double b, double c, double d) 237 | { 238 | if (t < d/2) 239 | return NSBKeyframeAnimationFunctionEaseInBounce (t*2, 0, c, d) * .5 + b; 240 | else 241 | return NSBKeyframeAnimationFunctionEaseOutBounce(t*2-d, 0, c, d) * .5 + c*.5 + b; 242 | } 243 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/Modules/NSBKeyframeAnimation/NSBKeyframeAnimation/Classes/NSBKeyframeAnimation/NSBKeyframeAnimationFunctions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSBKeyframeAnimationFunctions.h 3 | // NSBKeyframeAnimation 4 | // 5 | // Created by Nacho Soto on 8/6/12. 6 | // Copyright (c) 2012 Nacho Soto. All rights reserved. 7 | // 8 | 9 | typedef double (*NSBKeyframeAnimationFunction)(double, double, double, double); 10 | 11 | double NSBKeyframeAnimationFunctionEaseInQuad(double t,double b, double c, double d); 12 | double NSBKeyframeAnimationFunctionEaseOutQuad(double t,double b, double c, double d); 13 | double NSBKeyframeAnimationFunctionEaseInOutQuad(double t,double b, double c, double d); 14 | 15 | double NSBKeyframeAnimationFunctionEaseInCubic(double t,double b, double c, double d); 16 | double NSBKeyframeAnimationFunctionEaseOutCubic(double t,double b, double c, double d); 17 | double NSBKeyframeAnimationFunctionEaseInOutCubic(double t, double b, double c, double d); 18 | 19 | double NSBKeyframeAnimationFunctionEaseInQuart(double t, double b, double c, double d); 20 | double NSBKeyframeAnimationFunctionEaseOutQuart(double t, double b, double c, double d); 21 | double NSBKeyframeAnimationFunctionEaseInOutQuart(double t, double b, double c, double d); 22 | 23 | double NSBKeyframeAnimationFunctionEaseInQuint(double t, double b, double c, double d); 24 | double NSBKeyframeAnimationFunctionEaseOutQuint(double t, double b, double c, double d); 25 | double NSBKeyframeAnimationFunctionEaseInOutQuint(double t, double b, double c, double d); 26 | 27 | double NSBKeyframeAnimationFunctionEaseInSine(double t, double b, double c, double d); 28 | double NSBKeyframeAnimationFunctionEaseOutSine(double t, double b, double c, double d); 29 | double NSBKeyframeAnimationFunctionEaseInOutSine(double t, double b, double c, double d); 30 | 31 | double NSBKeyframeAnimationFunctionEaseInExpo(double t, double b, double c, double d); 32 | double NSBKeyframeAnimationFunctionEaseOutExpo(double t, double b, double c, double d); 33 | double NSBKeyframeAnimationFunctionEaseInOutExpo(double t, double b, double c, double d); 34 | 35 | double NSBKeyframeAnimationFunctionEaseInCirc(double t, double b, double c, double d); 36 | double NSBKeyframeAnimationFunctionEaseOutCirc(double t, double b, double c, double d); 37 | double NSBKeyframeAnimationFunctionEaseInOutCirc(double t, double b, double c, double d); 38 | 39 | double NSBKeyframeAnimationFunctionEaseInElastic(double t, double b, double c, double d); 40 | double NSBKeyframeAnimationFunctionEaseOutElastic(double t, double b, double c, double d); 41 | double NSBKeyframeAnimationFunctionEaseInOutElastic(double t, double b, double c, double d); 42 | 43 | double NSBKeyframeAnimationFunctionEaseInBack(double t, double b, double c, double d); 44 | double NSBKeyframeAnimationFunctionEaseOutBack(double t, double b, double c, double d); 45 | double NSBKeyframeAnimationFunctionEaseInOutBack(double t, double b, double c, double d); 46 | 47 | double NSBKeyframeAnimationFunctionEaseInBounce(double t, double b, double c, double d); 48 | double NSBKeyframeAnimationFunctionEaseOutBounce(double t, double b, double c, double d); 49 | double NSBKeyframeAnimationFunctionEaseInOutBounce(double t, double b, double c, double d); 50 | -------------------------------------------------------------------------------- /CocoaControls/ITPullToRefreshScrollView/README.md: -------------------------------------------------------------------------------- 1 | ITPullToRefreshScrollView 2 | ========================= 3 | 4 | `ITPullToRefreshScrollView` is a subclass of `NSScrollView` which allows iOS 7 style refreshing by pulling. 5 | `ITPullToRefreshScrollView` was created for [Play by Play](http://playbyplayapp.com), development funded by [David Keegan](http://davidkeegan.com). 6 | 7 | ![](./demo.gif) 8 | 9 | 10 | Thanks to 11 | --------- 12 | 13 | - [Sasmito Adibowo](https://github.com/adib), a lot of code is based on [RefreshableScrollView](https://github.com/adib/RefreshableScrollView) 14 | - [Abhi Beckert](https://github.com/abhibeckert) for the [DuxScrollViewAnimation class](https://github.com/abhibeckert/Dux/blob/master/Dux/DuxScrollViewAnimation.m). 15 | - [NachoSoto](https://github.com/NachoSoto) for the [NSBKeyframeAnimation class](https://github.com/NachoSoto/NSBKeyframeAnimation) 16 | 17 | 18 | Usage 19 | ----- 20 | 21 | ### Include files in project 22 | 23 | `ITPullToRefreshScrollView` has two submodules. 24 | You need to copy the following files: 25 | 26 | *Files under /ITPullToRefreshScrollView/Classes/* 27 | 28 | * `ITPullToRefreshScrollView.h` 29 | * `ITPullToRefreshScrollView.m` 30 | * `ITPullToRefreshClipView.h` 31 | * `ITPullToRefreshClipView.m` 32 | * `ITPullToRefreshEdgeView.h` 33 | * `ITPullToRefreshEdgeView.m` 34 | * `DuxScrollViewAnimation.h` 35 | * `DuxScrollViewAnimation.m` 36 | 37 | ----------- 38 | 39 | *Files under /Modules/ITProgressIndicator/ITProgressIndicator/Classes/* 40 | 41 | * `ITProgressIndicator.h` 42 | * `ITProgressIndicator.m` 43 | * `NSBezierPath+Geometry.h` 44 | * `NSBezierPath+Geometry.m` 45 | 46 | ----------- 47 | 48 | *Files under /Modules/NSBKeyframeAnimation/NSBKeyframeAnimation/Classes/NSBKeyframeAnimation/* 49 | 50 | * `NSBKeyframeAnimation.h` 51 | * `NSBKeyframeAnimation.m` 52 | * `NSBKeyframeAnimationFunctions.h` 53 | * `NSBKeyframeAnimationFunctions.c` 54 | 55 | ----------- 56 | 57 | Make sure to copy them to the project, and to add them to the target. 58 | 59 | 60 | ### Use in a project 61 | 62 | **Make sure to check out the sample project.** 63 | 64 | Set the custom class of your scroll view in Interface Builder to `ITPullToRefreshScrollView`. 65 | Next you need to connect a `IBOutlet` to your scroll view. 66 | ``` objc 67 | @property (assign) IBOutlet ITPullToRefreshScrollView *scrollView; 68 | ``` 69 | 70 | Then you can configure in code, which edges of the scroll view should be refreshable. 71 | ``` objc 72 | // Make top & bottom refreshable 73 | self.scrollView.refreshableEdges = ITPullToRefreshEdgeTop | ITPullToRefreshEdgeBottom; 74 | ``` 75 | 76 | To receive notifications from the scroll view, you need to create a delegate. 77 | To do this, your delegate class must implement the `ITPullToRefreshScrollViewDelegate` protocol. 78 | You can then implement the following methods. 79 | ``` objc 80 | /** 81 | * This method get's invoked when the scroll view started refreshing 82 | * 83 | * @param scrollView - The scroll view that started refreshing 84 | * @param edge - The edge that started refreshing 85 | */ 86 | - (void)pullToRefreshView:(ITPullToRefreshScrollView *)scrollView 87 | didStartRefreshingEdge:(ITPullToRefreshEdge)edge { 88 | 89 | // Do stuff that takes very long 90 | 91 | // Don't forget to call this line! 92 | [scrollView stopRefreshingEdge:edge]; 93 | } 94 | 95 | /** 96 | * This method get's invoked when the scroll view stopped refreshing 97 | * 98 | * @param scrollView - The scroll view that stopped refreshing 99 | * @param edge - The edge that stopped refreshing 100 | */ 101 | - (void)pullToRefreshView:(ITPullToRefreshScrollView *)scrollView 102 | didStopRefreshingEdge:(ITPullToRefreshEdge)edge { 103 | 104 | // Do UI stuff 105 | } 106 | ``` 107 | 108 | To receive notifications, you finally have to set the delegate of the scroll view. 109 | ``` objc 110 | self.scrollView.delegate = self; 111 | ``` 112 | 113 | ### Customisation 114 | 115 | To create custom `ITPullToRefreshEdgeView` subclasses, override the following methods: 116 | 117 | ``` objc 118 | // -------------------------- 119 | // ------------------- Events 120 | // -------------------------- 121 | 122 | /** 123 | * This method is called when the edge is triggered 124 | * 125 | * @param scrollView - The sender scroll view 126 | */ 127 | - (void)pullToRefreshScrollViewDidTriggerRefresh:(ITPullToRefreshScrollView *)scrollView; 128 | 129 | /** 130 | * This method is called when the edge is untriggered 131 | * 132 | * @param scrollView - The sender scroll view 133 | */ 134 | - (void)pullToRefreshScrollViewDidUntriggerRefresh:(ITPullToRefreshScrollView *)scrollView; 135 | 136 | /** 137 | * This method is called when the edge starts refreshing 138 | * 139 | * @param scrollView - The sender scroll view 140 | */ 141 | - (void)pullToRefreshScrollViewDidStartRefreshing:(ITPullToRefreshScrollView *)scrollView; 142 | 143 | /** 144 | * This method is called when the edge stops refreshing 145 | * 146 | * @param scrollView - The sender scroll view 147 | */ 148 | - (void)pullToRefreshScrollViewDidStopRefreshing:(ITPullToRefreshScrollView *)scrollView; 149 | 150 | /** 151 | * This method is called when part of the edge view becomes visible 152 | * 153 | * @param scrollView - The sender scroll view 154 | * @param progress - The amount of the edge view that is visible (from 0.0 to 1.0) 155 | */ 156 | - (void)pullToRefreshScrollView:(ITPullToRefreshScrollView *)scrollView didScrollWithProgress:(CGFloat)progress; 157 | 158 | 159 | 160 | // -------------------------- 161 | // ------------ Customisation 162 | // -------------------------- 163 | 164 | /** 165 | * Override this to remove the progress indicator and create other components 166 | */ 167 | - (void)installComponents; 168 | 169 | /** 170 | * The height of the edge view. 171 | * Override this method to achieve a custom edge view height. 172 | * 173 | * @return The height of the edge view 174 | */ 175 | - (CGFloat)edgeViewHeight; 176 | 177 | /** 178 | * Override this method to draw a custom background. 179 | * You can also just override `drawRect:` and to all the drawing on your own. 180 | * 181 | * @param The rect which should be drawn on 182 | */ 183 | - (void)drawBackgroundInRect:(NSRect)dirtyRect; 184 | ``` 185 | -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/AppIcon.appiconset/128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/CocoaControls/Images.xcassets/AppIcon.appiconset/128.png -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/AppIcon.appiconset/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/CocoaControls/Images.xcassets/AppIcon.appiconset/16.png -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/AppIcon.appiconset/256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/CocoaControls/Images.xcassets/AppIcon.appiconset/256.png -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/AppIcon.appiconset/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/CocoaControls/Images.xcassets/AppIcon.appiconset/32.png -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/AppIcon.appiconset/512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/CocoaControls/Images.xcassets/AppIcon.appiconset/512.png -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/AppIcon.appiconset/64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/CocoaControls/Images.xcassets/AppIcon.appiconset/64.png -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "idiom" : "mac", 59 | "size" : "512x512", 60 | "scale" : "2x" 61 | } 62 | ], 63 | "info" : { 64 | "version" : 1, 65 | "author" : "xcode" 66 | } 67 | } -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/cocoapods.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "cocoapods.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/cocoapods.imageset/cocoapods.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/CocoaControls/Images.xcassets/cocoapods.imageset/cocoapods.png -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/desktop-button.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "desktop-button.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/desktop-button.imageset/desktop-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/CocoaControls/Images.xcassets/desktop-button.imageset/desktop-button.png -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/filter.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "filter.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/filter.imageset/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/CocoaControls/Images.xcassets/filter.imageset/filter.png -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/more.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "more.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/more.imageset/more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/CocoaControls/Images.xcassets/more.imageset/more.png -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/placeholder.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "placeholder.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/placeholder.imageset/placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/CocoaControls/Images.xcassets/placeholder.imageset/placeholder.png -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/refresh.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "refresh.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/refresh.imageset/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/CocoaControls/Images.xcassets/refresh.imageset/refresh.png -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/star-half-o.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "star-half-o.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/star-half-o.imageset/star-half-o.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/CocoaControls/Images.xcassets/star-half-o.imageset/star-half-o.png -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/star-o.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "star-o.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/star-o.imageset/star-o.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/CocoaControls/Images.xcassets/star-o.imageset/star-o.png -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/star.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x", 10 | "filename" : "star.png" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /CocoaControls/Images.xcassets/star.imageset/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/CocoaControls/Images.xcassets/star.imageset/star.png -------------------------------------------------------------------------------- /CocoaControls/RSCCAPI.h: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCAPI.h 3 | // CocoaControls 4 | // 5 | // Created by R0CKSTAR on 5/5/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | @import Foundation; 10 | 11 | extern NSString *const RSCCAPIRoot, 12 | *const RSCCAPISearchFormat, 13 | *const RSCCAPIAllPlatform, 14 | *const RSCCAPISinglePlatformFormat, 15 | *const RSCCAPISortFormat, 16 | *const RSCCAPICocoaPodsFormat, 17 | *const RSCCAPILicenseFormat, 18 | *const RSCCAPIPageFormat; 19 | -------------------------------------------------------------------------------- /CocoaControls/RSCCAPI.m: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCAPI.m 3 | // CocoaControls 4 | // 5 | // Created by R0CKSTAR on 5/5/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "RSCCAPI.h" 10 | 11 | NSString *const RSCCAPIRoot = @"https://www.cocoacontrols.com", 12 | *const RSCCAPISearchFormat = @"search?utf8=✓&q=%@", 13 | *const RSCCAPIAllPlatform = @"controls", 14 | *const RSCCAPISinglePlatformFormat = @"platforms/%@/controls", 15 | *const RSCCAPISortFormat = @"sort=%@", 16 | *const RSCCAPICocoaPodsFormat = @"cocoapods=%@", 17 | *const RSCCAPILicenseFormat = @"license=%@", 18 | *const RSCCAPIPageFormat = @"page=%d"; 19 | -------------------------------------------------------------------------------- /CocoaControls/RSCCAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCAppDelegate.h 3 | // CocoaControls 4 | // 5 | // Created by R0CKSTAR on 14-5-2. 6 | // Copyright (c) 2014年 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RSCCAppDelegate : NSObject 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CocoaControls/RSCCControl.h: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCControl.h 3 | // CocoaControls 4 | // 5 | // Created by R0CKSTAR on 14-5-3. 6 | // Copyright (c) 2014年 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RSCCControl : NSObject 12 | 13 | @property (copy) NSString *title, *license, *date, *image, *link, *pod, *source; 14 | 15 | @property (nonatomic) BOOL isOnCocoaPods; 16 | 17 | @property (nonatomic) CGFloat rating; 18 | 19 | @property (nonatomic) int appsUsingThisControl; 20 | 21 | - initWithAssignment:(void (^)(RSCCControl *))assignment; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /CocoaControls/RSCCControl.m: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCControl.m 3 | // CocoaControls 4 | // 5 | // Created by R0CKSTAR on 14-5-3. 6 | // Copyright (c) 2014年 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "RSCCControl.h" 10 | 11 | @implementation RSCCControl 12 | 13 | - initWithAssignment:(void (^)(RSCCControl *))assignment { 14 | 15 | return self = super.init ? !assignment ?: assignment(self) , self : nil; 16 | } 17 | 18 | - (NSString*) description { 19 | 20 | return [NSString stringWithFormat:@"[Title : %@] [License : %@] [Date : %@] [Image : %@] [Link : %@] [CocoaPods : %d] [Rating : %f] [Apps using this Control : %d] [Pod : %@] [Source : %@]", 21 | self.title, self.license, self.date, self.image, self.link, self.isOnCocoaPods, self.rating, self.appsUsingThisControl, self.pod, self.source]; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /CocoaControls/RSCCControlCellView.h: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCControlCellView.h 3 | // CocoaControls 4 | // 5 | // Created by R0CKSTAR on 14-5-5. 6 | // Copyright (c) 2014年 P.D.Q. All rights reserved. 7 | // 8 | 9 | extern int const RSCCControlCellViewImageButtonTagBase, 10 | RSCCControlCellViewCocoaPodsButtonTagBase, 11 | RSCCControlCellViewCloneButtonTagBase; 12 | 13 | extern CGFloat const kCocoaPodsButtonWidthConstant, 14 | kButtonsGapConstant; 15 | 16 | @class RSCCControlCellViewBackgroundView; 17 | 18 | @interface RSCCControlCellView : NSTableCellView 19 | 20 | @property (assign) IBOutlet RSCCControlCellViewBackgroundView *backgroundView; 21 | @property (assign) IBOutlet NSTextField *titleField, *dateField, *licenseField; 22 | @property (assign) IBOutlet NSButton *imageButton, *cocoaPodsButton, *cloneButton; 23 | @property (assign) IBOutlet NSImageView *star0, *star1, *star2, *star3, *star4; 24 | @property (assign) IBOutlet NSLayoutConstraint *cocoaPodsButtonWidth, *buttonsGap; 25 | 26 | @property (nonatomic) NSArray *stars; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /CocoaControls/RSCCControlCellView.m: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCControlCellView.m 3 | // CocoaControls 4 | // 5 | // Created by R0CKSTAR on 14-5-5. 6 | // Copyright (c) 2014年 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "RSCCControlCellView.h" 10 | 11 | @interface RSCCControlCellViewBackgroundView : NSView 12 | @end 13 | 14 | @implementation RSCCControlCellViewBackgroundView 15 | 16 | - (void) drawRect:(NSRect)dirtyRect { 17 | 18 | CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]; 19 | NSUInteger hexRGBA = 0xeeeeeeee; 20 | CGContextSetRGBFillColor(context, ((hexRGBA & 0xFF000000) >> 24), ((hexRGBA & 0x00FF0000) >> 16), ((hexRGBA & 0x0000FF00) >> 8), (hexRGBA & 0x000000FF) / 255.0f); 21 | CGContextFillRect(context, NSRectToCGRect(dirtyRect)); 22 | } 23 | 24 | @end 25 | 26 | int const RSCCControlCellViewImageButtonTagBase = 1000, 27 | RSCCControlCellViewCocoaPodsButtonTagBase = 2000, 28 | RSCCControlCellViewCloneButtonTagBase = 3000; 29 | 30 | CGFloat const kCocoaPodsButtonWidthConstant = 40.0f, 31 | kButtonsGapConstant = 10.0f; 32 | 33 | @implementation RSCCControlCellView 34 | 35 | - (void) setBackgroundStyle:(NSBackgroundStyle)backgroundStyle {} 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /CocoaControls/RSCCCore.h: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCCore.h 3 | // CocoaControls 4 | // 5 | // Created by R0CKSTAR on 14-5-3. 6 | // Copyright (c) 2014年 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "AFNetworking.h" 10 | #import "RSCCAPI.h" 11 | #import "RSCCControl.h" 12 | 13 | extern NSString *const RSCCCoreControlsDidLoadNotification, 14 | *const RSCCCoreDetailDidLoadNotification; 15 | 16 | @interface RSCCCore : NSObject 17 | 18 | @property (copy) NSString *filter; 19 | 20 | @property (readonly) AFHTTPRequestOperationManager *imageManager; 21 | 22 | + (instancetype) sharedCore; 23 | 24 | - (void) refreshControls; 25 | 26 | - (void) moreControls; 27 | 28 | - (void) detailForControl:(RSCCControl*) control withSender:(NSButton*)_; 29 | 30 | - (void) searchControlsWithKey:(NSString*) key; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /CocoaControls/RSCCCore.m: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCCore.m 3 | // CocoaControls 4 | // 5 | // Created by R0CKSTAR on 14-5-3. 6 | // Copyright (c) 2014年 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "RSCCCore.h" 10 | #import "RSCCHTMLResponseSerializer.h" 11 | #import "RSCCImageRequestSerializer.h" 12 | #import "RSCCImageResponseSerializer.h" 13 | #import "TFHpple.h" 14 | 15 | NSString *const RSCCCoreControlsDidLoadNotification = @"com.pdq.core.controls.did.load", 16 | *const RSCCCoreDetailDidLoadNotification = @"com.pdq.core.control.detail.did.load"; 17 | 18 | @interface RSCCCore () 19 | 20 | @property (nonatomic) AFHTTPRequestOperationManager *requestManager, *imageManager; 21 | @property (nonatomic) int page; 22 | 23 | @end 24 | 25 | @implementation RSCCCore 26 | 27 | - (void) RSCC_parseControlsWithDoc:(TFHpple *)doc { 28 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 29 | NSMutableArray *cs = [@[] mutableCopy]; 30 | NSArray *elements = [doc searchWithXPathQuery:@"//*[@class=\"block-grid-item\"]"]; 31 | for (TFHppleElement *element in elements) { 32 | RSCCControl *c = [[RSCCControl alloc] initWithAssignment:^(RSCCControl *c) { 33 | NSArray *ps = [element childrenWithTagName:@"p"]; 34 | for (TFHppleElement *p in ps) { 35 | TFHppleElement *a = [p firstChildWithTagName:@"a"]; 36 | if (a) { 37 | TFHppleElement *img = [a firstChildWithTagName:@"img"]; 38 | if (img) { 39 | c.image = [img attributes][@"src"]; 40 | } else { 41 | c.title = a.text; 42 | c.link = [a attributes][@"href"]; 43 | } 44 | } else { 45 | NSArray *is = [p childrenWithTagName:@"i"]; 46 | if ([is count] > 0) { 47 | for (TFHppleElement *i in is) { 48 | NSString *class = [i attributes][@"class"]; 49 | if ([class isEqualToString:@"icon-star"]) { 50 | c.rating += 1; 51 | } else if ([class isEqualToString:@"icon-star-half-full"]) { 52 | c.rating += 0.5; 53 | } 54 | } 55 | } else { 56 | NSArray *components = [p.text componentsSeparatedByString:@" • "]; 57 | for (NSString *component in components) { 58 | if ([component rangeOfString:@"CocoaPod"].length > 0) { 59 | c.isOnCocoaPods = YES; 60 | } else if ([component rangeOfString:@"Licensed"].length > 0 || [component rangeOfString:@"License"].length > 0) { 61 | c.license = [component stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 62 | } else if ([component rangeOfString:@"App"].length > 0){ 63 | c.appsUsingThisControl = [[[component substringToIndex:[component rangeOfString:@"App"].location] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] intValue]; 64 | } else { 65 | c.date = component; 66 | } 67 | } 68 | } 69 | } 70 | } 71 | }]; 72 | [cs addObject:c]; 73 | } 74 | dispatch_async(dispatch_get_main_queue(), ^{ 75 | [NSNotificationCenter.defaultCenter postNotificationName:RSCCCoreControlsDidLoadNotification object:[NSArray arrayWithArray:cs] userInfo:@{@"page" : @(self.page)}]; 76 | }); 77 | }); 78 | } 79 | 80 | - (void) RSCC_loadControlsWithURLString:(NSString *)URLString { 81 | [self.requestManager.operationQueue cancelAllOperations]; 82 | [self.imageManager.operationQueue cancelAllOperations]; 83 | 84 | [self.requestManager GET:URLString parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { 85 | [self RSCC_parseControlsWithDoc:responseObject]; 86 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 87 | if ([error code] != NSURLErrorCancelled) { 88 | [NSNotificationCenter.defaultCenter postNotificationName:RSCCCoreControlsDidLoadNotification object:[NSArray array] userInfo:@{@"page" : @(self.page)}]; 89 | } 90 | }]; 91 | } 92 | 93 | - init { 94 | self = [super init]; 95 | if (self) { 96 | self.requestManager = [[AFHTTPRequestOperationManager alloc] initWithBaseURL:[NSURL URLWithString:RSCCAPIRoot]]; 97 | self.requestManager.responseSerializer = [RSCCHTMLResponseSerializer serializer]; 98 | 99 | self.imageManager = [AFHTTPRequestOperationManager manager]; 100 | self.imageManager.requestSerializer = [RSCCImageRequestSerializer serializer]; 101 | self.imageManager.responseSerializer = [RSCCImageResponseSerializer serializer]; 102 | 103 | self.filter = nil; 104 | 105 | [self refreshControls]; 106 | } 107 | return self; 108 | } 109 | 110 | + (instancetype) sharedCore { 111 | static RSCCCore *sharedCore = nil; 112 | static dispatch_once_t onceToken; 113 | dispatch_once(&onceToken, ^{ 114 | sharedCore = [self new]; 115 | }); 116 | return sharedCore; 117 | } 118 | 119 | - (void) refreshControls { 120 | self.page = 1; 121 | 122 | NSString *URLString = (self.filter != nil) ? [NSString stringWithFormat:@"%@&%@", self.filter, [NSString stringWithFormat:RSCCAPIPageFormat, self.page]] : [NSString stringWithFormat:@"%@?%@", RSCCAPIAllPlatform, [NSString stringWithFormat:RSCCAPIPageFormat, self.page]]; 123 | [self RSCC_loadControlsWithURLString:URLString]; 124 | } 125 | 126 | - (void) moreControls { 127 | self.page += 1; 128 | 129 | NSString *URLString = self.filter ? [NSString stringWithFormat:@"%@&%@", self.filter, [NSString stringWithFormat:RSCCAPIPageFormat, self.page]] : [NSString stringWithFormat:@"%@?%@", RSCCAPIAllPlatform, [NSString stringWithFormat:RSCCAPIPageFormat, self.page]]; 130 | 131 | [self RSCC_loadControlsWithURLString:URLString]; 132 | } 133 | 134 | - (void) searchControlsWithKey:(NSString*)key { 135 | self.page = 0; 136 | 137 | [self RSCC_loadControlsWithURLString:[[NSString stringWithFormat:RSCCAPISearchFormat, key] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; 138 | } 139 | 140 | - (void) detailForControl:(RSCCControl*)control withSender:(NSButton*)sender { 141 | [self.requestManager.operationQueue cancelAllOperations]; 142 | 143 | [self.requestManager GET:[NSString stringWithFormat:@"%@%@", RSCCAPIRoot, control.link] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) { 144 | NSArray *elements = [responseObject searchWithXPathQuery:@"//*[@id=\"pod\"]"]; 145 | if ([elements count] > 0) { 146 | TFHppleElement *pod = elements[0]; 147 | control.pod = [pod attributes][@"value"]; 148 | } 149 | 150 | elements = [responseObject searchWithXPathQuery:@"//*[@id=\"get_source_link\"]"]; 151 | if ([elements count] > 0) { 152 | TFHppleElement *source = elements[0]; 153 | control.source = [source attributes][@"href"]; 154 | } 155 | 156 | if (control.pod || control.source) { 157 | [NSNotificationCenter.defaultCenter postNotificationName:RSCCCoreDetailDidLoadNotification object:control userInfo:@{@"sender" : sender}]; 158 | } 159 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 160 | if ([error code] != NSURLErrorCancelled) { 161 | [NSNotificationCenter.defaultCenter postNotificationName:RSCCCoreDetailDidLoadNotification object:control userInfo:@{@"sender" : sender}]; 162 | } 163 | }]; 164 | } 165 | 166 | @end 167 | -------------------------------------------------------------------------------- /CocoaControls/RSCCHTMLResponseSerializer.h: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCHTMLResponseSerializer.h 3 | // CocoaControls 4 | // 5 | // Created by R0CKSTAR on 5/5/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "AFURLResponseSerialization.h" 10 | 11 | @interface RSCCHTMLResponseSerializer : AFHTTPResponseSerializer 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CocoaControls/RSCCHTMLResponseSerializer.m: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCHTMLResponseSerializer.m 3 | // CocoaControls 4 | // 5 | // Created by R0CKSTAR on 5/5/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "RSCCHTMLResponseSerializer.h" 10 | 11 | #import "TFHpple.h" 12 | 13 | @implementation RSCCHTMLResponseSerializer 14 | 15 | - responseObjectForResponse:(NSURLResponse *)response 16 | data:(NSData *)data 17 | error:(NSError *__autoreleasing *)error { 18 | 19 | return [TFHpple.alloc initWithHTMLData:data]; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /CocoaControls/RSCCImageRequestSerializer.h: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCImageRequestSerializer.h 3 | // CocoaControls 4 | // 5 | // Created by R0CKSTAR on 5/7/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "AFURLRequestSerialization.h" 10 | 11 | @interface RSCCImageRequestSerializer : AFHTTPRequestSerializer 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CocoaControls/RSCCImageRequestSerializer.m: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCImageRequestSerializer.m 3 | // CocoaControls 4 | // 5 | // Created by R0CKSTAR on 5/7/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "RSCCImageRequestSerializer.h" 10 | 11 | @implementation RSCCImageRequestSerializer 12 | 13 | - init { return super.init ? self.cachePolicy = NSURLRequestReturnCacheDataElseLoad, self : nil; } 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CocoaControls/RSCCImageResponseSerializer.h: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCImageResponseSerializer.h 3 | // CocoaControls 4 | // 5 | // Created by R0CKSTAR on 5/6/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "AFURLResponseSerialization.h" 10 | 11 | @interface RSCCImageResponseSerializer : AFHTTPResponseSerializer 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CocoaControls/RSCCImageResponseSerializer.m: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCImageResponseSerializer.m 3 | // CocoaControls 4 | // 5 | // Created by R0CKSTAR on 5/6/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "RSCCImageResponseSerializer.h" 10 | 11 | @implementation RSCCImageResponseSerializer 12 | 13 | - responseObjectForResponse:(NSURLResponse *)response 14 | data:(NSData *)data 15 | error:(NSError *__autoreleasing *)error { 16 | 17 | return [NSImage.alloc initWithData:data]; 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /CocoaControls/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf190 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;} 3 | {\colortbl;\red255\green255\blue255;} 4 | \paperw11900\paperh16840\vieww9600\viewh8400\viewkind0 5 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 6 | 7 | \f0\b\fs24 \cf0 Engineering: 8 | \b0 \ 9 | R0CKSTAR\ 10 | \ 11 | 12 | \b Human Interface Design: 13 | \b0 \ 14 | R0CKSTAR\ 15 | \ 16 | 17 | \b Testing: 18 | \b0 \ 19 | R0CKSTAR\ 20 | \ 21 | 22 | \b Documentation: 23 | \b0 \ 24 | R0CKSTAR\ 25 | \ 26 | 27 | \b With special thanks to: 28 | \b0 \ 29 | LY&YYY\ 30 | } -------------------------------------------------------------------------------- /CocoaControls/hpple/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009 Topfunky Corporation, http://topfunky.com 2 | 3 | MIT LICENSE 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /CocoaControls/hpple/README.markdown: -------------------------------------------------------------------------------- 1 | # DESCRIPTION 2 | 3 | Hpple: A nice Objective-C wrapper on the XPathQuery library for parsing HTML. 4 | 5 | Inspired by why the lucky stiff's [Hpricot](http://github.com/why/hpricot/tree/master). 6 | 7 | # CREDITS 8 | 9 | Hpple was created by Geoffrey Grosenbach, [Topfunky Corporation](http://topfunky.com) and [PeepCode Screencasts](http://peepcode.com). 10 | 11 | [Contributors](https://github.com/topfunky/hpple/graphs/contributors) 12 | 13 | # FEATURES 14 | 15 | * Easy searching by XPath (CSS selectors are planned) 16 | * Parses HTML (XML coming soon) 17 | * Easy access to tag content, name, and attributes. 18 | 19 | # INSTALLATION 20 | 21 | * Open your XCode project and the Hpple project. 22 | * Drag the "Hpple" directory to your project. 23 | * Add the libxml2.2.dylib framework to your project and search paths as described at [Cocoa with Love](http://cocoawithlove.com/2008/10/using-libxml2-for-parsing-and-xpath.html) 24 | 25 | More documentation and short screencast coming soon... 26 | 27 | # USAGE 28 | 29 | See TFHppleHTMLTest.m in the Hpple project for samples. 30 | 31 |
32 | #import "TFHpple.h"
33 | 
34 | NSData  * data      = [NSData dataWithContentsOfFile:@"index.html"];
35 | 
36 | TFHpple * doc       = [[TFHpple alloc] initWithHTMLData:data];
37 | NSArray * elements  = [doc search:@"//a[@class='sponsor']"];
38 | 
39 | TFHppleElement * element = [elements objectAtIndex:0];
40 | [e text];                       // The text inside the HTML element (the content of the first text node)
41 | [e tagName];                    // "a"
42 | [e attributes];                 // NSDictionary of href, class, id, etc.
43 | [e objectForKey:@"href"];       // Easy access to single attribute
44 | [e firstChildWithTagName:@"b"]; // The first "b" child node
45 | 
46 | 
47 | 48 | # TODO 49 | 50 | * Internal error catching and messages 51 | * CSS3 selectors in addition to XPath 52 | -------------------------------------------------------------------------------- /CocoaControls/hpple/TFHpple.h: -------------------------------------------------------------------------------- 1 | // 2 | // TFHpple.h 3 | // Hpple 4 | // 5 | // Created by Geoffrey Grosenbach on 1/31/09. 6 | // 7 | // Copyright (c) 2009 Topfunky Corporation, http://topfunky.com 8 | // 9 | // MIT LICENSE 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining 12 | // a copy of this software and associated documentation files (the 13 | // "Software"), to deal in the Software without restriction, including 14 | // without limitation the rights to use, copy, modify, merge, publish, 15 | // distribute, sublicense, and/or sell copies of the Software, and to 16 | // permit persons to whom the Software is furnished to do so, subject to 17 | // the following conditions: 18 | // 19 | // The above copyright notice and this permission notice shall be 20 | // included in all copies or substantial portions of the Software. 21 | // 22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 26 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 27 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | 30 | 31 | #import 32 | 33 | #import "TFHppleElement.h" 34 | 35 | @interface TFHpple : NSObject { 36 | @private 37 | NSData * data; 38 | BOOL isXML; 39 | } 40 | 41 | - (id) initWithData:(NSData *)theData isXML:(BOOL)isDataXML; 42 | - (id) initWithXMLData:(NSData *)theData; 43 | - (id) initWithHTMLData:(NSData *)theData; 44 | 45 | + (TFHpple *) hppleWithData:(NSData *)theData isXML:(BOOL)isDataXML; 46 | + (TFHpple *) hppleWithXMLData:(NSData *)theData; 47 | + (TFHpple *) hppleWithHTMLData:(NSData *)theData; 48 | 49 | - (NSArray *) searchWithXPathQuery:(NSString *)xPathOrCSS; 50 | - (TFHppleElement *) peekAtSearchWithXPathQuery:(NSString *)xPathOrCSS; 51 | 52 | @property (nonatomic, strong, readonly) NSData * data; 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /CocoaControls/hpple/TFHpple.m: -------------------------------------------------------------------------------- 1 | // 2 | // TFHpple.m 3 | // Hpple 4 | // 5 | // Created by Geoffrey Grosenbach on 1/31/09. 6 | // 7 | // Copyright (c) 2009 Topfunky Corporation, http://topfunky.com 8 | // 9 | // MIT LICENSE 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining 12 | // a copy of this software and associated documentation files (the 13 | // "Software"), to deal in the Software without restriction, including 14 | // without limitation the rights to use, copy, modify, merge, publish, 15 | // distribute, sublicense, and/or sell copies of the Software, and to 16 | // permit persons to whom the Software is furnished to do so, subject to 17 | // the following conditions: 18 | // 19 | // The above copyright notice and this permission notice shall be 20 | // included in all copies or substantial portions of the Software. 21 | // 22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 26 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 27 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | 30 | #import "TFHpple.h" 31 | #import "XPathQuery.h" 32 | 33 | @implementation TFHpple 34 | 35 | @synthesize data; 36 | 37 | 38 | - (id) initWithData:(NSData *)theData isXML:(BOOL)isDataXML 39 | { 40 | if (!(self = [super init])) { 41 | return nil; 42 | } 43 | 44 | data = theData; 45 | isXML = isDataXML; 46 | 47 | return self; 48 | } 49 | 50 | - (id) initWithXMLData:(NSData *)theData 51 | { 52 | return [self initWithData:theData isXML:YES]; 53 | } 54 | 55 | - (id) initWithHTMLData:(NSData *)theData 56 | { 57 | return [self initWithData:theData isXML:NO]; 58 | } 59 | 60 | + (TFHpple *) hppleWithData:(NSData *)theData isXML:(BOOL)isDataXML { 61 | return [[[self class] alloc] initWithData:theData isXML:isDataXML]; 62 | } 63 | 64 | + (TFHpple *) hppleWithHTMLData:(NSData *)theData { 65 | return [[self class] hppleWithData:theData isXML:NO]; 66 | } 67 | 68 | + (TFHpple *) hppleWithXMLData:(NSData *)theData { 69 | return [[self class] hppleWithData:theData isXML:YES]; 70 | } 71 | 72 | #pragma mark - 73 | 74 | // Returns all elements at xPath. 75 | - (NSArray *) searchWithXPathQuery:(NSString *)xPathOrCSS 76 | { 77 | NSArray * detailNodes = nil; 78 | if (isXML) { 79 | detailNodes = PerformXMLXPathQuery(data, xPathOrCSS); 80 | } else { 81 | detailNodes = PerformHTMLXPathQuery(data, xPathOrCSS); 82 | } 83 | 84 | NSMutableArray * hppleElements = [NSMutableArray array]; 85 | for (id node in detailNodes) { 86 | [hppleElements addObject:[TFHppleElement hppleElementWithNode:node]]; 87 | } 88 | return hppleElements; 89 | } 90 | 91 | // Returns first element at xPath 92 | - (TFHppleElement *) peekAtSearchWithXPathQuery:(NSString *)xPathOrCSS 93 | { 94 | NSArray * elements = [self searchWithXPathQuery:xPathOrCSS]; 95 | if ([elements count] >= 1) { 96 | return [elements objectAtIndex:0]; 97 | } 98 | 99 | return nil; 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /CocoaControls/hpple/TFHppleElement.h: -------------------------------------------------------------------------------- 1 | // 2 | // TFHppleElement.h 3 | // Hpple 4 | // 5 | // Created by Geoffrey Grosenbach on 1/31/09. 6 | // 7 | // Copyright (c) 2009 Topfunky Corporation, http://topfunky.com 8 | // 9 | // MIT LICENSE 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining 12 | // a copy of this software and associated documentation files (the 13 | // "Software"), to deal in the Software without restriction, including 14 | // without limitation the rights to use, copy, modify, merge, publish, 15 | // distribute, sublicense, and/or sell copies of the Software, and to 16 | // permit persons to whom the Software is furnished to do so, subject to 17 | // the following conditions: 18 | // 19 | // The above copyright notice and this permission notice shall be 20 | // included in all copies or substantial portions of the Software. 21 | // 22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 26 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 27 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | 30 | #import 31 | 32 | 33 | @interface TFHppleElement : NSObject { 34 | @private 35 | 36 | NSDictionary * node; 37 | __unsafe_unretained TFHppleElement *parent; 38 | } 39 | 40 | - (id) initWithNode:(NSDictionary *) theNode; 41 | 42 | + (TFHppleElement *) hppleElementWithNode:(NSDictionary *) theNode; 43 | 44 | @property (nonatomic, copy, readonly) NSString *raw; 45 | // Returns this tag's innerHTML content. 46 | @property (nonatomic, copy, readonly) NSString *content; 47 | 48 | // Returns the name of the current tag, such as "h3". 49 | @property (nonatomic, copy, readonly) NSString *tagName; 50 | 51 | // Returns tag attributes with name as key and content as value. 52 | // href = 'http://peepcode.com' 53 | // class = 'highlight' 54 | @property (nonatomic, strong, readonly) NSDictionary *attributes; 55 | 56 | // Returns the children of a given node 57 | @property (nonatomic, strong, readonly) NSArray *children; 58 | 59 | // Returns the first child of a given node 60 | @property (nonatomic, strong, readonly) TFHppleElement *firstChild; 61 | 62 | // the parent of a node 63 | @property (nonatomic, unsafe_unretained, readonly) TFHppleElement *parent; 64 | 65 | // Returns YES if the node has any child 66 | // This is more efficient than using the children property since no NSArray is constructed 67 | - (BOOL)hasChildren; 68 | 69 | // Returns YES if this is a text node 70 | - (BOOL)isTextNode; 71 | 72 | // Provides easy access to the content of a specific attribute, 73 | // such as 'href' or 'class'. 74 | - (NSString *) objectForKey:(NSString *) theKey; 75 | 76 | // Returns the children whose tag name equals the given string 77 | // (comparison is performed with NSString's isEqualToString) 78 | // Returns an empty array if no matching child is found 79 | - (NSArray *) childrenWithTagName:(NSString *)tagName; 80 | 81 | // Returns the first child node whose tag name equals the given string 82 | // (comparison is performed with NSString's isEqualToString) 83 | // Returns nil if no matching child is found 84 | - (TFHppleElement *) firstChildWithTagName:(NSString *)tagName; 85 | 86 | // Returns the children whose class equals the given string 87 | // (comparison is performed with NSString's isEqualToString) 88 | // Returns an empty array if no matching child is found 89 | - (NSArray *) childrenWithClassName:(NSString *)className; 90 | 91 | // Returns the first child whose class requals the given string 92 | // (comparison is performed with NSString's isEqualToString) 93 | // Returns nil if no matching child is found 94 | - (TFHppleElement *) firstChildWithClassName:(NSString*)className; 95 | 96 | // Returns the first text node from this element's children 97 | // Returns nil if there is no text node among the children 98 | - (TFHppleElement *) firstTextChild; 99 | 100 | // Returns the string contained by the first text node from this element's children 101 | // Convenience method which can be used instead of firstTextChild.content 102 | - (NSString *) text; 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /CocoaControls/hpple/TFHppleElement.m: -------------------------------------------------------------------------------- 1 | // 2 | // TFHppleElement.m 3 | // Hpple 4 | // 5 | // Created by Geoffrey Grosenbach on 1/31/09. 6 | // 7 | // Copyright (c) 2009 Topfunky Corporation, http://topfunky.com 8 | // 9 | // MIT LICENSE 10 | // 11 | // Permission is hereby granted, free of charge, to any person obtaining 12 | // a copy of this software and associated documentation files (the 13 | // "Software"), to deal in the Software without restriction, including 14 | // without limitation the rights to use, copy, modify, merge, publish, 15 | // distribute, sublicense, and/or sell copies of the Software, and to 16 | // permit persons to whom the Software is furnished to do so, subject to 17 | // the following conditions: 18 | // 19 | // The above copyright notice and this permission notice shall be 20 | // included in all copies or substantial portions of the Software. 21 | // 22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 26 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 27 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 | 30 | 31 | #import "TFHppleElement.h" 32 | 33 | static NSString * const TFHppleNodeContentKey = @"nodeContent"; 34 | static NSString * const TFHppleNodeNameKey = @"nodeName"; 35 | static NSString * const TFHppleNodeChildrenKey = @"nodeChildArray"; 36 | static NSString * const TFHppleNodeAttributeArrayKey = @"nodeAttributeArray"; 37 | static NSString * const TFHppleNodeAttributeNameKey = @"attributeName"; 38 | 39 | static NSString * const TFHppleTextNodeName = @"text"; 40 | 41 | @interface TFHppleElement () 42 | @property (nonatomic, unsafe_unretained, readwrite) TFHppleElement *parent; 43 | @end 44 | 45 | @implementation TFHppleElement 46 | @synthesize parent; 47 | 48 | 49 | - (id) initWithNode:(NSDictionary *) theNode 50 | { 51 | if (!(self = [super init])) 52 | return nil; 53 | 54 | node = theNode; 55 | 56 | return self; 57 | } 58 | 59 | + (TFHppleElement *) hppleElementWithNode:(NSDictionary *) theNode { 60 | return [[[self class] alloc] initWithNode:theNode]; 61 | } 62 | 63 | #pragma mark - 64 | 65 | - (NSString *)raw 66 | { 67 | return [node objectForKey:@"raw"]; 68 | } 69 | 70 | - (NSString *) content 71 | { 72 | return [node objectForKey:TFHppleNodeContentKey]; 73 | } 74 | 75 | 76 | - (NSString *) tagName 77 | { 78 | return [node objectForKey:TFHppleNodeNameKey]; 79 | } 80 | 81 | - (NSArray *) children 82 | { 83 | NSMutableArray *children = [NSMutableArray array]; 84 | for (NSDictionary *child in [node objectForKey:TFHppleNodeChildrenKey]) { 85 | TFHppleElement *element = [TFHppleElement hppleElementWithNode:child]; 86 | element.parent = self; 87 | [children addObject:element]; 88 | } 89 | return children; 90 | } 91 | 92 | - (TFHppleElement *) firstChild 93 | { 94 | NSArray * children = self.children; 95 | if (children.count) 96 | return [children objectAtIndex:0]; 97 | return nil; 98 | } 99 | 100 | 101 | - (NSDictionary *) attributes 102 | { 103 | NSMutableDictionary * translatedAttributes = [NSMutableDictionary dictionary]; 104 | for (NSDictionary * attributeDict in [node objectForKey:TFHppleNodeAttributeArrayKey]) { 105 | if ([attributeDict objectForKey:TFHppleNodeContentKey] && [attributeDict objectForKey:TFHppleNodeAttributeNameKey]) { 106 | [translatedAttributes setObject:[attributeDict objectForKey:TFHppleNodeContentKey] 107 | forKey:[attributeDict objectForKey:TFHppleNodeAttributeNameKey]]; 108 | } 109 | } 110 | return translatedAttributes; 111 | } 112 | 113 | - (NSString *) objectForKey:(NSString *) theKey 114 | { 115 | return [[self attributes] objectForKey:theKey]; 116 | } 117 | 118 | - (id) description 119 | { 120 | return [node description]; 121 | } 122 | 123 | - (BOOL)hasChildren 124 | { 125 | if ([node objectForKey:TFHppleNodeChildrenKey]) 126 | return YES; 127 | else 128 | return NO; 129 | } 130 | 131 | - (BOOL)isTextNode 132 | { 133 | // we must distinguish between real text nodes and standard nodes with tha name "text" () 134 | // real text nodes must have content 135 | if ([self.tagName isEqualToString:TFHppleTextNodeName] && (self.content)) 136 | return YES; 137 | else 138 | return NO; 139 | } 140 | 141 | - (NSArray*) childrenWithTagName:(NSString*)tagName 142 | { 143 | NSMutableArray* matches = [NSMutableArray array]; 144 | 145 | for (TFHppleElement* child in self.children) 146 | { 147 | if ([child.tagName isEqualToString:tagName]) 148 | [matches addObject:child]; 149 | } 150 | 151 | return matches; 152 | } 153 | 154 | - (TFHppleElement *) firstChildWithTagName:(NSString*)tagName 155 | { 156 | for (TFHppleElement* child in self.children) 157 | { 158 | if ([child.tagName isEqualToString:tagName]) 159 | return child; 160 | } 161 | 162 | return nil; 163 | } 164 | 165 | - (NSArray*) childrenWithClassName:(NSString*)className 166 | { 167 | NSMutableArray* matches = [NSMutableArray array]; 168 | 169 | for (TFHppleElement* child in self.children) 170 | { 171 | if ([[child objectForKey:@"class"] isEqualToString:className]) 172 | [matches addObject:child]; 173 | } 174 | 175 | return matches; 176 | } 177 | 178 | - (TFHppleElement *) firstChildWithClassName:(NSString*)className 179 | { 180 | for (TFHppleElement* child in self.children) 181 | { 182 | if ([[child objectForKey:@"class"] isEqualToString:className]) 183 | return child; 184 | } 185 | 186 | return nil; 187 | } 188 | 189 | - (TFHppleElement *) firstTextChild; 190 | { 191 | for (TFHppleElement* child in self.children) 192 | { 193 | if ([child isTextNode]) 194 | return child; 195 | } 196 | 197 | return [self firstChildWithTagName:TFHppleTextNodeName]; 198 | } 199 | 200 | - (NSString *) text 201 | { 202 | return self.firstTextChild.content; 203 | } 204 | 205 | @end 206 | -------------------------------------------------------------------------------- /CocoaControls/hpple/XPathQuery.h: -------------------------------------------------------------------------------- 1 | // 2 | // XPathQuery.h 3 | // FuelFinder 4 | // 5 | // Created by Matt Gallagher on 4/08/08. 6 | // Copyright 2008 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | NSArray *PerformHTMLXPathQuery(NSData *document, NSString *query); 10 | NSArray *PerformXMLXPathQuery(NSData *document, NSString *query); 11 | -------------------------------------------------------------------------------- /CocoaControls/hpple/XPathQuery.m: -------------------------------------------------------------------------------- 1 | // 2 | // XPathQuery.m 3 | // FuelFinder 4 | // 5 | // Created by Matt Gallagher on 4/08/08. 6 | // Copyright 2008 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "XPathQuery.h" 10 | 11 | #import 12 | #import 13 | #import 14 | #import 15 | #import 16 | 17 | NSDictionary *DictionaryForNode(xmlNodePtr currentNode, NSMutableDictionary *parentResult,BOOL parentContent); 18 | NSArray *PerformXPathQuery(xmlDocPtr doc, NSString *query); 19 | 20 | NSDictionary *DictionaryForNode(xmlNodePtr currentNode, NSMutableDictionary *parentResult,BOOL parentContent) 21 | { 22 | NSMutableDictionary *resultForNode = [NSMutableDictionary dictionary]; 23 | 24 | if (currentNode->name) 25 | { 26 | NSString *currentNodeContent = 27 | [NSString stringWithCString:(const char *)currentNode->name encoding:NSUTF8StringEncoding]; 28 | [resultForNode setObject:currentNodeContent forKey:@"nodeName"]; 29 | } 30 | 31 | if (currentNode->content && currentNode->content != (xmlChar *)-1) 32 | { 33 | NSString *currentNodeContent = 34 | [NSString stringWithCString:(const char *)currentNode->content encoding:NSUTF8StringEncoding]; 35 | 36 | if ([[resultForNode objectForKey:@"nodeName"] isEqual:@"text"] && parentResult) 37 | { 38 | if(parentContent) 39 | { 40 | [parentResult setObject:[currentNodeContent stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] forKey:@"nodeContent"]; 41 | return nil; 42 | } 43 | [resultForNode setObject:currentNodeContent forKey:@"nodeContent"]; 44 | // NSLog(@"content: %@",currentNodeContent); 45 | return resultForNode; 46 | 47 | } 48 | else { 49 | [resultForNode setObject:currentNodeContent forKey:@"nodeContent"]; 50 | } 51 | 52 | 53 | } 54 | 55 | xmlAttr *attribute = currentNode->properties; 56 | if (attribute) 57 | { 58 | NSMutableArray *attributeArray = [NSMutableArray array]; 59 | while (attribute) 60 | { 61 | NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary]; 62 | NSString *attributeName = 63 | [NSString stringWithCString:(const char *)attribute->name encoding:NSUTF8StringEncoding]; 64 | if (attributeName) 65 | { 66 | // NSLog(@"Attribute Name Set: %@",attributeName); 67 | [attributeDictionary setObject:attributeName forKey:@"attributeName"]; 68 | } 69 | 70 | if (attribute->children) 71 | { 72 | NSDictionary *childDictionary = DictionaryForNode(attribute->children, attributeDictionary,true); 73 | if (childDictionary) 74 | { 75 | [attributeDictionary setObject:childDictionary forKey:@"attributeContent"]; 76 | } 77 | } 78 | 79 | if ([attributeDictionary count] > 0) 80 | { 81 | [attributeArray addObject:attributeDictionary]; 82 | } 83 | attribute = attribute->next; 84 | } 85 | 86 | if ([attributeArray count] > 0) 87 | { 88 | [resultForNode setObject:attributeArray forKey:@"nodeAttributeArray"]; 89 | } 90 | } 91 | 92 | xmlNodePtr childNode = currentNode->children; 93 | if (childNode) 94 | { 95 | NSMutableArray *childContentArray = [NSMutableArray array]; 96 | while (childNode) 97 | { 98 | NSDictionary *childDictionary = DictionaryForNode(childNode, resultForNode,false); 99 | if (childDictionary) 100 | { 101 | [childContentArray addObject:childDictionary]; 102 | } 103 | childNode = childNode->next; 104 | } 105 | if ([childContentArray count] > 0) 106 | { 107 | [resultForNode setObject:childContentArray forKey:@"nodeChildArray"]; 108 | } 109 | } 110 | 111 | xmlBufferPtr buffer = xmlBufferCreate(); 112 | xmlNodeDump(buffer, currentNode->doc, currentNode, 0, 0); 113 | 114 | NSString *rawContent = [NSString stringWithCString:(const char *)buffer->content encoding:NSUTF8StringEncoding]; 115 | [resultForNode setObject:rawContent forKey:@"raw"]; 116 | 117 | xmlBufferFree(buffer); 118 | 119 | return resultForNode; 120 | } 121 | 122 | NSArray *PerformXPathQuery(xmlDocPtr doc, NSString *query) 123 | { 124 | xmlXPathContextPtr xpathCtx; 125 | xmlXPathObjectPtr xpathObj; 126 | 127 | /* Create xpath evaluation context */ 128 | xpathCtx = xmlXPathNewContext(doc); 129 | if(xpathCtx == NULL) 130 | { 131 | NSLog(@"Unable to create XPath context."); 132 | return nil; 133 | } 134 | 135 | /* Evaluate xpath expression */ 136 | xpathObj = xmlXPathEvalExpression((xmlChar *)[query cStringUsingEncoding:NSUTF8StringEncoding], xpathCtx); 137 | if(xpathObj == NULL) { 138 | NSLog(@"Unable to evaluate XPath."); 139 | xmlXPathFreeContext(xpathCtx); 140 | return nil; 141 | } 142 | 143 | xmlNodeSetPtr nodes = xpathObj->nodesetval; 144 | if (!nodes) 145 | { 146 | NSLog(@"Nodes was nil."); 147 | xmlXPathFreeObject(xpathObj); 148 | xmlXPathFreeContext(xpathCtx); 149 | return nil; 150 | } 151 | 152 | NSMutableArray *resultNodes = [NSMutableArray array]; 153 | for (NSInteger i = 0; i < nodes->nodeNr; i++) 154 | { 155 | NSDictionary *nodeDictionary = DictionaryForNode(nodes->nodeTab[i], nil,false); 156 | if (nodeDictionary) 157 | { 158 | [resultNodes addObject:nodeDictionary]; 159 | } 160 | } 161 | 162 | /* Cleanup */ 163 | xmlXPathFreeObject(xpathObj); 164 | xmlXPathFreeContext(xpathCtx); 165 | 166 | return resultNodes; 167 | } 168 | 169 | NSArray *PerformHTMLXPathQuery(NSData *document, NSString *query) 170 | { 171 | xmlDocPtr doc; 172 | 173 | /* Load XML document */ 174 | doc = htmlReadMemory([document bytes], (int)[document length], "", NULL, HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR); 175 | 176 | if (doc == NULL) 177 | { 178 | NSLog(@"Unable to parse."); 179 | return nil; 180 | } 181 | 182 | NSArray *result = PerformXPathQuery(doc, query); 183 | xmlFreeDoc(doc); 184 | 185 | return result; 186 | } 187 | 188 | NSArray *PerformXMLXPathQuery(NSData *document, NSString *query) 189 | { 190 | xmlDocPtr doc; 191 | 192 | /* Load XML document */ 193 | doc = xmlReadMemory([document bytes], (int)[document length], "", NULL, XML_PARSE_RECOVER); 194 | 195 | if (doc == NULL) 196 | { 197 | NSLog(@"Unable to parse."); 198 | return nil; 199 | } 200 | 201 | NSArray *result = PerformXPathQuery(doc, query); 202 | xmlFreeDoc(doc); 203 | 204 | return result; 205 | } 206 | -------------------------------------------------------------------------------- /CocoaControlsPlugin/CocoaControlsPlugin.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CocoaControlsPlugin/CocoaControlsPlugin.xcodeproj/project.xcworkspace/xcshareddata/CocoaControlsPlugin.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 7C3A4982-FB4F-4965-8B4C-0C3BCAFDC7DC 9 | IDESourceControlProjectName 10 | CocoaControlsPlugin 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 69291726009AC4C9A421F4E062E482087A00300B 14 | https://github.com/yeahdongcn/CocoaControlsPlugin.git 15 | 16 | IDESourceControlProjectPath 17 | CocoaControlsPlugin/CocoaControlsPlugin.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 69291726009AC4C9A421F4E062E482087A00300B 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/yeahdongcn/CocoaControlsPlugin.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 69291726009AC4C9A421F4E062E482087A00300B 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 69291726009AC4C9A421F4E062E482087A00300B 36 | IDESourceControlWCCName 37 | CocoaControlsPlugin 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /CocoaControlsPlugin/CocoaControlsPlugin.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CocoaControlsPlugin/CocoaControlsPlugin.xcodeproj/xcshareddata/xcschemes/CocoaControlsPlugin.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 66 | 67 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /CocoaControlsPlugin/CocoaControlsPlugin/CocoaControlsPlugin-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | BNDL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | DVTPlugInCompatibilityUUIDs 26 | 27 | FEC992CC-CA4A-4CFD-8881-77300FCB848A 28 | C4A681B0-4A26-480E-93EC-1218098B9AA0 29 | A2E4D43F-41F4-4FB9-BB94-7177011C9AED 30 | AD68E85B-441B-4301-B564-A45E4919A6AD 31 | 63FC1C47-140D-42B0-BB4D-A10B2D225574 32 | 37B30044-3B14-46BA-ABAA-F01000C27B63 33 | 640F884E-CE55-4B40-87C0-8869546CAB7A 34 | 992275C1-432A-4CF7-B659-D84ED6D42D3F 35 | A16FF353-8441-459E-A50C-B071F53F51B7 36 | 9F75337B-21B4-4ADC-B558-F9CADF7073A7 37 | E969541F-E6F9-4D25-8158-72DC3545A6C6 38 | 8DC44374-2B35-4C57-A6FE-2AD66A36AAD9 39 | AABB7188-E14E-4433-AD3B-5CD791EAD9A3 40 | 7FDF5C7A-131F-4ABB-9EDC-8C5F8F0B8A90 41 | 0420B86A-AA43-4792-9ED0-6FE0F2B16A13 42 | CC0D0F4F-05B3-431A-8F33-F84AFCB2C651 43 | 7265231C-39B4-402C-89E1-16167C4CC990 44 | 9AFF134A-08DC-4096-8CEE-62A4BB123046 45 | 46 | NSPrincipalClass 47 | RSCCPCocoaControlsPlugin 48 | XC4Compatible 49 | 50 | XC5Compatible 51 | 52 | XCGCReady 53 | 54 | XCPluginHasUI 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /CocoaControlsPlugin/CocoaControlsPlugin/CocoaControlsPlugin-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #import 10 | #endif 11 | -------------------------------------------------------------------------------- /CocoaControlsPlugin/CocoaControlsPlugin/Helpers/CCPProject.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCPWorkspace.h 3 | // 4 | // Copyright (c) 2013 Delisa Mason. http://delisa.me 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 | // IN THE SOFTWARE. 23 | 24 | @interface CCPProject : NSObject 25 | 26 | @property (nonatomic) NSString *directoryPath, *podspecPath, *podfilePath, *projectName; 27 | @property (nonatomic) NSDictionary *infoDictionary; 28 | @property (readonly) BOOL hasPodfile, hasPodspecFile; 29 | 30 | + (instancetype) projectForKeyWindow; 31 | + (instancetype) projectForWindow:window; 32 | 33 | - initWithName:(NSString*)name 34 | path:(NSString*)path; 35 | 36 | - (void) createPodspecFromTemplate:(NSString*)_template; 37 | 38 | - (BOOL) containsFileWithName:(NSString*)fileName; 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /CocoaControlsPlugin/CocoaControlsPlugin/Helpers/CCPProject.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCPWorkspace.m 3 | // 4 | // Copyright (c) 2013 Delisa Mason. http://delisa.me 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 | // IN THE SOFTWARE. 23 | 24 | #import 25 | #import "CCPProject.h" 26 | #import "CCPWorkspaceManager.h" 27 | 28 | @implementation CCPProject 29 | 30 | + (instancetype)projectForWindow:(id)window 31 | { 32 | id workspace = [CCPWorkspaceManager workspaceForWindow:window]; 33 | 34 | id contextManager = [workspace valueForKey:@"_runContextManager"]; 35 | for (id scheme in[contextManager valueForKey:@"runContexts"]) { 36 | NSString *schemeName = [scheme valueForKey:@"name"]; 37 | if (![schemeName hasPrefix:@"Pods-"]) { 38 | NSString *path = [CCPWorkspaceManager directoryPathForWorkspace:workspace]; 39 | return [[CCPProject alloc] initWithName:schemeName path:path]; 40 | } 41 | } 42 | 43 | return nil; 44 | } 45 | 46 | + (instancetype)projectForKeyWindow 47 | { 48 | id workspace = [CCPWorkspaceManager workspaceForKeyWindow]; 49 | 50 | id contextManager = [workspace valueForKey:@"_runContextManager"]; 51 | for (id scheme in[contextManager valueForKey:@"runContexts"]) { 52 | NSString *schemeName = [scheme valueForKey:@"name"]; 53 | if (![schemeName hasPrefix:@"Pods-"]) { 54 | NSString *path = [CCPWorkspaceManager directoryPathForWorkspace:workspace]; 55 | return [[CCPProject alloc] initWithName:schemeName path:path]; 56 | } 57 | } 58 | 59 | return nil; 60 | } 61 | 62 | - (id)initWithName:(NSString*)name 63 | path:(NSString*)path 64 | { 65 | if (self = [self init]) { 66 | _projectName = name; 67 | _podspecPath = [path stringByAppendingPathComponent:[name stringByAppendingString:@".podspec"]]; 68 | _directoryPath = path; 69 | 70 | NSString *infoPath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@"%@/%@-Info.plist", _projectName, _projectName]]; 71 | 72 | _infoDictionary = [NSDictionary dictionaryWithContentsOfFile:infoPath]; 73 | _podfilePath = [path stringByAppendingPathComponent:@"Podfile"]; 74 | } 75 | 76 | return self; 77 | } 78 | 79 | - (BOOL)hasPodspecFile 80 | { 81 | return [[NSFileManager defaultManager] fileExistsAtPath:self.podspecPath]; 82 | } 83 | 84 | - (BOOL)hasPodfile 85 | { 86 | return [[NSFileManager defaultManager] fileExistsAtPath:self.podfilePath]; 87 | } 88 | 89 | - (void)createPodspecFromTemplate:(NSString*)_template 90 | { 91 | NSMutableString *podspecFile = _template.mutableCopy; 92 | NSRange range; range.location = 0; 93 | 94 | range.length = podspecFile.length; 95 | [podspecFile replaceOccurrencesOfString:@"" 96 | withString:self.projectName 97 | options:NSLiteralSearch 98 | range:range]; 99 | 100 | NSString *version = self.infoDictionary[@"CFBundleShortVersionString"]; 101 | if (version) { 102 | range.length = podspecFile.length; 103 | [podspecFile replaceOccurrencesOfString:@"" 104 | withString:version 105 | options:NSLiteralSearch 106 | range:range]; 107 | } 108 | 109 | range.length = podspecFile.length; 110 | [podspecFile replaceOccurrencesOfString:@"'<" 111 | withString:@"'<#" 112 | options:NSLiteralSearch 113 | range:range]; 114 | 115 | range.length = podspecFile.length; 116 | [podspecFile replaceOccurrencesOfString:@">'" 117 | withString:@"#>'" 118 | options:NSLiteralSearch 119 | range:range]; 120 | 121 | // Reading dependencies 122 | NSString *podfileContent = [NSString stringWithContentsOfFile:self.podfilePath encoding:NSUTF8StringEncoding error:nil]; 123 | NSArray *fileLines = [podfileContent componentsSeparatedByString:@"\n"]; 124 | 125 | for (NSString *tmp in fileLines) { 126 | NSString *line = [tmp stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; 127 | 128 | if ([line rangeOfString:@"pod "].location == 0) { 129 | [podspecFile appendFormat:@"\n s.dependencies =\t%@", line]; 130 | } 131 | } 132 | 133 | [podspecFile appendString:@"\n\nend"]; 134 | 135 | // Write Podspec File 136 | [[NSFileManager defaultManager] createFileAtPath:self.podspecPath contents:nil attributes:nil]; 137 | [podspecFile writeToFile:self.podspecPath atomically:YES encoding:NSUTF8StringEncoding error:nil]; 138 | } 139 | 140 | - (BOOL)containsFileWithName:(NSString*)fileName 141 | { 142 | NSString *filePath = [self.directoryPath stringByAppendingPathComponent:fileName]; 143 | return [[NSFileManager defaultManager] fileExistsAtPath:filePath]; 144 | } 145 | 146 | @end 147 | -------------------------------------------------------------------------------- /CocoaControlsPlugin/CocoaControlsPlugin/Helpers/CCPWorkspaceManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // CCPWorkspaceManager.h 3 | // 4 | // Copyright (c) 2013 Delisa Mason. http://delisa.me 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 | // IN THE SOFTWARE. 23 | 24 | @interface CCPWorkspaceManager : NSObject 25 | 26 | + workspaceForKeyWindow; 27 | + workspaceForWindow:(NSWindow*)window; 28 | 29 | + (NSArray*) installedPodNamesInCurrentWorkspace; 30 | 31 | + (NSString*) currentWorkspaceDirectoryPath; 32 | + (NSString*) directoryPathForWorkspace:workspace; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /CocoaControlsPlugin/CocoaControlsPlugin/Helpers/CCPWorkspaceManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // CCPWorkspaceManager.m 3 | // 4 | // Copyright (c) 2013 Delisa Mason. http://delisa.me 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to 8 | // deal in the Software without restriction, including without limitation the 9 | // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 10 | // sell copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 | // IN THE SOFTWARE. 23 | 24 | #import "CCPWorkspaceManager.h" 25 | 26 | #import "CCPProject.h" 27 | 28 | static NSString *PODFILE = @"Podfile"; 29 | 30 | @implementation CCPWorkspaceManager 31 | 32 | + (NSArray*)installedPodNamesInCurrentWorkspace 33 | { 34 | NSMutableArray *names = [NSMutableArray new]; 35 | id workspace = [self workspaceForKeyWindow]; 36 | 37 | id contextManager = [workspace valueForKey:@"_runContextManager"]; 38 | for (id scheme in[contextManager valueForKey:@"runContexts"]) { 39 | NSString *schemeName = [scheme valueForKey:@"name"]; 40 | if ([schemeName hasPrefix:@"Pods-"]) { 41 | [names addObject:[schemeName stringByReplacingOccurrencesOfString:@"Pods-" withString:@""]]; 42 | } 43 | } 44 | return names; 45 | } 46 | 47 | + (NSString*)currentWorkspaceDirectoryPath 48 | { 49 | return [self directoryPathForWorkspace:[self workspaceForKeyWindow]]; 50 | } 51 | 52 | + (NSString*)directoryPathForWorkspace:(id)workspace 53 | { 54 | NSString *workspacePath = [[workspace valueForKey:@"representingFilePath"] valueForKey:@"_pathString"]; 55 | return [workspacePath stringByDeletingLastPathComponent]; 56 | } 57 | 58 | #pragma mark - Private 59 | 60 | + (id)workspaceForKeyWindow 61 | { 62 | return [self workspaceForWindow:[NSApp keyWindow]]; 63 | } 64 | 65 | + (id)workspaceForWindow:(NSWindow*)window 66 | { 67 | NSArray *workspaceWindowControllers = [NSClassFromString(@"IDEWorkspaceWindowController") valueForKey:@"workspaceWindowControllers"]; 68 | 69 | for (id controller in workspaceWindowControllers) { 70 | if ([[controller valueForKey:@"window"] isEqual:window]) { 71 | return [controller valueForKey:@"_workspace"]; 72 | } 73 | } 74 | return nil; 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /CocoaControlsPlugin/CocoaControlsPlugin/RSCCPCocoaControlsPlugin.h: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCPCocoaControlsPlugin.h 3 | // RSCCPCocoaControlsPlugin 4 | // 5 | // Created by R0CKSTAR on 5/8/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface RSCCPCocoaControlsPlugin : NSObject 12 | 13 | @end -------------------------------------------------------------------------------- /CocoaControlsPlugin/CocoaControlsPlugin/RSCCPCocoaControlsPlugin.m: -------------------------------------------------------------------------------- 1 | // 2 | // RSCCPCocoaControlsPlugin.m 3 | // RSCCPCocoaControlsPlugin 4 | // 5 | // Created by R0CKSTAR on 5/8/14. 6 | // Copyright (c) 2014 P.D.Q. All rights reserved. 7 | // 8 | 9 | #import "RSCCPCocoaControlsPlugin.h" 10 | #import "CCPProject.h" 11 | 12 | #import 13 | 14 | static RSCCPCocoaControlsPlugin *sharedPlugin; 15 | 16 | @interface RSCCPCocoaControlsPlugin() 17 | 18 | @property (nonatomic) NSBundle *bundle; 19 | @property (nonatomic, weak) NSWindow *keyWindow; 20 | 21 | @end 22 | 23 | @implementation RSCCPCocoaControlsPlugin 24 | 25 | - (void) RSCCP_openCocoaControlsApp { 26 | NSString *applicationBundlePathString = [self.bundle pathForAuxiliaryExecutable:@"CocoaControls.app"]; 27 | NSString *executablePathString = [NSString stringWithFormat:@"%@%@", applicationBundlePathString, @"/Contents/MacOS/CocoaControls"]; 28 | [NSTask launchedTaskWithLaunchPath:executablePathString arguments:@[]]; 29 | } 30 | 31 | - (void) RSCCP_createPodfile { 32 | CCPProject *project = [CCPProject projectForWindow:self.keyWindow]; 33 | if (project) { 34 | NSString *podFilePath = project.podfilePath; 35 | if (![project hasPodfile]) { 36 | NSError *error = nil; 37 | [[NSFileManager defaultManager] copyItemAtPath:[self.bundle pathForResource:@"DefaultPodfile" ofType:@""] toPath:podFilePath error:&error]; 38 | if (error) { 39 | [[NSAlert alertWithError:error] runModal]; 40 | } 41 | } 42 | 43 | NSFileHandle* fileHandle = [NSFileHandle fileHandleForWritingAtPath:podFilePath]; 44 | @try { 45 | [fileHandle seekToEndOfFile]; 46 | [fileHandle writeData:[[NSString stringWithFormat:@"%@%@", @"\n", [[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString]] dataUsingEncoding:NSUTF8StringEncoding]]; 47 | } 48 | @catch (NSException *e) { 49 | NSLog(@"%@", e); 50 | } 51 | [fileHandle closeFile]; 52 | 53 | [[[NSApplication sharedApplication] delegate] application:[NSApplication sharedApplication] 54 | openFile:podFilePath]; 55 | } 56 | } 57 | 58 | + (void)pluginDidLoad:(NSBundle*)plugin { 59 | static dispatch_once_t onceToken; 60 | NSString *currentApplicationName = [[NSBundle mainBundle] infoDictionary][@"CFBundleName"]; 61 | if ([currentApplicationName isEqual:@"Xcode"]) { 62 | dispatch_once(&onceToken, ^{ 63 | sharedPlugin = [[self alloc] initWithBundle:plugin]; 64 | }); 65 | } 66 | } 67 | 68 | static void NotificationReceivedCallback(CFNotificationCenterRef center, 69 | void *observer, CFStringRef name, 70 | const void *object, CFDictionaryRef 71 | userInfo) { 72 | [sharedPlugin RSCCP_createPodfile]; 73 | } 74 | 75 | - initWithBundle:(NSBundle*)plugin { 76 | if (self = [super init]) { 77 | // reference to plugin's bundle, for resource acccess 78 | self.bundle = plugin; 79 | 80 | CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, &NotificationReceivedCallback, CFSTR("com.pdq.rscccocoapods"), NULL, CFNotificationSuspensionBehaviorCoalesce); 81 | 82 | __weak __typeof(self)weakself = self; 83 | [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 84 | NSMenuItem *menuItem = [[NSApp mainMenu] itemWithTitle:@"View"]; 85 | if (menuItem) { 86 | [[menuItem submenu] addItem:[NSMenuItem separatorItem]]; 87 | 88 | NSMenuItem *actionMenuItem = [[NSMenuItem alloc] initWithTitle:@"Cocoa Controls" 89 | action:@selector(RSCCP_openCocoaControlsApp) 90 | keyEquivalent:@"c"]; 91 | [actionMenuItem setKeyEquivalentModifierMask:NSControlKeyMask]; 92 | [actionMenuItem setTarget:weakself]; 93 | [[menuItem submenu] addItem:actionMenuItem]; 94 | } 95 | }]; 96 | } 97 | return self; 98 | } 99 | 100 | - (BOOL) validateMenuItem:(NSMenuItem*)menuItem { 101 | if ([CCPProject projectForKeyWindow]) { 102 | if (!self.keyWindow) { 103 | self.keyWindow = NSApplication.sharedApplication.keyWindow; 104 | } 105 | } 106 | return YES; 107 | } 108 | 109 | @end 110 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2014 P.D.Q. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CocoaControls.app and Xcode plugin 2 | =================== 3 | [![Total views](https://sourcegraph.com/api/repos/github.com/yeahdongcn/RSImageOptimPlugin/counters/views.png)](https://sourcegraph.com/github.com/yeahdongcn/RSImageOptimPlugin) 4 | [![Views in the last 24 hours](https://sourcegraph.com/api/repos/github.com/yeahdongcn/RSImageOptimPlugin/counters/views-24h.png)](https://sourcegraph.com/github.com/yeahdongcn/RSImageOptimPlugin) 5 | 6 | OS X native application with Xcode plugin for browsing, searching, integrating, cloning controls in [Cocoa Controls](http://cocoacontrols.com/). 7 | 8 | #### Plugin screenshot 9 | ![screenshot](https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/master/plugin_screenshot.png) 10 | 11 | #### App screenshot 12 | ![screenshot](https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/master/app_screenshot.png) 13 | 14 | 15 | ##TODO 16 | * ~~Refresh and load more controls~~ 17 | * ~~Integrate Pods~~ 18 | * ~~Add refresh button and load more button at the bottom (for those people not using `Magic Mouse` or `Magic Trackpad`)~~ 19 | 20 | ##Requirements 21 | 22 | Xcode 5.0+ on OS X 10.9+. 23 | 24 | ##Installation 25 | 26 | #### Build from Source 27 | 28 | * Install pods. 29 | * Build the Xcode project. The plug-in will automatically be installed in `~/Library/Application Support/Developer/Shared/Xcode/Plug-ins`. 30 | * Relaunch Xcode. 31 | 32 | To uninstall, just remove the plugin from `~/Library/Application Support/Developer/Shared/Xcode/Plug-ins` and restart Xcode. 33 | 34 | ## How does it work? 35 | 36 | All the commands are laid at the bottom of the menu `View`. 37 | 38 | * Use the menu `Cocoa Controls` to open `CocoaControls.app` immediately. 39 | * `Click` on the `left image view` to open the image in a new window. 40 | * `Click` on the `pod button` to integrate pod. 41 | * `Click` on the `computer button` to clone the source. 42 | * `Double click` on the `cell view` to open the control in browser. 43 | 44 | ##Thanks 45 | 46 | Thanks [cocoapods-xcode-plugin](https://github.com/kattrali/cocoapods-xcode-plugin) from [Delisa Mason](https://github.com/kattrali) for the source to create/edit podfile. 47 | 48 | ##Credits 49 | 50 | Star icons are taken from [Font Awesome](http://fontawesome.io/) and converted to png using [font-awesome-to-png](https://github.com/odyniec/font-awesome-to-png). 51 | 52 | Filter icon is taken from [Anton Volodin](https://dribbble.com/cuzmich) [Icon](https://dribbble.com/shots/444019-Icons?list=users&offset=0). 53 | 54 | CocoaPods logo is taken from [CocoaPods](http://cocoapods.org/). 55 | 56 | Desktop icon is taken from [Github](https://github.com). 57 | 58 | Mouse scroller helper icons are taken from [Budi Tanrim](https://dribbble.com/buditanrim)'s [budicon tester](https://dribbble.com/shots/1182482-budicon-tester?list=users&offset=21). 59 | 60 | All data is taken from [Cocoa Controls](http://cocoacontrols.com/). 61 | 62 | ##License 63 | 64 | The MIT License (MIT) 65 | 66 | Copyright (c) 2012-2014 P.D.Q. 67 | 68 | Permission is hereby granted, free of charge, to any person obtaining a copy of 69 | this software and associated documentation files (the "Software"), to deal in 70 | the Software without restriction, including without limitation the rights to 71 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 72 | the Software, and to permit persons to whom the Software is furnished to do so, 73 | subject to the following conditions: 74 | 75 | The above copyright notice and this permission notice shall be included in all 76 | copies or substantial portions of the Software. 77 | 78 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 79 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 80 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 81 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 82 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 83 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 84 | 85 | -------------------------------------------------------------------------------- /app_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/app_screenshot.png -------------------------------------------------------------------------------- /plugin_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yeahdongcn/CocoaControlsPlugin/45f9dfd38cba0f92cdaec5c525907f6f5caecfb0/plugin_screenshot.png --------------------------------------------------------------------------------