diff --git a/.gitignore b/.gitignore index fbb01a5..50e3fd1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,38 @@ -# Xcode +# MacOSX .DS_Store +.AppleDouble +.LSOverride +.Spotlight-V100 +.Trashes +.AppleDB +.AppleDesktop +.apdisk -# CocoaPods -Pods/ +# Windows +$RECYCLE.BIN/ +Thumbs.db +ehthumbs.db +Desktop.ini +*.lnk +# XCode +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata +*.xccheckout +*.moved-aside +*.xcuserstate + +# Visual Studio +*.suo +*.sdf +*.opensdf +*.user + +# Project diff --git a/Classes/CG/Core/MobilyCG.m b/Classes/CG/Core/MobilyCG.m deleted file mode 100644 index 53edf83..0000000 --- a/Classes/CG/Core/MobilyCG.m +++ /dev/null @@ -1,310 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#include "MobilyCG.h" - -/*--------------------------------------------------*/ - -#include - -/*--------------------------------------------------*/ - -@implementation NSString (MobilyCG) - -- (CGPoint)convertToPoint { - return [self convertToPointSeparated:@";"]; -} - -- (CGPoint)convertToPointSeparated:(NSString*)separated { - CGPoint result = CGPointZero; - static NSNumberFormatter* formatter = nil; - if(formatter == nil) { - formatter = [NSNumberFormatter new]; - [formatter setNumberStyle:NSNumberFormatterDecimalStyle]; - } - NSArray* array = [self componentsSeparatedByString:separated]; - switch([array count]) { - case 1: { - result.x = [[formatter numberFromString:[array objectAtIndex:0]] floatValue]; - result.y = result.x; - break; - } - case 2: { - result.x = [[formatter numberFromString:[array objectAtIndex:0]] floatValue]; - result.y = [[formatter numberFromString:[array objectAtIndex:1]] floatValue]; - break; - } - default: - break; - } - return result; -} - -- (CGSize)convertToSize { - return [self convertToSizeSeparated:@";"]; -} - -- (CGSize)convertToSizeSeparated:(NSString*)separated { - CGSize result = CGSizeZero; - static NSNumberFormatter* formatter = nil; - if(formatter == nil) { - formatter = [NSNumberFormatter new]; - [formatter setNumberStyle:NSNumberFormatterDecimalStyle]; - } - NSArray* array = [self componentsSeparatedByString:separated]; - switch([array count]) { - case 1: { - result.width = [[formatter numberFromString:[array objectAtIndex:0]] floatValue]; - result.height = result.width; - break; - } - case 2: { - result.width = [[formatter numberFromString:[array objectAtIndex:0]] floatValue]; - result.height = [[formatter numberFromString:[array objectAtIndex:1]] floatValue]; - break; - } - default: - break; - } - return result; -} - -- (CGRect)convertToRect { - return [self convertToRectSeparated:@";"]; -} - -- (CGRect)convertToRectSeparated:(NSString*)separated { - CGRect result = CGRectZero; - static NSNumberFormatter* formatter = nil; - if(formatter == nil) { - formatter = [NSNumberFormatter new]; - [formatter setNumberStyle:NSNumberFormatterDecimalStyle]; - } - NSArray* array = [self componentsSeparatedByString:separated]; - switch([array count]) { - case 1: { - result.size.width = [[formatter numberFromString:[array objectAtIndex:0]] floatValue]; - result.size.height = result.size.width; - break; - } - case 2: { - result.size.width = [[formatter numberFromString:[array objectAtIndex:0]] floatValue]; - result.size.height = [[formatter numberFromString:[array objectAtIndex:1]] floatValue]; - break; - } - case 3: { - result.origin.x = [[formatter numberFromString:[array objectAtIndex:0]] floatValue]; - result.origin.y = [[formatter numberFromString:[array objectAtIndex:1]] floatValue]; - result.size.width = [[formatter numberFromString:[array objectAtIndex:2]] floatValue]; - result.size.height = result.size.width; - break; - } - case 4: { - result.origin.x = [[formatter numberFromString:[array objectAtIndex:0]] floatValue]; - result.origin.y = [[formatter numberFromString:[array objectAtIndex:1]] floatValue]; - result.size.width = [[formatter numberFromString:[array objectAtIndex:2]] floatValue]; - result.size.height = [[formatter numberFromString:[array objectAtIndex:3]] floatValue]; - break; - } - default: - break; - } - return result; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -CGFloat CGFloatNearestMore(CGFloat value, CGFloat step) { - CGFloat result = step; - while(result < value) { - result += step; - } - return result; -} - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -CGPoint CGPointAdd(CGPoint point, CGFloat value) { - return CGPointMake(point.x + value, point.y + value); -} - -CGPoint CGPointSub(CGPoint point, CGFloat value) { - return CGPointMake(point.x - value, point.y - value); -} - -CGPoint CGPointMul(CGPoint point, CGFloat value) { - return CGPointMake(point.x * value, point.y * value); -} - -CGPoint CGPointDiv(CGPoint point, CGFloat value) { - return CGPointMake(point.x / value, point.y / value); -} - -CGPoint CGPointAddPoint(CGPoint point1, CGPoint point2) { - return CGPointMake(point1.x + point2.x, point1.y + point2.y); -} - -CGPoint CGPointSubPoint(CGPoint point1, CGPoint point2) { - return CGPointMake(point1.x - point2.x, point1.y - point2.y); -} - -CGPoint CGPointMulPoint(CGPoint point1, CGPoint point2) { - return CGPointMake(point1.x * point2.x, point1.y * point2.y); -} - -CGPoint CGPointDivPoint(CGPoint point1, CGPoint point2) { - return CGPointMake(point1.x / point2.x, point1.y / point2.y); -} - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -CGSize CGSizeNearestMore(CGSize size, CGFloat step) { - return CGSizeMake(CGFloatNearestMore(size.width, step), CGFloatNearestMore(size.height, step)); -} - -CGSize CGSizeAdd(CGSize size, CGFloat value) { - return CGSizeMake(size.width + value, size.height + value); -} - -CGSize CGSizeSub(CGSize size, CGFloat value) { - return CGSizeMake(size.width - value, size.height - value); -} - -CGSize CGSizeMul(CGSize size, CGFloat value) { - return CGSizeMake(size.width * value, size.height * value); -} - -CGSize CGSizeDiv(CGSize size, CGFloat value) { - return CGSizeMake(size.width / value, size.height / value); -} - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -CGRect CGRectAdd(CGRect rect, CGFloat value) { - return CGRectMake(rect.origin.x + value, rect.origin.y + value, rect.size.width + value, rect.size.height + value); -} - -CGRect CGRectSub(CGRect rect, CGFloat value) { - return CGRectMake(rect.origin.x - value, rect.origin.y - value, rect.size.width - value, rect.size.height - value); -} - -CGRect CGRectMul(CGRect rect, CGFloat value) { - return CGRectMake(rect.origin.x * value, rect.origin.y * value, rect.size.width * value, rect.size.height * value); -} - -CGRect CGRectDiv(CGRect rect, CGFloat value) { - return CGRectMake(rect.origin.x / value, rect.origin.y / value, rect.size.width / value, rect.size.height / value); -} - -CGRect CGRectIntersectionExt(CGRect r1, CGRect r2, CGRect* smallRemainder, CGRect* largeRemainder) { - CGRect intersection = CGRectIntersection(r1, r2); - if(CGRectIsNull(intersection) == NO) { - CGFloat r1sx = CGRectGetMinX(r1); - CGFloat r1sy = CGRectGetMinY(r1); - CGFloat r1ex = CGRectGetMaxX(r1); - CGFloat r1ey = CGRectGetMaxY(r1); - CGFloat r2sx = CGRectGetMinX(r2); - CGFloat r2sy = CGRectGetMinY(r2); - CGFloat r2ex = CGRectGetMaxX(r2); - CGFloat r2ey = CGRectGetMaxY(r2); - CGFloat dsx = ABS(r1sx - r2sx); - CGFloat dsy = ABS(r1sy - r2sy); - CGFloat dex = ABS(r1ex - r2ex); - CGFloat dey = ABS(r1ey - r2ey); - if(smallRemainder != NULL) { - CGFloat sx = (dsx <= dex) ? r1sx : r2ex; - CGFloat sy = (dsy <= dey) ? r1sy : r2ey; - CGFloat ex = (dsx >= dex) ? r1ex : r2sx; - CGFloat ey = (dsy >= dey) ? r1ey : r2sy; - *smallRemainder = CGRectMake(sx, sy, ex - sx, ey - sy); - } - if(largeRemainder != NULL) { - CGFloat sx = (dsx >= dex) ? r1sx : r2ex; - CGFloat sy = (dsy >= dey) ? r1sy : r2ey; - CGFloat ex = (dsx <= dex) ? r1ex : r2sx; - CGFloat ey = (dsy <= dey) ? r1ey : r2sy; - *largeRemainder = CGRectMake(sx, sy, ex - sx, ey - sy); - } - } - return intersection; -} - -CGRect CGRectAspectFillFromBoundsAndSize(CGRect bounds, CGSize size) { - CGFloat iw = floorf(size.width); - CGFloat ih = floorf(size.height); - CGFloat bw = floorf(bounds.size.width); - CGFloat bh = floorf(bounds.size.height); - CGFloat fw = bw / iw; - CGFloat fh = bh / ih; - CGFloat scale = (fw > fh) ? fw : fh; - CGFloat rw = iw * scale; - CGFloat rh = ih * scale; - CGFloat rx = (bw - rw) * 0.5f; - CGFloat ry = (bh - rh) * 0.5f; - return CGRectMake(bounds.origin.x + rx, bounds.origin.y + ry, rw, rh); -} - -CGRect CGRectAspectFitFromBoundsAndSize(CGRect bounds, CGSize size) { - CGFloat iw = floorf(size.width); - CGFloat ih = floorf(size.height); - CGFloat bw = floorf(bounds.size.width); - CGFloat bh = floorf(bounds.size.height); - CGFloat fw = bw / iw; - CGFloat fh = bh / ih; - CGFloat scale = (fw < fh) ? fw : fh; - CGFloat rw = iw * scale; - CGFloat rh = ih * scale; - CGFloat rx = (bw - rw) * 0.5f; - CGFloat ry = (bh - rh) * 0.5f; - return CGRectMake(bounds.origin.x + rx, bounds.origin.y + ry, rw, rh); -} - -CGPoint CGRectGetCenterPoint(CGRect rect) { - return CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect)); -} - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ diff --git a/Classes/NS/Core/MobilyEvent.m b/Classes/NS/Core/MobilyEvent.m deleted file mode 100644 index 88ff570..0000000 --- a/Classes/NS/Core/MobilyEvent.m +++ /dev/null @@ -1,220 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyEvent.h" - -/*--------------------------------------------------*/ - -@interface MobilyEventSelector () - -@property(nonatomic, readwrite, weak) id target; -@property(nonatomic, readwrite, assign) SEL action; -@property(nonatomic, readwrite, weak) NSThread* safeThread; - -- (void)safeFireParams:(NSMutableDictionary*)params; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyEventBlock () - -@property(nonatomic, readwrite, copy) MobilyEventBlockType block; -@property(nonatomic, readwrite, assign) dispatch_queue_t safeQueue; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyEventSelector - -#pragma mark Standart - -+ (id)callbackWithTarget:(id)target action:(SEL)action { - return MOBILY_SAFE_AUTORELEASE([[self alloc] initWithTarget:target action:action thread:nil]); -} - -+ (id)callbackWithTarget:(id)target action:(SEL)action inMainThread:(BOOL)inMainThread { - return MOBILY_SAFE_AUTORELEASE([[self alloc] initWithTarget:target action:action thread:(inMainThread == YES) ? [NSThread mainThread] : nil]); -} - -+ (id)callbackWithTarget:(id)target action:(SEL)action inCurrentThread:(BOOL)inCurrentThread { - return MOBILY_SAFE_AUTORELEASE([[self alloc] initWithTarget:target action:action thread:(inCurrentThread == YES) ? [NSThread currentThread] : nil]); -} - -- (id)initWithTarget:(id)target action:(SEL)action thread:(NSThread*)thread { - self = [super init]; - if(self != nil) { - [self setTarget:target]; - [self setAction:action]; - [self setSafeThread:thread]; - } - return self; -} - -- (id)initWithCoder:(NSCoder*)coder { - self = [super init]; - if(self != nil) { - [self setAction:NSSelectorFromString([coder decodeObjectForKey:@"action"])]; - } - return self; -} - -- (void)dealloc { - [self setTarget:nil]; - [self setSafeThread:nil]; - - MOBILY_SAFE_DEALLOC; -} - -- (void)encodeWithCoder:(NSCoder*)coder { - [coder encodeObject:NSStringFromSelector(_action) forKey:@"action"]; -} - -#pragma mark Public - -- (id)fireSender:(id)sender object:(id)object { - id result = nil; - NSMethodSignature* signature = [_target methodSignatureForSelector:_action]; - if(signature != nil) { - NSUInteger numberOfArguments = [signature numberOfArguments]; - NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; - if(invocation != nil) { - [invocation setTarget:_target]; - [invocation setSelector:_action]; - if(numberOfArguments > 2) { - if(sender != nil) { - [invocation setArgument:&sender atIndex:2]; - if(object != nil) { - if(numberOfArguments > 3) { - [invocation setArgument:&object atIndex:3]; - } - } - } else { - if(object != nil) { - [invocation setArgument:&object atIndex:2]; - } - } - [invocation retainArguments]; - } - if(_safeThread != nil) { - [self performSelector:@selector(safeFireParams:) onThread:_safeThread withObject:invocation waitUntilDone:YES]; - } else { - [invocation invoke]; - } - if([signature methodReturnLength] == sizeof(id)) { - [invocation getReturnValue:&result]; - } - } - } - return result; -} - -#pragma mark Private - -- (void)safeFireParams:(NSInvocation*)invocation { - [invocation invoke]; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyEventBlock - -#pragma mark Standart - -+ (id)callbackWithBlock:(MobilyEventBlockType)block { - return MOBILY_SAFE_AUTORELEASE([[self alloc] initWithBlock:block queue:nil]); -} - -+ (id)callbackWithBlock:(MobilyEventBlockType)block inMainQueue:(BOOL)inMainQueue { - return MOBILY_SAFE_AUTORELEASE([[self alloc] initWithBlock:block queue:(inMainQueue == YES) ? dispatch_get_main_queue() : nil]); -} - -+ (id)callbackWithBlock:(MobilyEventBlockType)block inCurrentQueue:(BOOL)inCurrentQueue { - return MOBILY_SAFE_AUTORELEASE([[self alloc] initWithBlock:block queue:(inCurrentQueue == YES) ? dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) : nil]); -} - -- (id)initWithBlock:(MobilyEventBlockType)block queue:(dispatch_queue_t)queue { - self = [super init]; - if(self != nil) { - [self setBlock:block]; - [self setSafeQueue:queue]; - } - return self; -} - -- (id)initWithCoder:(NSCoder*)coder { - self = [super init]; - if(self != nil) { - } - return self; -} - -- (void)dealloc { - [self setBlock:nil]; - - MOBILY_SAFE_DEALLOC; -} - -- (void)encodeWithCoder:(NSCoder*)coder { -} - -#pragma mark Public - -- (id)fireSender:(id)sender object:(id)object { - if(_safeQueue != nil) { - dispatch_queue_t currentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); - if(currentQueue != _safeQueue) { - __block id result = nil; - dispatch_async(_safeQueue, ^{ - result = _block(sender, object); - }); - return result; - } - } - return _block(sender, object); -} - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/NS/Core/MobilyHttpQuery.m b/Classes/NS/Core/MobilyHttpQuery.m deleted file mode 100644 index bcd77f9..0000000 --- a/Classes/NS/Core/MobilyHttpQuery.m +++ /dev/null @@ -1,466 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyHttpQuery.h" - -/*--------------------------------------------------*/ - -@interface MobilyHttpQuery () < NSURLConnectionDelegate, NSURLConnectionDataDelegate > - -@property(nonatomic, readwrite, strong) NSURLConnection* connection; -@property(nonatomic, readwrite, strong) NSMutableURLRequest* request; -@property(nonatomic, readwrite, strong) NSHTTPURLResponse* response; -@property(nonatomic, readwrite, strong) NSMutableData* mutableResponseData; - -+ (NSDictionary*)formDataFromDictionary:(NSDictionary*)dictionary; -+ (void)formDataFromDictionary:(NSMutableDictionary*)dictionary value:(id)value keyPath:(NSString*)keyPath; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyHttpQuery - -#pragma mark Builder - -+ (MobilyHttpQuery*)queryWithMethod:(NSString*)method - headers:(NSDictionary*)headers - url:(NSString*)url - body:(id)body { - MobilyHttpQuery* query = [MobilyHttpQuery new]; - if(query != nil) { - NSData* bodyData = nil; - if([body isKindOfClass:[NSDictionary class]] == YES) { - NSMutableString* bodyString = [NSMutableString string]; - if(bodyString != nil) { - NSDictionary* formData = [self formDataFromDictionary:body]; - [formData enumerateKeysAndObjectsUsingBlock:^(NSString* key, id value, BOOL* stop) { - if([bodyString length] > 0) { - [bodyString appendString:@"&"]; - } - [bodyString appendFormat:@"%@=%@", key, [value description]]; - }]; - bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding]; - } - } - [query setRequestMethod:method]; - [query setRequestHeaders:headers]; - [query setRequestUrl:url]; - [query setRequestBody:bodyData]; - } - return query; -} - -+ (MobilyHttpQuery*)queryWithMethod:(NSString*)method - headers:(NSDictionary*)headers - url:(NSString*)url - params:(id)params - attachBoundary:(NSString*)attachBoundary - attachType:(NSString*)attachType - attachKey:(NSString*)attachKey - attachName:(NSString*)attachName - attachData:(NSData*)attachData { - MobilyHttpQuery* query = [MobilyHttpQuery new]; - if(query != nil) { - NSMutableDictionary* mutableHeaders = [NSMutableDictionary dictionaryWithDictionary:headers]; - if(mutableHeaders != nil) { - [mutableHeaders setObject:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", attachBoundary] forKey:@"Content-Type"]; - - NSMutableData* body = [NSMutableData data]; - if(body != nil) { - if([params isKindOfClass:[NSDictionary class]] == YES) { - NSDictionary* formData = [self formDataFromDictionary:params]; - [formData enumerateKeysAndObjectsUsingBlock:^(NSString* key, id value, BOOL* stop) { - [body appendData:[[NSString stringWithFormat:@"--%@\r\n", attachBoundary] dataUsingEncoding:NSUTF8StringEncoding]]; - [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]]; - [body appendData:[[NSString stringWithFormat:@"%@\r\n", [value description]] dataUsingEncoding:NSUTF8StringEncoding]]; - }]; - } - if(attachData != nil) { - [body appendData:[[NSString stringWithFormat:@"--%@\r\n", attachBoundary] dataUsingEncoding:NSUTF8StringEncoding]]; - [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", attachKey, attachName] dataUsingEncoding:NSUTF8StringEncoding]]; - [body appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", attachType] dataUsingEncoding:NSUTF8StringEncoding]]; - [body appendData:attachData]; - [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; - } - [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", attachBoundary] dataUsingEncoding:NSUTF8StringEncoding]]; - - [mutableHeaders setObject:[NSString stringWithFormat:@"%lu", (unsigned long)[body length]] forKey:@"Content-Length"]; - - [query setRequestMethod:@"POST"]; - [query setRequestHeaders:mutableHeaders]; - [query setRequestUrl:url]; - [query setRequestBody:body]; - } - } - } - return query;} - -#pragma mark Standart - -- (id)init { - self = [super init]; - if(self != nil) { - _request = MOBILY_SAFE_RETAIN([NSMutableURLRequest new]); - [_request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData]; - [_request setNetworkServiceType:NSURLNetworkServiceTypeDefault]; - } - return self; -} - -- (void)dealloc { - [self cancel]; - - [self setCertificateFilename:nil]; - [self setRequest:nil]; - [self setResponse:nil]; - [self setMutableResponseData:nil]; - [self setLastError:nil]; - [self setStartCallback:nil]; - [self setCancelCallback:nil]; - [self setFinishCallback:nil]; - [self setErrorCallback:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark Public - -- (void)addRequestHeader:(NSString*)header value:(NSString*)value { - [_request setValue:value forHTTPHeaderField:header]; -} - -- (void)removeRequestHeader:(NSString*)header { - NSMutableDictionary* headers = [NSMutableDictionary dictionaryWithDictionary:[_request allHTTPHeaderFields]]; - if(headers != nil) { - [headers removeObjectForKey:header]; - [_request setAllHTTPHeaderFields:headers]; - } -} - -- (void)start { - if(_connection == nil) { - [self setResponse:nil]; - [self setMutableResponseData:nil]; - [self setLastError:nil]; - - _connection = MOBILY_SAFE_RETAIN([[NSURLConnection alloc] initWithRequest:_request delegate:self startImmediately:NO]); - if(_connection != nil) { - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; - - [_connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; - [_connection start]; - - if(_startCallback != nil) { - _startCallback(self); - } - - [[NSRunLoop currentRunLoop] run]; - } - } -} - -- (void)cancel { - if(_connection != nil) { - [_connection cancel]; - - [self setConnection:nil]; - [self setResponse:nil]; - [self setMutableResponseData:nil]; - [self setLastError:nil]; - - if(_cancelCallback != nil) { - _cancelCallback(self); - } - - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; - } -} - -#pragma mark Property - -- (void)setRequestUrl:(NSString*)requestUrl { - [_request setURL:[NSURL URLWithString:requestUrl]]; -} - -- (NSString*)requestUrl { - return [[_request URL] absoluteString]; -} - -- (void)setRequestTimeout:(NSTimeInterval)requestTimeout { - [_request setTimeoutInterval:requestTimeout]; -} - -- (NSTimeInterval)requestTimeout { - return [_request timeoutInterval]; -} - -- (void)setRequestMethod:(NSString*)requestMethod { - [_request setHTTPMethod:requestMethod]; -} - -- (NSString*)requestMethod { - return [_request HTTPMethod]; -} - -- (void)setRequestHeaders:(NSDictionary*)requestHeaders { - [_request setAllHTTPHeaderFields:requestHeaders]; -} - -- (NSDictionary*)requestHeaders { - return [_request allHTTPHeaderFields]; -} - -- (void)setRequestBody:(NSData*)requestBody { - [_request setHTTPBody:requestBody]; -} - -- (NSData*)requestBody { - return [_request HTTPBody]; -} - -- (NSInteger)responseStatusCode { - return [_response statusCode]; -} - -- (NSString*)responseMimeType { - return [_response MIMEType]; -} - -- (NSString*)responseTextEncoding { - return [_response textEncodingName]; -} - -- (NSDictionary*)responseHeaders { - return [_response allHeaderFields]; -} - -- (NSData*)responseData { - return _mutableResponseData; -} - -- (NSString*)responseString { - return [NSString stringWithData:_mutableResponseData encoding:NSASCIIStringEncoding]; -} - -- (NSDictionary*)responseJsonObject { - id json = [self responseJson]; - if([json isKindOfClass:[NSDictionary class]] == YES) { - return json; - } - return nil; -} - -- (NSArray*)responseJsonArray { - id json = [self responseJson]; - if([json isKindOfClass:[NSArray class]] == YES) { - return json; - } - return nil; -} - -- (id)responseJson { - if([_mutableResponseData length] < 1) { - return nil; - } - NSError* error = nil; - id result = [NSJSONSerialization JSONObjectWithData:_mutableResponseData options:0 error:&error]; - if(error != nil) { - [self setLastError:error]; - } - return result; -} - -#pragma mark Private - -+ (NSDictionary*)formDataFromDictionary:(NSDictionary*)dictionary { - NSMutableDictionary* result = [NSMutableDictionary dictionary]; - [dictionary enumerateKeysAndObjectsUsingBlock:^(id keyPath, id value, BOOL* stop) { - [self formDataFromDictionary:result value:value keyPath:keyPath]; - }]; - return result; -} - -+ (void)formDataFromDictionary:(NSMutableDictionary*)dictionary value:(id)value keyPath:(NSString*)keyPath { - if([value isKindOfClass:[NSDictionary class]] == YES) { - [value enumerateKeysAndObjectsUsingBlock:^(id dictKey, id dictValue, BOOL* stop) { - [self formDataFromDictionary:dictionary value:dictValue keyPath:[NSString stringWithFormat:@"%@[%@]", keyPath, dictKey]]; - }]; - } else if([value isKindOfClass:[NSArray class]] == YES) { - [value enumerateObjectsUsingBlock:^(id arrayValue, NSUInteger arrayIndex, BOOL* stop) { - [self formDataFromDictionary:dictionary value:arrayValue keyPath:[NSString stringWithFormat:@"%@[%lu]", keyPath, (unsigned long)arrayIndex]]; - }]; - } else if([value isKindOfClass:[NSString class]] == YES) { - value = [value stringByEncodingURLFormat]; - if(value != nil) { - [dictionary setObject:value forKey:keyPath]; - } - } else { - [dictionary setObject:value forKey:keyPath]; - } -} - -#pragma mark NSURLConnectionDelegate - -- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error { - [self setConnection:nil]; - [self setResponse:nil]; - [self setMutableResponseData:nil]; - [self setLastError:error]; - - if(_errorCallback != nil) { - _errorCallback(self); - } - - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; -} - -- (void)connection:(NSURLConnection*)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge*)challenge { - id< NSURLAuthenticationChallengeSender > sender = [challenge sender]; - SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust]; - SecCertificateRef localCertificate = NULL; - - SecTrustResultType serverTrustResult = kSecTrustResultOtherError; - if(_certificateFilename != nil) { - NSString* path = [[NSBundle mainBundle] pathForResource:_certificateFilename ofType:@"der"]; - if(path != nil) { - NSData* data = [NSData dataWithContentsOfFile:path]; - if(data != nil) { - localCertificate = SecCertificateCreateWithData(NULL, (__bridge_retained CFDataRef)data); - if(localCertificate != NULL) { - CFArrayRef certArray = CFArrayCreate(NULL, (void*)&localCertificate, 1, NULL); - if(certArray != NULL) { - SecTrustSetAnchorCertificates(serverTrust, certArray); - SecTrustEvaluate(serverTrust, &serverTrustResult); - if(serverTrustResult == kSecTrustResultRecoverableTrustFailure) { - CFDataRef errorData = SecTrustCopyExceptions(serverTrust); - SecTrustSetExceptions(serverTrust, errorData); - SecTrustEvaluate(serverTrust, &serverTrustResult); - } - CFRelease(certArray); - } - } - } - } - } - if((serverTrustResult == kSecTrustResultUnspecified) || (serverTrustResult == kSecTrustResultProceed)) { - SecCertificateRef serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0); - if(serverCertificate != NULL) { - NSString* serverHash = nil; - NSData* serverCertificateData = (__bridge NSData*)SecCertificateCopyData(serverCertificate); - if(serverCertificateData != nil) { - serverHash = [[serverCertificateData toBase64] stringBySHA256]; - } - NSString* localHash = nil; - NSData* localCertificateData = (__bridge NSData*)SecCertificateCopyData(localCertificate); - if(localCertificateData != nil) { - localHash = [[localCertificateData toBase64] stringBySHA256]; - } - if([serverHash isEqualToString:localHash] == YES) { - NSURLCredential* credential = [NSURLCredential credentialForTrust:serverTrust]; - if(credential != nil) { - [sender useCredential:credential forAuthenticationChallenge:challenge]; - } else { - [sender cancelAuthenticationChallenge:challenge]; - } - } else { - [sender cancelAuthenticationChallenge:challenge]; - } - } else { - [sender cancelAuthenticationChallenge:challenge]; - } - } else { - [sender cancelAuthenticationChallenge:challenge]; - } - if(localCertificate != NULL) { - CFRelease(localCertificate); - } -} - -#pragma mark NSURLConnectionDataDelegate - -- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response { - if([response isKindOfClass:[NSHTTPURLResponse class]] == YES) { - _response = MOBILY_SAFE_RETAIN((NSHTTPURLResponse*)response); - } -} - -- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { - if(_mutableResponseData == nil) { - [self setMutableResponseData:[NSMutableData data]]; - } - [_mutableResponseData appendData:data]; -} - -- (void)connectionDidFinishLoading:(NSURLConnection*)connection { - [self setConnection:nil]; - - if(_finishCallback != nil) { - _finishCallback(self); - } - - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyTaskHttpQuery - -#pragma mark Standart - -- (void)dealloc { - [self setHttpQuery:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark Public - -- (void)cancel { - if(_httpQuery != nil) { - [_httpQuery cancel]; - } - [super cancel]; -} - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/NS/Core/MobilyNS.h b/Classes/NS/Core/MobilyNS.h deleted file mode 100644 index e77480e..0000000 --- a/Classes/NS/Core/MobilyNS.h +++ /dev/null @@ -1,186 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyCore.h" - -/*--------------------------------------------------*/ - -#define MOBILY_MINUTE 60.0f -#define MOBILY_HOUR (60.0f * MOBILY_MINUTE) -#define MOBILY_DAY (24.0f * MOBILY_HOUR) -#define MOBILY_5_DAYS (5.0f * MOBILY_DAY) -#define MOBILY_WEEK (7.0f * MOBILY_DAY) -#define MOBILY_MONTH (30.5f * MOBILY_DAY) -#define MOBILY_YEAR (365.0f * MOBILY_DAY) - -/*--------------------------------------------------*/ - -@interface NSDate (MobilyNS) - -+ (NSDate*)dateOffsetYears:(NSInteger)years months:(NSInteger)months days:(NSInteger)days toDate:(NSDate*)date; -+ (NSDate*)dateOffsetHours:(NSInteger)hours minutes:(NSInteger)minutes seconds:(NSInteger)secconds toDate:(NSDate*)date; -+ (NSDate*)dateOffsetYears:(NSInteger)years months:(NSInteger)months days:(NSInteger)days hours:(NSInteger)hours minutes:(NSInteger)minutes seconds:(NSInteger)secconds toDate:(NSDate*)date; - -- (NSString*)formatTime; -- (NSString*)formatDate; -- (NSString*)formatShortTime; -- (NSString*)formatDateTime; -- (NSString*)formatRelativeTime; -- (NSString*)formatShortRelativeTime; - -+ (NSDate*)dateFromIso8601:(NSString*)iso8601; -- (NSString*)iso8601; - -+ (NSDate*)dateWithUnixTimestamp:(NSUInteger)timestamp; -- (NSUInteger)unixTimestamp; - -@end - -/*--------------------------------------------------*/ - -@interface NSData (MobilyNS) - -- (NSString*)toHex; - -- (NSString*)toBase64; - -@end - -/*--------------------------------------------------*/ - -@interface NSString (MobilyNS) - -+ (id)stringWithData:(NSData*)data encoding:(NSStringEncoding)encoding; - -- (NSString*)stringByUppercaseFirstCharacterString; -- (NSString*)stringByLowercaseFirstCharacterString; - -- (NSString*)stringByMD5; -- (NSString*)stringBySHA256; - -- (NSString*)stringByDecodingURLFormat; -- (NSString*)stringByEncodingURLFormat; -- (NSMutableDictionary*)dictionaryFromQueryComponents; - -- (BOOL)isEmail; - -- (NSData*)HMACSHA1:(NSString*)key; - -- (BOOL)convertToBool; -- (NSNumber*)convertToNumber; -- (NSDate*)convertToDateWithFormat:(NSString*)format; - -- (NSTextAlignment)convertToTextAlignment; -- (NSLineBreakMode)convertToLineBreakMode; - -@end - -/*--------------------------------------------------*/ - -@interface NSArray (MobilyNS) - -+ (instancetype)arrayWithArray:(NSArray*)array andAddingObject:(id)object; -+ (instancetype)arrayWithArray:(NSArray*)array andAddingObjectsFromArray:(NSArray*)addingObjects; -+ (instancetype)arrayWithArray:(NSArray*)array andRemovingObject:(id)object; -+ (instancetype)arrayWithArray:(NSArray*)array andRemovingObjectsInArray:(NSArray*)removingObjects; - -- (NSArray*)arrayByReplaceObject:(id)object atIndex:(NSUInteger)index; - -- (NSArray*)arrayByRemovedObject:(id)object; -- (NSArray*)arrayByRemovedObjectsFromArray:(NSArray*)array; - -- (NSArray*)arrayByObjectClass:(Class)objectClass; -- (NSArray*)arrayByObjectProtocol:(Protocol*)objectProtocol; - -- (id)firstObjectIsClass:(Class)objectClass; -- (id)lastObjectIsClass:(Class)objectClass; - -- (id)firstObjectIsProtocol:(Protocol*)objectProtocol; -- (id)lastObjectIsProtocol:(Protocol*)objectProtocol; - -- (NSUInteger)nextIndexOfObject:(id)object; -- (NSUInteger)prevIndexOfObject:(id)object; - -- (id)nextObjectOfObject:(id)object; -- (id)prevObjectOfObject:(id)object; - -- (void)enumerateObjectsAtRange:(NSRange)range options:(NSEnumerationOptions)options usingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block NS_AVAILABLE(10_6, 4_0); - -@end - -/*--------------------------------------------------*/ - -@interface NSMutableArray (MobilyNS) - -- (void)removeFirstObjectsByCount:(NSUInteger)count; -- (void)removeLastObjectsByCount:(NSUInteger)count; - -@end - -/*--------------------------------------------------*/ - -@interface NSDictionary (MobilyNS) - -- (NSString*)stringFromQueryComponents; - -@end - -/*--------------------------------------------------*/ - -@interface NSURL (MobilyNS) - -- (NSMutableDictionary*)queryComponents; -- (NSMutableDictionary*)fragmentComponents; - -@end - -/*--------------------------------------------------*/ - -@interface NSFileManager (MobilyNS) - -+ (NSString*)documentDirectory; -+ (NSString*)cachesDirectory; - -@end - -/*--------------------------------------------------*/ - -@interface NSHTTPCookieStorage (MobilyNS) - -+ (void)clearCookieWithDomain:(NSString*)domain; - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/NS/Core/MobilyNS.m b/Classes/NS/Core/MobilyNS.m deleted file mode 100644 index 03e66b3..0000000 --- a/Classes/NS/Core/MobilyNS.m +++ /dev/null @@ -1,702 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyNS.h" - -/*--------------------------------------------------*/ - -#import -#import - -/*--------------------------------------------------*/ - -@implementation NSDate (MobilyNS) - -+ (NSDate*)dateOffsetYears:(NSInteger)years months:(NSInteger)months days:(NSInteger)days toDate:(NSDate*)date { - NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; - NSDateComponents* component = [[NSDateComponents alloc] init]; - [component setYear:years]; - [component setMonth:months]; - [component setDay:days]; - return [calendar dateByAddingComponents:component toDate:date options:0]; -} - -+ (NSDate*)dateOffsetHours:(NSInteger)hours minutes:(NSInteger)minutes seconds:(NSInteger)secconds toDate:(NSDate*)date { - NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; - NSDateComponents* component = [[NSDateComponents alloc] init]; - [component setHour:hours]; - [component setMinute:minutes]; - [component setSecond:secconds]; - return [calendar dateByAddingComponents:component toDate:date options:0]; -} - -+ (NSDate*)dateOffsetYears:(NSInteger)years months:(NSInteger)months days:(NSInteger)days hours:(NSInteger)hours minutes:(NSInteger)minutes seconds:(NSInteger)secconds toDate:(NSDate*)date { - NSCalendar* calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; - NSDateComponents* component = [[NSDateComponents alloc] init]; - [component setYear:years]; - [component setMonth:months]; - [component setDay:days]; - [component setHour:hours]; - [component setMinute:minutes]; - [component setSecond:secconds]; - return [calendar dateByAddingComponents:component toDate:date options:0]; -} - -- (NSString*)formatTime { - static NSDateFormatter* formatter = nil; - if(formatter == nil) { - formatter = [[NSDateFormatter alloc] init]; - [formatter setDateFormat:NSLocalizedString(@"h:mm a", @"Date format: 1:05 pm")]; - [formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:NSLocalizedString(@"en_EN", @"Current locale")]]; - [formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; - } - return [formatter stringFromDate:self]; -} - -- (NSString*)formatDate { - static NSDateFormatter* formatter = nil; - if(formatter == nil) { - formatter = [[NSDateFormatter alloc] init]; - [formatter setDateFormat:NSLocalizedString(@"EEEE, LLLL d, YYYY", @"Date format: Monday, July 27, 2009")]; - [formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:NSLocalizedString(@"en_EN", @"Current locale")]]; - [formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; - } - return [formatter stringFromDate:self]; -} - -- (NSString*)formatShortTime { - NSTimeInterval diff = abs([self timeIntervalSinceNow]); - - if(diff < MOBILY_DAY) { - return [self formatTime]; - } else if(diff < MOBILY_5_DAYS) { - static NSDateFormatter* formatter = nil; - if(formatter == nil) { - formatter = [[NSDateFormatter alloc] init]; - [formatter setDateFormat:NSLocalizedString(@"EEEE", @"Date format: Monday")]; - [formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:NSLocalizedString(@"en_EN", @"Current locale")]]; - [formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; - } - return [formatter stringFromDate:self]; - } else { - static NSDateFormatter* formatter = nil; - if(formatter == nil) { - formatter = [[NSDateFormatter alloc] init]; - [formatter setDateFormat:NSLocalizedString(@"M/d/yy", @"Date format: 7/27/09") ]; - [formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:NSLocalizedString(@"en_EN", @"Current locale")]]; - [formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; - } - return [formatter stringFromDate:self]; - } -} - -- (NSString*)formatDateTime { - NSTimeInterval diff = abs([self timeIntervalSinceNow]); - - if(diff < MOBILY_DAY) { - return [self formatTime]; - } else if(diff < MOBILY_5_DAYS) { - static NSDateFormatter* formatter = nil; - if(formatter == nil) { - formatter = [[NSDateFormatter alloc] init]; - [formatter setDateFormat:NSLocalizedString(@"EEE h:mm a", @"Date format: Mon 1:05 pm")]; - [formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:NSLocalizedString(@"en_EN", @"Current locale")]]; - [formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; - } - return [formatter stringFromDate:self]; - } else { - static NSDateFormatter* formatter = nil; - if(formatter == nil) { - formatter = [[NSDateFormatter alloc] init]; - [formatter setDateFormat:NSLocalizedString(@"MMM d h:mm a", @"Date format: Jul 27 1:05 pm")]; - [formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:NSLocalizedString(@"en_EN", @"Current locale")]]; - [formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; - } - return [formatter stringFromDate:self]; - } -} - -- (NSString*)formatRelativeTime { - NSTimeInterval elapsed = abs([self timeIntervalSinceNow]); - - if(elapsed <= 1.0f) { - return NSLocalizedString(@"just a moment ago", @""); - } else if(elapsed < MOBILY_MINUTE) { - int seconds = (int)(elapsed); - return [NSString stringWithFormat:NSLocalizedString(@"%d seconds ago", @""), seconds]; - } else if(elapsed < 2.0f * MOBILY_MINUTE) { - return NSLocalizedString(@"about a minute ago", @""); - } else if(elapsed < MOBILY_HOUR) { - int mins = (int)(elapsed / MOBILY_MINUTE); - return [NSString stringWithFormat:NSLocalizedString(@"%d minutes ago", @""), mins]; - } else if(elapsed < MOBILY_HOUR * 1.5f) { - return NSLocalizedString(@"about an hour ago", @""); - } else if(elapsed < MOBILY_DAY) { - int hours = (int)((elapsed + MOBILY_HOUR * 0.5f) / MOBILY_HOUR); - return [NSString stringWithFormat:NSLocalizedString(@"%d hours ago", @""), hours]; - } else { - return [self formatDateTime]; - } -} - -- (NSString*)formatShortRelativeTime { - NSTimeInterval elapsed = abs([self timeIntervalSinceNow]); - - if(elapsed < MOBILY_MINUTE) { - return NSLocalizedString(@"<1m", @"Date format: less than one minute ago"); - } else if(elapsed < MOBILY_HOUR) { - int mins = (int)(elapsed / MOBILY_MINUTE); - return [NSString stringWithFormat:NSLocalizedString(@"%dm", @"Date format: 50m"), mins]; - } else if(elapsed < MOBILY_DAY) { - int hours = (int)((elapsed + MOBILY_HOUR / 2) / MOBILY_HOUR); - return [NSString stringWithFormat:NSLocalizedString(@"%dh", @"Date format: 3h"), hours]; - } else if(elapsed < MOBILY_WEEK) { - int day = (int)((elapsed + MOBILY_DAY / 2) / MOBILY_DAY); - return [NSString stringWithFormat:NSLocalizedString(@"%dd", @"Date format: 3d"), day]; - } else { - return [self formatShortTime]; - } -} - -+ (NSDateFormatter*)dateFormatterWithIso8601 { - static NSDateFormatter* formatter = nil; - if(formatter == nil) { - formatter = [[NSDateFormatter alloc] init]; - [formatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'SSS'Z'"]; - [formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:NSLocalizedString(@"en_EN", @"Current locale")]]; - [formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; - } - return formatter; -} - -+ (NSDate*)dateFromIso8601:(NSString*)iso8601 { - return [[self dateFormatterWithIso8601] dateFromString:iso8601]; -} - -- (NSString*)iso8601 { - return [[NSDate dateFormatterWithIso8601] stringFromDate:self]; -} - -+ (NSDate*)dateWithUnixTimestamp:(NSUInteger)timestamp { - return [NSDate dateWithTimeIntervalSince1970:timestamp]; -} - -- (NSUInteger)unixTimestamp { - return (NSUInteger)[self timeIntervalSince1970]; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -static char NSDataBase64Table[] = "ABCDEMHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; - -/*--------------------------------------------------*/ - -@implementation NSData (MobilyNS) - -- (NSString*)toHex { - NSUInteger length = [self length]; - unsigned char* bytes = (unsigned char*)[self bytes]; - NSMutableString* hex = [NSMutableString stringWithCapacity:[self length]]; - for(NSUInteger i = 0; i < length; i++) { - [hex appendFormat:@"%02X", bytes[i]]; - } - return hex; -} - -- (NSString*)toBase64 { - NSData* data = [NSData dataWithBytes:[self bytes] length:[self length]]; - const uint8_t* input = (const uint8_t*)[data bytes]; - NSInteger length = [data length]; - - NSMutableData* result = [NSMutableData dataWithLength:((length + 2) / 3) * 4]; - uint8_t* output = (uint8_t*)[result mutableBytes]; - - for(NSInteger i = 0; i < length; i += 3) { - NSInteger value = 0; - for(NSInteger j = i; j < (i + 3); j++) { - value <<= 8; - if(j < length) { - value |= (0xFF & input[j]); - } - } - NSInteger index = (i / 3) * 4; - output[index + 0] = NSDataBase64Table[(value >> 18) & 0x3F]; - output[index + 1] = NSDataBase64Table[(value >> 12) & 0x3F]; - output[index + 2] = (i + 1) < length ? NSDataBase64Table[(value >> 6) & 0x3F] : '='; - output[index + 3] = (i + 2) < length ? NSDataBase64Table[(value >> 0) & 0x3F] : '='; - } - return MOBILY_SAFE_AUTORELEASE([[NSString alloc] initWithData:result encoding:NSASCIIStringEncoding]); -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation NSString (MobilyNS) - -+ (id)stringWithData:(NSData*)data encoding:(NSStringEncoding)encoding { - return MOBILY_SAFE_AUTORELEASE([[self alloc] initWithData:data encoding:encoding]); -} - -- (NSString*)stringByUppercaseFirstCharacterString { - if([self length] > 0) { - return [[[self substringToIndex:1] uppercaseString] stringByAppendingString:[self substringFromIndex:1]]; - } - return [NSString string]; -} - -- (NSString*)stringByLowercaseFirstCharacterString { - if([self length] > 0) { - return [[[self substringToIndex:1] lowercaseString] stringByAppendingString:[self substringFromIndex:1]]; - } - return [NSString string]; -} - -- (NSString*)stringByMD5 { - unsigned char result[16]; - const char* string = [self UTF8String]; - CC_MD5(string, (CC_LONG)strlen(string), result); - return [[NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7], result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15]] lowercaseString]; -} - -- (NSString*)stringBySHA256 { - unsigned char result[CC_SHA256_DIGEST_LENGTH]; - const char* string = [self UTF8String]; - CC_SHA256(string, (CC_LONG)strlen(string), result); - return [[NSString stringWithFormat: @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7], result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15], result[16], result[17], result[18], result[19], result[20], result[21], result[22], result[23], result[24], result[25], result[26], result[27], result[28], result[29], result[30], result[31]] lowercaseString]; -} - -- (NSString*)stringByDecodingURLFormat { - NSString* result = nil; - CFStringRef string = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL, MOBILY_SAFE_BRIDGE(CFStringRef, self), CFSTR(""), kCFStringEncodingUTF8); - if(string != nil) { - result = [NSString stringWithString:MOBILY_SAFE_BRIDGE(NSString*, string)]; - CFRelease(string); - } - return result; -} - -- (NSString*)stringByEncodingURLFormat { - NSString* result = nil; - CFStringRef string = CFURLCreateStringByAddingPercentEscapes(NULL, MOBILY_SAFE_BRIDGE(CFStringRef, self), NULL, CFSTR("!*'();:@&=+$,/?%#[]"), kCFStringEncodingUTF8); - if(string != nil) { - result = [NSString stringWithString:MOBILY_SAFE_BRIDGE(NSString*, string)]; - CFRelease(string); - } - return result; -} - -- (NSMutableDictionary*)dictionaryFromQueryComponents { - NSMutableDictionary* queryComponents = [NSMutableDictionary dictionary]; - for(NSString* keyValuePairString in [self componentsSeparatedByString:@"&"]) { - NSArray* keyValuePairArray = [keyValuePairString componentsSeparatedByString:@"="]; - if([keyValuePairArray count] < 2) { - continue; - } - NSString* key = [[keyValuePairArray objectAtIndex:0] stringByDecodingURLFormat]; - NSString* value = [[keyValuePairArray objectAtIndex:1] stringByDecodingURLFormat]; - NSMutableArray* results = [queryComponents objectForKey:key]; - if(results == nil) { - results = [NSMutableArray arrayWithCapacity:1]; - [queryComponents setObject:results forKey:key]; - } - [results addObject:value]; - } - return queryComponents; -} - -- (BOOL)isEmail { - static NSPredicate* predicate = nil; - if(predicate == nil) { - predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES[c] %@", @"(?:[a-z0-9!#$%\\&'*+/=?\\^_`{|}~-]+(?:\\.[a-z0-9!#$%\\&'*+/=?\\^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"]; - } - return [predicate evaluateWithObject:self]; -} - -- (NSData*)HMACSHA1:(NSString*)key { - const char* cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; - const char* cData = [self cStringUsingEncoding:NSASCIIStringEncoding]; - unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH]; - CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC); - return [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)]; -} - -- (BOOL)convertToBool { - if(([self isEqualToString:@"yes"] == YES) || ([self isEqualToString:@"true"] == YES)) { - return YES; - } - return NO; -} - -- (NSNumber*)convertToNumber { - static NSNumberFormatter* formatter = nil; - if(formatter == nil) { - formatter = [NSNumberFormatter new]; - [formatter setNumberStyle:NSNumberFormatterDecimalStyle]; - } - return [formatter numberFromString:self]; -} - -- (NSDate*)convertToDateWithFormat:(NSString*)format { - static NSDateFormatter* formatter = nil; - if(formatter == nil) { - formatter = [NSDateFormatter new]; - } - [formatter setDateFormat:format]; - return [formatter dateFromString:self]; -} - -- (NSTextAlignment)convertToTextAlignment { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"left"] == YES) { - return NSTextAlignmentLeft; - } else if([temp isEqualToString:@"center"] == YES) { - return NSTextAlignmentCenter; - } else if([temp isEqualToString:@"right"] == YES) { - return NSTextAlignmentRight; - } else if([temp isEqualToString:@"justified"] == YES) { - return NSTextAlignmentJustified; - } else if([temp isEqualToString:@"natural"] == YES) { - return NSTextAlignmentNatural; - } - return NSTextAlignmentLeft; -} - -- (NSLineBreakMode)convertToLineBreakMode { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"word-wrap"] == YES) { - return NSLineBreakByWordWrapping; - } else if([temp isEqualToString:@"char-wrap"] == YES) { - return NSLineBreakByCharWrapping; - } else if([temp isEqualToString:@"clip"] == YES) { - return NSLineBreakByClipping; - } else if([temp isEqualToString:@"truncate-head"] == YES) { - return NSLineBreakByTruncatingHead; - } else if([temp isEqualToString:@"truncate-middle"] == YES) { - return NSLineBreakByTruncatingMiddle; - } else if([temp isEqualToString:@"truncate-tail"] == YES) { - return NSLineBreakByTruncatingTail; - } - return NSLineBreakByWordWrapping; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation NSArray (MobilyNS) - -+ (instancetype)arrayWithArray:(NSArray*)array andAddingObject:(id)object { - NSMutableArray* result = [NSMutableArray arrayWithArray:array]; - [result addObject:object]; - return [NSArray arrayWithArray:result]; -} - -+ (instancetype)arrayWithArray:(NSArray*)array andAddingObjectsFromArray:(NSArray*)addingObjects { - NSMutableArray* result = [NSMutableArray arrayWithArray:array]; - [result addObjectsFromArray:addingObjects]; - return [NSArray arrayWithArray:result]; -} - -+ (instancetype)arrayWithArray:(NSArray*)array andRemovingObject:(id)object { - NSMutableArray* result = [NSMutableArray arrayWithArray:array]; - [result removeObject:object]; - return [NSArray arrayWithArray:result]; -} - -+ (instancetype)arrayWithArray:(NSArray*)array andRemovingObjectsInArray:(NSArray*)removingObjects { - NSMutableArray* result = [NSMutableArray arrayWithArray:array]; - [result removeObjectsInArray:removingObjects]; - return [NSArray arrayWithArray:result]; -} - -- (NSArray*)arrayByReplaceObject:(id)object atIndex:(NSUInteger)index { - NSMutableArray* result = [NSMutableArray arrayWithArray:self]; - [result replaceObjectAtIndex:index withObject:object]; - return [NSArray arrayWithArray:result]; -} - -- (NSArray*)arrayByRemovedObject:(id)object { - NSMutableArray* result = [NSMutableArray arrayWithArray:self]; - [result removeObject:object]; - return [NSArray arrayWithArray:result]; -} - -- (NSArray*)arrayByRemovedObjectsFromArray:(NSArray*)array { - NSMutableArray* result = [NSMutableArray arrayWithArray:self]; - [result removeObjectsInArray:array]; - return [NSArray arrayWithArray:result]; -} - -- (NSArray*)arrayByObjectClass:(Class)objectClass { - NSMutableArray* result = [NSMutableArray array]; - [self enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) { - if([object isKindOfClass:objectClass] == YES) { - [result addObject:object]; - } - }]; - return [NSArray arrayWithArray:result]; -} - -- (NSArray*)arrayByObjectProtocol:(Protocol*)objectProtocol { - NSMutableArray* result = [NSMutableArray array]; - [self enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) { - if([object conformsToProtocol:objectProtocol] == YES) { - [result addObject:object]; - } - }]; - return [NSArray arrayWithArray:result]; -} - -- (id)firstObjectIsClass:(Class)objectClass { - __block id result = nil; - [self enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) { - if([object isKindOfClass:objectClass] == YES) { - result = object; - *stop = YES; - } - }]; - return result; -} - -- (id)lastObjectIsClass:(Class)objectClass { - __block id result = nil; - [self enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id object, NSUInteger index, BOOL *stop) { - if([object isKindOfClass:objectClass] == YES) { - result = object; - *stop = YES; - } - }]; - return result; -} - -- (id)firstObjectIsProtocol:(Protocol*)objectProtocol { - __block id result = nil; - [self enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL *stop) { - if([object conformsToProtocol:objectProtocol] == YES) { - result = object; - *stop = YES; - } - }]; - return result; -} - -- (id)lastObjectIsProtocol:(Protocol*)objectProtocol { - __block id result = nil; - [self enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id object, NSUInteger index, BOOL *stop) { - if([object conformsToProtocol:objectProtocol] == YES) { - result = object; - *stop = YES; - } - }]; - return result; -} - -- (NSUInteger)nextIndexOfObject:(id)object { - NSUInteger index = [self indexOfObject:object]; - if(index != NSNotFound) { - if(index == [self count] - 1) { - index = NSNotFound; - } else { - index++; - } - } - return index; -} - -- (NSUInteger)prevIndexOfObject:(id)object { - NSUInteger index = [self indexOfObject:object]; - if(index != NSNotFound) { - if(index == 0) { - index = NSNotFound; - } else { - index--; - } - } - return index; -} - -- (id)nextObjectOfObject:(id)object { - NSUInteger index = [self indexOfObject:object]; - if(index != NSNotFound) { - if(index < [self count] - 1) { - return [self objectAtIndex:index + 1]; - } - } - return nil; -} - -- (id)prevObjectOfObject:(id)object { - NSUInteger index = [self indexOfObject:object]; - if(index != NSNotFound) { - if(index != 0) { - return [self objectAtIndex:index - 1]; - } - } - return nil; -} - -- (void)enumerateObjectsAtRange:(NSRange)range options:(NSEnumerationOptions)options usingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block { - [self enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range] options:options usingBlock:block]; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation NSMutableArray (MobilyNS) - -- (void)removeFirstObjectsByCount:(NSUInteger)count { - [self removeObjectsInRange:NSMakeRange(0, count)]; -} - -- (void)removeLastObjectsByCount:(NSUInteger)count { - [self removeObjectsInRange:NSMakeRange(([self count] - 1) - count, count)]; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation NSDictionary (MobilyNS) - -- (NSString*)stringFromQueryComponents { - NSString* result = nil; - for(NSString* dictKey in [self allKeys]) { - NSString* key = [dictKey stringByEncodingURLFormat]; - NSArray* allValues = [self objectForKey:key]; - if([allValues isKindOfClass:[NSArray class]]) { - for(NSString* dictValue in allValues) { - NSString* value = [[dictValue description] stringByEncodingURLFormat]; - if(result == nil) { - result = [NSString stringWithFormat:@"%@=%@",key,value]; - } else { - result = [result stringByAppendingFormat:@"&%@=%@",key,value]; - } - } - } else { - NSString* value = [[allValues description] stringByEncodingURLFormat]; - if(result == nil) { - result = [NSString stringWithFormat:@"%@=%@",key,value]; - } else { - result = [result stringByAppendingFormat:@"&%@=%@",key,value]; - } - } - } - return result; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation NSURL (MobilyNS) - -- (NSMutableDictionary*)queryComponents { - return [[self query] dictionaryFromQueryComponents]; -} - -- (NSMutableDictionary*)fragmentComponents { - return [[self fragment] dictionaryFromQueryComponents]; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation NSFileManager (MobilyNS) - -+ (NSString*)documentDirectory { - static NSString* result = nil; - if(result == nil) { - NSArray* directories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); - if([directories count] > 0) { - result = [directories firstObject]; - } - } - return result; -} - -+ (NSString*)cachesDirectory { - static NSString* result = nil; - if(result == nil) { - NSArray* directories = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); - if([directories count] > 0) { - result = [directories firstObject]; - } - } - return result; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation NSHTTPCookieStorage (MobilyNS) - -+ (void)clearCookieWithDomain:(NSString*)domain { - NSHTTPCookieStorage* storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; - if(storage != nil) { - for(NSHTTPCookie* cookie in [storage cookies]) { - NSRange range = [[cookie domain] rangeOfString:domain]; - if(range.length > 0) { - [storage deleteCookie:cookie]; - } - } - [[NSUserDefaults standardUserDefaults] synchronize]; - } -} - -@end - -/*--------------------------------------------------*/ \ No newline at end of file diff --git a/Classes/NS/Core/MobilyStorage.h b/Classes/NS/Core/MobilyStorage.h deleted file mode 100644 index 0408767..0000000 --- a/Classes/NS/Core/MobilyStorage.h +++ /dev/null @@ -1,273 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyNS.h" - -/*--------------------------------------------------*/ - -typedef void (^MobilyStorageItemBlock)(); - -/*--------------------------------------------------*/ - -@interface MobilyStorageItem : NSObject < NSCoding, NSCopying > - -@property(nonatomic, readwrite, strong) NSString* userDefaultsKey; - -- (id)initWithUserDefaultsKey:(NSString*)userDefaultsKey; -- (id)initWithJson:(id)json; - -- (void)setupItem; - -+ (NSArray*)propertyMap; -+ (NSDictionary*)jsonMap; - -- (void)convertFromJson:(id)json; - -- (void)clearItem; -- (void)clearItemComplete:(MobilyStorageItemBlock)complete; - -- (BOOL)saveItem; -- (void)saveItemSuccess:(MobilyStorageItemBlock)success failure:(MobilyStorageItemBlock)failure; - -- (void)loadItem; -- (void)loadItemComplete:(MobilyStorageItemBlock)complete; - -@end - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverter : NSObject - -@property(nonatomic, readonly, strong) NSString* path; - -- (id)initWithPath:(NSString*)path; - -- (id)parseJson:(id)json; - -- (id)convertValue:(id)value; - -@end - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterArray : MobilyStorageJsonConverter - -@property(nonatomic, readonly, strong) MobilyStorageJsonConverter* jsonConverter; - -- (id)initWithJsonConverter:(MobilyStorageJsonConverter*)jsonConverter; -- (id)initWithPath:(NSString*)path jsonConverter:(MobilyStorageJsonConverter*)jsonConverter; - -@end - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterDictionary : MobilyStorageJsonConverter - -@property(nonatomic, readonly, strong) MobilyStorageJsonConverter* jsonConverter; - -- (id)initWithJsonConverter:(MobilyStorageJsonConverter*)jsonConverter; -- (id)initWithPath:(NSString*)path jsonConverter:(MobilyStorageJsonConverter*)jsonConverter; - -@end - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterBool : MobilyStorageJsonConverter - -@property(nonatomic, readonly, assign) BOOL defaultValue; - -- (id)initWithPath:(NSString*)path defaultValue:(BOOL)defaultValue; - -@end - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterString : MobilyStorageJsonConverter - -@property(nonatomic, readonly, strong) NSString* defaultValue; - -- (id)initWithPath:(NSString*)path defaultValue:(NSString*)defaultValue; - -@end - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterNumber : MobilyStorageJsonConverter - -@property(nonatomic, readonly, strong) NSNumber* defaultValue; - -- (id)initWithPath:(NSString*)path defaultValue:(NSNumber*)defaultValue; - -@end - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterDate : MobilyStorageJsonConverter - -@property(nonatomic, readonly, strong) NSDate* defaultValue; -@property(nonatomic, readonly, strong) NSArray* formats; - -- (id)initWithFormat:(NSString*)format; -- (id)initWithFormats:(NSArray*)formats; -- (id)initWithFormat:(NSString*)format defaultValue:(NSDate*)defaultValue; -- (id)initWithFormats:(NSArray*)formats defaultValue:(NSDate*)defaultValue; -- (id)initWithPath:(NSString*)path format:(NSString*)format; -- (id)initWithPath:(NSString*)path formats:(NSArray*)formats; -- (id)initWithPath:(NSString*)path format:(NSString*)format defaultValue:(NSDate*)defaultValue; -- (id)initWithPath:(NSString*)path formats:(NSArray*)formats defaultValue:(NSDate*)defaultValue; -- (id)initWithPath:(NSString*)path defaultValue:(NSDate*)defaultValue; - -@end - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterEnum : MobilyStorageJsonConverter - -@property(nonatomic, readonly, strong) NSNumber* defaultValue; -@property(nonatomic, readonly, strong) NSDictionary* enums; - -- (id)initWithEnums:(NSDictionary*)enums; -- (id)initWithEnums:(NSDictionary*)enums defaultValue:(NSNumber*)defaultValue; -- (id)initWithPath:(NSString*)path enums:(NSDictionary*)enums; -- (id)initWithPath:(NSString*)path enums:(NSDictionary*)enums defaultValue:(NSNumber*)defaultValue; - -@end - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterCustomClass : MobilyStorageJsonConverter - -@property(nonatomic, readonly, assign) Class customClass; - -- (id)initWithCustomClass:(Class)customClass; -- (id)initWithPath:(NSString*)path customClass:(Class)customClass; - -@end - -/*--------------------------------------------------*/ - -typedef void (^MobilyStorageCollectionEnumBlock)(id item, BOOL* stop); - -/*--------------------------------------------------*/ - -@interface MobilyStorageCollection : NSObject < NSCoding, NSCopying > - -@property(nonatomic, readwrite, strong) NSString* userDefaultsKey; -@property(nonatomic, readwrite, strong) NSString* fileName; -@property(nonatomic, readonly, copy) NSArray* items; - -- (id)initWithUserDefaultsKey:(NSString*)userDefaultsKey; -- (id)initWithFileName:(NSString*)fileName; -- (id)initWithJson:(id)json storageItemClass:(Class)storageItemClass; - -- (void)setupCollection; - -- (void)convertFromJson:(id)json storageItemClass:(Class)storageItemClass; - -- (NSUInteger)countItems; - -- (id)itemAtIndex:(NSUInteger)index; - -- (id)firstItem; -- (id)lastItem; - -- (void)prependItem:(MobilyStorageItem*)item; -- (void)prependItems:(NSArray*)items; - -- (void)appendItem:(MobilyStorageItem*)item; -- (void)appendItems:(NSArray*)items; - -- (void)insertItem:(MobilyStorageItem*)item atIndex:(NSUInteger)index; -- (void)insertItems:(NSArray*)items atIndex:(NSUInteger)index; - -- (void)removeItem:(MobilyStorageItem*)item; -- (void)removeItems:(NSArray*)items; -- (void)removeAllItems; - -- (void)enumirateItemsUsingBlock:(MobilyStorageCollectionEnumBlock)block; - -- (BOOL)saveItems; - -@end - -/*--------------------------------------------------*/ - -typedef NS_ENUM(NSInteger, MobilyStorageQuerySortResult) { - MobilyStorageQuerySortResultMore = NSOrderedAscending, - MobilyStorageQuerySortResultEqual = NSOrderedSame, - MobilyStorageQuerySortResultLess = NSOrderedDescending -}; - -/*--------------------------------------------------*/ - -@protocol MobilyStorageQueryDelegate; - -/*--------------------------------------------------*/ - -typedef BOOL (^MobilyStorageQueryReloadBlock)(id item); -typedef MobilyStorageQuerySortResult (^MobilyStorageQueryResortBlock)(id item1, id item2); - -/*--------------------------------------------------*/ - -@interface MobilyStorageQuery : NSObject - -@property(nonatomic, readwrite, weak) id< MobilyStorageQueryDelegate > delegate; -@property(nonatomic, readwrite, copy) MobilyStorageQueryReloadBlock reloadBlock; -@property(nonatomic, readwrite, copy) MobilyStorageQueryResortBlock resortBlock; -@property(nonatomic, readwrite, assign) BOOL resortInvert; -@property(nonatomic, readonly, assign) NSArray* items; - -- (id)initWithCollection:(MobilyStorageCollection*)collection; - -- (void)setNeedReload; -- (void)setNeedResort; - -- (NSUInteger)countItems; - -- (id)itemAtIndex:(NSUInteger)index; - -@end - -/*--------------------------------------------------*/ - -@protocol MobilyStorageQueryDelegate < NSObject > - -@optional -- (BOOL)storageQuery:(MobilyStorageQuery*)storageQuery reloadItem:(id)item; -- (MobilyStorageQuerySortResult)storageQuery:(MobilyStorageQuery*)storageQuery resortItem1:(id)item1 item2:(id)item2; - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/NS/Core/MobilyStorage.m b/Classes/NS/Core/MobilyStorage.m deleted file mode 100644 index b240178..0000000 --- a/Classes/NS/Core/MobilyStorage.m +++ /dev/null @@ -1,1428 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyStorage.h" - -/*--------------------------------------------------*/ - -@interface MobilyStorage : NSObject - -+ (NSString*)fileSystemDirectory; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyStorageItem () - -@property(nonatomic, readwrite, weak) NSArray* propertyMap; -@property(nonatomic, readwrite, weak) NSDictionary* jsonMap; - -+ (NSArray*)buildPropertyMap; -+ (NSDictionary*)buildJsonMap; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverter () - -@property(nonatomic, readwrite, strong) NSString* path; -@property(nonatomic, readwrite, strong) NSArray* subPaths; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterArray () - -@property(nonatomic, readwrite, strong) MobilyStorageJsonConverter* jsonConverter; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterDictionary () - -@property(nonatomic, readwrite, strong) MobilyStorageJsonConverter* jsonConverter; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterBool () - -@property(nonatomic, readwrite, assign) BOOL defaultValue; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterString () - -@property(nonatomic, readwrite, strong) NSString* defaultValue; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterNumber () - -@property(nonatomic, readwrite, strong) NSNumber* defaultValue; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterDate () - -@property(nonatomic, readwrite, strong) NSDate* defaultValue; -@property(nonatomic, readwrite, strong) NSArray* formats; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterEnum () - -@property(nonatomic, readwrite, strong) NSNumber* defaultValue; -@property(nonatomic, readwrite, strong) NSDictionary* enums; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyStorageJsonConverterCustomClass () - -@property(nonatomic, readwrite, assign) Class customClass; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyStorageCollection () - -@property(nonatomic, readwrite, strong) NSString* filePath; -@property(nonatomic, readwrite, strong) NSMutableArray* unsafeItems; -@property(nonatomic, readwrite, assign) BOOL flagLoad; - -- (void)loadIsNeedItems; -- (void)loadItems; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyStorageQuery () { - NSMutableArray* _unsafeItems; -} - -@property(nonatomic, readwrite, weak) MobilyStorageCollection* collection; -@property(nonatomic, readwrite, strong) NSMutableArray* unsafeItems; -@property(nonatomic, readwrite, assign) BOOL flagReload; -@property(nonatomic, readwrite, assign) BOOL flagResort; - -- (void)reloadItems; -- (void)resortItems; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyStorage - -+ (NSString*)fileSystemDirectory { - static NSString* fileSystemDirectory = nil; - if(fileSystemDirectory == nil) { - fileSystemDirectory = [[NSFileManager cachesDirectory] stringByAppendingPathComponent:[[NSBundle mainBundle] bundleIdentifier]]; - } - return fileSystemDirectory; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyStorageItem - -#pragma mark Standart - -- (id)init { - self = [super init]; - if(self != nil) { - [self setupItem]; - } - return self; -} - -- (id)initWithCoder:(NSCoder*)coder { - self = [super init]; - if(self != nil) { - [[self propertyMap] enumerateObjectsUsingBlock:^(NSString* field, NSUInteger index, BOOL* stop) { - id value = [coder decodeObjectForKey:field]; - if(value != nil) { - [self setValue:value forKey:field]; - } - }]; - [self setupItem]; - } - return self; -} - -- (id)initWithJson:(id)json { - self = [super init]; - if(self != nil) { - [self convertFromJson:json]; - [self setupItem]; - } - return self; -} - -- (id)initWithUserDefaultsKey:(NSString*)userDefaultsKey { - self = [super init]; - if(self != nil) { - [self setUserDefaultsKey:userDefaultsKey]; - [self loadItem]; - [self setupItem]; - } - return self; -} - -- (void)dealloc { - [self setUserDefaultsKey:nil]; - [self setPropertyMap:nil]; - [self setJsonMap:nil]; - - MOBILY_SAFE_DEALLOC; -} - -- (BOOL)isEqual:(id)object { - __block BOOL result = NO; - if(([object isKindOfClass:[self class]] == YES) && ([[self propertyMap] count] > 0)) { - result = YES; - [[self propertyMap] enumerateObjectsUsingBlock:^(NSString* field, NSUInteger index, BOOL* stop) { - id value1 = [self valueForKey:field]; - id value2 = [object valueForKey:field]; - if(value1 != value2) { - if([value1 isEqual:value2] == NO) { - result = NO; - *stop = YES; - } - } - }]; - } else { - result = [super isEqual:object]; - } - return result; -} - -- (void)encodeWithCoder:(NSCoder*)coder { - [[self propertyMap] enumerateObjectsUsingBlock:^(NSString* field, NSUInteger index, BOOL* stop) { - id value = [self valueForKey:field]; - if(value != nil) { - [coder encodeObject:value forKey:field]; - } - }]; -} - -- (id)copyWithZone:(NSZone*)zone { - id result = [[[self class] allocWithZone:zone] init]; - if(result != nil) { - [result setPropertyMap:[self propertyMap]]; - [result setJsonMap:[self jsonMap]]; - [result setUserDefaultsKey:[self userDefaultsKey]]; - - [[self propertyMap] enumerateObjectsUsingBlock:^(NSString* field, NSUInteger index, BOOL* stop) { - [result setValue:[[self valueForKey:field] copyWithZone:zone] forKey:field]; - }]; - } - return result; -} - -#pragma mark Property - -- (void)setupItem { -} - -- (NSArray*)propertyMap { - if(_propertyMap == nil) { - [self setPropertyMap:[[self class] buildPropertyMap]]; - } - return _propertyMap; -} - -- (NSDictionary*)jsonMap { - if(_jsonMap == nil) { - [self setJsonMap:[[self class] buildJsonMap]]; - } - return _jsonMap; -} - -#pragma mark Public - -+ (NSArray*)propertyMap { - return nil; -} - -+ (NSDictionary*)jsonMap { - return nil; -} - -- (void)convertFromJson:(id)json { - [[self jsonMap] enumerateKeysAndObjectsUsingBlock:^(NSString* field, MobilyStorageJsonConverter* converter, BOOL* stop) { - id value = [converter parseJson:json]; - if(value != nil) { - [self setValue:value forKey:field]; - } - }]; -} - -- (void)clearItem { - [[self propertyMap] enumerateObjectsUsingBlock:^(NSString* field, NSUInteger index, BOOL* stop) { - @try { - [self setValue:nil forKey:field]; - } - @catch(NSException *exception) { - } - }]; -} - -- (void)clearItemComplete:(MobilyStorageItemBlock)complete { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - [self clearItem]; - if(complete != nil) { - dispatch_sync(dispatch_get_main_queue(), ^{ - complete(); - }); - } - }); -} - -- (BOOL)saveItem { - @try { - NSMutableDictionary* dict = [NSMutableDictionary dictionary]; - if(dict != nil) { - [[self propertyMap] enumerateObjectsUsingBlock:^(NSString* field, NSUInteger index, BOOL* stop) { - @try { - id value = [self valueForKey:field]; - if(value != nil) { - NSData* archive = [NSKeyedArchiver archivedDataWithRootObject:value]; - if(archive != nil) { - [dict setObject:archive forKey:field]; - } - } - } - @catch (NSException* exception) { - NSLog(@"MobilyStorageItem::saveItem:%@ Exception = %@ Field=%@", _userDefaultsKey, exception, field); - } - }]; - [[NSUserDefaults standardUserDefaults] setObject:dict forKey:_userDefaultsKey]; - return [[NSUserDefaults standardUserDefaults] synchronize]; - } - } - @catch(NSException* exception) { - NSLog(@"MobilyStorageItem::saveItem:%@ Exception = %@", _userDefaultsKey, exception); - } - return NO; -} - -- (void)saveItemSuccess:(MobilyStorageItemBlock)success failure:(MobilyStorageItemBlock)failure { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - if([self saveItem] == YES) { - if(success != nil) { - dispatch_sync(dispatch_get_main_queue(), ^{ - success(); - }); - } - } else { - if(failure != nil) { - dispatch_sync(dispatch_get_main_queue(), ^{ - failure(); - }); - } - } - }); -} - -- (void)loadItem { - @try { - NSDictionary* dict = [[NSUserDefaults standardUserDefaults] objectForKey:_userDefaultsKey]; - if(dict != nil) { - [[self propertyMap] enumerateObjectsUsingBlock:^(NSString* field, NSUInteger index, BOOL* stop) { - id value = [dict objectForKey:field]; - if(value != nil) { - if([value isKindOfClass:[NSData class]] == YES) { - id unarchive = [NSKeyedUnarchiver unarchiveObjectWithData:value]; - if(unarchive != nil) { - @try { - [self setValue:unarchive forKey:field]; - } - @catch(NSException *exception) { - } - } - } - } - }]; - } - } - @catch(NSException* exception) { - NSLog(@"MobilyStorageItem::loadItem:%@ Exception = %@", _userDefaultsKey, exception); - } -} - -- (void)loadItemComplete:(MobilyStorageItemBlock)complete { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ - [self loadItem]; - if(complete != nil) { - dispatch_sync(dispatch_get_main_queue(), ^{ - complete(); - }); - } - }); -} - -#pragma mark Private - -+ (NSArray*)buildPropertyMap { - static NSMutableDictionary* propertyMap = nil; - if(propertyMap == nil) { - propertyMap = [NSMutableDictionary dictionary]; - } - NSMutableArray* result = nil; - NSString* className = NSStringFromClass([self class]); - if(className != nil) { - result = [propertyMap objectForKey:className]; - if(result == nil) { - result = [NSMutableArray array]; - if(result != nil) { - NSMutableArray* finalMap = [NSMutableArray array]; - if(finalMap != nil) { - if([[self superclass] respondsToSelector:_cmd] == YES) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - id superMap = [[self superclass] performSelector:_cmd]; -#pragma clang diagnostic pop - if([superMap isKindOfClass:[NSArray class]] == YES) { - [result addObjectsFromArray:superMap]; - } - } - id selfMap = [self propertyMap]; - if([selfMap isKindOfClass:[NSArray class]] == YES) { - [result addObjectsFromArray:selfMap]; - } - [propertyMap setObject:result forKey:className]; - } - } - } - } - return result; -} - -+ (NSDictionary*)buildJsonMap { - static NSMutableDictionary* jsonMaps = nil; - if(jsonMaps == nil) { - jsonMaps = [NSMutableDictionary dictionary]; - } - NSMutableDictionary* result = nil; - NSString* className = NSStringFromClass([self class]); - if(className != nil) { - result = [jsonMaps objectForKey:className]; - if(result == nil) { - result = [NSMutableDictionary dictionary]; - if(result != nil) { - NSMutableDictionary* finalMap = [NSMutableDictionary dictionary]; - if(finalMap != nil) { - if([[self superclass] respondsToSelector:_cmd] == YES) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - id superMap = [[self superclass] performSelector:_cmd]; -#pragma clang diagnostic pop - if([superMap isKindOfClass:[NSDictionary class]] == YES) { - [result addEntriesFromDictionary:superMap]; - } - } - id selfMap = [self jsonMap]; - if([selfMap isKindOfClass:[NSDictionary class]] == YES) { - [result addEntriesFromDictionary:selfMap]; - } - [jsonMaps setObject:result forKey:className]; - } - } - } - } - return result; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyStorageJsonConverter - -- (id)initWithPath:(NSString*)path { - self = [super init]; - if(self != nil) { - [self setPath:path]; - - NSMutableArray* subPaths = [NSMutableArray arrayWithArray:[path componentsSeparatedByString:@"|"]]; - [subPaths enumerateObjectsUsingBlock:^(NSString* subPath, NSUInteger subPathIndex, BOOL* subPathStop) { - [subPaths replaceObjectAtIndex:subPathIndex withObject:[subPath componentsSeparatedByString:@"."]]; - }]; - [self setSubPaths:subPaths]; - } - return self; -} - -- (void)dealloc { - [self setSubPaths:nil]; - [self setPath:nil]; - - MOBILY_SAFE_DEALLOC; -} - -- (id)parseJson:(id)json { - __block id value = json; - if([value isKindOfClass:[NSDictionary class]] == YES) { - [_subPaths enumerateObjectsUsingBlock:^(NSArray* subPath, NSUInteger subPathIndex, BOOL* subPathStop) { - value = json; - [subPath enumerateObjectsUsingBlock:^(NSString* path, NSUInteger pathIndex, BOOL* pathStop) { - if([value isKindOfClass:[NSDictionary class]] == YES) { - value = [value objectForKey:path]; - if(value == nil) { - *pathStop = YES; - } - } else { - if(pathIndex != ([subPath count] - 1)) { - value = nil; - } - *pathStop = YES; - } - }]; - }]; - } - return [self convertValue:value]; -} - -- (id)convertValue:(id)value { - return value; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyStorageJsonConverterArray - -- (id)initWithJsonConverter:(MobilyStorageJsonConverter*)jsonConverter { - self = [super init]; - if(self != nil) { - [self setJsonConverter:jsonConverter]; - } - return self; -} - -- (id)initWithPath:(NSString*)path jsonConverter:(MobilyStorageJsonConverter*)jsonConverter { - self = [super initWithPath:path]; - if(self != nil) { - [self setJsonConverter:jsonConverter]; - } - return self; -} - -- (id)convertValue:(id)value { - if([value isKindOfClass:[NSArray class]] == YES) { - NSMutableArray* result = [NSMutableArray array]; - if(result != nil) { - [value enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL* stop) { - id convertedValue = [_jsonConverter convertValue:object]; - if(convertedValue != nil) { - [result addObject:convertedValue]; - } - }]; - return result; - } - } - return nil; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyStorageJsonConverterDictionary - -- (id)initWithJsonConverter:(MobilyStorageJsonConverter*)jsonConverter { - self = [super init]; - if(self != nil) { - [self setJsonConverter:jsonConverter]; - } - return self; -} - -- (id)initWithPath:(NSString*)path jsonConverter:(MobilyStorageJsonConverter*)jsonConverter { - self = [super initWithPath:path]; - if(self != nil) { - [self setJsonConverter:jsonConverter]; - } - return self; -} - -- (id)convertValue:(id)value { - if([value isKindOfClass:[NSDictionary class]] == YES) { - NSMutableDictionary* result = [NSMutableDictionary dictionary]; - if(result != nil) { - [value enumerateKeysAndObjectsUsingBlock:^(id key, id object, BOOL* stop) { - id convertedValue = [_jsonConverter convertValue:object]; - if(convertedValue != nil) { - [result setObject:convertedValue forKey:key]; - } - }]; - return result; - } - } - return nil; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyStorageJsonConverterBool - -- (id)initWithPath:(NSString*)path defaultValue:(BOOL)defaultValue { - self = [super initWithPath:path]; - if(self != nil) { - [self setDefaultValue:defaultValue]; - } - return self; -} - -- (id)convertValue:(id)value { - if([value isKindOfClass:[NSString class]] == YES) { - NSString* lowercaseString = [value lowercaseString]; - if(([lowercaseString isEqualToString:@"true"] == YES) || ([lowercaseString isEqualToString:@"yes"] == YES) || ([lowercaseString isEqualToString:@"on"] == YES)) { - return @YES; - } - return @NO; - } else if([value isKindOfClass:[NSNumber class]] == YES) { - return value; - } - return @(_defaultValue); -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyStorageJsonConverterString - -- (id)initWithPath:(NSString*)path defaultValue:(NSString*)defaultValue { - self = [super initWithPath:path]; - if(self != nil) { - [self setDefaultValue:defaultValue]; - } - return self; -} - -- (void)dealloc { - [self setDefaultValue:nil]; - - MOBILY_SAFE_DEALLOC; -} - -- (id)convertValue:(id)value { - if([value isKindOfClass:[NSString class]] == YES) { - return value; - } else if([value isKindOfClass:[NSNumber class]] == YES) { - static NSNumberFormatter* numberFormat = nil; - if(numberFormat == nil) { - numberFormat = [[NSNumberFormatter alloc] init]; - [numberFormat setLocale:[NSLocale currentLocale]]; - [numberFormat setFormatterBehavior:NSNumberFormatterBehavior10_4]; - [numberFormat setNumberStyle:NSNumberFormatterDecimalStyle]; - } - return [numberFormat stringFromNumber:value]; - } - return _defaultValue; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyStorageJsonConverterNumber - -- (id)initWithPath:(NSString*)path defaultValue:(NSNumber*)defaultValue { - self = [super initWithPath:path]; - if(self != nil) { - [self setDefaultValue:defaultValue]; - } - return self; -} - -- (void)dealloc { - [self setDefaultValue:nil]; - - MOBILY_SAFE_DEALLOC; -} - -- (id)convertValue:(id)value { - if([value isKindOfClass:[NSNumber class]] == YES) { - return value; - } else if([value isKindOfClass:[NSString class]] == YES) { - static NSNumberFormatter* numberFormat = nil; - if(numberFormat == nil) { - numberFormat = [[NSNumberFormatter alloc] init]; - } - [numberFormat setLocale:[NSLocale currentLocale]]; - [numberFormat setFormatterBehavior:NSNumberFormatterBehavior10_4]; - [numberFormat setNumberStyle:NSNumberFormatterDecimalStyle]; - - NSNumber* number = [numberFormat numberFromString:value]; - if(number == nil) { - if([[numberFormat decimalSeparator] isEqualToString:@"."] == YES) { - [numberFormat setDecimalSeparator:@","]; - } - number = [numberFormat numberFromString:value]; - } - if(number != nil) { - return number; - } - } - return _defaultValue; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyStorageJsonConverterDate - -- (id)initWithFormat:(NSString*)format { - self = [super init]; - if(self != nil) { - [self setFormats:@[ format ]]; - } - return self; -} - -- (id)initWithFormats:(NSArray*)formats { - self = [super init]; - if(self != nil) { - [self setFormats:formats]; - } - return self; -} - -- (id)initWithFormat:(NSString*)format defaultValue:(NSDate*)defaultValue { - self = [super init]; - if(self != nil) { - [self setFormats:@[ format ]]; - [self setDefaultValue:defaultValue]; - } - return self; -} - -- (id)initWithFormats:(NSArray*)formats defaultValue:(NSDate*)defaultValue { - self = [super init]; - if(self != nil) { - [self setFormats:formats]; - [self setDefaultValue:defaultValue]; - } - return self; -} - -- (id)initWithPath:(NSString*)path format:(NSString*)format { - self = [super initWithPath:path]; - if(self != nil) { - [self setFormats:@[ format ]]; - } - return self; -} - -- (id)initWithPath:(NSString*)path formats:(NSArray*)formats { - self = [super initWithPath:path]; - if(self != nil) { - [self setFormats:formats]; - } - return self; -} - -- (id)initWithPath:(NSString*)path format:(NSString*)format defaultValue:(NSDate*)defaultValue { - self = [super initWithPath:path]; - if(self != nil) { - [self setFormats:@[ format ]]; - [self setDefaultValue:defaultValue]; - } - return self; -} - -- (id)initWithPath:(NSString*)path formats:(NSArray*)formats defaultValue:(NSDate*)defaultValue { - self = [super initWithPath:path]; - if(self != nil) { - [self setFormats:formats]; - [self setDefaultValue:defaultValue]; - } - return self; -} - -- (id)initWithPath:(NSString*)path defaultValue:(NSDate*)defaultValue { - self = [super initWithPath:path]; - if(self != nil) { - [self setDefaultValue:defaultValue]; - } - return self; -} - -- (void)dealloc { - [self setFormats:nil]; - [self setDefaultValue:nil]; - - MOBILY_SAFE_DEALLOC; -} - -- (id)convertValue:(id)value { - if([value isKindOfClass:[NSString class]] == YES) { - static NSDateFormatter* dateFormatter = nil; - if(dateFormatter == nil) { - dateFormatter = [[NSDateFormatter alloc] init]; - } - __block NSDate* resultValue = nil; - [_formats enumerateObjectsUsingBlock:^(NSString* format, NSUInteger index, BOOL* stop) { - if([format isKindOfClass:[NSString class]] == true) { - [dateFormatter setDateFormat:format]; - } - NSDate* date = [dateFormatter dateFromString:value]; - if(date != nil) { - resultValue = date; - *stop = YES; - } - }]; - return resultValue; - } else if([value isKindOfClass:[NSNumber class]] == YES) { - return [NSDate dateWithTimeIntervalSince1970:[value floatValue]]; - } - return _defaultValue; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyStorageJsonConverterEnum - -- (id)initWithEnums:(NSDictionary*)enums { - self = [super init]; - if(self != nil) { - [self setEnums:enums]; - } - return self; -} - -- (id)initWithEnums:(NSDictionary*)enums defaultValue:(NSNumber*)defaultValue { - self = [super init]; - if(self != nil) { - [self setEnums:enums]; - [self setDefaultValue:defaultValue]; - } - return self; -} - -- (id)initWithPath:(NSString*)path enums:(NSDictionary*)enums { - self = [super initWithPath:path]; - if(self != nil) { - [self setEnums:enums]; - } - return self; -} - -- (id)initWithPath:(NSString*)path enums:(NSDictionary*)enums defaultValue:(NSNumber*)defaultValue { - self = [super initWithPath:path]; - if(self != nil) { - [self setEnums:enums]; - [self setDefaultValue:defaultValue]; - } - return self; -} - -- (void)dealloc { - [self setEnums:nil]; - [self setDefaultValue:nil]; - - MOBILY_SAFE_DEALLOC; -} - -- (id)convertValue:(id)value { - if([value isKindOfClass:[NSString class]] == YES) { - if([[_enums allKeys] containsObject:value] == YES) { - return [_enums objectForKey:value]; - } - } else if([value isKindOfClass:[NSNumber class]] == YES) { - if([[_enums allKeys] containsObject:value] == YES) { - return [_enums objectForKey:value]; - } - } - return _defaultValue; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyStorageJsonConverterCustomClass - -- (id)initWithCustomClass:(Class)customClass { - self = [super init]; - if(self != nil) { - [self setCustomClass:customClass]; - } - return self; -} - -- (id)initWithPath:(NSString*)path customClass:(Class)customClass { - self = [super initWithPath:path]; - if(self != nil) { - [self setCustomClass:customClass]; - } - return self; -} - -- (void)dealloc { - [self setCustomClass:nil]; - - MOBILY_SAFE_DEALLOC; -} - -- (id)convertValue:(id)value { - if([value isKindOfClass:[NSDictionary class]] == YES) { - return [[_customClass alloc] initWithJson:value]; - } - return nil; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -#define MOBILY_STORAGE_COLLECTION_EXTENSION @"collection" - -/*--------------------------------------------------*/ - -@implementation MobilyStorageCollection - -#pragma mark Standart - -- (id)init { - self = [super init]; - if(self != nil) { - [self setUnsafeItems:[NSMutableArray array]]; - [self setFlagLoad:NO]; - } - return self; -} - -- (id)initWithCoder:(NSCoder*)coder { - self = [super init]; - if(self != nil) { - id items = [coder decodeObjectForKey:@"items"]; - if(items != nil) { - [self setUnsafeItems:items]; - } else { - [self setUnsafeItems:[NSMutableArray array]]; - } - [self setFlagLoad:NO]; - [self setupCollection]; - } - return self; -} - -- (id)initWithUserDefaultsKey:(NSString*)userDefaultsKey { - self = [super init]; - if(self != nil) { - [self setUserDefaultsKey:userDefaultsKey]; - [self setUnsafeItems:[NSMutableArray array]]; - [self setFlagLoad:YES]; - [self setupCollection]; - } - return self; -} - -- (id)initWithFileName:(NSString*)fileName { - self = [super init]; - if(self != nil) { - NSString* fileGroup = [MobilyStorage fileSystemDirectory]; - if(fileGroup != nil) { - NSString* filePath = [fileGroup stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", fileName, MOBILY_STORAGE_COLLECTION_EXTENSION]]; - if(filePath != nil) { - [self setFileName:fileName]; - [self setFilePath:filePath]; - [self setUnsafeItems:[NSMutableArray array]]; - [self setFlagLoad:YES]; - [self setupCollection]; - } else { - self = nil; - } - } else { - self = nil; - } - } - return self; -} - -- (id)initWithJson:(id)json storageItemClass:(Class)storageItemClass { - self = [super init]; - if(self != nil) { - [self setUnsafeItems:[NSMutableArray array]]; - [self setFlagLoad:NO]; - [self convertFromJson:json storageItemClass:storageItemClass]; - [self setupCollection]; - } - return self; -} - -- (void)dealloc { - [self setFileName:nil]; - [self setUserDefaultsKey:nil]; - [self setFilePath:nil]; - [self setUnsafeItems:nil]; - - MOBILY_SAFE_DEALLOC; -} - -- (void)encodeWithCoder:(NSCoder*)coder { - [self loadIsNeedItems]; - [coder encodeObject:_unsafeItems forKey:@"items"]; -} - -- (id)copyWithZone:(NSZone*)zone { - id result = [[[self class] allocWithZone:zone] init]; - if(result != nil) { - [result setFilePath:[self filePath]]; - [result setUserDefaultsKey:[self userDefaultsKey]]; - [result setUnsafeItems:[[self unsafeItems] copyWithZone:zone]]; - [result setFlagLoad:[self flagLoad]]; - } - return result; -} - -#pragma mark Property - -- (void)setFileName:(NSString*)fileName { - if(_fileName != fileName) { - MOBILY_SAFE_SETTER(_fileName, fileName); - - NSString* fileGroup = [MobilyStorage fileSystemDirectory]; - if(fileGroup != nil) { - NSString* filePath = [fileGroup stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", fileName, MOBILY_STORAGE_COLLECTION_EXTENSION]]; - if(filePath != nil) { - [self setFilePath:filePath]; - } else { - [self setFilePath:nil]; - } - } else { - [self setFilePath:nil]; - } - } -} - -- (void)setUserDefaultsKey:(NSString*)userDefaultsKey { - if(_userDefaultsKey != userDefaultsKey) { - MOBILY_SAFE_SETTER(_userDefaultsKey, userDefaultsKey); - } -} - -#pragma mark Public - -- (void)setupCollection { -} - -- (void)convertFromJson:(id)json storageItemClass:(Class)storageItemClass { - [_unsafeItems removeAllObjects]; - if([storageItemClass isSubclassOfClass:[MobilyStorageItem class]] == YES) { - if([json isKindOfClass:[NSArray class]] == YES) { - [json enumerateObjectsUsingBlock:^(id jsonItem, NSUInteger jsonItemIndex, BOOL* jsonItemStop) { - id item = [[storageItemClass alloc] initWithJson:jsonItem]; - if(item != nil) { - [_unsafeItems addObject:item]; - } - }]; - } - } -} - -- (NSUInteger)countItems { - [self loadIsNeedItems]; - return [_unsafeItems count]; -} - -- (id)itemAtIndex:(NSUInteger)index { - [self loadIsNeedItems]; - return [_unsafeItems objectAtIndex:index]; -} - -- (id)firstItem { - [self loadIsNeedItems]; - if([_unsafeItems count] > 0) { - return [_unsafeItems objectAtIndex:0]; - } - return nil; -} - -- (id)lastItem { - return [_unsafeItems lastObject]; -} - -- (void)prependItem:(MobilyStorageItem*)item { - [self loadIsNeedItems]; - [_unsafeItems insertObject:item atIndex:0]; -} - -- (void)prependItems:(NSArray*)items { - [self loadIsNeedItems]; - [_unsafeItems insertObjects:items atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [items count])]]; -} - -- (void)appendItem:(MobilyStorageItem*)item { - [self loadIsNeedItems]; - [_unsafeItems addObject:item]; -} - -- (void)appendItems:(NSArray*)items { - [self loadIsNeedItems]; - [_unsafeItems addObjectsFromArray:items]; -} - -- (void)insertItem:(MobilyStorageItem*)item atIndex:(NSUInteger)index { - [self loadIsNeedItems]; - [_unsafeItems insertObject:item atIndex:index]; -} - -- (void)insertItems:(NSArray*)items atIndex:(NSUInteger)index { - [self loadIsNeedItems]; - [_unsafeItems insertObjects:items atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, [items count])]]; -} - -- (void)removeItem:(MobilyStorageItem*)item { - [self loadIsNeedItems]; - [_unsafeItems removeObject:item]; -} - -- (void)removeItems:(NSArray*)items { - [self loadIsNeedItems]; - [_unsafeItems removeObjectsInArray:items]; -} - -- (void)removeAllItems { - [self loadIsNeedItems]; - [_unsafeItems removeAllObjects]; -} - -- (NSArray*)items { - [self loadIsNeedItems]; - return MOBILY_SAFE_AUTORELEASE([_unsafeItems copy]); -} - -- (void)enumirateItemsUsingBlock:(MobilyStorageCollectionEnumBlock)block { - [self loadIsNeedItems]; - [_unsafeItems enumerateObjectsUsingBlock:^(id item, NSUInteger idx, BOOL *stop) { - block(item, stop); - }]; -} - -- (BOOL)saveItems { - @try { - if(_flagLoad == NO) { - if([_userDefaultsKey length] > 0) { - NSData* data = [[NSUserDefaults standardUserDefaults] objectForKey:_userDefaultsKey]; - if([data isKindOfClass:[NSData class]] == YES) { - id items = [NSKeyedUnarchiver unarchiveObjectWithData:data]; - if([items isKindOfClass:[NSArray class]] == YES) { - [_unsafeItems setArray:items]; - } else { - [_unsafeItems removeAllObjects]; - } - } - } else if([_filePath length] > 0) { - NSFileManager* fileManager = [NSFileManager defaultManager]; - if([fileManager fileExistsAtPath:_filePath] == NO) { - NSError* error = nil; - NSString* fileSystemDirectory = [MobilyStorage fileSystemDirectory]; - if([fileManager createDirectoryAtPath:fileSystemDirectory withIntermediateDirectories:YES attributes:nil error:&error] == NO) { - return NO; - } - } - return [NSKeyedArchiver archiveRootObject:_unsafeItems toFile:_filePath]; - } - } - } - @catch(NSException* exception) { -#if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) - NSLog(@"MobilyStorageCollection::saveItems: Exception = %@", exception); -#endif - } - return NO; -} - -#pragma mark Private - -- (NSMutableArray*)safeItems { - [self loadIsNeedItems]; - return _unsafeItems; -} - -- (void)loadIsNeedItems { - if(_flagLoad == YES) { - [self loadItems]; - _flagLoad = NO; - } -} - -- (void)loadItems { - @try { - if([_userDefaultsKey length] > 0) { - NSData* data = [[NSUserDefaults standardUserDefaults] objectForKey:_userDefaultsKey]; - if([data isKindOfClass:[NSData class]] == YES) { - id items = [NSKeyedUnarchiver unarchiveObjectWithData:data]; - if([items isKindOfClass:[NSArray class]] == YES) { - [_unsafeItems setArray:items]; - } else { - [_unsafeItems removeAllObjects]; - } - } - } else if([_filePath length] > 0) { - id items = [NSKeyedUnarchiver unarchiveObjectWithFile:_filePath]; - if([items isKindOfClass:[NSArray class]] == YES) { - [_unsafeItems setArray:items]; - } else { - [_unsafeItems removeAllObjects]; - } - } - } - @catch(NSException* exception) { -#if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) - NSLog(@"MobilyStorageCollection::loadItems: Exception = %@", exception); -#endif - [_unsafeItems removeAllObjects]; - } -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyStorageQuery : NSObject - -#pragma mark Standart - -- (id)initWithCollection:(MobilyStorageCollection*)collection { - self = [super init]; - if(self != nil) { - [self setCollection:collection]; - [self setUnsafeItems:[NSMutableArray array]]; - [self setFlagReload:YES]; - [self setFlagResort:YES]; - } - return self; -} - -- (void)dealloc { - [self setCollection:nil]; - [self setUnsafeItems:nil]; - [self setReloadBlock:nil]; - [self setResortBlock:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark Public - -- (void)setNeedReload { - _flagReload = YES; - _flagResort = YES; -} - -- (void)setNeedResort { - _flagReload = YES; -} - -- (NSUInteger)countItems { - return [[self items] count]; -} - -- (id)itemAtIndex:(NSUInteger)index { - return [[self items] objectAtIndex:index]; -} - -- (NSArray*)items { - if(_flagReload == YES) { - [self reloadItems]; - _flagReload = NO; - } - if(_flagResort == YES) { - [self resortItems]; - _flagResort = NO; - } - return _unsafeItems; -} - -#pragma mark Property - -- (void)setReloadBlock:(MobilyStorageQueryReloadBlock)block { - _reloadBlock = MOBILY_SAFE_RETAIN([block copy]); - _flagReload = YES; - _flagResort = YES; -} - -- (void)setResortBlock:(MobilyStorageQueryResortBlock)block { - _resortBlock = MOBILY_SAFE_RETAIN([block copy]); - _flagResort = YES; -} - -- (void)setResortInvert:(BOOL)resortInvert { - if(_resortInvert != resortInvert) { - _resortInvert = resortInvert; - _flagResort = YES; - } -} - -#pragma mark Private - -- (void)reloadItems { - [_unsafeItems removeAllObjects]; - - if([_delegate respondsToSelector:@selector(storageQuery:reloadItem:)] == YES) { - [[_collection safeItems] enumerateObjectsUsingBlock:^(id item, NSUInteger itemIndex, BOOL* itemStop) { - if([_delegate storageQuery:self reloadItem:item] == YES) { - [_unsafeItems addObject:item]; - } - }]; - } else if(_reloadBlock != nil) { - [[_collection safeItems] enumerateObjectsUsingBlock:^(id item, NSUInteger itemIndex, BOOL* itemStop) { - if(_reloadBlock(item) == YES) { - [_unsafeItems addObject:item]; - } - }]; - } else { - [_unsafeItems setArray:[_collection safeItems]]; - } -} - -- (void)resortItems { - if([_delegate respondsToSelector:@selector(storageQuery:resortItem1:item2:)] == YES) { - if(_resortInvert == YES) { - [_unsafeItems sortUsingComparator:^NSComparisonResult(id item1, id item2) { - switch([_delegate storageQuery:self resortItem1:item1 item2:item2]) { - case MobilyStorageQuerySortResultMore: return NSOrderedDescending; - case MobilyStorageQuerySortResultLess: return NSOrderedAscending; - default: break; - } - return NSOrderedSame; - }]; - } else { - [_unsafeItems sortUsingComparator:^NSComparisonResult(id item1, id item2) { - return (NSComparisonResult)[_delegate storageQuery:self resortItem1:item1 item2:item2]; - }]; - } - } else if(_resortBlock != nil) { - if(_resortInvert == YES) { - [_unsafeItems sortUsingComparator:^NSComparisonResult(id item1, id item2) { - switch(_resortBlock(item1, item2)) { - case MobilyStorageQuerySortResultMore: return NSOrderedDescending; - case MobilyStorageQuerySortResultLess: return NSOrderedAscending; - default: break; - } - return NSOrderedSame; - }]; - } else { - [_unsafeItems sortUsingComparator:^NSComparisonResult(id item1, id item2) { - return (NSComparisonResult)_resortBlock(item1, item2); - }]; - } - } -} - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/UI/ControllerDynamicsDrawer/MobilyControllerDynamicsDrawer.m b/Classes/UI/ControllerDynamicsDrawer/MobilyControllerDynamicsDrawer.m deleted file mode 100644 index 8f75f4f..0000000 --- a/Classes/UI/ControllerDynamicsDrawer/MobilyControllerDynamicsDrawer.m +++ /dev/null @@ -1,278 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyControllerDynamicsDrawer.h" - -/*--------------------------------------------------*/ - -@interface MobilyControllerDynamicsDrawer () < UIViewControllerTransitioningDelegate > - -@property(nonatomic, readwrite, assign, getter=isAppeared) BOOL appeared; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyControllerDynamicsDrawer - -@synthesize objectName = _objectName; -@synthesize objectParent = _objectParent; -@synthesize objectChilds = _objectChilds; - -#pragma mark NSKeyValueCoding - -MOBILY_DEFINE_VALIDATE_BOOL(NavigationBarHidden) -MOBILY_DEFINE_VALIDATE_TRANSITION_CONTROLLER(TransitionModal); -MOBILY_DEFINE_VALIDATE_EVENT(EventDidLoad) -MOBILY_DEFINE_VALIDATE_EVENT(EventDidUnload) -MOBILY_DEFINE_VALIDATE_EVENT(EventWillAppear) -MOBILY_DEFINE_VALIDATE_EVENT(EventDidAppear) -MOBILY_DEFINE_VALIDATE_EVENT(EventWillDisappear) -MOBILY_DEFINE_VALIDATE_EVENT(EventDidDisappear) - -#pragma mark Standart - -- (id)init { - self = [super init]; - if(self != nil) { - [self setupController]; - } - return self; -} - -- (id)initWithCoder:(NSCoder*)coder { - self = [super initWithCoder:coder]; - if(self != nil) { - [self setupController]; - } - return self; -} - -- (id)initWithNibName:(NSString*)nib bundle:(NSBundle*)bundle { - self = [super initWithNibName:nib bundle:bundle]; - if(self != nil) { - [self setupController]; - } - return self; -} - -- (void)dealloc { - [self setObjectName:nil]; - [self setObjectParent:nil]; - [self setObjectChilds:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark MobilyBuilderObject - -- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIViewController class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andAddingObject:objectChild]]; - } -} - -- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIViewController class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andRemovingObject:objectChild]]; - } -} - -- (void)willLoadObjectChilds { -} - -- (void)didLoadObjectChilds { -} - -- (id< MobilyBuilderObject >)objectForName:(NSString*)name { - return [MobilyBuilderForm object:self forName:name]; -} - -- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { - return [MobilyBuilderForm object:self forSelector:selector]; -} - -#pragma mark Public - -- (void)setupController { -} - -- (void)showWideLeftDrawerAnimated:(BOOL)animated completion:(void (^)(void))completion { - [self setPaneState:MSDynamicsDrawerPaneStateOpenWide inDirection:MSDynamicsDrawerDirectionLeft animated:animated allowUserInterruption:YES completion:completion]; -} - -- (void)showLeftDrawerAnimated:(BOOL)animated completion:(void (^)(void))completion { - [self setPaneState:MSDynamicsDrawerPaneStateOpen inDirection:MSDynamicsDrawerDirectionLeft animated:animated allowUserInterruption:YES completion:completion]; -} - -- (void)hideLeftDrawerAnimated:(BOOL)animated completion:(void (^)(void))completion { - [self setPaneState:MSDynamicsDrawerPaneStateClosed inDirection:MSDynamicsDrawerDirectionLeft animated:animated allowUserInterruption:YES completion:completion]; -} - -- (void)showWideRightDrawerAnimated:(BOOL)animated completion:(void (^)(void))completion { - [self setPaneState:MSDynamicsDrawerPaneStateOpenWide inDirection:MSDynamicsDrawerDirectionRight animated:animated allowUserInterruption:YES completion:completion]; -} - -- (void)showRightDrawerAnimated:(BOOL)animated completion:(void (^)(void))completion { - [self setPaneState:MSDynamicsDrawerPaneStateOpen inDirection:MSDynamicsDrawerDirectionRight animated:animated allowUserInterruption:YES completion:completion]; -} - -- (void)hideRightDrawerAnimated:(BOOL)animated completion:(void (^)(void))completion { - [self setPaneState:MSDynamicsDrawerPaneStateClosed inDirection:MSDynamicsDrawerDirectionRight animated:animated allowUserInterruption:YES completion:completion]; -} - -#pragma mark Property - -- (BOOL)isAppeared { - return (_appeared > 0); -} - -- (void)setLeftDrawerViewController:(UIViewController*)leftDrawerViewController { - [self setDrawerViewController:leftDrawerViewController forDirection:MSDynamicsDrawerDirectionLeft]; -} - -- (UIViewController*)leftDrawerViewController { - return [self drawerViewControllerForDirection:MSDynamicsDrawerDirectionLeft]; -} - -- (void)setRightDrawerViewController:(UIViewController*)rightDrawerViewController { - [self setDrawerViewController:rightDrawerViewController forDirection:MSDynamicsDrawerDirectionRight]; -} - -- (UIViewController*)rightDrawerViewController { - return [self drawerViewControllerForDirection:MSDynamicsDrawerDirectionRight]; -} - -#pragma mark UIViewController - -- (BOOL)prefersStatusBarHidden { - if([self paneViewController] != nil) { - return [[self paneViewController] prefersStatusBarHidden]; - } - return [super prefersStatusBarHidden]; -} - -- (UIStatusBarStyle)preferredStatusBarStyle { - if([self paneViewController] != nil) { - return [[self paneViewController] preferredStatusBarStyle]; - } - return [super preferredStatusBarStyle]; -} - -- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { - if([self paneViewController] != nil) { - return [[self paneViewController] preferredStatusBarUpdateAnimation]; - } - return [super preferredStatusBarUpdateAnimation]; -} - -- (void)viewDidLoad { - [super viewDidLoad]; - - if([self paneViewController] == nil) { - [self setPaneViewController:[_objectChilds firstObjectIsClass:[UIViewController class]]]; - } - [_eventDidLoad fireSender:self object:nil]; -} - -- (void)viewDidUnload { - [super viewDidUnload]; - - [_eventDidUnload fireSender:self object:nil]; -} - -- (void)viewWillAppear:(BOOL)animated { - [super viewWillAppear:animated]; - - if(_navigationBarHidden == YES) { - [[self navigationController] setNavigationBarHidden:YES animated:animated]; - } - [_eventWillAppear fireSender:self object:nil]; - [self setAppeared:_appeared + 1]; -} - -- (void)viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - - [_eventDidAppear fireSender:self object:nil]; -} - -- (void)viewWillDisappear:(BOOL)animated { - [super viewWillDisappear:animated]; - - if(_navigationBarHidden == YES) { - [[self navigationController] setNavigationBarHidden:NO animated:animated]; - } - [_eventWillDisappear fireSender:self object:nil]; -} - -- (void)viewDidDisappear:(BOOL)animated { - [super viewDidDisappear:animated]; - - [self setAppeared:_appeared - 1]; - [_eventDidDisappear fireSender:self object:nil]; -} - -- (void)didReceiveMemoryWarning { - [super didReceiveMemoryWarning]; - - if([self isViewLoaded] == YES) { - if([[self view] window] == nil) { - [self setView:nil]; - } - } -} - -#pragma mark UIViewControllerTransitioningDelegate - -- (id< UIViewControllerAnimatedTransitioning >)animationControllerForPresentedController:(UIViewController*)presented presentingController:(UIViewController*)presenting sourceController:(UIViewController*)source { - if(_transitionModal != nil) { - [_transitionModal setReverse:NO]; - } - return _transitionModal; -} - -- (id< UIViewControllerAnimatedTransitioning >)animationControllerForDismissedController:(UIViewController*)dismissed { - if(_transitionModal != nil) { - [_transitionModal setReverse:YES]; - } - return _transitionModal; -} - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/UI/ControllerSlideMenu/MobilyControllerSlideMenu.m b/Classes/UI/ControllerSlideMenu/MobilyControllerSlideMenu.m deleted file mode 100644 index 01c1b94..0000000 --- a/Classes/UI/ControllerSlideMenu/MobilyControllerSlideMenu.m +++ /dev/null @@ -1,269 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyControllerSlideMenu.h" - -/*--------------------------------------------------*/ - -@interface MobilyControllerSlideMenu () < UIViewControllerTransitioningDelegate > - -@property(nonatomic, readwrite, assign, getter=isAppeared) BOOL appeared; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyControllerSlideMenu - -@synthesize objectName = _objectName; -@synthesize objectParent = _objectParent; -@synthesize objectChilds = _objectChilds; - -#pragma mark NSKeyValueCoding - -MOBILY_DEFINE_VALIDATE_TRANSITION_CONTROLLER(TransitionModal); -MOBILY_DEFINE_VALIDATE_TRANSITION_CONTROLLER(TransitionNavigation); -MOBILY_DEFINE_VALIDATE_EVENT(EventDidLoad) -MOBILY_DEFINE_VALIDATE_EVENT(EventDidUnload) -MOBILY_DEFINE_VALIDATE_EVENT(EventWillAppear) -MOBILY_DEFINE_VALIDATE_EVENT(EventDidAppear) -MOBILY_DEFINE_VALIDATE_EVENT(EventWillDisappear) -MOBILY_DEFINE_VALIDATE_EVENT(EventDidDisappear) - -#pragma mark Standart - -- (id)initWithCoder:(NSCoder*)coder { - self = [super initWithCoder:coder]; - if(self != nil) { - [self setupController]; - } - return self; -} - -- (id)initWithNibName:(NSString*)nib bundle:(NSBundle*)bundle { - self = [super initWithNibName:nib bundle:bundle]; - if(self != nil) { - [self setupController]; - } - return self; -} - -- (instancetype)initWithNavigationBarClass:(Class)navigationBarClass toolbarClass:(Class)toolbarClass { - self = [super initWithNavigationBarClass:navigationBarClass toolbarClass:toolbarClass]; - if(self != nil) { - [self setupController]; - } - return self; -} - -- (instancetype)initWithRootViewController:(UIViewController*)rootViewController { - self = [super initWithRootViewController:rootViewController]; - if(self != nil) { - [self setupController]; - } - return self; -} - -- (void)dealloc { - [self setObjectName:nil]; - [self setObjectParent:nil]; - [self setObjectChilds:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark MobilyBuilderObject - -- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIViewController class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andAddingObject:objectChild]]; - } -} - -- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIViewController class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andRemovingObject:objectChild]]; - } -} - -- (void)willLoadObjectChilds { -} - -- (void)didLoadObjectChilds { - if([self rootViewController] == nil) { - UIViewController* viewController = [_objectChilds firstObjectIsClass:[UIViewController class]]; - if(viewController != nil) { - [self setViewControllers:@[ viewController ]]; - } - } -} - -- (id< MobilyBuilderObject >)objectForName:(NSString*)name { - return [MobilyBuilderForm object:self forName:name]; -} - -- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { - return [MobilyBuilderForm object:self forSelector:selector]; -} - -#pragma mark Public - -- (void)setupController { -} - -#pragma mark Property - -- (BOOL)isAppeared { - return (_appeared > 0); -} - -#pragma mark UIViewController - -- (BOOL)shouldAutorotate { - return [[self topViewController] shouldAutorotate]; -} - -- (NSUInteger)supportedInterfaceOrientations { - return [[self topViewController] supportedInterfaceOrientations]; -} - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation { - return [[self topViewController] shouldAutorotateToInterfaceOrientation:orientation]; -} - -- (BOOL)prefersStatusBarHidden { - return [[self topViewController] prefersStatusBarHidden]; -} - -- (UIStatusBarStyle)preferredStatusBarStyle { - return [[self topViewController] preferredStatusBarStyle]; -} - -- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { - return [[self topViewController] preferredStatusBarUpdateAnimation]; -} - -- (void)viewDidLoad { - [super viewDidLoad]; - - if([self rootViewController] == nil) { - UIViewController* viewController = [_objectChilds firstObjectIsClass:[UIViewController class]]; - if(viewController != nil) { - [self setViewControllers:@[ viewController ]]; - } - } - [_eventDidLoad fireSender:self object:nil]; -} - -- (void)viewDidUnload { - [super viewDidUnload]; - - [_eventDidUnload fireSender:self object:nil]; -} - -- (void)viewWillAppear:(BOOL)animated { - [super viewWillAppear:animated]; - - [_eventWillAppear fireSender:self object:nil]; - [self setAppeared:_appeared + 1]; -} - -- (void)viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - - [_eventDidAppear fireSender:self object:nil]; -} - -- (void)viewWillDisappear:(BOOL)animated { - [super viewWillDisappear:animated]; - - [_eventWillDisappear fireSender:self object:nil]; -} - -- (void)viewDidDisappear:(BOOL)animated { - [super viewDidDisappear:animated]; - - [self setAppeared:_appeared - 1]; - [_eventDidDisappear fireSender:self object:nil]; -} - -#pragma mark UIViewControllerTransitioningDelegate - -- (id< UIViewControllerAnimatedTransitioning >)animationControllerForPresentedController:(UIViewController*)presented presentingController:(UIViewController*)presenting sourceController:(UIViewController*)source { - if(_transitionModal != nil) { - [_transitionModal setReverse:NO]; - } - return _transitionModal; -} - -- (id< UIViewControllerAnimatedTransitioning >)animationControllerForDismissedController:(UIViewController*)dismissed { - if(_transitionModal != nil) { - [_transitionModal setReverse:YES]; - } - return _transitionModal; -} - -#pragma mark UINavigationControllerDelegate - -- (void)navigationController:(UINavigationController*)navigationController willShowViewController:(UIViewController*)viewController animated:(BOOL)animated { - if([viewController isKindOfClass:[MobilyController class]] == YES) { - MobilyController* mobilyController = (MobilyController*)viewController; - [navigationController setNavigationBarHidden:[mobilyController isNavigationBarHidden] animated:animated]; - } -} - -- (id< UIViewControllerAnimatedTransitioning >)navigationController:(UINavigationController*)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController*)fromViewController toViewController:(UIViewController*)toViewController { - switch(operation) { - case UINavigationControllerOperationPush: - if(_transitionNavigation != nil) { - [_transitionNavigation setReverse:NO]; - } - break; - case UINavigationControllerOperationPop: - if(_transitionNavigation != nil) { - [_transitionNavigation setReverse:YES]; - } - break; - default: - break; - } - return _transitionNavigation; -} - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimator.h b/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimator.h deleted file mode 100755 index acea162..0000000 --- a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimator.h +++ /dev/null @@ -1,44 +0,0 @@ -// -// SlideNavigationContorllerAnimation.h -// SlideMenu -// -// Created by Aryan Gh on 1/26/14. -// Copyright (c) 2014 Aryan Ghassemi. All rights reserved. -// -// https://github.com/aryaxt/iOS-Slide-Menu -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import -#import "SlideNavigationController.h" - -@protocol SlideNavigationContorllerAnimator - -// Initial state of the view before animation starts -// This gets called right before the menu is about to reveal -- (void)prepareMenuForAnimation:(Menu)menu; - -// Animate the view based on the progress (progress is between 0 and 1) -- (void)animateMenu:(Menu)menu withProgress:(CGFloat)progress; - -// Gets called ff for any the instance of animator is being change -// You should make any cleanup that is needed -- (void)clear; - -@end diff --git a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorFade.h b/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorFade.h deleted file mode 100755 index 4437bfd..0000000 --- a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorFade.h +++ /dev/null @@ -1,38 +0,0 @@ -// -// SlideNavigationContorllerAnimationFade.h -// SlideMenu -// -// Created by Aryan Gh on 1/26/14. -// Copyright (c) 2014 Aryan Ghassemi. All rights reserved. -// -// https://github.com/aryaxt/iOS-Slide-Menu -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import -#import "SlideNavigationContorllerAnimator.h" - -@interface SlideNavigationContorllerAnimatorFade : NSObject - -@property (nonatomic, assign) CGFloat maximumFadeAlpha; -@property (nonatomic, strong) UIColor *fadeColor; - -- (id)initWithMaximumFadeAlpha:(CGFloat)maximumFadeAlpha andFadeColor:(UIColor *)fadeColor; - -@end diff --git a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorFade.m b/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorFade.m deleted file mode 100755 index 09c3e60..0000000 --- a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorFade.m +++ /dev/null @@ -1,89 +0,0 @@ -// -// SlideNavigationContorllerAnimationFade.m -// SlideMenu -// -// Created by Aryan Gh on 1/26/14. -// Copyright (c) 2014 Aryan Ghassemi. All rights reserved. -// -// https://github.com/aryaxt/iOS-Slide-Menu -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import "SlideNavigationContorllerAnimatorFade.h" - -@interface SlideNavigationContorllerAnimatorFade() -@property (nonatomic, strong) UIView *fadeAnimationView; -@end - -@implementation SlideNavigationContorllerAnimatorFade - -#pragma mark - Initialization - - -- (id)init -{ - if (self = [self initWithMaximumFadeAlpha:.8 andFadeColor:[UIColor blackColor]]) - { - } - - return self; -} - -- (id)initWithMaximumFadeAlpha:(CGFloat)maximumFadeAlpha andFadeColor:(UIColor *)fadeColor -{ - if (self = [super init]) - { - self.maximumFadeAlpha = maximumFadeAlpha; - self.fadeColor = fadeColor; - - self.fadeAnimationView = [[UIView alloc] init]; - self.fadeAnimationView.backgroundColor = self.fadeColor; - } - - return self; -} - -#pragma mark - SlideNavigationContorllerAnimation Methods - - -- (void)prepareMenuForAnimation:(Menu)menu -{ - UIViewController *menuViewController = (menu == MenuLeft) - ? [SlideNavigationController sharedInstance].leftMenu - : [SlideNavigationController sharedInstance].rightMenu; - - self.fadeAnimationView.alpha = self.maximumFadeAlpha; - self.fadeAnimationView.frame = menuViewController.view.bounds; -} - -- (void)animateMenu:(Menu)menu withProgress:(CGFloat)progress -{ - UIViewController *menuViewController = (menu == MenuLeft) - ? [SlideNavigationController sharedInstance].leftMenu - : [SlideNavigationController sharedInstance].rightMenu; - - self.fadeAnimationView.frame = menuViewController.view.bounds; - [menuViewController.view addSubview:self.fadeAnimationView]; - self.fadeAnimationView.alpha = self.maximumFadeAlpha - (self.maximumFadeAlpha *progress); -} - -- (void)clear -{ - [self.fadeAnimationView removeFromSuperview]; -} - -@end diff --git a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorScale.h b/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorScale.h deleted file mode 100755 index a2092c4..0000000 --- a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorScale.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// SlideNavigationContorllerAnimationScale.h -// SlideMenu -// -// Created by Aryan Gh on 1/26/14. -// Copyright (c) 2014 Aryan Ghassemi. All rights reserved. -// -// https://github.com/aryaxt/iOS-Slide-Menu -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import -#import "SlideNavigationContorllerAnimator.h" - -@interface SlideNavigationContorllerAnimatorScale : NSObject - -@property (nonatomic, assign) CGFloat minimumScale; - -- (id)initWithMinimumScale:(CGFloat)minimumScale; - -@end diff --git a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorScale.m b/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorScale.m deleted file mode 100755 index 93fb90b..0000000 --- a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorScale.m +++ /dev/null @@ -1,80 +0,0 @@ -// -// SlideNavigationContorllerAnimationScale.m -// SlideMenu -// -// Created by Aryan Gh on 1/26/14. -// Copyright (c) 2014 Aryan Ghassemi. All rights reserved. -// -// https://github.com/aryaxt/iOS-Slide-Menu -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import "SlideNavigationContorllerAnimatorScale.h" - -@implementation SlideNavigationContorllerAnimatorScale - -#pragma mark - Initialization - - -- (id)init -{ - if (self = [self initWithMinimumScale:.9]) - { - } - - return self; -} - -- (id)initWithMinimumScale:(CGFloat)minimumScale -{ - if (self = [super init]) - { - self.minimumScale = minimumScale; - } - - return self; -} - -#pragma mark - SlideNavigationContorllerAnimation Methods - - -- (void)prepareMenuForAnimation:(Menu)menu -{ - UIViewController *menuViewController = (menu == MenuLeft) - ? [SlideNavigationController sharedInstance].leftMenu - : [SlideNavigationController sharedInstance].rightMenu; - - menuViewController.view.transform = CGAffineTransformScale(menuViewController.view.transform, self.minimumScale, self.minimumScale); -} - -- (void)animateMenu:(Menu)menu withProgress:(CGFloat)progress -{ - UIViewController *menuViewController = (menu == MenuLeft) - ? [SlideNavigationController sharedInstance].leftMenu - : [SlideNavigationController sharedInstance].rightMenu; - - CGFloat scale = MIN(1, (1-self.minimumScale) *progress + self.minimumScale); - menuViewController.view.transform = CGAffineTransformScale([SlideNavigationController sharedInstance].view.transform, scale, scale); -} - -- (void)clear -{ - [SlideNavigationController sharedInstance].leftMenu.view.transform = CGAffineTransformScale([SlideNavigationController sharedInstance].view.transform, 1, 1); - [SlideNavigationController sharedInstance].rightMenu.view.transform = CGAffineTransformScale([SlideNavigationController sharedInstance].view.transform, 1, 1); -} - -@end diff --git a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorScaleAndFade.h b/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorScaleAndFade.h deleted file mode 100755 index e83ba21..0000000 --- a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorScaleAndFade.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// SlideNavigationContorllerAnimationScaleAndFade.h -// SlideMenu -// -// Created by Aryan Gh on 1/26/14. -// Copyright (c) 2014 Aryan Ghassemi. All rights reserved. -// -// https://github.com/aryaxt/iOS-Slide-Menu -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import -#import "SlideNavigationContorllerAnimator.h" - -@interface SlideNavigationContorllerAnimatorScaleAndFade : NSObject - -- (id)initWithMaximumFadeAlpha:(CGFloat)maximumFadeAlpha fadeColor:(UIColor *)fadeColor andMinimumScale:(CGFloat)minimumScale; - -@end diff --git a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorScaleAndFade.m b/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorScaleAndFade.m deleted file mode 100755 index 84f7929..0000000 --- a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorScaleAndFade.m +++ /dev/null @@ -1,81 +0,0 @@ -// -// SlideNavigationContorllerAnimationScaleAndFade.m -// SlideMenu -// -// Created by Aryan Gh on 1/26/14. -// Copyright (c) 2014 Aryan Ghassemi. All rights reserved. -// -// https://github.com/aryaxt/iOS-Slide-Menu -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import "SlideNavigationContorllerAnimatorScaleAndFade.h" -#import "SlideNavigationContorllerAnimatorFade.h" -#import "SlideNavigationContorllerAnimatorScale.h" - -@interface SlideNavigationContorllerAnimatorScaleAndFade() -@property (nonatomic, strong) SlideNavigationContorllerAnimatorFade *fadeAnimation; -@property (nonatomic, strong) SlideNavigationContorllerAnimatorScale *scaleAnimation; -@end - -@implementation SlideNavigationContorllerAnimatorScaleAndFade - -#pragma mark - Initialization - - -- (id)init -{ - if (self = [self initWithMaximumFadeAlpha:.8 fadeColor:[UIColor blackColor] andMinimumScale:.8]) - { - } - - return self; -} - -- (id)initWithMaximumFadeAlpha:(CGFloat)maximumFadeAlpha fadeColor:(UIColor *)fadeColor andMinimumScale:(CGFloat)minimumScale -{ - if (self = [super init]) - { - self.fadeAnimation = [[SlideNavigationContorllerAnimatorFade alloc] initWithMaximumFadeAlpha:maximumFadeAlpha andFadeColor:fadeColor]; - self.scaleAnimation = [[SlideNavigationContorllerAnimatorScale alloc] initWithMinimumScale:minimumScale]; - } - - return self; -} - -#pragma mark - SlideNavigationContorllerAnimation Methods - - -- (void)prepareMenuForAnimation:(Menu)menu -{ - [self.fadeAnimation prepareMenuForAnimation:menu]; - [self.scaleAnimation prepareMenuForAnimation:menu]; -} - -- (void)animateMenu:(Menu)menu withProgress:(CGFloat)progress -{ - [self.fadeAnimation animateMenu:menu withProgress:progress]; - [self.scaleAnimation animateMenu:menu withProgress:progress]; -} - -- (void)clear -{ - [self.fadeAnimation clear]; - [self.scaleAnimation clear]; -} - -@end diff --git a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorSlide.h b/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorSlide.h deleted file mode 100755 index 189f12b..0000000 --- a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorSlide.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// SlideNavigationContorllerAnimationSlide.h -// SlideMenu -// -// Created by Aryan Gh on 1/26/14. -// Copyright (c) 2014 Aryan Ghassemi. All rights reserved. -// -// https://github.com/aryaxt/iOS-Slide-Menu -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import -#import "SlideNavigationContorllerAnimator.h" - -@interface SlideNavigationContorllerAnimatorSlide : NSObject - -@property (nonatomic, assign) CGFloat slideMovement; - -- (id)initWithSlideMovement:(CGFloat)slideMovement; - -@end diff --git a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorSlide.m b/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorSlide.m deleted file mode 100755 index 35439aa..0000000 --- a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorSlide.m +++ /dev/null @@ -1,173 +0,0 @@ -// -// SlideNavigationContorllerAnimationSlide.m -// SlideMenu -// -// Created by Aryan Gh on 1/26/14. -// Copyright (c) 2014 Aryan Ghassemi. All rights reserved. -// -// https://github.com/aryaxt/iOS-Slide-Menu -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import "SlideNavigationContorllerAnimatorSlide.h" - -@implementation SlideNavigationContorllerAnimatorSlide - -#pragma mark - Initialization - - -- (id)init -{ - if (self = [self initWithSlideMovement:100]) - { - } - - return self; -} - -- (id)initWithSlideMovement:(CGFloat)slideMovement -{ - if (self = [super init]) - { - self.slideMovement = slideMovement; - } - - return self; -} - -#pragma mark - SlideNavigationContorllerAnimation Methods - - -- (void)prepareMenuForAnimation:(Menu)menu -{ - UIViewController *menuViewController = (menu == MenuLeft) - ? [SlideNavigationController sharedInstance].leftMenu - : [SlideNavigationController sharedInstance].rightMenu; - - UIInterfaceOrientation orientation= [SlideNavigationController sharedInstance].interfaceOrientation; - CGRect rect = menuViewController.view.frame; - - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) - { - rect.origin.x = self.slideMovement; - } - else - { - if (UIInterfaceOrientationIsLandscape(orientation)) - { - if (orientation == UIInterfaceOrientationLandscapeRight) - { - rect.origin.y = (menu == MenuLeft) ? self.slideMovement*-1 : self.slideMovement; - } - else - { - rect.origin.y = (menu == MenuRight) ? self.slideMovement*-1 : self.slideMovement; - } - } - else - { - if (orientation == UIInterfaceOrientationPortrait) - { - rect.origin.x = (menu == MenuLeft) ? self.slideMovement*-1 : self.slideMovement; - } - else - { - rect.origin.x = (menu == MenuRight) ? self.slideMovement*-1 : self.slideMovement; - } - } - } - - menuViewController.view.frame = rect; -} - -- (void)animateMenu:(Menu)menu withProgress:(CGFloat)progress -{ - UIViewController *menuViewController = (menu == MenuLeft) - ? [SlideNavigationController sharedInstance].leftMenu - : [SlideNavigationController sharedInstance].rightMenu; - - UIInterfaceOrientation orientation = [SlideNavigationController sharedInstance].interfaceOrientation; - - NSInteger location = (menu == MenuLeft) - ? (self.slideMovement * -1) + (self.slideMovement * progress) - : (self.slideMovement * (1-progress)); - - if (menu == MenuLeft) - location = (location > 0) ? 0 : location; - - if (menu == MenuRight) - location = (location < 0) ? 0 : location; - - CGRect rect = menuViewController.view.frame; - - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) - { - rect.origin.x = location; - } - else - { - if (UIInterfaceOrientationIsLandscape(orientation)) - { - rect.origin.y = (orientation == UIInterfaceOrientationLandscapeRight) ? location : location*-1; - } - else - { - rect.origin.x = (orientation == UIInterfaceOrientationPortrait) ? location : location*-1; - } - } - - menuViewController.view.frame = rect; -} - -- (void)clear -{ - [self clearMenu:MenuLeft]; - [self clearMenu:MenuRight]; -} - -#pragma mark - Private Method - - -- (void)clearMenu:(Menu)menu -{ - UIViewController *menuViewController = (menu == MenuLeft) - ? [SlideNavigationController sharedInstance].leftMenu - : [SlideNavigationController sharedInstance].rightMenu; - - UIInterfaceOrientation orientation= [SlideNavigationController sharedInstance].interfaceOrientation; - - CGRect rect = menuViewController.view.frame; - - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) - { - rect.origin.x = 0; - } - else - { - if (UIInterfaceOrientationIsLandscape(orientation)) - { - rect.origin.y = 0; - } - else - { - rect.origin.x = 0; - } - } - - menuViewController.view.frame = rect; -} - -@end diff --git a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorSlideAndFade.h b/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorSlideAndFade.h deleted file mode 100755 index 9261509..0000000 --- a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorSlideAndFade.h +++ /dev/null @@ -1,35 +0,0 @@ -// -// SlideNavigationContorllerAnimationSlideAndFade.h -// SlideMenu -// -// Created by Aryan Gh on 1/26/14. -// Copyright (c) 2014 Aryan Ghassemi. All rights reserved. -// -// https://github.com/aryaxt/iOS-Slide-Menu -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import -#import "SlideNavigationContorllerAnimator.h" - -@interface SlideNavigationContorllerAnimatorSlideAndFade : NSObject - -- (id)initWithMaximumFadeAlpha:(CGFloat)maximumFadeAlpha fadeColor:(UIColor *)fadeColor andSlideMovement:(CGFloat)slideMovement; - -@end diff --git a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorSlideAndFade.m b/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorSlideAndFade.m deleted file mode 100755 index c0119b7..0000000 --- a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Animations/SlideNavigationContorllerAnimatorSlideAndFade.m +++ /dev/null @@ -1,81 +0,0 @@ -// -// SlideNavigationContorllerAnimationSlideAndFade.m -// SlideMenu -// -// Created by Aryan Gh on 1/26/14. -// Copyright (c) 2014 Aryan Ghassemi. All rights reserved. -// -// https://github.com/aryaxt/iOS-Slide-Menu -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import "SlideNavigationContorllerAnimatorSlideAndFade.h" -#import "SlideNavigationContorllerAnimatorSlide.h" -#import "SlideNavigationContorllerAnimatorFade.h" - -@interface SlideNavigationContorllerAnimatorSlideAndFade() -@property (nonatomic, strong) SlideNavigationContorllerAnimatorFade *fadeAnimation; -@property (nonatomic, strong) SlideNavigationContorllerAnimatorSlide *slideAnimation; -@end - -@implementation SlideNavigationContorllerAnimatorSlideAndFade - -#pragma mark - Initialization - - -- (id)init -{ - if (self = [self initWithMaximumFadeAlpha:.8 fadeColor:[UIColor blackColor] andSlideMovement:100]) - { - } - - return self; -} - -- (id)initWithMaximumFadeAlpha:(CGFloat)maximumFadeAlpha fadeColor:(UIColor *)fadeColor andSlideMovement:(CGFloat)slideMovement -{ - if (self = [super init]) - { - self.fadeAnimation = [[SlideNavigationContorllerAnimatorFade alloc] initWithMaximumFadeAlpha:maximumFadeAlpha andFadeColor:fadeColor]; - self.slideAnimation = [[SlideNavigationContorllerAnimatorSlide alloc] initWithSlideMovement:slideMovement]; - } - - return self; -} - -#pragma mark - SlideNavigationContorllerAnimation Methods - - -- (void)prepareMenuForAnimation:(Menu)menu -{ - [self.fadeAnimation prepareMenuForAnimation:menu]; - [self.slideAnimation prepareMenuForAnimation:menu]; -} - -- (void)animateMenu:(Menu)menu withProgress:(CGFloat)progress -{ - [self.fadeAnimation animateMenu:menu withProgress:progress]; - [self.slideAnimation animateMenu:menu withProgress:progress]; -} - -- (void)clear -{ - [self.fadeAnimation clear]; - [self.slideAnimation clear]; -} - -@end diff --git a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Assets/menu-button.png b/Classes/UI/ControllerSlideMenu/SlideNavigationController/Assets/menu-button.png deleted file mode 100755 index 4a4d467..0000000 Binary files a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Assets/menu-button.png and /dev/null differ diff --git a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Assets/menu-button@2x.png b/Classes/UI/ControllerSlideMenu/SlideNavigationController/Assets/menu-button@2x.png deleted file mode 100755 index 08dc402..0000000 Binary files a/Classes/UI/ControllerSlideMenu/SlideNavigationController/Assets/menu-button@2x.png and /dev/null differ diff --git a/Classes/UI/ControllerSlideMenu/SlideNavigationController/SlideNavigationController.h b/Classes/UI/ControllerSlideMenu/SlideNavigationController/SlideNavigationController.h deleted file mode 100755 index bc54bf1..0000000 --- a/Classes/UI/ControllerSlideMenu/SlideNavigationController/SlideNavigationController.h +++ /dev/null @@ -1,76 +0,0 @@ -// -// SlideNavigationController.h -// SlideMenu -// -// Created by Aryan Gh on 4/24/13. -// Copyright (c) 2013 Aryan Ghassemi. All rights reserved. -// -// https://github.com/aryaxt/iOS-Slide-Menu -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import -#import - -#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) - -@protocol SlideNavigationControllerDelegate -@optional -- (BOOL)slideNavigationControllerShouldDisplayRightMenu; -- (BOOL)slideNavigationControllerShouldDisplayLeftMenu; -@end - -typedef enum{ - MenuLeft = 1, - MenuRight = 2 -}Menu; - -@protocol SlideNavigationContorllerAnimator; -@interface SlideNavigationController : UINavigationController - -extern NSString * const SlideNavigationControllerDidOpen; -extern NSString *const SlideNavigationControllerDidClose; -extern NSString *const SlideNavigationControllerDidReveal; - -@property (nonatomic, assign) BOOL avoidSwitchingToSameClassViewController; -@property (nonatomic, assign) BOOL enableSwipeGesture; -@property (nonatomic, assign) BOOL enableShadow; -@property (nonatomic, strong) UIViewController *rightMenu; -@property (nonatomic, strong) UIViewController *leftMenu; -@property (nonatomic, strong) UIBarButtonItem *leftBarButtonItem; -@property (nonatomic, strong) UIBarButtonItem *rightBarButtonItem; -@property (nonatomic, assign) CGFloat portraitSlideOffset; -@property (nonatomic, assign) CGFloat landscapeSlideOffset; -@property (nonatomic, assign) CGFloat panGestureSideOffset; -@property (nonatomic, strong) id menuRevealAnimator; - -+ (SlideNavigationController *)sharedInstance; -- (void)switchToViewController:(UIViewController *)viewController withCompletion:(void (^)())completion __deprecated; -- (void)popToRootAndSwitchToViewController:(UIViewController *)viewController withSlideOutAnimation:(BOOL)slideOutAnimation andCompletion:(void (^)())completion; -- (void)popToRootAndSwitchToViewController:(UIViewController *)viewController withCompletion:(void (^)())completion; -- (void)popAllAndSwitchToViewController:(UIViewController *)viewController withSlideOutAnimation:(BOOL)slideOutAnimation andCompletion:(void (^)())completion; -- (void)popAllAndSwitchToViewController:(UIViewController *)viewController withCompletion:(void (^)())completion; -- (void)bounceMenu:(Menu)menu withCompletion:(void (^)())completion; -- (void)openMenu:(Menu)menu withCompletion:(void (^)())completion; -- (void)closeMenuWithCompletion:(void (^)())completion; -- (void)toggleLeftMenu; -- (void)toggleRightMenu; -- (BOOL)isMenuOpen; - -@end diff --git a/Classes/UI/ControllerSlideMenu/SlideNavigationController/SlideNavigationController.m b/Classes/UI/ControllerSlideMenu/SlideNavigationController/SlideNavigationController.m deleted file mode 100755 index 37089f8..0000000 --- a/Classes/UI/ControllerSlideMenu/SlideNavigationController/SlideNavigationController.m +++ /dev/null @@ -1,854 +0,0 @@ -// -// SlideNavigationController.m -// SlideMenu -// -// Created by Aryan Gh on 4/24/13. -// Copyright (c) 2013 Aryan Ghassemi. All rights reserved. -// -// https://github.com/aryaxt/iOS-Slide-Menu -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import "SlideNavigationController.h" -#import "SlideNavigationContorllerAnimator.h" - -typedef enum { - PopTypeAll, - PopTypeRoot -} PopType; - -@interface SlideNavigationController() -@property (nonatomic, strong) UITapGestureRecognizer *tapRecognizer; -@property (nonatomic, strong) UIPanGestureRecognizer *panRecognizer; -@property (nonatomic, assign) CGPoint draggingPoint; -@property (nonatomic, assign) Menu lastRevealedMenu; -@property (nonatomic, assign) BOOL menuNeedsLayout; -@end - -@implementation SlideNavigationController - -NSString * const SlideNavigationControllerDidOpen = @"SlideNavigationControllerDidOpen"; -NSString * const SlideNavigationControllerDidClose = @"SlideNavigationControllerDidClose"; -NSString *const SlideNavigationControllerDidReveal = @"SlideNavigationControllerDidReveal"; - -#define MENU_SLIDE_ANIMATION_DURATION .3 -#define MENU_QUICK_SLIDE_ANIMATION_DURATION .18 -#define MENU_IMAGE @"menu-button" -#define MENU_SHADOW_RADIUS 10 -#define MENU_SHADOW_OPACITY 1 -#define MENU_DEFAULT_SLIDE_OFFSET 60 -#define MENU_FAST_VELOCITY_FOR_SWIPE_FOLLOW_DIRECTION 1200 -#define STATUS_BAR_HEIGHT 20 -#define NOTIFICATION_USER_INFO_MENU_LEFT @"left" -#define NOTIFICATION_USER_INFO_MENU_RIGHT @"right" -#define NOTIFICATION_USER_INFO_MENU @"menu" - -static SlideNavigationController *singletonInstance; - -#pragma mark - Initialization - - -+ (SlideNavigationController *)sharedInstance -{ - if (!singletonInstance) - NSLog(@"SlideNavigationController has not been initialized. Either place one in your storyboard or initialize one in code"); - - return singletonInstance; -} - -- (id)init -{ - if (self = [super init]) - { - [self setup]; - } - - return self; -} - -- (id)initWithCoder:(NSCoder *)aDecoder -{ - if (self = [super initWithCoder:aDecoder]) - { - [self setup]; - } - - return self; -} - -- (id)initWithRootViewController:(UIViewController *)rootViewController -{ - if (self = [super initWithRootViewController:rootViewController]) - { - [self setup]; - } - - return self; -} - -- (void)setup -{ - if (singletonInstance) - NSLog(@"Singleton instance already exists. You can only instantiate one instance of SlideNavigationController. This could cause major issues"); - - singletonInstance = self; - - self.landscapeSlideOffset = MENU_DEFAULT_SLIDE_OFFSET; - self.portraitSlideOffset = MENU_DEFAULT_SLIDE_OFFSET; - self.panGestureSideOffset = 0; - self.avoidSwitchingToSameClassViewController = YES; - self.enableShadow = YES; - self.enableSwipeGesture = YES; - self.delegate = self; -} - -- (void)viewWillLayoutSubviews -{ - [super viewWillLayoutSubviews]; - - // Update shadow size of enabled - if (self.enableShadow) - self.view.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.view.bounds].CGPath; - - // When menu open we disable user interaction - // When rotates we want to make sure that userInteraction is enabled again - [self enableTapGestureToCloseMenu:NO]; - - if (self.menuNeedsLayout) - { - [self updateMenuFrameAndTransformAccordingToOrientation]; - - // Handle different horizontal/vertical slideOffset during rotation - // On iOS below 8 we just close the menu, iOS8 handles rotation better so we support keepiong the menu open - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0") && [self isMenuOpen]) - { - Menu menu = (self.horizontalLocation > 0) ? MenuLeft : MenuRight; - [self openMenu:menu withDuration:0 andCompletion:nil]; - } - - self.menuNeedsLayout = NO; - } -} - -- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator -{ - self.menuNeedsLayout = YES; -} - -- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration -{ - [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; - - self.menuNeedsLayout = YES; -} - -#pragma mark - Public Methods - - -- (void)bounceMenu:(Menu)menu withCompletion:(void (^)())completion -{ - [self prepareMenuForReveal:menu]; - NSInteger movementDirection = (menu == MenuLeft) ? 1 : -1; - - [UIView animateWithDuration:.16 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ - [self moveHorizontallyToLocation:30*movementDirection]; - } completion:^(BOOL finished){ - [UIView animateWithDuration:.1 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ - [self moveHorizontallyToLocation:0]; - } completion:^(BOOL finished){ - [UIView animateWithDuration:.12 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ - [self moveHorizontallyToLocation:16*movementDirection]; - } completion:^(BOOL finished){ - [UIView animateWithDuration:.08 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ - [self moveHorizontallyToLocation:0]; - } completion:^(BOOL finished){ - [UIView animateWithDuration:.08 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{ - [self moveHorizontallyToLocation:6*movementDirection]; - } completion:^(BOOL finished){ - [UIView animateWithDuration:.06 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ - [self moveHorizontallyToLocation:0]; - } completion:^(BOOL finished){ - if (completion) - completion(); - }]; - }]; - }]; - }]; - }]; - }]; -} - -- (void)switchToViewController:(UIViewController *)viewController - withSlideOutAnimation:(BOOL)slideOutAnimation - popType:(PopType)poptype - andCompletion:(void (^)())completion -{ - if (self.avoidSwitchingToSameClassViewController && [self.topViewController isKindOfClass:viewController.class]) - { - [self closeMenuWithCompletion:completion]; - return; - } - - void (^switchAndCallCompletion)(BOOL) = ^(BOOL closeMenuBeforeCallingCompletion) { - if (poptype == PopTypeAll) { - [self setViewControllers:@[viewController]]; - } - else { - [super popToRootViewControllerAnimated:NO]; - [super pushViewController:viewController animated:NO]; - } - - if (closeMenuBeforeCallingCompletion) - { - [self closeMenuWithCompletion:^{ - if (completion) - completion(); - }]; - } - else - { - if (completion) - completion(); - } - }; - - if ([self isMenuOpen]) - { - if (slideOutAnimation) - { - [UIView animateWithDuration:(slideOutAnimation) ? MENU_SLIDE_ANIMATION_DURATION : 0 - delay:0 - options:UIViewAnimationOptionCurveEaseOut - animations:^{ - CGFloat width = self.horizontalSize; - CGFloat moveLocation = (self.horizontalLocation> 0) ? width : -1*width; - [self moveHorizontallyToLocation:moveLocation]; - } completion:^(BOOL finished) { - switchAndCallCompletion(YES); - }]; - } - else - { - switchAndCallCompletion(YES); - } - } - else - { - switchAndCallCompletion(NO); - } -} - -- (void)switchToViewController:(UIViewController *)viewController withCompletion:(void (^)())completion -{ - [self switchToViewController:viewController withSlideOutAnimation:YES popType:PopTypeRoot andCompletion:completion]; -} - -- (void)popToRootAndSwitchToViewController:(UIViewController *)viewController - withSlideOutAnimation:(BOOL)slideOutAnimation - andCompletion:(void (^)())completion -{ - [self switchToViewController:viewController withSlideOutAnimation:slideOutAnimation popType:PopTypeRoot andCompletion:completion]; -} - -- (void)popToRootAndSwitchToViewController:(UIViewController *)viewController - withCompletion:(void (^)())completion -{ - [self switchToViewController:viewController withSlideOutAnimation:YES popType:PopTypeRoot andCompletion:completion]; -} - -- (void)popAllAndSwitchToViewController:(UIViewController *)viewController - withSlideOutAnimation:(BOOL)slideOutAnimation - andCompletion:(void (^)())completion -{ - [self switchToViewController:viewController withSlideOutAnimation:slideOutAnimation popType:PopTypeAll andCompletion:completion]; -} - -- (void)popAllAndSwitchToViewController:(UIViewController *)viewController - withCompletion:(void (^)())completion -{ - [self switchToViewController:viewController withSlideOutAnimation:YES popType:PopTypeAll andCompletion:completion]; -} - -- (void)closeMenuWithCompletion:(void (^)())completion -{ - [self closeMenuWithDuration:MENU_SLIDE_ANIMATION_DURATION andCompletion:completion]; -} - -- (void)openMenu:(Menu)menu withCompletion:(void (^)())completion -{ - [self openMenu:menu withDuration:MENU_SLIDE_ANIMATION_DURATION andCompletion:completion]; -} - -- (void)toggleLeftMenu -{ - [self toggleMenu:MenuLeft withCompletion:nil]; -} - -- (void)toggleRightMenu -{ - [self toggleMenu:MenuRight withCompletion:nil]; -} - -- (BOOL)isMenuOpen -{ - return (self.horizontalLocation == 0) ? NO : YES; -} - -- (void)setEnableShadow:(BOOL)enable -{ - _enableShadow = enable; - - if (enable) - { - self.view.layer.shadowColor = [UIColor darkGrayColor].CGColor; - self.view.layer.shadowRadius = MENU_SHADOW_RADIUS; - self.view.layer.shadowOpacity = MENU_SHADOW_OPACITY; - self.view.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.view.bounds].CGPath; - self.view.layer.shouldRasterize = YES; - self.view.layer.rasterizationScale = [UIScreen mainScreen].scale; - } - else - { - self.view.layer.shadowOpacity = 0; - self.view.layer.shadowRadius = 0; - } -} - -#pragma mark - Override Methods - - -- (NSArray *)popToRootViewControllerAnimated:(BOOL)animated -{ - if ([self isMenuOpen]) - { - [self closeMenuWithCompletion:^{ - [super popToRootViewControllerAnimated:animated]; - }]; - } - else - { - return [super popToRootViewControllerAnimated:animated]; - } - - return nil; -} - -- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated -{ - if ([self isMenuOpen]) - { - [self closeMenuWithCompletion:^{ - [super pushViewController:viewController animated:animated]; - }]; - } - else - { - [super pushViewController:viewController animated:animated]; - } -} - -- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated -{ - if ([self isMenuOpen]) - { - [self closeMenuWithCompletion:^{ - [super popToViewController:viewController animated:animated]; - }]; - } - else - { - return [super popToViewController:viewController animated:animated]; - } - - return nil; -} - -#pragma mark - Private Methods - - -- (void)updateMenuFrameAndTransformAccordingToOrientation -{ - // Animate rotatation when menu is open and device rotates - CGAffineTransform transform = self.view.transform; - self.leftMenu.view.transform = transform; - self.rightMenu.view.transform = transform; - - self.leftMenu.view.frame = [self initialRectForMenu]; - self.rightMenu.view.frame = [self initialRectForMenu]; -} - -- (void)enableTapGestureToCloseMenu:(BOOL)enable -{ - if (enable) - { - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) - self.interactivePopGestureRecognizer.enabled = NO; - - self.topViewController.view.userInteractionEnabled = NO; - [self.view addGestureRecognizer:self.tapRecognizer]; - } - else - { - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) - self.interactivePopGestureRecognizer.enabled = YES; - - self.topViewController.view.userInteractionEnabled = YES; - [self.view removeGestureRecognizer:self.tapRecognizer]; - } -} - -- (void)toggleMenu:(Menu)menu withCompletion:(void (^)())completion -{ - if ([self isMenuOpen]) - [self closeMenuWithCompletion:completion]; - else - [self openMenu:menu withCompletion:completion]; -} - -- (UIBarButtonItem *)barButtonItemForMenu:(Menu)menu -{ - SEL selector = (menu == MenuLeft) ? @selector(leftMenuSelected:) : @selector(righttMenuSelected:); - UIBarButtonItem *customButton = (menu == MenuLeft) ? self.leftBarButtonItem : self.rightBarButtonItem; - - if (customButton) - { - customButton.action = selector; - customButton.target = self; - return customButton; - } - else - { - UIImage *image = [UIImage imageNamed:MENU_IMAGE]; - return [[UIBarButtonItem alloc] initWithImage:image style:UIBarButtonItemStylePlain target:self action:selector]; - } -} - -- (BOOL)shouldDisplayMenu:(Menu)menu forViewController:(UIViewController *)vc -{ - if (menu == MenuRight) - { - if ([vc respondsToSelector:@selector(slideNavigationControllerShouldDisplayRightMenu)] && - [(UIViewController *)vc slideNavigationControllerShouldDisplayRightMenu]) - { - return YES; - } - } - if (menu == MenuLeft) - { - if ([vc respondsToSelector:@selector(slideNavigationControllerShouldDisplayLeftMenu)] && - [(UIViewController *)vc slideNavigationControllerShouldDisplayLeftMenu]) - { - return YES; - } - } - - return NO; -} - -- (void)openMenu:(Menu)menu withDuration:(float)duration andCompletion:(void (^)())completion -{ - [self enableTapGestureToCloseMenu:YES]; - - [self prepareMenuForReveal:menu]; - - [UIView animateWithDuration:duration - delay:0 - options:UIViewAnimationOptionCurveEaseOut - animations:^{ - CGRect rect = self.view.frame; - CGFloat width = self.horizontalSize; - rect.origin.x = (menu == MenuLeft) ? (width - self.slideOffset) : ((width - self.slideOffset )* -1); - [self moveHorizontallyToLocation:rect.origin.x]; - } - completion:^(BOOL finished) { - if (completion) - completion(); - - [self postNotificationWithName:SlideNavigationControllerDidOpen forMenu:menu]; - }]; -} - -- (void)closeMenuWithDuration:(float)duration andCompletion:(void (^)())completion -{ - [self enableTapGestureToCloseMenu:NO]; - - Menu menu = (self.horizontalLocation > 0) ? MenuLeft : MenuRight; - - [UIView animateWithDuration:duration - delay:0 - options:UIViewAnimationOptionCurveEaseOut - animations:^{ - CGRect rect = self.view.frame; - rect.origin.x = 0; - [self moveHorizontallyToLocation:rect.origin.x]; - } - completion:^(BOOL finished) { - if (completion) - completion(); - - [self postNotificationWithName:SlideNavigationControllerDidClose forMenu:menu]; - }]; -} - -- (void)moveHorizontallyToLocation:(CGFloat)location -{ - CGRect rect = self.view.frame; - UIInterfaceOrientation orientation = self.interfaceOrientation; - Menu menu = (self.horizontalLocation >= 0 && location >= 0) ? MenuLeft : MenuRight; - - if ((location > 0 && self.horizontalLocation <= 0) || (location < 0 && self.horizontalLocation >= 0)) { - [self postNotificationWithName:SlideNavigationControllerDidReveal forMenu:(location > 0) ? MenuLeft : MenuRight]; - } - - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) - { - rect.origin.x = location; - rect.origin.y = 0; - } - else - { - if (UIInterfaceOrientationIsLandscape(orientation)) - { - rect.origin.x = 0; - rect.origin.y = (orientation == UIInterfaceOrientationLandscapeRight) ? location : location*-1; - } - else - { - rect.origin.x = (orientation == UIInterfaceOrientationPortrait) ? location : location*-1; - rect.origin.y = 0; - } - } - - self.view.frame = rect; - [self updateMenuAnimation:menu]; -} - -- (void)updateMenuAnimation:(Menu)menu -{ - CGFloat progress = (menu == MenuLeft) - ? (self.horizontalLocation / (self.horizontalSize - self.slideOffset)) - : (self.horizontalLocation / ((self.horizontalSize - self.slideOffset) * -1)); - - [self.menuRevealAnimator animateMenu:menu withProgress:progress]; -} - -- (CGRect)initialRectForMenu -{ - CGRect rect = self.view.frame; - rect.origin.x = 0; - rect.origin.y = 0; - - if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"7.0")) - { - return rect; - } - - if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) - { - // For some reasons in landscape below the status bar is considered y=0, but in portrait it's considered y=20 - rect.origin.x = (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight) ? 0 : STATUS_BAR_HEIGHT; - rect.size.width = self.view.frame.size.width-STATUS_BAR_HEIGHT; - } - else - { - // For some reasons in landscape below the status bar is considered y=0, but in portrait it's considered y=20 - rect.origin.y = (self.interfaceOrientation == UIInterfaceOrientationPortrait) ? STATUS_BAR_HEIGHT : 0; - rect.size.height = self.view.frame.size.height-STATUS_BAR_HEIGHT; - } - - return rect; -} - -- (void)prepareMenuForReveal:(Menu)menu -{ - // Only prepare menu if it has changed (ex: from MenuLeft to MenuRight or vice versa) - if (self.lastRevealedMenu && menu == self.lastRevealedMenu) - return; - - UIViewController *menuViewController = (menu == MenuLeft) ? self.leftMenu : self.rightMenu; - UIViewController *removingMenuViewController = (menu == MenuLeft) ? self.rightMenu : self.leftMenu; - - self.lastRevealedMenu = menu; - - [removingMenuViewController.view removeFromSuperview]; - [self.view.window insertSubview:menuViewController.view atIndex:0]; - - [self updateMenuFrameAndTransformAccordingToOrientation]; - - [self.menuRevealAnimator prepareMenuForAnimation:menu]; -} - -- (CGFloat)horizontalLocation -{ - CGRect rect = self.view.frame; - UIInterfaceOrientation orientation = self.interfaceOrientation; - - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) - { - return rect.origin.x; - } - else - { - if (UIInterfaceOrientationIsLandscape(orientation)) - { - return (orientation == UIInterfaceOrientationLandscapeRight) - ? rect.origin.y - : rect.origin.y*-1; - } - else - { - return (orientation == UIInterfaceOrientationPortrait) - ? rect.origin.x - : rect.origin.x*-1; - } - } -} - -- (CGFloat)horizontalSize -{ - CGRect rect = self.view.frame; - UIInterfaceOrientation orientation = self.interfaceOrientation; - - if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) - { - return rect.size.width; - } - else - { - if (UIInterfaceOrientationIsLandscape(orientation)) - { - return rect.size.height; - } - else - { - return rect.size.width; - } - } -} - -- (void)postNotificationWithName:(NSString *)name forMenu:(Menu)menu -{ - NSString *menuString = (menu == MenuLeft) ? NOTIFICATION_USER_INFO_MENU_LEFT : NOTIFICATION_USER_INFO_MENU_RIGHT; - NSDictionary *userInfo = @{ NOTIFICATION_USER_INFO_MENU : menuString }; - [[NSNotificationCenter defaultCenter] postNotificationName:name object:nil userInfo:userInfo]; -} - -#pragma mark - UINavigationControllerDelegate Methods - - -- (void)navigationController:(UINavigationController *)navigationController - willShowViewController:(UIViewController *)viewController - animated:(BOOL)animated -{ - if ([self shouldDisplayMenu:MenuLeft forViewController:viewController]) - viewController.navigationItem.leftBarButtonItem = [self barButtonItemForMenu:MenuLeft]; - - if ([self shouldDisplayMenu:MenuRight forViewController:viewController]) - viewController.navigationItem.rightBarButtonItem = [self barButtonItemForMenu:MenuRight]; -} - -- (CGFloat)slideOffset -{ - return (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) - ? self.landscapeSlideOffset - : self.portraitSlideOffset; -} - -#pragma mark - IBActions - - -- (void)leftMenuSelected:(id)sender -{ - if ([self isMenuOpen]) - [self closeMenuWithCompletion:nil]; - else - [self openMenu:MenuLeft withCompletion:nil]; -} - -- (void)righttMenuSelected:(id)sender -{ - if ([self isMenuOpen]) - [self closeMenuWithCompletion:nil]; - else - [self openMenu:MenuRight withCompletion:nil]; -} - -#pragma mark - Gesture Recognizing - - -- (void)tapDetected:(UITapGestureRecognizer *)tapRecognizer -{ - [self closeMenuWithCompletion:nil]; -} - -- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch -{ - if (self.panGestureSideOffset == 0) - return YES; - - CGPoint pointInView = [touch locationInView:self.view]; - CGFloat horizontalSize = [self horizontalSize]; - - return (pointInView.x <= self.panGestureSideOffset || pointInView.x >= horizontalSize - self.panGestureSideOffset) - ? YES - : NO; -} - -- (void)panDetected:(UIPanGestureRecognizer *)aPanRecognizer -{ - CGPoint translation = [aPanRecognizer translationInView:aPanRecognizer.view]; - CGPoint velocity = [aPanRecognizer velocityInView:aPanRecognizer.view]; - NSInteger movement = translation.x - self.draggingPoint.x; - - Menu currentMenu; - - if (self.horizontalLocation > 0) - currentMenu = MenuLeft; - else if (self.horizontalLocation < 0) - currentMenu = MenuRight; - else - currentMenu = (translation.x > 0) ? MenuLeft : MenuRight; - - if (![self shouldDisplayMenu:currentMenu forViewController:self.topViewController]) - return; - - [self prepareMenuForReveal:currentMenu]; - - if (aPanRecognizer.state == UIGestureRecognizerStateBegan) - { - self.draggingPoint = translation; - } - else if (aPanRecognizer.state == UIGestureRecognizerStateChanged) - { - static CGFloat lastHorizontalLocation = 0; - CGFloat newHorizontalLocation = [self horizontalLocation]; - lastHorizontalLocation = newHorizontalLocation; - newHorizontalLocation += movement; - - if (newHorizontalLocation >= self.minXForDragging && newHorizontalLocation <= self.maxXForDragging) - [self moveHorizontallyToLocation:newHorizontalLocation]; - - self.draggingPoint = translation; - } - else if (aPanRecognizer.state == UIGestureRecognizerStateEnded) - { - NSInteger currentX = [self horizontalLocation]; - NSInteger currentXOffset = (currentX > 0) ? currentX : currentX * -1; - NSInteger positiveVelocity = (velocity.x > 0) ? velocity.x : velocity.x * -1; - - // If the speed is high enough follow direction - if (positiveVelocity >= MENU_FAST_VELOCITY_FOR_SWIPE_FOLLOW_DIRECTION) - { - Menu menu = (velocity.x > 0) ? MenuLeft : MenuRight; - - // Moving Right - if (velocity.x > 0) - { - if (currentX > 0) - { - if ([self shouldDisplayMenu:menu forViewController:self.visibleViewController]) - [self openMenu:(velocity.x > 0) ? MenuLeft : MenuRight withDuration:MENU_QUICK_SLIDE_ANIMATION_DURATION andCompletion:nil]; - } - else - { - [self closeMenuWithDuration:MENU_QUICK_SLIDE_ANIMATION_DURATION andCompletion:nil]; - } - } - // Moving Left - else - { - if (currentX > 0) - { - [self closeMenuWithDuration:MENU_QUICK_SLIDE_ANIMATION_DURATION andCompletion:nil]; - } - else - { - if ([self shouldDisplayMenu:menu forViewController:self.visibleViewController]) - [self openMenu:(velocity.x > 0) ? MenuLeft : MenuRight withDuration:MENU_QUICK_SLIDE_ANIMATION_DURATION andCompletion:nil]; - } - } - } - else - { - if (currentXOffset < (self.horizontalSize - self.slideOffset)/2) - [self closeMenuWithCompletion:nil]; - else - [self openMenu:(currentX > 0) ? MenuLeft : MenuRight withCompletion:nil]; - } - } -} - -- (NSInteger)minXForDragging -{ - if ([self shouldDisplayMenu:MenuRight forViewController:self.topViewController]) - { - return (self.horizontalSize - self.slideOffset) * -1; - } - - return 0; -} - -- (NSInteger)maxXForDragging -{ - if ([self shouldDisplayMenu:MenuLeft forViewController:self.topViewController]) - { - return self.horizontalSize - self.slideOffset; - } - - return 0; -} - -#pragma mark - Setter & Getter - - -- (UITapGestureRecognizer *)tapRecognizer -{ - if (!_tapRecognizer) - { - _tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapDetected:)]; - } - - return _tapRecognizer; -} - -- (UIPanGestureRecognizer *)panRecognizer -{ - if (!_panRecognizer) - { - _panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panDetected:)]; - _panRecognizer.delegate = self; - } - - return _panRecognizer; -} - -- (void)setEnableSwipeGesture:(BOOL)markEnableSwipeGesture -{ - _enableSwipeGesture = markEnableSwipeGesture; - - if (_enableSwipeGesture) - { - [self.view addGestureRecognizer:self.panRecognizer]; - } - else - { - [self.view removeGestureRecognizer:self.panRecognizer]; - } -} - -- (void)setMenuRevealAnimator:(id)menuRevealAnimator -{ - [self.menuRevealAnimator clear]; - - _menuRevealAnimator = menuRevealAnimator; -} - -@end diff --git a/Classes/UI/Core/MobilyContext.m b/Classes/UI/Core/MobilyContext.m deleted file mode 100644 index 942ae31..0000000 --- a/Classes/UI/Core/MobilyContext.m +++ /dev/null @@ -1,210 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyContext.h" - -/*--------------------------------------------------*/ - -#define MOBILY_FILE_PRESETS @"Presets" -#define MOBILY_FILE_APPLICATION @"Application" - -/*--------------------------------------------------*/ - -@interface MobilyContext () < UIApplicationDelegate > - -@property(nonatomic, readwrite, strong) MobilyApplication* application; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -static MobilyApplication* MOBILY_APPLICATION = nil; -static int MOBILY_YARG_COUNT = 0; -static char** MOBILY_YARG_VALUE = nil; -static NSString* MOBILY_ACCESS_KEY = nil; - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyContext - -@synthesize objectName = _objectName; -@synthesize objectParent = _objectParent; -@synthesize objectChilds = _objectChilds; - -#pragma mark Public - -+ (void)setArgCount:(int)argCount argValue:(char**)argValue { - MOBILY_YARG_COUNT = argCount; - MOBILY_YARG_VALUE = argValue; -} - -+ (void)setAccessKey:(NSString*)accessKey { - MOBILY_SAFE_SETTER(MOBILY_ACCESS_KEY, accessKey); -} - -+ (int)run { - return UIApplicationMain(MOBILY_YARG_COUNT, MOBILY_YARG_VALUE, nil, NSStringFromClass([MobilyContext class])); -} - -+ (id)application { - return MOBILY_APPLICATION; -} - -#pragma mark Standart - -- (id)init { - self = [super init]; - if(self != nil) { - } - return self; -} - -- (void)dealloc { - [self setApplication:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark MobilyBuilderObject - -- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIViewController class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andAddingObject:objectChild]]; - } -} - -- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIViewController class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andRemovingObject:objectChild]]; - } -} - -- (void)willLoadObjectChilds { -} - -- (void)didLoadObjectChilds { -} - -- (id< MobilyBuilderObject >)objectForName:(NSString*)name { - return [MobilyBuilderForm object:self forName:name]; -} - -- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { - return [MobilyBuilderForm object:self forSelector:selector]; -} - -#pragma mark UIApplicationDelegate - -- (void)setWindow:(UIWindow*)window { - [window makeKeyWindow]; -} - -- (UIWindow*)window { - return [[UIApplication sharedApplication] keyWindow]; -} - -- (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)options { - [MobilyBuilderPreset loadFromFilename:MOBILY_FILE_PRESETS]; - - id mobilyApplication = [MobilyBuilderForm objectFromFilename:MOBILY_FILE_APPLICATION owner:self]; - if([mobilyApplication isKindOfClass:[MobilyApplication class]] == YES) { - MOBILY_APPLICATION = mobilyApplication; - [self setApplication:mobilyApplication]; - if(_application != nil) { - [_application launchingWithOptions:options]; - } - } else { -#if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) - NSLog(@"Failure loading '%@' object '%@'", MOBILY_FILE_APPLICATION, NSStringFromClass([application class])); -#endif - } - return (_application != nil); -} - -- (void)applicationWillTerminate:(UIApplication*)application { - if(_application != nil) { - [_application terminate]; - [self setApplication:nil]; - } - MOBILY_APPLICATION = nil; -} - -- (void)applicationDidReceiveMemoryWarning:(UIApplication*)application { - [_application receiveMemoryWarning]; -} - -- (void)applicationDidBecomeActive:(UIApplication*)application { - [_application becomeActive]; -} - -- (void)applicationWillResignActive:(UIApplication*)application { - [_application resignActive]; -} - -- (void)applicationWillEnterForeground:(UIApplication*)application { - [_application enterForeground]; -} - -- (void)applicationDidEnterBackground:(UIApplication*)application { - [_application enterBackground]; -} - -- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken { - [_application registerForRemoteNotificationsWithDeviceToken:deviceToken]; -} - -- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error { - [_application failToRegisterForRemoteNotificationsWithError:error]; -} - -- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)notification { - [_application receiveRemoteNotification:notification]; -} - -- (void)application:(UIApplication*)application didReceiveLocalNotification:(UILocalNotification*)notification { - [_application receiveLocalNotification:notification]; -} - -- (BOOL)application:(UIApplication*)application openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation { - return [_application openURL:url sourceApplication:sourceApplication annotation:annotation]; -} - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyControllerNavigation.m b/Classes/UI/Core/MobilyControllerNavigation.m deleted file mode 100644 index e95f5d2..0000000 --- a/Classes/UI/Core/MobilyControllerNavigation.m +++ /dev/null @@ -1,273 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyControllerNavigation.h" -#import "MobilyControllerTabBar.h" -#import "MobilyController.h" -#import "MobilyEvent.h" - -/*--------------------------------------------------*/ - -@interface MobilyControllerNavigation () < UIViewControllerTransitioningDelegate, UINavigationControllerDelegate > - -@property(nonatomic, readwrite, assign, getter=isAppeared) BOOL appeared; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyControllerNavigation - -@synthesize objectName = _objectName; -@synthesize objectParent = _objectParent; -@synthesize objectChilds = _objectChilds; - -#pragma mark NSKeyValueCoding - -MOBILY_DEFINE_VALIDATE_TRANSITION_CONTROLLER(TransitionModal); -MOBILY_DEFINE_VALIDATE_TRANSITION_CONTROLLER(TransitionNavigation); -MOBILY_DEFINE_VALIDATE_EVENT(EventDidLoad) -MOBILY_DEFINE_VALIDATE_EVENT(EventDidUnload) -MOBILY_DEFINE_VALIDATE_EVENT(EventWillAppear) -MOBILY_DEFINE_VALIDATE_EVENT(EventDidAppear) -MOBILY_DEFINE_VALIDATE_EVENT(EventWillDisappear) -MOBILY_DEFINE_VALIDATE_EVENT(EventDidDisappear) - -#pragma mark Standart - -- (id)initWithCoder:(NSCoder*)coder { - self = [super initWithCoder:coder]; - if(self != nil) { - [self setupController]; - } - return self; -} - -- (id)initWithNibName:(NSString*)nib bundle:(NSBundle*)bundle { - self = [super initWithNibName:nib bundle:bundle]; - if(self != nil) { - [self setupController]; - } - return self; -} - -- (instancetype)initWithNavigationBarClass:(Class)navigationBarClass toolbarClass:(Class)toolbarClass { - self = [super initWithNavigationBarClass:navigationBarClass toolbarClass:toolbarClass]; - if(self != nil) { - [self setupController]; - } - return self; -} - -- (instancetype)initWithRootViewController:(UIViewController*)rootViewController { - self = [super initWithRootViewController:rootViewController]; - if(self != nil) { - [self setupController]; - } - return self; -} - -- (void)dealloc { - [self setObjectName:nil]; - [self setObjectParent:nil]; - [self setObjectChilds:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark MobilyBuilderObject - -- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIViewController class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andAddingObject:objectChild]]; - } -} - -- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIViewController class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andRemovingObject:objectChild]]; - } -} - -- (void)willLoadObjectChilds { -} - -- (void)didLoadObjectChilds { - if([self rootViewController] == nil) { - UIViewController* viewController = [_objectChilds firstObjectIsClass:[UIViewController class]]; - if(viewController != nil) { - [self setViewControllers:@[ viewController ]]; - } - } -} - -- (id< MobilyBuilderObject >)objectForName:(NSString*)name { - return [MobilyBuilderForm object:self forName:name]; -} - -- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { - return [MobilyBuilderForm object:self forSelector:selector]; -} - -#pragma mark Property - -- (BOOL)isAppeared { - return (_appeared > 0); -} - -#pragma mark Public - -- (void)setupController { - [self setDelegate:self]; -} - -#pragma mark UIViewController - -- (BOOL)shouldAutorotate { - return [[self topViewController] shouldAutorotate]; -} - -- (NSUInteger)supportedInterfaceOrientations { - return [[self topViewController] supportedInterfaceOrientations]; -} - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation { - return [[self topViewController] shouldAutorotateToInterfaceOrientation:orientation]; -} - -- (BOOL)prefersStatusBarHidden { - return [[self topViewController] prefersStatusBarHidden]; -} - -- (UIStatusBarStyle)preferredStatusBarStyle { - return [[self topViewController] preferredStatusBarStyle]; -} - -- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { - return [[self topViewController] preferredStatusBarUpdateAnimation]; -} - -- (void)viewDidLoad { - [super viewDidLoad]; - - if([self rootViewController] == nil) { - UIViewController* viewController = [_objectChilds firstObjectIsClass:[UIViewController class]]; - if(viewController != nil) { - [self setViewControllers:@[ viewController ]]; - } - } - [_eventDidLoad fireSender:self object:nil]; -} - -- (void)viewDidUnload { - [super viewDidUnload]; - - [_eventDidUnload fireSender:self object:nil]; -} - -- (void)viewWillAppear:(BOOL)animated { - [super viewWillAppear:animated]; - - [_eventWillAppear fireSender:self object:nil]; - [self setAppeared:_appeared + 1]; -} - -- (void)viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - - [_eventDidAppear fireSender:self object:nil]; -} - -- (void)viewWillDisappear:(BOOL)animated { - [super viewWillDisappear:animated]; - - [_eventWillDisappear fireSender:self object:nil]; -} - -- (void)viewDidDisappear:(BOOL)animated { - [super viewDidDisappear:animated]; - - [self setAppeared:_appeared - 1]; - [_eventDidDisappear fireSender:self object:nil]; -} - -#pragma mark UIViewControllerTransitioningDelegate - -- (id< UIViewControllerAnimatedTransitioning >)animationControllerForPresentedController:(UIViewController*)presented presentingController:(UIViewController*)presenting sourceController:(UIViewController*)source { - if(_transitionModal != nil) { - [_transitionModal setReverse:NO]; - } - return _transitionModal; -} - -- (id< UIViewControllerAnimatedTransitioning >)animationControllerForDismissedController:(UIViewController*)dismissed { - if(_transitionModal != nil) { - [_transitionModal setReverse:YES]; - } - return _transitionModal; -} - -#pragma mark UINavigationControllerDelegate - -- (void)navigationController:(UINavigationController*)navigationController willShowViewController:(UIViewController*)viewController animated:(BOOL)animated { - if([viewController isKindOfClass:[MobilyController class]] == YES) { - MobilyController* mobilyController = (MobilyController*)viewController; - [navigationController setNavigationBarHidden:[mobilyController isNavigationBarHidden] animated:animated]; - } -} - -- (id< UIViewControllerAnimatedTransitioning >)navigationController:(UINavigationController*)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController*)fromViewController toViewController:(UIViewController*)toViewController { - switch(operation) { - case UINavigationControllerOperationPush: - if(_transitionNavigation != nil) { - [_transitionNavigation setReverse:NO]; - } - break; - case UINavigationControllerOperationPop: - if(_transitionNavigation != nil) { - [_transitionNavigation setReverse:YES]; - } - break; - default: - break; - } - return _transitionNavigation; -} - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyControllerTabBar.m b/Classes/UI/Core/MobilyControllerTabBar.m deleted file mode 100644 index 7622584..0000000 --- a/Classes/UI/Core/MobilyControllerTabBar.m +++ /dev/null @@ -1,246 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyControllerTabBar.h" -#import "MobilyControllerNavigation.h" -#import "MobilyController.h" -#import "MobilyEvent.h" - -/*--------------------------------------------------*/ - -@interface MobilyControllerTabBar () < UIViewControllerTransitioningDelegate, UITabBarControllerDelegate > - -@property(nonatomic, readwrite, assign, getter=isAppeared) BOOL appeared; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyControllerTabBar - -@synthesize objectName = _objectName; -@synthesize objectParent = _objectParent; -@synthesize objectChilds = _objectChilds; - -#pragma mark NSKeyValueCoding - -MOBILY_DEFINE_VALIDATE_BOOL(NavigationBarHidden) -MOBILY_DEFINE_VALIDATE_TRANSITION_CONTROLLER(TransitionModal); -MOBILY_DEFINE_VALIDATE_TRANSITION_CONTROLLER(TransitionNavigation); -MOBILY_DEFINE_VALIDATE_EVENT(EventDidLoad) -MOBILY_DEFINE_VALIDATE_EVENT(EventDidUnload) -MOBILY_DEFINE_VALIDATE_EVENT(EventWillAppear) -MOBILY_DEFINE_VALIDATE_EVENT(EventDidAppear) -MOBILY_DEFINE_VALIDATE_EVENT(EventWillDisappear) -MOBILY_DEFINE_VALIDATE_EVENT(EventDidDisappear) - -#pragma mark Standart - -- (id)initWithCoder:(NSCoder*)coder { - self = [super initWithCoder:coder]; - if(self != nil) { - [self setupController]; - } - return self; -} - -- (id)initWithNibName:(NSString*)nib bundle:(NSBundle*)bundle { - self = [super initWithNibName:nib bundle:bundle]; - if(self != nil) { - [self setupController]; - } - return self; -} - -- (void)dealloc { - [self setObjectName:nil]; - [self setObjectParent:nil]; - [self setObjectChilds:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark MobilyBuilderObject - -- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIViewController class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andAddingObject:objectChild]]; - } -} - -- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIViewController class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andRemovingObject:objectChild]]; - } -} - -- (void)willLoadObjectChilds { -} - -- (void)didLoadObjectChilds { - if([UIDevice systemVersion] >= 7.0f) { - if([[self viewControllers] count] < 1) { - [self setViewControllers:[_objectChilds arrayByObjectClass:[UIViewController class]]]; - } - [_eventDidLoad fireSender:self object:nil]; - } -} - -- (id< MobilyBuilderObject >)objectForName:(NSString*)name { - return [MobilyBuilderForm object:self forName:name]; -} - -- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { - return [MobilyBuilderForm object:self forSelector:selector]; -} - -#pragma mark Property - -- (BOOL)isAppeared { - return (_appeared > 0); -} - -#pragma mark Public - -- (void)setupController { - [self setDelegate:self]; -} - -#pragma mark UIViewController - -- (BOOL)shouldAutorotate { - return [[self selectedViewController] shouldAutorotate]; -} - -- (NSUInteger)supportedInterfaceOrientations { - return [[self selectedViewController] supportedInterfaceOrientations]; -} - -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation { - return [[self selectedViewController] shouldAutorotateToInterfaceOrientation:orientation]; -} - -- (BOOL)prefersStatusBarHidden { - return [[self selectedViewController] prefersStatusBarHidden]; -} - -- (UIStatusBarStyle)preferredStatusBarStyle { - return [[self selectedViewController] preferredStatusBarStyle]; -} - -- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { - return [[self selectedViewController] preferredStatusBarUpdateAnimation]; -} - -- (void)viewDidLoad { - [super viewDidLoad]; - - if([UIDevice systemVersion] < 7.0f) { - if([[self viewControllers] count] < 1) { - [self setViewControllers:[_objectChilds arrayByObjectClass:[UIViewController class]]]; - } - [_eventDidLoad fireSender:self object:nil]; - } -} - -- (void)viewDidUnload { - [super viewDidUnload]; - - [_eventDidUnload fireSender:self object:nil]; -} - -- (void)viewWillAppear:(BOOL)animated { - [super viewWillAppear:animated]; - - if(_navigationBarHidden == YES) { - [[self navigationController] setNavigationBarHidden:YES animated:animated]; - } - [_eventWillAppear fireSender:self object:nil]; - [self setAppeared:_appeared + 1]; -} - -- (void)viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - - [_eventDidAppear fireSender:self object:nil]; -} - -- (void)viewWillDisappear:(BOOL)animated { - [super viewWillDisappear:animated]; - - if(_navigationBarHidden == YES) { - [[self navigationController] setNavigationBarHidden:NO animated:animated]; - } - [_eventWillDisappear fireSender:self object:nil]; -} - -- (void)viewDidDisappear:(BOOL)animated { - [super viewDidDisappear:animated]; - - [self setAppeared:_appeared - 1]; - [_eventDidDisappear fireSender:self object:nil]; -} - -#pragma mark UIViewControllerTransitioningDelegate - -- (id< UIViewControllerAnimatedTransitioning >)animationControllerForPresentedController:(UIViewController*)presented presentingController:(UIViewController*)presenting sourceController:(UIViewController*)source { - if(_transitionModal != nil) { - [_transitionModal setReverse:NO]; - } - return _transitionModal; -} - -- (id< UIViewControllerAnimatedTransitioning >)animationControllerForDismissedController:(UIViewController*)dismissed { - if(_transitionModal != nil) { - [_transitionModal setReverse:YES]; - } - return _transitionModal; -} - -#pragma mark UITabBarControllerDelegate - -- (id< UIViewControllerAnimatedTransitioning >)tabBarController:(UITabBarController*)tabBarController animationControllerForTransitionFromViewController:(UIViewController*)fromVC toViewController:(UIViewController*)toVC { - NSArray* viewControllers = [tabBarController viewControllers]; - NSUInteger fromVCIndex = [viewControllers indexOfObject:fromVC]; - NSUInteger toVCIndex = [viewControllers indexOfObject:toVC]; - [_transitionNavigation setReverse:fromVCIndex < toVCIndex]; - return _transitionNavigation; -} - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyTransitionController.m b/Classes/UI/Core/MobilyTransitionController.m deleted file mode 100644 index a12e3eb..0000000 --- a/Classes/UI/Core/MobilyTransitionController.m +++ /dev/null @@ -1,123 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyTransitionController.h" - -/*--------------------------------------------------*/ - -#define MOBILY_TRANSITION_CONTROLLER_CLASS @"MobilyTransitionController%@" - -/*--------------------------------------------------*/ - -@implementation NSString (MobilyTransitionController) - -- (MobilyTransitionController*)convertToTransitionController { - static NSCharacterSet* characterSet = nil; - if(characterSet == nil) { - characterSet = [NSCharacterSet characterSetWithCharactersInString:@":-"]; - } - - __block NSString* validKey = [NSString string];; - NSArray* components = [self componentsSeparatedByCharactersInSet:characterSet]; - if([components count] > 1) { - [components enumerateObjectsUsingBlock:^(NSString* component, NSUInteger index, BOOL* stop) { - validKey = [validKey stringByAppendingString:[component stringByUppercaseFirstCharacterString]]; - }]; - } else { - validKey = [self stringByUppercaseFirstCharacterString]; - } - - Class resultClass = nil; - if([validKey length] > 0) { - Class defaultClass = NSClassFromString([NSString stringWithFormat:MOBILY_TRANSITION_CONTROLLER_CLASS, validKey]); - if([defaultClass isSubclassOfClass:[MobilyTransitionController class]] == YES) { - resultClass = defaultClass; - } else { - Class customClass = NSClassFromString(self); - if([customClass isSubclassOfClass:[MobilyTransitionController class]] == YES) { - resultClass = customClass; - } - } - } - - MobilyTransitionController* result = nil; - if(resultClass != nil) { - result = [[resultClass alloc] init]; - } - return result; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyTransitionController - -#pragma mark Standart - -- (id)init { - self = [super init]; - if(self != nil) { - [self setupTransitionController]; - } - return self; -} - -#pragma mark Public - -- (void)setupTransitionController { - [self setDuration:1.0f]; -} - -- (void)animateTransition:(id< UIViewControllerContextTransitioning >)transitionContext fromVC:(UIViewController*)fromVC toVC:(UIViewController*)toVC fromView:(UIView*)fromView toView:(UIView*)toView { -} - -#pragma mark UIViewControllerAnimatedTransitioning - -- (NSTimeInterval)transitionDuration:(id< UIViewControllerContextTransitioning >)transitionContext { - return _duration; -} - -- (void)animateTransition:(id< UIViewControllerContextTransitioning >)transitionContext { - UIViewController* fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; - UIViewController* toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; - [self animateTransition:transitionContext fromVC:fromVC toVC:toVC fromView:[fromVC view] toView:[toVC view]]; -} - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyUI.h b/Classes/UI/Core/MobilyUI.h deleted file mode 100644 index 280d06f..0000000 --- a/Classes/UI/Core/MobilyUI.h +++ /dev/null @@ -1,408 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyNS.h" -#import "MobilyCG.h" - -/*--------------------------------------------------*/ - -#import "MobilyEvent.h" - -/*--------------------------------------------------*/ - -@interface NSString (MobilyUI) - -- (CGSize)implicitSizeWithFont:(UIFont*)font lineBreakMode:(NSLineBreakMode)lineBreakMode; -- (CGSize)implicitSizeWithFont:(UIFont*)font forWidth:(CGFloat)width lineBreakMode:(NSLineBreakMode)lineBreakMode; -- (CGSize)implicitSizeWithFont:(UIFont*)font forSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode; - -- (UIEdgeInsets)convertToEdgeInsets; -- (UIEdgeInsets)convertToEdgeInsetsSeparated:(NSString*)separated; - -- (UIBezierPath*)convertToBezierPath; -- (UIBezierPath*)convertToBezierPathSeparated:(NSString*)separated; - -- (UIFont*)convertToFont; -- (UIFont*)convertToFontSeparated:(NSString*)separated; -- (UIImage*)convertToImage; -- (UIImage*)convertToImageSeparated:(NSString*)separated edgeInsetsSeparated:(NSString*)edgeInsetsSeparated; -- (NSArray*)convertToImages; -- (NSArray*)convertToImagesSeparated:(NSString*)separated edgeInsetsSeparated:(NSString*)edgeInsetsSeparated frameSeparated:(NSString*)frameSeparated; - -- (UIRemoteNotificationType)convertToRemoteNotificationType; -- (UIRemoteNotificationType)convertToRemoteNotificationTypeSeparated:(NSString*)separated; -- (UIInterfaceOrientationMask)convertToInterfaceOrientationMask; -- (UIInterfaceOrientationMask)convertToInterfaceOrientationMaskSeparated:(NSString*)separated; - -- (UIStatusBarStyle)convertToStatusBarStyle; -- (UIStatusBarAnimation)convertToStatusBarAnimation; - -- (UIViewAutoresizing)convertToViewAutoresizing; -- (UIViewAutoresizing)convertToViewAutoresizingSeparated:(NSString*)separated; -- (UIViewContentMode)convertToViewContentMode; -- (UIControlContentHorizontalAlignment)convertToControlContentHorizontalAlignment; -- (UIControlContentVerticalAlignment)convertToControlContentVerticalAlignment; -- (UITextAutocapitalizationType)convertToTextAutocapitalizationType; -- (UITextAutocorrectionType)convertToTextAutocorrectionType; -- (UITextSpellCheckingType)convertToTestSpellCheckingType; -- (UIKeyboardType)convertToKeyboardType; -- (UIReturnKeyType)convertToReturnKeyType; -- (UIBaselineAdjustment)convertToBaselineAdjustment; - -- (UIScrollViewIndicatorStyle)convertToScrollViewIndicatorStyle; -- (UIScrollViewKeyboardDismissMode)convertToScrollViewKeyboardDismissMode; -- (UIBarStyle)convertToBarStyle; -- (UITabBarItemPositioning)convertToTabBarItemPositioning; -- (UISearchBarStyle)convertToSearchBarStyle; -- (UIProgressViewStyle)convertToProgressViewStyle; -- (UITextBorderStyle)convertToTextBorderStyle; - -@end - -/*--------------------------------------------------*/ -/* BASE */ -/*--------------------------------------------------*/ - -#define MOBILY_COLOR_RGB(R, G, B) [UIColor colorWithRed:(R) / 255.0f green:(G) / 255.0f blue:(B) / 255.0f alpha:1.0f] -#define MOBILY_COLOR_RGBA(R, G, B, A) [UIColor colorWithRed:(R) / 255.0f green:(G) / 255.0f blue:(B) / 255.0f alpha:(A) / 255.0f] - -/*--------------------------------------------------*/ - -typedef struct { - CGFloat hue; - CGFloat saturation; - CGFloat brightness; -} MobilyColorHSB; - -/*--------------------------------------------------*/ - -BOOL MobilyColorHSBEqualToColorHSB(MobilyColorHSB color1, MobilyColorHSB color2); - -/*--------------------------------------------------*/ - -@interface UIColor (MobilyUI) - -+ (UIColor*)colorWithString:(NSString*)string; -+ (CGFloat)colorComponentFromString:(NSString*)string start:(NSUInteger)start length:(NSUInteger)length; - --(MobilyColorHSB)hsb; - -@end - -/*--------------------------------------------------*/ - -@interface UIImage (MobilyUI) - -+ (UIImage*)imageNamed:(NSString*)name capInsets:(UIEdgeInsets)capInsets; - -- (UIImage*)scaleToSize:(CGSize)size; - -@end - -/*--------------------------------------------------*/ - -@interface UINib (MobilyUI) - -+ (id)viewWithNibName:(NSString*)nibName withClass:(Class)class; -+ (id)viewWithNibName:(NSString*)nibName withClass:(Class)class withOwner:(id)owner; - -+ (UINib*)nibWithBaseName:(NSString*)baseName bundle:(NSBundle*)bundle; -+ (UINib*)nibWithClass:(Class)class bundle:(NSBundle*)bundle; - -- (id)instantiateWithClass:(Class)class owner:(id)owner options:(NSDictionary*)options; - -@end - -/*--------------------------------------------------*/ - -@interface UIResponder (MobilyUI) - -+ (id)currentFirstResponderInView:(UIView*)view; -+ (id)currentFirstResponder; - -+ (UIResponder*)prevResponderFromView:(UIView*)view; -+ (UIResponder*)nextResponderFromView:(UIView*)view; - -@end - -/*--------------------------------------------------*/ -/* VIEWS */ -/*--------------------------------------------------*/ - -@interface UIWindow (MobilyUI) - -@property(nonatomic, readonly, strong) UIViewController* currentViewController; - -#ifdef __IPHONE_7_0 - -@property(nonatomic, readonly, strong) UIViewController* viewControllerForStatusBarStyle; -@property(nonatomic, readonly, strong) UIViewController* viewControllerForStatusBarHidden; - -#endif - -@end - -/*--------------------------------------------------*/ - -@interface UIView (MobilyUI) - -@property(nonatomic, readwrite, assign) CGPoint framePosition; -@property(nonatomic, readwrite, assign) CGPoint frameCenter; -@property(nonatomic, readwrite, assign) CGSize frameSize; -@property(nonatomic, readwrite, assign) CGFloat frameSX; -@property(nonatomic, readwrite, assign) CGFloat frameCX; -@property(nonatomic, readwrite, assign) CGFloat frameEX; -@property(nonatomic, readwrite, assign) CGFloat frameSY; -@property(nonatomic, readwrite, assign) CGFloat frameCY; -@property(nonatomic, readwrite, assign) CGFloat frameEY; -@property(nonatomic, readwrite, assign) CGFloat frameWidth; -@property(nonatomic, readwrite, assign) CGFloat frameHeight; -@property(nonatomic, readwrite, assign) CGFloat frameLeft; -@property(nonatomic, readwrite, assign) CGFloat frameRight; -@property(nonatomic, readwrite, assign) CGFloat frameTop; -@property(nonatomic, readwrite, assign) CGFloat frameBottom; - -@property(nonatomic, readonly, assign) CGPoint boundsPosition; -@property(nonatomic, readonly, assign) CGPoint boundsCenter; -@property(nonatomic, readonly, assign) CGSize boundsSize; -@property(nonatomic, readonly, assign) CGFloat boundsCX; -@property(nonatomic, readonly, assign) CGFloat boundsCY; -@property(nonatomic, readonly, assign) CGFloat boundsWidth; -@property(nonatomic, readonly, assign) CGFloat boundsHeight; - -@property(nonatomic, readwrite, assign) CGFloat cornerRadius; -@property(nonatomic, readwrite, assign) CGFloat borderWidth; -@property(nonatomic, readwrite, strong) UIColor* borderColor; -@property(nonatomic, readwrite, strong) UIColor* shadowColor; -@property(nonatomic, readwrite, assign) CGFloat shadowOpacity; -@property(nonatomic, readwrite, assign) CGSize shadowOffset; -@property(nonatomic, readwrite, assign) CGFloat shadowRadius; -@property(nonatomic, readwrite, strong) UIBezierPath* shadowPath; - -- (NSArray*)responders; - -- (BOOL)isContainsSubview:(UIView*)subview; - -- (void)removeSubview:(UIView*)subview; - -- (void)setSubviews:(NSArray*)subviews; -- (void)removeAllSubviews; - -- (void)blinkBackgroundColor:(UIColor*)color duration:(NSTimeInterval)duration timeout:(NSTimeInterval)timeout; - -@end - -/*--------------------------------------------------*/ - -@interface UIScrollView (MobilyUI) - -@property(nonatomic, readwrite, assign) UIEdgeInsets keyboardInset; - -@property(nonatomic, readwrite, assign) CGFloat contentOffsetX; -@property(nonatomic, readwrite, assign) CGFloat contentOffsetY; -@property(nonatomic, readwrite, assign) CGFloat contentSizeWidth; -@property(nonatomic, readwrite, assign) CGFloat contentSizeHeight; -@property(nonatomic, readwrite, assign) CGFloat contentInsetTop; -@property(nonatomic, readwrite, assign) CGFloat contentInsetRight; -@property(nonatomic, readwrite, assign) CGFloat contentInsetBottom; -@property(nonatomic, readwrite, assign) CGFloat contentInsetLeft; -@property(nonatomic, readwrite, assign) CGFloat scrollIndicatorInsetTop; -@property(nonatomic, readwrite, assign) CGFloat scrollIndicatorInsetRight; -@property(nonatomic, readwrite, assign) CGFloat scrollIndicatorInsetBottom; -@property(nonatomic, readwrite, assign) CGFloat scrollIndicatorInsetLeft; - -- (void)setContentOffsetX:(CGFloat)contentOffsetX animated:(BOOL)animated; -- (void)setContentOffsetY:(CGFloat)contentOffsetY animated:(BOOL)animated; - -- (CGSize)contentSizeFromSubviews; - -- (void)registerAdjustmentResponder; -- (void)unregisterAdjustmentResponder; - -@end - -/*--------------------------------------------------*/ - -@interface UITabBar (MobilyUI) - -@property(nonatomic, readwrite, assign) NSUInteger selectedItemIndex; - -@end - -/*--------------------------------------------------*/ - -@interface UINavigationBar (MobilyUI) - - - -@end - -/*--------------------------------------------------*/ - -@interface UILabel (MobilyUI) - -- (CGSize)implicitSize; -- (CGSize)implicitSizeForWidth:(CGFloat)width; -- (CGSize)implicitSizeForSize:(CGSize)size; - -@end - -/*--------------------------------------------------*/ - -@interface UIButton (MobilyUI) - -@property(nonatomic, readwrite, strong) NSString* normalTitle; -@property(nonatomic, readwrite, strong) UIColor* normalTitleColor; -@property(nonatomic, readwrite, strong) UIColor* normalTitleShadowColor; -@property(nonatomic, readwrite, strong) UIImage* normalImage; -@property(nonatomic, readwrite, strong) UIImage* normalBackgroundImage; - -@property(nonatomic, readwrite, strong) NSString* highlightedTitle; -@property(nonatomic, readwrite, strong) UIColor* highlightedTitleColor; -@property(nonatomic, readwrite, strong) UIColor* highlightedTitleShadowColor; -@property(nonatomic, readwrite, strong) UIImage* highlightedImage; -@property(nonatomic, readwrite, strong) UIImage* highlightedBackgroundImage; - -@property(nonatomic, readwrite, strong) NSString* disabledTitle; -@property(nonatomic, readwrite, strong) UIColor* disabledTitleColor; -@property(nonatomic, readwrite, strong) UIColor* disabledTitleShadowColor; -@property(nonatomic, readwrite, strong) UIImage* disabledImage; -@property(nonatomic, readwrite, strong) UIImage* disabledBackgroundImage; - -@property(nonatomic, readwrite, strong) NSString* selectedTitle; -@property(nonatomic, readwrite, strong) UIColor* selectedTitleColor; -@property(nonatomic, readwrite, strong) UIColor* selectedTitleShadowColor; -@property(nonatomic, readwrite, strong) UIImage* selectedImage; -@property(nonatomic, readwrite, strong) UIImage* selectedBackgroundImage; - -@end - -/*--------------------------------------------------*/ -/* CONTROLLERS */ -/*--------------------------------------------------*/ - -@interface UIViewController (MobilyUI) - -- (void)loadViewIfNeed; -- (void)unloadViewIfPossible; -- (void)unloadView; - -- (UIViewController*)currentViewController; - -@end - -/*--------------------------------------------------*/ - -@interface UINavigationController (MobilyUI) - -@property(nonatomic, readwrite, assign, getter=isTranslucent) BOOL translucent NS_AVAILABLE_IOS(3_0); -@property(nonatomic, readwrite, retain) UIColor* tintColor; -@property(nonatomic, readwrite, retain) UIColor* barTintColor NS_AVAILABLE_IOS(7_0); -@property(nonatomic, readwrite, retain) UIImage* shadowImage NS_AVAILABLE_IOS(6_0); -@property(nonatomic, readwrite, copy) NSDictionary* titleTextAttributes NS_AVAILABLE_IOS(5_0); -@property(nonatomic, readwrite, retain) UIImage* backIndicatorImage NS_AVAILABLE_IOS(7_0); -@property(nonatomic, readwrite, retain) UIImage* backIndicatorTransitionMaskImage NS_AVAILABLE_IOS(7_0); - -- (UIViewController*)rootViewController; - -@end - -/*--------------------------------------------------*/ - -@interface UINavigationItem (MobilyUI) - -- (void)setLeftBarView:(UIView*)view animated:(BOOL)animated; -- (void)setRightBarView:(UIView*)view animated:(BOOL)animated; - -@end - -/*--------------------------------------------------*/ -/* OTHER */ -/*--------------------------------------------------*/ - -@interface UIDevice (MobilyUI) - -+ (CGFloat)systemVersion; - -+ (BOOL)isIPhone; -+ (BOOL)isIPad; - -@end - -/*--------------------------------------------------*/ - -#define MOBILY_DEFINE_VALIDATE_STRING(name) \ -- (BOOL)validate##name:(inout id*)value error:(out NSError**)error { \ - return [*value isKindOfClass:[NSString class]]; \ -} - -/*--------------------------------------------------*/ - -#define MOBILY_DEFINE_VALIDATE_STRING_BASED(name, resultClass, convertValue) \ -- (BOOL)validate##name:(inout id*)value error:(out NSError**)error { \ - if([*value isKindOfClass:[NSString class]] == YES) { \ - *value = convertValue; \ - } \ - return [*value isKindOfClass:[resultClass class]]; \ -} - -#define MOBILY_DEFINE_VALIDATE_BOOL(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithBool:[*value convertToBool]]) -#define MOBILY_DEFINE_VALIDATE_NUMBER(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [*value convertToNumber]) -#define MOBILY_DEFINE_VALIDATE_RECT(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSValue, [NSValue valueWithCGRect:[*value convertToRect]]) -#define MOBILY_DEFINE_VALIDATE_POINT(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSValue, [NSValue valueWithCGPoint:[*value convertToPoint]]) -#define MOBILY_DEFINE_VALIDATE_SIZE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSValue, [NSValue valueWithCGSize:[*value convertToSize]]) -#define MOBILY_DEFINE_VALIDATE_EDGE_INSETS(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSValue, [NSValue valueWithUIEdgeInsets:[*value convertToEdgeInsets]]) -#define MOBILY_DEFINE_VALIDATE_COLOR(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, UIColor, [UIColor colorWithString:*value]) -#define MOBILY_DEFINE_VALIDATE_BEZIER_PATH(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, UIBezierPath, [*value convertToBezierPath]) -#define MOBILY_DEFINE_VALIDATE_IMAGE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, UIImage, [*value convertToImage]) -#define MOBILY_DEFINE_VALIDATE_FONT(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, UIFont, [*value convertToFont]) -#define MOBILY_DEFINE_VALIDATE_REMOTE_NOTIFICATION_TYPE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToRemoteNotificationType]]) -#define MOBILY_DEFINE_VALIDATE_INTERFACE_ORIENTATION_MASK(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToInterfaceOrientationMask]]) -#define MOBILY_DEFINE_VALIDATE_STATUS_BAR_STYLE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToStatusBarStyle]]) -#define MOBILY_DEFINE_VALIDATE_STATUS_BAR_ANIMATION(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToStatusBarAnimation]]) -#define MOBILY_DEFINE_VALIDATE_AUTORESIZING(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToViewAutoresizing]]) -#define MOBILY_DEFINE_VALIDATE_CONTENT_MODE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToViewContentMode]]) -#define MOBILY_DEFINE_VALIDATE_TEXT_ALIGNMENT(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToTextAlignment]]) -#define MOBILY_DEFINE_VALIDATE_LINE_BREAKMODE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToLineBreakMode]]) -#define MOBILY_DEFINE_VALIDATE_BASELINE_ADJUSTMENT(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToBaselineAdjustment]]) -#define MOBILY_DEFINE_VALIDATE_SCROLL_VIEW_INDICATOR_STYLE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToScrollViewIndicatorStyle]]) -#define MOBILY_DEFINE_VALIDATE_SCROLL_VIEW_KEYBOARD_DISMISS_MODE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToScrollViewKeyboardDismissMode]]) -#define MOBILY_DEFINE_VALIDATE_BAR_STYLE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToBarStyle]]) -#define MOBILY_DEFINE_VALIDATE_TAB_BAR_ITEM_POSITIONING(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToTabBarItemPositioning]]) -#define MOBILY_DEFINE_VALIDATE_SEARCH_BAR_STYLE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToSearchBarStyle]]) -#define MOBILY_DEFINE_VALIDATE_PROGRESS_VIEW_STYLE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToProgressViewStyle]]) -#define MOBILY_DEFINE_VALIDATE_TEXT_BORDER_STYLE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[*value convertToTextBorderStyle]]) - -/*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyUI.m b/Classes/UI/Core/MobilyUI.m deleted file mode 100644 index f66b903..0000000 --- a/Classes/UI/Core/MobilyUI.m +++ /dev/null @@ -1,2032 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyUI.h" -#import "MobilyCG.h" - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation NSString (MobilyUI) - -- (CGSize)implicitSizeWithFont:(UIFont*)font lineBreakMode:(NSLineBreakMode)lineBreakMode { - return [self implicitSizeWithFont:font forSize:CGSizeMake(NSIntegerMax, NSIntegerMax) lineBreakMode:lineBreakMode]; -} - -- (CGSize)implicitSizeWithFont:(UIFont*)font forWidth:(CGFloat)width lineBreakMode:(NSLineBreakMode)lineBreakMode { - return [self implicitSizeWithFont:font forSize:CGSizeMake(width, NSIntegerMax) lineBreakMode:lineBreakMode]; -} - -- (CGSize)implicitSizeWithFont:(UIFont*)font forSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode { -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_0 - if([UIDevice systemVersion] >= 7.0) { - NSMutableParagraphStyle* paragraphStyle = MOBILY_SAFE_AUTORELEASE([NSMutableParagraphStyle new]); - [paragraphStyle setLineBreakMode:lineBreakMode]; - NSDictionary* attributes = @{ NSFontAttributeName : font, NSParagraphStyleAttributeName : paragraphStyle }; - CGRect textRect = [self boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attributes context:nil]; - if(textRect.size.height < [font lineHeight]) { - textRect.size.height = [font lineHeight]; - } - return CGSizeMake(floorf(textRect.size.width), floorf(textRect.size.height)); - } -#endif -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - size = [self sizeWithFont:font constrainedToSize:size lineBreakMode:lineBreakMode]; - if(size.height < [font lineHeight]) { - size.height = [font lineHeight]; - } -#pragma clang diagnostic pop - return CGSizeMake(floorf(size.width), floorf(size.height)); -} - -- (UIEdgeInsets)convertToEdgeInsets { - return [self convertToEdgeInsetsSeparated:@";"]; -} - -- (UIEdgeInsets)convertToEdgeInsetsSeparated:(NSString*)separated { - UIEdgeInsets result = UIEdgeInsetsZero; - static NSNumberFormatter* formatter = nil; - if(formatter == nil) { - formatter = [NSNumberFormatter new]; - [formatter setNumberStyle:NSNumberFormatterDecimalStyle]; - } - NSArray* array = [self componentsSeparatedByString:separated]; - switch([array count]) { - case 1: { - result.top = [[formatter numberFromString:[array objectAtIndex:0]] floatValue]; - result.left = result.bottom = result.right = result.top; - break; - } - case 2: { - result.top = [[formatter numberFromString:[array objectAtIndex:0]] floatValue]; - result.left = [[formatter numberFromString:[array objectAtIndex:1]] floatValue]; - result.bottom = result.top; - result.right = result.left; - break; - } - case 4: { - result.top = [[formatter numberFromString:[array objectAtIndex:0]] floatValue]; - result.left = [[formatter numberFromString:[array objectAtIndex:1]] floatValue]; - result.bottom = [[formatter numberFromString:[array objectAtIndex:2]] floatValue]; - result.right = [[formatter numberFromString:[array objectAtIndex:3]] floatValue]; - break; - } - default: - break; - } - return result; -} - -- (UIBezierPath*)convertToBezierPath { - return [self convertToBezierPathSeparated:@";"]; -} - -- (UIBezierPath*)convertToBezierPathSeparated:(NSString*)separated { - return nil; -} - -- (UIFont*)convertToFont { - return [self convertToFontSeparated:@";"]; -} - -- (UIFont*)convertToFontSeparated:(NSString*)separated { - UIFont* result = nil; - NSArray* array = [self componentsSeparatedByString:separated]; - if([array count] > 0) { - static NSNumberFormatter* formatter = nil; - if(formatter == nil) { - formatter = [NSNumberFormatter new]; - [formatter setNumberStyle:NSNumberFormatterDecimalStyle]; - } - switch([array count]) { - case 1: { - result = [UIFont fontWithName:[array objectAtIndex:0] size:[UIFont systemFontSize]]; - break; - } - case 2: { - result = [UIFont fontWithName:[array objectAtIndex:0] size:[[formatter numberFromString:[array objectAtIndex:1]] floatValue]]; - break; - } - default: - break; - } - } - return result; -} - -- (UIImage*)convertToImage { - return [self convertToImageSeparated:@";" edgeInsetsSeparated:@";"]; -} - -- (UIImage*)convertToImageSeparated:(NSString*)separated edgeInsetsSeparated:(NSString*)edgeInsetsSeparated { - UIImage* result = nil; - NSArray* array = [self componentsSeparatedByString:separated]; - switch([array count]) { - case 1: { - result = [UIImage imageNamed:self]; - break; - } - default:{ - NSString* pattern = [NSString stringWithFormat:@"([A-Za-z0-9-_]+)[%@]+\\[([0-9%@ ]*)\\]", separated, edgeInsetsSeparated]; - NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:NULL]; - NSArray* matches = [regex matchesInString:self options:0 range:NSMakeRange(0, [self length])]; - if([matches count] > 0) { - NSTextCheckingResult* match = [matches objectAtIndex:0]; - if([match numberOfRanges] == 3) { - NSString* imageName = [self substringWithRange:[match rangeAtIndex:1]]; - result = [UIImage imageNamed:imageName]; - if(result != nil) { - UIEdgeInsets edgeInsets = UIEdgeInsetsZero; - NSString* imageInsets = [self substringWithRange:[match rangeAtIndex:2]]; - if(imageInsets != nil) { - [imageInsets convertToEdgeInsetsSeparated:edgeInsetsSeparated]; - } - result = [result resizableImageWithCapInsets:edgeInsets]; - } - } - } - break; - } - } - return result; -} - -- (NSArray*)convertToImages { - return [self convertToImagesSeparated:@";" edgeInsetsSeparated:@";" frameSeparated:@"|"]; -} - -- (NSArray*)convertToImagesSeparated:(NSString*)separated edgeInsetsSeparated:(NSString*)edgeInsetsSeparated frameSeparated:(NSString*)frameSeparated { - NSMutableArray* result = [NSMutableArray array]; - NSArray* array = [self componentsSeparatedByString:frameSeparated]; - if([array count] > 0) { - [array enumerateObjectsUsingBlock:^(NSString* frame, NSUInteger index, BOOL* stop) { - UIImage* image = [frame convertToImageSeparated:separated edgeInsetsSeparated:edgeInsetsSeparated]; - if(image != nil) { - [result addObject:image]; - } - }]; - } - return result; -} - -- (UIRemoteNotificationType)convertToRemoteNotificationType { - return [self convertToRemoteNotificationTypeSeparated:@"|"]; -} - -- (UIRemoteNotificationType)convertToRemoteNotificationTypeSeparated:(NSString*)separated { - __block UIRemoteNotificationType result = UIRemoteNotificationTypeNone; - NSString* value = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([value isEqualToString:@"all"] == YES) { - result = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeNewsstandContentAvailability; - } else { - NSArray* keys = [value componentsSeparatedByString:separated]; - [keys enumerateObjectsUsingBlock:^(NSString* key, NSUInteger index, BOOL* stop) { - NSString* temp = [key stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; - if([temp isEqualToString:@"badge"] == YES) { - result |= UIRemoteNotificationTypeBadge; - } else if([temp isEqualToString:@"sound"] == YES) { - result |= UIRemoteNotificationTypeSound; - } else if([temp isEqualToString:@"alert"] == YES) { - result |= UIRemoteNotificationTypeAlert; - } else if([temp isEqualToString:@"news-stand"] == YES) { - result |= UIRemoteNotificationTypeNewsstandContentAvailability; - } - }]; - } - return result; -} - -- (UIInterfaceOrientationMask)convertToInterfaceOrientationMask { - return [self convertToInterfaceOrientationMaskSeparated:@"|"]; -} - -- (UIInterfaceOrientationMask)convertToInterfaceOrientationMaskSeparated:(NSString*)separated { - __block UIInterfaceOrientationMask result = 0; - NSString* value = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([value isEqualToString:@"all"] == YES) { - result = UIInterfaceOrientationMaskAll; - } else { - NSArray* keys = [value componentsSeparatedByString:separated]; - [keys enumerateObjectsUsingBlock:^(NSString* key, NSUInteger index, BOOL* stop) { - NSString* temp = [key stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; - if([temp isEqualToString:@"portrait"] == YES) { - result |= UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; - } else if([temp isEqualToString:@"landscape"] == YES) { - result |= UIInterfaceOrientationMaskLandscape; - } else if([temp isEqualToString:@"portrait-down"] == YES) { - result |= UIInterfaceOrientationMaskPortrait; - } else if([temp isEqualToString:@"portrait-up"] == YES) { - result |= UIInterfaceOrientationMaskPortraitUpsideDown; - } else if([temp isEqualToString:@"landscape-left"] == YES) { - result |= UIInterfaceOrientationMaskLandscapeLeft; - } else if([temp isEqualToString:@"landscape-right"] == YES) { - result |= UIInterfaceOrientationMaskLandscapeRight; - } - }]; - } - return result; -} - -- (UIStatusBarStyle)convertToStatusBarStyle { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"default"] == YES) { - return UIStatusBarStyleDefault; - } else if([temp isEqualToString:@"light-content"] == YES) { - return UIStatusBarStyleLightContent; - } else if([temp isEqualToString:@"black-translucent"] == YES) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - return UIStatusBarStyleBlackTranslucent; -#pragma clang diagnostic pop - } else if([temp isEqualToString:@"black-opaque"] == YES) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - return UIStatusBarStyleBlackOpaque; -#pragma clang diagnostic pop - } - return UIStatusBarStyleDefault; -} - -- (UIStatusBarAnimation)convertToStatusBarAnimation { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"fade"] == YES) { - return UIStatusBarAnimationFade; - } else if([temp isEqualToString:@"slide"] == YES) { - return UIStatusBarAnimationSlide; - } - return UIStatusBarAnimationNone; -} - -- (UIViewAutoresizing)convertToViewAutoresizing { - return [self convertToViewAutoresizingSeparated:@"|"]; -} - -- (UIViewAutoresizing)convertToViewAutoresizingSeparated:(NSString*)separated { - __block UIViewAutoresizing result = UIViewAutoresizingNone; - NSString* value = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([value isEqualToString:@"all"] == YES) { - result = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - } else { - NSArray* keys = [value componentsSeparatedByString:separated]; - [keys enumerateObjectsUsingBlock:^(NSString* key, NSUInteger index, BOOL* stop) { - NSString* temp = [key stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; - if([temp isEqualToString:@"size"] == YES) { - result |= UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; - } else if([temp isEqualToString:@"width"] == YES) { - result |= UIViewAutoresizingFlexibleWidth; - } else if([temp isEqualToString:@"height"] == YES) { - result |= UIViewAutoresizingFlexibleHeight; - } else if([temp isEqualToString:@"top"] == YES) { - result |= UIViewAutoresizingFlexibleBottomMargin; - } else if([temp isEqualToString:@"bottom"] == YES) { - result |= UIViewAutoresizingFlexibleTopMargin; - } else if([temp isEqualToString:@"left"] == YES) { - result |= UIViewAutoresizingFlexibleRightMargin; - } else if([temp isEqualToString:@"right"] == YES) { - result |= UIViewAutoresizingFlexibleLeftMargin; - } - }]; - } - return result; -} - -- (UIViewContentMode)convertToViewContentMode { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"stretch"] == YES) { - return UIViewContentModeScaleToFill; - } else if([temp isEqualToString:@"aspect-fill"] == YES) { - return UIViewContentModeScaleAspectFill; - } else if([temp isEqualToString:@"aspect-fit"] == YES) { - return UIViewContentModeScaleAspectFit; - } else if([temp isEqualToString:@"center"] == YES) { - return UIViewContentModeCenter; - } else if([temp isEqualToString:@"center"] == YES) { - return UIViewContentModeCenter; - } else if([temp isEqualToString:@"left"] == YES) { - return UIViewContentModeLeft; - } else if([temp isEqualToString:@"right"] == YES) { - return UIViewContentModeRight; - } else if([temp isEqualToString:@"top"] == YES) { - return UIViewContentModeTop; - } else if([temp isEqualToString:@"top-left"] == YES) { - return UIViewContentModeTopLeft; - } else if([temp isEqualToString:@"top-right"] == YES) { - return UIViewContentModeTopRight; - } else if([temp isEqualToString:@"bottom"] == YES) { - return UIViewContentModeBottom; - } else if([temp isEqualToString:@"bottom-left"] == YES) { - return UIViewContentModeBottomLeft; - } else if([temp isEqualToString:@"bottom-right"] == YES) { - return UIViewContentModeBottomRight; - } - return UIViewContentModeScaleToFill; -} - -- (UIControlContentHorizontalAlignment)convertToControlContentHorizontalAlignment { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"center"] == YES) { - return UIControlContentHorizontalAlignmentCenter; - } else if([temp isEqualToString:@"left"] == YES) { - return UIControlContentHorizontalAlignmentLeft; - } else if([temp isEqualToString:@"right"] == YES) { - return UIControlContentHorizontalAlignmentRight; - } else if([temp isEqualToString:@"fill"] == YES) { - return UIControlContentHorizontalAlignmentFill; - } - return UIControlContentHorizontalAlignmentCenter; -} - -- (UIControlContentVerticalAlignment)convertToControlContentVerticalAlignment { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"center"] == YES) { - return UIControlContentVerticalAlignmentCenter; - } else if([temp isEqualToString:@"top"] == YES) { - return UIControlContentVerticalAlignmentTop; - } else if([temp isEqualToString:@"bottom"] == YES) { - return UIControlContentVerticalAlignmentBottom; - } else if([temp isEqualToString:@"fill"] == YES) { - return UIControlContentVerticalAlignmentFill; - } - return UIControlContentVerticalAlignmentCenter; -} - -- (UITextAutocapitalizationType)convertToTextAutocapitalizationType { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"none"] == YES) { - return UITextAutocapitalizationTypeNone; - } else if([temp isEqualToString:@"words"] == YES) { - return UITextAutocapitalizationTypeWords; - } else if([temp isEqualToString:@"sentences"] == YES) { - return UITextAutocapitalizationTypeSentences; - } else if([temp isEqualToString:@"all"] == YES) { - return UITextAutocapitalizationTypeAllCharacters; - } - return UITextAutocapitalizationTypeNone; -} - -- (UITextAutocorrectionType)convertToTextAutocorrectionType { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"default"] == YES) { - return UITextAutocorrectionTypeDefault; - } else if([temp isEqualToString:@"yes"] == YES) { - return UITextAutocorrectionTypeYes; - } else if([temp isEqualToString:@"no"] == YES) { - return UITextAutocorrectionTypeNo; - } - return UITextAutocorrectionTypeDefault; -} - -- (UITextSpellCheckingType)convertToTestSpellCheckingType { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"default"] == YES) { - return UITextSpellCheckingTypeDefault; - } else if([temp isEqualToString:@"yes"] == YES) { - return UITextSpellCheckingTypeYes; - } else if([temp isEqualToString:@"no"] == YES) { - return UITextSpellCheckingTypeNo; - } - return UITextSpellCheckingTypeDefault; -} - -- (UIKeyboardType)convertToKeyboardType { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"default"] == YES) { - return UIKeyboardTypeDefault; - } else if([temp isEqualToString:@"ascii"] == YES) { - return UIKeyboardTypeASCIICapable; - } else if([temp isEqualToString:@"url"] == YES) { - return UIKeyboardTypeURL; - } else if([temp isEqualToString:@"number"] == YES) { - return UIKeyboardTypeNumberPad; - } else if([temp isEqualToString:@"number-punctuation"] == YES) { - return UIKeyboardTypeNumbersAndPunctuation; - } else if([temp isEqualToString:@"phone"] == YES) { - return UIKeyboardTypePhonePad; - } else if([temp isEqualToString:@"name-phone"] == YES) { - return UIKeyboardTypeNamePhonePad; - } else if([temp isEqualToString:@"email-address"] == YES) { - return UIKeyboardTypeEmailAddress; - } else if([temp isEqualToString:@"decimal"] == YES) { - return UIKeyboardTypeDecimalPad; - } else if([temp isEqualToString:@"twitter"] == YES) { - return UIKeyboardTypeTwitter; - } else if([temp isEqualToString:@"web-search"] == YES) { - return UIKeyboardTypeWebSearch; - } - return UIKeyboardTypeDefault; -} - -- (UIReturnKeyType)convertToReturnKeyType { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"default"] == YES) { - return UIReturnKeyDefault; - } else if([temp isEqualToString:@"go"] == YES) { - return UIReturnKeyGo; - } else if([temp isEqualToString:@"google"] == YES) { - return UIReturnKeyGoogle; - } else if([temp isEqualToString:@"join"] == YES) { - return UIReturnKeyJoin; - } else if([temp isEqualToString:@"next"] == YES) { - return UIReturnKeyNext; - } else if([temp isEqualToString:@"route"] == YES) { - return UIReturnKeyRoute; - } else if([temp isEqualToString:@"search"] == YES) { - return UIReturnKeySearch; - } else if([temp isEqualToString:@"send"] == YES) { - return UIReturnKeySend; - } else if([temp isEqualToString:@"yahoo"] == YES) { - return UIReturnKeyYahoo; - } else if([temp isEqualToString:@"done"] == YES) { - return UIReturnKeyDone; - } else if([temp isEqualToString:@"emergency-call"] == YES) { - return UIReturnKeyEmergencyCall; - } - return UIReturnKeyDefault; -} - -- (UIBaselineAdjustment)convertToBaselineAdjustment { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"baselines"] == YES) { - return UIBaselineAdjustmentAlignBaselines; - } else if([temp isEqualToString:@"centers"] == YES) { - return UIBaselineAdjustmentAlignCenters; - } else if([temp isEqualToString:@"none"] == YES) { - return UIBaselineAdjustmentNone; - } - return UIBaselineAdjustmentAlignBaselines; -} - -- (UIScrollViewIndicatorStyle)convertToScrollViewIndicatorStyle { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"default"] == YES) { - return UIScrollViewIndicatorStyleDefault; - } else if([temp isEqualToString:@"black"] == YES) { - return UIScrollViewIndicatorStyleBlack; - } else if([temp isEqualToString:@"white"] == YES) { - return UIScrollViewIndicatorStyleWhite; - } - return UIScrollViewIndicatorStyleDefault; -} - -- (UIScrollViewKeyboardDismissMode)convertToScrollViewKeyboardDismissMode { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"none"] == YES) { - return UIScrollViewKeyboardDismissModeNone; - } else if([temp isEqualToString:@"drag"] == YES) { - return UIScrollViewKeyboardDismissModeOnDrag; - } else if([temp isEqualToString:@"interactive"] == YES) { - return UIScrollViewKeyboardDismissModeInteractive; - } - return UIScrollViewKeyboardDismissModeNone; -} - -- (UIBarStyle)convertToBarStyle { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"default"] == YES) { - return UIBarStyleDefault; - } else if([temp isEqualToString:@"black"] == YES) { - return UIBarStyleBlack; - } else if([temp isEqualToString:@"black-opaque"] == YES) { - return UIBarStyleBlackOpaque; - } else if([temp isEqualToString:@"black-translucent"] == YES) { - return UIBarStyleBlackTranslucent; - } - return UIBarStyleDefault; -} - -- (UITabBarItemPositioning)convertToTabBarItemPositioning { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"automatic"] == YES) { - return UITabBarItemPositioningAutomatic; - } else if([temp isEqualToString:@"fill"] == YES) { - return UITabBarItemPositioningFill; - } else if([temp isEqualToString:@"centered"] == YES) { - return UITabBarItemPositioningCentered; - } - return UITabBarItemPositioningAutomatic; -} - -- (UISearchBarStyle)convertToSearchBarStyle { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"default"] == YES) { - return UISearchBarStyleDefault; - } else if([temp isEqualToString:@"minimal"] == YES) { - return UISearchBarStyleMinimal; - } else if([temp isEqualToString:@"prominent"] == YES) { - return UISearchBarStyleProminent; - } - return UISearchBarStyleDefault; -} - -- (UIProgressViewStyle)convertToProgressViewStyle { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"default"] == YES) { - return UIProgressViewStyleDefault; - } else if([temp isEqualToString:@"bar"] == YES) { - return UIProgressViewStyleBar; - } - return UIProgressViewStyleDefault; -} - -- (UITextBorderStyle)convertToTextBorderStyle { - NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; - if([temp isEqualToString:@"none"] == YES) { - return UITextBorderStyleNone; - } else if([temp isEqualToString:@"line"] == YES) { - return UITextBorderStyleLine; - } else if([temp isEqualToString:@"bezer"] == YES) { - return UITextBorderStyleBezel; - } else if([temp isEqualToString:@"rounded"] == YES) { - return UITextBorderStyleRoundedRect; - } - return UITextBorderStyleNone; -} - -@end - -/*--------------------------------------------------*/ - -BOOL MobilyColorHSBEqualToColorHSB(MobilyColorHSB color1, MobilyColorHSB color2) { - if((color1.hue == color2.hue) && (color1.saturation == color2.saturation) && (color1.brightness == color2.brightness)) { - return YES; - } - return NO; -} - -/*--------------------------------------------------*/ - -@implementation UIColor (MobilyUI) - -+ (UIColor*)colorWithString:(NSString*)string { - UIColor* result = nil; - NSRange range = [string rangeOfString:@"#"]; - if((range.location != NSNotFound) && (range.length > 0)) { - CGFloat red = 1.0f, blue = 1.0f, green = 1.0f, alpha = 1.0f; - NSString* colorString = [[string stringByReplacingOccurrencesOfString:@"#" withString:@""] uppercaseString]; - switch ([colorString length]) { - case 6: // #RRGGBB - red = [self colorComponentFromString:colorString start:0 length:2]; - green = [self colorComponentFromString:colorString start:2 length:2]; - blue = [self colorComponentFromString:colorString start:4 length:2]; - break; - case 8: // #RRGGBBAA - red = [self colorComponentFromString:colorString start:0 length:2]; - green = [self colorComponentFromString:colorString start:2 length:2]; - blue = [self colorComponentFromString:colorString start:4 length:2]; - alpha = [self colorComponentFromString:colorString start:6 length:2]; - break; - } - result = [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; - } - return result; -} - -+ (CGFloat)colorComponentFromString:(NSString*)string start:(NSUInteger)start length:(NSUInteger)length { - unsigned result = 0; - NSString* part = [string substringWithRange:NSMakeRange(start, length)]; - if(part != nil) { - NSScanner* scaner = [NSScanner scannerWithString:part]; - if(scaner != nil) { - [scaner scanHexInt:&result]; - } - } - return ((CGFloat)result / 255.0f); -} - -- (MobilyColorHSB)hsb { - MobilyColorHSB hsb; - hsb.hue = 0.0f; - hsb.saturation = 0.0f; - hsb.brightness = 0.0f; - CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace([self CGColor])); - if((model == kCGColorSpaceModelMonochrome) || (model == kCGColorSpaceModelRGB)) { - const CGFloat* c = CGColorGetComponents([self CGColor]); - CGFloat x = fminf(fminf(c[0], c[1]), c[2]); - CGFloat b = fmaxf(fmaxf(c[0], c[1]), c[2]); - if(b == x) { - hsb.hue = 0.0f; - hsb.saturation = 0.0f; - hsb.brightness = b; - } else { - CGFloat f = (c[0] == x) ? c[1] - c[2] : ((c[1] == x) ? c[2] - c[0] : c[0] - c[1]); - NSInteger i = (c[0] == x) ? 3 : ((c[1] == x) ? 5 : 1); - hsb.hue = ((i - f /(b - x)) / 6.0f); - hsb.saturation = (b - x)/b; - hsb.brightness = b; - } - } - return hsb; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation UIImage (MobilyUI) - -+ (UIImage*)imageNamed:(NSString*)name capInsets:(UIEdgeInsets)capInsets { - UIImage* result = [self imageNamed:name]; - if(result != nil) { - result = [result resizableImageWithCapInsets:capInsets]; - } - return result; -} - -- (UIImage*)scaleToSize:(CGSize)size { - UIImage* result = nil; - - CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); - if(colourSpace != NULL) { - CGRect drawRect = CGRectAspectFitFromBoundsAndSize(CGRectMake(0.0f, 0.0f, size.width, size.height), [self size]); - drawRect.size.width = floorf(drawRect.size.width); - drawRect.size.height = floorf(drawRect.size.height); - - CGContextRef context = CGBitmapContextCreate(NULL, drawRect.size.width, drawRect.size.height, 8, drawRect.size.width * 4, colourSpace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast); - if(context != NULL) { - CGContextClearRect(context, CGRectMake(0.0f, 0.0f, drawRect.size.width, drawRect.size.height)); - CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, drawRect.size.width, drawRect.size.height), [self CGImage]); - - CGImageRef image = CGBitmapContextCreateImage(context); - if(image != NULL) { - result = [UIImage imageWithCGImage:image scale:[self scale] orientation:[self imageOrientation]]; - CGImageRelease(image); - } - CGContextRelease(context); - } - CGColorSpaceRelease(colourSpace); - } - return result; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation UINib (MobilyUI) - -+ (id)viewWithNibName:(NSString*)nibName withClass:(Class)class { - return [self viewWithNibName:nibName withClass:class withOwner:nil]; -} - -+ (id)viewWithNibName:(NSString*)nibName withClass:(Class)class withOwner:(id)owner { - UINib* nib = [UINib nibWithNibName:nibName bundle:nil]; - if(nib != nil) { - return [nib instantiateWithClass:class owner:owner options:nil]; - } - return nil; -} - -+ (UINib*)nibWithBaseName:(NSString*)baseName bundle:(NSBundle*)bundle { - if(bundle == nil) { - bundle = [NSBundle mainBundle]; - } - NSString* nib = nil; - NSFileManager* fileManager = [NSFileManager defaultManager]; - if([UIDevice isIPhone] == YES) { - NSString* iPhoneName = [NSString stringWithFormat:@"%@%@", baseName, @"-iPhone"]; - if([fileManager fileExistsAtPath:[bundle pathForResource:iPhoneName ofType:@"nib"]] == YES) { - nib = iPhoneName; - } - } else if([UIDevice isIPad] == YES) { - NSString* iPadName = [NSString stringWithFormat:@"%@%@", baseName, @"-iPad"]; - if([fileManager fileExistsAtPath:[bundle pathForResource:iPadName ofType:@"nib"]] == YES) { - nib = iPadName; - } - } - if(nib == nil) { - if([fileManager fileExistsAtPath:[bundle pathForResource:baseName ofType:@"nib"]] == YES) { - nib = baseName; - } - } - if(nib != nil) { - return [self nibWithNibName:nib bundle:bundle]; - } - return nil; -} - -+ (UINib*)nibWithClass:(Class)class bundle:(NSBundle*)bundle { - return [self nibWithBaseName:NSStringFromClass(class) bundle:bundle]; -} - -- (id)instantiateWithClass:(Class)class owner:(id)owner options:(NSDictionary*)options { - id result = nil; - NSArray* content = [self instantiateWithOwner:owner options:nil]; - [content enumerateObjectsUsingBlock:^(id item, NSUInteger index, BOOL* stop) { - if([item isKindOfClass:class] == YES) { - item = result; - *stop = YES; - } - }]; - return result; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -static UIResponder* MOBILY_CURRENT_FIRST_RESPONDER = nil; - -/*--------------------------------------------------*/ - -@implementation UIResponder (MobilyUI) - -+ (id)currentFirstResponderInView:(UIView*)view { - id currentFirstResponder = [self currentFirstResponder]; - if([currentFirstResponder isKindOfClass:[UIView class]] == YES) { - if([view isContainsSubview:currentFirstResponder] == YES) { - return currentFirstResponder; - } - } - return nil; -} - -+ (id)currentFirstResponder { - MOBILY_CURRENT_FIRST_RESPONDER = nil; - [[UIApplication sharedApplication] sendAction:@selector(findFirstResponder:) to:nil from:nil forEvent:nil]; - return MOBILY_CURRENT_FIRST_RESPONDER; -} - -- (void)findFirstResponder:(id)sender { - MOBILY_CURRENT_FIRST_RESPONDER = self; -} - -+ (UIResponder*)prevResponderFromView:(UIView*)view { - NSArray* responders = [[view window] responders]; - if([responders count] > 1) { - NSInteger index = [responders indexOfObject:view]; - if(index != NSNotFound) { - if(index > 0) { - return [responders objectAtIndex:index - 1]; - } - } - } - return nil; -} - -+ (UIResponder*)nextResponderFromView:(UIView*)view { - NSArray* responders = [[view window] responders]; - if([responders count] > 1) { - NSInteger index = [responders indexOfObject:view]; - if(index != NSNotFound) { - if(index < [responders count] - 1) { - return [responders objectAtIndex:index + 1]; - } - } - } - return nil; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation UIWindow (MobilyUI) - -#pragma mark NSKeyValueCoding - -#pragma mark Property - -- (UIViewController*)currentViewController { - return [[self rootViewController] currentViewController]; -} - -#ifdef __IPHONE_7_0 - -- (UIViewController*)viewControllerForStatusBarStyle { - UIViewController* currentViewController = [self currentViewController]; - while([currentViewController childViewControllerForStatusBarStyle] != nil) { - currentViewController = [currentViewController childViewControllerForStatusBarStyle]; - } - return currentViewController; -} - -- (UIViewController*)viewControllerForStatusBarHidden { - UIViewController* currentViewController = [self currentViewController]; - while ([currentViewController childViewControllerForStatusBarHidden] != nil) { - currentViewController = [currentViewController childViewControllerForStatusBarHidden]; - } - return currentViewController; -} - -#endif - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation UIView (MobilyUI) - -#pragma mark NSKeyValueCoding - -MOBILY_DEFINE_VALIDATE_BOOL(UserInteractionEnabled) -MOBILY_DEFINE_VALIDATE_RECT(Frame) -MOBILY_DEFINE_VALIDATE_POINT(FramePosition) -MOBILY_DEFINE_VALIDATE_POINT(FrameCenter) -MOBILY_DEFINE_VALIDATE_SIZE(FrameSize) -MOBILY_DEFINE_VALIDATE_NUMBER(FrameSX) -MOBILY_DEFINE_VALIDATE_NUMBER(FrameSY) -MOBILY_DEFINE_VALIDATE_NUMBER(FrameCX) -MOBILY_DEFINE_VALIDATE_NUMBER(FrameCY) -MOBILY_DEFINE_VALIDATE_NUMBER(FrameEX) -MOBILY_DEFINE_VALIDATE_NUMBER(FrameEY) -MOBILY_DEFINE_VALIDATE_NUMBER(FrameWidth) -MOBILY_DEFINE_VALIDATE_NUMBER(FrameHeight) -MOBILY_DEFINE_VALIDATE_NUMBER(FrameLeft) -MOBILY_DEFINE_VALIDATE_NUMBER(FrameRight) -MOBILY_DEFINE_VALIDATE_NUMBER(FrameTop) -MOBILY_DEFINE_VALIDATE_NUMBER(FrameBottom) -MOBILY_DEFINE_VALIDATE_NUMBER(CornerRadius) -MOBILY_DEFINE_VALIDATE_NUMBER(BorderWidth) -MOBILY_DEFINE_VALIDATE_COLOR(BorderColor) -MOBILY_DEFINE_VALIDATE_COLOR(ShadowColor) -MOBILY_DEFINE_VALIDATE_NUMBER(ShadowOpacity); -MOBILY_DEFINE_VALIDATE_SIZE(ShadowOffset); -MOBILY_DEFINE_VALIDATE_NUMBER(ShadowRadius); -MOBILY_DEFINE_VALIDATE_BEZIER_PATH(ShadowPath); -MOBILY_DEFINE_VALIDATE_RECT(Bounds) -MOBILY_DEFINE_VALIDATE_POINT(Center) -MOBILY_DEFINE_VALIDATE_NUMBER(ContentScaleFactor) -MOBILY_DEFINE_VALIDATE_BOOL(MultipleTouchEnabled) -MOBILY_DEFINE_VALIDATE_BOOL(AutoresizesSubviews) -MOBILY_DEFINE_VALIDATE_AUTORESIZING(AutoresizingMask) -MOBILY_DEFINE_VALIDATE_BOOL(ClipsToBounds) -MOBILY_DEFINE_VALIDATE_COLOR(BackgroundColor) -MOBILY_DEFINE_VALIDATE_NUMBER(Alpha) -MOBILY_DEFINE_VALIDATE_BOOL(Opaque) -MOBILY_DEFINE_VALIDATE_BOOL(ClearsContextBeforeDrawing) -MOBILY_DEFINE_VALIDATE_BOOL(Hidden) -MOBILY_DEFINE_VALIDATE_CONTENT_MODE(ContentMode) -MOBILY_DEFINE_VALIDATE_RECT(ContentStretch) -MOBILY_DEFINE_VALIDATE_COLOR(TintColor); - -#pragma mark Property - -- (void)setFramePosition:(CGPoint)framePosition { - CGRect frame = [self frame]; - [self setFrame:CGRectMake(framePosition.x, framePosition.y, frame.size.width, frame.size.height)]; -} - -- (CGPoint)framePosition { - return [self frame].origin; -} - -- (void)setFrameCenter:(CGPoint)frameCenter { - CGRect frame = [self frame]; - [self setFrame:CGRectMake(frameCenter.x - (frame.size.width * 0.5f), frameCenter.y - (frame.size.height * 0.5f), frame.size.width, frame.size.height)]; -} - -- (CGPoint)frameCenter { - CGRect frame = [self frame]; - return CGPointMake(frame.origin.x + (frame.size.width * 0.5f), frame.origin.y + (frame.size.height * 0.5f)); -} - -- (void)setFrameSize:(CGSize)frameSize { - CGRect frame = [self frame]; - [self setFrame:CGRectMake(frame.origin.x, frame.origin.y, frameSize.width, frameSize.height)]; -} - -- (CGSize)frameSize { - return [self frame].size; -} - -- (void)setFrameSX:(CGFloat)frameSX { - CGRect frame = [self frame]; - [self setFrame:CGRectMake(frameSX, frame.origin.y, frame.size.width, frame.size.height)]; -} - -- (CGFloat)frameSX { - return CGRectGetMinX([self frame]); -} - -- (void)setFrameCX:(CGFloat)frameCX { - CGRect frame = [self frame]; - [self setFrame:CGRectMake(frameCX - (frame.size.width * 0.5f), frame.origin.y, frame.size.width, frame.size.height)]; -} - -- (CGFloat)frameCX { - return CGRectGetMidX([self frame]); -} - -- (void)setFrameEX:(CGFloat)frameEX { - CGRect frame = [self frame]; - [self setFrame:CGRectMake(frame.origin.x, frame.origin.y, frameEX - frame.origin.x, frame.size.height)]; -} - -- (CGFloat)frameEX { - return CGRectGetMaxX([self frame]); -} - -- (void)setFrameSY:(CGFloat)frameSY { - CGRect frame = [self frame]; - [self setFrame:CGRectMake(frame.origin.x, frameSY, frame.size.width, frame.size.height)]; -} - -- (CGFloat)frameSY { - return CGRectGetMinY([self frame]); -} - -- (void)setFrameCY:(CGFloat)frameCY { - CGRect frame = [self frame]; - [self setFrame:CGRectMake(frame.origin.x, frameCY - (frame.size.height * 0.5f), frame.size.width, frame.size.height)]; -} - -- (CGFloat)frameCY { - return CGRectGetMidY([self frame]); -} - -- (void)setFrameEY:(CGFloat)frameEY { - CGRect frame = [self frame]; - [self setFrame:CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, frameEY - frame.origin.y)]; -} - -- (CGFloat)frameEY { - return CGRectGetMaxY([self frame]); -} - -- (void)setFrameWidth:(CGFloat)frameWidth { - CGRect frame = [self frame]; - [self setFrame:CGRectMake(frame.origin.x, frame.origin.y, frameWidth, frame.size.height)]; -} - -- (CGFloat)frameWidth { - return CGRectGetWidth([self frame]); -} - -- (void)setFrameHeight:(CGFloat)frameHeight { - CGRect frame = [self frame]; - [self setFrame:CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, frameHeight)]; -} - -- (CGFloat)frameHeight { - return CGRectGetHeight([self frame]); -} - -- (void)setFrameLeft:(CGFloat)frameLeft { - CGRect frame = [self frame]; - CGFloat offset = frameLeft; - CGFloat size = frame.size.width - (frameLeft - frame.origin.x); - [self setFrame:CGRectMake(offset, frame.origin.y, size, frame.size.height)]; -} - -- (CGFloat)frameLeft { - CGRect frame = [self frame]; - return frame.origin.x; -} - -- (void)setFrameRight:(CGFloat)frameRight { - CGRect frame = [self frame]; - CGRect bounds = [[self superview] bounds]; - CGFloat offset = frame.origin.x; - CGFloat size = bounds.size.width - (frame.origin.x + frameRight); - [self setFrame:CGRectMake(offset, frame.origin.y, size, frame.size.height)]; -} - -- (CGFloat)frameRight { - CGRect frame = [self frame]; - CGRect bounds = [[self superview] bounds]; - return bounds.size.width - (frame.origin.x + frame.size.width); -} - -- (void)setFrameTop:(CGFloat)frameTop { - CGRect frame = [self frame]; - CGFloat offset = frameTop; - CGFloat size = frame.size.height - (frameTop - frame.origin.y); - [self setFrame:CGRectMake(frame.origin.x, offset, frame.size.width, size)]; -} - -- (CGFloat)frameTop { - CGRect frame = [self frame]; - return frame.origin.y; -} - -- (void)setFrameBottom:(CGFloat)frameBottom { - CGRect frame = [self frame]; - CGRect bounds = [[self superview] bounds]; - CGFloat offset = frame.origin.y; - CGFloat size = bounds.size.height - (frame.origin.y + frameBottom); - [self setFrame:CGRectMake(frame.origin.x, offset, frame.size.width, size)]; -} - -- (CGFloat)frameBottom { - CGRect frame = [self frame]; - CGRect bounds = [[self superview] bounds]; - return bounds.size.height - (frame.origin.y + frame.size.height); -} - -- (CGPoint)boundsPosition { - return [self bounds].origin; -} - -- (CGSize)boundsSize { - return [self bounds].size; -} - -- (CGPoint)boundsCenter { - CGRect bounds = [self bounds]; - return CGPointMake(bounds.origin.x + (bounds.size.width * 0.5f), bounds.origin.y + (bounds.size.height * 0.5f)); -} - -- (CGFloat)boundsCX { - return CGRectGetMidX([self bounds]); -} - -- (CGFloat)boundsCY { - return CGRectGetMidY([self bounds]); -} - -- (CGFloat)boundsWidth { - return CGRectGetWidth([self bounds]); -} - -- (CGFloat)boundsHeight { - return CGRectGetHeight([self bounds]); -} - -- (void)setCornerRadius:(CGFloat)cornerRadius { - [[self layer] setCornerRadius:cornerRadius]; -} - -- (CGFloat)cornerRadius { - return [[self layer] cornerRadius]; -} - -- (void)setBorderWidth:(CGFloat)borderWidth { - [[self layer] setBorderWidth:borderWidth]; -} - -- (CGFloat)borderWidth { - return [[self layer] borderWidth]; -} - -- (void)setBorderColor:(UIColor*)borderColor { - [[self layer] setBorderColor:[borderColor CGColor]]; -} - -- (UIColor*)borderColor { - return [UIColor colorWithCGColor:[[self layer] borderColor]]; -} - -- (void)setShadowColor:(UIColor*)shadowColor { - [[self layer] setShadowColor:[shadowColor CGColor]]; -} - -- (UIColor*)shadowColor { - return [UIColor colorWithCGColor:[[self layer] shadowColor]]; -} - -- (void)setShadowOpacity:(CGFloat)shadowOpacity { - [[self layer] setShadowOpacity:shadowOpacity]; -} - -- (CGFloat)shadowOpacity { - return [[self layer] shadowOpacity]; -} - -- (void)setShadowOffset:(CGSize)shadowOffset { - [[self layer] setShadowOffset:shadowOffset]; -} - -- (CGSize)shadowOffset { - return [[self layer] shadowOffset]; -} - -- (void)setShadowRadius:(CGFloat)shadowRadius { - [[self layer] setShadowRadius:shadowRadius]; -} - -- (CGFloat)shadowRadius { - return [[self layer] shadowRadius]; -} - -- (void)setShadowPath:(UIBezierPath*)shadowPath { - [[self layer] setShadowPath:[shadowPath CGPath]]; -} - -- (UIBezierPath*)shadowPath { - return [UIBezierPath bezierPathWithCGPath:[[self layer] shadowPath]]; -} - -#pragma mark Public - -- (NSArray*)responders { - NSMutableArray* result = [NSMutableArray array]; - if([self canBecomeFirstResponder] == YES) { - [result addObject:self]; - } - [[self subviews] enumerateObjectsUsingBlock:^(UIView* view, NSUInteger index, BOOL* stop) { - [result addObjectsFromArray:[view responders]]; - }]; - [result sortWithOptions:0 usingComparator:^NSComparisonResult(UIView* viewA, UIView* viewB) { - CGFloat aOrder = [[viewA layer] zPosition], bOrder = [[viewB layer] zPosition]; - CGRect aFrame = [viewA frame], bFrame = [viewB frame]; - if(aOrder < bOrder) { - return NSOrderedAscending; - } else if(aOrder > bOrder) { - return NSOrderedDescending; - } else { - if(aFrame.origin.y < bFrame.origin.y) { - return NSOrderedAscending; - } else if(aFrame.origin.y > bFrame.origin.y) { - return NSOrderedDescending; - } else { - if(aFrame.origin.x < bFrame.origin.x) { - return NSOrderedAscending; - } else if(aFrame.origin.x > bFrame.origin.x) { - return NSOrderedDescending; - } - } - } - return NSOrderedSame; - }]; - return result; -} - -- (BOOL)isContainsSubview:(UIView*)subview { - __block BOOL result = [[self subviews] containsObject:subview]; - if(result == NO) { - [[self subviews] enumerateObjectsUsingBlock:^(UIView* view, NSUInteger index, BOOL* stop) { - if([view isContainsSubview:subview] == YES) { - result = YES; - *stop = YES; - } - }]; - } - return result; -} - -- (void)removeSubview:(UIView*)subview { - [subview removeFromSuperview]; -} - -- (void)setSubviews:(NSArray*)subviews { - NSArray* currentSubviews = [self subviews]; - if([currentSubviews isEqualToArray:subviews] == NO) { - [[self subviews] enumerateObjectsUsingBlock:^(UIView* view, NSUInteger index, BOOL* stop) { - [view removeFromSuperview]; - }]; - [subviews enumerateObjectsUsingBlock:^(UIView* view, NSUInteger index, BOOL* stop) { - [self addSubview:view]; - }]; - } -} - -- (void)removeAllSubviews { - [[self subviews] enumerateObjectsUsingBlock:^(UIView* view, NSUInteger index, BOOL* stop) { - [view removeFromSuperview]; - }]; -} - -- (void)blinkBackgroundColor:(UIColor*)color duration:(NSTimeInterval)duration timeout:(NSTimeInterval)timeout { - UIColor* prevColor = [self backgroundColor]; - [UIView animateWithDuration:duration - animations:^{ - [self setBackgroundColor:color]; - } completion:^(BOOL finished) { - [UIView animateWithDuration:duration - delay:timeout - options:0 - animations:^{ - [self setBackgroundColor:prevColor]; - } - completion:nil]; - }]; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface UIScrollView (MobilyUI_Keyboard) - -@property(nonatomic, readwrite, weak) UIResponder* keyboardResponder; -@property(nonatomic, readwrite, assign) CGPoint keyboardContentOffset; -@property(nonatomic, readwrite, assign) UIEdgeInsets keyboardContentInset; -@property(nonatomic, readwrite, assign) UIEdgeInsets keyboardIndicatorInset; - -@end - -/*--------------------------------------------------*/ - -@implementation UIScrollView (MobilyUI) - -#pragma mark NSKeyValueCoding - -MOBILY_DEFINE_VALIDATE_POINT(СontentOffset) -MOBILY_DEFINE_VALIDATE_SIZE(ContentSize) -MOBILY_DEFINE_VALIDATE_EDGE_INSETS(ContentInset) -MOBILY_DEFINE_VALIDATE_BOOL(DirectionalLockEnabled) -MOBILY_DEFINE_VALIDATE_BOOL(Bounces) -MOBILY_DEFINE_VALIDATE_BOOL(AlwaysBounceVertical) -MOBILY_DEFINE_VALIDATE_BOOL(AlwaysBounceHorizontal) -MOBILY_DEFINE_VALIDATE_BOOL(PagingEnabled) -MOBILY_DEFINE_VALIDATE_BOOL(ScrollEnabled) -MOBILY_DEFINE_VALIDATE_BOOL(ShowsHorizontalScrollIndicator) -MOBILY_DEFINE_VALIDATE_BOOL(ShowsVerticalScrollIndicator) -MOBILY_DEFINE_VALIDATE_EDGE_INSETS(ScrollIndicatorInsets) -MOBILY_DEFINE_VALIDATE_SCROLL_VIEW_INDICATOR_STYLE(IndicatorStyle) -MOBILY_DEFINE_VALIDATE_NUMBER(DecelerationRate) -MOBILY_DEFINE_VALIDATE_BOOL(DelaysContentTouches) -MOBILY_DEFINE_VALIDATE_BOOL(CanCancelContentTouches) -MOBILY_DEFINE_VALIDATE_NUMBER(MinimumZoomScale) -MOBILY_DEFINE_VALIDATE_NUMBER(MaximumZoomScale) -MOBILY_DEFINE_VALIDATE_NUMBER(ZoomScale) -MOBILY_DEFINE_VALIDATE_NUMBER(BouncesZoom) -MOBILY_DEFINE_VALIDATE_SCROLL_VIEW_KEYBOARD_DISMISS_MODE(KeyboardDismissMode) - -#pragma mark Property - -- (void)setKeyboardResponder:(UIResponder*)keyboardResponder { - if([self keyboardResponder] == nil) { - [self setKeyboardContentOffset:[self contentOffset]]; - [self setKeyboardContentInset:[self contentInset]]; - [self setKeyboardIndicatorInset:[self scrollIndicatorInsets]]; - } - objc_setAssociatedObject(self, @selector(keyboardResponder), keyboardResponder, OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (UIResponder*)keyboardResponder { - return objc_getAssociatedObject(self, @selector(keyboardResponder)); -} - -- (void)setKeyboardContentOffset:(CGPoint)keyboardContentOffset { - objc_setAssociatedObject(self, @selector(keyboardContentOffset), [NSValue valueWithCGPoint:keyboardContentOffset], OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (CGPoint)keyboardContentOffset { - return [objc_getAssociatedObject(self, @selector(keyboardContentOffset)) CGPointValue]; -} - -- (void)setKeyboardContentInset:(UIEdgeInsets)keyboardContentInset { - objc_setAssociatedObject(self, @selector(keyboardContentInset), [NSValue valueWithUIEdgeInsets:keyboardContentInset], OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (UIEdgeInsets)keyboardContentInset { - return [objc_getAssociatedObject(self, @selector(keyboardContentInset)) UIEdgeInsetsValue]; -} - -- (void)setKeyboardIndicatorInset:(UIEdgeInsets)keyboardIndicatorInset { - objc_setAssociatedObject(self, @selector(keyboardIndicatorInset), [NSValue valueWithUIEdgeInsets:keyboardIndicatorInset], OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (UIEdgeInsets)keyboardIndicatorInset { - return [objc_getAssociatedObject(self, @selector(keyboardIndicatorInset)) UIEdgeInsetsValue]; -} - -- (void)setKeyboardInset:(UIEdgeInsets)keyboardInset { - objc_setAssociatedObject(self, @selector(keyboardInset), [NSValue valueWithUIEdgeInsets:keyboardInset], OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -- (UIEdgeInsets)keyboardInset { - NSValue* value = objc_getAssociatedObject(self, @selector(keyboardInset)); - if(value != nil) { - return [value UIEdgeInsetsValue]; - } - return UIEdgeInsetsMake(8.0f, 8.0f, 8.0f, 8.0f); -} - -- (void)setContentOffsetX:(CGFloat)contentOffsetX { - [self setContentOffsetX:contentOffsetX animated:NO]; -} - -- (CGFloat)contentOffsetX { - CGPoint contentOffset = [self contentOffset]; - return contentOffset.x; -} - -- (void)setContentOffsetY:(CGFloat)contentOffsetY { - [self setContentOffsetY:contentOffsetY animated:NO]; -} - -- (CGFloat)contentOffsetY { - CGPoint contentOffset = [self contentOffset]; - return contentOffset.y; -} - -- (void)setContentSizeWidth:(CGFloat)contentSizeWidth { - CGSize contentSize = [self contentSize]; - [self setContentSize:CGSizeMake(contentSizeWidth, contentSize.height)]; -} - -- (CGFloat)contentSizeWidth { - CGSize contentSize = [self contentSize]; - return contentSize.width; -} - -- (void)setContentSizeHeight:(CGFloat)contentSizeHeight { - CGSize contentSize = [self contentSize]; - [self setContentSize:CGSizeMake(contentSize.width, contentSizeHeight)]; -} - -- (CGFloat)contentSizeHeight { - CGSize contentSize = [self contentSize]; - return contentSize.height; -} - -- (void)setContentInsetTop:(CGFloat)contentInsetTop { - UIEdgeInsets contentInset = [self contentInset]; - [self setContentInset:UIEdgeInsetsMake(contentInsetTop, contentInset.left, contentInset.bottom, contentInset.right)]; -} - -- (CGFloat)contentInsetTop { - UIEdgeInsets contentInset = [self contentInset]; - return contentInset.top; -} - -- (void)setContentInsetRight:(CGFloat)contentInsetRight { - UIEdgeInsets contentInset = [self contentInset]; - [self setContentInset:UIEdgeInsetsMake(contentInset.top, contentInset.left, contentInset.bottom, contentInsetRight)]; -} - -- (CGFloat)contentInsetRight { - UIEdgeInsets contentInset = [self contentInset]; - return contentInset.right; -} - -- (void)setContentInsetBottom:(CGFloat)contentInsetBottom { - UIEdgeInsets contentInset = [self contentInset]; - [self setContentInset:UIEdgeInsetsMake(contentInset.top, contentInset.left, contentInsetBottom, contentInset.right)]; -} - -- (CGFloat)contentInsetBottom { - UIEdgeInsets contentInset = [self contentInset]; - return contentInset.bottom; -} - -- (void)setContentInsetLeft:(CGFloat)contentInsetLeft { - UIEdgeInsets contentInset = [self contentInset]; - [self setContentInset:UIEdgeInsetsMake(contentInset.top, contentInsetLeft, contentInset.bottom, contentInset.right)]; -} - -- (CGFloat)contentInsetLeft { - UIEdgeInsets contentInset = [self contentInset]; - return contentInset.left; -} - -- (void)setScrollIndicatorInsetTop:(CGFloat)scrollIndicatorInsetTop { - UIEdgeInsets scrollIndicatorInset = [self scrollIndicatorInsets]; - [self setScrollIndicatorInsets:UIEdgeInsetsMake(scrollIndicatorInsetTop, scrollIndicatorInset.left, scrollIndicatorInset.bottom, scrollIndicatorInset.right)]; -} - -- (CGFloat)scrollIndicatorInsetTop { - UIEdgeInsets scrollIndicatorInset = [self scrollIndicatorInsets]; - return scrollIndicatorInset.top; -} - -- (void)setScrollIndicatorInsetRight:(CGFloat)scrollIndicatorInsetRight { - UIEdgeInsets scrollIndicatorInset = [self scrollIndicatorInsets]; - [self setScrollIndicatorInsets:UIEdgeInsetsMake(scrollIndicatorInset.top, scrollIndicatorInset.left, scrollIndicatorInset.bottom, scrollIndicatorInsetRight)]; -} - -- (CGFloat)scrollIndicatorInsetRight { - UIEdgeInsets scrollIndicatorInset = [self scrollIndicatorInsets]; - return scrollIndicatorInset.right; -} - -- (void)setScrollIndicatorInsetBottom:(CGFloat)scrollIndicatorInsetBottom { - UIEdgeInsets scrollIndicatorInset = [self scrollIndicatorInsets]; - [self setScrollIndicatorInsets:UIEdgeInsetsMake(scrollIndicatorInset.top, scrollIndicatorInset.left, scrollIndicatorInsetBottom, scrollIndicatorInset.right)]; -} - -- (CGFloat)scrollIndicatorInsetBottom { - UIEdgeInsets scrollIndicatorInset = [self scrollIndicatorInsets]; - return scrollIndicatorInset.bottom; -} - -- (void)setScrollIndicatorInsetLeft:(CGFloat)scrollIndicatorInsetLeft { - UIEdgeInsets scrollIndicatorInset = [self scrollIndicatorInsets]; - [self setScrollIndicatorInsets:UIEdgeInsetsMake(scrollIndicatorInset.top, scrollIndicatorInsetLeft, scrollIndicatorInset.bottom, scrollIndicatorInset.right)]; -} - -- (CGFloat)scrollIndicatorInsetLeft { - UIEdgeInsets scrollIndicatorInset = [self scrollIndicatorInsets]; - return scrollIndicatorInset.left; -} - -#pragma mark Public - -- (void)setContentOffsetX:(CGFloat)contentOffsetX animated:(BOOL)animated { - CGPoint contentOffset = [self contentOffset]; - [self setContentOffset:CGPointMake(contentOffsetX, contentOffset.y) animated:animated]; -} - -- (void)setContentOffsetY:(CGFloat)contentOffsetY animated:(BOOL)animated { - CGPoint contentOffset = [self contentOffset]; - [self setContentOffset:CGPointMake(contentOffset.x, contentOffsetY) animated:animated]; -} - -- (CGSize)contentSizeFromSubviews { - CGRect rect = CGRectZero; - for(UIView* view in [self subviews]) { - rect = CGRectUnion(rect, [view frame]); - } - return rect.size; -} - -- (void)registerAdjustmentResponder { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(adjustmentNotificationKeyboardShow:) name:UIKeyboardWillShowNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(adjustmentNotificationKeyboardHide:) name:UIKeyboardWillHideNotification object:nil]; -} - -- (void)unregisterAdjustmentResponder { - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -#pragma mark UIKeyboarNotification - -- (void)adjustmentNotificationKeyboardShow:(NSNotification*)notification { - [self setKeyboardResponder:[UIResponder currentFirstResponderInView:self]]; - if([[self keyboardResponder] isKindOfClass:[UIView class]] == YES) { - CGPoint contentOffset = [self contentOffset]; - UIEdgeInsets contentInsets = [self contentInset]; - UIEdgeInsets indicatorInsets = [self scrollIndicatorInsets]; - CGRect scrollRect = [self convertRect:[self bounds] toView:nil]; - CGRect keyboardRect = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; - CGRect responderRect = [(UIView*)[self keyboardResponder] convertRect:[(UIView*)[self keyboardResponder] bounds] toView:nil]; - CGRect smallRemainderRect = CGRectZero, largeRemainderRect = CGRectZero; - CGRect intersectionRect = CGRectIntersectionExt(scrollRect, keyboardRect, &smallRemainderRect, &largeRemainderRect); - if(CGRectIsNull(intersectionRect) == NO) { - CGPoint smallRemainderCenter = CGRectGetCenterPoint(smallRemainderRect); - CGPoint largeRemainderCenter = CGRectGetCenterPoint(largeRemainderRect); - if(ABS(smallRemainderCenter.x - largeRemainderCenter.x) > FLT_EPSILON) { - if(smallRemainderCenter.x >= largeRemainderCenter.x) { - contentInsets.right = intersectionRect.size.width + smallRemainderRect.size.width; - indicatorInsets.right = intersectionRect.size.width + smallRemainderRect.size.width; - } else { - contentInsets.left = intersectionRect.size.width + smallRemainderRect.size.width; - indicatorInsets.left = intersectionRect.size.width + smallRemainderRect.size.width; - } - } - if(ABS(smallRemainderCenter.y - largeRemainderCenter.y) > FLT_EPSILON) { - if(smallRemainderCenter.y >= largeRemainderCenter.y) { - contentInsets.bottom = intersectionRect.size.height + smallRemainderRect.size.height; - indicatorInsets.bottom = intersectionRect.size.height + smallRemainderRect.size.height; - } else { - contentInsets.top = intersectionRect.size.height + smallRemainderRect.size.height; - indicatorInsets.top = intersectionRect.size.height + smallRemainderRect.size.height; - } - } - if(CGRectContainsRect(largeRemainderRect, responderRect) == NO) { - CGRect visibleRect = UIEdgeInsetsInsetRect(largeRemainderRect, [self keyboardInset]); - CGRect correctRect = CGRectOffset(responderRect, contentOffset.x, contentOffset.y); - CGFloat vrsx = CGRectGetMinX(visibleRect), vrsy = CGRectGetMinY(visibleRect); - CGFloat vrex = CGRectGetMaxX(visibleRect), vrey = CGRectGetMaxY(visibleRect); - CGFloat vrcx = CGRectGetMidX(visibleRect), vrcy = CGRectGetMidY(visibleRect); - CGFloat crsx = CGRectGetMinX(correctRect), crsy = CGRectGetMinY(correctRect); - CGFloat crex = CGRectGetMaxX(correctRect), crey = CGRectGetMaxY(correctRect); - CGFloat crcx = CGRectGetMidX(correctRect), crcy = CGRectGetMidY(correctRect); - if((vrex - vrsx) < (crex - crsx)) { - contentOffset.x += vrcx - crcx; - } else if(vrsx > crsx) { - contentOffset.x -= vrsx - crsx; - } else if(vrex < crex) { - contentOffset.x -= vrex - crex; - } - if((vrey - vrsy) < (crey - crsy)) { - contentOffset.y += vrcy - crcy; - } else if(vrsy > crsy) { - contentOffset.y -= vrsy - crsy; - } else if(vrey < crey) { - contentOffset.y -= vrey - crey; - } - } - } - [self setContentInset:contentInsets]; - [self setScrollIndicatorInsets:indicatorInsets]; - [self setContentOffset:contentOffset animated:YES]; - } -} - -- (void)adjustmentNotificationKeyboardHide:(NSNotification*)notification { - if([self keyboardResponder] != nil) { - CGPoint contentOffset = [self keyboardContentOffset]; - [self setContentInset:[self keyboardContentInset]]; - [self setScrollIndicatorInsets:[self keyboardIndicatorInset]]; - [self setContentOffset:contentOffset animated:YES]; - [self setKeyboardResponder:nil]; - } -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation UITabBar (MobilyUI) - -#pragma mark NSKeyValueCoding - -MOBILY_DEFINE_VALIDATE_COLOR(TintColor) -MOBILY_DEFINE_VALIDATE_COLOR(BarTintColor) -MOBILY_DEFINE_VALIDATE_COLOR(SelectedImageTintColor) -MOBILY_DEFINE_VALIDATE_IMAGE(BackgroundImage) -MOBILY_DEFINE_VALIDATE_IMAGE(SelectionIndicatorImage) -MOBILY_DEFINE_VALIDATE_IMAGE(ShadowImage) -MOBILY_DEFINE_VALIDATE_TAB_BAR_ITEM_POSITIONING(ItemPositioning); -MOBILY_DEFINE_VALIDATE_NUMBER(ItemWidth) -MOBILY_DEFINE_VALIDATE_NUMBER(ItemSpacing) -MOBILY_DEFINE_VALIDATE_BAR_STYLE(BarStyle) -MOBILY_DEFINE_VALIDATE_BOOL(Translucent) -MOBILY_DEFINE_VALIDATE_NUMBER(SelectedItemIndex) - -#pragma mark Property - -- (void)setSelectedItemIndex:(NSUInteger)index { - [self setSelectedItem:[[self items] objectAtIndex:index]]; -} - -- (NSUInteger)selectedItemIndex { - return [[self items] indexOfObject:[self selectedItem]]; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation UINavigationBar (MobilyUI) - -#pragma mark NSKeyValueCoding - -#pragma mark Property - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation UILabel (MobilyUI) - -#pragma mark NSKeyValueCoding - -MOBILY_DEFINE_VALIDATE_STRING(Text) -MOBILY_DEFINE_VALIDATE_FONT(Font) -MOBILY_DEFINE_VALIDATE_COLOR(TextColor) -MOBILY_DEFINE_VALIDATE_COLOR(ShadowColor) -MOBILY_DEFINE_VALIDATE_SIZE(ShadowOffset) -MOBILY_DEFINE_VALIDATE_TEXT_ALIGNMENT(TextAlignment) -MOBILY_DEFINE_VALIDATE_LINE_BREAKMODE(LineBreakMode) -MOBILY_DEFINE_VALIDATE_COLOR(HighlightedTextColor) -MOBILY_DEFINE_VALIDATE_BOOL(Highlighted) -MOBILY_DEFINE_VALIDATE_BOOL(Enabled) -MOBILY_DEFINE_VALIDATE_NUMBER(NumberOfLines) -MOBILY_DEFINE_VALIDATE_BOOL(AdjustsFontSizeToFitWidth) -MOBILY_DEFINE_VALIDATE_BOOL(AdjustsLetterSpacingToFitWidth) -MOBILY_DEFINE_VALIDATE_NUMBER(MinimumFontSize) -MOBILY_DEFINE_VALIDATE_BASELINE_ADJUSTMENT(BaselineAdjustment) -MOBILY_DEFINE_VALIDATE_NUMBER(MinimumScaleFactor) -MOBILY_DEFINE_VALIDATE_NUMBER(PreferredMaxLayoutWidth) - -#pragma mark Public - -- (CGSize)implicitSize { - return [self implicitSizeForSize:CGSizeMake(NSIntegerMax, NSIntegerMax)]; -} - -- (CGSize)implicitSizeForWidth:(CGFloat)width { - return [self implicitSizeForSize:CGSizeMake(width, NSIntegerMax)]; -} - -- (CGSize)implicitSizeForSize:(CGSize)size { - return [[self text] implicitSizeWithFont:[self font] forSize:size lineBreakMode:[self lineBreakMode]]; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation UIButton (MobilyUI) - -#pragma mark NSKeyValueCoding - -MOBILY_DEFINE_VALIDATE_EDGE_INSETS(ContentEdgeInsets) -MOBILY_DEFINE_VALIDATE_EDGE_INSETS(TitleEdgeInsets) -MOBILY_DEFINE_VALIDATE_BOOL(ReversesTitleShadowWhenHighlighted) -MOBILY_DEFINE_VALIDATE_EDGE_INSETS(ImageEdgeInsets) -MOBILY_DEFINE_VALIDATE_BOOL(AdjustsImageWhenHighlighted) -MOBILY_DEFINE_VALIDATE_BOOL(AdjustsImageWhenDisabled) -MOBILY_DEFINE_VALIDATE_BOOL(ShowsTouchWhenHighlighted) -MOBILY_DEFINE_VALIDATE_COLOR(TintColor) - -MOBILY_DEFINE_VALIDATE_STRING(NormalTitle) -MOBILY_DEFINE_VALIDATE_COLOR(NormalTitleColor) -MOBILY_DEFINE_VALIDATE_COLOR(NormalTitleShadowColor) -MOBILY_DEFINE_VALIDATE_IMAGE(NormalImage) -MOBILY_DEFINE_VALIDATE_IMAGE(NormalBackgroundImage) -MOBILY_DEFINE_VALIDATE_STRING(HighlightedTitle) -MOBILY_DEFINE_VALIDATE_COLOR(HighlightedTitleColor) -MOBILY_DEFINE_VALIDATE_COLOR(HighlightedTitleShadowColor) -MOBILY_DEFINE_VALIDATE_IMAGE(HighlightedImage) -MOBILY_DEFINE_VALIDATE_IMAGE(HighlightedBackgroundImage) -MOBILY_DEFINE_VALIDATE_STRING(DisabledTitle) -MOBILY_DEFINE_VALIDATE_COLOR(DisabledTitleColor) -MOBILY_DEFINE_VALIDATE_COLOR(DisabledTitleShadowColor) -MOBILY_DEFINE_VALIDATE_IMAGE(DisabledImage) -MOBILY_DEFINE_VALIDATE_IMAGE(DisabledBackgroundImage) -MOBILY_DEFINE_VALIDATE_STRING(SelectedTitle) -MOBILY_DEFINE_VALIDATE_COLOR(SelectedTitleColor) -MOBILY_DEFINE_VALIDATE_COLOR(SelectedTitleShadowColor) -MOBILY_DEFINE_VALIDATE_IMAGE(SelectedImage) -MOBILY_DEFINE_VALIDATE_IMAGE(SelectedBackgroundImage) - -#pragma mark Property - -- (void)setNormalTitle:(NSString*)normalTitle { - [self setTitle:normalTitle forState:UIControlStateNormal]; -} - -- (NSString*)normalTitle { - return [self titleForState:UIControlStateNormal]; -} - -- (void)setNormalTitleColor:(UIColor*)normalTitleColor { - [self setTitleColor:normalTitleColor forState:UIControlStateNormal]; -} - -- (UIColor*)normalTitleColor { - return [self titleColorForState:UIControlStateNormal]; -} - -- (void)setNormalTitleShadowColor:(UIColor*)normalTitleShadowColor { - [self setTitleShadowColor:normalTitleShadowColor forState:UIControlStateNormal]; -} - -- (UIColor*)normalTitleShadowColor { - return [self titleShadowColorForState:UIControlStateNormal]; -} - -- (void)setNormalImage:(UIImage*)normalImage { - [self setImage:normalImage forState:UIControlStateNormal]; -} - -- (UIImage*)normalImage { - return [self imageForState:UIControlStateNormal]; -} - -- (void)setNormalBackgroundImage:(UIImage*)normalBackgroundImage { - [self setBackgroundImage:normalBackgroundImage forState:UIControlStateNormal]; -} - -- (UIImage*)normalBackgroundImage { - return [self backgroundImageForState:UIControlStateNormal]; -} - -- (void)setHighlightedTitle:(NSString*)highlightedTitle { - [self setTitle:highlightedTitle forState:UIControlStateHighlighted]; -} - -- (NSString*)highlightedTitle { - return [self titleForState:UIControlStateHighlighted]; -} - -- (void)setHighlightedTitleColor:(UIColor*)highlightedTitleColor { - [self setTitleColor:highlightedTitleColor forState:UIControlStateHighlighted]; -} - -- (UIColor*)highlightedTitleColor { - return [self titleColorForState:UIControlStateHighlighted]; -} - -- (void)setHighlightedTitleShadowColor:(UIColor*)highlightedTitleShadowColor { - [self setTitleShadowColor:highlightedTitleShadowColor forState:UIControlStateHighlighted]; -} - -- (UIColor*)highlightedTitleShadowColor { - return [self titleShadowColorForState:UIControlStateHighlighted]; -} - -- (void)setHighlightedImage:(UIImage*)highlightedImage { - [self setImage:highlightedImage forState:UIControlStateHighlighted]; -} - -- (UIImage*)highlightedImage { - return [self imageForState:UIControlStateHighlighted]; -} - -- (void)setHighlightedBackgroundImage:(UIImage*)highlightedBackgroundImage { - [self setBackgroundImage:highlightedBackgroundImage forState:UIControlStateHighlighted]; -} - -- (UIImage*)highlightedBackgroundImage { - return [self backgroundImageForState:UIControlStateHighlighted]; -} - -- (void)setDisabledTitle:(NSString*)disabledTitle { - [self setTitle:disabledTitle forState:UIControlStateDisabled]; -} - -- (NSString*)disabledTitle { - return [self titleForState:UIControlStateDisabled]; -} - -- (void)setDisabledTitleColor:(UIColor*)disabledTitleColor { - [self setTitleColor:disabledTitleColor forState:UIControlStateDisabled]; -} - -- (UIColor*)disabledTitleColor { - return [self titleColorForState:UIControlStateDisabled]; -} - -- (void)setDisabledTitleShadowColor:(UIColor*)disabledTitleShadowColor { - [self setTitleShadowColor:disabledTitleShadowColor forState:UIControlStateDisabled]; -} - -- (UIColor*)disabledTitleShadowColor { - return [self titleShadowColorForState:UIControlStateDisabled]; -} - -- (void)setDisabledImage:(UIImage*)disabledImage { - [self setImage:disabledImage forState:UIControlStateDisabled]; -} - -- (UIImage*)disabledImage { - return [self imageForState:UIControlStateDisabled]; -} - -- (void)setDisabledBackgroundImage:(UIImage*)disabledBackgroundImage { - [self setBackgroundImage:disabledBackgroundImage forState:UIControlStateDisabled]; -} - -- (UIImage*)disabledBackgroundImage { - return [self backgroundImageForState:UIControlStateDisabled]; -} - -- (void)setSelectedTitle:(NSString*)selectedTitle { - [self setTitle:selectedTitle forState:UIControlStateSelected]; -} - -- (NSString*)selectedTitle { - return [self titleForState:UIControlStateSelected]; -} - -- (void)setSelectedTitleColor:(UIColor*)selectedTitleColor { - [self setTitleColor:selectedTitleColor forState:UIControlStateSelected]; -} - -- (UIColor*)selectedTitleColor { - return [self titleColorForState:UIControlStateSelected]; -} - -- (void)setSelectedTitleShadowColor:(UIColor*)selectedTitleShadowColor { - [self setTitleShadowColor:selectedTitleShadowColor forState:UIControlStateSelected]; -} - -- (UIColor*)selectedTitleShadowColor { - return [self titleShadowColorForState:UIControlStateSelected]; -} - -- (void)setSelectedImage:(UIImage*)selectedImage { - [self setImage:selectedImage forState:UIControlStateSelected]; -} - -- (UIImage*)selectedImage { - return [self imageForState:UIControlStateSelected]; -} - -- (void)setSelectedBackgroundImage:(UIImage*)selectedBackgroundImage { - [self setBackgroundImage:selectedBackgroundImage forState:UIControlStateSelected]; -} - -- (UIImage*)selectedBackgroundImage { - return [self backgroundImageForState:UIControlStateSelected]; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation UIViewController (MobilyUI) - -#pragma mark NSKeyValueCoding - -MOBILY_DEFINE_VALIDATE_STRING(Title) - -#pragma mark Public - -- (void)loadViewIfNeed { - if([self isViewLoaded] == NO) { - [self loadView]; - } -} - -- (void)unloadViewIfPossible { - if([self isViewLoaded] == YES) { - if([[self view] window] == nil) { - [self setView:nil]; - } - } -} - -- (void)unloadView { - if([self isViewLoaded] == YES) { - [self setView:nil]; - } -} - -- (UIViewController*)currentViewController { - return [UIViewController currentViewController:self]; -} - -#pragma mark Private - -+ (UIViewController*)currentViewController:(UIViewController*)rootViewController { - if([rootViewController presentedViewController] != nil) { - return [self currentViewController:[rootViewController presentedViewController]]; - } - if([rootViewController isKindOfClass:[UINavigationController class]] == YES) { - UINavigationController* navigationController = (UINavigationController*)rootViewController; - return [self currentViewController:[navigationController topViewController]]; - } else if([rootViewController isKindOfClass:[UITabBarController class]] == YES) { - UITabBarController* tabBarController = (UITabBarController*)rootViewController; - return [self currentViewController:[tabBarController selectedViewController]]; - } - return rootViewController; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation UINavigationController (MobilyUI) - -#pragma mark NSKeyValueCoding - -MOBILY_DEFINE_VALIDATE_BOOL(NavigationBarHidden) -MOBILY_DEFINE_VALIDATE_BOOL(ToolbarHidden) -MOBILY_DEFINE_VALIDATE_BOOL(Translucent) -MOBILY_DEFINE_VALIDATE_COLOR(TintColor) -MOBILY_DEFINE_VALIDATE_COLOR(BarTintColor) -MOBILY_DEFINE_VALIDATE_IMAGE(ShadowImage) -//MOBILY_DEFINE_VALIDATE_TEXT_ATTRIBUTES(TitleTextAttributes) -MOBILY_DEFINE_VALIDATE_IMAGE(BackIndicatorImage) -MOBILY_DEFINE_VALIDATE_IMAGE(BackIndicatorTransitionMaskImage) - -#pragma mark Property - -- (void)setTranslucent:(BOOL)translucent { - [[self navigationBar] setTranslucent:translucent]; -} - -- (BOOL)isTranslucent { - return [[self navigationBar] isTranslucent]; -} - -- (void)setTintColor:(UIColor*)tintColor { - [[self navigationBar] setTintColor:tintColor]; -} - -- (UIColor*)tintColor { - return [[self navigationBar] tintColor]; -} - -- (void)setBarTintColor:(UIColor*)barTintColor { - [[self navigationBar] setBarTintColor:barTintColor]; -} - -- (UIColor*)barTintColor { - return [[self navigationBar] barTintColor]; -} - -- (void)setShadowImage:(UIImage*)shadowImage { - [[self navigationBar] setShadowImage:shadowImage]; -} - -- (UIImage*)shadowImage { - return [[self navigationBar] shadowImage]; -} - -- (void)setTitleTextAttributes:(NSDictionary*)titleTextAttributes { - [[self navigationBar] setTitleTextAttributes:titleTextAttributes]; -} - -- (NSDictionary*)titleTextAttributes { - return [[self navigationBar] titleTextAttributes]; -} - -- (void)setBackIndicatorImage:(UIImage*)backIndicatorImage { - [[self navigationBar] setBackIndicatorImage:backIndicatorImage]; -} - -- (UIImage*)backIndicatorImage { - return [[self navigationBar] backIndicatorImage]; -} - -- (void)setBackIndicatorTransitionMaskImage:(UIImage*)backIndicatorTransitionMaskImage { - [[self navigationBar] setBackIndicatorTransitionMaskImage:backIndicatorTransitionMaskImage]; -} - -- (UIImage*)backIndicatorTransitionMaskImage { - return [[self navigationBar] backIndicatorTransitionMaskImage]; -} - -- (UIViewController*)rootViewController { - NSArray* viewControllers = [self viewControllers]; - if([viewControllers count] > 0) { - return [viewControllers objectAtIndex:0]; - } - return nil; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation UINavigationItem (MobilyUI) - -#pragma mark NSKeyValueCoding - -#pragma mark Property - -- (void)setLeftBarView:(UIView*)view animated:(BOOL)animated { - UIBarButtonItem* item = MOBILY_SAFE_AUTORELEASE([[UIBarButtonItem alloc] initWithCustomView:view]); - [self setLeftBarButtonItem:item animated:animated]; -} - -- (void)setRightBarView:(UIView*)view animated:(BOOL)animated { - UIBarButtonItem* item = MOBILY_SAFE_AUTORELEASE([[UIBarButtonItem alloc] initWithCustomView:view]); - [self setRightBarButtonItem:item animated:animated]; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation UIDevice (MobilyUI) - -+ (CGFloat)systemVersion { - static CGFloat version = 0.0f; - if(version == 0.0f) { - version = [[[self currentDevice] systemVersion] floatValue]; - } - return version; -} - -+ (BOOL)isIPhone { - return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone); -} - -+ (BOOL)isIPad { - return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad); -} - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyWindow.m b/Classes/UI/Core/MobilyWindow.m deleted file mode 100644 index d55a56e..0000000 --- a/Classes/UI/Core/MobilyWindow.m +++ /dev/null @@ -1,248 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyWindow.h" -#import "MobilyApplication.h" -#import "MobilyEvent.h" - -/*--------------------------------------------------*/ - -#import "MobilyControllerView.h" - -/*--------------------------------------------------*/ - -@interface MobilyWindow () - -@property(nonatomic, readwrite, assign) BOOL isNeedLoad; - -@property(nonatomic, readwrite, strong) UIView* emptyView; -@property(nonatomic, readwrite, strong) UITapGestureRecognizer* emptyTabGesture; -@property(nonatomic, readwrite, strong) UIPanGestureRecognizer* emptyPanGesture; - -- (void)willShowKeyboard:(NSNotification*)notification; -- (void)didHideKeyboard:(NSNotification*)notification; - -- (void)resignCurrentFirstResponder; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyWindow - -@synthesize objectName = _objectName; -@synthesize objectParent = _objectParent; -@synthesize objectChilds = _objectChilds; - -#pragma mark NSKeyValueCoding - -MOBILY_DEFINE_VALIDATE_EVENT(EventDidLoad) -MOBILY_DEFINE_VALIDATE_EVENT(EventDidUnload) - -#pragma mark Standart - -- (id)init { - self = [super initWithFrame:[[UIScreen mainScreen] bounds]]; - if(self != nil) { - [self setupWindow]; - } - return self; -} - -- (id)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if(self != nil) { - [self setupWindow]; - } - return self; -} - -- (void)dealloc { - [_eventDidUnload fireSender:self object:nil]; - - [self setObjectName:nil]; - [self setObjectParent:nil]; - [self setObjectChilds:nil]; - - [self setEmptyView:nil]; - [self setEmptyTabGesture:nil]; - [self setEmptyPanGesture:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark MobilyBuilderObject - -- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIViewController class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andAddingObject:objectChild]]; - } -} - -- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIViewController class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andRemovingObject:objectChild]]; - } -} - -- (void)willLoadObjectChilds { -} - -- (void)didLoadObjectChilds { -} - -- (id< MobilyBuilderObject >)objectForName:(NSString*)name { - return [MobilyBuilderForm object:self forName:name]; -} - -- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { - return [MobilyBuilderForm object:self forSelector:selector]; -} - -#pragma mark UIWindow - -- (void)becomeKeyWindow { - [super becomeKeyWindow]; - - if(_emptyView == nil) { - [self setEmptyView:[[UIView alloc] initWithFrame:[self bounds]]]; - if(_emptyView != nil) { - [_emptyView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)]; - [_emptyView setBackgroundColor:[UIColor clearColor]]; - [_emptyView setHidden:YES]; - [self addSubview:_emptyView]; - - [self setEmptyTabGesture:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(resignCurrentFirstResponder)]]; - if(_emptyTabGesture != nil) { - [_emptyView addGestureRecognizer:_emptyTabGesture]; - } - - [self setEmptyPanGesture:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(resignCurrentFirstResponder)]]; - if(_emptyPanGesture != nil) { - [_emptyView addGestureRecognizer:_emptyPanGesture]; - } - } - } - - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willShowKeyboard:) name:UIKeyboardWillShowNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didHideKeyboard:) name:UIKeyboardDidHideNotification object:nil]; - - if([self rootViewController] == nil) { - UIViewController* controller = [_eventDidLoad fireSender:self object:nil]; - if(controller != nil) { - [self setRootViewController:controller]; - } else if([_objectChilds count] > 0) { - [self setRootViewController:[_objectChilds firstObject]]; - } - } -} - -- (void)resignKeyWindow { - [super resignKeyWindow]; - - [[NSNotificationCenter defaultCenter] removeObserver:self]; -} - -- (void)didAddSubview:(UIView*)subview { - [super didAddSubview:subview]; - [self bringSubviewToFront:_emptyView]; -} - -- (void)willRemoveSubview:(UIView*)subview { - [super willRemoveSubview:subview]; - [self bringSubviewToFront:_emptyView]; -} - -- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event { - if([_emptyView isHidden] == NO) { - UIViewController* currentViewController = [self currentViewController]; - UIViewController* parentViewController = [currentViewController parentViewController]; - if(parentViewController == nil) { - parentViewController = currentViewController; - } - if(_automaticallyHideKeyboard == YES) { - if([currentViewController isKindOfClass:[MobilyControllerView class]] == YES) { - MobilyControllerView* mobilyViewController = (MobilyControllerView*)currentViewController; - if([mobilyViewController isAutomaticallyHideKeyboard] == NO) { - return [[[self rootViewController] view] hitTest:point withEvent:event]; - } - } - UIView* view = [[parentViewController view] hitTest:point withEvent:event]; - if([view canBecomeFirstResponder] == NO) { - if([view isKindOfClass:[UIControl class]] == YES) { - UIControl* control = (UIControl*)view; - if([control isEnabled] == NO) { - view = _emptyView; - } - } else { - view = _emptyView; - } - } - return view; - } else { - return [[[self rootViewController] view] hitTest:point withEvent:event]; - } - } - return [super hitTest:point withEvent:event]; -} - -#pragma mark Public - -- (void)setupWindow { - [self setAutomaticallyHideKeyboard:YES]; -} - -#pragma mark Private - -- (void)willShowKeyboard:(NSNotification*)notification { - [_emptyView setHidden:NO]; -} - -- (void)didHideKeyboard:(NSNotification*)notification { - [_emptyView setHidden:YES]; -} - -- (void)resignCurrentFirstResponder { - UIResponder* firstResponder = [UIResponder currentFirstResponder]; - if(firstResponder != nil) { - [firstResponder resignFirstResponder]; - } -} - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/UI/ViewElements/MobilyViewElements.h b/Classes/UI/ViewElements/MobilyViewElements.h deleted file mode 100644 index 3c1ba36..0000000 --- a/Classes/UI/ViewElements/MobilyViewElements.h +++ /dev/null @@ -1,227 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyBuilder.h" - -/*--------------------------------------------------*/ - -@class MobilyViewElements; -@class MobilyViewElementsCell; -@class MobilyViewElementsItem; - -/*--------------------------------------------------*/ - -@protocol MobilyViewElementsDataSource < NSObject > - -@required -- (NSInteger)numberOfItemsInElements:(MobilyViewElements*)elements; -- (NSString*)elements:(MobilyViewElements*)elements itemIdentifierAtIndex:(NSUInteger)index; -- (CGSize)elements:(MobilyViewElements*)elements itemSizeAtIndex:(NSUInteger)index; - -@end - -/*--------------------------------------------------*/ - -@protocol MobilyViewElementsDelegate < NSObject > - -@optional -- (void)elements:(MobilyViewElements*)elements showCell:(MobilyViewElementsCell*)elementsCell atIndex:(NSUInteger)index; -- (void)elements:(MobilyViewElements*)elements hideCell:(MobilyViewElementsCell*)elementsCell atIndex:(NSUInteger)index; - -@optional -- (BOOL)elements:(MobilyViewElements*)elements shouldSelectItemAtIndex:(NSUInteger)index; -- (BOOL)elements:(MobilyViewElements*)elements shouldDeselectItemAtIndex:(NSUInteger)index; -- (void)elements:(MobilyViewElements*)elements didSelectItemAtIndex:(NSUInteger)index; -- (void)elements:(MobilyViewElements*)elements didDeselectItemAtIndex:(NSUInteger)index; - -@optional -- (void)elements:(MobilyViewElements*)elements animationReloadBeforeElementsCell:(MobilyViewElementsCell*)elementsCell; -- (void)elements:(MobilyViewElements*)elements animationReloadAfterElementsCell:(MobilyViewElementsCell*)elementsCell; -- (void)elements:(MobilyViewElements*)elements animationInsertElementsCell:(MobilyViewElementsCell*)elementsCell; -- (void)elements:(MobilyViewElements*)elements animationDeleteElementsCell:(MobilyViewElementsCell*)elementsCell; - -@end - -/*--------------------------------------------------*/ - -@protocol MobilyViewElementsLayout < NSObject > - -@required -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems; - -@optional -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems itemsSize:(CGSize)itemsSize reloadRange:(NSRange)reloadRange reloadBeforeItems:(NSArray*)reloadBeforeItems reloadAfterItems:(NSArray*)reloadAfterItems; -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems itemsSize:(CGSize)itemsSize reloadIndexSet:(NSIndexSet*)reloadIndexSet; - -@optional -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems itemsSize:(CGSize)itemsSize insertRange:(NSRange)insertRange insertItems:(NSArray*)insertItems; -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems itemsSize:(CGSize)itemsSize insertIndexSet:(NSIndexSet*)insertIndexSet; - -@optional -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems itemsSize:(CGSize)itemsSize deleteRange:(NSRange)deleteRange deleteItems:(NSArray*)deleteItems; -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems itemsSize:(CGSize)itemsSize deleteIndexSet:(NSIndexSet*)deleteIndexSet; - -@end - -/*--------------------------------------------------*/ - -typedef void (^MobilyViewElementsUpdateBlock)(); -typedef void (^MobilyViewElementsCompleteBlock)(BOOL finished); - -/*--------------------------------------------------*/ - -typedef NS_OPTIONS(NSUInteger, MobilyViewElementsScrollPosition) { - MobilyViewElementsScrollPositionNone = 0, - MobilyViewElementsScrollPositionTop = 1 << 0, - MobilyViewElementsScrollPositionCenteredVertically = 1 << 1, - MobilyViewElementsScrollPositionBottom = 1 << 2, - MobilyViewElementsScrollPositionLeft = 1 << 3, - MobilyViewElementsScrollPositionCenteredHorizontally = 1 << 4, - MobilyViewElementsScrollPositionRight = 1 << 5 -}; - -/*--------------------------------------------------*/ - -@interface MobilyViewElements : UIScrollView< MobilyBuilderObject > - -@property(nonatomic, readwrite, assign) IBOutlet id< MobilyViewElementsDataSource > elementsDataSource; -@property(nonatomic, readwrite, assign) IBOutlet id< MobilyViewElementsDelegate > elementsDelegate; -@property(nonatomic, readwrite, weak) IBOutlet id< MobilyViewElementsLayout > elementsLayout; - -@property(nonatomic, readwrite, assign) BOOL allowsSelection; -@property(nonatomic, readwrite, assign) BOOL allowsMultipleSelection; - -@property(nonatomic, readonly, copy) NSIndexSet* visibleIndexSet; -@property(nonatomic, readonly, strong) NSArray* visibleItems; -@property(nonatomic, readonly, strong) NSArray* visibleCells; - -@property(nonatomic, readonly, copy) NSIndexSet* selectedIndexSet; -@property(nonatomic, readonly, assign) NSUInteger selectedIndex; -@property(nonatomic, readonly, strong) NSArray* selectedItems; -@property(nonatomic, readonly, strong) NSArray* selectedCells; - -@property(nonatomic, readonly, assign, getter=isUpdating) BOOL updating; - -- (void)setupView; - -- (void)registerCellClass:(Class)cellClass withIdentifier:(NSString*)identifier; -- (void)registerCellClass:(Class)cellClass fromNib:(UINib*)nib withIdentifier:(NSString*)identifier; -- (void)unregisterCellWithIdentifier:(NSString*)identifier; - -- (MobilyViewElementsItem*)itemAtIndex:(NSUInteger)index; -- (NSUInteger)indexAtItem:(MobilyViewElementsItem*)item; - -- (BOOL)isSelectedItem:(MobilyViewElementsItem*)item; -- (BOOL)isSelectedItemAtIndex:(NSUInteger)index; - -- (BOOL)shouldSelectItem:(MobilyViewElementsItem*)item; -- (BOOL)shouldSelectItemAtIndex:(NSUInteger)index; - -- (BOOL)shouldDeselectItem:(MobilyViewElementsItem*)item; -- (BOOL)shouldDeselectItemAtIndex:(NSUInteger)index; - -- (void)selectItem:(MobilyViewElementsItem*)item animated:(BOOL)animated; -- (void)selectItemAtIndex:(NSUInteger)index animated:(BOOL)animated; -- (void)selectItemAtIndexSet:(NSIndexSet*)indexSet animated:(BOOL)animated; - -- (void)deselectItem:(MobilyViewElementsItem*)item animated:(BOOL)animated; -- (void)deselectItemAtIndex:(NSUInteger)index animated:(BOOL)animated; -- (void)deselectItemAtIndexSet:(NSIndexSet*)indexSet animated:(BOOL)animated; -- (void)deselectAllSelectedItemsAnimated:(BOOL)animated; - -- (void)scrollToItem:(MobilyViewElementsItem*)item scrollPosition:(MobilyViewElementsScrollPosition)scrollPosition animated:(BOOL)animated; -- (void)scrollToItemAtIndex:(NSUInteger)index scrollPosition:(MobilyViewElementsScrollPosition)scrollPosition animated:(BOOL)animated; - -- (void)reloadItems; - -- (void)reloadItemAtIndexSet:(NSIndexSet*)indexSet; -- (void)insertItemAtIndexSet:(NSIndexSet*)indexSet; -- (void)deleteItemAtIndexSet:(NSIndexSet*)indexSet; - -- (void)performBatchUpdate:(MobilyViewElementsUpdateBlock)update complete:(MobilyViewElementsCompleteBlock)complete; -- (void)performBatchDuration:(NSTimeInterval)duration update:(MobilyViewElementsUpdateBlock)update complete:(MobilyViewElementsCompleteBlock)complete; - -@end - -/*--------------------------------------------------*/ - -@interface MobilyViewElementsCell : UIControl< MobilyBuilderObject > - -@property(nonatomic, readonly, weak) MobilyViewElements* elements; -@property(nonatomic, readonly, weak) MobilyViewElementsItem* elementsItem; - -- (void)setup; - -- (void)setSelected:(BOOL)selected animated:(BOOL)animated; -- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated; - -- (void)prepareItem:(MobilyViewElementsItem*)elementsItem; -- (void)updatingItem:(MobilyViewElementsItem*)elementsItem animated:(BOOL)animated; -- (void)cleanupItem:(MobilyViewElementsItem*)elementsItem; - -@end - -/*--------------------------------------------------*/ - -@interface MobilyViewElementsItem : NSObject - -@property(nonatomic, readonly, weak) MobilyViewElements* elements; -@property(nonatomic, readonly, weak) MobilyViewElementsCell* elementsCell; - -@property(nonatomic, readonly, assign) NSUInteger index; -@property(nonatomic, readonly, strong) NSString* identifier; -@property(nonatomic, readonly, assign, getter=isSelected) BOOL selected; - -@property(nonatomic, readwrite, assign) NSInteger zIndex; - -@property(nonatomic, readwrite, assign) CGRect initialFrame; -@property(nonatomic, readwrite, assign) CGPoint initialFrameOrigin; -@property(nonatomic, readwrite, assign) CGFloat initialFrameOriginX; -@property(nonatomic, readwrite, assign) CGFloat initialFrameOriginY; -@property(nonatomic, readwrite, assign) CGSize initialFrameSize; -@property(nonatomic, readwrite, assign) CGFloat initialFrameSizeWidth; -@property(nonatomic, readwrite, assign) CGFloat initialFrameSizeHeight; - -@property(nonatomic, readwrite, assign) CGRect frame; -@property(nonatomic, readwrite, assign) CGPoint frameOrigin; -@property(nonatomic, readwrite, assign) CGFloat frameOriginX; -@property(nonatomic, readwrite, assign) CGFloat frameOriginY; -@property(nonatomic, readwrite, assign) CGSize frameSize; -@property(nonatomic, readwrite, assign) CGFloat frameSizeWidth; -@property(nonatomic, readwrite, assign) CGFloat frameSizeHeight; - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/UI/ViewElements/MobilyViewElements.m b/Classes/UI/ViewElements/MobilyViewElements.m deleted file mode 100644 index b093175..0000000 --- a/Classes/UI/ViewElements/MobilyViewElements.m +++ /dev/null @@ -1,1284 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyViewElements.h" - -/*--------------------------------------------------*/ - -@interface MobilyViewElements () - -// Protocol access -@property(nonatomic, readwrite, assign) BOOL elementsDelegateShowCellAtIndex; -@property(nonatomic, readwrite, assign) BOOL elementsDelegateHideCellAtIndex; -@property(nonatomic, readwrite, assign) BOOL elementsDelegateShouldSelectItemAtIndex; -@property(nonatomic, readwrite, assign) BOOL elementsDelegateShouldDeselectItemAtIndex; -@property(nonatomic, readwrite, assign) BOOL elementsDelegateDidSelectItemAtIndex; -@property(nonatomic, readwrite, assign) BOOL elementsDelegateDidDeselectItemAtIndex; -@property(nonatomic, readwrite, assign) BOOL elementsDelegateAnimationReloadBeforeElementsCell; -@property(nonatomic, readwrite, assign) BOOL elementsDelegateAnimationReloadAfterElementsCell; -@property(nonatomic, readwrite, assign) BOOL elementsDelegateAnimationInsertElementsCell; -@property(nonatomic, readwrite, assign) BOOL elementsDelegateAnimationDeleteElementsCell; - -@property(nonatomic, readwrite, assign) BOOL elementsLayoutItemsItemsSizeReloadRangeBeloadBeforeItemsReloadAfterItems; -@property(nonatomic, readwrite, assign) BOOL elementsLayoutItemsItemsSizeReloadIndexSet; -@property(nonatomic, readwrite, assign) BOOL elementsLayoutItemsItemsSizeInsertRangeInsertItems; -@property(nonatomic, readwrite, assign) BOOL elementsLayoutItemsItemsSizeInsertIndexSet; -@property(nonatomic, readwrite, assign) BOOL elementsLayoutItemsItemsSizeDeleteRangeDeleteItems; -@property(nonatomic, readwrite, assign) BOOL elementsLayoutItemsItemsSizeDeleteIndexSet; - -// Change access -@property(nonatomic, readwrite, strong) NSMutableArray* items; -@property(nonatomic, readwrite, strong) NSMutableIndexSet* mutableVisibleIndexSet; -@property(nonatomic, readwrite, strong) NSMutableIndexSet* mutableSelectedIndexSet; - -@property(nonatomic, readwrite, assign, getter=isUpdating) BOOL updating; -@property(nonatomic, readwrite, assign) CGSize updatingContentSize; - -// Private -@property(nonatomic, readwrite, strong) NSMutableDictionary* registersCells; -@property(nonatomic, readwrite, strong) NSMutableDictionary* queueCells; - -@property(nonatomic, readwrite, strong) NSMutableArray* reloadedBeforeItems; -@property(nonatomic, readwrite, strong) NSMutableArray* reloadedAfterItems; -@property(nonatomic, readwrite, strong) NSMutableArray* deletedItems; -@property(nonatomic, readwrite, strong) NSMutableArray* insertedItems; - -- (void)notificationReceiveMemoryWarning:(NSNotification*)notification; - -- (MobilyViewElementsCell*)dequeueCellWithElementsItem:(MobilyViewElementsItem*)item; -- (void)enqueueCellWithElementsItem:(MobilyViewElementsItem*)item; - -- (void)layoutItems; -- (void)applyLayoutItems; -- (void)updateVisibleItems; - -- (void)selectItemAtIndex:(NSUInteger)index animated:(BOOL)animated user:(BOOL)user; -- (void)deselectItemAtIndex:(NSUInteger)index animated:(BOOL)animated user:(BOOL)user; - -- (void)selectItemAtElementsCell:(MobilyViewElementsCell*)cell animated:(BOOL)animated; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyViewElementsCell () - -@property(nonatomic, readwrite, weak) MobilyViewElements* elements; -@property(nonatomic, readwrite, weak) MobilyViewElementsItem* elementsItem; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyViewElementsItem () - -@property(nonatomic, readwrite, weak) MobilyViewElements* elements; -@property(nonatomic, readwrite, weak) MobilyViewElementsCell* elementsCell; - -@property(nonatomic, readwrite, assign) NSUInteger index; -@property(nonatomic, readwrite, strong) NSString* identifier; -@property(nonatomic, readwrite, assign, getter=isSelected) BOOL selected; - -- (id)initWithElements:(MobilyViewElements*)elements; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyViewElementsRegisterCell : NSObject - -@property(nonatomic ,readwrite, assign) Class cellClass; -@property(nonatomic ,readwrite, strong) UINib* cellNib; - -- (id)initWithCellClass:(Class)cellClass; -- (id)initWithCellClass:(Class)cellClass cellNib:(UINib*)cellNib; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyViewElements - -@synthesize objectName = _objectName; -@synthesize objectParent = _objectParent; -@synthesize objectChilds = _objectChilds; - -#pragma mark NSKeyValueCoding - -#pragma mark Standart - -- (id)initWithCoder:(NSCoder*)coder { - self = [super initWithCoder:coder]; - if(self != nil) { - [self setupView]; - } - return self; -} - -- (id)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if(self != nil) { - [self setupView]; - } - return self; -} - -- (void)dealloc { - [self unregisterAdjustmentResponder]; - - [self setObjectName:nil]; - [self setObjectParent:nil]; - [self setObjectChilds:nil]; - - [self setItems:nil]; - [self setMutableVisibleIndexSet:nil]; - [self setMutableSelectedIndexSet:nil]; - [self setRegistersCells:nil]; - [self setQueueCells:nil]; - [self setReloadedBeforeItems:nil]; - [self setReloadedAfterItems:nil]; - [self setDeletedItems:nil]; - [self setInsertedItems:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark MobilyBuilderObject - -- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIView class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andAddingObject:objectChild]]; - [self addSubview:(UIView*)objectChild]; - } -} - -- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIView class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andRemovingObject:objectChild]]; - [self removeSubview:(UIView*)objectChild]; - } -} - -- (void)willLoadObjectChilds { -} - -- (void)didLoadObjectChilds { -} - -- (id< MobilyBuilderObject >)objectForName:(NSString*)name { - return [MobilyBuilderForm object:self forName:name]; -} - -- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { - return [MobilyBuilderForm object:self forSelector:selector]; -} - -#pragma mark UIView - -- (void)layoutSubviews { - [super layoutSubviews]; - - [self updateVisibleItems]; -} - -#pragma mark NSNotificationCenter - -- (void)notificationReceiveMemoryWarning:(NSNotification*)notification { - [_queueCells removeAllObjects]; -} - -#pragma mark Public - -- (void)setupView { - [self setAllowsSelection:YES]; - [self setAllowsMultipleSelection:NO]; - - [self setItems:[NSMutableArray array]]; - [self setMutableVisibleIndexSet:[NSMutableIndexSet indexSet]]; - [self setMutableSelectedIndexSet:[NSMutableIndexSet indexSet]]; - [self setRegistersCells:[NSMutableDictionary dictionary]]; - [self setQueueCells:[NSMutableDictionary dictionary]]; - [self setReloadedBeforeItems:[NSMutableArray array]]; - [self setReloadedAfterItems:[NSMutableArray array]]; - [self setDeletedItems:[NSMutableArray array]]; - [self setInsertedItems:[NSMutableArray array]]; - - [self registerAdjustmentResponder]; - - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; -} - -- (void)registerCellClass:(Class)cellClass withIdentifier:(NSString*)identifier { - [_registersCells setObject:[[MobilyViewElementsRegisterCell alloc] initWithCellClass:cellClass] forKey:identifier]; -} - -- (void)registerCellClass:(Class)cellClass fromNib:(UINib*)nib withIdentifier:(NSString*)identifier { - [_registersCells setObject:[[MobilyViewElementsRegisterCell alloc] initWithCellClass:cellClass cellNib:nib] forKey:identifier]; -} - -- (void)unregisterCellWithIdentifier:(NSString*)identifier { - [_registersCells removeObjectForKey:identifier]; -} - -- (MobilyViewElementsItem*)itemAtIndex:(NSUInteger)index { - if(index >= [_items count]) { - return nil; - } - return [_items objectAtIndex:index]; -} - -- (NSUInteger)indexAtItem:(MobilyViewElementsItem*)item { - return [_items indexOfObject:item]; -} - -- (BOOL)isSelectedItem:(MobilyViewElementsItem*)item { - return [self isSelectedItemAtIndex:[self indexAtItem:item]]; -} - -- (BOOL)isSelectedItemAtIndex:(NSUInteger)index { - if(index >= [_items count]) { - return NO; - } - return [_mutableSelectedIndexSet containsIndex:index]; -} - -- (BOOL)shouldSelectItem:(MobilyViewElementsItem*)item { - return [self shouldSelectItemAtIndex:[self indexAtItem:item]]; -} - -- (BOOL)shouldSelectItemAtIndex:(NSUInteger)index { - if(index >= [_items count]) { - return NO; - } - if(_elementsDelegateShouldSelectItemAtIndex == YES) { - return [_elementsDelegate elements:self shouldSelectItemAtIndex:index]; - } - return YES; -} - -- (BOOL)shouldDeselectItem:(MobilyViewElementsItem*)item { - return [self shouldDeselectItemAtIndex:[self indexAtItem:item]]; -} - -- (BOOL)shouldDeselectItemAtIndex:(NSUInteger)index { - if(index >= [_items count]) { - return NO; - } - if(_elementsDelegateShouldDeselectItemAtIndex == YES) { - return [_elementsDelegate elements:self shouldDeselectItemAtIndex:index]; - } - return YES; -} - -- (void)selectItem:(MobilyViewElementsItem*)item animated:(BOOL)animated { - [self selectItemAtIndex:[self indexAtItem:item] animated:animated]; -} - -- (void)selectItemAtIndex:(NSUInteger)index animated:(BOOL)animated { - [self selectItemAtIndex:index animated:animated user:NO]; -} - -- (void)selectItemAtIndexSet:(NSIndexSet*)indexSet animated:(BOOL)animated { - NSUInteger index = [indexSet firstIndex]; - while(index != NSNotFound) { - [self selectItemAtIndex:index animated:animated]; - index = [indexSet indexGreaterThanIndex:index]; - } -} - -- (void)deselectItem:(MobilyViewElementsItem*)item animated:(BOOL)animated { - [self deselectItemAtIndex:[self indexAtItem:item] animated:animated]; -} - -- (void)deselectItemAtIndex:(NSUInteger)index animated:(BOOL)animated { - [self deselectItemAtIndex:index animated:animated user:NO]; -} - -- (void)deselectItemAtIndexSet:(NSIndexSet*)indexSet animated:(BOOL)animated { - NSUInteger index = [indexSet firstIndex]; - while(index != NSNotFound) { - [self selectItemAtIndex:index animated:animated]; - index = [indexSet indexGreaterThanIndex:index]; - } -} - -- (void)deselectAllSelectedItemsAnimated:(BOOL)animated { - [_mutableSelectedIndexSet enumerateIndexesUsingBlock:^(NSUInteger selectedIndex, BOOL* stop) { - [self deselectItemAtIndex:selectedIndex animated:animated]; - }]; -} - -- (void)scrollToItem:(MobilyViewElementsItem*)item scrollPosition:(MobilyViewElementsScrollPosition)scrollPosition animated:(BOOL)animated { - [self scrollToItemAtIndex:[self indexAtItem:item] scrollPosition:scrollPosition animated:animated]; -} - -- (void)scrollToItemAtIndex:(NSUInteger)index scrollPosition:(MobilyViewElementsScrollPosition)scrollPosition animated:(BOOL)animated { - if(index >= [_items count]) { - return; - } - NSUInteger vPosition = scrollPosition & 0x07; - NSUInteger hPosition = scrollPosition & 0x38; - if((vPosition != MobilyViewElementsScrollPositionNone) && (vPosition != MobilyViewElementsScrollPositionTop) && (vPosition != MobilyViewElementsScrollPositionCenteredVertically) && (vPosition != MobilyViewElementsScrollPositionBottom)) { - @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"MobilyViewElementsScrollPosition: attempt to use a scroll position with multiple vertical positioning styles" userInfo:nil]; - } - if((hPosition != MobilyViewElementsScrollPositionNone) && (hPosition != MobilyViewElementsScrollPositionLeft) && (hPosition != MobilyViewElementsScrollPositionCenteredHorizontally) && (hPosition != MobilyViewElementsScrollPositionRight)) { - @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"MobilyViewElementsScrollPosition: attempt to use a scroll position with multiple horizontal positioning styles" userInfo:nil]; - } - CGRect visibleRect = [self bounds]; - UIEdgeInsets contentInset = [self contentInset]; - MobilyViewElementsItem* item = [_items objectAtIndex:index]; - CGRect itemFrame = [item frame]; - switch(vPosition) { - case MobilyViewElementsScrollPositionCenteredVertically: { - CGFloat offset = fmax(itemFrame.origin.y - ((visibleRect.size.height * 0.5f) - (itemFrame.size.height * 0.5f)), -contentInset.top); - itemFrame = CGRectMake(itemFrame.origin.x, offset, itemFrame.size.width, visibleRect.size.height); - break; - } - case MobilyViewElementsScrollPositionTop: { - itemFrame = CGRectMake(itemFrame.origin.x, itemFrame.origin.y, itemFrame.size.width, visibleRect.size.height); - break; - } - case MobilyViewElementsScrollPositionBottom: { - CGFloat offset = fmax(itemFrame.origin.y - (visibleRect.size.height - itemFrame.size.height), -contentInset.top); - itemFrame = CGRectMake(itemFrame.origin.x, offset, itemFrame.size.width, visibleRect.size.height); - break; - } - } - switch(hPosition) { - case MobilyViewElementsScrollPositionLeft: { - itemFrame = CGRectMake(itemFrame.origin.x, itemFrame.origin.y, visibleRect.size.width, itemFrame.size.height); - break; - } - case MobilyViewElementsScrollPositionCenteredHorizontally: { - CGFloat offset = itemFrame.origin.x - ((visibleRect.size.width * 0.5f) - (itemFrame.size.width * 0.5f)); - itemFrame = CGRectMake(offset, itemFrame.origin.y, visibleRect.size.width, itemFrame.size.height); - break; - } - case MobilyViewElementsScrollPositionRight: { - CGFloat offset = itemFrame.origin.x - (visibleRect.size.width - itemFrame.size.width); - itemFrame = CGRectMake(offset, itemFrame.origin.y, visibleRect.size.width, itemFrame.size.height); - break; - } - } - [self scrollRectToVisible:itemFrame animated:animated]; -} - -- (void)reloadItems { - if(_updating == NO) { - [UIView performWithoutAnimation:^{ - [_items enumerateObjectsUsingBlock:^(MobilyViewElementsItem* item, NSUInteger elementsIndex, BOOL* stop) { - [self enqueueCellWithElementsItem:item]; - }]; - [_mutableVisibleIndexSet removeAllIndexes]; - - NSUInteger itemsCount = [_items count]; - NSUInteger count = [_elementsDataSource numberOfItemsInElements:self]; - if(itemsCount > count) { - NSUInteger removeCount = itemsCount - count; - NSRange removeRange = NSMakeRange(itemsCount - removeCount, removeCount); - [_items removeObjectsInRange:removeRange]; - [_mutableSelectedIndexSet removeIndexesInRange:removeRange]; - itemsCount = count; - } - if([_items count] > 0) { - [_items enumerateObjectsUsingBlock:^(MobilyViewElementsItem* item, NSUInteger elementsIndex, BOOL* stop) { - [item setIdentifier:[_elementsDataSource elements:self itemIdentifierAtIndex:elementsIndex]]; - [item setInitialFrameSize:[_elementsDataSource elements:self itemSizeAtIndex:elementsIndex]]; - [item setFrame:[item initialFrame]]; - }]; - } - if(count > 0) { - for(NSUInteger index = itemsCount; index < count; index++) { - MobilyViewElementsItem* item = [[MobilyViewElementsItem alloc] initWithElements:self]; - if(item != nil) { - [item setIndex:index]; - [item setIdentifier:[_elementsDataSource elements:self itemIdentifierAtIndex:index]]; - [item setInitialFrameSize:[_elementsDataSource elements:self itemSizeAtIndex:index]]; - [item setFrame:[item initialFrame]]; - - [_items addObject:item]; - } - } - [self layoutItems]; - } else { - [self setContentSize:CGSizeZero]; - } - [self updateVisibleItems]; - [self applyLayoutItems]; - }]; - } else { - @throw [NSException exceptionWithName:NSGenericException reason:@"reloadData - The method should be called in batch update block" userInfo:nil]; - } -} - -- (void)reloadItemAtIndexSet:(NSIndexSet*)indexSet { - if(_updating == YES) { - if(indexSet == nil) { - return; - } - if([indexSet count] > 0) { - [indexSet enumerateRangesWithOptions:NSEnumerationReverse usingBlock:^(NSRange reloadRange, BOOL* stop) { - [_mutableVisibleIndexSet removeIndexesInRange:reloadRange]; - - NSArray* reloadBeforeItems = [_items subarrayWithRange:reloadRange]; - if(reloadBeforeItems != nil) { - [_reloadedBeforeItems addObjectsFromArray:reloadBeforeItems]; - } - for(NSUInteger index = reloadRange.location; index < (reloadRange.location + reloadRange.length); index++) { - MobilyViewElementsItem* item = [[MobilyViewElementsItem alloc] initWithElements:self]; - if(item != nil) { - [item setIndex:index]; - [item setSelected:[_mutableSelectedIndexSet containsIndex:index]]; - [item setIdentifier:[_elementsDataSource elements:self itemIdentifierAtIndex:index]]; - [item setInitialFrameSize:[_elementsDataSource elements:self itemSizeAtIndex:index]]; - [item setFrame:[item initialFrame]]; - - [_items replaceObjectAtIndex:index withObject:item]; - } - } - NSArray* reloadAfterItems = [_items subarrayWithRange:reloadRange]; - if(reloadAfterItems != nil) { - [_reloadedAfterItems addObjectsFromArray:reloadAfterItems]; - } - if(_elementsLayoutItemsItemsSizeReloadRangeBeloadBeforeItemsReloadAfterItems == YES) { - [self setUpdatingContentSize:[_elementsLayout elements:self layoutItems:_items itemsSize:_updatingContentSize reloadRange:reloadRange reloadBeforeItems:reloadBeforeItems reloadAfterItems:reloadAfterItems]]; - } - }]; - if(_elementsLayoutItemsItemsSizeReloadRangeBeloadBeforeItemsReloadAfterItems == NO) { - if(_elementsLayoutItemsItemsSizeReloadIndexSet == YES) { - [self setUpdatingContentSize:[_elementsLayout elements:self layoutItems:_items itemsSize:_updatingContentSize reloadIndexSet:indexSet]]; - } else { - [self setUpdatingContentSize:[_elementsLayout elements:self layoutItems:_items]]; - } - } - } - } else { - @throw [NSException exceptionWithName:NSGenericException reason:@"reloadItemAtIndexSet: - The method should be called in batch update block" userInfo:nil]; - } -} - -- (void)insertItemAtIndexSet:(NSIndexSet*)indexSet { - if(_updating == YES) { - if(indexSet == nil) { - return; - } - if([indexSet count] > 0) { - [indexSet enumerateRangesWithOptions:NSEnumerationReverse usingBlock:^(NSRange insertRange, BOOL* stop) { - [_mutableVisibleIndexSet shiftIndexesStartingAtIndex:insertRange.location by:insertRange.length]; - [_mutableSelectedIndexSet shiftIndexesStartingAtIndex:insertRange.location by:insertRange.length]; - - NSMutableArray* insertItems = [NSMutableArray arrayWithCapacity:insertRange.length]; - for(NSUInteger index = insertRange.location; index < (insertRange.location + insertRange.length); index++) { - MobilyViewElementsItem* item = [[MobilyViewElementsItem alloc] initWithElements:self]; - if(item != nil) { - [item setSelected:[_mutableSelectedIndexSet containsIndex:index]]; - [item setIdentifier:[_elementsDataSource elements:self itemIdentifierAtIndex:index]]; - [item setInitialFrameSize:[_elementsDataSource elements:self itemSizeAtIndex:index]]; - [item setFrame:[item initialFrame]]; - - [_items insertObject:item atIndex:index]; - [insertItems addObject:item]; - } - } - [_items enumerateObjectsUsingBlock:^(MobilyViewElementsItem* item, NSUInteger index, BOOL* stop) { - [item setIndex:index]; - }]; - [_insertedItems addObjectsFromArray:insertItems]; - if(_elementsLayoutItemsItemsSizeInsertRangeInsertItems == YES) { - [self setUpdatingContentSize:[_elementsLayout elements:self layoutItems:_items itemsSize:_updatingContentSize insertRange:insertRange insertItems:insertItems]]; - } - }]; - if(_elementsLayoutItemsItemsSizeInsertRangeInsertItems == NO) { - if(_elementsLayoutItemsItemsSizeInsertIndexSet == YES) { - [self setUpdatingContentSize:[_elementsLayout elements:self layoutItems:_items itemsSize:_updatingContentSize insertIndexSet:indexSet]]; - } else { - [self setUpdatingContentSize:[_elementsLayout elements:self layoutItems:_items]]; - } - } - } - } else { - @throw [NSException exceptionWithName:NSGenericException reason:@"insertItemAtIndexSet: - The method should be called in batch update block" userInfo:nil]; - } -} - -- (void)deleteItemAtIndexSet:(NSIndexSet*)indexSet { - if(_updating == YES) { - if(indexSet == nil) { - return; - } - if([indexSet count] > 0) { - [indexSet enumerateRangesWithOptions:NSEnumerationReverse usingBlock:^(NSRange deleteRange, BOOL* stop) { - NSArray* deletedItems = [_items subarrayWithRange:deleteRange]; - if(deletedItems != nil) { - if(_elementsLayoutItemsItemsSizeDeleteRangeDeleteItems == YES) { - [self setUpdatingContentSize:[_elementsLayout elements:self layoutItems:_items itemsSize:_updatingContentSize deleteRange:deleteRange deleteItems:deletedItems]]; - } - [_mutableVisibleIndexSet removeIndexesInRange:deleteRange]; - [_mutableSelectedIndexSet removeIndexesInRange:deleteRange]; - - [_items removeObjectsInRange:deleteRange]; - [_items enumerateObjectsUsingBlock:^(MobilyViewElementsItem* item, NSUInteger index, BOOL* stop) { - [item setIndex:index]; - }]; - [_deletedItems addObjectsFromArray:deletedItems]; - } - }]; - if(_elementsLayoutItemsItemsSizeDeleteRangeDeleteItems == NO) { - if(_elementsLayoutItemsItemsSizeDeleteIndexSet == YES) { - [self setUpdatingContentSize:[_elementsLayout elements:self layoutItems:_items itemsSize:_updatingContentSize deleteIndexSet:indexSet]]; - } else { - [self setUpdatingContentSize:[_elementsLayout elements:self layoutItems:_items]]; - } - } - } - } else { - @throw [NSException exceptionWithName:NSGenericException reason:@"deleteItemAtIndexSet: - The method should be called in batch update block" userInfo:nil]; - } -} - -- (void)performBatchUpdate:(MobilyViewElementsUpdateBlock)update complete:(MobilyViewElementsCompleteBlock)complete { - [self performBatchDuration:0.33f update:update complete:complete]; -} - -- (void)performBatchDuration:(NSTimeInterval)duration update:(MobilyViewElementsUpdateBlock)update complete:(MobilyViewElementsCompleteBlock)complete { - if(_updating == NO) { - [UIView animateWithDuration:duration - delay:0.0f - options:0 - animations:^{ - [self setUpdating:YES]; - [self setUpdatingContentSize:[self contentSize]]; - - update(); - - if([_items count] > 0) { - [_mutableVisibleIndexSet removeIndexesInRange:NSMakeRange([_items count] - 1, INT_MAX)]; - } else { - [_mutableVisibleIndexSet removeAllIndexes]; - } - [self setContentSize:_updatingContentSize]; - [self updateVisibleItems]; - [self applyLayoutItems]; - - [_reloadedBeforeItems enumerateObjectsUsingBlock:^(MobilyViewElementsItem* item, NSUInteger index, BOOL* stop) { - MobilyViewElementsCell* cell = [item elementsCell]; - if(cell != nil) { - if(_elementsDelegateAnimationReloadBeforeElementsCell == YES) { - [_elementsDelegate elements:self animationReloadBeforeElementsCell:cell]; - } else { - [[cell layer] setZPosition:-1.0f]; - [cell setAlpha:0.0f]; - } - } - }]; - [_reloadedAfterItems enumerateObjectsUsingBlock:^(MobilyViewElementsItem* item, NSUInteger index, BOOL* stop) { - MobilyViewElementsCell* cell = [item elementsCell]; - if(cell != nil) { - if(_elementsDelegateAnimationReloadAfterElementsCell == YES) { - [_elementsDelegate elements:self animationReloadAfterElementsCell:cell]; - } else { - [UIView performWithoutAnimation:^{ - [cell setAlpha:0.0f]; - }]; - [[cell layer] setZPosition:1.0f]; - [cell setAlpha:1.0f]; - } - } - }]; - [_insertedItems enumerateObjectsUsingBlock:^(MobilyViewElementsItem* item, NSUInteger index, BOOL* stop) { - MobilyViewElementsCell* cell = [item elementsCell]; - if(cell != nil) { - if(_elementsDelegateAnimationInsertElementsCell == YES) { - [_elementsDelegate elements:self animationInsertElementsCell:cell]; - } else { - [UIView performWithoutAnimation:^{ - [cell setAlpha:0.0f]; - }]; - [[cell layer] setZPosition:-1.0f]; - [cell setAlpha:1.0f]; - } - } - }]; - [_deletedItems enumerateObjectsUsingBlock:^(MobilyViewElementsItem* item, NSUInteger index, BOOL* stop) { - MobilyViewElementsCell* cell = [item elementsCell]; - if(cell != nil) { - if(_elementsDelegateAnimationDeleteElementsCell == YES) { - [_elementsDelegate elements:self animationDeleteElementsCell:cell]; - } else { - [[cell layer] setZPosition:-1.0f]; - [cell setAlpha:0.0f]; - } - } - }]; - } - completion:^(BOOL finished) { - if([_reloadedBeforeItems count] > 0) { - [_reloadedBeforeItems enumerateObjectsUsingBlock:^(MobilyViewElementsItem* item, NSUInteger index, BOOL* stop) { - MobilyViewElementsCell* cell = [item elementsCell]; - if(cell != nil) { - [cell setElementsItem:nil]; - [cell removeFromSuperview]; - } - }]; - [_reloadedBeforeItems removeAllObjects]; - } - if([_reloadedAfterItems count] > 0) { - [_reloadedAfterItems removeAllObjects]; - } - if([_insertedItems count] > 0) { - [_insertedItems removeAllObjects]; - } - if([_deletedItems count] > 0) { - [_deletedItems enumerateObjectsUsingBlock:^(MobilyViewElementsItem* item, NSUInteger index, BOOL* stop) { - MobilyViewElementsCell* cell = [item elementsCell]; - if(cell != nil) { - [cell setElementsItem:nil]; - [cell removeFromSuperview]; - } - }]; - [_deletedItems removeAllObjects]; - } - [_items enumerateObjectsUsingBlock:^(MobilyViewElementsItem* item, NSUInteger elementsIndex, BOOL* stop) { - [item setInitialFrame:[item frame]]; - }]; - [self setUpdating:NO]; - [self updateVisibleItems]; - [self applyLayoutItems]; - - if(complete != nil) { - complete(finished); - } - }]; - } -} - -#pragma mark Property - -- (void)setElementsDataSource:(id< MobilyViewElementsDataSource >)elementsDataSource { - if(_elementsDataSource != elementsDataSource) { - _elementsDataSource = elementsDataSource; - } -} - -- (void)setElementsDelegate:(id< MobilyViewElementsDelegate >)elementsDelegate { - if(_elementsDelegate != elementsDelegate) { - _elementsDelegate = elementsDelegate; - - [self setElementsDelegateShowCellAtIndex:[_elementsDelegate respondsToSelector:@selector(elements:showCell:atIndex:)]]; - [self setElementsDelegateHideCellAtIndex:[_elementsDelegate respondsToSelector:@selector(elements:hideCell:atIndex:)]]; - [self setElementsDelegateShouldSelectItemAtIndex:[_elementsDelegate respondsToSelector:@selector(elements:shouldSelectItemAtIndex:)]]; - [self setElementsDelegateShouldDeselectItemAtIndex:[_elementsDelegate respondsToSelector:@selector(elements:shouldDeselectItemAtIndex:)]]; - [self setElementsDelegateDidSelectItemAtIndex:[_elementsDelegate respondsToSelector:@selector(elements:didSelectItemAtIndex:)]]; - [self setElementsDelegateDidDeselectItemAtIndex:[_elementsDelegate respondsToSelector:@selector(elements:didDeselectItemAtIndex:)]]; - [self setElementsDelegateAnimationReloadBeforeElementsCell:[_elementsDelegate respondsToSelector:@selector(elements:animationReloadBeforeElementsCell:)]]; - [self setElementsDelegateAnimationReloadAfterElementsCell:[_elementsDelegate respondsToSelector:@selector(elements:animationReloadAfterElementsCell:)]]; - [self setElementsDelegateAnimationInsertElementsCell:[_elementsDelegate respondsToSelector:@selector(elements:animationInsertElementsCell:)]]; - [self setElementsDelegateAnimationDeleteElementsCell:[_elementsDelegate respondsToSelector:@selector(elements:animationDeleteElementsCell:)]]; - } -} - -- (void)setElementsLayout:(id< MobilyViewElementsLayout >)elementsLayout { - if(_elementsLayout != elementsLayout) { - _elementsLayout = elementsLayout; - - [self setElementsLayoutItemsItemsSizeReloadRangeBeloadBeforeItemsReloadAfterItems:[_elementsLayout respondsToSelector:@selector(elements:layoutItems:itemsSize:reloadRange:reloadBeforeItems:reloadAfterItems:)]]; - [self setElementsLayoutItemsItemsSizeReloadIndexSet:[_elementsLayout respondsToSelector:@selector(elements:layoutItems:itemsSize:reloadIndexSet:)]]; - [self setElementsLayoutItemsItemsSizeInsertRangeInsertItems:[_elementsLayout respondsToSelector:@selector(elements:layoutItems:itemsSize:insertRange:insertItems:)]]; - [self setElementsLayoutItemsItemsSizeInsertIndexSet:[_elementsLayout respondsToSelector:@selector(elements:layoutItems:itemsSize:insertIndexSet:)]]; - [self setElementsLayoutItemsItemsSizeDeleteRangeDeleteItems:[_elementsLayout respondsToSelector:@selector(elements:layoutItems:itemsSize:deleteRange:deleteItems:)]]; - [self setElementsLayoutItemsItemsSizeDeleteIndexSet:[_elementsLayout respondsToSelector:@selector(elements:layoutItems:itemsSize:deleteIndexSet:)]]; - } -} - -- (void)setFrame:(CGRect)frame { - CGRect oldFrame = [self frame]; - BOOL isSizeChanged = (CGSizeEqualToSize(oldFrame.size, frame.size) == NO); - [super setFrame:frame]; - if(isSizeChanged == YES) { - if((_updating == NO) && ([_items count] > 0)) { - [self layoutItems]; - [self applyLayoutItems]; - } - } -} - -- (void)setBounds:(CGRect)bounds { - CGRect oldBounds = [self bounds]; - BOOL isSizeChanged = (CGSizeEqualToSize(oldBounds.size, bounds.size) == NO); - [super setBounds:bounds]; - if(isSizeChanged == YES) { - if((_updating == NO) && ([_items count] > 0)) { - [self layoutItems]; - [self applyLayoutItems]; - } - } -} - -- (NSIndexSet*)visibleIndexSet { - return [_mutableVisibleIndexSet copy]; -} - -- (NSArray*)visibleItems { - NSArray* result = [NSArray array]; - if([_items count] > 0) { - if([_mutableVisibleIndexSet count] > 0) { - result = [_items objectsAtIndexes:_mutableVisibleIndexSet]; - } - } - return result; -} - -- (NSArray*)visibleCells { - NSMutableArray* result = [NSMutableArray array]; - if([_items count] > 0) { - if([_mutableVisibleIndexSet count] > 0) { - [_items enumerateObjectsAtIndexes:_mutableVisibleIndexSet options:0 usingBlock:^(MobilyViewElementsItem* item, NSUInteger index, BOOL* stop) { - if([item elementsCell] != nil) { - [result addObject:[item elementsCell]]; - } - }]; - } - } - return [NSArray arrayWithArray:result]; -} - -- (NSIndexSet*)selectedIndexSet { - return [_mutableSelectedIndexSet copy]; -} - -- (NSUInteger)selectedIndex { - if([_mutableSelectedIndexSet count] > 0) { - return [_mutableSelectedIndexSet firstIndex]; - } - return NSNotFound; -} - -- (NSArray*)selectedItems { - NSArray* result = [NSArray array]; - if([_items count] > 0) { - result = [_items objectsAtIndexes:_mutableSelectedIndexSet]; - } - return result; -} - -- (NSArray*)selectedCells { - NSMutableArray* result = [NSMutableArray array]; - if(([_items count] > 0) && ([_mutableSelectedIndexSet count] > 0)) { - [_items enumerateObjectsAtIndexes:_mutableSelectedIndexSet options:0 usingBlock:^(MobilyViewElementsItem* item, NSUInteger index, BOOL* stop) { - if([item elementsCell] != nil) { - [result addObject:[item elementsCell]]; - } - }]; - } - return result; -} - -#pragma mark Private - -- (MobilyViewElementsCell*)dequeueCellWithElementsItem:(MobilyViewElementsItem*)item { - NSString* identifier = [item identifier]; - NSMutableArray* queue = [_queueCells objectForKey:identifier]; - __block MobilyViewElementsCell* cell = [queue lastObject]; - if(cell != nil) { - [queue removeLastObject]; - } else { - MobilyViewElementsRegisterCell* registerCell = [_registersCells objectForKey:identifier]; - if(registerCell != nil) { - Class cellClass = [registerCell cellClass]; - if(cellClass != nil) { - UINib* cellNib = [registerCell cellNib]; - if(cellNib != nil) { - NSArray* nibObjects = [cellNib instantiateWithOwner:self options:nil]; - [nibObjects enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL* stop) { - if([object isKindOfClass:cellClass] == YES) { - [object setElements:self]; - cell = object; - *stop = YES; - } - }]; - } else { - cell = [[cellClass alloc] initWithFrame:[item initialFrame]]; - if(cell != nil) { - [cell setElements:self]; - } - } - } - } - } - if(cell != nil) { - [self insertSubview:cell atIndex:0]; - [cell setElementsItem:item]; - if(_elementsDelegateShowCellAtIndex == YES) { - [_elementsDelegate elements:self showCell:cell atIndex:[item index]]; - } - } - return cell; -} - -- (void)enqueueCellWithElementsItem:(MobilyViewElementsItem*)item { - MobilyViewElementsCell* cell = [item elementsCell]; - if(cell != nil) { - NSMutableArray* queue = [_queueCells objectForKey:[item identifier]]; - if(queue == nil) { - [_queueCells setObject:[NSMutableArray arrayWithObject:cell] forKey:[item identifier]]; - } else { - [queue addObject:cell]; - } - if(_elementsDelegateHideCellAtIndex == YES) { - [_elementsDelegate elements:self hideCell:cell atIndex:[item index]]; - } - [cell setElementsItem:nil]; - [cell removeFromSuperview]; - } -} - -- (void)layoutItems { - if(_elementsLayout != nil) { - [self setContentSize:[_elementsLayout elements:self layoutItems:_items]]; - } else { - @throw [NSException exceptionWithName:NSStringFromClass([self class]) reason:@"Not assigned layout" userInfo:nil]; - } -} - -- (void)applyLayoutItems { - [_items enumerateObjectsUsingBlock:^(MobilyViewElementsItem* item, NSUInteger index, BOOL* stop) { - MobilyViewElementsCell* cell = [item elementsCell]; - if(cell != nil) { - [cell setFrame:[item frame]]; - } - }]; -} - -- (void)updateVisibleItems { - CGRect visibleRect = [self bounds]; - - if(_updating == NO) { - [_mutableVisibleIndexSet removeIndexesInRange:NSMakeRange([_items count] - 1, INT_MAX)]; - [_items enumerateObjectsAtIndexes:_mutableVisibleIndexSet options:0 usingBlock:^(MobilyViewElementsItem* item, NSUInteger index, BOOL* stop) { - if(CGRectIntersectsRect([item frame], visibleRect) == NO) { - [self enqueueCellWithElementsItem:item]; - [_mutableVisibleIndexSet removeIndex:index]; - } - }]; - } - [_items enumerateObjectsUsingBlock:^(MobilyViewElementsItem* item, NSUInteger index, BOOL* stop) { - CGRect itemUnionFrame = CGRectUnion([item initialFrame], [item frame]); - if(CGRectIntersectsRect(visibleRect, itemUnionFrame) == YES) { - if([item elementsCell] == nil) { - [_mutableVisibleIndexSet addIndex:index]; - [self dequeueCellWithElementsItem:item]; - } - } - }]; -} - -- (void)selectItemAtIndex:(NSUInteger)index animated:(BOOL)animated user:(BOOL)user { - if(index >= [_items count]) { - return; - } - if([_mutableSelectedIndexSet containsIndex:index] == NO) { - if(_allowsMultipleSelection == YES) { - if([self shouldSelectItemAtIndex:index] == YES) { - [_mutableSelectedIndexSet addIndex:index]; - MobilyViewElementsItem* item = [_items objectAtIndex:index]; - [item setSelected:YES]; - MobilyViewElementsCell* cell = [item elementsCell]; - if(cell != nil) { - [cell setSelected:YES animated:animated]; - } - if((user == YES) && (_elementsDelegateDidSelectItemAtIndex == YES)) { - [_elementsDelegate elements:self didSelectItemAtIndex:index]; - } - } - } else { - if([self shouldSelectItemAtIndex:index] == YES) { - if([_mutableSelectedIndexSet count] > 0) { - [_items enumerateObjectsAtIndexes:_mutableSelectedIndexSet options:0 usingBlock:^(MobilyViewElementsItem* item, NSUInteger elementsIndex, BOOL* stop) { - [item setSelected:NO]; - MobilyViewElementsCell* cell = [item elementsCell]; - if(cell != nil) { - [cell setSelected:NO animated:animated]; - } - }]; - [_mutableSelectedIndexSet removeAllIndexes]; - } - [_mutableSelectedIndexSet addIndex:index]; - MobilyViewElementsItem* item = [_items objectAtIndex:index]; - [item setSelected:YES]; - MobilyViewElementsCell* cell = [item elementsCell]; - if(cell != nil) { - [cell setSelected:YES animated:animated]; - } - if((user == YES) && (_elementsDelegateDidSelectItemAtIndex == YES)) { - [_elementsDelegate elements:self didSelectItemAtIndex:index]; - } - } - } - } -} - -- (void)deselectItemAtIndex:(NSUInteger)index animated:(BOOL)animated user:(BOOL)user { - if(index >= [_items count]) { - return; - } - if([_mutableSelectedIndexSet containsIndex:index] == YES) { - if([self shouldDeselectItemAtIndex:index] == YES) { - [_mutableSelectedIndexSet removeIndex:index]; - MobilyViewElementsItem* item = [_items objectAtIndex:index]; - [item setSelected:NO]; - MobilyViewElementsCell* cell = [item elementsCell]; - if(cell != nil) { - [cell setSelected:NO animated:animated]; - } - if((user == YES) && (_elementsDelegateDidDeselectItemAtIndex == YES)) { - [_elementsDelegate elements:self didDeselectItemAtIndex:index]; - } - } - } -} - -- (void)selectItemAtElementsCell:(MobilyViewElementsCell*)cell animated:(BOOL)animated { - if(_allowsSelection == YES) { - NSUInteger elementIndex = [[cell elementsItem] index]; - if([_mutableSelectedIndexSet containsIndex:elementIndex] == NO) { - [self selectItemAtIndex:elementIndex animated:animated user:YES]; - } else { - [self deselectItemAtIndex:elementIndex animated:animated user:YES]; - } - } -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyViewElementsCell - -@synthesize objectName = _objectName; -@synthesize objectParent = _objectParent; -@synthesize objectChilds = _objectChilds; - -#pragma mark Standart - -- (id)initWithCoder:(NSCoder*)coder { - self = [super initWithCoder:coder]; - if(self != nil) { - [self setup]; - } - return self; -} - -- (id)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if(self != nil) { - [self setup]; - } - return self; -} - -- (void)setup { - [self addTarget:self action:@selector(actionTouchUpInside:) forControlEvents:UIControlEventTouchUpInside]; -} - -- (void)dealloc { - [self setObjectName:nil]; - [self setObjectParent:nil]; - [self setObjectChilds:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark MobilyBuilderObject - -- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIView class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andAddingObject:objectChild]]; - [self addSubview:(UIView*)objectChild]; - } -} - -- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIView class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andRemovingObject:objectChild]]; - [self removeSubview:(UIView*)objectChild]; - } -} - -- (void)willLoadObjectChilds { -} - -- (void)didLoadObjectChilds { -} - -- (id< MobilyBuilderObject >)objectForName:(NSString*)name { - return [MobilyBuilderForm object:self forName:name]; -} - -- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { - return [MobilyBuilderForm object:self forSelector:selector]; -} - -#pragma mark Public - -- (void)prepareItem:(MobilyViewElementsItem*)item { -} - -- (void)updatingItem:(MobilyViewElementsItem*)item animated:(BOOL)animated { -} - -- (void)cleanupItem:(MobilyViewElementsItem*)item { -} - -#pragma mark Property - -- (void)setSelected:(BOOL)selected { - [self setSelected:selected animated:NO]; -} - -- (void)setHighlighted:(BOOL)highlighted { - [self setHighlighted:highlighted animated:NO]; -} - -- (void)setSelected:(BOOL)selected animated:(BOOL)animated { - if([self isSelected] != selected) { - [super setSelected:selected]; - [self updatingItem:_elementsItem animated:animated]; - } -} - -- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated { - if([self isHighlighted] != highlighted) { - [super setHighlighted:highlighted]; - [self updatingItem:_elementsItem animated:animated]; - } -} - -- (void)setElementsItem:(MobilyViewElementsItem*)elementsItem { - if(_elementsItem != elementsItem) { - if(_elementsItem != nil) { - [UIView performWithoutAnimation:^{ - [self cleanupItem:_elementsItem]; - }]; - [_elementsItem setElementsCell:nil]; - } - _elementsItem = elementsItem; - if(_elementsItem != nil) { - [_elementsItem setElementsCell:self]; - - [UIView performWithoutAnimation:^{ - [[self layer] setZPosition:[_elementsItem zIndex]]; - [self setFrame:[_elementsItem initialFrame]]; - [self setSelected:[_elementsItem isSelected]]; - [self prepareItem:_elementsItem]; - }]; - } - } -} - -#pragma mark Action - -- (void)actionTouchUpInside:(id)sender { - if(self == sender) { - [_elements selectItemAtElementsCell:self animated:YES]; - } -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyViewElementsItem - -#pragma mark Standart - -- (id)initWithElements:(MobilyViewElements*)elements { - self = [super init]; - if(self != nil) { - [self setElements:elements]; - } - return self; -} - -- (void)dealloc { - [self setElementsCell:nil]; - [self setElements:nil]; - [self setIdentifier:nil]; -} - -#pragma mark Property - -- (void)setInitialFrameOrigin:(CGPoint)initialFrameOrigin { - [self setInitialFrame:CGRectMake(initialFrameOrigin.x, initialFrameOrigin.y, _frame.size.width, _frame.size.height)]; -} - -- (CGPoint)initialFrameOrigin { - return _initialFrame.origin; -} - -- (void)setInitialFrameOriginX:(CGFloat)initialFrameOriginX { - [self setInitialFrame:CGRectMake(initialFrameOriginX, _initialFrame.origin.y, _initialFrame.size.width, _initialFrame.size.height)]; -} - -- (CGFloat)initialFrameOriginX { - return _initialFrame.origin.x; -} - -- (void)setInitialFrameOriginY:(CGFloat)initialFrameOriginY { - [self setInitialFrame:CGRectMake(_initialFrame.origin.x, initialFrameOriginY, _initialFrame.size.width, _initialFrame.size.height)]; -} - -- (CGFloat)initialFrameOriginY { - return _initialFrame.origin.y; -} - -- (void)setInitialFrameSize:(CGSize)initialFrameSize { - [self setInitialFrame:CGRectMake(_initialFrame.origin.x, _initialFrame.origin.y, initialFrameSize.width, initialFrameSize.height)]; -} - -- (CGSize)initialFrameSize { - return _initialFrame.size; -} - -- (void)setInitialFrameSizeWidth:(CGFloat)initialFrameSizeWidth { - [self setInitialFrame:CGRectMake(_initialFrame.origin.x, _initialFrame.origin.y, initialFrameSizeWidth, _initialFrame.size.height)]; -} - -- (CGFloat)initialFrameSizeWidth { - return _initialFrame.size.width; -} - -- (void)setInitialFrameSizeHeight:(CGFloat)initialFrameSizeHeight { - [self setInitialFrame:CGRectMake(_initialFrame.origin.x, _initialFrame.origin.y, _initialFrame.size.width, initialFrameSizeHeight)]; -} - -- (CGFloat)initialFrameSizeHeight { - return _initialFrame.size.height; -} - -- (void)setFrameOrigin:(CGPoint)frameOrigin { - [self setFrame:CGRectMake(frameOrigin.x, frameOrigin.y, _frame.size.width, _frame.size.height)]; -} - -- (CGPoint)frameOrigin { - return _frame.origin; -} - -- (void)setFrameOriginX:(CGFloat)afterFrameOriginX { - [self setFrame:CGRectMake(afterFrameOriginX, _frame.origin.y, _frame.size.width, _frame.size.height)]; -} - -- (CGFloat)frameOriginX { - return _frame.origin.x; -} - -- (void)setFrameOriginY:(CGFloat)afterFrameOriginY { - [self setFrame:CGRectMake(_frame.origin.x, afterFrameOriginY, _frame.size.width, _frame.size.height)]; -} - -- (CGFloat)frameOriginY { - return _frame.origin.y; -} - -- (void)setFrameSize:(CGSize)frameSize { - [self setFrame:CGRectMake(_frame.origin.x, _frame.origin.y, frameSize.width, frameSize.height)]; -} - -- (CGSize)frameSize { - return _frame.size; -} - -- (void)setFrameSizeWidth:(CGFloat)afterFrameSizeWidth { - [self setFrame:CGRectMake(_frame.origin.x, _frame.origin.y, afterFrameSizeWidth, _frame.size.height)]; -} - -- (CGFloat)frameSizeWidth { - return _frame.size.width; -} - -- (void)setFrameSizeHeight:(CGFloat)frameSizeHeight { - [self setFrame:CGRectMake(_frame.origin.x, _frame.origin.y, _frame.size.width, frameSizeHeight)]; -} - -- (CGFloat)frameSizeHeight { - return _frame.size.height; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyViewElementsRegisterCell - -#pragma mark Standart - -- (id)initWithCellClass:(Class)cellClass { - self = [super init]; - if(self != nil) { - [self setCellClass:cellClass]; - } - return self; -} - -- (id)initWithCellClass:(Class)cellClass cellNib:(UINib*)cellNib { - self = [super init]; - if(self != nil) { - [self setCellClass:cellClass]; - [self setCellNib:cellNib]; - } - return self; -} - -- (void)dealloc { - [self setCellClass:nil]; - [self setCellNib:nil]; -} - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/UI/ViewElements/MobilyViewElementsLayout.m b/Classes/UI/ViewElements/MobilyViewElementsLayout.m deleted file mode 100644 index 234ace6..0000000 --- a/Classes/UI/ViewElements/MobilyViewElementsLayout.m +++ /dev/null @@ -1,342 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyViewElementsLayout.h" - -/*--------------------------------------------------*/ - -@implementation MobilyViewElementsLayoutList - -- (id)init { - self = [super init]; - if(self != nil) { - [self setMargin:2.0f]; - [self setSpacing:2.0f]; - } - return self; -} - -- (void)dealloc { - MOBILY_SAFE_DEALLOC; -} - -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems { - return CGSizeZero; -} - -@end - -/*--------------------------------------------------*/ - -@implementation MobilyViewElementsLayoutListVertical - -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems { - CGRect bounds = [elements bounds]; - CGFloat margin = [self margin]; - CGFloat spacing = [self spacing]; - - __block CGFloat offset = margin; - if([layoutItems count] > 0) { - [layoutItems enumerateObjectsUsingBlock:^(MobilyViewElementsItem* layoutItem, NSUInteger elementsIndex, BOOL* stop) { - [layoutItem setInitialFrameOrigin:CGPointMake(margin, offset)]; - [layoutItem setInitialFrameSizeWidth:bounds.size.width - (margin + margin)]; - [layoutItem setFrame:[layoutItem initialFrame]]; - offset += [layoutItem initialFrameSizeHeight] + spacing; - }]; - offset -= spacing; - } - offset += margin; - return CGSizeMake(bounds.size.width, offset); -} - -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems itemsSize:(CGSize)itemsSize insertRange:(NSRange)insertRange insertItems:(NSArray*)insertItems { - CGRect bounds = [elements bounds]; - CGFloat margin = [self margin]; - CGFloat spacing = [self spacing]; - - __block CGFloat insertItemsOffset = 0.0f; - if(insertRange.location > 0) { - MobilyViewElementsItem* layoutItem = [layoutItems objectAtIndex:(insertRange.location - 1)]; - insertItemsOffset = ([layoutItem frameOriginY] + [layoutItem frameSizeHeight]) + spacing; - } - __block CGFloat insertItemsSize = 0.0f; - [insertItems enumerateObjectsUsingBlock:^(MobilyViewElementsItem* layoutItem, NSUInteger elementsIndex, BOOL* stop) { - [layoutItem setInitialFrameOrigin:CGPointMake(margin, insertItemsOffset)]; - [layoutItem setInitialFrameSizeWidth:bounds.size.width - (margin + margin)]; - [layoutItem setFrame:[layoutItem initialFrame]]; - insertItemsOffset += [layoutItem frameSizeHeight] + spacing; - insertItemsSize += [layoutItem frameSizeHeight] + spacing; - }]; - NSUInteger index = insertRange.location + insertRange.length; - NSUInteger count = [layoutItems count] - index; - [layoutItems enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, count)] options:0 usingBlock:^(MobilyViewElementsItem* layoutItem, NSUInteger elementsIndex, BOOL* stop) { - [layoutItem setFrameOriginY:[layoutItem frameOriginY] + insertItemsSize]; - }]; - return CGSizeMake(itemsSize.width, itemsSize.height + insertItemsSize); -} - -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems itemsSize:(CGSize)itemsSize deleteRange:(NSRange)deleteRange deleteItems:(NSArray*)deleteItems { - CGFloat spacing = [self spacing]; - - __block CGFloat deleteItemsSize = 0.0f; - if([deleteItems count] > 0) { - [deleteItems enumerateObjectsUsingBlock:^(MobilyViewElementsItem* layoutItem, NSUInteger elementsIndex, BOOL* stop) { - deleteItemsSize += [layoutItem frameSizeHeight] + spacing; - }]; - } - NSUInteger index = deleteRange.location + deleteRange.length; - NSUInteger count = [layoutItems count] - index; - [layoutItems enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, count)] options:0 usingBlock:^(MobilyViewElementsItem* layoutItem, NSUInteger elementsIndex, BOOL* stop) { - [layoutItem setFrameOriginY:[layoutItem frameOriginY] - deleteItemsSize]; - }]; - return CGSizeMake(itemsSize.width, itemsSize.height - deleteItemsSize); -} - -@end - -/*--------------------------------------------------*/ - -@implementation MobilyViewElementsLayoutListHorizontal - -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems { - CGRect bounds = [elements bounds]; - CGFloat margin = [self margin]; - CGFloat margin2 = margin + margin; - CGFloat spacing = [self spacing]; - - __block CGFloat offset = margin; - if([layoutItems count] > 0) { - [layoutItems enumerateObjectsUsingBlock:^(MobilyViewElementsItem* layoutItem, NSUInteger elementsIndex, BOOL* stop) { - [layoutItem setInitialFrameOrigin:CGPointMake(offset, margin)]; - [layoutItem setInitialFrameSizeHeight:bounds.size.height - (margin2)]; - [layoutItem setFrame:[layoutItem initialFrame]]; - offset += [layoutItem initialFrameSizeWidth] + spacing; - }]; - offset -= spacing; - } - offset += margin; - return CGSizeMake(offset, bounds.size.height); -} - -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems itemsSize:(CGSize)itemsSize insertRange:(NSRange)insertRange insertItems:(NSArray*)insertItems { - CGRect bounds = [elements bounds]; - CGFloat margin = [self margin]; - CGFloat spacing = [self spacing]; - - __block CGFloat insertItemsOffset = 0.0f; - if(insertRange.location > 0) { - MobilyViewElementsItem* layoutItem = [layoutItems objectAtIndex:(insertRange.location - 1)]; - insertItemsOffset = ([layoutItem frameOriginX] + [layoutItem frameSizeWidth]) + spacing; - } - __block CGFloat insertItemsSize = 0.0f; - [insertItems enumerateObjectsUsingBlock:^(MobilyViewElementsItem* layoutItem, NSUInteger elementsIndex, BOOL* stop) { - [layoutItem setInitialFrameOrigin:CGPointMake(insertItemsOffset, margin)]; - [layoutItem setInitialFrameSizeHeight:bounds.size.height - (margin + margin)]; - [layoutItem setFrame:[layoutItem initialFrame]]; - insertItemsOffset += [layoutItem frameSizeWidth] + spacing; - insertItemsSize += [layoutItem frameSizeWidth] + spacing; - }]; - NSUInteger index = insertRange.location + insertRange.length; - NSUInteger count = [layoutItems count] - index; - [layoutItems enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, count)] options:0 usingBlock:^(MobilyViewElementsItem* layoutItem, NSUInteger elementsIndex, BOOL* stop) { - [layoutItem setFrameOriginX:[layoutItem frameOriginX] + insertItemsSize]; - }]; - return CGSizeMake(itemsSize.width + insertItemsSize, itemsSize.height); -} - -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems itemsSize:(CGSize)itemsSize deleteRange:(NSRange)deleteRange deleteItems:(NSArray*)deleteItems { - CGFloat spacing = [self spacing]; - - __block CGFloat deleteItemsSize = 0.0f; - if([deleteItems count] > 0) { - [deleteItems enumerateObjectsUsingBlock:^(MobilyViewElementsItem* layoutItem, NSUInteger elementsIndex, BOOL* stop) { - deleteItemsSize += [layoutItem frameSizeWidth] + spacing; - }]; - } - NSUInteger index = deleteRange.location + deleteRange.length; - NSUInteger count = [layoutItems count] - index; - [layoutItems enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, count)] options:0 usingBlock:^(MobilyViewElementsItem* layoutItem, NSUInteger elementsIndex, BOOL* stop) { - [layoutItem setFrameOriginX:[layoutItem frameOriginX] - deleteItemsSize]; - }]; - return CGSizeMake(itemsSize.width - deleteItemsSize, itemsSize.height); -} - -@end - -/*--------------------------------------------------*/ - -@implementation MobilyViewElementsLayoutGrid - -- (id)init { - self = [super init]; - if(self != nil) { - [self setMargin:CGSizeMake(2.0f, 2.0f)]; - [self setSpacing:CGSizeMake(2.0f, 2.0f)]; - } - return self; -} - -- (void)dealloc { - MOBILY_SAFE_DEALLOC; -} - -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems { - return CGSizeZero; -} - -@end - -/*--------------------------------------------------*/ - -@implementation MobilyViewElementsLayoutGridVertical - -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems { - CGRect bounds = [elements bounds]; - CGSize margin = [self margin]; - CGSize spacing = [self spacing]; - - __block CGPoint offset = CGPointMake(margin.width, margin.height); - __block CGSize size = CGSizeMake(margin.width + margin.width, margin.height + margin.height); - if([layoutItems count] > 0) { - __block CGSize rowSize = CGSizeZero; - NSMutableArray* rowItems = [NSMutableArray array]; - [layoutItems enumerateObjectsUsingBlock:^(MobilyViewElementsItem* layoutItem, NSUInteger elementsIndex, BOOL* stop) { - CGSize elementsItemSize = [layoutItem initialFrameSize]; - if([rowItems count] > 0) { - if(offset.x + elementsItemSize.width > (bounds.origin.x + bounds.size.width) - margin.width) { - offset.x = margin.width; - offset.y += rowSize.height + spacing.height; - size.width = MAX(size.width, margin.width + rowSize.width + margin.width); - size.height += rowSize.height + spacing.height; - - [rowItems removeAllObjects]; - rowSize = CGSizeZero; - } - } - [layoutItem setInitialFrameOrigin:offset]; - [layoutItem setFrame:[layoutItem initialFrame]]; - offset.x += elementsItemSize.width + spacing.width; - rowSize.width += elementsItemSize.width + spacing.width; - rowSize.height = MAX(elementsItemSize.height, rowSize.height); - [rowItems addObject:layoutItem]; - }]; - size.width = MAX(size.width, margin.width + rowSize.width + margin.width); - size.height += rowSize.height + spacing.height; - } - return size; -} - -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems itemsSize:(CGSize)itemsSize deleteRange:(NSRange)deleteRange deleteItems:(NSArray*)deleteItems { - CGRect bounds = [elements bounds]; - CGSize margin = [self margin]; - CGSize spacing = [self spacing]; - - __block CGPoint offset = CGPointMake(margin.width, margin.height); - __block CGSize size = CGSizeMake(margin.width + margin.width, margin.height + margin.height); - if([layoutItems count] > 0) { - __block CGSize rowSize = CGSizeZero; - NSMutableArray* rowItems = [NSMutableArray array]; - [layoutItems enumerateObjectsUsingBlock:^(MobilyViewElementsItem* layoutItem, NSUInteger elementsIndex, BOOL* stop) { - if(NSLocationInRange(elementsIndex, deleteRange) == NO) { - CGSize elementsItemSize = [layoutItem frameSize]; - if([rowItems count] > 0) { - if(offset.x + elementsItemSize.width > (bounds.origin.x + bounds.size.width) - margin.width) { - offset.x = margin.width; - offset.y += rowSize.height + spacing.height; - size.width = MAX(size.width, margin.width + rowSize.width + margin.width); - size.height += rowSize.height + spacing.height; - - [rowItems removeAllObjects]; - rowSize = CGSizeZero; - } - } - [layoutItem setFrameOrigin:offset]; - offset.x += elementsItemSize.width + spacing.width; - rowSize.width += elementsItemSize.width + spacing.width; - rowSize.height = MAX(elementsItemSize.height, rowSize.height); - [rowItems addObject:layoutItem]; - } - }]; - size.width = MAX(size.width, margin.width + rowSize.width + margin.width); - size.height += rowSize.height + spacing.height; - } - return size; -} - -@end - -/*--------------------------------------------------*/ - -@implementation MobilyViewElementsLayoutGridHorizontal - -- (CGSize)elements:(MobilyViewElements*)elements layoutItems:(NSArray*)layoutItems { - CGRect bounds = [elements bounds]; - CGSize margin = [self margin]; - CGSize spacing = [self spacing]; - - __block CGPoint offset = CGPointMake(margin.width, margin.height); - __block CGSize size = CGSizeMake(margin.width + margin.width, margin.height + margin.height); - if([layoutItems count] > 0) { - __block CGSize rowSize = CGSizeZero; - NSMutableArray* rowItems = [NSMutableArray array]; - [layoutItems enumerateObjectsUsingBlock:^(MobilyViewElementsItem* layoutItem, NSUInteger elementsIndex, BOOL* stop) { - CGSize elementsItemSize = [layoutItem initialFrameSize]; - if([rowItems count] > 0) { - if(offset.y + elementsItemSize.height > (bounds.origin.y + bounds.size.height) - margin.height) { - offset.x += rowSize.width + spacing.width; - offset.y = margin.height; - size.width += rowSize.width + spacing.width; - size.height = MAX(size.height, margin.height + rowSize.height + margin.height); - - [rowItems removeAllObjects]; - rowSize = CGSizeZero; - } - } - [layoutItem setInitialFrameOrigin:offset]; - [layoutItem setFrame:[layoutItem initialFrame]]; - offset.y += elementsItemSize.height + spacing.height; - rowSize.width = MAX(elementsItemSize.width, rowSize.width); - rowSize.height += elementsItemSize.height + spacing.height; - [rowItems addObject:layoutItem]; - }]; - size.width += rowSize.width + spacing.width; - size.height = MAX(size.height, margin.height + rowSize.height + margin.height); - } - return size; -} - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/UI/ViewFieldText/MobilyViewFieldText.m b/Classes/UI/ViewFieldText/MobilyViewFieldText.m deleted file mode 100644 index 242ae3f..0000000 --- a/Classes/UI/ViewFieldText/MobilyViewFieldText.m +++ /dev/null @@ -1,216 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyViewFieldText.h" - -/*--------------------------------------------------*/ - -#define MOBILY_DURATION 0.2f -#define MOBILY_TOOLBAR_HEIGHT 44.0f - -/*--------------------------------------------------*/ - -@interface MobilyViewFieldText () - -@property(nonatomic, readwrite, weak) UIResponder* prevInputResponder; -@property(nonatomic, readwrite, weak) UIResponder* nextInputResponder; - -- (void)pressedPrev; -- (void)pressedNext; -- (void)pressedDone; - -@end - -/*--------------------------------------------------*/ - -@implementation MobilyViewFieldText - -@synthesize objectName = _objectName; -@synthesize objectParent = _objectParent; -@synthesize objectChilds = _objectChilds; - -#pragma mark NSKeyValueCoding - -#pragma mark Standart - -- (id)initWithCoder:(NSCoder*)coder { - self = [super initWithCoder:coder]; - if(self != nil) { - [self setupView]; - } - return self; -} - -- (id)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if(self != nil) { - [self setupView]; - } - return self; -} - -- (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self]; - - [self setObjectName:nil]; - [self setObjectParent:nil]; - [self setObjectChilds:nil]; - - [self setToolbar:nil]; - [self setPrevButton:nil]; - [self setNextButton:nil]; - [self setFlexButton:nil]; - [self setDoneButton:nil]; - - [self setPrevInputResponder:nil]; - [self setNextInputResponder:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark MobilyBuilderObject - -- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIView class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andAddingObject:objectChild]]; - [self addSubview:(UIView*)objectChild]; - } -} - -- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIView class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andRemovingObject:objectChild]]; - [self removeSubview:(UIView*)objectChild]; - } -} - -- (void)willLoadObjectChilds { -} - -- (void)didLoadObjectChilds { -} - -- (id< MobilyBuilderObject >)objectForName:(NSString*)name { - return [MobilyBuilderForm object:self forName:name]; -} - -- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { - return [MobilyBuilderForm object:self forSelector:selector]; -} - -#pragma mark Property - -- (void)setHiddenToolbar:(BOOL)hiddenToolbar { - [self setHiddenToolbar:hiddenToolbar animated:NO]; -} - -#pragma mark Public - -- (void)setupView { - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didBeginEditing) name:UITextFieldTextDidBeginEditingNotification object:self]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEndEditing) name:UITextFieldTextDidEndEditingNotification object:self]; -} - -- (void)setHiddenToolbar:(BOOL)hiddenToolbar animated:(BOOL)animated { - if(_hiddenToolbar != hiddenToolbar) { - _hiddenToolbar = hiddenToolbar; - - if([self isEditing] == YES) { - CGFloat toolbarHeight = (_hiddenToolbar == NO) ? MOBILY_TOOLBAR_HEIGHT : 0.0f; - if(animated == YES) { - [UIView animateWithDuration:MOBILY_DURATION - animations:^{ - [_toolbar setFrameHeight:toolbarHeight]; - }]; - } else { - [_toolbar setFrameHeight:toolbarHeight]; - } - } - } -} - -- (void)didBeginEditing { - if(_toolbar == nil) { - CGRect windowBounds = [[self window] bounds]; - [self setToolbar:[[UIToolbar alloc] initWithFrame:CGRectMake(windowBounds.origin.x, windowBounds.origin.y, windowBounds.size.width, MOBILY_TOOLBAR_HEIGHT)]]; - if(_toolbar != nil) { - [self setPrevButton:[[UIBarButtonItem alloc] initWithTitle:@"<" style:UIBarButtonItemStyleBordered target:self action:@selector(pressedPrev)]]; - [self setNextButton:[[UIBarButtonItem alloc] initWithTitle:@">" style:UIBarButtonItemStyleBordered target:self action:@selector(pressedNext)]]; - [self setFlexButton:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]]; - [self setDoneButton:[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(pressedDone)]]; - - [_toolbar setItems:@[_prevButton, _nextButton, _flexButton, _doneButton]]; - [_toolbar setBarStyle:UIBarStyleDefault]; - [_toolbar setClipsToBounds:YES]; - } - } - if(_toolbar != nil) { - _prevInputResponder = [UIResponder prevResponderFromView:self]; - _nextInputResponder = [UIResponder nextResponderFromView:self]; - [_prevButton setEnabled:(_prevInputResponder != nil)]; - [_nextButton setEnabled:(_nextInputResponder != nil)]; - - [_toolbar setFrameHeight:(_hiddenToolbar == NO) ? MOBILY_TOOLBAR_HEIGHT : 0.0f]; - [self setInputAccessoryView:_toolbar]; - } -} - -- (void)didEndEditing { - _prevInputResponder = nil; - _nextInputResponder = nil; -} - -#pragma mark Private - -- (void)pressedPrev { - if(_prevInputResponder != nil) { - [_prevInputResponder becomeFirstResponder]; - } -} - -- (void)pressedNext { - if(_nextInputResponder != nil) { - [_nextInputResponder becomeFirstResponder]; - } -} - -- (void)pressedDone { - [self resignFirstResponder]; -} - - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/UI/ViewImage/MobilyViewImage.m b/Classes/UI/ViewImage/MobilyViewImage.m deleted file mode 100644 index bf7ac3f..0000000 --- a/Classes/UI/ViewImage/MobilyViewImage.m +++ /dev/null @@ -1,529 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "MobilyViewImage.h" -#import "MobilyTaskManager.h" - -/*--------------------------------------------------*/ - -typedef void (^MobilyImageLoaderBlock)(); - -/*--------------------------------------------------*/ - -@interface MobilyImageLoader () - -@property(nonatomic, readwrite, strong) MobilyTaskManager* taskManager; -@property(nonatomic, readwrite, strong) NSCache* cache; - -+ (MobilyImageLoader*)shared; - -- (NSString*)cacheKeyByImageUrl:(NSString*)imageUrl; - -- (BOOL)isExistImageWithImageUrl:(NSString*)imageUrl; -- (BOOL)isExistImageWithCacheKey:(NSString*)cacheKey; -- (UIImage*)imageWithImageUrl:(NSString*)imageUrl; -- (UIImage*)imageWithCacheKey:(NSString*)cacheKey; -- (void)addImageData:(NSData*)imageData byImageUrl:(NSString*)imageUrl; -- (void)addImageData:(NSData*)imageData byCacheKey:(NSString*)cacheKey; -- (void)removeByImageUrl:(NSString*)imageUrl; -- (void)removeByCacheKey:(NSString*)cacheKey; -- (void)cleanup; - -- (void)loadWithImageUrl:(NSString*)imageUrl target:(id)target completeSelector:(SEL)completeSelector failureSelector:(SEL)failureSelector; -- (void)loadWithImageUrl:(NSString*)imageUrl target:(id)target completeBlock:(MobilyImageLoaderCompleteBlock)completeBlock failureBlock:(MobilyImageLoaderFailureBlock)failureBlock; -- (void)cancelByImageUrl:(NSString*)imageUrl; -- (void)cancelByTarget:(id)target; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@interface MobilyTaskImageLoader : MobilyTask - -@property(nonatomic, readwrite, weak) MobilyImageLoader* imageLoader; -@property(nonatomic, readwrite, strong) id target; -@property(nonatomic, readwrite, strong) NSString* imageUrl; -@property(nonatomic, readwrite, strong) NSString* cacheKey; -@property(nonatomic, readwrite, strong) UIImage* image; -@property(nonatomic, readwrite, assign) NSUInteger countErrors; -@property(nonatomic, readwrite, strong) id< MobilyEvent > completeEvent; -@property(nonatomic, readwrite, strong) id< MobilyEvent > failureEvent; - -- (id)initWithImageUrl:(NSString*)imageUrl cacheKey:(NSString*)cacheKey target:(id)target; -- (id)initWithImageUrl:(NSString*)imageUrl cacheKey:(NSString*)cacheKey target:(id)target completeSelector:(SEL)completeSelector failureSelector:(SEL)failureSelector; -- (id)initWithImageUrl:(NSString*)imageUrl cacheKey:(NSString*)cacheKey target:(id)target completeBlock:(MobilyImageLoaderCompleteBlock)completeBlock failureBlock:(MobilyImageLoaderFailureBlock)failureBlock; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyViewImage - -@synthesize objectName = _objectName; -@synthesize objectParent = _objectParent; -@synthesize objectChilds = _objectChilds; - -#pragma mark NSKeyValueCoding - -#pragma mark Standart - -- (id)initWithCoder:(NSCoder*)coder { - self = [super initWithCoder:coder]; - if(self != nil) { - [self setupView]; - } - return self; -} - -- (id)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if(self != nil) { - [self setupView]; - } - return self; -} - -- (void)dealloc { - [self setObjectName:nil]; - [self setObjectParent:nil]; - [self setObjectChilds:nil]; - - [self setDefaultImage:nil]; - [self setImageUrl:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark MobilyBuilderObject - -- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIView class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andAddingObject:objectChild]]; - [self addSubview:(UIView*)objectChild]; - } -} - -- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIView class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andRemovingObject:objectChild]]; - [self removeSubview:(UIView*)objectChild]; - } -} - -- (void)willLoadObjectChilds { -} - -- (void)didLoadObjectChilds { -} - -- (id< MobilyBuilderObject >)objectForName:(NSString*)name { - return [MobilyBuilderForm object:self forName:name]; -} - -- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { - return [MobilyBuilderForm object:self forSelector:selector]; -} - -#pragma mark Public - -- (void)setupView { - [[self layer] setMasksToBounds:YES]; -} - -#pragma mark Property - -- (void)setImage:(UIImage*)image { - if(image == nil) { - image = _defaultImage; - } - [super setImage:image]; -} - -- (void)setImageUrl:(NSString*)imageUrl { - [self setImageUrl:imageUrl complete:nil failure:nil]; -} - -- (void)setImageUrl:(NSString*)imageUrl complete:(MobilyImageLoaderCompleteBlock)complete failure:(MobilyImageLoaderFailureBlock)failure { - if([_imageUrl isEqualToString:imageUrl] == NO) { - if(_imageUrl != nil) { - [MobilyImageLoader cancelByTarget:self]; - } - _imageUrl = imageUrl; - [super setImage:_defaultImage]; - [MobilyImageLoader loadWithImageUrl:_imageUrl target:self completeBlock:^(UIImage* image, NSString* imageUrl) { - [super setImage:image]; - if(complete != nil) { - complete(image, imageUrl); - } - } failureBlock:failure]; - } else { - if(complete != nil) { - complete([self image], imageUrl); - } - } -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -static MobilyImageLoader* MOBILY_IMAGE_LOADER = nil; - -/*--------------------------------------------------*/ - -#define MOBILY_IMAGE_LOADER_FOLDER @"MobilyImageLoaderCache" -#define MOBILY_IMAGE_LOADER_MAX_CONCURRENT_TASK 5 -#define MOBILY_IMAGE_LOADER_COUNT_LIMIT 512 - -/*--------------------------------------------------*/ - -@implementation MobilyImageLoader - -#pragma mark Standart - -- (id)init { - self = [super init]; - if(self != nil) { - [self setTaskManager:[[MobilyTaskManager alloc] init]]; - if(_taskManager != nil) { - [_taskManager setMaxConcurrentTask:MOBILY_IMAGE_LOADER_MAX_CONCURRENT_TASK]; - } - [self setCache:[[NSCache alloc] init]]; - if(_cache != nil) { - [_cache setName:MOBILY_IMAGE_LOADER_FOLDER]; - [_cache setCountLimit:MOBILY_IMAGE_LOADER_COUNT_LIMIT]; - } - } - return self; -} - -- (void)dealloc { - [self setTaskManager:nil]; - [self setCache:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark Public - -+ (BOOL)isExistImageWithImageUrl:(NSString*)imageUrl { - return [[self shared] isExistImageWithImageUrl:imageUrl]; -} - -+ (UIImage*)imageWithImageUrl:(NSString*)imageUrl { - return [[self shared] imageWithImageUrl:imageUrl]; -} - -+ (void)removeByImageUrl:(NSString*)imageUrl { - [[self shared] removeByImageUrl:imageUrl]; -} - -+ (void)cleanup { - [[self shared] cleanup]; -} - -+ (void)loadWithImageUrl:(NSString*)imageUrl target:(id)target completeSelector:(SEL)completeSelector failureSelector:(SEL)failureSelector { - [[self shared] loadWithImageUrl:imageUrl target:target completeSelector:completeSelector failureSelector:failureSelector]; -} - -+ (void)loadWithImageUrl:(NSString*)imageUrl target:(id)target completeBlock:(MobilyImageLoaderCompleteBlock)completeBlock failureBlock:(MobilyImageLoaderFailureBlock)failureBlock { - [[self shared] loadWithImageUrl:imageUrl target:target completeBlock:completeBlock failureBlock:failureBlock]; -} - -+ (void)cancelByImageUrl:(NSString*)imageUrl { - [[self shared] cancelByImageUrl:imageUrl]; -} - -+ (void)cancelByTarget:(id)target { - [[self shared] cancelByTarget:target]; -} - -#pragma mark Private - -+ (MobilyImageLoader*)shared { - if(MOBILY_IMAGE_LOADER == nil) { - @synchronized(self) { - if(MOBILY_IMAGE_LOADER == nil) { - MOBILY_IMAGE_LOADER = [[self alloc] init]; - } - } - } - return MOBILY_IMAGE_LOADER; -} - -- (NSString*)cacheKeyByImageUrl:(NSString*)imageUrl { - return [[[imageUrl stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString] stringByMD5]; -} - -- (BOOL)isExistImageWithImageUrl:(NSString*)imageUrl { - return [self isExistImageWithCacheKey:[self cacheKeyByImageUrl:imageUrl]]; -} - -- (BOOL)isExistImageWithCacheKey:(NSString*)cacheKey { - return ([_cache objectForKey:cacheKey] != nil); -} - -- (UIImage*)imageWithImageUrl:(NSString*)imageUrl { - return [self imageWithCacheKey:[self cacheKeyByImageUrl:imageUrl]]; -} - -- (UIImage*)imageWithCacheKey:(NSString*)cacheKey { - NSData* imageData = [_cache objectForKey:cacheKey]; - if(imageData != nil) { - return [UIImage imageWithData:imageData]; - } - return nil; -} - -- (void)addImageData:(NSData*)imageData byImageUrl:(NSString*)imageUrl { - [self addImageData:imageData byCacheKey:[self cacheKeyByImageUrl:imageUrl]]; -} - -- (void)addImageData:(NSData*)imageData byCacheKey:(NSString*)cacheKey { - [_cache setObject:imageData forKey:cacheKey]; -} - -- (void)removeByImageUrl:(NSString*)imageUrl { - [_cache removeObjectForKey:[self cacheKeyByImageUrl:imageUrl]]; -} - -- (void)removeByCacheKey:(NSString*)cacheKey { - [self removeByImageUrl:cacheKey]; -} - -- (void)cleanup { - [_cache removeAllObjects]; -} - -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" -- (void)loadWithImageUrl:(NSString*)imageUrl target:(id)target completeSelector:(SEL)completeSelector failureSelector:(SEL)failureSelector { - NSString* cacheKey = [self cacheKeyByImageUrl:imageUrl]; - if([cacheKey length] > 0) { - UIImage* image = nil; - NSData* imageData = [_cache objectForKey:cacheKey]; - if(imageData != nil) { - image = [UIImage imageWithData:imageData]; - } - if(image == nil) { - MobilyTaskImageLoader* task = [[MobilyTaskImageLoader alloc] initWithImageUrl:imageUrl cacheKey:cacheKey target:target completeSelector:completeSelector failureSelector:failureSelector]; - if(task != nil) { - [_taskManager updating]; - [_taskManager addTask:task]; - [_taskManager updated]; - } else { - if([target respondsToSelector:failureSelector] == YES) { - [target performSelector:failureSelector withObject:imageUrl]; - } - } - } else { - if([target respondsToSelector:completeSelector] == YES) { - [target performSelector:completeSelector withObject:image withObject:imageUrl]; - } - } - } else { - if([target respondsToSelector:failureSelector] == YES) { - [target performSelector:failureSelector withObject:imageUrl]; - } - } -} -#pragma clang diagnostic pop - -- (void)loadWithImageUrl:(NSString*)imageUrl target:(id)target completeBlock:(MobilyImageLoaderCompleteBlock)completeBlock failureBlock:(MobilyImageLoaderFailureBlock)failureBlock { - NSString* cacheKey = [self cacheKeyByImageUrl:imageUrl]; - if([cacheKey length] > 0) { - UIImage* image = nil; - NSData* imageData = [_cache objectForKey:cacheKey]; - if(imageData != nil) { - image = [UIImage imageWithData:imageData]; - } - if(image == nil) { - MobilyTaskImageLoader* task = [[MobilyTaskImageLoader alloc] initWithImageUrl:imageUrl cacheKey:cacheKey target:target completeBlock:completeBlock failureBlock:failureBlock]; - if(task != nil) { - [_taskManager updating]; - [_taskManager addTask:task]; - [_taskManager updated]; - } else { - if(failureBlock != nil) { - failureBlock(imageUrl); - } - } - } else { - if(completeBlock != nil) { - completeBlock(image, imageUrl); - } - } - } else { - if(failureBlock != nil) { - failureBlock(imageUrl); - } - } -} - -- (void)cancelByImageUrl:(NSString*)imageUrl { - [_taskManager enumirateTasksUsingBlock:^(MobilyTaskImageLoader* task, BOOL* stop) { - if([[task imageUrl] isEqualToString:imageUrl] == YES) { - [task cancel]; - } - }]; -} - -- (void)cancelByTarget:(id)target { - [_taskManager enumirateTasksUsingBlock:^(MobilyTaskImageLoader* task, BOOL* stop) { - if([task target] == target) { - [task cancel]; - } - }]; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -#define MOBILY_TASK_IMAGE_LOADER_ERROR_LIMITS 5 -#define MOBILY_TASK_IMAGE_LOADER_DELAY 1.0f - -/*--------------------------------------------------*/ - -@implementation MobilyTaskImageLoader - -#pragma mark Standart - -- (id)initWithImageUrl:(NSString*)imageUrl cacheKey:(NSString*)cacheKey target:(id)target { - self = [super init]; - if(self != nil) { - [self setImageLoader:[MobilyImageLoader shared]]; - [self setTarget:target]; - [self setImageUrl:imageUrl]; - [self setCacheKey:cacheKey]; - } - return self; -} - -- (id)initWithImageUrl:(NSString*)imageUrl cacheKey:(NSString*)cacheKey target:(id)target completeSelector:(SEL)completeSelector failureSelector:(SEL)failureSelector { - self = [self initWithImageUrl:imageUrl cacheKey:cacheKey target:target]; - if(self != nil) { - [self setCompleteEvent:[MobilyEventSelector callbackWithTarget:target action:completeSelector inMainThread:YES]]; - [self setFailureEvent:[MobilyEventSelector callbackWithTarget:target action:failureSelector inMainThread:YES]]; - } - return self; -} - -- (id)initWithImageUrl:(NSString*)imageUrl cacheKey:(NSString*)cacheKey target:(id)target completeBlock:(MobilyImageLoaderCompleteBlock)completeBlock failureBlock:(MobilyImageLoaderFailureBlock)failureBlock { - self = [self initWithImageUrl:imageUrl cacheKey:cacheKey target:target]; - if(self != nil) { - [self setCompleteEvent:[MobilyEventBlock callbackWithBlock:^id(id sender, id object) { - if(completeBlock != nil) { - completeBlock(_image, _imageUrl); - } - return nil; - } inMainQueue:YES]]; - [self setFailureEvent:[MobilyEventBlock callbackWithBlock:^id(id sender, id object) { - if(failureBlock != nil) { - failureBlock(_imageUrl); - } - return nil; - } inMainQueue:YES]]; - } - return self; -} - -- (void)dealloc { - [self setImageLoader:nil]; - [self setTarget:nil]; - [self setImageUrl:nil]; - [self setCacheKey:nil]; - [self setImage:nil]; - [self setCompleteEvent:nil]; - [self setFailureEvent:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark MobilyTask - -- (void)working { - UIImage* image = [_imageLoader imageWithImageUrl:_imageUrl]; - if(image == nil) { - NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:_imageUrl]]; - if(data != nil) { - image = [UIImage imageWithData:data]; - if(image != nil) { - [_imageLoader addImageData:data byCacheKey:_cacheKey]; - [self setImage:image]; - [self setNeedRework:NO]; - } - } else { - if(_countErrors < MOBILY_TASK_IMAGE_LOADER_ERROR_LIMITS) { - [self setCountErrors:_countErrors + 1]; - [self setNeedRework:YES]; - } else { - [self setNeedRework:NO]; - } -#if defined(MOBILY_DEBUG) - NSLog(@"Failure load image:%@", _imageUrl); -#endif - [NSThread sleepForTimeInterval:MOBILY_TASK_IMAGE_LOADER_DELAY]; - } - } else { - [self setImage:image]; - } -} - -- (void)didComplete { - if(_image != nil) { - [_completeEvent fireSender:_image object:_imageUrl]; - } else { - [_failureEvent fireSender:_imageUrl object:nil]; - } -} - -- (void)cancel { - [self setCompleteEvent:nil]; - [self setFailureEvent:nil]; - [super cancel]; -} - -@end - -/*--------------------------------------------------*/ diff --git a/Classes/UI/ViewScroll/MobilyViewScroll.m b/Classes/UI/ViewScroll/MobilyViewScroll.m deleted file mode 100644 index 259c76b..0000000 --- a/Classes/UI/ViewScroll/MobilyViewScroll.m +++ /dev/null @@ -1,244 +0,0 @@ -/*--------------------------------------------------*/ - -#import "MobilyViewScroll.h" - -/*--------------------------------------------------*/ - -@interface MobilyViewScroll () - -@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewL; -@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewT; -@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewR; -@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewB; -@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewW; -@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewH; - -- (void)linkConstraint; -- (void)unlinkConstraint; - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation MobilyViewScroll - -@synthesize objectName = _objectName; -@synthesize objectParent = _objectParent; -@synthesize objectChilds = _objectChilds; - -#pragma mark NSKeyValueCoding - -#pragma mark Standart - -- (id)initWithCoder:(NSCoder*)coder { - self = [super initWithCoder:coder]; - if(self != nil) { - [self setupView]; - } - return self; -} - -- (id)initWithFrame:(CGRect)frame { - self = [super initWithFrame:frame]; - if(self != nil) { - [self setupView]; - } - return self; -} - -- (void)dealloc { - [self unregisterAdjustmentResponder]; - - [self setObjectName:nil]; - [self setObjectParent:nil]; - [self setObjectChilds:nil]; - - [self setRootView:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark MobilyBuilderObject - -- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIView class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andAddingObject:objectChild]]; - [self addSubview:(UIView*)objectChild]; - } -} - -- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIView class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andRemovingObject:objectChild]]; - [self removeSubview:(UIView*)objectChild]; - } -} - -- (void)willLoadObjectChilds { -} - -- (void)didLoadObjectChilds { -} - -- (id< MobilyBuilderObject >)objectForName:(NSString*)name { - return [MobilyBuilderForm object:self forName:name]; -} - -- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { - return [MobilyBuilderForm object:self forSelector:selector]; -} - -#pragma mark Public - -- (void)setupView { - [self setDirection:MobilyViewScrollDirectionVertical]; - - [self registerAdjustmentResponder]; -} - -#pragma mark Property - -- (void)setConstraintRootViewL:(NSLayoutConstraint*)constraintRootViewL { - if(_constraintRootViewL != constraintRootViewL) { - if(_constraintRootViewL != nil) { - [self removeConstraint:_constraintRootViewL]; - } - MOBILY_SAFE_SETTER(_constraintRootViewL, constraintRootViewL); - if(_constraintRootViewL != nil) { - [self addConstraint:_constraintRootViewL]; - } - } -} - -- (void)setConstraintRootViewT:(NSLayoutConstraint*)constraintRootViewT { - if(_constraintRootViewT != constraintRootViewT) { - if(_constraintRootViewT != nil) { - [self removeConstraint:_constraintRootViewT]; - } - MOBILY_SAFE_SETTER(_constraintRootViewT, constraintRootViewT); - if(_constraintRootViewT != nil) { - [self addConstraint:_constraintRootViewT]; - } - } -} - -- (void)setConstraintRootViewR:(NSLayoutConstraint*)constraintRootViewR { - if(_constraintRootViewR != constraintRootViewR) { - if(_constraintRootViewR != nil) { - [self removeConstraint:_constraintRootViewR]; - } - MOBILY_SAFE_SETTER(_constraintRootViewR, constraintRootViewR); - if(_constraintRootViewR != nil) { - [self addConstraint:_constraintRootViewR]; - } - } -} - -- (void)setConstraintRootViewB:(NSLayoutConstraint*)constraintRootViewB { - if(_constraintRootViewB != constraintRootViewB) { - if(_constraintRootViewB != nil) { - [self removeConstraint:_constraintRootViewB]; - } - MOBILY_SAFE_SETTER(_constraintRootViewB, constraintRootViewB); - if(_constraintRootViewB != nil) { - [self addConstraint:_constraintRootViewB]; - } - } -} - -- (void)setConstraintRootViewW:(NSLayoutConstraint*)constraintRootViewW { - if(_constraintRootViewW != constraintRootViewW) { - if(_constraintRootViewW != nil) { - [self removeConstraint:_constraintRootViewW]; - } - MOBILY_SAFE_SETTER(_constraintRootViewW, constraintRootViewW); - if(_constraintRootViewW != nil) { - [self addConstraint:_constraintRootViewW]; - } - } -} - -- (void)setConstraintRootViewH:(NSLayoutConstraint*)constraintRootViewH { - if(_constraintRootViewH != constraintRootViewH) { - if(_constraintRootViewH != nil) { - [self removeConstraint:_constraintRootViewH]; - } - MOBILY_SAFE_SETTER(_constraintRootViewH, constraintRootViewH); - if(_constraintRootViewH != nil) { - [self addConstraint:_constraintRootViewH]; - } - } -} - -- (void)setDirection:(MobilyViewScrollDirection)direction { - if(_direction != direction) { - if(_rootView != nil) { - [self unlinkConstraint]; - } - _direction = direction; - if(_rootView != nil) { - [self linkConstraint]; - } - [self setNeedsLayout]; - } -} - -- (void)setRootView:(UIView*)rootView { - if(_rootView != rootView) { - if(_rootView != nil) { - [self unlinkConstraint]; - [_rootView removeFromSuperview]; - } - MOBILY_SAFE_SETTER(_rootView, rootView); - if(_rootView != nil) { - [_rootView setTranslatesAutoresizingMaskIntoConstraints:NO]; - [self addSubview:_rootView]; - [self linkConstraint]; - } - [self setNeedsLayout]; - } -} - -#pragma mark Private - -- (void)linkConstraint { - switch(_direction) { - case MobilyViewScrollDirectionStretch: - [self setConstraintRootViewT:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]]; - [self setConstraintRootViewB:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]]; - [self setConstraintRootViewL:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]]; - [self setConstraintRootViewR:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]]; - [self setConstraintRootViewW:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f]]; - [self setConstraintRootViewH:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]]; - break; - case MobilyViewScrollDirectionVertical: - [self setConstraintRootViewT:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]]; - [self setConstraintRootViewB:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]]; - [self setConstraintRootViewL:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]]; - [self setConstraintRootViewR:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]]; - [self setConstraintRootViewW:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f]]; - break; - case MobilyViewScrollDirectionHorizontal: - [self setConstraintRootViewT:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]]; - [self setConstraintRootViewB:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]]; - [self setConstraintRootViewL:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1.0f constant:0.0f]]; - [self setConstraintRootViewR:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:0.0f]]; - [self setConstraintRootViewH:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]]; - break; - } -} - -- (void)unlinkConstraint { - [self setConstraintRootViewL:nil]; - [self setConstraintRootViewT:nil]; - [self setConstraintRootViewR:nil]; - [self setConstraintRootViewB:nil]; - [self setConstraintRootViewW:nil]; - [self setConstraintRootViewH:nil]; -} - -@end - -/*--------------------------------------------------*/ diff --git a/Demo.xcodeproj/project.pbxproj b/Demo.xcodeproj/project.pbxproj new file mode 100644 index 0000000..4aa68e1 --- /dev/null +++ b/Demo.xcodeproj/project.pbxproj @@ -0,0 +1,510 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 409CAF351B75F30500BF7317 /* libMobilyCore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 409CAF1D1B75F2E800BF7317 /* libMobilyCore.a */; }; + 40CE50741B76AABE004E132A /* ChoiceController.m in Sources */ = {isa = PBXBuildFile; fileRef = 40CE50721B76AABE004E132A /* ChoiceController.m */; }; + 40CE50751B76AABE004E132A /* ChoiceController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 40CE50731B76AABE004E132A /* ChoiceController.xib */; }; + 40CE50791B76AADE004E132A /* ChoiceCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 40CE50771B76AADE004E132A /* ChoiceCell.m */; }; + 40CE507A1B76AADE004E132A /* ChoiceCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 40CE50781B76AADE004E132A /* ChoiceCell.xib */; }; + 40CE507E1B76AAF0004E132A /* ChoiceHeaderCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 40CE507C1B76AAF0004E132A /* ChoiceHeaderCell.m */; }; + 40CE507F1B76AAF0004E132A /* ChoiceHeaderCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 40CE507D1B76AAF0004E132A /* ChoiceHeaderCell.xib */; }; + 40CE50831B773B12004E132A /* ChoiceModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 40CE50821B773B12004E132A /* ChoiceModel.m */; }; + 40CE50861B773B25004E132A /* ChoiceGroupModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 40CE50851B773B25004E132A /* ChoiceGroupModel.m */; }; + 40D42BD01B72A24B00A69F3D /* App.m in Sources */ = {isa = PBXBuildFile; fileRef = 40D42BC81B72A24B00A69F3D /* App.m */; }; + 40D42BD21B72A24B00A69F3D /* Demo.m in Sources */ = {isa = PBXBuildFile; fileRef = 40D42BCD1B72A24B00A69F3D /* Demo.m */; }; + 40D42BD41B72A24B00A69F3D /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 40D42BCF1B72A24B00A69F3D /* Images.xcassets */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 409CAF1C1B75F2E800BF7317 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 409CAF131B75F2E700BF7317 /* Mobily.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 40B75EBD1ADF9EE500F0CB09; + remoteInfo = "MobilyCore-Library"; + }; + 409CAF1E1B75F2E800BF7317 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 409CAF131B75F2E700BF7317 /* Mobily.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 40B75EF61ADF9F1C00F0CB09; + remoteInfo = "MobilySocial-Library"; + }; + 409CAF201B75F2E800BF7317 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 409CAF131B75F2E700BF7317 /* Mobily.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 4080D2281B3B44AB00328837; + remoteInfo = "MobilyStore-Library"; + }; + 409CAF221B75F2E800BF7317 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 409CAF131B75F2E700BF7317 /* Mobily.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 4096BC211B20230E0048B07E; + remoteInfo = "MobilyCore-Framework"; + }; + 409CAF241B75F2E800BF7317 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 409CAF131B75F2E700BF7317 /* Mobily.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 4096BC431B20237D0048B07E; + remoteInfo = "MobilySocial-Framework"; + }; + 409CAF261B75F2E800BF7317 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 409CAF131B75F2E700BF7317 /* Mobily.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 4080D23C1B3B44B800328837; + remoteInfo = "MobilyStore-Framework"; + }; + 409CAF291B75F2FF00BF7317 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 409CAF131B75F2E700BF7317 /* Mobily.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 40B75EBC1ADF9EE500F0CB09; + remoteInfo = "MobilyCore-Library"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 409CAF131B75F2E700BF7317 /* Mobily.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; path = Mobily.xcodeproj; sourceTree = ""; }; + 40CE50711B76AABE004E132A /* ChoiceController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChoiceController.h; sourceTree = ""; }; + 40CE50721B76AABE004E132A /* ChoiceController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChoiceController.m; sourceTree = ""; }; + 40CE50731B76AABE004E132A /* ChoiceController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ChoiceController.xib; sourceTree = ""; }; + 40CE50761B76AADE004E132A /* ChoiceCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChoiceCell.h; sourceTree = ""; }; + 40CE50771B76AADE004E132A /* ChoiceCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChoiceCell.m; sourceTree = ""; }; + 40CE50781B76AADE004E132A /* ChoiceCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ChoiceCell.xib; sourceTree = ""; }; + 40CE507B1B76AAF0004E132A /* ChoiceHeaderCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChoiceHeaderCell.h; sourceTree = ""; }; + 40CE507C1B76AAF0004E132A /* ChoiceHeaderCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChoiceHeaderCell.m; sourceTree = ""; }; + 40CE507D1B76AAF0004E132A /* ChoiceHeaderCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ChoiceHeaderCell.xib; sourceTree = ""; }; + 40CE50811B773B12004E132A /* ChoiceModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChoiceModel.h; sourceTree = ""; }; + 40CE50821B773B12004E132A /* ChoiceModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChoiceModel.m; sourceTree = ""; }; + 40CE50841B773B25004E132A /* ChoiceGroupModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChoiceGroupModel.h; sourceTree = ""; }; + 40CE50851B773B25004E132A /* ChoiceGroupModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChoiceGroupModel.m; sourceTree = ""; }; + 40D42B941B729A0200A69F3D /* Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 40D42BC71B72A24B00A69F3D /* App.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = App.h; sourceTree = ""; }; + 40D42BC81B72A24B00A69F3D /* App.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = App.m; sourceTree = ""; }; + 40D42BCD1B72A24B00A69F3D /* Demo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Demo.m; sourceTree = ""; }; + 40D42BCE1B72A24B00A69F3D /* Demo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Demo.plist; sourceTree = ""; }; + 40D42BCF1B72A24B00A69F3D /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 40FF54431B75F46800E4E604 /* Demo.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Demo.pch; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 40D42B911B729A0200A69F3D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 409CAF351B75F30500BF7317 /* libMobilyCore.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 409CAF141B75F2E700BF7317 /* Products */ = { + isa = PBXGroup; + children = ( + 409CAF1D1B75F2E800BF7317 /* libMobilyCore.a */, + 409CAF1F1B75F2E800BF7317 /* libMobilySocial.a */, + 409CAF211B75F2E800BF7317 /* libMobilyStore.a */, + 409CAF231B75F2E800BF7317 /* MobilyCore.framework */, + 409CAF251B75F2E800BF7317 /* MobilySocial.framework */, + 409CAF271B75F2E800BF7317 /* MobilyStore-Framework.framework */, + ); + name = Products; + sourceTree = ""; + }; + 40CE506F1B76AABE004E132A /* Choice */ = { + isa = PBXGroup; + children = ( + 40CE50801B773AFC004E132A /* Models */, + 40CE50701B76AABE004E132A /* Cells */, + 40CE50711B76AABE004E132A /* ChoiceController.h */, + 40CE50721B76AABE004E132A /* ChoiceController.m */, + 40CE50731B76AABE004E132A /* ChoiceController.xib */, + ); + path = Choice; + sourceTree = ""; + }; + 40CE50701B76AABE004E132A /* Cells */ = { + isa = PBXGroup; + children = ( + 40CE507B1B76AAF0004E132A /* ChoiceHeaderCell.h */, + 40CE507C1B76AAF0004E132A /* ChoiceHeaderCell.m */, + 40CE507D1B76AAF0004E132A /* ChoiceHeaderCell.xib */, + 40CE50761B76AADE004E132A /* ChoiceCell.h */, + 40CE50771B76AADE004E132A /* ChoiceCell.m */, + 40CE50781B76AADE004E132A /* ChoiceCell.xib */, + ); + path = Cells; + sourceTree = ""; + }; + 40CE50801B773AFC004E132A /* Models */ = { + isa = PBXGroup; + children = ( + 40CE50841B773B25004E132A /* ChoiceGroupModel.h */, + 40CE50851B773B25004E132A /* ChoiceGroupModel.m */, + 40CE50811B773B12004E132A /* ChoiceModel.h */, + 40CE50821B773B12004E132A /* ChoiceModel.m */, + ); + path = Models; + sourceTree = ""; + }; + 40D42B8B1B729A0200A69F3D = { + isa = PBXGroup; + children = ( + 409CAF131B75F2E700BF7317 /* Mobily.xcodeproj */, + 40D42B961B729A0200A69F3D /* Demo */, + 40D42B951B729A0200A69F3D /* Products */, + ); + sourceTree = ""; + }; + 40D42B951B729A0200A69F3D /* Products */ = { + isa = PBXGroup; + children = ( + 40D42B941B729A0200A69F3D /* Demo.app */, + ); + name = Products; + sourceTree = ""; + }; + 40D42B961B729A0200A69F3D /* Demo */ = { + isa = PBXGroup; + children = ( + 40D42BC61B72A24B00A69F3D /* Sources */, + 40D42BCC1B72A24B00A69F3D /* Support */, + ); + path = Demo; + sourceTree = ""; + }; + 40D42BC61B72A24B00A69F3D /* Sources */ = { + isa = PBXGroup; + children = ( + 40D42BC71B72A24B00A69F3D /* App.h */, + 40D42BC81B72A24B00A69F3D /* App.m */, + 40D42BC91B72A24B00A69F3D /* Controllers */, + ); + path = Sources; + sourceTree = ""; + }; + 40D42BC91B72A24B00A69F3D /* Controllers */ = { + isa = PBXGroup; + children = ( + 40CE506F1B76AABE004E132A /* Choice */, + ); + path = Controllers; + sourceTree = ""; + }; + 40D42BCC1B72A24B00A69F3D /* Support */ = { + isa = PBXGroup; + children = ( + 40D42BCD1B72A24B00A69F3D /* Demo.m */, + 40FF54431B75F46800E4E604 /* Demo.pch */, + 40D42BCE1B72A24B00A69F3D /* Demo.plist */, + 40D42BCF1B72A24B00A69F3D /* Images.xcassets */, + ); + path = Support; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 40D42B931B729A0200A69F3D /* Demo */ = { + isa = PBXNativeTarget; + buildConfigurationList = 40D42BB71B729A0200A69F3D /* Build configuration list for PBXNativeTarget "Demo" */; + buildPhases = ( + 40D42B901B729A0200A69F3D /* Sources */, + 40D42B911B729A0200A69F3D /* Frameworks */, + 40D42B921B729A0200A69F3D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 409CAF2A1B75F2FF00BF7317 /* PBXTargetDependency */, + ); + name = Demo; + productName = Demo; + productReference = 40D42B941B729A0200A69F3D /* Demo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 40D42B8C1B729A0200A69F3D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0640; + ORGANIZATIONNAME = Mobily; + TargetAttributes = { + 40D42B931B729A0200A69F3D = { + CreatedOnToolsVersion = 6.4; + }; + }; + }; + buildConfigurationList = 40D42B8F1B729A0200A69F3D /* Build configuration list for PBXProject "Demo" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 40D42B8B1B729A0200A69F3D; + productRefGroup = 40D42B951B729A0200A69F3D /* Products */; + projectDirPath = ""; + projectReferences = ( + { + ProductGroup = 409CAF141B75F2E700BF7317 /* Products */; + ProjectRef = 409CAF131B75F2E700BF7317 /* Mobily.xcodeproj */; + }, + ); + projectRoot = ""; + targets = ( + 40D42B931B729A0200A69F3D /* Demo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXReferenceProxy section */ + 409CAF1D1B75F2E800BF7317 /* libMobilyCore.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libMobilyCore.a; + remoteRef = 409CAF1C1B75F2E800BF7317 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 409CAF1F1B75F2E800BF7317 /* libMobilySocial.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libMobilySocial.a; + remoteRef = 409CAF1E1B75F2E800BF7317 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 409CAF211B75F2E800BF7317 /* libMobilyStore.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libMobilyStore.a; + remoteRef = 409CAF201B75F2E800BF7317 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 409CAF231B75F2E800BF7317 /* MobilyCore.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = MobilyCore.framework; + remoteRef = 409CAF221B75F2E800BF7317 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 409CAF251B75F2E800BF7317 /* MobilySocial.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = MobilySocial.framework; + remoteRef = 409CAF241B75F2E800BF7317 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + 409CAF271B75F2E800BF7317 /* MobilyStore-Framework.framework */ = { + isa = PBXReferenceProxy; + fileType = wrapper.framework; + path = "MobilyStore-Framework.framework"; + remoteRef = 409CAF261B75F2E800BF7317 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; +/* End PBXReferenceProxy section */ + +/* Begin PBXResourcesBuildPhase section */ + 40D42B921B729A0200A69F3D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 40CE507A1B76AADE004E132A /* ChoiceCell.xib in Resources */, + 40CE507F1B76AAF0004E132A /* ChoiceHeaderCell.xib in Resources */, + 40CE50751B76AABE004E132A /* ChoiceController.xib in Resources */, + 40D42BD41B72A24B00A69F3D /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 40D42B901B729A0200A69F3D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 40CE50741B76AABE004E132A /* ChoiceController.m in Sources */, + 40CE50861B773B25004E132A /* ChoiceGroupModel.m in Sources */, + 40D42BD21B72A24B00A69F3D /* Demo.m in Sources */, + 40CE507E1B76AAF0004E132A /* ChoiceHeaderCell.m in Sources */, + 40CE50791B76AADE004E132A /* ChoiceCell.m in Sources */, + 40CE50831B773B12004E132A /* ChoiceModel.m in Sources */, + 40D42BD01B72A24B00A69F3D /* App.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 409CAF2A1B75F2FF00BF7317 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = "MobilyCore-Library"; + targetProxy = 409CAF291B75F2FF00BF7317 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 40D42BB51B729A0200A69F3D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(PROJECT_DIR)/Sources/**", + ); + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 40D42BB61B729A0200A69F3D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(PROJECT_DIR)/Sources/**", + ); + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 40D42BB81B729A0200A69F3D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(PROJECT_DIR)/Demo/Support/Demo.pch"; + INFOPLIST_FILE = "$(PROJECT_DIR)/Demo/Support/Demo.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); + OTHER_LIBTOOLFLAGS = "$(inherited)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 40D42BB91B729A0200A69F3D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(PROJECT_DIR)/Demo/Support/Demo.pch"; + INFOPLIST_FILE = "$(PROJECT_DIR)/Demo/Support/Demo.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + OTHER_LDFLAGS = ( + "$(inherited)", + "-ObjC", + ); + OTHER_LIBTOOLFLAGS = "$(inherited)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 40D42B8F1B729A0200A69F3D /* Build configuration list for PBXProject "Demo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 40D42BB51B729A0200A69F3D /* Debug */, + 40D42BB61B729A0200A69F3D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 40D42BB71B729A0200A69F3D /* Build configuration list for PBXNativeTarget "Demo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 40D42BB81B729A0200A69F3D /* Debug */, + 40D42BB91B729A0200A69F3D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 40D42B8C1B729A0200A69F3D /* Project object */; +} diff --git a/Project/MobilyExample/MobilyExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 68% rename from Project/MobilyExample/MobilyExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata index af75053..02a6973 100644 --- a/Project/MobilyExample/MobilyExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:Demo.xcodeproj"> diff --git a/Demo/Sources/App.h b/Demo/Sources/App.h new file mode 100644 index 0000000..e6b0a7f --- /dev/null +++ b/Demo/Sources/App.h @@ -0,0 +1,15 @@ +/*--------------------------------------------------*/ + +@class ChoiceController; + +/*--------------------------------------------------*/ + +@interface App : MobilyApplication + +@property(nonatomic, readonly, strong) MobilyWindow* window; +@property(nonatomic, readonly, strong) MobilyNavigationController* choiceNavigation; +@property(nonatomic, readonly, strong) ChoiceController* choiceController; + +@end + +/*--------------------------------------------------*/ diff --git a/Demo/Sources/App.m b/Demo/Sources/App.m new file mode 100644 index 0000000..fbf4de0 --- /dev/null +++ b/Demo/Sources/App.m @@ -0,0 +1,65 @@ +/*--------------------------------------------------*/ + +#import "App.h" + +/*--------------------------------------------------*/ + +#import "ChoiceController.h" + +/*--------------------------------------------------*/ + +@interface App () + +@end + +/*--------------------------------------------------*/ + +@implementation App + +#pragma mark Public + +@synthesize window = _window; +@synthesize choiceNavigation = _choiceNavigation; +@synthesize choiceController = _choiceController; + +#pragma mark Public + +- (BOOL)launchingWithOptions:(NSDictionary*)options { + BOOL result = [super launchingWithOptions:options]; + if(result == YES) { + self.window.rootViewController = self.choiceNavigation; + } + return result; +} + +- (void)terminate { + [super terminate]; +} + +#pragma mark Property + +- (MobilyWindow*)window { + if(_window == nil) { + _window = [MobilyWindow new]; + [_window makeKeyAndVisible]; + } + return _window; +} + +- (MobilyNavigationController*)choiceNavigation { + if(_choiceNavigation == nil) { + _choiceNavigation = [[MobilyNavigationController alloc] initWithRootViewController:self.choiceController]; + } + return _choiceNavigation; +} + +- (ChoiceController*)choiceController { + if(_choiceController == nil) { + _choiceController = [ChoiceController new]; + } + return _choiceController; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Demo/Sources/Controllers/Choice/Cells/ChoiceCell.h b/Demo/Sources/Controllers/Choice/Cells/ChoiceCell.h new file mode 100644 index 0000000..7a72909 --- /dev/null +++ b/Demo/Sources/Controllers/Choice/Cells/ChoiceCell.h @@ -0,0 +1,11 @@ +/*--------------------------------------------------*/ + +@interface ChoiceCell : MobilyDataCell + +@end + +/*--------------------------------------------------*/ + +extern NSString* ChoiceCellIdentifier; + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/Demo/Sources/Controllers/Choice/Cells/ChoiceCell.m b/Demo/Sources/Controllers/Choice/Cells/ChoiceCell.m new file mode 100644 index 0000000..d722954 --- /dev/null +++ b/Demo/Sources/Controllers/Choice/Cells/ChoiceCell.m @@ -0,0 +1,43 @@ +/*--------------------------------------------------*/ + +#import "ChoiceCell.h" +#import "ChoiceModel.h" + +/*--------------------------------------------------*/ + +@interface ChoiceCell () + +@property(nonatomic, readwrite, weak) IBOutlet UILabel* titleLabel; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation ChoiceCell + +#pragma mark MobilyDataCell + +- (void)prepareForUse { + [super prepareForUse]; + + ChoiceModel* model = self.item.data; + _titleLabel.text = model.title; +} + +- (void)prepareForUnuse { + [super prepareForUnuse]; +} + +#pragma mark Action + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +NSString* ChoiceCellIdentifier = @"ChoiceCellIdentifier"; + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/Demo/Sources/Controllers/Choice/Cells/ChoiceCell.xib b/Demo/Sources/Controllers/Choice/Cells/ChoiceCell.xib new file mode 100644 index 0000000..059b716 --- /dev/null +++ b/Demo/Sources/Controllers/Choice/Cells/ChoiceCell.xib @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Demo/Sources/Controllers/Choice/Cells/ChoiceHeaderCell.h b/Demo/Sources/Controllers/Choice/Cells/ChoiceHeaderCell.h new file mode 100644 index 0000000..776d739 --- /dev/null +++ b/Demo/Sources/Controllers/Choice/Cells/ChoiceHeaderCell.h @@ -0,0 +1,11 @@ +/*--------------------------------------------------*/ + +@interface ChoiceHeaderCell : MobilyDataCell + +@end + +/*--------------------------------------------------*/ + +extern NSString* ChoiceHeaderCellIdentifier; + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/Demo/Sources/Controllers/Choice/Cells/ChoiceHeaderCell.m b/Demo/Sources/Controllers/Choice/Cells/ChoiceHeaderCell.m new file mode 100644 index 0000000..986fd33 --- /dev/null +++ b/Demo/Sources/Controllers/Choice/Cells/ChoiceHeaderCell.m @@ -0,0 +1,41 @@ +/*--------------------------------------------------*/ + +#import "ChoiceHeaderCell.h" +#import "ChoiceGroupModel.h" + +/*--------------------------------------------------*/ + +@interface ChoiceHeaderCell () + +@property(nonatomic, readwrite, weak) IBOutlet UILabel* titleLabel; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation ChoiceHeaderCell + +#pragma mark MobilyDataCell + +- (void)prepareForUse { + [super prepareForUse]; + + ChoiceGroupModel* model = self.item.data; + _titleLabel.text = model.title; +} + +- (void)prepareForUnuse { + [super prepareForUnuse]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +NSString* ChoiceHeaderCellIdentifier = @"ChoiceHeaderCellIdentifier"; + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/Demo/Sources/Controllers/Choice/Cells/ChoiceHeaderCell.xib b/Demo/Sources/Controllers/Choice/Cells/ChoiceHeaderCell.xib new file mode 100644 index 0000000..221f3a4 --- /dev/null +++ b/Demo/Sources/Controllers/Choice/Cells/ChoiceHeaderCell.xib @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Demo/Sources/Controllers/Choice/ChoiceController.h b/Demo/Sources/Controllers/Choice/ChoiceController.h new file mode 100644 index 0000000..63ffa0b --- /dev/null +++ b/Demo/Sources/Controllers/Choice/ChoiceController.h @@ -0,0 +1,7 @@ +/*--------------------------------------------------*/ + +@interface ChoiceController : MobilyViewController + +@end + +/*--------------------------------------------------*/ diff --git a/Demo/Sources/Controllers/Choice/ChoiceController.m b/Demo/Sources/Controllers/Choice/ChoiceController.m new file mode 100644 index 0000000..adf9cd7 --- /dev/null +++ b/Demo/Sources/Controllers/Choice/ChoiceController.m @@ -0,0 +1,90 @@ +/*--------------------------------------------------*/ + +#import "ChoiceController.h" +#import "ChoiceHeaderCell.h" +#import "ChoiceCell.h" + +/*--------------------------------------------------*/ + +#import "ChoiceGroupModel.h" +#import "ChoiceModel.h" + +/*--------------------------------------------------*/ + +@interface ChoiceController () + +@property(nonatomic, readwrite, weak) IBOutlet MobilyDataView* dataView; + +@property(nonatomic, readwrite, strong) MobilyDataContainerSectionsList* dataContainer; + +@end + +/*--------------------------------------------------*/ + +@implementation ChoiceController + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.dataContainer = [MobilyDataContainerSectionsList containerWithOrientation:MobilyDataContainerOrientationVertical]; + + self.dataView.allowsSelection = NO; + self.dataView.allowsEditing = NO; + [self.dataView registerIdentifier:ChoiceHeaderCellIdentifier withViewClass:ChoiceHeaderCell.class]; + [self.dataView registerIdentifier:ChoiceCellIdentifier withViewClass:ChoiceCell.class]; + [self.dataView registerEventWithTarget:self action:@selector(pressedChoiceCell:forItem:) forIdentifier:ChoiceCellIdentifier forKey:MobilyDataCellPressed]; + self.dataView.container = self.dataContainer; +} + +- (void)viewDidUnload { + [super viewDidUnload]; +} + +- (void)update { + [super update]; + + NSArray* groups = @[ + [ChoiceGroupModel choiceGroupWithTitle:@"DataView" items:@[ + [ChoiceModel choiceWithTitle:@"List" type:ChoiceTypeDataViewList], + [ChoiceModel choiceWithTitle:@"Flow" type:ChoiceTypeDataViewFlow], + [ChoiceModel choiceWithTitle:@"Calendar" type:ChoiceTypeDataViewCalendar], + ]], + [ChoiceGroupModel choiceGroupWithTitle:@"ScrollView" items:@[ + [ChoiceModel choiceWithTitle:@"Form" type:ChoiceTypeScrollViewForm], + ]], + ]; + [self.dataView batchUpdate:^{ + [groups moEach:^(ChoiceGroupModel* group) { + MobilyDataContainerItemsList* container = [MobilyDataContainerItemsList containerWithOrientation:MobilyDataContainerOrientationVertical]; + container.header = [MobilyDataItem itemWithIdentifier:ChoiceHeaderCellIdentifier order:1 data:group]; + [group.items moEach:^(ChoiceModel* item) { + [container appendIdentifier:ChoiceCellIdentifier byData:item]; + }]; + [self.dataContainer appendSection:container]; + }]; + }]; +} + +- (void)clear { + [super clear]; +} + +#pragma mark Actions + +- (IBAction)pressedChoiceCell:(MobilyDataCell*)cell forItem:(MobilyDataItem*)item { + ChoiceModel* choice = item.data; + switch(choice.type) { + case ChoiceTypeDataViewList: + break; + case ChoiceTypeDataViewFlow: + break; + case ChoiceTypeDataViewCalendar: + break; + case ChoiceTypeScrollViewForm: + break; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Demo/Sources/Controllers/Choice/ChoiceController.xib b/Demo/Sources/Controllers/Choice/ChoiceController.xib new file mode 100644 index 0000000..82a3662 --- /dev/null +++ b/Demo/Sources/Controllers/Choice/ChoiceController.xib @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Demo/Sources/Controllers/Choice/Models/ChoiceGroupModel.h b/Demo/Sources/Controllers/Choice/Models/ChoiceGroupModel.h new file mode 100644 index 0000000..9b691e8 --- /dev/null +++ b/Demo/Sources/Controllers/Choice/Models/ChoiceGroupModel.h @@ -0,0 +1,13 @@ +/*--------------------------------------------------*/ + +@interface ChoiceGroupModel : MobilyModel + +@property(nonatomic, readonly, strong) NSString* title; +@property(nonatomic, readonly, strong) NSArray* items; + ++ (instancetype)choiceGroupWithTitle:(NSString*)title items:(NSArray*)items; +- (instancetype)initWithTitle:(NSString*)title items:(NSArray*)items; + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/Demo/Sources/Controllers/Choice/Models/ChoiceGroupModel.m b/Demo/Sources/Controllers/Choice/Models/ChoiceGroupModel.m new file mode 100644 index 0000000..5c9baa8 --- /dev/null +++ b/Demo/Sources/Controllers/Choice/Models/ChoiceGroupModel.m @@ -0,0 +1,35 @@ +/*--------------------------------------------------*/ + +#import "ChoiceGroupModel.h" + +/*--------------------------------------------------*/ + +@interface ChoiceGroupModel () + +@property(nonatomic, readwrite, strong) NSString* title; +@property(nonatomic, readwrite, strong) NSArray* items; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation ChoiceGroupModel + ++ (instancetype)choiceGroupWithTitle:(NSString*)title items:(NSArray*)items { + return [[self alloc] initWithTitle:title items:items]; +} + +- (instancetype)initWithTitle:(NSString*)title items:(NSArray*)items { + self = [super init]; + if(self != nil) { + self.title = title; + self.items = items; + } + return self; +} + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/Demo/Sources/Controllers/Choice/Models/ChoiceModel.h b/Demo/Sources/Controllers/Choice/Models/ChoiceModel.h new file mode 100644 index 0000000..f29e5f6 --- /dev/null +++ b/Demo/Sources/Controllers/Choice/Models/ChoiceModel.h @@ -0,0 +1,22 @@ +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, ChoiceType) { + ChoiceTypeDataViewList, + ChoiceTypeDataViewFlow, + ChoiceTypeDataViewCalendar, + ChoiceTypeScrollViewForm, +}; + +/*--------------------------------------------------*/ + +@interface ChoiceModel : MobilyModel + +@property(nonatomic, readonly, strong) NSString* title; +@property(nonatomic, readonly, assign) ChoiceType type; + ++ (instancetype)choiceWithTitle:(NSString*)title type:(ChoiceType)type; +- (instancetype)initWithTitle:(NSString*)title type:(ChoiceType)type; + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/Demo/Sources/Controllers/Choice/Models/ChoiceModel.m b/Demo/Sources/Controllers/Choice/Models/ChoiceModel.m new file mode 100644 index 0000000..9d09e68 --- /dev/null +++ b/Demo/Sources/Controllers/Choice/Models/ChoiceModel.m @@ -0,0 +1,35 @@ +/*--------------------------------------------------*/ + +#import "ChoiceModel.h" + +/*--------------------------------------------------*/ + +@interface ChoiceModel () + +@property(nonatomic, readwrite, strong) NSString* title; +@property(nonatomic, readwrite, assign) ChoiceType type; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation ChoiceModel + ++ (instancetype)choiceWithTitle:(NSString*)title type:(ChoiceType)type { + return [[self alloc] initWithTitle:title type:type]; +} + +- (instancetype)initWithTitle:(NSString*)title type:(ChoiceType)type { + self = [super init]; + if(self != nil) { + self.title = title; + self.type = type; + } + return self; +} + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/Demo/Support/Demo.m b/Demo/Support/Demo.m new file mode 100644 index 0000000..fc2ee91 --- /dev/null +++ b/Demo/Support/Demo.m @@ -0,0 +1,15 @@ +/*--------------------------------------------------*/ + +#import "App.h" + +/*--------------------------------------------------*/ + +int main(int argc, char * argv[]) { + @autoreleasepool { + [MobilyContext setArgCount:argc argValue:argv]; + [MobilyContext setApplicationClass:App.class]; + return [MobilyContext run]; + } +} + +/*--------------------------------------------------*/ diff --git a/Mobily/Mobily-Prefix.pch b/Demo/Support/Demo.pch similarity index 54% rename from Mobily/Mobily-Prefix.pch rename to Demo/Support/Demo.pch index dbc0b50..257d0ef 100644 --- a/Mobily/Mobily-Prefix.pch +++ b/Demo/Support/Demo.pch @@ -4,15 +4,20 @@ /*--------------------------------------------------*/ -#ifndef __IPHONE_5_0 -# warning "This project uses features only available in iOS SDK 5.0 and later." +#ifndef __IPHONE_7_0 +#warning "This project uses features only available in iOS SDK 7.0 and later." #endif /*--------------------------------------------------*/ #ifdef __OBJC__ -# import -# import +#import +#endif + +/*--------------------------------------------------*/ + +#ifdef __OBJC__ +#import #endif /*--------------------------------------------------*/ diff --git a/Project/MobilyExample/MobilyExample/MobilyExample-Info.plist b/Demo/Support/Demo.plist similarity index 83% rename from Project/MobilyExample/MobilyExample/MobilyExample-Info.plist rename to Demo/Support/Demo.plist index 33741d9..1de39f2 100644 --- a/Project/MobilyExample/MobilyExample/MobilyExample-Info.plist +++ b/Demo/Support/Demo.plist @@ -4,16 +4,14 @@ CFBundleDevelopmentRegion en - CFBundleDisplayName - ${PRODUCT_NAME} CFBundleExecutable - ${EXECUTABLE_NAME} + $(EXECUTABLE_NAME) CFBundleIdentifier - org.fgengine.mobily-example.${PRODUCT_NAME:rfc1034identifier} + org.mobily.$(PRODUCT_NAME:rfc1034identifier) CFBundleInfoDictionaryVersion 6.0 CFBundleName - ${PRODUCT_NAME} + $(PRODUCT_NAME) CFBundlePackageType APPL CFBundleShortVersionString @@ -21,7 +19,7 @@ CFBundleSignature ???? CFBundleVersion - 1.0 + 1 LSRequiresIPhoneOS UIRequiredDeviceCapabilities diff --git a/Project/MobilyExample/MobilyExample/Images.xcassets/AppIcon.appiconset/Contents.json b/Demo/Support/Images.xcassets/AppIcon.appiconset/Contents.json similarity index 76% rename from Project/MobilyExample/MobilyExample/Images.xcassets/AppIcon.appiconset/Contents.json rename to Demo/Support/Images.xcassets/AppIcon.appiconset/Contents.json index 91bf9c1..36d2c80 100644 --- a/Project/MobilyExample/MobilyExample/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/Demo/Support/Images.xcassets/AppIcon.appiconset/Contents.json @@ -5,16 +5,31 @@ "size" : "29x29", "scale" : "2x" }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "40x40", "scale" : "2x" }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, { "idiom" : "iphone", "size" : "60x60", "scale" : "2x" }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, { "idiom" : "ipad", "size" : "29x29", diff --git a/File Templates/Controller.xctemplate/TemplateIcon.icns b/File Templates/Controller.xctemplate/TemplateIcon.icns new file mode 100644 index 0000000..43918dc Binary files /dev/null and b/File Templates/Controller.xctemplate/TemplateIcon.icns differ diff --git a/File Templates/Controller.xctemplate/TemplateInfo.plist b/File Templates/Controller.xctemplate/TemplateInfo.plist new file mode 100644 index 0000000..14aa332 --- /dev/null +++ b/File Templates/Controller.xctemplate/TemplateInfo.plist @@ -0,0 +1,68 @@ + + + + + AllowedTypes + + public.objective-c-source + + DefaultCompletionName + Controller + Description + A Controller class + Kind + Xcode.IDEKit.TextSubstitutionFileTemplateKind + MainTemplateFile + ___FILEBASENAME___.m + Platforms + + com.apple.platform.iphoneos + + Options + + + Default + Controller + Description + The name of the Controller class to create + Identifier + productName + Name + Class Name + NotPersisted + + Required + + Type + text + + + Default + BaseController + Description + Base class + Identifier + baseClass + Name + Base class + Required + + NotPersisted + + Type + text + + + Default + ___VARIABLE_baseClass:identifier___ + Identifier + baseClassName + Type + static + + + + Summary + A Controller class + + diff --git a/File Templates/Controller.xctemplate/___FILEBASENAME___.h b/File Templates/Controller.xctemplate/___FILEBASENAME___.h new file mode 100644 index 0000000..ad90261 --- /dev/null +++ b/File Templates/Controller.xctemplate/___FILEBASENAME___.h @@ -0,0 +1,11 @@ +/*--------------------------------------------------*/ + +#import "___VARIABLE_baseClass:identifier___.h" + +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ : ___VARIABLE_baseClass:identifier___ + +@end + +/*--------------------------------------------------*/ diff --git a/File Templates/Controller.xctemplate/___FILEBASENAME___.m b/File Templates/Controller.xctemplate/___FILEBASENAME___.m new file mode 100644 index 0000000..a36e2ab --- /dev/null +++ b/File Templates/Controller.xctemplate/___FILEBASENAME___.m @@ -0,0 +1,35 @@ +/*--------------------------------------------------*/ + +#import "___FILEBASENAME___.h" + +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ () + +@end + +/*--------------------------------------------------*/ + +@implementation ___FILEBASENAMEASIDENTIFIER___ + +- (void)viewDidLoad { + [super viewDidLoad]; + + // Do any additional setup after loading the view. +} + +- (void)update { + [super update]; + + // update screen data +} + +- (void)clear { + // clear all data + + [super clear]; +} + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/File Templates/Controller.xctemplate/___FILEBASENAME___.xib b/File Templates/Controller.xctemplate/___FILEBASENAME___.xib new file mode 100644 index 0000000..73fecca --- /dev/null +++ b/File Templates/Controller.xctemplate/___FILEBASENAME___.xib @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/File Templates/DataCell.xctemplate/Simple/___FILEBASENAME___.h b/File Templates/DataCell.xctemplate/Simple/___FILEBASENAME___.h new file mode 100644 index 0000000..6dc2a49 --- /dev/null +++ b/File Templates/DataCell.xctemplate/Simple/___FILEBASENAME___.h @@ -0,0 +1,11 @@ +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ : MobilyDataCell + +@end + +/*--------------------------------------------------*/ + +extern NSString* ___FILEBASENAMEASIDENTIFIER___Identifier; + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/File Templates/DataCell.xctemplate/Simple/___FILEBASENAME___.m b/File Templates/DataCell.xctemplate/Simple/___FILEBASENAME___.m new file mode 100644 index 0000000..999a817 --- /dev/null +++ b/File Templates/DataCell.xctemplate/Simple/___FILEBASENAME___.m @@ -0,0 +1,43 @@ +/*--------------------------------------------------*/ + +#import "___FILEBASENAME___.h" + +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ () + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation ___FILEBASENAMEASIDENTIFIER___ + +#pragma mark Static + ++ (CGSize)sizeForItem:(MobilyDataItem*)item availableSize:(CGSize)size { + return size; +} + +#pragma mark MobilyDataCell + +- (void)prepareForUse { + [super prepareForUse]; +} + +- (void)prepareForUnuse { + [super prepareForUnuse]; +} + +#pragma mark Action + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +NSString* ___FILEBASENAMEASIDENTIFIER___Identifier = @"___FILEBASENAMEASIDENTIFIER___Identifier"; + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/File Templates/DataCell.xctemplate/Simple/___FILEBASENAME___.xib b/File Templates/DataCell.xctemplate/Simple/___FILEBASENAME___.xib new file mode 100644 index 0000000..07e46be --- /dev/null +++ b/File Templates/DataCell.xctemplate/Simple/___FILEBASENAME___.xib @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/File Templates/DataCell.xctemplate/Swipe/___FILEBASENAME___.h b/File Templates/DataCell.xctemplate/Swipe/___FILEBASENAME___.h new file mode 100644 index 0000000..fd0c05f --- /dev/null +++ b/File Templates/DataCell.xctemplate/Swipe/___FILEBASENAME___.h @@ -0,0 +1,11 @@ +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ : MobilyDataCellSwipe + +@end + +/*--------------------------------------------------*/ + +extern NSString* ___FILEBASENAMEASIDENTIFIER___Identifier; + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/File Templates/DataCell.xctemplate/Swipe/___FILEBASENAME___.m b/File Templates/DataCell.xctemplate/Swipe/___FILEBASENAME___.m new file mode 100644 index 0000000..999a817 --- /dev/null +++ b/File Templates/DataCell.xctemplate/Swipe/___FILEBASENAME___.m @@ -0,0 +1,43 @@ +/*--------------------------------------------------*/ + +#import "___FILEBASENAME___.h" + +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ () + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation ___FILEBASENAMEASIDENTIFIER___ + +#pragma mark Static + ++ (CGSize)sizeForItem:(MobilyDataItem*)item availableSize:(CGSize)size { + return size; +} + +#pragma mark MobilyDataCell + +- (void)prepareForUse { + [super prepareForUse]; +} + +- (void)prepareForUnuse { + [super prepareForUnuse]; +} + +#pragma mark Action + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +NSString* ___FILEBASENAMEASIDENTIFIER___Identifier = @"___FILEBASENAMEASIDENTIFIER___Identifier"; + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/File Templates/DataCell.xctemplate/Swipe/___FILEBASENAME___.xib b/File Templates/DataCell.xctemplate/Swipe/___FILEBASENAME___.xib new file mode 100644 index 0000000..95ea5f5 --- /dev/null +++ b/File Templates/DataCell.xctemplate/Swipe/___FILEBASENAME___.xib @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/File Templates/DataCell.xctemplate/TemplateIcon.icns b/File Templates/DataCell.xctemplate/TemplateIcon.icns new file mode 100644 index 0000000..a26fed6 Binary files /dev/null and b/File Templates/DataCell.xctemplate/TemplateIcon.icns differ diff --git a/File Templates/DataCell.xctemplate/TemplateInfo.plist b/File Templates/DataCell.xctemplate/TemplateInfo.plist new file mode 100644 index 0000000..d5faf7d --- /dev/null +++ b/File Templates/DataCell.xctemplate/TemplateInfo.plist @@ -0,0 +1,58 @@ + + + + + AllowedTypes + + public.objective-c-source + + Description + Creates a new DataCell class. + Kind + Xcode.IDEKit.TextSubstitutionFileTemplateKind + Options + + + Default + DataCell + Description + The name of the DataCell class to create + Identifier + productName + Name + Class Name + NotPersisted + + Required + + Type + text + + + Identifier + cellType + Name + Cell Type + Description + The type of cell to create. + Type + popup + Default + Simple + NotPersisted + + Values + + Simple + Swipe + + + + Platforms + + com.apple.platform.iphoneos + + Summary + A DataCell class. + + diff --git a/File Templates/DataRefreshView.xctemplate/TemplateIcon.icns b/File Templates/DataRefreshView.xctemplate/TemplateIcon.icns new file mode 100644 index 0000000..a26fed6 Binary files /dev/null and b/File Templates/DataRefreshView.xctemplate/TemplateIcon.icns differ diff --git a/File Templates/DataRefreshView.xctemplate/TemplateInfo.plist b/File Templates/DataRefreshView.xctemplate/TemplateInfo.plist new file mode 100644 index 0000000..7989502 --- /dev/null +++ b/File Templates/DataRefreshView.xctemplate/TemplateInfo.plist @@ -0,0 +1,20 @@ + + + + + AllowedTypes + + public.objective-c-source + + Description + Mobily data refresh view template. + Kind + Xcode.IDEKit.TextSubstitutionFileTemplateKind + MainTemplateFile + ___FILEBASENAME___.m + Platforms + + com.apple.platform.iphoneos + + + diff --git a/File Templates/DataRefreshView.xctemplate/___FILEBASENAME___.h b/File Templates/DataRefreshView.xctemplate/___FILEBASENAME___.h new file mode 100644 index 0000000..4e032fb --- /dev/null +++ b/File Templates/DataRefreshView.xctemplate/___FILEBASENAME___.h @@ -0,0 +1,7 @@ +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ : MobilyDataRefreshView + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/File Templates/DataRefreshView.xctemplate/___FILEBASENAME___.m b/File Templates/DataRefreshView.xctemplate/___FILEBASENAME___.m new file mode 100644 index 0000000..291dc7c --- /dev/null +++ b/File Templates/DataRefreshView.xctemplate/___FILEBASENAME___.m @@ -0,0 +1,39 @@ +/*--------------------------------------------------*/ + +#import "___FILEBASENAME___.h" + +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ () + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation ___FILEBASENAMEASIDENTIFIER___ + +#pragma mark Init / Free + +- (void)setup { + [super setup]; +} + +#pragma mark Public + +- (void)didIdle { +} + +- (void)didPull { +} + +- (void)didRelease { +} + +- (void)didLoading { +} + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/File Templates/DataViewController.xctemplate/TemplateIcon.icns b/File Templates/DataViewController.xctemplate/TemplateIcon.icns new file mode 100644 index 0000000..43918dc Binary files /dev/null and b/File Templates/DataViewController.xctemplate/TemplateIcon.icns differ diff --git a/File Templates/DataViewController.xctemplate/TemplateInfo.plist b/File Templates/DataViewController.xctemplate/TemplateInfo.plist new file mode 100644 index 0000000..14aa332 --- /dev/null +++ b/File Templates/DataViewController.xctemplate/TemplateInfo.plist @@ -0,0 +1,68 @@ + + + + + AllowedTypes + + public.objective-c-source + + DefaultCompletionName + Controller + Description + A Controller class + Kind + Xcode.IDEKit.TextSubstitutionFileTemplateKind + MainTemplateFile + ___FILEBASENAME___.m + Platforms + + com.apple.platform.iphoneos + + Options + + + Default + Controller + Description + The name of the Controller class to create + Identifier + productName + Name + Class Name + NotPersisted + + Required + + Type + text + + + Default + BaseController + Description + Base class + Identifier + baseClass + Name + Base class + Required + + NotPersisted + + Type + text + + + Default + ___VARIABLE_baseClass:identifier___ + Identifier + baseClassName + Type + static + + + + Summary + A Controller class + + diff --git a/File Templates/DataViewController.xctemplate/___FILEBASENAME___.h b/File Templates/DataViewController.xctemplate/___FILEBASENAME___.h new file mode 100644 index 0000000..ad90261 --- /dev/null +++ b/File Templates/DataViewController.xctemplate/___FILEBASENAME___.h @@ -0,0 +1,11 @@ +/*--------------------------------------------------*/ + +#import "___VARIABLE_baseClass:identifier___.h" + +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ : ___VARIABLE_baseClass:identifier___ + +@end + +/*--------------------------------------------------*/ diff --git a/File Templates/DataViewController.xctemplate/___FILEBASENAME___.m b/File Templates/DataViewController.xctemplate/___FILEBASENAME___.m new file mode 100644 index 0000000..03b4ec3 --- /dev/null +++ b/File Templates/DataViewController.xctemplate/___FILEBASENAME___.m @@ -0,0 +1,57 @@ +/*--------------------------------------------------*/ + +#import "___FILEBASENAME___.h" + +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ () + +@property(nonatomic, readwrite, weak) IBOutlet MobilyDataView* dataView; +@property(nonatomic, readwrite, strong) MobilyDataContainer* dataContainer; + +@end + +/*--------------------------------------------------*/ + +@implementation ___FILEBASENAMEASIDENTIFIER___ + +#pragma mark Init / Free + +- (void)setup { + [super setup]; +} + +#pragma mark Load / Unload + +- (void)viewDidLoad { + [super viewDidLoad]; + + // Do any additional setup after loading the view. + // [_dataView registerIdentifier:<#(NSString *)#> withViewClass:<#(__unsafe_unretained Class)#>]; + // [_dataView registerEventWithTarget:<#(id)#> action:<#(SEL)#> forIdentifier:<#(NSString *)#> forKey:<#(id)#>]; + _dataView.container = _dataContainer; +} + +#pragma mark Update / Clear + +- (void)update { + [super update]; + + // update screen data +} + +- (void)clear { + // clear all data + + [super clear]; +} + +#pragma mark Public + +#pragma mark Private + +#pragma mark Actions + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/File Templates/DataViewController.xctemplate/___FILEBASENAME___.xib b/File Templates/DataViewController.xctemplate/___FILEBASENAME___.xib new file mode 100644 index 0000000..b56da95 --- /dev/null +++ b/File Templates/DataViewController.xctemplate/___FILEBASENAME___.xib @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/File Templates/Manager.xctemplate/API/___FILEBASENAME___.h b/File Templates/Manager.xctemplate/API/___FILEBASENAME___.h new file mode 100644 index 0000000..f962173 --- /dev/null +++ b/File Templates/Manager.xctemplate/API/___FILEBASENAME___.h @@ -0,0 +1,22 @@ +/*--------------------------------------------------*/ + +// imports + +/*--------------------------------------------------*/ + +// success +typedef void (^ApiSuccess)(); +typedef void (^ApiMessageSuccess)(NSString* message); + +// failure +typedef void (^ApiFailure)(NSString* message, NSError* httpError); + +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ : NSObject + ++ (void)exampleRequestSuccess:(ApiSuccess)success failure:(ApiFailure)failure; + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/File Templates/Manager.xctemplate/API/___FILEBASENAME___.m b/File Templates/Manager.xctemplate/API/___FILEBASENAME___.m new file mode 100644 index 0000000..fd69869 --- /dev/null +++ b/File Templates/Manager.xctemplate/API/___FILEBASENAME___.m @@ -0,0 +1,54 @@ +/*--------------------------------------------------*/ + +#import "___FILEBASENAME___.h" + +/*--------------------------------------------------*/ + +static NSString* ___FILEBASENAMEASIDENTIFIER___ServerUrl = @"http://httpbin.org/"; + +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ () + ++ (MobilyApiProvider*)___FILEBASENAMEASIDENTIFIER___Provider; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation ___FILEBASENAMEASIDENTIFIER___ + +#pragma mark Property + ++ (MobilyApiProvider*)___FILEBASENAMEASIDENTIFIER___Provider { + static MobilyApiProvider* ___FILEBASENAMEASIDENTIFIER___Provider = nil; + if(___FILEBASENAMEASIDENTIFIER___Provider == nil) { + ___FILEBASENAMEASIDENTIFIER___Provider = [[MobilyApiProvider alloc] initWithName:@"___FILEBASENAMEASIDENTIFIER___Provider" url:[NSURL URLWithString:___FILEBASENAMEASIDENTIFIER___ServerUrl]]; + [[MobilyApiManager shared] registerProvider:___FILEBASENAMEASIDENTIFIER___Provider]; + } + return ___FILEBASENAMEASIDENTIFIER___Provider; +} + +#pragma mark Public + ++ (void)exampleRequestSuccess:(ApiSuccess)success failure:(ApiFailure)failure { + [self.___FILEBASENAMEASIDENTIFIER___Provider sendRequest:[[MobilyApiRequest alloc] initWithGetRelativeUrl:@"/get"] + byTarget:self + completeBlock:^(MobilyApiRequest* request, MobilyApiResponse* response) { + if(response.httpError == nil) { + if(success != nil) { + success(); + } + } else { + if(failure != nil) { + failure(@"error", response.httpError); + } + } + }]; +} + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/File Templates/Manager.xctemplate/Base/___FILEBASENAME___.h b/File Templates/Manager.xctemplate/Base/___FILEBASENAME___.h new file mode 100644 index 0000000..0bdff9e --- /dev/null +++ b/File Templates/Manager.xctemplate/Base/___FILEBASENAME___.h @@ -0,0 +1,22 @@ +/*--------------------------------------------------*/ + +// imports + +/*--------------------------------------------------*/ + +// success +typedef void (^ManagerSuccess)(); +typedef void (^ManagerMessageSuccess)(NSString* message); + +// failure +typedef void (^ManagerFailure)(NSString* message, NSError* httpError); + +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ : MobilyModel + ++ (instancetype)shared; + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/File Templates/Manager.xctemplate/Base/___FILEBASENAME___.m b/File Templates/Manager.xctemplate/Base/___FILEBASENAME___.m new file mode 100644 index 0000000..b9927e3 --- /dev/null +++ b/File Templates/Manager.xctemplate/Base/___FILEBASENAME___.m @@ -0,0 +1,42 @@ +/*--------------------------------------------------*/ + +#import "___FILEBASENAME___.h" + +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ () + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation ___FILEBASENAMEASIDENTIFIER___ + +#pragma mark MobilyModel + ++ (NSArray*)serializeMap { + return @[ + ]; +} + +#pragma mark Singleton + ++ (instancetype)shared { + static id result = nil; + if(result == nil) { + result = [[self alloc] initWithUserDefaultsKey:@"___FILEBASENAMEASIDENTIFIER___"]; + } + return result; +} + +#pragma mark Setup + +- (void)setup { + [super setup]; +} + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/File Templates/Manager.xctemplate/TemplateIcon.icns b/File Templates/Manager.xctemplate/TemplateIcon.icns new file mode 100644 index 0000000..a26fed6 Binary files /dev/null and b/File Templates/Manager.xctemplate/TemplateIcon.icns differ diff --git a/File Templates/Manager.xctemplate/TemplateInfo.plist b/File Templates/Manager.xctemplate/TemplateInfo.plist new file mode 100644 index 0000000..e96355b --- /dev/null +++ b/File Templates/Manager.xctemplate/TemplateInfo.plist @@ -0,0 +1,60 @@ + + + + + AllowedTypes + + public.objective-c-source + + DefaultCompletionName + Manager + Description + Creates a new Manager class. + Kind + Xcode.IDEKit.TextSubstitutionFileTemplateKind + MainTemplateFile + ___FILEBASENAME___.m + Options + + + Description + The name of the Manager class to create + Identifier + productName + Name + Class Name + NotPersisted + + Required + + Type + text + + + Identifier + managerType + Name + Manager Type + Description + The type of Manager to create. + Type + popup + Default + Base + NotPersisted + + Values + + Base + API + + + + Platforms + + com.apple.platform.iphoneos + + Summary + A Manager class. + + diff --git a/File Templates/Model.xctemplate/TemplateIcon.icns b/File Templates/Model.xctemplate/TemplateIcon.icns new file mode 100644 index 0000000..a26fed6 Binary files /dev/null and b/File Templates/Model.xctemplate/TemplateIcon.icns differ diff --git a/File Templates/Model.xctemplate/TemplateInfo.plist b/File Templates/Model.xctemplate/TemplateInfo.plist new file mode 100644 index 0000000..b130df6 --- /dev/null +++ b/File Templates/Model.xctemplate/TemplateInfo.plist @@ -0,0 +1,20 @@ + + + + + AllowedTypes + + public.objective-c-source + + Description + Mobily model template. + Kind + Xcode.IDEKit.TextSubstitutionFileTemplateKind + MainTemplateFile + ___FILEBASENAME___.m + Platforms + + com.apple.platform.iphoneos + + + diff --git a/File Templates/Model.xctemplate/___FILEBASENAME___.h b/File Templates/Model.xctemplate/___FILEBASENAME___.h new file mode 100644 index 0000000..730f887 --- /dev/null +++ b/File Templates/Model.xctemplate/___FILEBASENAME___.h @@ -0,0 +1,7 @@ +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ : MobilyModel + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/File Templates/Model.xctemplate/___FILEBASENAME___.m b/File Templates/Model.xctemplate/___FILEBASENAME___.m new file mode 100644 index 0000000..25f5fac --- /dev/null +++ b/File Templates/Model.xctemplate/___FILEBASENAME___.m @@ -0,0 +1,35 @@ +/*--------------------------------------------------*/ + +#import "___FILEBASENAME___.h" + +/*--------------------------------------------------*/ + +@interface ___FILEBASENAMEASIDENTIFIER___ () + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation ___FILEBASENAMEASIDENTIFIER___ + +#pragma mark Storage item configuration + ++ (NSArray*)compareMap { + return @[]; +} + ++ (NSArray*)serializeMap { + return @[ + ]; +} + ++ (NSDictionary*)jsonMap { + return @{ + }; +} + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/File Templates/TemplateInstall.command b/File Templates/TemplateInstall.command new file mode 100755 index 0000000..0ecb5ae --- /dev/null +++ b/File Templates/TemplateInstall.command @@ -0,0 +1,12 @@ +#!/bin/sh + +installDirectory=~/Library/Developer/Xcode/Templates/File\ Templates/Mobily + +if [ -d "$installDirectory" ] +then + rm -r "$installDirectory" +fi + +mkdir -p "$installDirectory" + +cp -r "$(dirname "$0")"/*.xctemplate "$installDirectory" diff --git a/Frameworks/Bolts.framework/Bolts b/Frameworks/Bolts.framework/Bolts new file mode 100644 index 0000000..73c602d Binary files /dev/null and b/Frameworks/Bolts.framework/Bolts differ diff --git a/Frameworks/Bolts.framework/Headers/BFAppLink.h b/Frameworks/Bolts.framework/Headers/BFAppLink.h new file mode 100644 index 0000000..5e51acd --- /dev/null +++ b/Frameworks/Bolts.framework/Headers/BFAppLink.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +/*! The version of the App Link protocol that this library supports */ +FOUNDATION_EXPORT NSString *const BFAppLinkVersion; + +/*! + Contains App Link metadata relevant for navigation on this device + derived from the HTML at a given URL. + */ +@interface BFAppLink : NSObject + +/*! + Creates a BFAppLink with the given list of BFAppLinkTargets and target URL. + + Generally, this will only be used by implementers of the BFAppLinkResolving protocol, + as these implementers will produce App Link metadata for a given URL. + + @param sourceURL the URL from which this App Link is derived + @param targets an ordered list of BFAppLinkTargets for this platform derived + from App Link metadata. + @param webURL the fallback web URL, if any, for the app link. + */ ++ (instancetype)appLinkWithSourceURL:(NSURL *)sourceURL + targets:(NSArray *)targets + webURL:(NSURL *)webURL; + +/*! The URL from which this BFAppLink was derived */ +@property (nonatomic, strong, readonly) NSURL *sourceURL; + +/*! + The ordered list of targets applicable to this platform that will be used + for navigation. + */ +@property (nonatomic, copy, readonly) NSArray *targets; + +/*! The fallback web URL to use if no targets are installed on this device. */ +@property (nonatomic, strong, readonly) NSURL *webURL; + +@end diff --git a/Frameworks/Bolts.framework/Headers/BFAppLinkNavigation.h b/Frameworks/Bolts.framework/Headers/BFAppLinkNavigation.h new file mode 100644 index 0000000..d459f72 --- /dev/null +++ b/Frameworks/Bolts.framework/Headers/BFAppLinkNavigation.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +#import + +/*! + The result of calling navigate on a BFAppLinkNavigation + */ +typedef NS_ENUM(NSInteger, BFAppLinkNavigationType) { + /*! Indicates that the navigation failed and no app was opened */ + BFAppLinkNavigationTypeFailure, + /*! Indicates that the navigation succeeded by opening the URL in the browser */ + BFAppLinkNavigationTypeBrowser, + /*! Indicates that the navigation succeeded by opening the URL in an app on the device */ + BFAppLinkNavigationTypeApp +}; + +@protocol BFAppLinkResolving; +@class BFTask; + +/*! + Represents a pending request to navigate to an App Link. Most developers will + simply use navigateToURLInBackground: to open a URL, but developers can build + custom requests with additional navigation and app data attached to them by + creating BFAppLinkNavigations themselves. + */ +@interface BFAppLinkNavigation : NSObject + +/*! + The extras for the AppLinkNavigation. This will generally contain application-specific + data that should be passed along with the request, such as advertiser or affiliate IDs or + other such metadata relevant on this device. + */ +@property (nonatomic, copy, readonly) NSDictionary *extras; + +/*! + The al_applink_data for the AppLinkNavigation. This will generally contain data common to + navigation attempts such as back-links, user agents, and other information that may be used + in routing and handling an App Link request. + */ +@property (nonatomic, copy, readonly) NSDictionary *appLinkData; + +/*! The AppLink to navigate to */ +@property (nonatomic, strong, readonly) BFAppLink *appLink; + +/*! Creates an AppLinkNavigation with the given link, extras, and App Link data */ ++ (instancetype)navigationWithAppLink:(BFAppLink *)appLink + extras:(NSDictionary *)extras + appLinkData:(NSDictionary *)appLinkData; + +/*! Performs the navigation */ +- (BFAppLinkNavigationType)navigate:(NSError **)error; + +/*! Returns a BFAppLink for the given URL */ ++ (BFTask *)resolveAppLinkInBackground:(NSURL *)destination; + +/*! Returns a BFAppLink for the given URL using the given App Link resolution strategy */ ++ (BFTask *)resolveAppLinkInBackground:(NSURL *)destination resolver:(id)resolver; + +/*! Navigates to a BFAppLink and returns whether it opened in-app or in-browser */ ++ (BFAppLinkNavigationType)navigateToAppLink:(BFAppLink *)link error:(NSError **)error; + +/*! Navigates to a URL (an asynchronous action) and returns a BFNavigationType */ ++ (BFTask *)navigateToURLInBackground:(NSURL *)destination; + +/*! + Navigates to a URL (an asynchronous action) using the given App Link resolution + strategy and returns a BFNavigationType + */ ++ (BFTask *)navigateToURLInBackground:(NSURL *)destination resolver:(id)resolver; + +/*! + Gets the default resolver to be used for App Link resolution. If the developer has not set one explicitly, + a basic, built-in resolver will be used. + */ ++ (id)defaultResolver; + +/*! + Sets the default resolver to be used for App Link resolution. Setting this to nil will revert the + default resolver to the basic, built-in resolver provided by Bolts. + */ ++ (void)setDefaultResolver:(id)resolver; + +@end diff --git a/Frameworks/Bolts.framework/Headers/BFAppLinkResolving.h b/Frameworks/Bolts.framework/Headers/BFAppLinkResolving.h new file mode 100644 index 0000000..baa1451 --- /dev/null +++ b/Frameworks/Bolts.framework/Headers/BFAppLinkResolving.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +@class BFTask; + +/*! + Implement this protocol to provide an alternate strategy for resolving + App Links that may include pre-fetching, caching, or querying for App Link + data from an index provided by a service provider. + */ +@protocol BFAppLinkResolving + +/*! + Asynchronously resolves App Link data for a given URL. + + @param url The URL to resolve into an App Link. + @returns A BFTask that will return a BFAppLink for the given URL. + */ +- (BFTask *)appLinkFromURLInBackground:(NSURL *)url; + +@end diff --git a/Frameworks/Bolts.framework/Headers/BFAppLinkReturnToRefererController.h b/Frameworks/Bolts.framework/Headers/BFAppLinkReturnToRefererController.h new file mode 100644 index 0000000..22648d4 --- /dev/null +++ b/Frameworks/Bolts.framework/Headers/BFAppLinkReturnToRefererController.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import +#import + +#import + +@class BFAppLink; +@class BFAppLinkReturnToRefererController; + +/*! + Protocol that a class can implement in order to be notified when the user has navigated back + to the referer of an App Link. + */ +@protocol BFAppLinkReturnToRefererControllerDelegate + +@optional + +/*! Called when the user has tapped to navigate, but before the navigation has been performed. */ +- (void)returnToRefererController:(BFAppLinkReturnToRefererController *)controller + willNavigateToAppLink:(BFAppLink *)appLink; + +/*! Called after the navigation has been attempted, with an indication of whether the referer + app link was successfully opened. */ +- (void)returnToRefererController:(BFAppLinkReturnToRefererController *)controller + didNavigateToAppLink:(BFAppLink *)url + type:(BFAppLinkNavigationType)type; + +@end + +/*! + A controller class that implements default behavior for a BFAppLinkReturnToRefererView, including + the ability to display the view above the navigation bar for navigation-bsaed apps. + */ +@interface BFAppLinkReturnToRefererController : NSObject + +/*! + The delegate that will be notified when the user navigates back to the referer. + */ +@property (nonatomic, weak) id delegate; + +/*! + The BFAppLinkReturnToRefererView this controller is controlling. + */ +@property (nonatomic, strong) BFAppLinkReturnToRefererView *view; + +/*! + Initializes a controller suitable for controlling a BFAppLinkReturnToRefererView that is to be displayed + contained within another UIView (i.e., not displayed above the navigation bar). + */ +- (instancetype)init; + +/*! + Initializes a controller suitable for controlling a BFAppLinkReturnToRefererView that is to be displayed + displayed above the navigation bar. + */ +- (instancetype)initForDisplayAboveNavController:(UINavigationController *)navController; + +/*! + Removes the view entirely from the navigation controller it is currently displayed in. + */ +- (void)removeFromNavController; + +/*! + Shows the BFAppLinkReturnToRefererView with the specified referer information. If nil or missing data, + the view will not be displayed. */ +- (void)showViewForRefererAppLink:(BFAppLink *)refererAppLink; + +/*! + Shows the BFAppLinkReturnToRefererView with referer information extracted from the specified URL. + If nil or missing referer App Link data, the view will not be displayed. */ +- (void)showViewForRefererURL:(NSURL *)url; + +/*! + Closes the view, possibly animating it. + */ +- (void)closeViewAnimated:(BOOL)animated; + +@end diff --git a/Frameworks/Bolts.framework/Headers/BFAppLinkReturnToRefererView.h b/Frameworks/Bolts.framework/Headers/BFAppLinkReturnToRefererView.h new file mode 100644 index 0000000..cf3825c --- /dev/null +++ b/Frameworks/Bolts.framework/Headers/BFAppLinkReturnToRefererView.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import +#import + +#import + +@class BFAppLinkReturnToRefererView; +@class BFURL; + +typedef NS_ENUM(NSUInteger, BFIncludeStatusBarInSize) +{ + BFIncludeStatusBarInSizeNever, + BFIncludeStatusBarInSizeIOS7AndLater, + BFIncludeStatusBarInSizeAlways, +}; + +/*! + Protocol that a class can implement in order to be notified when the user has navigated back + to the referer of an App Link. + */ +@protocol BFAppLinkReturnToRefererViewDelegate + +/*! + Called when the user has tapped inside the close button. + */ +- (void)returnToRefererViewDidTapInsideCloseButton:(BFAppLinkReturnToRefererView *)view; + +/*! + Called when the user has tapped inside the App Link portion of the view. + */ +- (void)returnToRefererViewDidTapInsideLink:(BFAppLinkReturnToRefererView *)view + link:(BFAppLink *)link; + +@end + +/*! + Provides a UIView that displays a button allowing users to navigate back to the + application that launched the App Link currently being handled, if the App Link + contained referer data. The user can also close the view by clicking a close button + rather than navigating away. If the view is provided an App Link that does not contain + referer data, it will have zero size and no UI will be displayed. + */ +@interface BFAppLinkReturnToRefererView : UIView + +/*! + The delegate that will be notified when the user navigates back to the referer. + */ +@property (nonatomic, weak) id delegate; + +/*! + The color of the text label and close button. + */ +@property (nonatomic, strong) UIColor *textColor; + +@property (nonatomic, strong) BFAppLink *refererAppLink; + +/*! + Indicates whether to extend the size of the view to include the current status bar + size, for use in scenarios where the view might extend under the status bar on iOS 7 and + above; this property has no effect on earlier versions of iOS. + */ +@property (nonatomic, assign) BFIncludeStatusBarInSize includeStatusBarInSize; + +/*! + Indicates whether the user has closed the view by clicking the close button. + */ +@property (nonatomic, assign) BOOL closed; + +@end diff --git a/Frameworks/Bolts.framework/Headers/BFAppLinkTarget.h b/Frameworks/Bolts.framework/Headers/BFAppLinkTarget.h new file mode 100644 index 0000000..6172126 --- /dev/null +++ b/Frameworks/Bolts.framework/Headers/BFAppLinkTarget.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +/*! + Represents a target defined in App Link metadata, consisting of at least + a URL, and optionally an App Store ID and name. + */ +@interface BFAppLinkTarget : NSObject + +/*! Creates a BFAppLinkTarget with the given app site and target URL. */ ++ (instancetype)appLinkTargetWithURL:(NSURL *)url + appStoreId:(NSString *)appStoreId + appName:(NSString *)appName; + +/*! The URL prefix for this app link target */ +@property (nonatomic, strong, readonly) NSURL *URL; + +/*! The app ID for the app store */ +@property (nonatomic, copy, readonly) NSString *appStoreId; + +/*! The name of the app */ +@property (nonatomic, copy, readonly) NSString *appName; + +@end diff --git a/Frameworks/Bolts.framework/Headers/BFExecutor.h b/Frameworks/Bolts.framework/Headers/BFExecutor.h new file mode 100644 index 0000000..02af9ba --- /dev/null +++ b/Frameworks/Bolts.framework/Headers/BFExecutor.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +/*! + An object that can run a given block. + */ +@interface BFExecutor : NSObject + +/*! + Returns a default executor, which runs continuations immediately until the call stack gets too + deep, then dispatches to a new GCD queue. + */ ++ (instancetype)defaultExecutor; + +/*! + Returns an executor that runs continuations on the thread where the previous task was completed. + */ ++ (instancetype)immediateExecutor; + +/*! + Returns an executor that runs continuations on the main thread. + */ ++ (instancetype)mainThreadExecutor; + +/*! + Returns a new executor that uses the given block to execute continuations. + @param block The block to use. + */ ++ (instancetype)executorWithBlock:(void(^)(void(^block)()))block; + +/*! + Returns a new executor that runs continuations on the given queue. + @param queue The instance of `dispatch_queue_t` to dispatch all continuations onto. + */ ++ (instancetype)executorWithDispatchQueue:(dispatch_queue_t)queue; + +/*! + Returns a new executor that runs continuations on the given queue. + @param queue The instance of `NSOperationQueue` to run all continuations on. + */ ++ (instancetype)executorWithOperationQueue:(NSOperationQueue *)queue; + +/*! + Runs the given block using this executor's particular strategy. + @param block The block to execute. + */ +- (void)execute:(void(^)())block; + +@end diff --git a/Frameworks/Bolts.framework/Headers/BFMeasurementEvent.h b/Frameworks/Bolts.framework/Headers/BFMeasurementEvent.h new file mode 100644 index 0000000..7a9948c --- /dev/null +++ b/Frameworks/Bolts.framework/Headers/BFMeasurementEvent.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +/*! The name of the notification posted by BFMeasurementEvent */ +FOUNDATION_EXPORT NSString *const BFMeasurementEventNotificationName; + +/*! Defines keys in the userInfo object for the notification named BFMeasurementEventNotificationName */ +/*! The string field for the name of the event */ +FOUNDATION_EXPORT NSString *const BFMeasurementEventNameKey; +/*! The dictionary field for the arguments of the event */ +FOUNDATION_EXPORT NSString *const BFMeasurementEventArgsKey; + + +/*! Bolts Events raised by BFMeasurementEvent for Applink */ +/*! + The name of the event posted when [BFURL URLWithURL:] is called successfully. This represents the successful parsing of an app link URL. + */ +FOUNDATION_EXPORT NSString *const BFAppLinkParseEventName; + +/*! + The name of the event posted when [BFURL URLWithInboundURL:] is called successfully. + This represents parsing an inbound app link URL from a different application + */ +FOUNDATION_EXPORT NSString *const BFAppLinkNavigateInEventName; + +/*! The event raised when the user navigates from your app to other apps */ +FOUNDATION_EXPORT NSString *const BFAppLinkNavigateOutEventName; + +/*! + The event raised when the user navigates out from your app and back to the referrer app. + e.g when the user leaves your app after tapping the back-to-referrer navigation bar + */ +FOUNDATION_EXPORT NSString *const BFAppLinkNavigateBackToReferrerEventName; + +@interface BFMeasurementEvent : NSObject + +@end diff --git a/Frameworks/Bolts.framework/Headers/BFTask.h b/Frameworks/Bolts.framework/Headers/BFTask.h new file mode 100644 index 0000000..ce8db4f --- /dev/null +++ b/Frameworks/Bolts.framework/Headers/BFTask.h @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +/*! + Error domain used if there was multiple errors on . + */ +extern NSString *const BFTaskErrorDomain; + +/*! + An exception that is thrown if there was multiple exceptions on . + */ +extern NSString *const BFTaskMultipleExceptionsException; + +@class BFExecutor; +@class BFTask; + +/*! + A block that can act as a continuation for a task. + */ +typedef id(^BFContinuationBlock)(BFTask *task); + +/*! + The consumer view of a Task. A BFTask has methods to + inspect the state of the task, and to add continuations to + be run once the task is complete. + */ +@interface BFTask : NSObject + +/*! + Creates a task that is already completed with the given result. + @param result The result for the task. + */ ++ (instancetype)taskWithResult:(id)result; + +/*! + Creates a task that is already completed with the given error. + @param error The error for the task. + */ ++ (instancetype)taskWithError:(NSError *)error; + +/*! + Creates a task that is already completed with the given exception. + @param exception The exception for the task. + */ ++ (instancetype)taskWithException:(NSException *)exception; + +/*! + Creates a task that is already cancelled. + */ ++ (instancetype)cancelledTask; + +/*! + Returns a task that will be completed (with result == nil) once + all of the input tasks have completed. + @param tasks An `NSArray` of the tasks to use as an input. + */ ++ (instancetype)taskForCompletionOfAllTasks:(NSArray *)tasks; + +/*! + Returns a task that will be completed once all of the input tasks have completed. + If all tasks complete successfully without being faulted or cancelled the result will be + an `NSArray` of all task results in the order they were provided. + @param tasks An `NSArray` of the tasks to use as an input. + */ ++ (instancetype)taskForCompletionOfAllTasksWithResults:(NSArray *)tasks; + +/*! + Returns a task that will be completed a certain amount of time in the future. + @param millis The approximate number of milliseconds to wait before the + task will be finished (with result == nil). + */ ++ (instancetype)taskWithDelay:(int)millis; + +/*! + Returns a task that will be completed after the given block completes with + the specified executor. + @param executor A BFExecutor responsible for determining how the + continuation block will be run. + @param block The block to immediately schedule to run with the given executor. + @returns A task that will be completed after block has run. + If block returns a BFTask, then the task returned from + this method will not be completed until that task is completed. + */ ++ (instancetype)taskFromExecutor:(BFExecutor *)executor + withBlock:(id (^)())block; + +// Properties that will be set on the task once it is completed. + +/*! + The result of a successful task. + */ +@property (nonatomic, strong, readonly) id result; + + +/*! + The error of a failed task. + */ +@property (nonatomic, strong, readonly) NSError *error; + +/*! + The exception of a failed task. + */ +@property (nonatomic, strong, readonly) NSException *exception; + +/*! + Whether this task has been cancelled. + */ +@property (nonatomic, assign, readonly, getter = isCancelled) BOOL cancelled; + +/*! + Whether this task has completed due to an error or exception. + */ +@property (nonatomic, assign, readonly, getter = isFaulted) BOOL faulted; + +/*! + Whether this task has completed. + */ +@property (nonatomic, assign, readonly, getter = isCompleted) BOOL completed; + +/*! + Enqueues the given block to be run once this task is complete. + This method uses a default execution strategy. The block will be + run on the thread where the previous task completes, unless the + the stack depth is too deep, in which case it will be run on a + dispatch queue with default priority. + @param block The block to be run once this task is complete. + @returns A task that will be completed after block has run. + If block returns a BFTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (instancetype)continueWithBlock:(BFContinuationBlock)block; + +/*! + Enqueues the given block to be run once this task is complete. + @param executor A BFExecutor responsible for determining how the + continuation block will be run. + @param block The block to be run once this task is complete. + @returns A task that will be completed after block has run. + If block returns a BFTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (instancetype)continueWithExecutor:(BFExecutor *)executor + withBlock:(BFContinuationBlock)block; + +/*! + Identical to continueWithBlock:, except that the block is only run + if this task did not produce a cancellation, error, or exception. + If it did, then the failure will be propagated to the returned + task. + @param block The block to be run once this task is complete. + @returns A task that will be completed after block has run. + If block returns a BFTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (instancetype)continueWithSuccessBlock:(BFContinuationBlock)block; + +/*! + Identical to continueWithExecutor:withBlock:, except that the block + is only run if this task did not produce a cancellation, error, or + exception. If it did, then the failure will be propagated to the + returned task. + @param executor A BFExecutor responsible for determining how the + continuation block will be run. + @param block The block to be run once this task is complete. + @returns A task that will be completed after block has run. + If block returns a BFTask, then the task returned from + this method will not be completed until that task is completed. + */ +- (instancetype)continueWithExecutor:(BFExecutor *)executor + withSuccessBlock:(BFContinuationBlock)block; + +/*! + Waits until this operation is completed. + This method is inefficient and consumes a thread resource while + it's running. It should be avoided. This method logs a warning + message if it is used on the main thread. + */ +- (void)waitUntilFinished; + +@end diff --git a/Frameworks/Bolts.framework/Headers/BFTaskCompletionSource.h b/Frameworks/Bolts.framework/Headers/BFTaskCompletionSource.h new file mode 100644 index 0000000..d0ea545 --- /dev/null +++ b/Frameworks/Bolts.framework/Headers/BFTaskCompletionSource.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +@class BFTask; + +/*! + A BFTaskCompletionSource represents the producer side of tasks. + It is a task that also has methods for changing the state of the + task by settings its completion values. + */ +@interface BFTaskCompletionSource : NSObject + +/*! + Creates a new unfinished task. + */ ++ (instancetype)taskCompletionSource; + +/*! + The task associated with this TaskCompletionSource. + */ +@property (nonatomic, retain, readonly) BFTask *task; + +/*! + Completes the task by setting the result. + Attempting to set this for a completed task will raise an exception. + @param result The result of the task. + */ +- (void)setResult:(id)result; + +/*! + Completes the task by setting the error. + Attempting to set this for a completed task will raise an exception. + @param error The error for the task. + */ +- (void)setError:(NSError *)error; + +/*! + Completes the task by setting an exception. + Attempting to set this for a completed task will raise an exception. + @param exception The exception for the task. + */ +- (void)setException:(NSException *)exception; + +/*! + Completes the task by marking it as cancelled. + Attempting to set this for a completed task will raise an exception. + */ +- (void)cancel; + +/*! + Sets the result of the task if it wasn't already completed. + @returns whether the new value was set. + */ +- (BOOL)trySetResult:(id)result; + +/*! + Sets the error of the task if it wasn't already completed. + @param error The error for the task. + @returns whether the new value was set. + */ +- (BOOL)trySetError:(NSError *)error; + +/*! + Sets the exception of the task if it wasn't already completed. + @param exception The exception for the task. + @returns whether the new value was set. + */ +- (BOOL)trySetException:(NSException *)exception; + +/*! + Sets the cancellation state of the task if it wasn't already completed. + @returns whether the new value was set. + */ +- (BOOL)trySetCancelled; + +@end diff --git a/Frameworks/Bolts.framework/Headers/BFURL.h b/Frameworks/Bolts.framework/Headers/BFURL.h new file mode 100644 index 0000000..f269e2d --- /dev/null +++ b/Frameworks/Bolts.framework/Headers/BFURL.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + + + +@class BFAppLink; + +/*! + Provides a set of utilities for working with NSURLs, such as parsing of query parameters + and handling for App Link requests. + */ +@interface BFURL : NSObject + +/*! + Creates a link target from a raw URL. + On success, this posts the BFAppLinkParseEventName measurement event. If you are constructing the BFURL within your application delegate's + application:openURL:sourceApplication:annotation:, you should instead use URLWithInboundURL:sourceApplication: + to support better BFMeasurementEvent notifications + @param url The instance of `NSURL` to create BFURL from. + */ ++ (BFURL *)URLWithURL:(NSURL *)url; + +/*! + Creates a link target from a raw URL received from an external application. This is typically called from the app delegate's + application:openURL:sourceApplication:annotation: and will post the BFAppLinkNavigateInEventName measurement event. + @param url The instance of `NSURL` to create BFURL from. + @param sourceApplication the bundle ID of the app that is requesting your app to open the URL. The same sourceApplication in application:openURL:sourceApplication:annotation: +*/ ++ (BFURL *)URLWithInboundURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication; + +/*! + Gets the target URL. If the link is an App Link, this is the target of the App Link. + Otherwise, it is the url that created the target. + */ +@property (nonatomic, strong, readonly) NSURL *targetURL; + +/*! + Gets the query parameters for the target, parsed into an NSDictionary. + */ +@property (nonatomic, strong, readonly) NSDictionary *targetQueryParameters; + +/*! + If this link target is an App Link, this is the data found in al_applink_data. + Otherwise, it is nil. + */ +@property (nonatomic, strong, readonly) NSDictionary *appLinkData; + +/*! + If this link target is an App Link, this is the data found in extras. + */ +@property (nonatomic, strong, readonly) NSDictionary *appLinkExtras; + +/*! + The App Link indicating how to navigate back to the referer app, if any. + */ +@property (nonatomic, strong, readonly) BFAppLink *appLinkReferer; + +/*! + The URL that was used to create this BFURL. + */ +@property (nonatomic, strong, readonly) NSURL *inputURL; + +/*! + The query parameters of the inputURL, parsed into an NSDictionary. + */ +@property (nonatomic, strong, readonly) NSDictionary *inputQueryParameters; + +@end diff --git a/Frameworks/Bolts.framework/Headers/BFWebViewAppLinkResolver.h b/Frameworks/Bolts.framework/Headers/BFWebViewAppLinkResolver.h new file mode 100644 index 0000000..cffa529 --- /dev/null +++ b/Frameworks/Bolts.framework/Headers/BFWebViewAppLinkResolver.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import + +#import + +/*! + A reference implementation for an App Link resolver that uses a hidden UIWebView + to parse the HTML containing App Link metadata. + */ +@interface BFWebViewAppLinkResolver : NSObject + +/*! + Gets the instance of a BFWebViewAppLinkResolver. + */ ++ (instancetype)sharedInstance; + +@end diff --git a/Frameworks/Bolts.framework/Headers/Bolts.h b/Frameworks/Bolts.framework/Headers/Bolts.h new file mode 100644 index 0000000..e22bdd5 --- /dev/null +++ b/Frameworks/Bolts.framework/Headers/Bolts.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +#import +#import +#import +#import + +#if TARGET_OS_IPHONE +#import +#import +#import +#import +#import +#import +#import +#endif + +/*! @abstract 80175001: There were multiple errors. */ +extern NSInteger const kBFMultipleErrorsError; + +@interface Bolts : NSObject + +/*! + Returns the version of the Bolts Framework as an NSString. + @returns The NSString representation of the current version. + */ ++ (NSString *)version; + +@end diff --git a/Frameworks/Bolts.framework/Headers/BoltsVersion.h b/Frameworks/Bolts.framework/Headers/BoltsVersion.h new file mode 100644 index 0000000..866d954 --- /dev/null +++ b/Frameworks/Bolts.framework/Headers/BoltsVersion.h @@ -0,0 +1 @@ +#define BOLTS_VERSION @"1.1.4" diff --git a/Frameworks/Bolts.framework/Info.plist b/Frameworks/Bolts.framework/Info.plist new file mode 100644 index 0000000..0ea40d3 Binary files /dev/null and b/Frameworks/Bolts.framework/Info.plist differ diff --git a/Frameworks/Bolts.framework/Modules/module.modulemap b/Frameworks/Bolts.framework/Modules/module.modulemap new file mode 100644 index 0000000..3c92a17 --- /dev/null +++ b/Frameworks/Bolts.framework/Modules/module.modulemap @@ -0,0 +1,15 @@ +framework module Bolts { + umbrella header "Bolts.h" + + export * + module * { export * } + + explicit module BFAppLinkResolving { + header "BFAppLinkResolving.h" + export * + } + explicit module BFWebViewAppLinkResolver { + header "BFWebViewAppLinkResolver.h" + export * + } +} diff --git a/Frameworks/FBAudienceNetwork.framework/FBAudienceNetwork b/Frameworks/FBAudienceNetwork.framework/FBAudienceNetwork new file mode 100644 index 0000000..0785175 Binary files /dev/null and b/Frameworks/FBAudienceNetwork.framework/FBAudienceNetwork differ diff --git a/Frameworks/FBAudienceNetwork.framework/Headers/FBAdChoicesView.h b/Frameworks/FBAudienceNetwork.framework/Headers/FBAdChoicesView.h new file mode 100644 index 0000000..54ac6a3 --- /dev/null +++ b/Frameworks/FBAudienceNetwork.framework/Headers/FBAdChoicesView.h @@ -0,0 +1,89 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBAdDefines.h" + +@class FBAdImage; +@class FBNativeAd; +@class FBNativeAdViewAttributes; + +/*! + @class FBAdChoicesView + + @abstract + FBAdChoicesView offers a simple way to display a sponsored or AdChoices icon. + */ +FB_CLASS_EXPORT +@interface FBAdChoicesView : UIView + +/*! + @property + @abstract Access to the text label contained in this view. + */ +@property (nonatomic, weak, readonly) UILabel *label; + +/*! + @property + @abstract Determines whether the background mask is shown, or a transparent mask is used. + */ +@property (nonatomic, assign, getter=isBackgroundShown) BOOL backgroundShown; + +/*! + @method + + @abstract + Initialize this view with a given native ad. Configuration is pulled from the native ad. + + @param nativeAd The native ad to initialize with. + */ +- (instancetype)initWithNativeAd:(FBNativeAd *)nativeAd; + +/*! + @method + + @abstract + Initialize this view with explicit parameters. + + @param viewController View controller to present the AdChoices webview from. + @param adChoicesIcon Native ad AdChoices icon. + @param adChoicesLinkURL Native ad AdChoices link URL. + @param attributes Attributes to configure look and feel. + */ +- (instancetype)initWithViewController:(UIViewController *)viewController adChoicesIcon:(FBAdImage *)adChoicesIcon adChoicesLinkURL:(NSURL *)adChoicesLinkURL attributes:(FBNativeAdViewAttributes *)attributes NS_DESIGNATED_INITIALIZER; + +/*! + @method + + @abstract + Using the superview, this updates the frame of this view, positioning the icon in the top right corner by default. + */ +- (void)updateFrameFromSuperview; + +/*! + @method + + @abstract + Using the superview, this updates the frame of this view, positioning the icon in the corner specified. UIRectCornerAllCorners not supported. + + @param corner The corner to display this view from. + */ +- (void)updateFrameFromSuperview:(UIRectCorner)corner; + +@end diff --git a/Frameworks/FBAudienceNetwork.framework/Headers/FBAdDefines.h b/Frameworks/FBAudienceNetwork.framework/Headers/FBAdDefines.h new file mode 100644 index 0000000..f38abcc --- /dev/null +++ b/Frameworks/FBAudienceNetwork.framework/Headers/FBAdDefines.h @@ -0,0 +1,38 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#ifndef FBAudienceNetwork_FBAdDefines_h +#define FBAudienceNetwork_FBAdDefines_h + +#ifdef __cplusplus +#define FB_EXTERN_C_BEGIN extern "C" { +#define FB_EXTERN_C_END } +#else +#define FB_EXTERN_C_BEGIN +#define FB_EXTERN_C_END +#endif + +#ifdef __cplusplus +# define FB_EXPORT extern "C" __attribute__((visibility("default"))) +#else +# define FB_EXPORT extern __attribute__((visibility("default"))) +#endif + +#define FB_CLASS_EXPORT __attribute__((visibility("default"))) + +#endif diff --git a/Frameworks/FBAudienceNetwork.framework/Headers/FBAdSettings.h b/Frameworks/FBAudienceNetwork.framework/Headers/FBAdSettings.h new file mode 100644 index 0000000..8f297a6 --- /dev/null +++ b/Frameworks/FBAudienceNetwork.framework/Headers/FBAdSettings.h @@ -0,0 +1,116 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBAdDefines.h" + +FB_EXPORT NSString *const FBAudienceNetworkErrorDomain; + +typedef NS_ENUM(NSInteger, FBAdLogLevel) { + FBAdLogLevelNone, + FBAdLogLevelNotification, + FBAdLogLevelError, + FBAdLogLevelWarning, + FBAdLogLevelLog, + FBAdLogLevelDebug, + FBAdLogLevelVerbose +}; + +/*! + @class FBAdSettings + + @abstract AdSettings contains global settings for all ad controls. + */ +FB_CLASS_EXPORT +@interface FBAdSettings : NSObject + +/*! + @method + + @abstract + Adds a test device. + + @param deviceHash The id of the device to use test mode, can be obtained from debug log + + @discussion + Copy the current device Id from debug log and add it as a test device to get test ads. Apps + running on emulator will automatically get test ads. Test devices should be added before loadAd is called. + */ ++ (void)addTestDevice:(NSString *)deviceHash; + +/*! + @method + + @abstract + Add a collection of test devices. See `+addTestDevices:` for details. + + @param devicesHash The array of the device id to use test mode, can be obtained from debug log + */ ++ (void)addTestDevices:(NSArray *)devicesHash; + +/*! + @method + + @abstract + Clear all the added test devices + */ ++ (void)clearTestDevices; + +/*! + @method + + @abstract + Configures the ad control for treatment as child-directed. + + @param isChildDirected Indicates whether you would like your ad control to be treated as child-directed + + @discussion + Note that you may have other legal obligations under the Children's Online Privacy Protection Act (COPPA). + Please review the FTC's guidance and consult with your own legal counsel. + */ ++ (void)setIsChildDirected:(BOOL)isChildDirected; + +/*! + @method + + @abstract + Sets the url prefix to use when making ad requests. + + @discussion + This method should never be used in production. + */ ++ (void)setUrlPrefix:(NSString *) urlPrefix; + +/*! + @method + + @abstract + Gets the current SDK logging level + */ ++ (FBAdLogLevel)getLogLevel; + +/*! + @method + + @abstract + Sets the current SDK logging level + */ ++ (void)setLogLevel:(FBAdLogLevel)level; + +@end diff --git a/Frameworks/FBAudienceNetwork.framework/Headers/FBAdSize.h b/Frameworks/FBAudienceNetwork.framework/Headers/FBAdSize.h new file mode 100644 index 0000000..3ad9e18 --- /dev/null +++ b/Frameworks/FBAudienceNetwork.framework/Headers/FBAdSize.h @@ -0,0 +1,67 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +#import "FBAdDefines.h" + +/*! + @typedef FBAdSize + + @abstract + Represents the ad size. + */ +typedef struct FBAdSize { + CGSize size; +} FBAdSize; + +/*! + @abstract DEPRECATED - Represents the fixed banner ad size - 320pt by 50pt. + */ +FB_EXPORT FBAdSize const kFBAdSize320x50; + +/*! + @abstract Represents the flexible banner ad size, where banner width depends on + its container width, and banner height is fixed as 50pt. + */ +FB_EXPORT FBAdSize const kFBAdSizeHeight50Banner; + +/*! + @abstract Represents the flexible banner ad size, where banner width depends on + its container width, and banner height is fixed as 90pt. + */ +FB_EXPORT FBAdSize const kFBAdSizeHeight90Banner; + +/*! + @abstract Represents the interstitial ad size. + */ +FB_EXPORT FBAdSize const kFBAdSizeInterstital; + +/*! + @abstract Represents the flexible rectangle ad size, where width depends on + its container width, and height is fixed as 250pt. + */ +FB_EXPORT FBAdSize const kFBAdSizeHeight250Rectangle; + +FB_CLASS_EXPORT +@interface FBAdCustomSize : NSObject + ++ (FBAdSize)customSize:(CGSize)size; + +@end diff --git a/Frameworks/FBAudienceNetwork.framework/Headers/FBAdView.h b/Frameworks/FBAudienceNetwork.framework/Headers/FBAdView.h new file mode 100644 index 0000000..1e843d5 --- /dev/null +++ b/Frameworks/FBAudienceNetwork.framework/Headers/FBAdView.h @@ -0,0 +1,167 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +#import "FBAdDefines.h" +#import "FBAdSize.h" + +@protocol FBAdViewDelegate; + +/*! + @class FBAdView + + @abstract A customized UIView to represent a Facebook ad (a.k.a. banner ad). + */ +FB_CLASS_EXPORT +@interface FBAdView : UIView + +/*! + @method + + @abstract + This is a method to initialize an FBAdView matching the given placement id. + + @param placementID The id of the ad placement. You can create your placement id from Facebook developers page. + @param adSize The size of the ad; for example, kFBAdSizeHeight50Banner or kFBAdSizeHeight90Banner. + @param viewController The view controller that will be used to present the ad and the app store view. + */ +- (instancetype)initWithPlacementID:(NSString *)placementID + adSize:(FBAdSize)adSize + rootViewController:(UIViewController *)viewController; + +/*! + @method + + @abstract + Begins loading the FBAdView content. + + @discussion You can implement `adViewDidLoad:` and `adView:didFailWithError:` methods + of `FBAdViewDelegate` if you would like to be notified as loading succeeds or fails. + */ +- (void)loadAd; + +/*! + @method + + @abstract + This is a method to disable auto refresh for the FBAdView instance + + @discussion By default, we read the refresh interval from the placement setting in your Facebook + developers page. Once you call this method, the auto refresh will be disabled for this FBAdView + instance, and you cannot re-enable the refresh for this instance. A new created FBAdView will still + use the default behavior. + + This method is designed for ad network mediation. We still recommend you to set the placement + refresh interval as 'None' if you're using one of the ad network mediation. + */ +- (void)disableAutoRefresh; + +/*! + @property + @abstract Typed access to the id of the ad placement. + */ +@property (nonatomic, copy, readonly) NSString *placementID; +/*! + @property + @abstract Typed access to the app's root view controller. + */ +@property (nonatomic, weak, readonly) UIViewController *rootViewController; +/*! + @property + @abstract the delegate + */ +@property (nonatomic, weak) id delegate; + +@end + +/*! + @protocol + + @abstract + The methods declared by the FBAdViewDelegate protocol allow the adopting delegate to respond + to messages from the FBAdView class and thus respond to operations such as whether the ad has + been loaded, the person has clicked the ad. + */ +@protocol FBAdViewDelegate + +@optional + +/*! + @method + + @abstract + Sent after an ad has been clicked by the person. + + @param adView An FBAdView object sending the message. + */ +- (void)adViewDidClick:(FBAdView *)adView; +/*! + @method + + @abstract + When an ad is clicked, the modal view will be presented. And when the user finishes the + interaction with the modal view and dismiss it, this message will be sent, returning control + to the application. + + @param adView An FBAdView object sending the message. + */ +- (void)adViewDidFinishHandlingClick:(FBAdView *)adView; +/*! + @method + + @abstract + Sent when an ad has been successfully loaded. + + @param adView An FBAdView object sending the message. + */ +- (void)adViewDidLoad:(FBAdView *)adView; +/*! + @method + + @abstract + Sent after an FBAdView fails to load the ad. + + @param adView An FBAdView object sending the message. + @param error An error object containing details of the error. + */ +- (void)adView:(FBAdView *)adView didFailWithError:(NSError *)error; + +/*! + @method + + @abstract + Sent immediately before the impression of an FBAdView object will be logged. + + @param adView An FBAdView object sending the message. + */ +- (void)adViewWillLogImpression:(FBAdView *)adView; + +/*! + @method + + @abstract + Asks the delegate for a view controller to present modal content, such as the in-app + browser that can appear when an ad is clicked. + + @return A view controller that is used to present modal content. + */ +- (UIViewController *)viewControllerForPresentingModalView; + +@end diff --git a/Frameworks/FBAudienceNetwork.framework/Headers/FBAudienceNetwork.h b/Frameworks/FBAudienceNetwork.framework/Headers/FBAudienceNetwork.h new file mode 100644 index 0000000..b237422 --- /dev/null +++ b/Frameworks/FBAudienceNetwork.framework/Headers/FBAudienceNetwork.h @@ -0,0 +1,33 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#define FB_AD_SDK_VERSION @"4.2.0" diff --git a/Frameworks/FBAudienceNetwork.framework/Headers/FBInterstitialAd.h b/Frameworks/FBAudienceNetwork.framework/Headers/FBInterstitialAd.h new file mode 100644 index 0000000..da67ce6 --- /dev/null +++ b/Frameworks/FBAudienceNetwork.framework/Headers/FBInterstitialAd.h @@ -0,0 +1,168 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +#import "FBAdDefines.h" +#import "FBAdView.h" + +@protocol FBInterstitialAdDelegate; + +/*! + @class FBInterstitialAd + + @abstract A modal view controller to represent a Facebook interstitial ad. This + is a full-screen ad shown in your application. + */ +FB_CLASS_EXPORT +@interface FBInterstitialAd : UIViewController + +/*! + @property + @abstract Typed access to the id of the ad placement. + */ +@property (nonatomic, copy, readonly) NSString *placementID; +/*! + @property + @abstract the delegate + */ +@property (nonatomic, weak) id delegate; + +/*! + @method + + @abstract + This is a method to initialize an FBInterstitialAd matching the given placement id. + + @param placementID The id of the ad placement. You can create your placement id from Facebook developers page. + */ +- (instancetype)initWithPlacementID:(NSString *)placementID; + +/*! + @property + + @abstract + Returns true if the interstitial ad has been successfully loaded. + + @discussion You should check `isAdValid` before trying to show the ad. + */ +@property (nonatomic, getter=isAdValid, readonly) BOOL adValid; + +/*! + @method + + @abstract + Begins loading the FBInterstitialAd content. + + @discussion You can implement `interstitialAdDidLoad:` and `interstitialAd:didFailWithError:` methods + of `FBInterstitialAdDelegate` if you would like to be notified as loading succeeds or fails. + */ +- (void)loadAd; + +/*! + @method + + @abstract + Presents the interstitial ad modally from the specified view controller. + + @param rootViewController The view controller that will be used to present the interstitial ad. + + @discussion You can implement `interstitialAdDidClick:`, `interstitialAdWillClose:` and `interstitialAdWillClose` + methods of `FBInterstitialAdDelegate` if you would like to stay informed for thoses events + */ +- (BOOL)showAdFromRootViewController:(UIViewController *)rootViewController; + +@end + +/*! + @protocol + + @abstract + The methods declared by the FBInterstitialAdDelegate protocol allow the adopting delegate to respond + to messages from the FBInterstitialAd class and thus respond to operations such as whether the + interstitial ad has been loaded, user has clicked or closed the interstitial. + */ +@protocol FBInterstitialAdDelegate + +@optional + +/*! + @method + + @abstract + Sent after an ad in the FBInterstitialAd object is clicked. The appropriate app store view or + app browser will be launched. + + @param interstitialAd An FBInterstitialAd object sending the message. + */ +- (void)interstitialAdDidClick:(FBInterstitialAd *)interstitialAd; + +/*! + @method + + @abstract + Sent after an FBInterstitialAd object has been dismissed from the screen, returning control + to your application. + + @param interstitialAd An FBInterstitialAd object sending the message. + */ +- (void)interstitialAdDidClose:(FBInterstitialAd *)interstitialAd; + +/*! + @method + + @abstract + Sent immediately before an FBInterstitialAd object will be dismissed from the screen. + + @param interstitialAd An FBInterstitialAd object sending the message. + */ +- (void)interstitialAdWillClose:(FBInterstitialAd *)interstitialAd; + +/*! + @method + + @abstract + Sent when an FBInterstitialAd successfully loads an ad. + + @param interstitialAd An FBInterstitialAd object sending the message. + */ +- (void)interstitialAdDidLoad:(FBInterstitialAd *)interstitialAd; + +/*! + @method + + @abstract + Sent when an FBInterstitialAd failes to load an ad. + + @param interstitialAd An FBInterstitialAd object sending the message. + @param error An error object containing details of the error. + */ +- (void)interstitialAd:(FBInterstitialAd *)interstitialAd didFailWithError:(NSError *)error; + +/*! + @method + + @abstract + Sent immediately before the impression of an FBInterstitialAd object will be logged. + + @param interstitialAd An FBInterstitialAd object sending the message. + */ +- (void)interstitialAdWillLogImpression:(FBInterstitialAd *)interstitialAd; + +@end diff --git a/Frameworks/FBAudienceNetwork.framework/Headers/FBMediaView.h b/Frameworks/FBAudienceNetwork.framework/Headers/FBMediaView.h new file mode 100644 index 0000000..8619c7b --- /dev/null +++ b/Frameworks/FBAudienceNetwork.framework/Headers/FBMediaView.h @@ -0,0 +1,73 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBAdDefines.h" + +@protocol FBMediaViewDelegate; +@class FBNativeAd; + +/*! + @class FBNativeAd + + @abstract + The FBMediaView loads media content from a given FBNativeAd. This view takes the place of manually loading a cover image. + */ +FB_CLASS_EXPORT +@interface FBMediaView : UIView + +/*! + @property + @abstract the delegate + */ +@property (nonatomic, weak) id delegate; + +/*! + @method + @abstract + This is a method to create a media view using the given native ad. + @param nativeAd The native ad to load media content from. + */ +- (instancetype)initWithNativeAd:(FBNativeAd *)nativeAd; + +@property (nonatomic, strong) FBNativeAd *nativeAd; + +@end + +/*! + @protocol + + @abstract + The methods declared by the FBMediaViewDelegate protocol allow the adopting delegate to respond to messages from the FBMediaView class and thus respond to operations such as whether the media content has been loaded. + */ +@protocol FBMediaViewDelegate + +@optional + +/*! + @method + + @abstract + Sent when an FBMediaView has been successfully loaded. + + @param mediaView An FBMediaView object sending the message. + */ +- (void)mediaViewDidLoad:(FBMediaView *)mediaView; + +@end diff --git a/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAd.h b/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAd.h new file mode 100644 index 0000000..9864c67 --- /dev/null +++ b/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAd.h @@ -0,0 +1,335 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBAdDefines.h" + +@protocol FBNativeAdDelegate; +@class FBAdImage; + +typedef NS_ENUM(NSInteger, FBNativeAdsCachePolicy) { + FBNativeAdsCachePolicyNone = 0, + FBNativeAdsCachePolicyIcon = 0x1, + FBNativeAdsCachePolicyCoverImage = 0x2, + FBNativeAdsCachePolicyAll = FBNativeAdsCachePolicyCoverImage | FBNativeAdsCachePolicyIcon, +}; + +/*! + @class FBNativeAd + + @abstract + The FBNativeAd represents ad metadata to allow you to construct custom ad views. + See the NativeAdSample in the sample apps section of the Audience Network framework. + */ +FB_CLASS_EXPORT +@interface FBNativeAd : NSObject + +/*! + @property + @abstract Typed access to the id of the ad placement. + */ +@property (nonatomic, copy, readonly) NSString *placementID; +/*! + @property + @abstract Typed access to the ad star rating. See `FBAdStarRating` for details. + */ +@property (nonatomic, assign, readonly) struct FBAdStarRating starRating; +/*! + @property + @abstract Typed access to the ad title. + */ +@property (nonatomic, copy, readonly) NSString *title; +/*! + @property + @abstract Typed access to the ad subtitle. + */ +@property (nonatomic, copy, readonly) NSString *subtitle; +/*! + @property + @abstract Typed access to the ad social context, for example "Over half a million users". + */ +@property (nonatomic, copy, readonly) NSString *socialContext; +/*! + @property + @abstract Typed access to the call to action phrase of the ad, for example "Install Now". + */ +@property (nonatomic, copy, readonly) NSString *callToAction; +/*! + @property + @abstract Typed access to the ad icon. See `FBAdImage` for details. + */ +@property (nonatomic, strong, readonly) FBAdImage *icon; +/*! + @property + @abstract Typed access to the ad cover image creative. See `FBAdImage` for details. + */ +@property (nonatomic, strong, readonly) FBAdImage *coverImage; +/*! + @property + @abstract Typed access to the body text, usually a longer description of the ad. + */ +@property (nonatomic, copy, readonly) NSString *body; +/*! + @property + + @abstract Set the native ad caching policy. This controls which media from the native ad are cached before the native ad calls nativeAdLoaded on its delegate. The default is to not block on caching. + */ +@property (nonatomic, assign) FBNativeAdsCachePolicy mediaCachePolicy; +/*! + @property + @abstract the delegate + */ +@property (nonatomic, weak) id delegate; + +/*! + @method + + @abstract + This is a method to initialize a FBNativeAd object matching the given placement id. + + @param placementID The id of the ad placement. You can create your placement id from Facebook developers page. + */ +- (instancetype)initWithPlacementID:(NSString *)placementID NS_DESIGNATED_INITIALIZER; + +/*! + @method + + @abstract + This is a method to associate a FBNativeAd with the UIView you will use to display the native ads. + + @param view The UIView you created to render all the native ads data elements. + @param viewController The UIViewController that will be used to present SKStoreProductViewController + (iTunes Store product information) or the in-app browser. + + @discussion The whole area of the UIView will be clickable. + */ +- (void)registerViewForInteraction:(UIView *)view + withViewController:(UIViewController *)viewController; + +/*! + @method + + @abstract + This is a method to associate FBNativeAd with the UIView you will use to display the native ads + and set clickable areas. + + @param view The UIView you created to render all the native ads data elements. + @param viewController The UIViewController that will be used to present SKStoreProductViewController + (iTunes Store product information). + @param clickableViews An array of UIView you created to render the native ads data element, e.g. + CallToAction button, Icon image, which you want to specify as clickable. + */ +- (void)registerViewForInteraction:(UIView *)view + withViewController:(UIViewController *)viewController + withClickableViews:(NSArray *)clickableViews; + +/*! + @method + + @abstract + This is a method to disconnect a FBNativeAd with the UIView you used to display the native ads. + */ +- (void)unregisterView; + +/*! + @method + + @abstract + Begins loading the FBNativeAd content. + + @discussion You can implement `nativeAdDidLoad:` and `nativeAd:didFailWithError:` methods + of `FBNativeAdDelegate` if you would like to be notified as loading succeeds or fails. + */ +- (void)loadAd; + +/*! + @property + + @abstract + Call isAdValid to check whether native ad is valid & internal consistent prior rendering using its properties. If + rendering is done as part of the loadAd callback, it is guarantee to be consistent + */ +@property (nonatomic, getter=isAdValid, readonly) BOOL adValid; + +@end + +/*! + @protocol + + @abstract + The methods declared by the FBNativeAdDelegate protocol allow the adopting delegate to respond to messages + from the FBNativeAd class and thus respond to operations such as whether the native ad has been loaded. + */ +@protocol FBNativeAdDelegate + +@optional + +/*! + @method + + @abstract + Sent when an FBNativeAd has been successfully loaded. + + @param nativeAd An FBNativeAd object sending the message. + */ +- (void)nativeAdDidLoad:(FBNativeAd *)nativeAd; + +/*! + @method + + @abstract + Sent immediately before the impression of an FBNativeAd object will be logged. + + @param nativeAd An FBNativeAd object sending the message. + */ +- (void)nativeAdWillLogImpression:(FBNativeAd *)nativeAd; + +/*! + @method + + @abstract + Sent when an FBNativeAd is failed to load. + + @param nativeAd An FBNativeAd object sending the message. + @param error An error object containing details of the error. + */ +- (void)nativeAd:(FBNativeAd *)nativeAd didFailWithError:(NSError *)error; + +/*! + @method + + @abstract + Sent after an ad has been clicked by the person. + + @param nativeAd An FBNativeAd object sending the message. + */ +- (void)nativeAdDidClick:(FBNativeAd *)nativeAd; + +/*! + @method + + @abstract + When an ad is clicked, the modal view will be presented. And when the user finishes the + interaction with the modal view and dismiss it, this message will be sent, returning control + to the application. + + @param nativeAd An FBNativeAd object sending the message. + */ +- (void)nativeAdDidFinishHandlingClick:(FBNativeAd *)nativeAd; + +@end + +/*! + @class FBAdStarRating + + @abstract + Represents the Facebook ad star rating, which contains the rating value and rating scale. + */ +FB_EXPORT struct FBAdStarRating { + CGFloat value; + NSInteger scale; +} FBAdStarRating; + +/*! + @class FBAdImage + + @abstract Represents an image creative. + */ +FB_CLASS_EXPORT +@interface FBAdImage : NSObject + +/*! + @property + @abstract Typed access to the image url. + */ +@property (nonatomic, copy, readonly) NSURL *url; +/*! + @property + @abstract Typed access to the image width. + */ +@property (nonatomic, assign, readonly) NSInteger width; +/*! + @property + @abstract Typed access to the image height. + */ +@property (nonatomic, assign, readonly) NSInteger height; + +/*! + @method + + @abstract + This is a method to initialize an FBAdImage. + + @param url the image url. + @param width the image width. + @param height the image height. + */ +- (instancetype)initWithURL:(NSURL *)url width:(NSInteger)width height:(NSInteger)height NS_DESIGNATED_INITIALIZER; + +/*! + @method + + @abstract + Loads an image from self.url over the network, or returns the cached image immediately. + + @param block Block to handle the loaded image. + */ +- (void)loadImageAsyncWithBlock:(void (^)(UIImage * image))block; + +@end + +/*! + @class FBAdStarRatingView + + @abstract + Helper view that draws a star rating based off a native ad. + */ +FB_CLASS_EXPORT +@interface FBAdStarRatingView : UIView + +/*! + @property + @abstract The current rating from an FBNativeAd. When set, updates the view. + */ +@property (nonatomic) struct FBAdStarRating rating; + +/*! + @property + @abstract The color drawn for filled-in stars. Defaults to yellow. + */ +@property (strong, nonatomic) UIColor *primaryColor; + +/*! + @property + @abstract The color drawn for empty stars. Defaults to gray. + */ +@property (strong, nonatomic) UIColor *secondaryColor; + +/*! + @method + + @abstract + Initializes a star rating view with a given frame and star rating. + + @param frame Frame of this view. + @param starRating Star rating from a native ad. + */ +- (instancetype)initWithFrame:(CGRect)frame withStarRating:(struct FBAdStarRating)starRating NS_DESIGNATED_INITIALIZER; + +@end diff --git a/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAdScrollView.h b/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAdScrollView.h new file mode 100644 index 0000000..91371dc --- /dev/null +++ b/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAdScrollView.h @@ -0,0 +1,118 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBAdDefines.h" +#import "FBNativeAdView.h" +#import "FBNativeAdsManager.h" + +@protocol FBNativeAdView; + +/*! + @class FBNativeAdScrollView + @abstract Contains multiple ads in a scroll view. + @discussion + If adding this view to a XIB or Storyboard, you may recieve the error "Unknown class FBNativeAdScrollView in Interface Builder file" in some cases. This error is caused by the linker failing to include FBNativeAdScrollView in your build. To resolve this, call [FBNativeAdScrollView class] in your project, or add "-all_load -ObjC" to "Other Linker Flags" in your project settings. + */ +FB_CLASS_EXPORT +@interface FBNativeAdScrollView : UIView + +/*! + @property + @abstract Maximum native ads that this scroll view will load. Defaults to 5. If changed after calling loadAds, all current ads will be discarded and loadAds must be called again. + */ +@property (nonatomic, assign, readonly) NSUInteger maximumNativeAdCount; + +/*! + @property + @abstract Toggles animating the loaded views. Default is YES. + */ +@property (nonatomic, assign, getter=isAnimationEnabled) BOOL animationEnabled; + +/*! + @property + @abstract Horizontal inset for views in the scroll view. Defaults to 8 points. + */ +@property (nonatomic, assign) CGFloat xInset; + +/*! + @property + @abstract Reloads the same ads for the same manager. Default is NO. + */ +@property (nonatomic, assign, getter=isAdPersistenceEnabled) BOOL adPersistenceEnabled; + +/*! + @property + @abstract A view controller that is used to present modal content. If nil, the view searches for a view controller. + */ +@property (nonatomic, weak) UIViewController *viewController; + +/*! + @property + @abstract Passes delegate methods from FBNativeAd. Separate delegate calls will be made for each native ad contained. + */ +@property (nonatomic, weak) id delegate; + +/*! + @method + @abstract Creates a native ad horizontal scroll view for a given native ads manager and native ad template. The manager can be preloaded with ads, and loadAds will use the preloaded ads from the manager. Otherwise, the scroll view uses the manager to load ads normally. + @param manager An instance of FBNativeAdManager. Can be preloaded with ads. + @param type The type of this native ad template. For more information, consult FBNativeAdViewType. + */ +- (instancetype)initWithNativeAdsManager:(FBNativeAdsManager *)manager withType:(FBNativeAdViewType)type; + + +/*! + @method + @abstract Creates a native ad horizontal scroll view for a given native ads manager and native ad template. The manager can be preloaded with ads, and loadAds will use the preloaded ads from the manager. Otherwise, the scroll view uses the manager to load ads normally. + @param manager An instance of FBNativeAdManager. Can be preloaded with ads. + @param type The type of this native ad template. For more information, consult FBNativeAdViewType. + @param attributes The layout of this native ad template. For more information, consult FBNativeAdViewLayout. + */ +- (instancetype)initWithNativeAdsManager:(FBNativeAdsManager *)manager withType:(FBNativeAdViewType)type withAttributes:(FBNativeAdViewAttributes *)attributes; + +/*! + @method + @abstract Creates a native ad horizontal scroll view for a given native ads manager and native ad template. The manager can be preloaded with ads, and loadAds will use the preloaded ads from the manager. Otherwise, the scroll view uses the manager to load ads normally. + @param manager An instance of FBNativeAdManager. Can be preloaded with ads. + @param type The type of this native ad template. For more information, consult FBNativeAdViewType. + @param attributes The layout of this native ad template. For more information, consult FBNativeAdViewLayout. + @param maximumNativeAdCount Maximum native ads to show at once. + */ +- (instancetype)initWithNativeAdsManager:(FBNativeAdsManager *)manager withType:(FBNativeAdViewType)type withAttributes:(FBNativeAdViewAttributes *)attributes withMaximum:(NSUInteger)maximumNativeAdCount; + + +/*! + @method + @abstract This is a method to create a native ad horizontal scroll view from a user provided view. + @param manager An instance of FBNativeAdManager. Can be preloaded with ads. + @param childViewProvider Block that creates new views for each loaded native ad. Must not reuse the same instance, but return a new view for each call. Views may be arbitrarily resized and should support resizing their content through Auto Layout constraints, autoresizing masks, or manual resizing. + */ +- (instancetype)initWithNativeAdsManager:(FBNativeAdsManager *)manager withViewProvider:(UIView *(^)(FBNativeAd *nativeAd, NSUInteger position))childViewProvider; + +/*! + @method + @abstract This is a method to create a native ad horizontal scroll view from a user provided view. + @param manager An instance of FBNativeAdManager. Can be preloaded with ads. + @param childViewProvider Block that creates new views for each loaded native ad. Must not reuse the same instance, but return a new view for each call. Views may be arbitrarily resized and should support resizing their content through Auto Layout constraints, autoresizing masks, or manual resizing. + @param maximumNativeAdCount Maximum native ads to show at once. + */ +- (instancetype)initWithNativeAdsManager:(FBNativeAdsManager *)manager withViewProvider:(UIView *(^)(FBNativeAd *nativeAd, NSUInteger position))childViewProvider withMaximum:(NSUInteger)maximumNativeAdCount; + +@end diff --git a/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAdTableViewAdProvider.h b/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAdTableViewAdProvider.h new file mode 100644 index 0000000..7e01c9d --- /dev/null +++ b/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAdTableViewAdProvider.h @@ -0,0 +1,93 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +#import "FBAdDefines.h" +#import "FBNativeAd.h" +#import "FBNativeAdsManager.h" + +/*! + @class FBNativeAdTableViewAdProvider + + @abstract Additional functionality on top of FBNativeAdsManager to assist in using native ads within a UITableView. This class contains a mechanism to map indexPaths to native ads in a stable manner as well as helpers which assist in doing the math to include ads at a regular interval within a table view. + */ +FB_CLASS_EXPORT +@interface FBNativeAdTableViewAdProvider : NSObject + +/*! + @property + @abstract Passes delegate methods from FBNativeAd. Separate delegate calls will be made for each native ad contained. + */ +@property (nonatomic, weak) id delegate; + +/*! + @method + + @abstract Create a FBNativeAdTableViewAdProvider. + + @param manager The FBNativeAdsManager which is consumed by this class. + */ +- (instancetype)initWithManager:(FBNativeAdsManager *)manager; + +/*! + @method + + @abstract Retrieve a native ad for an indexPath, will return the same ad for a given indexPath until the native ads manager is refreshed. This method is intended for usage with a table view and specifically the caller is recommended to wait until tableView:cellForRowAtIndexPath: to ensure getting the best native ad for the given table cell. + + @param tableView The tableView where native ad will be used + @param indexPath The indexPath to use as a key for this native ad + @return A FBNativeAd which is loaded and ready to be used. + */ +- (FBNativeAd *)tableView:(UITableView *)tableView nativeAdForRowAtIndexPath:(NSIndexPath *)indexPath; + +/*! + @method + + @abstract Support for evenly distributed native ads within a table view. Computes whether this cell is an ad or not. + + @param indexPath The indexPath of the cell within the table view + @param stride The frequency that native ads are to appear within the table view + @return Boolean indicating whether the cell at the path is an ad + */ +- (BOOL)isAdCellAtIndexPath:(NSIndexPath *)indexPath forStride:(NSUInteger)stride; + +/*! + @method + + @abstract Support for evenly distributed native ads within a table view. Adjusts a non-ad cell indexPath to the indexPath it would be in a collection with no ads. + + @param indexPath The indexPath to of the non-ad cell + @param stride The frequency that native ads are to appear within the table view + @return An indexPath adjusted to what it would be in a table view with no ads + */ +- (NSIndexPath *)adjustNonAdCellIndexPath:(NSIndexPath *)indexPath forStride:(NSUInteger)stride; + +/*! + @method + + @abstract Support for evenly distributed native ads within a table view. Adjusts the total count of cells within the table view to account for the ad cells. + + @param count The count of cells in the table view not including ads + @param stride The frequency that native ads are to appear within the table view + @return The total count of cells within the table view including both ad and non-ad cells + */ +- (NSUInteger)adjustCount:(NSUInteger)count forStride:(NSUInteger)stride; + +@end diff --git a/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAdTableViewCellProvider.h b/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAdTableViewCellProvider.h new file mode 100644 index 0000000..cf9aac0 --- /dev/null +++ b/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAdTableViewCellProvider.h @@ -0,0 +1,78 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +#import "FBAdDefines.h" +#import "FBNativeAd.h" +#import "FBNativeAdTableViewAdProvider.h" +#import "FBNativeAdView.h" +#import "FBNativeAdsManager.h" + +/*! + @class FBNativeAdTableViewCellProvider + + @abstract Class which assists in putting FBNativeAdViews into UITableViews. This class manages the creation of UITableViewCells which host native ad views. Functionality is provided to create UITableCellViews as needed for a given indexPath as well as computing the height of the cells. + */ +FB_CLASS_EXPORT +@interface FBNativeAdTableViewCellProvider : FBNativeAdTableViewAdProvider + +/*! + @method + + @abstract Method to create a FBNativeAdTableViewCellProvider. + + @param manager The naitve ad manager consumed by this provider + @param type The type of this native ad template. For more information, consult FBNativeAdViewType. + */ +- (instancetype)initWithManager:(FBNativeAdsManager *)manager forType:(FBNativeAdViewType)type; + +/*! + @method + + @abstract Method to create a FBNativeAdTableViewCellProvider. + + @param manager The naitve ad manager consumed by this provider + @param type The type of this native ad template. For more information, consult FBNativeAdViewType. + @param attributes The layout of this native ad template. For more information, consult FBNativeAdViewLayout. + */ +- (instancetype)initWithManager:(FBNativeAdsManager *)manager forType:(FBNativeAdViewType)type forAttributes:(FBNativeAdViewAttributes *)attributes; + +/*! + @method + + @abstract Helper method for implementors of UITableViewDataSource who would like to host native ad UITableViewCells in their table view. + */ +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; + +/*! + @method + + @abstract Helper method for implementors of UITableViewDelegate who would like to host native ad UITableViewCells in their table view. + */ +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; + +/*! + @method + + @abstract Helper method for implementors of UITableViewDelegate who would like to host native ad UITableViewCells in their table view. + */ +- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath; + +@end diff --git a/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAdView.h b/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAdView.h new file mode 100644 index 0000000..746cb01 --- /dev/null +++ b/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAdView.h @@ -0,0 +1,151 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBAdDefines.h" +#import "FBNativeAd.h" + +@class FBNativeAdViewAttributes; + +/*! + @enum FBNativeAdViewType enum + @abstract Determines the type of native ad template. Different views are created + for different values of FBNativeAdViewType + */ +typedef NS_ENUM(NSInteger, FBNativeAdViewType) { + FBNativeAdViewTypeGenericHeight100 = 1, + FBNativeAdViewTypeGenericHeight120, + FBNativeAdViewTypeGenericHeight300, + FBNativeAdViewTypeGenericHeight400, +}; + +/*! + @class FBNativeAdView + + @abstract + The FBNativeAdView creates prebuilt native ad template views and manages native ads. + */ +FB_CLASS_EXPORT +@interface FBNativeAdView : UIView + +/*! + @property + @abstract The type of the view, specifies which template to use + */ +@property (nonatomic, assign, readonly) FBNativeAdViewType type; + +/*! + @method + @abstract + This is a method to create a native ad template using the given placement id and type. + @param nativeAd The native ad to use to create this view. + @param type The type of this native ad template. For more information, consult FBNativeAdViewType. + */ ++ (instancetype)nativeAdViewWithNativeAd:(FBNativeAd *)nativeAd withType:(FBNativeAdViewType)type; + +/*! + @property + @abstract A view controller that is used to present modal content. If nil, the view searches for a view controller. + */ +@property (nonatomic, weak) UIViewController *viewController; + +/*! + @method + @abstract + This is a method to create a native ad template using the given placement id and type. + @param nativeAd The native ad to use to create this view. + @param type The type of this native ad template. For more information, consult FBNativeAdViewType. + @param attributes The attributes to render this native ad template with. + */ ++ (instancetype)nativeAdViewWithNativeAd:(FBNativeAd *)nativeAd withType:(FBNativeAdViewType)type withAttributes:(FBNativeAdViewAttributes *)attributes; + +@end + +/*! + @class FBNativeAdViewLayout + @abstract + Describes the look and feel of a native ad view. + */ +@interface FBNativeAdViewAttributes : NSObject + +/*! + @property + @abstract + Background color of the native ad view. + */ +@property (nonatomic, copy) UIColor *backgroundColor; +/*! + @property + @abstract + Color of the title label. + */ +@property (nonatomic, copy) UIColor *titleColor; +/*! + @property + @abstract + Font of the title label. + */ +@property (nonatomic, copy) UIFont *titleFont; +/*! + @property + @abstract + Color of the description label. + */ +@property (nonatomic, copy) UIColor *descriptionColor; +/*! + @property + @abstract + Font of the description label. + */ +@property (nonatomic, copy) UIFont *descriptionFont; +/*! + @property + @abstract + Background color of the call to action button. + */ +@property (nonatomic, copy) UIColor *buttonColor; +/*! + @property + @abstract + Color of the call to action button's title label. + */ +@property (nonatomic, copy) UIColor *buttonTitleColor; +/*! + @property + @abstract + Font of the call to action button's title label. + */ +@property (nonatomic, copy) UIFont *buttonTitleFont; +/*! + @property + @abstract + Border color of the call to action button. If nil, no border is shown. + */ +@property (nonatomic, copy) UIColor *buttonBorderColor; + +/*! + @method + @abstract + Returns default attributes for a given type. + + @param type The type for this layout. + */ ++ (instancetype)defaultAttributesForType:(FBNativeAdViewType)type; + +@end diff --git a/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAdsManager.h b/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAdsManager.h new file mode 100644 index 0000000..cfe331c --- /dev/null +++ b/Frameworks/FBAudienceNetwork.framework/Headers/FBNativeAdsManager.h @@ -0,0 +1,118 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBAdDefines.h" +#import "FBNativeAd.h" + +/*! + @protocol FBNativeAdsManagerDelegate + + @abstract Messages from FBNativeAdsManager indicating success or failure loading ads. + */ +@protocol FBNativeAdsManagerDelegate + +/*! + @method + + @abstract When the FBNativeAdsManager has finished loading a batch of ads this message will be sent. A batch of ads may be loaded in response to calling loadAds or due to an automatic refresh by the FBNativeAdsManager. At the point this message is fired all of the native ads will already be loaded and will not hence send their own nativeAdLoad: or nativeAd:didFailWithError: message. + + */ +- (void)nativeAdsLoaded; + +/*! + @method + + @abstract When the FBNativeAdsManager has reached a failure while attempting to load a batch of ads this message will be sent to the application. + @param error An NSError object with information about the failure. + */ +- (void)nativeAdsFailedToLoadWithError:(NSError *)error; + +@end + +/*! + @class FBNativeAdsManager + + @abstract This class provides a mechanism to fetch a set of ads and then use them within your application. The recommended usage is to call nextNativeAd: at the moment when you are about to render an ad. The native ads manager supports giving out as many ads as needed by cloning over the set of ads it got back from the server which can be useful for feed scenarios. + */ +FB_CLASS_EXPORT +@interface FBNativeAdsManager : NSObject + +/*! + @property + + @abstract The delegate + */ +@property (nonatomic, weak) id delegate; + +/*! + @property + + @abstract Set the native ads manager caching policy. This controls which media from the native ads are cached before the native ads manager calls nativeAdsLoaded on its delegate. The default is to not block on caching. + */ +@property (nonatomic, assign) FBNativeAdsCachePolicy mediaCachePolicy; + +/*! + @property + + @abstract Number of unique native ads that can be accessed through nextNativeAd:. This is not valid until the nativeAdsLoaded: message has been sent. + */ +@property (nonatomic, assign, readonly) NSUInteger uniqueNativeAdCount; + +/*! + @property + + @abstract Returns YES after nativeAdsLoaded: message has been sent. + */ +@property (nonatomic, assign, getter=isValid, readonly) BOOL valid; + +/*! + @method + + @abstract Initialize the native ads manager. + + @param placementID The id of the ad placement. You can create your placement id from Facebook developers page. + @param numAdsRequested The number of ads you would like the native ads manager to retrieve. + */ +- (instancetype)initWithPlacementID:(NSString *)placementID + forNumAdsRequested:(NSUInteger)numAdsRequested; + +/*! + @method + + @abstract The method that kicks off the loading of ads. It may be called again in the future to refresh the ads manually. + */ +- (void)loadAds; + +/*! + @method + + @abstract By default the native ads manager will refresh its ads periodically. This does not mean that any ads which are shown in the application's UI will be refreshed but simply that calling nextNativeAd: may return different ads at different times. This method disables that functionality. + */ +- (void)disableAutoRefresh; + + +/*! + @method + + @abstract Retrieve the next native ad to be used from the batch. It is highly recommended that the caller wait until immediately before rendering the ad content to call this method to ensure the best ad for the given context is used. If more than uniqueNativeAdCount ads are requested cloned ads will be returned. Periodically the native ads manager will refresh and new ads will be returned. + + @return A FBNativeAd which is loaded and ready to be used. + */ +- (FBNativeAd *)nextNativeAd; + +@end diff --git a/Frameworks/FBAudienceNetwork.framework/Info.plist b/Frameworks/FBAudienceNetwork.framework/Info.plist new file mode 100644 index 0000000..4cdf7db Binary files /dev/null and b/Frameworks/FBAudienceNetwork.framework/Info.plist differ diff --git a/Frameworks/FBAudienceNetwork.framework/Modules/module.modulemap b/Frameworks/FBAudienceNetwork.framework/Modules/module.modulemap new file mode 100644 index 0000000..b0a3468 --- /dev/null +++ b/Frameworks/FBAudienceNetwork.framework/Modules/module.modulemap @@ -0,0 +1,17 @@ +framework module FBAudienceNetwork { + umbrella header "FBAudienceNetwork.h" + + export * + module * { + export * + } + + link framework "AdSupport" + link framework "CoreGraphics" + link framework "CoreImage" + link framework "CoreMotion" + link framework "Foundation" + link framework "Security" + link framework "StoreKit" + link framework "UIKit" +} diff --git a/Frameworks/FBSDKCoreKit.framework/FBSDKCoreKit b/Frameworks/FBSDKCoreKit.framework/FBSDKCoreKit new file mode 100644 index 0000000..a5cb1f7 Binary files /dev/null and b/Frameworks/FBSDKCoreKit.framework/FBSDKCoreKit differ diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKAccessToken.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKAccessToken.h new file mode 100644 index 0000000..c364cf2 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKAccessToken.h @@ -0,0 +1,159 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import +#import + +/*! + @abstract Notification indicating that the `currentAccessToken` has changed. + @discussion the userInfo dictionary of the notification will contain keys + `FBSDKAccessTokenChangeOldKey` and + `FBSDKAccessTokenChangeNewKey`. + */ +FBSDK_EXTERN NSString *const FBSDKAccessTokenDidChangeNotification; + +/*! + @abstract A key in the notification's userInfo that will be set + if and only if the user ID changed between the old and new tokens. + @discussion Token refreshes can occur automatically with the SDK + which do not change the user. If you're only interested in user + changes (such as logging out), you should check for the existence + of this key. The value is a NSNumber with a boolValue. + */ +FBSDK_EXTERN NSString *const FBSDKAccessTokenDidChangeUserID; + +/* + @abstract key in notification's userInfo object for getting the old token. + @discussion If there was no old token, the key will not be present. + */ +FBSDK_EXTERN NSString *const FBSDKAccessTokenChangeOldKey; + +/* + @abstract key in notification's userInfo object for getting the new token. + @discussion If there is no new token, the key will not be present. + */ +FBSDK_EXTERN NSString *const FBSDKAccessTokenChangeNewKey; + + +/*! + @class FBSDKAccessToken + @abstract Represents an immutable access token for using Facebook services. + */ +@interface FBSDKAccessToken : NSObject + +/*! + @abstract Returns the app ID. + */ +@property (readonly, copy, nonatomic) NSString *appID; + +/*! + @abstract Returns the known declined permissions. + */ +@property (readonly, copy, nonatomic) NSSet *declinedPermissions; + +/*! + @abstract Returns the expiration date. + */ +@property (readonly, copy, nonatomic) NSDate *expirationDate; + +/*! + @abstract Returns the known granted permissions. + */ +@property (readonly, copy, nonatomic) NSSet *permissions; + +/*! + @abstract Returns the date the token was last refreshed. +*/ +@property (readonly, copy, nonatomic) NSDate *refreshDate; + +/*! + @abstract Returns the opaque token string. + */ +@property (readonly, copy, nonatomic) NSString *tokenString; + +/*! + @abstract Returns the user ID. + */ +@property (readonly, copy, nonatomic) NSString *userID; + +/*! + @abstract Initializes a new instance. + @param tokenString the opaque token string. + @param permissions the granted permissions. Note this is converted to NSSet and is only + an NSArray for the convenience of literal syntax. + @param declinedPermissions the declined permissions. Note this is converted to NSSet and is only + an NSArray for the convenience of literal syntax. + @param appID the app ID. + @param userID the user ID. + @param expirationDate the optional expiration date (defaults to distantFuture). + @param refreshDate the optional date the token was last refreshed (defaults to today). + @discussion This initializer should only be used for advanced apps that + manage tokens explicitly. Typical login flows only need to use `FBSDKLoginManager` + along with `+currentAccessToken`. + */ +- (instancetype)initWithTokenString:(NSString *)tokenString + permissions:(NSArray *)permissions + declinedPermissions:(NSArray *)declinedPermissions + appID:(NSString *)appID + userID:(NSString *)userID + expirationDate:(NSDate *)expirationDate + refreshDate:(NSDate *)refreshDate +NS_DESIGNATED_INITIALIZER; + +/*! + @abstract Convenience getter to determine if a permission has been granted + @param permission The permission to check. + */ +- (BOOL)hasGranted:(NSString *)permission; + +/*! + @abstract Compares the receiver to another FBSDKAccessToken + @param token The other token + @return YES if the receiver's values are equal to the other token's values; otherwise NO + */ +- (BOOL)isEqualToAccessToken:(FBSDKAccessToken *)token; + +/*! + @abstract Returns the "global" access token that represents the currently logged in user. + @discussion The `currentAccessToken` is a convenient representation of the token of the + current user and is used by other SDK components (like `FBSDKLoginManager`). + */ ++ (FBSDKAccessToken *)currentAccessToken; + +/*! + @abstract Sets the "global" access token that represents the currently logged in user. + @param token The access token to set. + @discussion This will broadcast a notification and save the token to the app keychain. + */ ++ (void)setCurrentAccessToken:(FBSDKAccessToken *)token; + +/*! + @abstract Refresh the current access token's permission state and extend the token's expiration date, + if possible. + @param completionHandler an optional callback handler that can surface any errors related to permission refreshing. + @discussion On a successful refresh, the currentAccessToken will be updated so you typically only need to + observe the `FBSDKAccessTokenDidChangeNotification` notification. + + If a token is already expired, it cannot be refreshed. + */ ++ (void)refreshCurrentAccessToken:(FBSDKGraphRequestHandler)completionHandler; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKAppEvents.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKAppEvents.h new file mode 100644 index 0000000..ecfe0c3 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKAppEvents.h @@ -0,0 +1,462 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKMacros.h" + +@class FBSDKAccessToken; +@class FBSDKGraphRequest; + +/*! @abstract NSNotificationCenter name indicating a result of a failed log flush attempt. The posted object will be an NSError instance. */ +FBSDK_EXTERN NSString *const FBSDKAppEventsLoggingResultNotification; + +/*! @abstract optional plist key ("FacebookLoggingOverrideAppID") for setting `loggingOverrideAppID` */ +FBSDK_EXTERN NSString *const FBSDKAppEventsOverrideAppIDBundleKey; + +/*! + + @typedef NS_ENUM (NSUInteger, FBSDKAppEventsFlushBehavior) + + @abstract Specifies when `FBSDKAppEvents` sends log events to the server. + + */ +typedef NS_ENUM(NSUInteger, FBSDKAppEventsFlushBehavior) +{ + + /*! Flush automatically: periodically (once a minute or every 100 logged events) and always at app reactivation. */ + FBSDKAppEventsFlushBehaviorAuto = 0, + + /*! Only flush when the `flush` method is called. When an app is moved to background/terminated, the + events are persisted and re-established at activation, but they will only be written with an + explicit call to `flush`. */ + FBSDKAppEventsFlushBehaviorExplicitOnly, + +}; + +/*! + @methodgroup Predefined event names for logging events common to many apps. Logging occurs through the `logEvent` family of methods on `FBSDKAppEvents`. + Common event parameters are provided in the `FBSDKAppEventsParameterNames*` constants. + */ + +/*! Log this event when the user has achieved a level in the app. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameAchievedLevel; + +/*! Log this event when the user has entered their payment info. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameAddedPaymentInfo; + +/*! Log this event when the user has added an item to their cart. The valueToSum passed to logEvent should be the item's price. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameAddedToCart; + +/*! Log this event when the user has added an item to their wishlist. The valueToSum passed to logEvent should be the item's price. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameAddedToWishlist; + +/*! Log this event when a user has completed registration with the app. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameCompletedRegistration; + +/*! Log this event when the user has completed a tutorial in the app. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameCompletedTutorial; + +/*! Log this event when the user has entered the checkout process. The valueToSum passed to logEvent should be the total price in the cart. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameInitiatedCheckout; + +/*! Log this event when the user has rated an item in the app. The valueToSum passed to logEvent should be the numeric rating. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameRated; + +/*! Log this event when a user has performed a search within the app. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameSearched; + +/*! Log this event when the user has spent app credits. The valueToSum passed to logEvent should be the number of credits spent. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameSpentCredits; + +/*! Log this event when the user has unlocked an achievement in the app. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameUnlockedAchievement; + +/*! Log this event when a user has viewed a form of content in the app. */ +FBSDK_EXTERN NSString *const FBSDKAppEventNameViewedContent; + +/*! + @methodgroup Predefined event name parameters for common additional information to accompany events logged through the `logEvent` family + of methods on `FBSDKAppEvents`. Common event names are provided in the `FBAppEventName*` constants. + */ + +/*! Parameter key used to specify an ID for the specific piece of content being logged about. Could be an EAN, article identifier, etc., depending on the nature of the app. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameContentID; + +/*! Parameter key used to specify a generic content type/family for the logged event, e.g. "music", "photo", "video". Options to use will vary based upon what the app is all about. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameContentType; + +/*! Parameter key used to specify currency used with logged event. E.g. "USD", "EUR", "GBP". See ISO-4217 for specific values. One reference for these is . */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameCurrency; + +/*! Parameter key used to specify a description appropriate to the event being logged. E.g., the name of the achievement unlocked in the `FBAppEventNameAchievementUnlocked` event. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameDescription; + +/*! Parameter key used to specify the level achieved in a `FBAppEventNameAchieved` event. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameLevel; + +/*! Parameter key used to specify the maximum rating available for the `FBAppEventNameRate` event. E.g., "5" or "10". */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameMaxRatingValue; + +/*! Parameter key used to specify how many items are being processed for an `FBAppEventNameInitiatedCheckout` or `FBAppEventNamePurchased` event. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameNumItems; + +/*! Parameter key used to specify whether payment info is available for the `FBAppEventNameInitiatedCheckout` event. `FBSDKAppEventParameterValueYes` and `FBSDKAppEventParameterValueNo` are good canonical values to use for this parameter. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNamePaymentInfoAvailable; + +/*! Parameter key used to specify method user has used to register for the app, e.g., "Facebook", "email", "Twitter", etc */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameRegistrationMethod; + +/*! Parameter key used to specify the string provided by the user for a search operation. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameSearchString; + +/*! Parameter key used to specify whether the activity being logged about was successful or not. `FBSDKAppEventParameterValueYes` and `FBSDKAppEventParameterValueNo` are good canonical values to use for this parameter. */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterNameSuccess; + +/* + @methodgroup Predefined values to assign to event parameters that accompany events logged through the `logEvent` family + of methods on `FBSDKAppEvents`. Common event parameters are provided in the `FBSDKAppEventParameterName*` constants. + */ + +/*! Yes-valued parameter value to be used with parameter keys that need a Yes/No value */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterValueYes; + +/*! No-valued parameter value to be used with parameter keys that need a Yes/No value */ +FBSDK_EXTERN NSString *const FBSDKAppEventParameterValueNo; + + +/*! + + @class FBSDKAppEvents + + @abstract + Client-side event logging for specialized application analytics available through Facebook App Insights + and for use with Facebook Ads conversion tracking and optimization. + + @discussion + The `FBSDKAppEvents` static class has a few related roles: + + + Logging predefined and application-defined events to Facebook App Insights with a + numeric value to sum across a large number of events, and an optional set of key/value + parameters that define "segments" for this event (e.g., 'purchaserStatus' : 'frequent', or + 'gamerLevel' : 'intermediate') + + + Logging events to later be used for ads optimization around lifetime value. + + + Methods that control the way in which events are flushed out to the Facebook servers. + + Here are some important characteristics of the logging mechanism provided by `FBSDKAppEvents`: + + + Events are not sent immediately when logged. They're cached and flushed out to the Facebook servers + in a number of situations: + - when an event count threshold is passed (currently 100 logged events). + - when a time threshold is passed (currently 15 seconds). + - when an app has gone to background and is then brought back to the foreground. + + + Events will be accumulated when the app is in a disconnected state, and sent when the connection is + restored and one of the above 'flush' conditions are met. + + + The `FBSDKAppEvents` class in thread-safe in that events may be logged from any of the app's threads. + + + The developer can set the `flushBehavior` on `FBSDKAppEvents` to force the flushing of events to only + occur on an explicit call to the `flush` method. + + + The developer can turn on console debug output for event logging and flushing to the server by using + the `FBSDKLoggingBehaviorAppEvents` value in `[FBSettings setLoggingBehavior:]`. + + Some things to note when logging events: + + + There is a limit on the number of unique event names an app can use, on the order of 300. + + There is a limit to the number of unique parameter names in the provided parameters that can + be used per event, on the order of 25. This is not just for an individual call, but for all + invocations for that eventName. + + Event names and parameter names (the keys in the NSDictionary) must be between 2 and 40 characters, and + must consist of alphanumeric characters, _, -, or spaces. + + The length of each parameter value can be no more than on the order of 100 characters. + + */ +@interface FBSDKAppEvents : NSObject + +/* + * Basic event logging + */ + +/*! + + @abstract + Log an event with just an eventName. + + @param eventName The name of the event to record. Limitations on number of events and name length + are given in the `FBSDKAppEvents` documentation. + + */ ++ (void)logEvent:(NSString *)eventName; + +/*! + + @abstract + Log an event with an eventName and a numeric value to be aggregated with other events of this name. + + @param eventName The name of the event to record. Limitations on number of events and name length + are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants. + + @param valueToSum Amount to be aggregated into all events of this eventName, and App Insights will report + the cumulative and average value of this amount. + */ ++ (void)logEvent:(NSString *)eventName + valueToSum:(double)valueToSum; + + +/*! + + @abstract + Log an event with an eventName and a set of key/value pairs in the parameters dictionary. + Parameter limitations are described above. + + @param eventName The name of the event to record. Limitations on number of events and name construction + are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants. + + @param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must + be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of + parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names + are provided in `FBSDKAppEventParameterName*` constants. + */ ++ (void)logEvent:(NSString *)eventName + parameters:(NSDictionary *)parameters; + +/*! + + @abstract + Log an event with an eventName, a numeric value to be aggregated with other events of this name, + and a set of key/value pairs in the parameters dictionary. + + @param eventName The name of the event to record. Limitations on number of events and name construction + are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants. + + @param valueToSum Amount to be aggregated into all events of this eventName, and App Insights will report + the cumulative and average value of this amount. + + @param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must + be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of + parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names + are provided in `FBSDKAppEventParameterName*` constants. + + */ ++ (void)logEvent:(NSString *)eventName + valueToSum:(double)valueToSum + parameters:(NSDictionary *)parameters; + + +/*! + + @abstract + Log an event with an eventName, a numeric value to be aggregated with other events of this name, + and a set of key/value pairs in the parameters dictionary. Providing session lets the developer + target a particular . If nil is provided, then `[FBSession activeSession]` will be used. + + @param eventName The name of the event to record. Limitations on number of events and name construction + are given in the `FBSDKAppEvents` documentation. Common event names are provided in `FBAppEventName*` constants. + + @param valueToSum Amount to be aggregated into all events of this eventName, and App Insights will report + the cumulative and average value of this amount. Note that this is an NSNumber, and a value of `nil` denotes + that this event doesn't have a value associated with it for summation. + + @param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must + be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of + parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names + are provided in `FBSDKAppEventParameterName*` constants. + + @param accessToken The optional access token to log the event as. + */ ++ (void)logEvent:(NSString *)eventName + valueToSum:(NSNumber *)valueToSum + parameters:(NSDictionary *)parameters + accessToken:(FBSDKAccessToken *)accessToken; + +/* + * Purchase logging + */ + +/*! + + @abstract + Log a purchase of the specified amount, in the specified currency. + + @param purchaseAmount Purchase amount to be logged, as expressed in the specified currency. This value + will be rounded to the thousandths place (e.g., 12.34567 becomes 12.346). + + @param currency Currency, is denoted as, e.g. "USD", "EUR", "GBP". See ISO-4217 for + specific values. One reference for these is . + + @discussion This event immediately triggers a flush of the `FBSDKAppEvents` event queue, unless the `flushBehavior` is set + to `FBSDKAppEventsFlushBehaviorExplicitOnly`. + + */ ++ (void)logPurchase:(double)purchaseAmount + currency:(NSString *)currency; + +/*! + + @abstract + Log a purchase of the specified amount, in the specified currency, also providing a set of + additional characteristics describing the purchase. + + @param purchaseAmount Purchase amount to be logged, as expressed in the specified currency.This value + will be rounded to the thousandths place (e.g., 12.34567 becomes 12.346). + + @param currency Currency, is denoted as, e.g. "USD", "EUR", "GBP". See ISO-4217 for + specific values. One reference for these is . + + @param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must + be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of + parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names + are provided in `FBSDKAppEventParameterName*` constants. + + @discussion This event immediately triggers a flush of the `FBSDKAppEvents` event queue, unless the `flushBehavior` is set + to `FBSDKAppEventsFlushBehaviorExplicitOnly`. + + */ ++ (void)logPurchase:(double)purchaseAmount + currency:(NSString *)currency + parameters:(NSDictionary *)parameters; + +/*! + + @abstract + Log a purchase of the specified amount, in the specified currency, also providing a set of + additional characteristics describing the purchase, as well as an to log to. + + @param purchaseAmount Purchase amount to be logged, as expressed in the specified currency.This value + will be rounded to the thousandths place (e.g., 12.34567 becomes 12.346). + + @param currency Currency, is denoted as, e.g. "USD", "EUR", "GBP". See ISO-4217 for + specific values. One reference for these is . + + @param parameters Arbitrary parameter dictionary of characteristics. The keys to this dictionary must + be NSString's, and the values are expected to be NSString or NSNumber. Limitations on the number of + parameters and name construction are given in the `FBSDKAppEvents` documentation. Commonly used parameter names + are provided in `FBSDKAppEventParameterName*` constants. + + @param accessToken The optional access token to log the event as. + + @discussion This event immediately triggers a flush of the `FBSDKAppEvents` event queue, unless the `flushBehavior` is set + to `FBSDKAppEventsFlushBehaviorExplicitOnly`. + + */ ++ (void)logPurchase:(double)purchaseAmount + currency:(NSString *)currency + parameters:(NSDictionary *)parameters + accessToken:(FBSDKAccessToken *)accessToken; + +/*! + + @abstract + Notifies the events system that the app has launched and, when appropriate, logs an "activated app" event. Should typically be placed in the + app delegates' `applicationDidBecomeActive:` method. + + This method also takes care of logging the event indicating the first time this app has been launched, which, among other things, is used to + track user acquisition and app install ads conversions. + + @discussion + `activateApp` will not log an event on every app launch, since launches happen every time the app is backgrounded and then foregrounded. + "activated app" events will be logged when the app has not been active for more than 60 seconds. This method also causes a "deactivated app" + event to be logged when sessions are "completed", and these events are logged with the session length, with an indication of how much + time has elapsed between sessions, and with the number of background/foreground interruptions that session had. This data + is all visible in your app's App Events Insights. + */ ++ (void)activateApp; + +/* + * Control over event batching/flushing + */ + +/*! + + @abstract + Get the current event flushing behavior specifying when events are sent back to Facebook servers. + */ ++ (FBSDKAppEventsFlushBehavior)flushBehavior; + +/*! + + @abstract + Set the current event flushing behavior specifying when events are sent back to Facebook servers. + + @param flushBehavior The desired `FBSDKAppEventsFlushBehavior` to be used. + */ ++ (void)setFlushBehavior:(FBSDKAppEventsFlushBehavior)flushBehavior; + +/*! + @abstract + Set the 'override' App ID for App Event logging. + + @discussion + In some cases, apps want to use one Facebook App ID for login and social presence and another + for App Event logging. (An example is if multiple apps from the same company share an app ID for login, but + want distinct logging.) By default, this value is `nil`, and defers to the `FBSDKAppEventsOverrideAppIDBundleKey` + plist value. If that's not set, it defaults to `[FBSDKSettigns appID]`. + + This should be set before any other calls are made to `FBSDKAppEvents`. Thus, you should set it in your application + delegate's `application:didFinishLaunchingWithOptions:` delegate. + + @param appID The Facebook App ID to be used for App Event logging. + */ ++ (void)setLoggingOverrideAppID:(NSString *)appID; + +/*! + @abstract + Get the 'override' App ID for App Event logging. + + @see setLoggingOverrideAppID: + + */ ++ (NSString *)loggingOverrideAppID; + + +/*! + @abstract + Explicitly kick off flushing of events to Facebook. This is an asynchronous method, but it does initiate an immediate + kick off. Server failures will be reported through the NotificationCenter with notification ID `FBSDKAppEventsLoggingResultNotification`. + */ ++ (void)flush; + +/*! + @abstract + Creates a request representing the Graph API call to retrieve a Custom Audience "third party ID" for the app's Facebook user. + Callers will send this ID back to their own servers, collect up a set to create a Facebook Custom Audience with, + and then use the resultant Custom Audience to target ads. + + @param accessToken The access token to use to establish the user's identity for users logged into Facebook through this app. + If `nil`, then the `[FBSDKAccessToken currentAccessToken]` is used. + + @discussion + The JSON in the request's response will include an "custom_audience_third_party_id" key/value pair, with the value being the ID retrieved. + This ID is an encrypted encoding of the Facebook user's ID and the invoking Facebook app ID. + Multiple calls with the same user will return different IDs, thus these IDs cannot be used to correlate behavior + across devices or applications, and are only meaningful when sent back to Facebook for creating Custom Audiences. + + The ID retrieved represents the Facebook user identified in the following way: if the specified access token is valid, + the ID will represent the user associated with that token; otherwise the ID will represent the user logged into the + native Facebook app on the device. If there is no native Facebook app, no one is logged into it, or the user has opted out + at the iOS level from ad tracking, then a `nil` ID will be returned. + + This method returns `nil` if either the user has opted-out (via iOS) from Ad Tracking, the app itself has limited event usage + via the `[FBSDKSettings limitEventAndDataUsage]` flag, or a specific Facebook user cannot be identified. + */ ++ (FBSDKGraphRequest *)requestForCustomAudienceThirdPartyIDWithAccessToken:(FBSDKAccessToken *)accessToken; +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKAppLinkResolver.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKAppLinkResolver.h new file mode 100644 index 0000000..8e65e5b --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKAppLinkResolver.h @@ -0,0 +1,82 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class BFTask; + +// Check if Bolts.framework is available for import +#if __has_include() +// Import it if it's available +# import +#else +// Otherwise - redeclare BFAppLinkResolving protocol to resolve the problem of missing symbols +// Please note: Bolts.framework is still required for AppLink resolving to work, +// but this allows FBSDKCoreKit to weakly link Bolts.framework as well as this enables clang modulemaps to work. + +/*! + Implement this protocol to provide an alternate strategy for resolving + App Links that may include pre-fetching, caching, or querying for App Link + data from an index provided by a service provider. + */ +@protocol BFAppLinkResolving + +/*! + Asynchronously resolves App Link data for a given URL. + + @param url The URL to resolve into an App Link. + @returns A BFTask that will return a BFAppLink for the given URL. + */ +- (BFTask *)appLinkFromURLInBackground:(NSURL *)url; + +@end + +#endif + +/*! + @class FBSDKAppLinkResolver + + @abstract + Provides an implementation of the BFAppLinkResolving protocol that uses the Facebook App Link + Index API to resolve App Links given a URL. It also provides an additional helper method that can resolve + multiple App Links in a single call. + + @discussion + Usage of this type requires a client token. See `[FBSDKSettings setClientToken:]` and linking + Bolts.framework + */ +@interface FBSDKAppLinkResolver : NSObject + +/*! + @abstract Asynchronously resolves App Link data for multiple URLs. + + @param urls An array of NSURLs to resolve into App Links. + @returns A BFTask that will return dictionary mapping input NSURLs to their + corresponding BFAppLink. + + @discussion + You should set the client token before making this call. See `[FBSDKSettings setClientToken:]` + */ +- (BFTask *)appLinksFromURLsInBackground:(NSArray *)urls; + +/*! + @abstract Allocates and initializes a new instance of FBSDKAppLinkResolver. + */ ++ (instancetype)resolver; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKAppLinkUtility.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKAppLinkUtility.h new file mode 100644 index 0000000..216b71d --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKAppLinkUtility.h @@ -0,0 +1,55 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @abstract Describes the callback for fetchDeferredAppLink. + @param url the url representing the deferred App Link + @param error the error during the request, if any + + @discussion The url may also have a fb_click_time_utc query parameter that + represents when the click occurred that caused the deferred App Link to be created. + */ +typedef void (^FBSDKDeferredAppLinkHandler)(NSURL *url, NSError *error); + +/*! + @abstract Class containing App Links related utility methods. + */ +@interface FBSDKAppLinkUtility : NSObject + +/*! + @abstract + Call this method from the main thread to fetch deferred applink data if you use Mobile App + Engagement Ads (https://developers.facebook.com/docs/ads-for-apps/mobile-app-ads-engagement). + This may require a network round trip. If successful, the handler is invoked with the link + data (this will only return a valid URL once, and future calls will result in a nil URL + value in the callback). + + @param handler the handler to be invoked if there is deferred App Link data + + @discussion The handler may contain an NSError instance to capture any errors. In the + common case where there simply was no app link data, the NSError instance will be nil. + + This method should only be called from a location that occurs after any launching URL has + been processed (e.g., you should call this method from your application delegate's + applicationDidBecomeActive:). + */ ++ (void)fetchDeferredAppLink:(FBSDKDeferredAppLinkHandler)handler; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKApplicationDelegate.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKApplicationDelegate.h new file mode 100644 index 0000000..857acd0 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKApplicationDelegate.h @@ -0,0 +1,74 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @class FBSDKApplicationDelegate + + @abstract + The FBSDKApplicationDelegate is designed to post process the results from Facebook Login + or Facebook Dialogs (or any action that requires switching over to the native Facebook + app or Safari). + + @discussion + The methods in this class are designed to mirror those in UIApplicationDelegate, and you + should call them in the respective methods in your AppDelegate implementation. + */ +@interface FBSDKApplicationDelegate : NSObject + +/*! + @abstract Gets the singleton instance. + */ ++ (instancetype)sharedInstance; + +/*! + @abstract + Call this method from the [UIApplicationDelegate application:openURL:sourceApplication:annotation:] method + of the AppDelegate for your app. It should be invoked for the proper processing of responses during interaction + with the native Facebook app or Safari as part of SSO authorization flow or Facebook dialogs. + + @param application The application as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:]. + + @param url The URL as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:]. + + @param sourceApplication The sourceApplication as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:]. + + @param annotation The annotation as passed to [UIApplicationDelegate application:openURL:sourceApplication:annotation:]. + + @return YES if the url was intended for the Facebook SDK, NO if not. + */ +- (BOOL)application:(UIApplication *)application + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation; + +/*! + @abstract + Call this method from the [UIApplicationDelegate application:didFinishLaunchingWithOptions:] method + of the AppDelegate for your app. It should be invoked for the proper use of the Facebook SDK. + + @param application The application as passed to [UIApplicationDelegate application:didFinishLaunchingWithOptions:]. + + @param launchOptions The launchOptions as passed to [UIApplicationDelegate application:didFinishLaunchingWithOptions:]. + + @return YES if the url was intended for the Facebook SDK, NO if not. + */ +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKButton.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKButton.h new file mode 100644 index 0000000..8132998 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKButton.h @@ -0,0 +1,26 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @abstract A base class for common SDK buttons. + */ +@interface FBSDKButton : UIButton + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKConstants.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKConstants.h new file mode 100644 index 0000000..1d316db --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKConstants.h @@ -0,0 +1,195 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract The error domain for all errors from FBSDKCoreKit. + @discussion Error codes from the SDK in the range 0-99 are reserved for this domain. + */ +FBSDK_EXTERN NSString *const FBSDKErrorDomain; + +/*! + @typedef NS_ENUM(NSInteger, FBSDKErrorCode) + @abstract Error codes for FBSDKErrorDomain. + */ +typedef NS_ENUM(NSInteger, FBSDKErrorCode) +{ + /*! + @abstract Reserved. + */ + FBSDKReservedErrorCode = 0, + + /*! + @abstract The error code for errors from invalid encryption on incoming encryption URLs. + */ + FBSDKEncryptionErrorCode, + + /*! + @abstract The error code for errors from invalid arguments to SDK methods. + */ + FBSDKInvalidArgumentErrorCode, + + /*! + @abstract The error code for unknown errors. + */ + FBSDKUnknownErrorCode, + + /*! + @abstract A request failed due to a network error. Use NSUnderlyingErrorKey to retrieve + the error object from the NSURLConnection for more information. + */ + FBSDKNetworkErrorCode, + + /*! + @abstract The error code for errors encounted during an App Events flush. + */ + FBSDKAppEventsFlushErrorCode, + + /*! + @abstract An endpoint that returns a binary response was used with FBSDKGraphRequestConnection. + @discussion Endpoints that return image/jpg, etc. should be accessed using NSURLRequest + */ + FBSDKGraphRequestNonTextMimeTypeReturnedErrorCode, + + /*! + @abstract The operation failed because the server returned an unexpected response. + @discussion You can get this error if you are not using the most recent SDK, or you are accessing a version of the + Graph API incompatible with the current SDK. + */ + FBSDKGraphRequestProtocolMismatchErrorCode, + + /*! + @abstract The Graph API returned an error. + @discussion See below for useful userInfo keys (beginning with FBSDKGraphRequestError*) + */ + FBSDKGraphRequestGraphAPIErrorCode, + + /*! + @abstract The specified dialog configuration is not available. + @discussion This error may signify that the configuration for the dialogs has not yet been downloaded from the server + or that the dialog is unavailable. Subsequent attempts to use the dialog may succeed as the configuration is loaded. + */ + FBSDKDialogUnavailableErrorCode, +}; + +/*! + @typedef NS_ENUM(NSUInteger, FBSDKGraphRequestErrorCategory) + @abstract Describes the category of Facebook error. See `FBSDKGraphRequestErrorCategoryKey`. + */ +typedef NS_ENUM(NSUInteger, FBSDKGraphRequestErrorCategory) +{ + /*! The default error category that is not known to be recoverable. Check `FBSDKLocalizedErrorDescriptionKey` for a user facing message. */ + FBSDKGraphRequestErrorCategoryOther = 0, + /*! Indicates the error is temporary (such as server throttling). While a recoveryAttempter will be provided with the error instance, the attempt is guaranteed to succeed so you can simply retry the operation if you do not want to present an alert. */ + FBSDKGraphRequestErrorCategoryTransient = 1, + /*! Indicates the error can be recovered (such as requiring a login). A recoveryAttempter will be provided with the error instance that can take UI action. */ + FBSDKGraphRequestErrorCategoryRecoverable = 2 +}; + +/* + @methodgroup error userInfo keys + */ + +/*! + @abstract The userInfo key for the invalid collection for errors with FBSDKInvalidArgumentErrorCode. + @discussion If the invalid argument is a collection, the collection can be found with this key and the individual + invalid item can be found with FBSDKErrorArgumentValueKey. + */ +FBSDK_EXTERN NSString *const FBSDKErrorArgumentCollectionKey; + +/*! + @abstract The userInfo key for the invalid argument name for errors with FBSDKInvalidArgumentErrorCode. + */ +FBSDK_EXTERN NSString *const FBSDKErrorArgumentNameKey; + +/*! + @abstract The userInfo key for the invalid argument value for errors with FBSDKInvalidArgumentErrorCode. + */ +FBSDK_EXTERN NSString *const FBSDKErrorArgumentValueKey; + +/*! + @abstract The userInfo key for the message for developers in NSErrors that originate from the SDK. + @discussion The developer message will not be localized and is not intended to be presented within the app. + */ +FBSDK_EXTERN NSString *const FBSDKErrorDeveloperMessageKey; + +/*! + @abstract The userInfo key describing a localized description that can be presented to the user. + */ +FBSDK_EXTERN NSString *const FBSDKErrorLocalizedDescriptionKey; + +/*! + @abstract The userInfo key describing a localized title that can be presented to the user, used with `FBSDKLocalizedErrorDescriptionKey`. + */ +FBSDK_EXTERN NSString *const FBSDKErrorLocalizedTitleKey; + +/* + @methodgroup FBSDKGraphRequest error userInfo keys + */ + +/*! + @abstract The userInfo key describing the error category, for error recovery purposes. + @discussion See `FBSDKGraphErrorRecoveryProcessor` and `[FBSDKGraphRequest disableErrorRecovery]`. + */ +FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorCategoryKey; + +/* + @abstract The userInfo key for the Graph API error code. + */ +FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorGraphErrorCode; + +/* + @abstract The userInfo key for the Graph API error subcode. + */ +FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorGraphErrorSubcode; + +/* + @abstract The userInfo key for the HTTP status code. + */ +FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorHTTPStatusCodeKey; + +/* + @abstract The userInfo key for the raw JSON response. + */ +FBSDK_EXTERN NSString *const FBSDKGraphRequestErrorParsedJSONResponseKey; + +/*! + @abstract a formal protocol very similar to the informal protocol NSErrorRecoveryAttempting + */ +@protocol FBSDKErrorRecoveryAttempting + +/*! + @abstract attempt the recovery + @param error the error + @param recoveryOptionIndex the selected option index + @param delegate the delegate + @param didRecoverSelector the callback selector, see discussion. + @param contextInfo context info to pass back to callback selector, see discussion. + @discussion + Given that an error alert has been presented document-modally to the user, and the user has chosen one of the error's recovery options, attempt recovery from the error, and send the selected message to the specified delegate. The option index is an index into the error's array of localized recovery options. The method selected by didRecoverSelector must have the same signature as: + + - (void)didPresentErrorWithRecovery:(BOOL)didRecover contextInfo:(void *)contextInfo; + + The value passed for didRecover must be YES if error recovery was completely successful, NO otherwise. + */ +- (void)attemptRecoveryFromError:(NSError *)error optionIndex:(NSUInteger)recoveryOptionIndex delegate:(id)delegate didRecoverSelector:(SEL)didRecoverSelector contextInfo:(void *)contextInfo; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKCopying.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKCopying.h new file mode 100644 index 0000000..f4ad767 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKCopying.h @@ -0,0 +1,33 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @abstract Extension protocol for NSCopying that adds the copy method, which is implemented on NSObject. + @discussion NSObject implicitly conforms to this protocol. + */ +@protocol FBSDKCopying + +/*! + @abstract Implemented by NSObject as a convenience to copyWithZone:. + @return A copy of the receiver. + */ +- (id)copy; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKCoreKit.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKCoreKit.h new file mode 100644 index 0000000..455444b --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKCoreKit.h @@ -0,0 +1,38 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +#define FBSDK_VERSION_STRING @"4.2.0" +#define FBSDK_TARGET_PLATFORM_VERSION @"v2.3" diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKGraphErrorRecoveryProcessor.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKGraphErrorRecoveryProcessor.h new file mode 100644 index 0000000..d2b0313 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKGraphErrorRecoveryProcessor.h @@ -0,0 +1,97 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKConstants.h" + +@class FBSDKGraphErrorRecoveryProcessor; +@class FBSDKGraphRequest; + +/*! + @abstract Defines a delegate for `FBSDKGraphErrorRecoveryProcessor`. + */ +@protocol FBSDKGraphErrorRecoveryProcessorDelegate + +/*! + @abstract Indicates the error recovery has been attempted. + @param processor the processor instance. + @param didRecover YES if the recovery was successful. + @param error the error that that was attempted to be recovered from. + */ +- (void)processorDidAttemptRecovery:(FBSDKGraphErrorRecoveryProcessor *)processor didRecover:(BOOL)didRecover error:(NSError *)error; + +@optional +/*! + @abstract Indicates the processor is about to process the error. + @param processor the processor instance. + @param error the error is about to be processed. + @discussion return NO if the processor should not process the error. For example, + if you want to prevent alerts of localized messages but otherwise perform retries and recoveries, + you could return NO for errors where userInfo[FBSDKGraphRequestErrorCategoryKey] equal to FBSDKGraphRequestErrorCategoryOther + */ +- (BOOL)processorWillProcessError:(FBSDKGraphErrorRecoveryProcessor *)processor error:(NSError *)error; + +@end + +/*! + @abstract Defines a type that can process Facebook NSErrors with best practices. + @discussion Facebook NSErrors can contain FBSDKErrorRecoveryAttempting instances to recover from errors, or + localized messages to present to the user. This class will process the instances as follows: + + 1. If the error is temporary as indicated by FBSDKGraphRequestErrorCategoryKey, assume the recovery succeeded and + notify the delegate. + 2. If a FBSDKErrorRecoveryAttempting instance is available, display an alert (dispatched to main thread) + with the recovery options and call the instance's [ attemptRecoveryFromError:optionIndex:...]. + 3. If a FBSDKErrorRecoveryAttempting is not available, check the userInfo for FBSDKLocalizedErrorDescriptionKey + and present that in an alert (dispatched to main thread). + + By default, FBSDKGraphRequests use this type to process errors and retry the request upon a successful + recovery. + + Note that Facebook recovery attempters can present UI or even cause app switches (such as to login). Any such + work is dispatched to the main thread (therefore your request handlers may then run on the main thread). + + Login recovery requires FBSDKLoginKit. Login will use FBSDKLoginBehaviorNative and will prompt the user + for all permissions last granted. If any are declined on the new request, the recovery is not successful but + the `[FBSDKAccessToken currentAccessToken]` might still have been updated. + . + */ +@interface FBSDKGraphErrorRecoveryProcessor : NSObject + +/*! + @abstract Gets the delegate. Note this is a strong reference, and is nil'ed out after recovery is complete. + */ +@property (nonatomic, strong, readonly) iddelegate; + +/*! + @abstract Attempts to process the error, return YES if the error can be processed. + @param error the error to process. + @param request the relateed request that may be reissued. + @param delegate the delegate that will be retained until recovery is complete. + */ +- (BOOL)processError:(NSError *)error request:(FBSDKGraphRequest *)request delegate:(id) delegate; + +/*! + @abstract The callback for FBSDKErrorRecoveryAttempting + @param didRecover if the recovery succeeded + @param contextInfo unused + */ +- (void)didPresentErrorWithRecovery:(BOOL)didRecover contextInfo:(void *)contextInfo; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKGraphRequest.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKGraphRequest.h new file mode 100644 index 0000000..5ae03e2 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKGraphRequest.h @@ -0,0 +1,120 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@class FBSDKAccessToken; + +/*! + @abstract Represents a request to the Facebook Graph API. + + @discussion `FBSDKGraphRequest` encapsulates the components of a request (the + Graph API path, the parameters, error recovery behavior) and should be + used in conjunction with `FBSDKGraphRequestConnection` to issue the request. + + Nearly all Graph APIs require an access token. Unless specified, the + `[FBSDKAccessToken currentAccessToken]` is used. Therefore, most requests + will require login first (see `FBSDKLoginManager` in FBSDKLoginKit.framework). + + A `- start` method is provided for convenience for single requests. + + By default, FBSDKGraphRequest will attempt to recover any errors returned from + Facebook. You can disable this via `disableErrorRecovery:`. + @see FBSDKGraphErrorRecoveryProcessor + */ +@interface FBSDKGraphRequest : NSObject + +/*! + @abstract Initializes a new instance that use use `[FBSDKAccessToken currentAccessToken]`. + @param graphPath the graph path (e.g., @"me"). + @param parameters the optional parameters dictionary. + */ +- (instancetype)initWithGraphPath:(NSString *)graphPath + parameters:(NSDictionary *)parameters; + +/*! + @abstract Initializes a new instance that use use `[FBSDKAccessToken currentAccessToken]`. + @param graphPath the graph path (e.g., @"me"). + @param parameters the optional parameters dictionary. + @param HTTPMethod the optional HTTP method. nil defaults to @"GET". + */ +- (instancetype)initWithGraphPath:(NSString *)graphPath + parameters:(NSDictionary *)parameters + HTTPMethod:(NSString *)HTTPMethod; + +/*! + @abstract Initializes a new instance. + @param graphPath the graph path (e.g., @"me"). + @param parameters the optional parameters dictionary. + @param tokenString the token string to use. Specifying nil will cause no token to be used. + @param version the optional Graph API version (e.g., @"v2.0"). nil defaults to FBSDK_TARGET_PLATFORM_VERSION. + @param HTTPMethod the optional HTTP method (e.g., @"POST"). nil defaults to @"GET". + */ +- (instancetype)initWithGraphPath:(NSString *)graphPath + parameters:(NSDictionary *)parameters + tokenString:(NSString *)tokenString + version:(NSString *)version + HTTPMethod:(NSString *)HTTPMethod +NS_DESIGNATED_INITIALIZER; + +/*! + @abstract The request parameters. + */ +@property (nonatomic, strong, readonly) NSMutableDictionary *parameters; + +/*! + @abstract The access token string used by the request. + */ +@property (nonatomic, copy, readonly) NSString *tokenString; + +/*! + @abstract The Graph API endpoint to use for the request, for example "me". + */ +@property (nonatomic, copy, readonly) NSString *graphPath; + +/*! + @abstract The HTTPMethod to use for the request, for example "GET" or "POST". + */ +@property (nonatomic, copy, readonly) NSString *HTTPMethod; + +/*! + @abstract The Graph API version to use (e.g., "v2.0") + */ +@property (nonatomic, copy, readonly) NSString *version; + +/*! + @abstract If set, disables the automatic error recovery mechanism. + @param disable whether to disable the automatic error recovery mechanism + @discussion By default, non-batched FBSDKGraphRequest instances will automatically try to recover + from errors by constructing a `FBSDKGraphErrorRecoveryProcessor` instance that + re-issues the request on successful recoveries. The re-issued request will call the same + handler as the receiver but may occur with a different `FBSDKGraphRequestConnection` instance. + + This will override [FBSDKSettings setGraphErrorRecoveryDisabled:]. + */ +- (void)setGraphErrorRecoveryDisabled:(BOOL)disable; + +/*! + @abstract Starts a connection to the Graph API. + @param handler The handler block to call when the request completes. + */ +- (FBSDKGraphRequestConnection *)startWithCompletionHandler:(FBSDKGraphRequestHandler)handler; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKGraphRequestConnection.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKGraphRequestConnection.h new file mode 100644 index 0000000..441f8dc --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKGraphRequestConnection.h @@ -0,0 +1,311 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@class FBSDKGraphRequest; +@class FBSDKGraphRequestConnection; + +/*! + @typedef FBSDKGraphRequestHandler + + @abstract + A block that is passed to addRequest to register for a callback with the results of that + request once the connection completes. + + @discussion + Pass a block of this type when calling addRequest. This will be called once + the request completes. The call occurs on the UI thread. + + @param connection The `FBSDKGraphRequestConnection` that sent the request. + + @param result The result of the request. This is a translation of + JSON data to `NSDictionary` and `NSArray` objects. This + is nil if there was an error. + + @param error The `NSError` representing any error that occurred. + + */ +typedef void (^FBSDKGraphRequestHandler)(FBSDKGraphRequestConnection *connection, + id result, + NSError *error); + +/*! + @protocol + + @abstract + The `FBSDKGraphRequestConnectionDelegate` protocol defines the methods used to receive network + activity progress information from a . + */ +@protocol FBSDKGraphRequestConnectionDelegate + +@optional + +/*! + @method + + @abstract + Tells the delegate the request connection will begin loading + + @discussion + If the is created using one of the convenience factory methods prefixed with + start, the object returned from the convenience method has already begun loading and this method + will not be called when the delegate is set. + + @param connection The request connection that is starting a network request + */ +- (void)requestConnectionWillBeginLoading:(FBSDKGraphRequestConnection *)connection; + +/*! + @method + + @abstract + Tells the delegate the request connection finished loading + + @discussion + If the request connection completes without a network error occuring then this method is called. + Invocation of this method does not indicate success of every made, only that the + request connection has no further activity. Use the error argument passed to the FBSDKGraphRequestHandler + block to determine success or failure of each . + + This method is invoked after the completion handler for each . + + @param connection The request connection that successfully completed a network request + */ +- (void)requestConnectionDidFinishLoading:(FBSDKGraphRequestConnection *)connection; + +/*! + @method + + @abstract + Tells the delegate the request connection failed with an error + + @discussion + If the request connection fails with a network error then this method is called. The `error` + argument specifies why the network connection failed. The `NSError` object passed to the + FBSDKGraphRequestHandler block may contain additional information. + + @param connection The request connection that successfully completed a network request + @param error The `NSError` representing the network error that occurred, if any. May be nil + in some circumstances. Consult the `NSError` for the for reliable + failure information. + */ +- (void)requestConnection:(FBSDKGraphRequestConnection *)connection + didFailWithError:(NSError *)error; + +/*! + @method + + @abstract + Tells the delegate how much data has been sent and is planned to send to the remote host + + @discussion + The byte count arguments refer to the aggregated objects, not a particular . + + Like `NSURLConnection`, the values may change in unexpected ways if data needs to be resent. + + @param connection The request connection transmitting data to a remote host + @param bytesWritten The number of bytes sent in the last transmission + @param totalBytesWritten The total number of bytes sent to the remote host + @param totalBytesExpectedToWrite The total number of bytes expected to send to the remote host + */ +- (void)requestConnection:(FBSDKGraphRequestConnection *)connection + didSendBodyData:(NSInteger)bytesWritten + totalBytesWritten:(NSInteger)totalBytesWritten +totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite; + +@end + +/*! + @class FBSDKGraphRequestConnection + + @abstract + The `FBSDKGraphRequestConnection` represents a single connection to Facebook to service a request. + + @discussion + The request settings are encapsulated in a reusable object. The + `FBSDKGraphRequestConnection` object encapsulates the concerns of a single communication + e.g. starting a connection, canceling a connection, or batching requests. + + */ +@interface FBSDKGraphRequestConnection : NSObject + +/*! + @abstract + The delegate object that receives updates. + */ +@property (nonatomic, assign) id delegate; + +/*! + @abstract Gets or sets the timeout interval to wait for a response before giving up. + */ +@property (nonatomic) NSTimeInterval timeout; + +/*! + @abstract + The raw response that was returned from the server. (readonly) + + @discussion + This property can be used to inspect HTTP headers that were returned from + the server. + + The property is nil until the request completes. If there was a response + then this property will be non-nil during the FBSDKGraphRequestHandler callback. + */ +@property (nonatomic, retain, readonly) NSHTTPURLResponse *URLResponse; + +/*! + @methodgroup Adding requests + */ + +/*! + @method + + @abstract + This method adds an object to this connection. + + @param request A request to be included in the round-trip when start is called. + @param handler A handler to call back when the round-trip completes or times out. + + @discussion + The completion handler is retained until the block is called upon the + completion or cancellation of the connection. + */ +- (void)addRequest:(FBSDKGraphRequest *)request + completionHandler:(FBSDKGraphRequestHandler)handler; + +/*! + @method + + @abstract + This method adds an object to this connection. + + @param request A request to be included in the round-trip when start is called. + + @param handler A handler to call back when the round-trip completes or times out. + The handler will be invoked on the main thread. + + @param name An optional name for this request. This can be used to feed + the results of one request to the input of another in the same + `FBSDKGraphRequestConnection` as described in + [Graph API Batch Requests]( https://developers.facebook.com/docs/reference/api/batch/ ). + + @discussion + The completion handler is retained until the block is called upon the + completion or cancellation of the connection. This request can be named + to allow for using the request's response in a subsequent request. + */ +- (void)addRequest:(FBSDKGraphRequest *)request + completionHandler:(FBSDKGraphRequestHandler)handler + batchEntryName:(NSString *)name; + +/*! + @method + + @abstract + This method adds an object to this connection. + + @param request A request to be included in the round-trip when start is called. + + @param handler A handler to call back when the round-trip completes or times out. + + @param batchParameters The optional dictionary of parameters to include for this request + as described in [Graph API Batch Requests]( https://developers.facebook.com/docs/reference/api/batch/ ). + Examples include "depends_on", "name", or "omit_response_on_success". + + @discussion + The completion handler is retained until the block is called upon the + completion or cancellation of the connection. This request can be named + to allow for using the request's response in a subsequent request. + */ +- (void)addRequest:(FBSDKGraphRequest *)request + completionHandler:(FBSDKGraphRequestHandler)handler + batchParameters:(NSDictionary *)batchParameters; + +/*! + @methodgroup Instance methods + */ + +/*! + @method + + @abstract + Signals that a connection should be logically terminated as the + application is no longer interested in a response. + + @discussion + Synchronously calls any handlers indicating the request was cancelled. Cancel + does not guarantee that the request-related processing will cease. It + does promise that all handlers will complete before the cancel returns. A call to + cancel prior to a start implies a cancellation of all requests associated + with the connection. + */ +- (void)cancel; + +/*! + @method + + @abstract + This method starts a connection with the server and is capable of handling all of the + requests that were added to the connection. + + @discussion By default, a connection is scheduled on the current thread in the default mode when it is created. + See `setDelegateQueue:` for other options. + + This method cannot be called twice for an `FBSDKGraphRequestConnection` instance. + */ +- (void)start; + +/*! + @abstract Determines the operation queue that is used to call methods on the connection's delegate. + @param queue The operation queue to use when calling delegate methods. + @discussion By default, a connection is scheduled on the current thread in the default mode when it is created. + You cannot reschedule a connection after it has started. + + This is very similar to `[NSURLConnection setDelegateQueue:]`. + */ +- (void)setDelegateQueue:(NSOperationQueue *)queue; + +/*! + @method + + @abstract + Overrides the default version for a batch request + + @discussion + The SDK automatically prepends a version part, such as "v2.0" to API paths in order to simplify API versioning + for applications. If you want to override the version part while using batch requests on the connection, call + this method to set the version for the batch request. + + @param version This is a string in the form @"v2.0" which will be used for the version part of an API path + */ +- (void)overrideVersionPartWith:(NSString *)version; + +@end + +/*! + @abstract The key in the result dictionary for requests to old versions of the Graph API + whose response is not a JSON object. + + @discussion When a request returns a non-JSON response (such as a "true" literal), that response + will be wrapped into a dictionary using this const as the key. This only applies for very few Graph API + prior to v2.1. + */ +FBSDK_EXTERN NSString *const FBSDKNonJSONResponseProperty; diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKGraphRequestDataAttachment.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKGraphRequestDataAttachment.h new file mode 100644 index 0000000..c179e29 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKGraphRequestDataAttachment.h @@ -0,0 +1,52 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @abstract A container class for data attachments so that additional metadata can be provided about the attachment. + */ +@interface FBSDKGraphRequestDataAttachment : NSObject + +/*! + @abstract Initializes the receiver with the attachment data and metadata. + @param data The attachment data (retained, not copied) + @param filename The filename for the attachment + @param contentType The content type for the attachment + */ +- (instancetype)initWithData:(NSData *)data + filename:(NSString *)filename + contentType:(NSString *)contentType +NS_DESIGNATED_INITIALIZER; + +/*! + @abstract The content type for the attachment. + */ +@property (nonatomic, copy, readonly) NSString *contentType; + +/*! + @abstract The attachment data. + */ +@property (nonatomic, strong, readonly) NSData *data; + +/*! + @abstract The filename for the attachment. + */ +@property (nonatomic, copy, readonly) NSString *filename; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKMacros.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKMacros.h new file mode 100644 index 0000000..fd2e2ff --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKMacros.h @@ -0,0 +1,39 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#ifdef __cplusplus +#define FBSDK_EXTERN extern "C" __attribute__((visibility ("default"))) +#else +#define FBSDK_EXTERN extern __attribute__((visibility ("default"))) +#endif + +#define FBSDK_STATIC_INLINE static inline + +#define FBSDK_NO_DESIGNATED_INITIALIZER() \ +@throw [NSException exceptionWithName:NSInvalidArgumentException \ + reason:[NSString stringWithFormat:@"unrecognized selector sent to instance %p", self] \ + userInfo:nil] + +#define FBSDK_NOT_DESIGNATED_INITIALIZER(DESIGNATED_INITIALIZER) \ +@throw [NSException exceptionWithName:NSInvalidArgumentException \ + reason:[NSString stringWithFormat:@"Please use the designated initializer [%p %@]", \ + self, \ + NSStringFromSelector(@selector(DESIGNATED_INITIALIZER))] \ + userInfo:nil] diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKMutableCopying.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKMutableCopying.h new file mode 100644 index 0000000..621fac9 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKMutableCopying.h @@ -0,0 +1,35 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract Extension protocol for NSMutableCopying that adds the mutableCopy method, which is implemented on NSObject. + @discussion NSObject implicitly conforms to this protocol. + */ +@protocol FBSDKMutableCopying + +/*! + @abstract Implemented by NSObject as a convenience to mutableCopyWithZone:. + @return A mutable copy of the receiver. + */ +- (id)mutableCopy; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKProfile.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKProfile.h new file mode 100644 index 0000000..c206a2b --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKProfile.h @@ -0,0 +1,139 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKMacros.h" +#import "FBSDKProfilePictureView.h" + +/*! + @abstract Notification indicating that the `currentProfile` has changed. + @discussion the userInfo dictionary of the notification will contain keys + `FBSDKProfileChangeOldKey` and + `FBSDKProfileChangeNewKey`. + */ +FBSDK_EXTERN NSString *const FBSDKProfileDidChangeNotification; + +/* @abstract key in notification's userInfo object for getting the old profile. + @discussion If there was no old profile, the key will not be present. + */ +FBSDK_EXTERN NSString *const FBSDKProfileChangeOldKey; + +/* @abstract key in notification's userInfo object for getting the new profile. + @discussion If there is no new profile, the key will not be present. + */ +FBSDK_EXTERN NSString *const FBSDKProfileChangeNewKey; + +/*! + @abstract Represents an immutable Facebook profile + @discussion This class provides a global "currentProfile" instance to more easily + add social context to your application. When the profile changes, a notification is + posted so that you can update relevant parts of your UI and is persisted to NSUserDefaults. + + Typically, you will want to call `enableUpdatesOnAccessTokenChange:YES` so that + it automatically observes changes to the `[FBSDKAccessToken currentAccessToken]`. + + You can use this class to build your own `FBSDKProfilePictureView` or in place of typical requests to "/me". + */ +@interface FBSDKProfile : NSObject + +/*! + @abstract initializes a new instance. + @param userID the user ID + @param firstName the user's first name + @param middleName the user's middle name + @param lastName the user's last name + @param name the user's complete name + @param linkURL the link for this profile + @param refreshDate the optional date this profile was fetched. Defaults to [NSDate date]. + */ +- (instancetype)initWithUserID:(NSString *)userID + firstName:(NSString *)firstName + middleName:(NSString *)middleName + lastName:(NSString *)lastName + name:(NSString *)name + linkURL:(NSURL *)linkURL + refreshDate:(NSDate *)refreshDate NS_DESIGNATED_INITIALIZER; +/*! + @abstract The user id + */ +@property (nonatomic, readonly) NSString *userID; +/*! + @abstract The user's first name + */ +@property (nonatomic, readonly) NSString *firstName; +/*! + @abstract The user's middle name + */ +@property (nonatomic, readonly) NSString *middleName; +/*! + @abstract The user's last name + */ +@property (nonatomic, readonly) NSString *lastName; +/*! + @abstract The user's complete name + */ +@property (nonatomic, readonly) NSString *name; +/*! + @abstract A URL to the user's profile. + @discussion Consider using Bolts and `FBSDKAppLinkResolver` to resolve this + to an app link to link directly to the user's profile in the Facebook app. + */ +@property (nonatomic, readonly) NSURL *linkURL; + +/*! + @abstract The last time the profile data was fetched. + */ +@property (nonatomic, readonly) NSDate *refreshDate; + +/*! + @abstract Gets the current FBSDKProfile instance. + */ ++ (FBSDKProfile *)currentProfile; + +/*! + @abstract Sets the current instance and posts the appropriate notification if the profile parameter is different + than the receiver. + @param profile the profile to set + @discussion This persists the profile to NSUserDefaults. + */ ++ (void)setCurrentProfile:(FBSDKProfile *)profile; + +/*! + @abstract Indicates if `currentProfile` will automatically observe `FBSDKAccessTokenDidChangeNotification` notifications + @param enable YES is observing + @discussion If observing, this class will issue a graph request for public profile data when the current token's userID + differs from the current profile. You can observe `FBSDKProfileDidChangeNotification` for when the profile is updated. + + Note that if `[FBSDKAccessToken currentAccessToken]` is unset, the `currentProfile` instance remains. It's also possible + for `currentProfile` to return nil until the data is fetched. + */ ++ (void)enableUpdatesOnAccessTokenChange:(BOOL)enable; + +/*! + @abstract A convenience method for returning a Graph API path for retrieving the user's profile image. + @discussion You can pass this to a `FBSDKGraphRequest` instance to download the image. + @param mode The picture mode + @param size The height and width. This will be rounded to integer precision. + */ +- (NSString *)imagePathForPictureMode:(FBSDKProfilePictureMode)mode size:(CGSize)size; + +/*! + @abstract Returns YES if the profile is equivalent to the receiver. + @param profile the profile to compare to. + */ +- (BOOL)isEqualToProfile:(FBSDKProfile *)profile; +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKProfilePictureView.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKProfilePictureView.h new file mode 100644 index 0000000..f1f64cb --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKProfilePictureView.h @@ -0,0 +1,59 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @typedef FBSDKProfilePictureMode enum + @abstract Defines the aspect ratio mode for the source image of the profile picture. + */ +typedef NS_ENUM(NSUInteger, FBSDKProfilePictureMode) +{ + /*! + @abstract A square cropped version of the image will be included in the view. + */ + FBSDKProfilePictureModeSquare, + /*! + @abstract The original picture's aspect ratio will be used for the source image in the view. + */ + FBSDKProfilePictureModeNormal, +}; + +/*! + @abstract A view to display a profile picture. + */ +@interface FBSDKProfilePictureView : UIView + +/*! + @abstract The mode for the receiver to determine the aspect ratio of the source image. + */ +@property (nonatomic, assign) FBSDKProfilePictureMode pictureMode; + +/*! + @abstract The profile ID to show the picture for. + */ +@property (nonatomic, copy) NSString *profileID; + +/*! + @abstract Explicitly marks the receiver as needing to update the image. + @discussion This method is called whenever any properties that affect the source image are modified, but this can also + be used to trigger a manual update of the image if it needs to be re-downloaded. + */ +- (void)setNeedsImageUpdate; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKSettings.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKSettings.h new file mode 100644 index 0000000..edc0040 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKSettings.h @@ -0,0 +1,209 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/* + * Constants defining logging behavior. Use with <[FBSDKSettings setLoggingBehavior]>. + */ + +/*! Include access token in logging. */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorAccessTokens; + +/*! Log performance characteristics */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorPerformanceCharacteristics; + +/*! Log FBSDKAppEvents interactions */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorAppEvents; + +/*! Log Informational occurrences */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorInformational; + +/*! Log cache errors. */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorCacheErrors; + +/*! Log errors from SDK UI controls */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorUIControlErrors; + +/*! Log debug warnings from API response, i.e. when friends fields requested, but user_friends permission isn't granted. */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorGraphAPIDebugWarning; + +/*! Log warnings from API response, i.e. when requested feature will be deprecated in next version of API. + Info is the lowest level of severity, using it will result in logging all previously mentioned levels. + */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorGraphAPIDebugInfo; + +/*! Log errors from SDK network requests */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorNetworkRequests; + +/*! Log errors likely to be preventable by the developer. This is in the default set of enabled logging behaviors. */ +FBSDK_EXTERN NSString *const FBSDKLoggingBehaviorDeveloperErrors; + +@interface FBSDKSettings : NSObject + +/*! + @abstract Get the Facebook App ID used by the SDK. + @discussion If not explicitly set, the default will be read from the application's plist (FacebookAppID). + */ ++ (NSString *)appID; + +/*! + @abstract Set the Facebook App ID to be used by the SDK. + @param appID The Facebook App ID to be used by the SDK. + */ ++ (void)setAppID:(NSString *)appID; + +/*! + @abstract Get the default url scheme suffix used for sessions. + @discussion If not explicitly set, the default will be read from the application's plist (FacebookUrlSchemeSuffix). + */ ++ (NSString *)appURLSchemeSuffix; + +/*! + @abstract Set the app url scheme suffix used by the SDK. + @param appURLSchemeSuffix The url scheme suffix to be used by the SDK. + */ ++ (void)setAppURLSchemeSuffix:(NSString *)appURLSchemeSuffix; + +/*! + @abstract Retrieve the Client Token that has been set via [FBSDKSettings setClientToken]. + @discussion If not explicitly set, the default will be read from the application's plist (FacebookClientToken). + */ ++ (NSString *)clientToken; + +/*! + @abstract Sets the Client Token for the Facebook App. + @discussion This is needed for certain API calls when made anonymously, without a user-based access token. + @param clientToken The Facebook App's "client token", which, for a given appid can be found in the Security + section of the Advanced tab of the Facebook App settings found at + */ ++ (void)setClientToken:(NSString *)clientToken; + +/*! + @abstract A convenient way to toggle error recovery for all FBSDKGraphRequest instances created after this is set. + @param disableGraphErrorRecovery YES or NO. + */ ++ (void)setGraphErrorRecoveryDisabled:(BOOL)disableGraphErrorRecovery; + +/*! + @abstract Get the Facebook Display Name used by the SDK. + @discussion If not explicitly set, the default will be read from the application's plist (FacebookDisplayName). + */ ++ (NSString *)displayName; + +/*! + @abstract Set the default Facebook Display Name to be used by the SDK. + @discussion This should match the Display Name that has been set for the app with the corresponding Facebook App ID, + in the Facebook App Dashboard. + @param displayName The Facebook Display Name to be used by the SDK. + */ ++ (void)setDisplayName:(NSString *)displayName; + +/*! + @abstract Get the Facebook domain part. + @discussion If not explicitly set, the default will be read from the application's plist (FacebookDomainPart). + */ ++ (NSString *)facebookDomainPart; + +/*! + @abstract Set the subpart of the Facebook domain. + @discussion This can be used to change the Facebook domain (e.g. @"beta") so that requests will be sent to + graph.beta.facebook.com + @param facebookDomainPart The domain part to be inserted into facebook.com. + */ ++ (void)setFacebookDomainPart:(NSString *)facebookDomainPart; + +/*! + @abstract The quality of JPEG images sent to Facebook from the SDK. + @discussion If not explicitly set, the default is 0.9. + @see [UIImageJPEGRepresentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/#//apple_ref/c/func/UIImageJPEGRepresentation) */ ++ (CGFloat)JPEGCompressionQuality; + +/*! + @abstract Set the quality of JPEG images sent to Facebook from the SDK. + @param JPEGCompressionQuality The quality for JPEG images, expressed as a value from 0.0 to 1.0. + @see [UIImageJPEGRepresentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIKitFunctionReference/#//apple_ref/c/func/UIImageJPEGRepresentation) */ ++ (void)setJPEGCompressionQuality:(CGFloat)JPEGCompressionQuality; + +/*! + @abstract + Gets whether data such as that generated through FBSDKAppEvents and sent to Facebook should be restricted from being used for other than analytics and conversions. Defaults to NO. This value is stored on the device and persists across app launches. + */ ++ (BOOL)limitEventAndDataUsage; + +/*! + @abstract + Sets whether data such as that generated through FBSDKAppEvents and sent to Facebook should be restricted from being used for other than analytics and conversions. Defaults to NO. This value is stored on the device and persists across app launches. + + @param limitEventAndDataUsage The desired value. + */ ++ (void)setLimitEventAndDataUsage:(BOOL)limitEventAndDataUsage; + +/*! + @abstract Retrieve the current iOS SDK version. + */ ++ (NSString *)sdkVersion; + +/*! + @abstract Retrieve the current Facebook SDK logging behavior. + */ ++ (NSSet *)loggingBehavior; + +/*! + @abstract Set the current Facebook SDK logging behavior. This should consist of strings defined as + constants with FBSDKLoggingBehavior*. + + @param loggingBehavior A set of strings indicating what information should be logged. If nil is provided, the logging + behavior is reset to the default set of enabled behaviors. Set to an empty set in order to disable all logging. + + @discussion You can also define this via an array in your app plist with key "FacebookLoggingBehavior" or add and remove individual values via enableLoggingBehavior: or disableLogginBehavior: + */ ++ (void)setLoggingBehavior:(NSSet *)loggingBehavior; + +/*! + @abstract Enable a particular Facebook SDK logging behavior. + + @param loggingBehavior The LoggingBehavior to enable. This should be a string defined as a constant with FBSDKLoggingBehavior*. + */ ++ (void)enableLoggingBehavior:(NSString *)loggingBehavior; + +/*! + @abstract Disable a particular Facebook SDK logging behavior. + + @param loggingBehavior The LoggingBehavior to disable. This should be a string defined as a constant with FBSDKLoggingBehavior*. + */ ++ (void)disableLoggingBehavior:(NSString *)loggingBehavior; + +/*! + @abstract Set the user defaults key used by legacy token caches. + + @param tokenInformationKeyName the key used by legacy token caches. + + @discussion Use this only if you customized FBSessionTokenCachingStrategy in v3.x of + the Facebook SDK for iOS. +*/ ++ (void)setLegacyUserDefaultTokenInformationKeyName:(NSString *)tokenInformationKeyName; + +/*! + @abstract Get the user defaults key used by legacy token caches. +*/ ++ (NSString *)legacyUserDefaultTokenInformationKeyName; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKTestUsersManager.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKTestUsersManager.h new file mode 100644 index 0000000..7d2e0ac --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKTestUsersManager.h @@ -0,0 +1,102 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class FBSDKAccessToken; + +/*! + @typedef + + @abstract Callback block for returning an array of FBSDKAccessToken instances (and possibly `NSNull` instances); or an error. + */ +typedef void (^FBSDKTestUsersManagerRetrieveTestAccountTokensHandler)(NSArray *tokens, NSError *error) ; + +/*! + @typedef + + @abstract Callback block for removing a test user. + */ +typedef void (^FBSDKTestUsersManagerRemoveTestAccountHandler)(NSError *error) ; + + +/*! + @class FBSDKTestUsersManager + @abstract Provides methods for managing test accounts for testing Facebook integration. + + @discussion Facebook allows developers to create test accounts for testing their applications' + Facebook integration (see https://developers.facebook.com/docs/test_users/). This class + simplifies use of these accounts for writing tests. It is not designed for use in + production application code. + + This class will make Graph API calls on behalf of your app to manage test accounts and requires + an app id and app secret. You will typically use this class to write unit or integration tests. + Make sure you NEVER include your app secret in your production app. + */ +@interface FBSDKTestUsersManager : NSObject + +/*! + @abstract construct or return the shared instance + @param appID the Facebook app id + @param appSecret the Facebook app secret + */ ++ (instancetype)sharedInstanceForAppID:(NSString *)appID appSecret:(NSString *)appSecret; + +/*! + @abstract retrieve FBSDKAccessToken instances for test accounts with the specific permissions. + @param arraysOfPermissions an array of permissions sets, such as @[ [NSSet setWithObject:@"email"], [NSSet setWithObject:@"user_birthday"]] + if you needed two test accounts with email and birthday permissions, respectively. You can pass in empty nested sets + if you need two arbitrary test accounts. For convenience, passing nil is treated as @[ [NSSet set] ] + for fetching a single test user. + @param createIfNotFound if YES, new test accounts are created if no test accounts existed that fit the permissions + requirement + @param handler the callback to invoke which will return an array of `FBAccessTokenData` instances or an `NSError`. + If param `createIfNotFound` is NO, the array may contain `[NSNull null]` instances. + + @discussion If you are requesting test accounts with differing number of permissions, try to order + `arrayOfPermissionsArrays` so that the most number of permissions come first to minimize creation of new + test accounts. + */ +- (void)requestTestAccountTokensWithArraysOfPermissions:(NSArray *)arraysOfPermissions + createIfNotFound:(BOOL)createIfNotFound + completionHandler:(FBSDKTestUsersManagerRetrieveTestAccountTokensHandler)handler; + +/*! + @abstract add a test account with the specified permissions + @param permissions the set of permissions, e.g., [NSSet setWithObjects:@"email", @"user_friends"] + @param handler the callback handler + */ +- (void)addTestAccountWithPermissions:(NSSet *)permissions + completionHandler:(FBSDKTestUsersManagerRetrieveTestAccountTokensHandler)handler; + +/*! + @abstract remove a test account for the given user id + @param userId the user id + @param handler the callback handler + */ +- (void)removeTestAccount:(NSString *)userId completionHandler:(FBSDKTestUsersManagerRemoveTestAccountHandler)handler; + +/*! + @abstract Make two test users friends with each other. + @param first the token of the first user + @param second the token of the second user + @param callback the callback handler + */ +- (void)makeFriendsWithFirst:(FBSDKAccessToken *)first second:(FBSDKAccessToken *)second callback:(void (^)(NSError *))callback; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKUtility.h b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKUtility.h new file mode 100644 index 0000000..46c490b --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Headers/FBSDKUtility.h @@ -0,0 +1,55 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @abstract Class to contain common utility methods. + */ +@interface FBSDKUtility : NSObject + +/*! + @abstract Parses a query string into a dictionary. + @param queryString The query string value. + @return A dictionary with the key/value pairs. + */ ++ (NSDictionary *)dictionaryWithQueryString:(NSString *)queryString; + +/*! + @abstract Constructs a query string from a dictionary. + @param dictionary The dictionary with key/value pairs for the query string. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @result Query string representation of the parameters. + */ ++ (NSString *)queryStringWithDictionary:(NSDictionary *)dictionary error:(NSError *__autoreleasing *)errorRef; + +/*! + @abstract Decodes a value from an URL. + @param value The value to decode. + @result The decoded value. + */ ++ (NSString *)URLDecode:(NSString *)value; + +/*! + @abstract Encodes a value for an URL. + @param value The value to encode. + @result The encoded value. + */ ++ (NSString *)URLEncode:(NSString *)value; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/Info.plist b/Frameworks/FBSDKCoreKit.framework/Info.plist new file mode 100644 index 0000000..e8bbb13 Binary files /dev/null and b/Frameworks/FBSDKCoreKit.framework/Info.plist differ diff --git a/Frameworks/FBSDKCoreKit.framework/Modules/module.modulemap b/Frameworks/FBSDKCoreKit.framework/Modules/module.modulemap new file mode 100644 index 0000000..3c3e6e6 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/Modules/module.modulemap @@ -0,0 +1,31 @@ +framework module FBSDKCoreKit { + umbrella header "FBSDKCoreKit.h" + + export * + module * { export * } + + explicit module FBSDKButton { + header "FBSDKButton.h" + export * + } + + explicit module FBSDKAppLinkResolver { + header "FBSDKAppLinkResolver.h" + export * + } + + explicit module FBSDKGraphErrorRecoveryProcessor { + header "FBSDKGraphErrorRecoveryProcessor.h" + export * + } + + explicit module FBSDKGraphRequestDataAttachment { + header "FBSDKGraphRequestDataAttachment.h" + export * + } + + explicit module FBSDKTestUsersManager { + header "FBSDKTestUsersManager.h" + export * + } +} diff --git a/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKAccessTokenCacheV4.h b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKAccessTokenCacheV4.h new file mode 100644 index 0000000..7fa7d7f --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKAccessTokenCacheV4.h @@ -0,0 +1,26 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKAccessToken.h" +#import "FBSDKAccessTokenCaching.h" + +@interface FBSDKAccessTokenCacheV4 : NSObject + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKBridgeAPICrypto.h b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKBridgeAPICrypto.h new file mode 100644 index 0000000..7d488e7 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKBridgeAPICrypto.h @@ -0,0 +1,31 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKBridgeAPIRequest.h" + +@interface FBSDKBridgeAPICrypto : NSObject + ++ (void)addCipherKeyToQueryParameters:(NSMutableDictionary *)queryParameters; ++ (NSDictionary *)decryptResponseForRequest:(FBSDKBridgeAPIRequest *)request + queryParameters:(NSDictionary *)queryParameters + error:(NSError *__autoreleasing *)errorRef; ++ (void)reset; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKBridgeAPIProtocol.h b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKBridgeAPIProtocol.h new file mode 100644 index 0000000..1c41f1a --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKBridgeAPIProtocol.h @@ -0,0 +1,46 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import "FBSDKBridgeAPIProtocolType.h" + +@class FBSDKBridgeAPIRequest; + +FBSDK_EXTERN NSString *const FBSDKBridgeAPIAppIDKey; +FBSDK_EXTERN NSString *const FBSDKBridgeAPISchemeSuffixKey; +FBSDK_EXTERN NSString *const FBSDKBridgeAPIVersionKey; + +@protocol FBSDKBridgeAPIProtocol + +@property (nonatomic, assign, readonly, getter=isEnabled) BOOL enabled; + +- (NSURL *)requestURLWithActionID:(NSString *)actionID + scheme:(NSString *)scheme + methodName:(NSString *)methodName + methodVersion:(NSString *)methodVersion + parameters:(NSDictionary *)parameters + error:(NSError *__autoreleasing *)errorRef; +- (NSDictionary *)responseParametersForActionID:(NSString *)actionID + queryParameters:(NSDictionary *)queryParameters + cancelled:(BOOL *)cancelledRef + error:(NSError *__autoreleasing *)errorRef; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKBridgeAPIProtocolNativeV1.h b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKBridgeAPIProtocolNativeV1.h new file mode 100644 index 0000000..8fd34bd --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKBridgeAPIProtocolNativeV1.h @@ -0,0 +1,70 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import "FBSDKBridgeAPIProtocol.h" + +typedef struct +{ + __unsafe_unretained NSString *bridgeArgs; + __unsafe_unretained NSString *methodArgs; + __unsafe_unretained NSString *methodVersion; +} FBSDKBridgeAPIProtocolNativeV1OutputKeysStruct; +FBSDK_EXTERN const FBSDKBridgeAPIProtocolNativeV1OutputKeysStruct FBSDKBridgeAPIProtocolNativeV1OutputKeys; + +typedef struct +{ + __unsafe_unretained NSString *actionID; + __unsafe_unretained NSString *appIcon; + __unsafe_unretained NSString *appName; + __unsafe_unretained NSString *sdkVersion; +} FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeysStruct; +FBSDK_EXTERN const FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeysStruct FBSDKBridgeAPIProtocolNativeV1BridgeParameterOutputKeys; + +typedef struct +{ + __unsafe_unretained NSString *bridgeArgs; + __unsafe_unretained NSString *methodResults; +} FBSDKBridgeAPIProtocolNativeV1InputKeysStruct; +FBSDK_EXTERN const FBSDKBridgeAPIProtocolNativeV1InputKeysStruct FBSDKBridgeAPIProtocolNativeV1InputKeys; + +typedef struct +{ + __unsafe_unretained NSString *actionID; + __unsafe_unretained NSString *error; +} FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeysStruct; +FBSDK_EXTERN const FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeysStruct FBSDKBridgeAPIProtocolNativeV1BridgeParameterInputKeys; + +@interface FBSDKBridgeAPIProtocolNativeV1 : NSObject + +- (instancetype)initWithAppScheme:(NSString *)appScheme; +- (instancetype)initWithAppScheme:(NSString *)appScheme + pasteboard:(UIPasteboard *)pasteboard + dataLengthThreshold:(NSUInteger)dataLengthThreshold + includeAppIcon:(BOOL)includeAppIcon +NS_DESIGNATED_INITIALIZER; + +@property (nonatomic, copy, readonly) NSString *appScheme; +@property (nonatomic, assign, readonly) NSUInteger dataLengthThreshold; +@property (nonatomic, assign, readonly) BOOL includeAppIcon; +@property (nonatomic, strong, readonly) UIPasteboard *pasteboard; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKBridgeAPIProtocolWebV1.h b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKBridgeAPIProtocolWebV1.h new file mode 100644 index 0000000..c7b28f4 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKBridgeAPIProtocolWebV1.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKBridgeAPIProtocol.h" + +@interface FBSDKBridgeAPIProtocolWebV1 : NSObject + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKError.h b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKError.h new file mode 100644 index 0000000..f37bd86 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKError.h @@ -0,0 +1,56 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@interface FBSDKError : NSObject + ++ (NSString *)errorDomain; + ++ (BOOL)errorIsNetworkError:(NSError *)error; + ++ (NSError *)errorWithCode:(NSInteger)code message:(NSString *)message; ++ (NSError *)errorWithCode:(NSInteger)code message:(NSString *)message underlyingError:(NSError *)underlyingError; ++ (NSError *)errorWithCode:(NSInteger)code + userInfo:(NSDictionary *)userInfo + message:(NSString *)message + underlyingError:(NSError *)underlyingError; + ++ (NSError *)invalidArgumentErrorWithName:(NSString *)name value:(id)value message:(NSString *)message; ++ (NSError *)invalidArgumentErrorWithName:(NSString *)name + value:(id)value + message:(NSString *)message + underlyingError:(NSError *)underlyingError; ++ (NSError *)invalidCollectionErrorWithName:(NSString *)name + collection:(id)collection + item:(id)item + message:(NSString *)message; ++ (NSError *)invalidCollectionErrorWithName:(NSString *)name + collection:(id)collection + item:(id)item + message:(NSString *)message + underlyingError:(NSError *)underlyingError; + ++ (NSError *)requiredArgumentErrorWithName:(NSString *)name message:(NSString *)message; ++ (NSError *)requiredArgumentErrorWithName:(NSString *)name + message:(NSString *)message + underlyingError:(NSError *)underlyingError; + ++ (NSError *)unknownErrorWithMessage:(NSString *)message; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKGraphRequestBody.h b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKGraphRequestBody.h new file mode 100644 index 0000000..b61c782 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKGraphRequestBody.h @@ -0,0 +1,47 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +@class FBSDKGraphRequestDataAttachment; +@class FBSDKLogger; + +@interface FBSDKGraphRequestBody : NSObject + +@property (nonatomic, retain, readonly) NSData *data; + +- (void)appendWithKey:(NSString *)key + formValue:(NSString *)value + logger:(FBSDKLogger *)logger; + +- (void)appendWithKey:(NSString *)key + imageValue:(UIImage *)image + logger:(FBSDKLogger *)logger; + +- (void)appendWithKey:(NSString *)key + dataValue:(NSData *)data + logger:(FBSDKLogger *)logger; + +- (void)appendWithKey:(NSString *)key + dataAttachmentValue:(FBSDKGraphRequestDataAttachment *)dataAttachment + logger:(FBSDKLogger *)logger; + ++ (NSString *)mimeContentType; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKGraphRequestMetadata.h b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKGraphRequestMetadata.h new file mode 100644 index 0000000..801485d --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKGraphRequestMetadata.h @@ -0,0 +1,40 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +// Internal only class to facilitate FBRequest processing, specifically +// associating FBRequest and FBRequestHandler instances and necessary +// data for retry processing. +@interface FBSDKGraphRequestMetadata : NSObject + +@property (nonatomic, retain) FBSDKGraphRequest *request; +@property (nonatomic, copy) FBSDKGraphRequestHandler completionHandler; +@property (nonatomic, copy) NSDictionary *batchParameters; + +- (instancetype)initWithRequest:(FBSDKGraphRequest *)request + completionHandler:(FBSDKGraphRequestHandler)handler + batchParameters:(NSDictionary *)batchParameters +NS_DESIGNATED_INITIALIZER; + +- (void)invokeCompletionHandlerForConnection:(FBSDKGraphRequestConnection *)connection + withResults:(id)results + error:(NSError *)error; +@end diff --git a/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKURLConnection.h b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKURLConnection.h new file mode 100644 index 0000000..cbe80a0 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKURLConnection.h @@ -0,0 +1,51 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class FBSDKURLConnection; + +typedef void (^FBSDKURLConnectionHandler)(FBSDKURLConnection *connection, + NSError *error, + NSURLResponse *response, + NSData *responseData); + +@protocol FBSDKURLConnectionDelegate + +@optional + +- (void)facebookURLConnection:(FBSDKURLConnection *)connection + didSendBodyData:(NSInteger)bytesWritten + totalBytesWritten:(NSInteger)totalBytesWritten + totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite; + +@end + +@interface FBSDKURLConnection : NSObject + +- (FBSDKURLConnection *)initWithRequest:(NSURLRequest *)request + completionHandler:(FBSDKURLConnectionHandler)handler +NS_DESIGNATED_INITIALIZER; + +@property (nonatomic, assign) id delegate; + +- (void)cancel; +- (void)start; +- (void)setDelegateQueue:(NSOperationQueue *)queue; + +@end diff --git a/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKWebDialogView.h b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKWebDialogView.h new file mode 100644 index 0000000..9ad7427 --- /dev/null +++ b/Frameworks/FBSDKCoreKit.framework/PrivateHeaders/FBSDKWebDialogView.h @@ -0,0 +1,39 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@protocol FBSDKWebDialogViewDelegate; + +@interface FBSDKWebDialogView : UIView + +@property (nonatomic, assign) id delegate; + +- (void)loadURL:(NSURL *)URL; +- (void)stopLoading; + +@end + +@protocol FBSDKWebDialogViewDelegate + +- (void)webDialogView:(FBSDKWebDialogView *)webDialogView didCompleteWithResults:(NSDictionary *)results; +- (void)webDialogView:(FBSDKWebDialogView *)webDialogView didFailWithError:(NSError *)error; +- (void)webDialogViewDidCancel:(FBSDKWebDialogView *)webDialogView; +- (void)webDialogViewDidFinishLoad:(FBSDKWebDialogView *)webDialogView; + +@end diff --git a/Frameworks/FBSDKLoginKit.framework/FBSDKLoginKit b/Frameworks/FBSDKLoginKit.framework/FBSDKLoginKit new file mode 100644 index 0000000..85eef4b Binary files /dev/null and b/Frameworks/FBSDKLoginKit.framework/FBSDKLoginKit differ diff --git a/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginButton.h b/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginButton.h new file mode 100644 index 0000000..7aaec92 --- /dev/null +++ b/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginButton.h @@ -0,0 +1,117 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import + +#import "FBSDKTooltipView.h" + +@protocol FBSDKLoginButtonDelegate; + +/*! + @typedef NS_ENUM(NSUInteger, FBSDKLoginButtonTooltipBehavior) + @abstract Indicates the desired login tooltip behavior. + */ +typedef NS_ENUM(NSUInteger, FBSDKLoginButtonTooltipBehavior) +{ + /*! The default behavior. The tooltip will only be displayed if + the app is eligible (determined by possible server round trip) */ + FBSDKLoginButtonTooltipBehaviorAutomatic = 0, + /*! Force display of the tooltip (typically for UI testing) */ + FBSDKLoginButtonTooltipBehaviorForceDisplay = 1, + /*! Force disable. In this case you can still exert more refined + control by manually constructing a `FBSDKLoginTooltipView` instance. */ + FBSDKLoginButtonTooltipBehaviorDisable = 2 +}; + +/*! + @abstract A button to simplify login. + @discussion `FBSDKLoginButton` works with `[FBSDKAccessToken currentAccessToken]` to + determine what to display. The delegate is only notified when a login flow is initiated + by a tapping the button and your app delegate is connected to `FBSDKApplicationDelegate` + (in the same way when using `FBSDKLoginManager`). + + `FBSDKLoginButton` has a fixed height, but you may change the width. `initWithFrame:CGRectZero` + will size the button to its minimum frame. +*/ +@interface FBSDKLoginButton : FBSDKButton + +/*! + @abstract The default audience to use, if publish permissions are requested at login time. + */ +@property (assign, nonatomic) FBSDKDefaultAudience defaultAudience; +/*! + @abstract Gets or sets the delegate. + */ +@property (weak, nonatomic) IBOutlet id delegate; +/*! + @abstract Gets or sets the login behavior to use + */ +@property (assign, nonatomic) FBSDKLoginBehavior loginBehavior; +/*! + @abstract The publish permissions to request. + + @discussion Use `defaultAudience` to specify the default audience to publish to. + Note this is converted to NSSet and is only + an NSArray for the convenience of literal syntax. + */ +@property (copy, nonatomic) NSArray *publishPermissions; +/*! + @abstract The read permissions to request. + + @discussion Note, that if read permissions are specified, then publish permissions should not be specified. This is converted to NSSet and is only + an NSArray for the convenience of literal syntax. + */ +@property (copy, nonatomic) NSArray *readPermissions; +/*! + @abstract Gets or sets the desired tooltip behavior. + */ +@property (assign, nonatomic) FBSDKLoginButtonTooltipBehavior tooltipBehavior; +/*! + @abstract Gets or sets the desired tooltip color style. + */ +@property (assign, nonatomic) FBSDKTooltipColorStyle tooltipColorStyle; + +@end + +/*! + @protocol + @abstract A delegate for `FBSDKLoginButton` + */ +@protocol FBSDKLoginButtonDelegate + +/*! + @abstract Sent to the delegate when the button was used to login. + @param loginButton the sender + @param result The results of the login + @param error The error (if any) from the login + */ +- (void) loginButton:(FBSDKLoginButton *)loginButton +didCompleteWithResult:(FBSDKLoginManagerLoginResult *)result + error:(NSError *)error; + +/*! + @abstract Sent to the delegate when the button was used to logout. + @param loginButton The button that was clicked. +*/ +- (void)loginButtonDidLogOut:(FBSDKLoginButton *)loginButton; + +@end diff --git a/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginConstants.h b/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginConstants.h new file mode 100644 index 0000000..100c09a --- /dev/null +++ b/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginConstants.h @@ -0,0 +1,75 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract The error domain for all errors from FBSDKLoginKit + @discussion Error codes from the SDK in the range 300-399 are reserved for this domain. + */ +FBSDK_EXTERN NSString *const FBSDKLoginErrorDomain; + +/*! + @typedef NS_ENUM(NSInteger, FBSDKLoginErrorCode) + @abstract Error codes for FBSDKLoginErrorDomain. + */ +typedef NS_ENUM(NSInteger, FBSDKLoginErrorCode) +{ + /*! + @abstract Reserved. + */ + FBSDKLoginReservedErrorCode = 300, + /*! + @abstract The error code for unknown errors. + */ + FBSDKLoginUnknownErrorCode, + + /*! + @abstract The user's password has changed and must log in again + */ + FBSDKLoginPasswordChangedErrorCode, + /*! + @abstract The user must log in to their account on www.facebook.com to restore access + */ + FBSDKLoginUserCheckpointedErrorCode, + /*! + @abstract Indicates a failure to request new permissions because the user has changed. + */ + FBSDKLoginUserMismatchErrorCode, + /*! + @abstract The user must confirm their account with Facebook before logging in + */ + FBSDKLoginUnconfirmedUserErrorCode, + + /*! + @abstract The Accounts framework failed without returning an error, indicating the + app's slider in the iOS Facebook Settings (device Settings -> Facebook -> App Name) has + been disabled. + */ + FBSDKLoginSystemAccountAppDisabledErrorCode, + /*! + @abstract An error occurred related to Facebook system Account store + */ + FBSDKLoginSystemAccountUnavailableErrorCode, + /*! + @abstract The login response was missing a valid challenge string. + */ + FBSDKLoginBadChallengeString, +}; diff --git a/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginKit.h b/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginKit.h new file mode 100644 index 0000000..4723940 --- /dev/null +++ b/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginKit.h @@ -0,0 +1,25 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import +#import +#import +#import diff --git a/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginManager.h b/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginManager.h new file mode 100644 index 0000000..2a6ec8f --- /dev/null +++ b/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginManager.h @@ -0,0 +1,186 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +@class FBSDKLoginManagerLoginResult; + +/*! + @abstract Describes the call back to the FBSDKLoginManager + @param result the result of the authorization + @param error the authorization error, if any. + */ +typedef void (^FBSDKLoginManagerRequestTokenHandler)(FBSDKLoginManagerLoginResult *result, NSError *error); + + +/*! + @typedef FBSDKDefaultAudience enum + + @abstract + Passed to open to indicate which default audience to use for sessions that post data to Facebook. + + @discussion + Certain operations such as publishing a status or publishing a photo require an audience. When the user + grants an application permission to perform a publish operation, a default audience is selected as the + publication ceiling for the application. This enumerated value allows the application to select which + audience to ask the user to grant publish permission for. + */ +typedef NS_ENUM(NSUInteger, FBSDKDefaultAudience) +{ + /*! Indicates that the user's friends are able to see posts made by the application */ + FBSDKDefaultAudienceFriends = 0, + /*! Indicates that only the user is able to see posts made by the application */ + FBSDKDefaultAudienceOnlyMe, + /*! Indicates that all Facebook users are able to see posts made by the application */ + FBSDKDefaultAudienceEveryone, +}; + +/*! + @typedef FBSDKLoginBehavior enum + + @abstract + Passed to the \c FBSDKLoginManager to indicate how Facebook Login should be attempted. + + @discussion + Facebook Login authorizes the application to act on behalf of the user, using the user's + Facebook account. Usually a Facebook Login will rely on an account maintained outside of + the application, by the native Facebook application, the browser, or perhaps the device + itself. This avoids the need for a user to enter their username and password directly, and + provides the most secure and lowest friction way for a user to authorize the application to + interact with Facebook. + + The \c FBSDKLoginBehavior enum specifies which log in method should be attempted. Most + applications will use the default, which attempts a login through the Facebook app and falls + back to the browser if needed. + + If log in cannot be completed using the specificed behavior, the completion handler will + be invoked with an error in the \c FBSDKErrorDomain and a code of \c FBSDKLoginUnknownErrorCode. + */ +typedef NS_ENUM(NSUInteger, FBSDKLoginBehavior) +{ + /*! + @abstract Attempts log in through the native Facebook app. If the Facebook app is + not installed on the device, falls back to \c FBSDKLoginBehaviorBrowser. This is the + default behavior. + */ + FBSDKLoginBehaviorNative = 0, + /*! + @abstract Attempts log in through the Safari browser + */ + FBSDKLoginBehaviorBrowser, + /*! + @abstract Attempts log in through the Facebook account currently signed in through Settings. + If no Facebook account is signed in, falls back to \c FBSDKLoginBehaviorNative. + */ + FBSDKLoginBehaviorSystemAccount, + /*! + @abstract Attemps log in through a modal \c UIWebView pop up + + @note This behavior is only available to certain types of apps. Please check the Facebook + Platform Policy to verify your app meets the restrictions. + */ + FBSDKLoginBehaviorWeb, +}; + +/*! + @abstract `FBSDKLoginManager` provides methods for logging the user in and out. + @discussion `FBSDKLoginManager` works directly with `[FBSDKAccessToken currentAccessToken]` and + sets the "currentAccessToken" upon successful authorizations (or sets `nil` in case of `logOut`). + + You should check `[FBSDKAccessToken currentAccessToken]` before calling logIn* to see if there is + a cached token available (typically in your viewDidLoad). + + If you are managing your own token instances outside of "currentAccessToken", you will need to set + "currentAccessToken" before calling logIn* to authorize futher permissions on your tokens. + */ +@interface FBSDKLoginManager : NSObject + +/*! + @abstract the default audience. + @discussion you should set this if you intend to ask for publish permissions. + */ +@property (assign, nonatomic) FBSDKDefaultAudience defaultAudience; + +/*! + @abstract the login behavior + @discussion you should only set this if you want an explicit login flow; otherwise, the SDK + will automatically determine the best flow available. + */ +@property (assign, nonatomic) FBSDKLoginBehavior loginBehavior; + +/*! + @abstract Logs the user in or authorizes additional permissions. + @param permissions the optional array of permissions. Note this is converted to NSSet and is only + an NSArray for the convenience of literal syntax. + @param handler the callback. + @discussion Use this method when asking for read permissions. You should only ask for permissions when they + are needed and explain the value to the user. You can inspect the result.declinedPermissions to also + provide more information to the user if they decline permissions. + + If `[FBSDKAccessToken currentAccessToken]` is not nil, it will be treated as a reauthorization for that user + and will pass the "rerequest" flag to the login dialog. + + This method will present UI the user. You typically should check if `[FBSDKAccessToken currentAccessToken]` + already contains the permissions you need before asking to reduce unnecessary app switching. For example, + you could make that check at viewDidLoad. + */ +- (void)logInWithReadPermissions:(NSArray *)permissions handler:(FBSDKLoginManagerRequestTokenHandler)handler; + +/*! + @abstract Logs the user in or authorizes additional permissions. + @param permissions the optional array of permissions. Note this is converted to NSSet and is only + an NSArray for the convenience of literal syntax. + @param handler the callback. + @discussion Use this method when asking for publish permissions. You should only ask for permissions when they + are needed and explain the value to the user. You can inspect the result.declinedPermissions to also + provide more information to the user if they decline permissions. + + If `[FBSDKAccessToken currentAccessToken]` is not nil, it will be treated as a reauthorization for that user + and will pass the "rerequest" flag to the login dialog. + + This method will present UI the user. You typically should check if `[FBSDKAccessToken currentAccessToken]` + already contains the permissions you need before asking to reduce unnecessary app switching. For example, + you could make that check at viewDidLoad. + */ +- (void)logInWithPublishPermissions:(NSArray *)permissions handler:(FBSDKLoginManagerRequestTokenHandler)handler; + +/*! + @abstract Logs the user out + @discussion This calls [FBSDKAccessToken setCurrentAccessToken:nil] and [FBSDKProfile setCurrentProfile:nil]. + */ +- (void)logOut; + +/*! + @method + + @abstract Issues an asychronous renewCredentialsForAccount call to the device's Facebook account store. + + @param handler The completion handler to call when the renewal is completed. This can be invoked on an arbitrary thread. + + @discussion This can be used to explicitly renew account credentials and is provided as a convenience wrapper around + `[ACAccountStore renewCredentialsForAccount:completion]`. Note the method will not issue the renewal call if the the + Facebook account has not been set on the device, or if access had not been granted to the account (though the handler + wil receive an error). + + If the `[FBSDKAccessToken currentAccessToken]` was from the account store, a succesful renewal will also set + a new "currentAccessToken". + */ ++ (void)renewSystemCredentials:(void (^)(ACAccountCredentialRenewResult result, NSError *error))handler; + +@end diff --git a/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginManagerLoginResult.h b/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginManagerLoginResult.h new file mode 100644 index 0000000..36a1af6 --- /dev/null +++ b/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginManagerLoginResult.h @@ -0,0 +1,62 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class FBSDKAccessToken; + +/*! + @abstract Describes the result of a login attempt. + */ +@interface FBSDKLoginManagerLoginResult : NSObject + +/*! + @abstract the access token. + */ +@property (copy, nonatomic) FBSDKAccessToken *token; + +/*! + @abstract whether the login was cancelled by the user. + */ +@property (readonly, nonatomic) BOOL isCancelled; + +/*! + @abstract the set of permissions granted by the user in the associated request. + @discussion inspect the token's permissions set for a complete list. + */ +@property (copy, nonatomic) NSSet *grantedPermissions; + +/*! + @abstract the set of permissions declined by the user in the associated request. + @discussion inspect the token's permissions set for a complete list. + */ +@property (copy, nonatomic) NSSet *declinedPermissions; + +/*! + @abstract Initializes a new instance. + @param token the access token + @param isCancelled whether the login was cancelled by the user + @param grantedPermissions the set of granted permissions + @param declinedPermissions the set of declined permissions + */ +- (instancetype)initWithToken:(FBSDKAccessToken *)token + isCancelled:(BOOL)isCancelled + grantedPermissions:(NSSet *)grantedPermissions + declinedPermissions:(NSSet *)declinedPermissions +NS_DESIGNATED_INITIALIZER; +@end diff --git a/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginTooltipView.h b/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginTooltipView.h new file mode 100644 index 0000000..e6a9411 --- /dev/null +++ b/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKLoginTooltipView.h @@ -0,0 +1,93 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@protocol FBSDKLoginTooltipViewDelegate; + +/*! + @class FBSDKLoginTooltipView + + @abstract Represents a tooltip to be displayed next to a Facebook login button + to highlight features for new users. + + @discussion The `FBSDKLoginButton` may display this view automatically. If you do + not use the `FBSDKLoginButton`, you can manually call one of the `present*` methods + as appropriate and customize behavior via `FBSDKLoginTooltipViewDelegate` delegate. + + By default, the `FBSDKLoginTooltipView` is not added to the superview until it is + determined the app has migrated to the new login experience. You can override this + (e.g., to test the UI layout) by implementing the delegate or setting `forceDisplay` to YES. + + */ +@interface FBSDKLoginTooltipView : FBSDKTooltipView + +/*! @abstract the delegate */ +@property (nonatomic, assign) id delegate; + +/*! @abstract if set to YES, the view will always be displayed and the delegate's + `loginTooltipView:shouldAppear:` will NOT be called. */ +@property (nonatomic, assign) BOOL forceDisplay; + +@end + +/*! + @protocol + + @abstract + The `FBSDKLoginTooltipViewDelegate` protocol defines the methods used to receive event + notifications from `FBSDKLoginTooltipView` objects. + */ +@protocol FBSDKLoginTooltipViewDelegate + +@optional + +/*! + @abstract + Asks the delegate if the tooltip view should appear + + @param view The tooltip view. + @param appIsEligible The value fetched from the server identifying if the app + is eligible for the new login experience. + + @discussion Use this method to customize display behavior. + */ +- (BOOL)loginTooltipView:(FBSDKLoginTooltipView *)view shouldAppear:(BOOL)appIsEligible; + +/*! + @abstract + Tells the delegate the tooltip view will appear, specifically after it's been + added to the super view but before the fade in animation. + + @param view The tooltip view. + */ +- (void)loginTooltipViewWillAppear:(FBSDKLoginTooltipView *)view; + +/*! + @abstract + Tells the delegate the tooltip view will not appear (i.e., was not + added to the super view). + + @param view The tooltip view. + */ +- (void)loginTooltipViewWillNotAppear:(FBSDKLoginTooltipView *)view; + + +@end diff --git a/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKTooltipView.h b/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKTooltipView.h new file mode 100644 index 0000000..aff1067 --- /dev/null +++ b/Frameworks/FBSDKLoginKit.framework/Headers/FBSDKTooltipView.h @@ -0,0 +1,141 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @typedef FBSDKTooltipViewArrowDirection enum + + @abstract + Passed on construction to determine arrow orientation. + */ +typedef NS_ENUM(NSUInteger, FBSDKTooltipViewArrowDirection) +{ + /*! View is located above given point, arrow is pointing down. */ + FBSDKTooltipViewArrowDirectionDown = 0, + /*! View is located below given point, arrow is pointing up. */ + FBSDKTooltipViewArrowDirectionUp = 1, +}; + +/*! + @typedef FBSDKTooltipColorStyle enum + + @abstract + Passed on construction to determine color styling. + */ +typedef NS_ENUM(NSUInteger, FBSDKTooltipColorStyle) +{ + /*! Light blue background, white text, faded blue close button. */ + FBSDKTooltipColorStyleFriendlyBlue = 0, + /*! Dark gray background, white text, light gray close button. */ + FBSDKTooltipColorStyleNeutralGray = 1, +}; + +/*! + @class FBSDKTooltipView + + @abstract + Tooltip bubble with text in it used to display tips for UI elements, + with a pointed arrow (to refer to the UI element). + + @discussion + The tooltip fades in and will automatically fade out. See `displayDuration`. + */ +@interface FBSDKTooltipView : UIView + +/*! + @abstract Gets or sets the amount of time in seconds the tooltip should be displayed. + + @discussion Set this to zero to make the display permanent until explicitly dismissed. + Defaults to six seconds. + */ +@property (nonatomic, assign) CFTimeInterval displayDuration; + +/*! + @abstract Gets or sets the color style after initialization. + + @discussion Defaults to value passed to -initWithTagline:message:colorStyle:. + */ +@property (nonatomic, assign) FBSDKTooltipColorStyle colorStyle; + +/*! + @abstract Gets or sets the message. + */ +@property (nonatomic, copy) NSString *message; + +/*! + @abstract Gets or sets the optional phrase that comprises the first part of the label (and is highlighted differently). + */ +@property (nonatomic, copy) NSString *tagline; + +/*! + @abstract + Designated initializer. + + @param tagline First part of the label, that will be highlighted with different color. Can be nil. + + @param message Main message to display. + + @param colorStyle Color style to use for tooltip. + + @discussion + If you need to show a tooltip for login, consider using the `FBSDKLoginTooltipView` view. + + @see FBSDKLoginTooltipView + */ +- (instancetype)initWithTagline:(NSString *)tagline message:(NSString *)message colorStyle:(FBSDKTooltipColorStyle)colorStyle; + +/*! + @abstract + Show tooltip at the top or at the bottom of given view. + Tooltip will be added to anchorView.window.rootViewController.view + + @param anchorView view to show at, must be already added to window view hierarchy, in order to decide + where tooltip will be shown. (If there's not enough space at the top of the anchorView in window bounds - + tooltip will be shown at the bottom of it) + + @discussion + Use this method to present the tooltip with automatic positioning or + use -presentInView:withArrowPosition:direction: for manual positioning + If anchorView is nil or has no window - this method does nothing. + */ +- (void)presentFromView:(UIView *)anchorView; + +/*! + @abstract + Adds tooltip to given view, with given position and arrow direction. + + @param view View to be used as superview. + + @param arrowPosition Point in view's cordinates, where arrow will be pointing + + @param arrowDirection whenever arrow should be pointing up (message bubble is below the arrow) or + down (message bubble is above the arrow). + */ +- (void)presentInView:(UIView *)view withArrowPosition:(CGPoint)arrowPosition direction:(FBSDKTooltipViewArrowDirection)arrowDirection; + +/*! + @abstract + Remove tooltip manually. + + @discussion + Calling this method isn't necessary - tooltip will dismiss itself automatically after the `displayDuration`. + */ +- (void)dismiss; + +@end diff --git a/Frameworks/FBSDKLoginKit.framework/Info.plist b/Frameworks/FBSDKLoginKit.framework/Info.plist new file mode 100644 index 0000000..fb3726e Binary files /dev/null and b/Frameworks/FBSDKLoginKit.framework/Info.plist differ diff --git a/Frameworks/FBSDKLoginKit.framework/Modules/module.modulemap b/Frameworks/FBSDKLoginKit.framework/Modules/module.modulemap new file mode 100644 index 0000000..4b1d57b --- /dev/null +++ b/Frameworks/FBSDKLoginKit.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module FBSDKLoginKit { + umbrella header "FBSDKLoginKit.h" + + export * + module * { export * } +} diff --git a/Frameworks/FBSDKMessengerShareKit.framework/FBSDKMessengerShareKit b/Frameworks/FBSDKMessengerShareKit.framework/FBSDKMessengerShareKit new file mode 100644 index 0000000..d24f158 Binary files /dev/null and b/Frameworks/FBSDKMessengerShareKit.framework/FBSDKMessengerShareKit differ diff --git a/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerBroadcastContext.h b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerBroadcastContext.h new file mode 100644 index 0000000..ce05fb6 --- /dev/null +++ b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerBroadcastContext.h @@ -0,0 +1,31 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKMessengerShareKit.h" + +/*! + @class FBSDKMessengerBroadcastContext + + @abstract + This object is used as an override in FBSDKMessengerShareOptions to ensure + the broadcast flow in Messenger is triggered, even if your app was entered from + a flow that normally triggers the Messenger reply flow + */ +@interface FBSDKMessengerBroadcastContext : FBSDKMessengerContext + +@end diff --git a/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerButton.h b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerButton.h new file mode 100644 index 0000000..921a2c8 --- /dev/null +++ b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerButton.h @@ -0,0 +1,78 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @abstract + Defines what visual style a UIButton should have + */ +typedef NS_ENUM(NSUInteger, FBSDKMessengerShareButtonStyle) { + FBSDKMessengerShareButtonStyleBlue = 0, + FBSDKMessengerShareButtonStyleWhite = 1, + FBSDKMessengerShareButtonStyleWhiteBordered = 2, +}; + +/*! + @class FBSDKMessengerShareButton + + @abstract + Provides a helper method to return a UIButton intended for sharing to Messenger + */ +@interface FBSDKMessengerShareButton : NSObject + +/*! + @abstract + Returns a rounded rectangular UIButton customized for sharing to Messenger + + @param style Specifies how the button should look + + @discussion + This button can be resized after creation + + There is 1 string in the implemention of this button which needs to be translated + by your app: + + NSLocalizedString(@"Send", @"Button label for sending a message") + */ ++ (UIButton *)rectangularButtonWithStyle:(FBSDKMessengerShareButtonStyle)style; + + +/*! + @abstract + Returns a circular UIButton customized for sharing to Messenger + + @param style Specifies how the button should look + @param width The desired frame width (and height) of this button. + + @discussion + This button's asset is drawn as a vector such that it scales appropriately + using the width parameter as a hint. This hint is to prevent button resizing artifacts. + */ ++ (UIButton *)circularButtonWithStyle:(FBSDKMessengerShareButtonStyle)style + width:(CGFloat)width; + +/*! + @abstract + Returns a circular UIButton customized for sharing to Messenger of default size + + @param style Specifies how the button should look + */ ++ (UIButton *)circularButtonWithStyle:(FBSDKMessengerShareButtonStyle)style; + +@end diff --git a/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerContext.h b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerContext.h new file mode 100644 index 0000000..5921480 --- /dev/null +++ b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerContext.h @@ -0,0 +1,28 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @class FBSDKMessengerContext + + @abstract + This represents the way that content is shared between Messenger and partner apps. + */ +@interface FBSDKMessengerContext : NSObject +@end diff --git a/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerShareKit.h b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerShareKit.h new file mode 100644 index 0000000..9ec734f --- /dev/null +++ b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerShareKit.h @@ -0,0 +1,31 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#define FBSDK_MESSENGER_SHARE_KIT_VERSION @"1.2.2" + +#import "FBSDKMessengerContext.h" +#import "FBSDKMessengerSharer.h" +#import "FBSDKMessengerURLHandler.h" +#import "FBSDKMessengerURLHandlerReplyContext.h" +#import "FBSDKMessengerURLHandlerOpenFromComposerContext.h" +#import "FBSDKMessengerButton.h" +#import "FBSDKMessengerURLHandlerCancelContext.h" +#import "FBSDKMessengerShareOptions.h" +#import "FBSDKMessengerBroadcastContext.h" diff --git a/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerShareOptions.h b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerShareOptions.h new file mode 100644 index 0000000..4a72e2b --- /dev/null +++ b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerShareOptions.h @@ -0,0 +1,57 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKMessengerContext.h" + +/*! + @class FBSDKMessengerShareOptions + + @abstract + Optional parameters that change the way content is shared into Messenger + */ +@interface FBSDKMessengerShareOptions : NSObject + +/*! + @abstract Pass additional information to be sent to Messenger which is sent back to + the user's app when they reply to an attributed message. + */ +@property (nonatomic, readwrite, copy) NSString *metadata; + +/*! +@abstract Optional property describing the www source URL of the content + +@discussion Setting this property improves performance by allowing Messenger to download + the content directly rather than uploading the content from your app. + This option is only used for animated GIFs and WebPs +*/ +@property (nonatomic, readwrite, copy) NSURL *sourceURL; + +/*! + @abstract Optional property that overrides the default way the content will be shared to messenger + + @discussion By default, if a user enters your app via a replyable context in Messenger + (for instance, tapping Reply on a message or opening your app from composer), the next share + out of your app will trigger the reply flow in Messenger by default. If you'd prefer to not + trigger the reply flow, then overriding this with FBSDKMessengerBroadcastContext will trigger the + broadcast flow in messenger. + */ +@property (nonatomic, readwrite, strong) FBSDKMessengerContext *contextOverride; + +@end diff --git a/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerSharer.h b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerSharer.h new file mode 100644 index 0000000..ccecd53 --- /dev/null +++ b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerSharer.h @@ -0,0 +1,240 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +@class FBSDKMessengerContext; +@class FBSDKMessengerShareOptions; + +/*! + @typedef NS_OPTION(NSUInteger, FBSDKMessengerPlatformCapability) + @abstract Used to test the platform capabilities the currently installed Messenger version has + */ +typedef NS_OPTIONS(NSUInteger, FBSDKMessengerPlatformCapability) +{ + FBSDKMessengerPlatformCapabilityNone = 0, + FBSDKMessengerPlatformCapabilityOpen = 1 << 0, + FBSDKMessengerPlatformCapabilityImage = 1 << 1, + FBSDKMessengerPlatformCapabilityAnimatedGIF = 1 << 2, + FBSDKMessengerPlatformCapabilityAnimatedWebP = 1 << 3, + FBSDKMessengerPlatformCapabilityVideo = 1 << 4, + FBSDKMessengerPlatformCapabilityAudio = 1 << 5, +}; + +/*! + @class FBSDKMessengerSharer + + @abstract + The FBSDKMessengerSharer is used to share media from apps into Messenger. The underlying + mechanism used to share data between apps is UIPasteboard + + @discussion + - FacebookAppID must be set in the your app's Info.plist with the Facebook App Id + - Any existing data in the system's public pasteboard will get overwritten with the shared media + - Once the data is shared in Messenger, the pasteboard with be cleared + - The following strings need to be translated in your app: + NSLocalizedString(@"Get Messenger", @"Alert title telling a user they need to install Messenger") + NSLocalizedString(@"You'll need to install the latest version of Messenger to send this.", @"Alert message when an old version of messenger is installed") + NSLocalizedString(@"Not Now", @"Button label when user doesn't want to install Messenger") + NSLocalizedString(@"Install", @"Button label to install Messenger") + NSLocalizedString(@"Send", @"Button label for sending a message") + */ +@interface FBSDKMessengerSharer : NSObject + +/*! + @abstract + This method checks the currently installed version of Messenger to see what SDK capabilities it has + + @discussion + Before sharing any media, first use this bitmask to check to see if it can be shared to Messenger + + @return bitmask of the Messenger capabilities + */ ++ (FBSDKMessengerPlatformCapability)messengerPlatformCapabilities; + +/*! + @abstract + Call this method to open Messenger + */ ++ (void)openMessenger NS_EXTENSION_UNAVAILABLE_IOS(""); + +/*! + @abstract + Call this method to open Messenger and share an image. + + @deprecated + use shareImage:withOptions: instead + + @param image The image to be shared in Messenger + @param metadata Additional optional information to be sent to Messenger which is sent back to + the user's app when they reply to an attributed message. This may be nil. + @param context The way the content is to be shared in Messenger. If nil, a standard share will take place. + + @discussion If there is not an installed version of Messenger on the device that supports the share, an alert will be presented to the user to go to the App Store to install the latest version of Messenger + */ ++ (void)shareImage:(UIImage *)image + withMetadata:(NSString *)metadata + withContext:(FBSDKMessengerContext *)context __attribute__ ((deprecated("use use shareImage:withOptions: instead"))) NS_EXTENSION_UNAVAILABLE_IOS(""); + +/*! + @abstract + Call this method to open Messenger and share an image. + + @param image The image to be shared in Messenger + @param options Additional optional parameters that affect the way the content is shared + + @discussion If there is not an installed version of Messenger on the device that supports the share, an alert will be presented to the user to go to the App Store to install the latest version of Messenger + */ ++ (void)shareImage:(UIImage *)image withOptions:(FBSDKMessengerShareOptions *)options NS_EXTENSION_UNAVAILABLE_IOS(""); + +/*! + @abstract + Call this method to open Messenger and share an animated GIF. + + @deprecated + use shareAnimatedGIF:withOptions: instead + + @param animatedGIFData The animated GIF to be shared in Messenger + @param metadata Additional optional information to be sent to Messenger which is sent back to + the user's app when they reply to an attributed message. This may be nil. + @param context The way the content is to be shared in Messenger. If nil, a standard share will take place. + + @discussion If there is not an installed version of Messenger on the device that supports the share, an alert will be presented to the user to go to the App Store to install the latest version of Messenger + */ ++ (void)shareAnimatedGIF:(NSData *)animatedGIFData + withMetadata:(NSString *)metadata + withContext:(FBSDKMessengerContext *)context __attribute__ ((deprecated("use use shareAnimatedGIF:withOptions: instead"))) NS_EXTENSION_UNAVAILABLE_IOS(""); + +/*! + @abstract + Call this method to open Messenger and share an animated GIF. + + @param animatedGIFData The animated GIF to be shared in Messenger + @param options Additional optional parameters that affect the way the content is shared + + @discussion If there is not an installed version of Messenger on the device that supports the share, an alert will be presented to the user to go to the App Store to install the latest version of Messenger + */ ++ (void)shareAnimatedGIF:(NSData *)animatedGIFData withOptions:(FBSDKMessengerShareOptions *)options NS_EXTENSION_UNAVAILABLE_IOS(""); + +/*! + @abstract + Call this method to open Messenger and share an animated GIF. + + @deprecated + use shareAnimatedWebP:withOptions: instead + + @param animatedWebPData The animated WebP image to be shared in Messenger + @param metadata Additional optional information to be sent to Messenger which is sent back to + the user's app when they reply to an attributed message. This may be nil. + @param context The way the content is to be shared in Messenger. If nil, a standard share will take place. + + @discussion If there is not an installed version of Messenger on the device that supports the share, an alert will be presented to the user to go to the App Store to install the latest version of Messenger + */ ++ (void)shareAnimatedWebP:(NSData *)animatedWebPData + withMetadata:(NSString *)metadata + withContext:(FBSDKMessengerContext *)context __attribute__ ((deprecated("use use shareAnimatedWebP:withOptions: instead"))) NS_EXTENSION_UNAVAILABLE_IOS(""); + +/*! + @abstract + Call this method to open Messenger and share an animated GIF. + + @param animatedWebPData The animated WebP image to be shared in Messenger + @param options Additional optional parameters that affect the way the content is shared + + @discussion If there is not an installed version of Messenger on the device that supports the share, an alert will be presented to the user to go to the App Store to install the latest version of Messenger + */ ++ (void)shareAnimatedWebP:(NSData *)animatedWebPData withOptions:(FBSDKMessengerShareOptions *)options NS_EXTENSION_UNAVAILABLE_IOS(""); + +/*! + @abstract + Call this method to open Messenger and share a video. + + @deprecated + use shareVideo:withOptions: instead + + @discussion + Note that there's no way to send an AVAsset between apps, so you may need to + serialize your AVAsset to a file, and get an NSData representation of the video via + [NSData dataWithContentsOfFile:filepath]; + + @param videoData The image to be shared in Messenger + @param metadata Additional optional information to be sent to Messenger which is sent back to + the user's app when they reply to an attributed message. This may be nil. + @param context The way the content is to be shared in Messenger. If nil, a standard share will take place. + + @discussion If there is not an installed version of Messenger on the device that supports the share, an alert will be presented to the user to go to the App Store to install the latest version of Messenger + */ ++ (void)shareVideo:(NSData *)videoData + withMetadata:(NSString *)metadata + withContext:(FBSDKMessengerContext *)context __attribute__ ((deprecated("use use shareVideo:withOptions: instead"))) NS_EXTENSION_UNAVAILABLE_IOS(""); + +/*! + @abstract + Call this method to open Messenger and share a video. + + @discussion + Note that there's no way to send an AVAsset between apps, so you may need to + serialize your AVAsset to a file, and get an NSData representation of the video via + [NSData dataWithContentsOfFile:filepath]; + + @param videoData The image to be shared in Messenger + @param options Additional optional parameters that affect the way the content is shared + + @discussion If there is not an installed version of Messenger on the device that supports the share, an alert will be presented to the user to go to the App Store to install the latest version of Messenger + */ ++ (void)shareVideo:(NSData *)videoData withOptions:(FBSDKMessengerShareOptions *)options NS_EXTENSION_UNAVAILABLE_IOS(""); + +/*! + @abstract + Call this method to open Messenger and share an audio file. + + @deprecated + use shareAudio:withOptions: instead + + @discussion + Note that there's no way to send an AVAsset between apps, so you may need to + serialize your AVAsset to a file, and get an NSData representation of the video via + [NSData dataWithContentsOfFile:filepath]; + + @param audioData The audio to be shared in Messenger + @param metadata Additional optional information to be sent to Messenger + + @discussion If there is not an installed version of Messenger on the device that supports the share, an alert will be presented to the user to go to the App Store to install the latest version of Messenger +*/ ++ (void)shareAudio:(NSData *)audioData + withMetadata:(NSString *)metadata + withContext:(FBSDKMessengerContext *)context __attribute__ ((deprecated("use use shareAudio:withOptions: instead"))) NS_EXTENSION_UNAVAILABLE_IOS(""); + +/*! + @abstract + Call this method to open Messenger and share an audio file. + + @discussion + Note that there's no way to send an AVAsset between apps, so you may need to + serialize your AVAsset to a file, and get an NSData representation of the video via + [NSData dataWithContentsOfFile:filepath]; + + @param audioData The audio to be shared in Messenger + @param options Additional optional parameters that affect the way the content is shared + + @discussion If there is not an installed version of Messenger on the device that supports the share, an alert will be presented to the user to go to the App Store to install the latest version of Messenger + */ ++ (void)shareAudio:(NSData *)audioData withOptions:(FBSDKMessengerShareOptions *)options NS_EXTENSION_UNAVAILABLE_IOS(""); + +@end diff --git a/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerURLHandler.h b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerURLHandler.h new file mode 100644 index 0000000..e60f960 --- /dev/null +++ b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerURLHandler.h @@ -0,0 +1,95 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class FBSDKMessengerURLHandler, +FBSDKMessengerURLHandlerReplyContext, +FBSDKMessengerURLHandlerOpenFromComposerContext, +FBSDKMessengerURLHandlerCancelContext; + +@protocol FBSDKMessengerURLHandlerDelegate + +@optional + +/*! + @abstract + This is called after FBSDKMessengerURLHandler has received a reply from messenger + + @param messengerURLHandler The handler that handled the URL + @param context The data passed from Messenger + */ +- (void)messengerURLHandler:(FBSDKMessengerURLHandler *)messengerURLHandler + didHandleReplyWithContext:(FBSDKMessengerURLHandlerReplyContext *)context; + +/*! + @abstract + This is called after a user tapped this app from the composer in Messenger + + @param messengerURLHandler The handler that handled the URL + @param context The data passed from Messenger + */ +- (void) messengerURLHandler:(FBSDKMessengerURLHandler *)messengerURLHandler + didHandleOpenFromComposerWithContext:(FBSDKMessengerURLHandlerOpenFromComposerContext *)context; + +/*! + @abstract + This is called after a user canceled a share and Messenger redirected here + + @param messengerURLHandler The handler that handled the URL + @param context The data passed from Messenger + */ +- (void)messengerURLHandler:(FBSDKMessengerURLHandler *)messengerURLHandler + didHandleCancelWithContext:(FBSDKMessengerURLHandlerCancelContext *)context; + +@end + +/*! + @class FBSDKMessengerURLHandler + + @abstract + FBSDKMessengerURLHandler is used to handle incoming URLs from Messenger. + */ +@interface FBSDKMessengerURLHandler : NSObject + +/*! + @abstract + Determines whether an incoming URL can be handled by this class + + @param url The URL passed in from the source application + @param sourceApplication The bundle id representing the source application + + @return YES if this URL can be handled + */ +- (BOOL)canOpenURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication; + +/*! + @abstract + Attempts to handle the Messenger URL and returns YES if and only if successful. + This should be called from the AppDelegate's -openURL: method + + @param url The URL passed in from the source application + @param sourceApplication The bundle id representing the source application + + @return YES if this successfully handled the URL + */ +- (BOOL)openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication; + +@property (nonatomic, weak) id delegate; + +@end diff --git a/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerURLHandlerCancelContext.h b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerURLHandlerCancelContext.h new file mode 100644 index 0000000..7eefa41 --- /dev/null +++ b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerURLHandlerCancelContext.h @@ -0,0 +1,31 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKMessengerContext.h" + +/*! + @class FBSDKMessengerURLHandlerCancelContext + + @abstract + This object represents a user canceling out of a share flow in Messenger + */ +@interface FBSDKMessengerURLHandlerCancelContext : FBSDKMessengerContext + +@end diff --git a/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerURLHandlerOpenFromComposerContext.h b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerURLHandlerOpenFromComposerContext.h new file mode 100644 index 0000000..8d6c514 --- /dev/null +++ b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerURLHandlerOpenFromComposerContext.h @@ -0,0 +1,56 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "FBSDKMessengerShareKit.h" + +/*! + @class FBSDKMessengerURLHandlerReplyContext + + @abstract + This object represents a user selecting this app from the composer in Messenger + Passing this context into a share method will trigger a the reply flow + */ +@interface FBSDKMessengerURLHandlerOpenFromComposerContext : FBSDKMessengerContext + +/*! + @abstract + Additional information that was passed along with the original media + + @discussion + Note that when opening your app from Messenger composer, the metadata is pulled from + the most recent attributed message on the thread. + If the most recent attributed message with metadata is not cached on the device, metadata will be nil + */ +@property (nonatomic, copy, readonly) NSString *metadata; + +/*! + @abstract + The user IDs of the other participants on the thread. + + @discussion + User IDs can be used with the Facebook SDK and Graph API (https://developers.facebook.com/docs/graph-api) + to query names, photos, and other data. This will only contain IDs of users that + have also logged into your app via their Facebook account. + + Note that when opening your app from Messenger composer, the userIDs are pulled from + the most recent attributed message on the thread. + If the most recent attributed message is not cached on the device, userIDs will be nil + */ +@property (nonatomic, copy, readonly) NSSet *userIDs; + +@end diff --git a/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerURLHandlerReplyContext.h b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerURLHandlerReplyContext.h new file mode 100644 index 0000000..a5fda7e --- /dev/null +++ b/Frameworks/FBSDKMessengerShareKit.framework/Headers/FBSDKMessengerURLHandlerReplyContext.h @@ -0,0 +1,54 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import "FBSDKMessengerContext.h" + +/*! + @class FBSDKMessengerURLHandlerReplyContext + + @abstract + This object represents a user tapping reply from a message in Messenger. Passing + this context into a share method will trigger the reply flow + */ +@interface FBSDKMessengerURLHandlerReplyContext : FBSDKMessengerContext + +/*! + @abstract + Additional information that was passed along with the original media that was replied to + + @discussion + If content shared to Messenger incuded metadata and the user replied to that message, + that metadata is passed along with the reply back to the app. If no metadata was included + this is nil + */ +@property (nonatomic, copy, readonly) NSString *metadata; + +/*! + @abstract + The user IDs of the other participants on the thread. + + @discussion + User IDs can be used with the Facebook SDK and Graph API (https://developers.facebook.com/docs/graph-api) + to query names, photos, and other data. This will only contain IDs of users that + have also logged into your app via their Facebook account. + */ +@property (nonatomic, copy, readonly) NSSet *userIDs; + +@end diff --git a/Frameworks/FBSDKMessengerShareKit.framework/Info.plist b/Frameworks/FBSDKMessengerShareKit.framework/Info.plist new file mode 100644 index 0000000..640a878 Binary files /dev/null and b/Frameworks/FBSDKMessengerShareKit.framework/Info.plist differ diff --git a/Frameworks/FBSDKMessengerShareKit.framework/Modules/module.modulemap b/Frameworks/FBSDKMessengerShareKit.framework/Modules/module.modulemap new file mode 100644 index 0000000..ff7e48b --- /dev/null +++ b/Frameworks/FBSDKMessengerShareKit.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module FBSDKMessengerShareKit { + umbrella header "FBSDKMessengerShareKit.h" + + export * + module * { export * } +} \ No newline at end of file diff --git a/Frameworks/FBSDKShareKit.framework/FBSDKShareKit b/Frameworks/FBSDKShareKit.framework/FBSDKShareKit new file mode 100644 index 0000000..d6e7269 Binary files /dev/null and b/Frameworks/FBSDKShareKit.framework/FBSDKShareKit differ diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKAppGroupAddDialog.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKAppGroupAddDialog.h new file mode 100644 index 0000000..05b26ff --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKAppGroupAddDialog.h @@ -0,0 +1,101 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@protocol FBSDKAppGroupAddDialogDelegate; + +/*! + @abstract A dialog for creating app groups. + */ +@interface FBSDKAppGroupAddDialog : NSObject + +/*! + @abstract Convenience method to build up an app group dialog with content and a delegate. + @param content The content for the app group. + @param delegate The receiver's delegate. + */ ++ (instancetype)showWithContent:(FBSDKAppGroupContent *)content + delegate:(id)delegate; + +/*! + @abstract The receiver's delegate or nil if it doesn't have a delegate. + */ +@property (nonatomic, weak) id delegate; + +/*! + @abstract The content for app group. + */ +@property (nonatomic, copy) FBSDKAppGroupContent *content; + +/*! + @abstract A Boolean value that indicates whether the receiver can initiate an app group dialog. + @discussion May return NO if the appropriate Facebook app is not installed and is required or an access token is + required but not available. This method does not validate the content on the receiver, so this can be checked before + building up the content. + @see validateWithError: + @result YES if the receiver can share, otherwise NO. + */ +- (BOOL)canShow; + +/*! + @abstract Begins the app group dialog from the receiver. + @result YES if the receiver was able to show the dialog, otherwise NO. + */ +- (BOOL)show; + +/*! + @abstract Validates the content on the receiver. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return YES if the content is valid, otherwise NO. + */ +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef; + +@end + +/*! + @abstract A delegate for FBSDKAppGroupAddDialog. + @discussion The delegate is notified with the results of the app group request as long as the application has + permissions to receive the information. For example, if the person is not signed into the containing app, the shower + may not be able to distinguish between completion of an app group request and cancellation. + */ +@protocol FBSDKAppGroupAddDialogDelegate + +/*! + @abstract Sent to the delegate when the app group request completes without error. + @param appGroupAddDialog The FBSDKAppGroupAddDialog that completed. + @param results The results from the dialog. This may be nil or empty. + */ +- (void)appGroupAddDialog:(FBSDKAppGroupAddDialog *)appGroupAddDialog didCompleteWithResults:(NSDictionary *)results; + +/*! + @abstract Sent to the delegate when the app group request encounters an error. + @param appGroupAddDialog The FBSDKAppGroupAddDialog that completed. + @param error The error. + */ +- (void)appGroupAddDialog:(FBSDKAppGroupAddDialog *)appGroupAddDialog didFailWithError:(NSError *)error; + +/*! + @abstract Sent to the delegate when the app group dialog is cancelled. + @param appGroupAddDialog The FBSDKAppGroupAddDialog that completed. + */ +- (void)appGroupAddDialogDidCancel:(FBSDKAppGroupAddDialog *)appGroupAddDialog; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKAppGroupContent.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKAppGroupContent.h new file mode 100644 index 0000000..f2bdf6e --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKAppGroupContent.h @@ -0,0 +1,73 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import + +/*! + @typedef NS_ENUM(NSUInteger, FBSDKAppGroupPrivacy) + @abstract Specifies the privacy of a group. + */ +typedef NS_ENUM(NSUInteger, FBSDKAppGroupPrivacy) +{ + /*! Anyone can see the group, who's in it and what members post. */ + FBSDKAppGroupPrivacyOpen = 0, + /*! Anyone can see the group and who's in it, but only members can see posts. */ + FBSDKAppGroupPrivacyClosed, +}; + +/*! + @abstract Converts an FBSDKAppGroupPrivacy to an NSString. + */ +FBSDK_EXTERN NSString *NSStringFromFBSDKAppGroupPrivacy(FBSDKAppGroupPrivacy privacy); + +/*! + @abstract A model for creating an app group. + */ +@interface FBSDKAppGroupContent : NSObject + +/*! + @abstract The description of the group. + */ +@property (nonatomic, copy) NSString *groupDescription; + +/*! + @abstract The ID for the group. + */ +@property (nonatomic, copy) NSString *groupID; + +/*! + @abstract The name of the group. + */ +@property (nonatomic, copy) NSString *name; + +/*! + @abstract The privacy for the group. + */ +@property (nonatomic, assign) FBSDKAppGroupPrivacy privacy; + +/*! + @abstract Compares the receiver to another app group content. + @param content The other content + @return YES if the receiver's values are equal to the other content's values; otherwise NO + */ +- (BOOL)isEqualToAppGroupContent:(FBSDKAppGroupContent *)content; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKAppGroupJoinDialog.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKAppGroupJoinDialog.h new file mode 100644 index 0000000..70e4e7a --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKAppGroupJoinDialog.h @@ -0,0 +1,99 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@protocol FBSDKAppGroupJoinDialogDelegate; + +/*! + @abstract A dialog for joining app groups. + */ +@interface FBSDKAppGroupJoinDialog : NSObject + +/*! + @abstract Convenience method to build up an app group dialog with content and a delegate. + @param groupID The ID for the group. + @param delegate The receiver's delegate. + */ ++ (instancetype)showWithGroupID:(NSString *)groupID + delegate:(id)delegate; + +/*! + @abstract The receiver's delegate or nil if it doesn't have a delegate. + */ +@property (nonatomic, weak) id delegate; + +/*! + @abstract The ID for group. + */ +@property (nonatomic, copy) NSString *groupID; + +/*! + @abstract A Boolean value that indicates whether the receiver can initiate an app group dialog. + @discussion May return NO if the appropriate Facebook app is not installed and is required or an access token is + required but not available. This method does not validate the content on the receiver, so this can be checked before + building up the content. + @see validateWithError: + @result YES if the receiver can share, otherwise NO. + */ +- (BOOL)canShow; + +/*! + @abstract Begins the app group dialog from the receiver. + @result YES if the receiver was able to show the dialog, otherwise NO. + */ +- (BOOL)show; + +/*! + @abstract Validates the content on the receiver. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return YES if the content is valid, otherwise NO. + */ +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef; + +@end + +/*! + @abstract A delegate for FBSDKAppGroupJoinDialog. + @discussion The delegate is notified with the results of the app group request as long as the application has + permissions to receive the information. For example, if the person is not signed into the containing app, the shower + may not be able to distinguish between completion of an app group request and cancellation. + */ +@protocol FBSDKAppGroupJoinDialogDelegate + +/*! + @abstract Sent to the delegate when the app group request completes without error. + @param appGroupJoinDialog The FBSDKAppGroupJoinDialog that completed. + @param results The results from the dialog. This may be nil or empty. + */ +- (void)appGroupJoinDialog:(FBSDKAppGroupJoinDialog *)appGroupJoinDialog didCompleteWithResults:(NSDictionary *)results; + +/*! + @abstract Sent to the delegate when the app group request encounters an error. + @param appGroupJoinDialog The FBSDKAppGroupJoinDialog that completed. + @param error The error. + */ +- (void)appGroupJoinDialog:(FBSDKAppGroupJoinDialog *)appGroupJoinDialog didFailWithError:(NSError *)error; + +/*! + @abstract Sent to the delegate when the app group dialog is cancelled. + @param appGroupJoinDialog The FBSDKAppGroupJoinDialog that completed. + */ +- (void)appGroupJoinDialogDidCancel:(FBSDKAppGroupJoinDialog *)appGroupJoinDialog; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKAppInviteContent.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKAppInviteContent.h new file mode 100644 index 0000000..1feb828 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKAppInviteContent.h @@ -0,0 +1,54 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract A model for app invite. + */ +@interface FBSDKAppInviteContent : NSObject + +/*! + @abstract A URL to a preview image that will be displayed with the app invite + + @discussion This is optional. If you don't include it a fallback image will be used. +*/ +@property (nonatomic, copy) NSURL *appInvitePreviewImageURL; + +/*! + @abstract An app link target that will be used as a target when the user accept the invite. + + @discussion This is a requirement. + */ +@property (nonatomic, copy) NSURL *appLinkURL; + +/*! + @deprecated Use `appInvitePreviewImageURL` instead. + */ +@property (nonatomic, copy) NSURL *previewImageURL __attribute__ ((deprecated("use appInvitePreviewImageURL instead"))); + +/*! + @abstract Compares the receiver to another app invite content. + @param content The other content + @return YES if the receiver's values are equal to the other content's values; otherwise NO + */ +- (BOOL)isEqualToAppInviteContent:(FBSDKAppInviteContent *)content; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKAppInviteDialog.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKAppInviteDialog.h new file mode 100644 index 0000000..3b7494e --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKAppInviteDialog.h @@ -0,0 +1,94 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@protocol FBSDKAppInviteDialogDelegate; + +/*! + @abstract A dialog for sending App Invites. + */ +@interface FBSDKAppInviteDialog : NSObject + +/*! + @abstract Convenience method to show a FBSDKAppInviteDialog + @param content The content for the app invite. + @param delegate The receiver's delegate. + */ ++ (instancetype)showWithContent:(FBSDKAppInviteContent *)content delegate:(id)delegate; + +/*! + @abstract The receiver's delegate or nil if it doesn't have a delegate. + */ +@property (nonatomic, weak) id delegate; + +/*! + @abstract The content for app invite. + */ +@property (nonatomic, copy) FBSDKAppInviteContent *content; + +/*! + @abstract A Boolean value that indicates whether the receiver can initiate an app invite. + @discussion May return NO if the appropriate Facebook app is not installed and is required or an access token is + required but not available. This method does not validate the content on the receiver, so this can be checked before + building up the content. + @see validateWithError: + @result YES if the receiver can show the dialog, otherwise NO. + */ +- (BOOL)canShow; + +/*! + @abstract Begins the app invite from the receiver. + @result YES if the receiver was able to show the dialog, otherwise NO. + */ +- (BOOL)show; + +/*! + @abstract Validates the content on the receiver. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return YES if the content is valid, otherwise NO. + */ +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef; + +@end + +/*! + @abstract A delegate for FBSDKAppInviteDialog. + @discussion The delegate is notified with the results of the app invite as long as the application has permissions to + receive the information. For example, if the person is not signed into the containing app, the shower may not be able + to distinguish between completion of an app invite and cancellation. + */ +@protocol FBSDKAppInviteDialogDelegate + +/*! + @abstract Sent to the delegate when the app invite completes without error. + @param appInviteDialog The FBSDKAppInviteDialog that completed. + @param results The results from the dialog. This may be nil or empty. + */ +- (void)appInviteDialog:(FBSDKAppInviteDialog *)appInviteDialog didCompleteWithResults:(NSDictionary *)results; + +/*! + @abstract Sent to the delegate when the app invite encounters an error. + @param appInviteDialog The FBSDKAppInviteDialog that completed. + @param error The error. + */ +- (void)appInviteDialog:(FBSDKAppInviteDialog *)appInviteDialog didFailWithError:(NSError *)error; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKGameRequestContent.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKGameRequestContent.h new file mode 100644 index 0000000..13edc06 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKGameRequestContent.h @@ -0,0 +1,131 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @typedef NS_ENUM(NSUInteger, FBSDKGameRequestActionType) + @abstract Additional context about the nature of the request. + */ +typedef NS_ENUM(NSUInteger, FBSDKGameRequestActionType) +{ + /*! No action type */ + FBSDKGameRequestActionTypeNone = 0, + /*! Send action type: The user is sending an object to the friends. */ + FBSDKGameRequestActionTypeSend, + /*! Ask For action type: The user is asking for an object from friends. */ + FBSDKGameRequestActionTypeAskFor, + /*! Turn action type: It is the turn of the friends to play against the user in a match. (no object) */ + FBSDKGameRequestActionTypeTurn, +}; + +/*! + @typedef NS_ENUM(NSUInteger, FBSDKGameRequestFilters) + @abstract Filter for who can be displayed in the multi-friend selector. + */ +typedef NS_ENUM(NSUInteger, FBSDKGameRequestFilter) +{ + /*! No filter, all friends can be displayed. */ + FBSDKGameRequestFilterNone = 0, + /*! Friends using the app can be displayed. */ + FBSDKGameRequestFilterAppUsers, + /*! Friends not using the app can be displayed. */ + FBSDKGameRequestFilterAppNonUsers, +}; + +/*! + @abstract A model for a game request. + */ +@interface FBSDKGameRequestContent : NSObject + +/*! + @abstract Used when defining additional context about the nature of the request. + @discussion The parameter 'objectID' is required if the action type is either + 'FBSDKGameRequestSendActionType' or 'FBSDKGameRequestAskForActionType'. + @seealso objectID + */ +@property (nonatomic, assign) FBSDKGameRequestActionType actionType; + +/*! + @abstract Compares the receiver to another game request content. + @param content The other content + @return YES if the receiver's values are equal to the other content's values; otherwise NO + */ +- (BOOL)isEqualToGameRequestContent:(FBSDKGameRequestContent *)content; + +/*! + @abstract Additional freeform data you may pass for tracking. This will be stored as part of + the request objects created. The maximum length is 255 characters. + */ +@property (nonatomic, copy) NSString *data; + +/*! + @abstract This controls the set of friends someone sees if a multi-friend selector is shown. + It is FBSDKGameRequestNoFilter by default, meaning that all friends can be shown. + If specify as FBSDKGameRequestAppUsersFilter, only friends who use the app will be shown. + On the other hands, use FBSDKGameRequestAppNonUsersFilter to filter only friends who do not use the app. + @discussion The parameter name is preserved to be consistent with the counter part on desktop. + */ +@property (nonatomic, assign) FBSDKGameRequestFilter filters; + +/*! + @abstract A plain-text message to be sent as part of the request. This text will surface in the App Center view + of the request, but not on the notification jewel. Required parameter. + */ +@property (nonatomic, copy) NSString *message; + +/*! + @abstract The Open Graph object ID of the object being sent. + @seealso actionType + */ +@property (nonatomic, copy) NSString *objectID; + +/*! + @abstract An array of user IDs, usernames or invite tokens (NSString) of people to send request. + @discussion These may or may not be a friend of the sender. If this is specified by the app, + the sender will not have a choice of recipients. If not, the sender will see a multi-friend selector + + This is equivalent to the "to" parameter when using the web game request dialog. + */ +@property (nonatomic, copy) NSArray *recipients; + +/*! + @abstract An array of user IDs that will be included in the dialog as the first suggested friends. + Cannot be used together with filters. + @discussion This is equivalent to the "suggestions" parameter when using the web game request dialog. +*/ +@property (nonatomic, copy) NSArray *recipientSuggestions; + +/*! + @deprecated Use `recipientSuggestions` instead. +*/ +@property (nonatomic, copy) NSArray *suggestions __attribute__ ((deprecated("use recipientSuggestions instead"))); + +/*! + @abstract The title for the dialog. + */ +@property (nonatomic, copy) NSString *title; + +/*! + @deprecated Use `recipients` instead. + */ +@property (nonatomic, copy) NSArray *to __attribute__ ((deprecated("use recipients instead"))); + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKGameRequestDialog.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKGameRequestDialog.h new file mode 100644 index 0000000..2f5acc5 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKGameRequestDialog.h @@ -0,0 +1,105 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@protocol FBSDKGameRequestDialogDelegate; + +/*! + @abstract A dialog for sending game requests. + */ +@interface FBSDKGameRequestDialog : NSObject + +/*! + @abstract Convenience method to build up a game request with content and a delegate. + @param content The content for the game request. + @param delegate The receiver's delegate. + */ ++ (instancetype)showWithContent:(FBSDKGameRequestContent *)content delegate:(id)delegate; + +/*! + @abstract The receiver's delegate or nil if it doesn't have a delegate. + */ +@property (nonatomic, weak) id delegate; + +/*! + @abstract The content for game request. + */ +@property (nonatomic, copy) FBSDKGameRequestContent *content; + +/*! + @abstract Specifies whether frictionless requests are enabled. + */ +@property (nonatomic, assign) BOOL frictionlessRequestsEnabled; + +/*! + @abstract A Boolean value that indicates whether the receiver can initiate a game request. + @discussion May return NO if the appropriate Facebook app is not installed and is required or an access token is + required but not available. This method does not validate the content on the receiver, so this can be checked before + building up the content. + @see validateWithError: + @result YES if the receiver can share, otherwise NO. + */ +- (BOOL)canShow; + +/*! + @abstract Begins the game request from the receiver. + @result YES if the receiver was able to show the dialog, otherwise NO. + */ +- (BOOL)show; + +/*! + @abstract Validates the content on the receiver. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return YES if the content is valid, otherwise NO. + */ +- (BOOL)validateWithError:(NSError *__autoreleasing *)errorRef; + +@end + +/*! + @abstract A delegate for FBSDKGameRequestDialog. + @discussion The delegate is notified with the results of the game request as long as the application has permissions to + receive the information. For example, if the person is not signed into the containing app, the shower may not be able + to distinguish between completion of a game request and cancellation. + */ +@protocol FBSDKGameRequestDialogDelegate + +/*! + @abstract Sent to the delegate when the game request completes without error. + @param gameRequestDialog The FBSDKGameRequestDialog that completed. + @param results The results from the dialog. This may be nil or empty. + */ +- (void)gameRequestDialog:(FBSDKGameRequestDialog *)gameRequestDialog didCompleteWithResults:(NSDictionary *)results; + +/*! + @abstract Sent to the delegate when the game request encounters an error. + @param gameRequestDialog The FBSDKGameRequestDialog that completed. + @param error The error. + */ +- (void)gameRequestDialog:(FBSDKGameRequestDialog *)gameRequestDialog didFailWithError:(NSError *)error; + +/*! + @abstract Sent to the delegate when the game request dialog is cancelled. + @param gameRequestDialog The FBSDKGameRequestDialog that completed. + */ +- (void)gameRequestDialogDidCancel:(FBSDKGameRequestDialog *)gameRequestDialog; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKLikeButton.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKLikeButton.h new file mode 100644 index 0000000..0b01c4e --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKLikeButton.h @@ -0,0 +1,42 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import +#import + +/*! + @abstract A button to like an object. + @discussion Tapping the receiver will invoke an API call to the Facebook app through a fast-app-switch that allows + the object to be liked. Upon return to the calling app, the view will update with the new state. If the + currentAccessToken has "publish_actions" permission and the object is an Open Graph object, then the like can happen + seamlessly without the fast-app-switch. + */ +@interface FBSDKLikeButton : FBSDKButton + +/*! + @abstract If YES, a sound is played when the receiver is toggled. + + @default YES + */ +@property (nonatomic, assign, getter = isSoundEnabled) BOOL soundEnabled; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKLikeControl.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKLikeControl.h new file mode 100644 index 0000000..bbc88f2 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKLikeControl.h @@ -0,0 +1,139 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import +#import + +/*! + @typedef NS_ENUM (NSUInteger, FBSDKLikeControlAuxiliaryPosition) + + @abstract Specifies the position of the auxiliary view relative to the like button. + */ +typedef NS_ENUM(NSUInteger, FBSDKLikeControlAuxiliaryPosition) +{ + /*! The auxiliary view is inline with the like button. */ + FBSDKLikeControlAuxiliaryPositionInline, + /*! The auxiliary view is above the like button. */ + FBSDKLikeControlAuxiliaryPositionTop, + /*! The auxiliary view is below the like button. */ + FBSDKLikeControlAuxiliaryPositionBottom, +}; + +/*! + @abstract Converts an FBSDKLikeControlAuxiliaryPosition to an NSString. + */ +FBSDK_EXTERN NSString *NSStringFromFBSDKLikeControlAuxiliaryPosition(FBSDKLikeControlAuxiliaryPosition auxiliaryPosition); + +/*! + @typedef NS_ENUM(NSUInteger, FBSDKLikeControlHorizontalAlignment) + + @abstract Specifies the horizontal alignment for FBSDKLikeControlStyleStandard with + FBSDKLikeControlAuxiliaryPositionTop or FBSDKLikeControlAuxiliaryPositionBottom. + */ +typedef NS_ENUM(NSUInteger, FBSDKLikeControlHorizontalAlignment) +{ + /*! The subviews are left aligned. */ + FBSDKLikeControlHorizontalAlignmentLeft, + /*! The subviews are center aligned. */ + FBSDKLikeControlHorizontalAlignmentCenter, + /*! The subviews are right aligned. */ + FBSDKLikeControlHorizontalAlignmentRight, +}; + +/*! + @abstract Converts an FBSDKLikeControlHorizontalAlignment to an NSString. + */ +FBSDK_EXTERN NSString *NSStringFromFBSDKLikeControlHorizontalAlignment(FBSDKLikeControlHorizontalAlignment horizontalAlignment); + +/*! + @typedef NS_ENUM (NSUInteger, FBSDKLikeControlStyle) + + @abstract Specifies the style of a like control. + */ +typedef NS_ENUM(NSUInteger, FBSDKLikeControlStyle) +{ + /*! Displays the button and the social sentence. */ + FBSDKLikeControlStyleStandard = 0, + /*! Displays the button and a box that contains the like count. */ + FBSDKLikeControlStyleBoxCount, +}; + +/*! + @abstract Converts an FBSDKLikeControlStyle to an NSString. + */ +FBSDK_EXTERN NSString *NSStringFromFBSDKLikeControlStyle(FBSDKLikeControlStyle style); + +/*! + @class FBSDKLikeControl + + @abstract UI control to like an object in the Facebook graph. + + @discussion Taps on the like button within this control will invoke an API call to the Facebook app through a + fast-app-switch that allows the user to like the object. Upon return to the calling app, the view will update + with the new state and send actions for the UIControlEventValueChanged event. + */ +@interface FBSDKLikeControl : UIControl + +/*! + @abstract The foreground color to use for the content of the receiver. + */ +@property (nonatomic, strong) UIColor *foregroundColor; + +/*! + @abstract The position for the auxiliary view for the receiver. + + @see FBSDKLikeControlAuxiliaryPosition + */ +@property (nonatomic, assign) FBSDKLikeControlAuxiliaryPosition likeControlAuxiliaryPosition; + +/*! + @abstract The text alignment of the social sentence. + + @discussion This value is only valid for FBSDKLikeControlStyleStandard with + FBSDKLikeControlAuxiliaryPositionTop|Bottom. + */ +@property (nonatomic, assign) FBSDKLikeControlHorizontalAlignment likeControlHorizontalAlignment; + +/*! + @abstract The style to use for the receiver. + + @see FBSDKLikeControlStyle + */ +@property (nonatomic, assign) FBSDKLikeControlStyle likeControlStyle; + +/*! + @abstract The preferred maximum width (in points) for autolayout. + + @discussion This property affects the size of the receiver when layout constraints are applied to it. During layout, + if the text extends beyond the width specified by this property, the additional text is flowed to one or more new + lines, thereby increasing the height of the receiver. + */ +@property (nonatomic, assign) CGFloat preferredMaxLayoutWidth; + +/*! + @abstract If YES, a sound is played when the receiver is toggled. + + @default YES + */ +@property (nonatomic, assign, getter = isSoundEnabled) BOOL soundEnabled; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKLikeObjectType.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKLikeObjectType.h new file mode 100644 index 0000000..dadff43 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKLikeObjectType.h @@ -0,0 +1,40 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @typedef NS_ENUM (NSUInteger, FBSDKLikeObjectType) + @abstract Specifies the type of object referenced by the objectID for likes. + */ +typedef NS_ENUM(NSUInteger, FBSDKLikeObjectType) +{ + /*! The objectID refers to an unknown object type. */ + FBSDKLikeObjectTypeUnknown = 0, + /*! The objectID refers to an Open Graph object. */ + FBSDKLikeObjectTypeOpenGraph, + /*! The objectID refers to an Page object. */ + FBSDKLikeObjectTypePage, +}; + +/*! + @abstract Converts an FBLikeControlObjectType to an NSString. + */ +FBSDK_EXTERN NSString *NSStringFromFBSDKLikeObjectType(FBSDKLikeObjectType objectType); diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKLiking.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKLiking.h new file mode 100644 index 0000000..e2d4a4a --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKLiking.h @@ -0,0 +1,45 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +/*! + @abstract The common interface for components that initiate liking. + @see FBSDKLikeButton + @see FBSDKLikeControl + */ +@protocol FBSDKLiking + +/*! + @abstract The objectID for the object to like. + + @discussion This value may be an Open Graph object ID or a string representation of an URL that describes an + Open Graph object. The objects may be public objects, like pages, or objects that are defined by your application. + */ +@property (nonatomic, copy) NSString *objectID; + +/*! + @abstract The type of object referenced by the objectID. + + @discussion If the objectType is unknown, the control will determine the objectType by querying the server with the + objectID. Specifying a value for the objectType is an optimization that should be used if the type is known by the + consumer. Consider setting the objectType if it is known when setting the objectID. + */ +@property (nonatomic, assign) FBSDKLikeObjectType objectType; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKMessageDialog.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKMessageDialog.h new file mode 100644 index 0000000..2819eb7 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKMessageDialog.h @@ -0,0 +1,35 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract A dialog for sharing content through Messenger. + */ +@interface FBSDKMessageDialog : NSObject + +/*! + @abstract Convenience method to show a Message Share Dialog with content and a delegate. + @param content The content to be shared. + @param delegate The receiver's delegate. + */ ++ (instancetype)showWithContent:(id)content delegate:(id)delegate; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSendButton.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSendButton.h new file mode 100644 index 0000000..347f0e4 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSendButton.h @@ -0,0 +1,32 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import + +/*! + @abstract A button to send content through Messenger. + @discussion Tapping the receiver will invoke the FBSDKShareDialog with the attached shareContent. If the dialog cannot + be shown, the button will be disable. + */ +@interface FBSDKSendButton : FBSDKButton + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareAPI.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareAPI.h new file mode 100644 index 0000000..6bc13d5 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareAPI.h @@ -0,0 +1,71 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import + +/*! + @abstract A utility class for sharing through the graph API. Using this class requires an access token in + [FBSDKAccessToken currentAccessToken] that has been granted the "publish_actions" permission. + */ +@interface FBSDKShareAPI : NSObject + +/*! + @abstract Convenience method to build up a share API with content and a delegate. + @param content The content to be shared. + @param delegate The receiver's delegate. + */ ++ (instancetype)shareWithContent:(id)content delegate:(id)delegate; + +/*! + @abstract The message the person has provided through the custom dialog that will accompany the share content. + */ +@property (nonatomic, copy) NSString *message; + +/*! + @abstract A Boolean value that indicates whether the receiver can send the share. + @discussion May return NO if the appropriate Facebook app is not installed and is required or an access token is + required but not available. This method does not validate the content on the receiver, so this can be checked before + building up the content. + @see [FBSDKSharing validateWithError:] + @result YES if the receiver can send, otherwise NO. + */ +- (BOOL)canShare; + +/*! + @abstract Creates an User Owned Open Graph object without an action. + @param openGraphObject The open graph object to create. + @discussion Use this method to create an object alone, when an action is not going to be posted with the object. If + the object will be used within an action, just put the object in the action and share that as the shareContent and the + object will be created in the process. The delegate will be messaged with the results. + + Also see https://developers.facebook.com/docs/sharing/opengraph/object-api#objectapi-creatinguser + + @result YES if the receiver was able to send the request to create the object, otherwise NO. + */ +- (BOOL)createOpenGraphObject:(FBSDKShareOpenGraphObject *)openGraphObject; + +/*! + @abstract Begins the send from the receiver. + @result YES if the receiver was able to send the share, otherwise NO. + */ +- (BOOL)share; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareButton.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareButton.h new file mode 100644 index 0000000..d6b46fd --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareButton.h @@ -0,0 +1,32 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import + +/*! + @abstract A button to share content. + @discussion Tapping the receiver will invoke the FBSDKShareDialog with the attached shareContent. If the dialog cannot + be shown, the button will be disabled. + */ +@interface FBSDKShareButton : FBSDKButton + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareConstants.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareConstants.h new file mode 100644 index 0000000..4f2af4f --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareConstants.h @@ -0,0 +1,50 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract The error domain for all errors from FBSDKShareKit. + @discussion Error codes from the SDK in the range 200-299 are reserved for this domain. + */ +FBSDK_EXTERN NSString *const FBSDKShareErrorDomain; + +/*! + @typedef NS_ENUM(NSInteger, FBSDKShareErrorCode) + @abstract Error codes for FBSDKShareErrorDomain. + */ +typedef NS_ENUM(NSInteger, FBSDKShareErrorCode) +{ + /*! + @abstract Reserved. + */ + FBSDKShareReservedErrorCode = 200, + + /*! + @abstract The error code for errors from uploading open graph objects. + */ + FBSDKShareOpenGraphErrorCode, + + /*! + @abstract The error code for when a sharing dialog is not available. + @discussion Use the canShare methods to check for this case before calling show. + */ + FBSDKShareDialogNotAvailableErrorCode, +}; diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareDialog.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareDialog.h new file mode 100644 index 0000000..3fc15cb --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareDialog.h @@ -0,0 +1,52 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import +#import + +/*! + @abstract A dialog for sharing content on Facebook. + */ +@interface FBSDKShareDialog : NSObject + +/*! + @abstract Convenience method to show an FBSDKShareDialog with a fromViewController, content and a delegate. + @param viewController A UIViewController to present the dialog from, if appropriate. + @param content The content to be shared. + @param delegate The receiver's delegate. + */ ++ (instancetype)showFromViewController:(UIViewController *)viewController + withContent:(id)content + delegate:(id)delegate; + +/*! + @abstract A UIViewController to present the dialog from, if appropriate. + @discussion This value is required for FBSDKShareDialogModeShareSheet. + */ +@property (nonatomic, weak) UIViewController *fromViewController; + +/*! + @abstract The mode with which to display the dialog. + @discussion Defaults to FBSDKShareDialogModeAutomatic, which will automatically choose the best available mode. + */ +@property (nonatomic, assign) FBSDKShareDialogMode mode; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareDialogMode.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareDialogMode.h new file mode 100644 index 0000000..bdea19e --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareDialogMode.h @@ -0,0 +1,64 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @typedef NS_ENUM(NSUInteger, FBSDKShareDialogMode) + @abstract Modes for the FBSDKShareDialog. + @discussion The automatic mode will progressively check the availability of different modes and open the most + appropriate mode for the dialog that is available. + */ +typedef NS_ENUM(NSUInteger, FBSDKShareDialogMode) +{ + /*! + @abstract Acts with the most appropriate mode that is available. + */ + FBSDKShareDialogModeAutomatic = 0, + /*! + @Displays the dialog in the main native Facebook app. + */ + FBSDKShareDialogModeNative, + /*! + @Displays the dialog in the iOS integrated share sheet. + */ + FBSDKShareDialogModeShareSheet, + /*! + @Displays the dialog in Safari. + */ + FBSDKShareDialogModeBrowser, + /*! + @Displays the dialog in a UIWebView within the app. + */ + FBSDKShareDialogModeWeb, + /*! + @Displays the feed dialog in Safari. + */ + FBSDKShareDialogModeFeedBrowser, + /*! + @Displays the feed dialog in a UIWebView within the app. + */ + FBSDKShareDialogModeFeedWeb, +}; + +/*! + @abstract Converts an FBLikeControlObjectType to an NSString. + */ +FBSDK_EXTERN NSString *NSStringFromFBSDKShareDialogMode(FBSDKShareDialogMode dialogMode); diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareKit.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareKit.h new file mode 100644 index 0000000..c2406c8 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareKit.h @@ -0,0 +1,47 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareLinkContent.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareLinkContent.h new file mode 100644 index 0000000..af04602 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareLinkContent.h @@ -0,0 +1,55 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract A model for status and link content to be shared. + */ +@interface FBSDKShareLinkContent : NSObject + +/*! + @abstract The description of the link. + @discussion If not specified, this field is automatically populated by information scraped from the contentURL, + typically the title of the page. + @return The description of the link + */ +@property (nonatomic, copy) NSString *contentDescription; + +/*! + @abstract The title to display for this link. + @return The link title + */ +@property (nonatomic, copy) NSString *contentTitle; + +/*! + @abstract The URL of a picture to attach to this content. + @return The network URL of an image + */ +@property (nonatomic, copy) NSURL *imageURL; + +/*! + @abstract Compares the receiver to another link content. + @param content The other content + @return YES if the receiver's values are equal to the other content's values; otherwise NO + */ +- (BOOL)isEqualToShareLinkContent:(FBSDKShareLinkContent *)content; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareOpenGraphAction.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareOpenGraphAction.h new file mode 100644 index 0000000..5f6db0a --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareOpenGraphAction.h @@ -0,0 +1,69 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import +#import + +/*! + @abstract An Open Graph Action for sharing. + @discussion The property keys MUST have namespaces specified on them, such as `og:image`. + */ +@interface FBSDKShareOpenGraphAction : FBSDKShareOpenGraphValueContainer + +/*! + @abstract Convenience method to build a new action and set the object for the specified key. + @param actionType The action type of the receiver + @param object The Open Graph object represented by this action + @param key The key for the object + */ ++ (instancetype)actionWithType:(NSString *)actionType object:(FBSDKShareOpenGraphObject *)object key:(NSString *)key; + +/*! + @abstract Convenience method to build a new action and set the object for the specified key. + @param actionType The action type of the receiver + @param objectID The ID of an existing Open Graph object + @param key The key for the object + */ ++ (instancetype)actionWithType:(NSString *)actionType objectID:(NSString *)objectID key:(NSString *)key; + +/*! + @abstract Convenience method to build a new action and set the object for the specified key. + @param actionType The action type of the receiver + @param objectURL The URL to a page that defines the Open Graph object with meta tags + @param key The key for the object + */ ++ (instancetype)actionWithType:(NSString *)actionType objectURL:(NSURL *)objectURL key:(NSString *)key; + +/*! + @abstract Gets the action type. + @return The action type + */ +@property (nonatomic, copy) NSString *actionType; + +/*! + @abstract Compares the receiver to another Open Graph Action. + @param action The other action + @return YES if the receiver's values are equal to the other action's values; otherwise NO + */ +- (BOOL)isEqualToShareOpenGraphAction:(FBSDKShareOpenGraphAction *)action; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareOpenGraphContent.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareOpenGraphContent.h new file mode 100644 index 0000000..4393b0c --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareOpenGraphContent.h @@ -0,0 +1,49 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import + +/*! + @abstract A model for Open Graph content to be shared. + */ +@interface FBSDKShareOpenGraphContent : NSObject + +/*! + @abstract Open Graph Action to be shared. + @return The action + */ +@property (nonatomic, copy) FBSDKShareOpenGraphAction *action; + +/*! + @abstract Property name that points to the primary Open Graph Object in the action. + @discussion The value that this action points to will be use for rendering the preview for the share. + @return The property name for the Open Graph Object in the action + */ +@property (nonatomic, copy) NSString *previewPropertyName; + +/*! + @abstract Compares the receiver to another Open Graph content. + @param content The other content + @return YES if the receiver's values are equal to the other content's values; otherwise NO + */ +- (BOOL)isEqualToShareOpenGraphContent:(FBSDKShareOpenGraphContent *)content; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareOpenGraphObject.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareOpenGraphObject.h new file mode 100644 index 0000000..3a1e1a5 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareOpenGraphObject.h @@ -0,0 +1,58 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +#import + +/*! + @abstract An Open Graph Object for sharing. + @discussion The property keys MUST have namespaces specified on them, such as `og:image`, + and `og:type` is required. + + See https://developers.facebook.com/docs/sharing/opengraph/object-properties for other properties. + + You can specify nested namespaces inline to define complex properties. For example, the following + code will generate a fitness.course object with a location: + + FBSDKShareOpenGraphObject *course = [FBSDKShareOpenGraphObject objectWithProperties: + @{ + @"og:type": @"fitness.course", + @"og:title": @"Sample course", + @"fitness:metrics:location:latitude": @"41.40338", + @"fitness:metrics:location:longitude": @"2.17403", + }]; + */ +@interface FBSDKShareOpenGraphObject : FBSDKShareOpenGraphValueContainer + +/*! + @abstract Convenience method to build a new action and set the object for the specified key. + @param properties Properties for the Open Graph object, which will be parsed into the proper models + */ ++ (instancetype)objectWithProperties:(NSDictionary *)properties; + +/*! + @abstract Compares the receiver to another Open Graph Object. + @param object The other object + @return YES if the receiver's values are equal to the other object's values; otherwise NO + */ +- (BOOL)isEqualToShareOpenGraphObject:(FBSDKShareOpenGraphObject *)object; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareOpenGraphValueContainer.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareOpenGraphValueContainer.h new file mode 100644 index 0000000..4687828 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareOpenGraphValueContainer.h @@ -0,0 +1,160 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +@class FBSDKShareOpenGraphObject; +@class FBSDKSharePhoto; + +/*! + @abstract Protocol defining operations on open graph actions and objects. + @discussion The property keys MUST have namespaces specified on them, such as `og:image`. + */ +@protocol FBSDKShareOpenGraphValueContaining + +/*! + @abstract Gets an NSArray out of the receiver. + @param key The key for the value + @return The NSArray value or nil + */ +- (NSArray *)arrayForKey:(NSString *)key; + +/*! + @abstract Applies a given block object to the entries of the receiver. + @param block A block object to operate on entries in the receiver + */ +- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(NSString *key, id object, BOOL *stop))block; + +/*! + @abstract Returns an enumerator object that lets you access each key in the receiver. + @return An enumerator object that lets you access each key in the receiver + */ +- (NSEnumerator *)keyEnumerator; + +/*! + @abstract Gets an NSNumber out of the receiver. + @param key The key for the value + @return The NSNumber value or nil + */ +- (NSNumber *)numberForKey:(NSString *)key; + +/*! + @abstract Returns an enumerator object that lets you access each value in the receiver. + @return An enumerator object that lets you access each value in the receiver + */ +- (NSEnumerator *)objectEnumerator; + +/*! + @abstract Gets an FBSDKShareOpenGraphObject out of the receiver. + @param key The key for the value + @return The FBSDKShareOpenGraphObject value or nil + */ +- (FBSDKShareOpenGraphObject *)objectForKey:(NSString *)key; + +/*! + @abstract Enables subscript access to the values in the receiver. + @param key The key for the value + @return The value + */ +- (id)objectForKeyedSubscript:(NSString *)key; + +/*! + @abstract Parses properties out of a dictionary into the receiver. + @param properties The properties to parse. + */ +- (void)parseProperties:(NSDictionary *)properties; + +/*! + @abstract Gets an FBSDKSharePhoto out of the receiver. + @param key The key for the value + @return The FBSDKSharePhoto value or nil + */ +- (FBSDKSharePhoto *)photoForKey:(NSString *)key; + +/*! + @abstract Removes a value from the receiver for the specified key. + @param key The key for the value + */ +- (void)removeObjectForKey:(NSString *)key; + +/*! + @abstract Sets an NSArray on the receiver. + @discussion This method will throw if the array contains any values that is not an NSNumber, NSString, NSURL, + FBSDKSharePhoto or FBSDKShareOpenGraphObject. + @param array The NSArray value + @param key The key for the value + */ +- (void)setArray:(NSArray *)array forKey:(NSString *)key; + +/*! + @abstract Sets an NSNumber on the receiver. + @param number The NSNumber value + @param key The key for the value + */ +- (void)setNumber:(NSNumber *)number forKey:(NSString *)key; + +/*! + @abstract Sets an FBSDKShareOpenGraphObject on the receiver. + @param object The FBSDKShareOpenGraphObject value + @param key The key for the value + */ +- (void)setObject:(FBSDKShareOpenGraphObject *)object forKey:(NSString *)key; + +/*! + @abstract Sets an FBSDKSharePhoto on the receiver. + @param photo The FBSDKSharePhoto value + @param key The key for the value + */ +- (void)setPhoto:(FBSDKSharePhoto *)photo forKey:(NSString *)key; + +/*! + @abstract Sets an NSString on the receiver. + @param string The NSString value + @param key The key for the value + */ +- (void)setString:(NSString *)string forKey:(NSString *)key; + +/*! + @abstract Sets an NSURL on the receiver. + @param URL The NSURL value + @param key The key for the value + */ +- (void)setURL:(NSURL *)URL forKey:(NSString *)key; + +/*! + @abstract Gets an NSString out of the receiver. + @param key The key for the value + @return The NSString value or nil + */ +- (NSString *)stringForKey:(NSString *)key; + +/*! + @abstract Gets an NSURL out of the receiver. + @param key The key for the value + @return The NSURL value or nil + */ +- (NSURL *)URLForKey:(NSString *)key; + +@end + +/*! + @abstract A base class to container Open Graph values. + */ +@interface FBSDKShareOpenGraphValueContainer : NSObject + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSharePhoto.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSharePhoto.h new file mode 100644 index 0000000..84de5f4 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSharePhoto.h @@ -0,0 +1,77 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract A photo for sharing. + */ +@interface FBSDKSharePhoto : NSObject + +/*! + @abstract Convenience method to build a new photo object with an image. + @param image If the photo is resident in memory, this method supplies the data + @param userGenerated Specifies whether the photo represented by the receiver was generated by the user or by the + application + */ ++ (instancetype)photoWithImage:(UIImage *)image userGenerated:(BOOL)userGenerated; + +/*! + @abstract Convenience method to build a new photo object with an imageURL. + @param imageURL The URL to the photo + @param userGenerated Specifies whether the photo represented by the receiver was generated by the user or by the + application + */ ++ (instancetype)photoWithImageURL:(NSURL *)imageURL userGenerated:(BOOL)userGenerated; + +/*! + @abstract If the photo is resident in memory, this method supplies the data. + @return UIImage representation of the photo + */ +@property (nonatomic, strong) UIImage *image; + +/*! + @abstract The URL to the photo. + @return URL that points to a network location or the location of the photo on disk + */ +@property (nonatomic, copy) NSURL *imageURL; + +/*! + @abstract Specifies whether the photo represented by the receiver was generated by the user or by the application. + @return YES if the photo is user-generated, otherwise NO + */ +@property (nonatomic, assign, getter=isUserGenerated) BOOL userGenerated; + +/*! + @abstract Compares the receiver to another photo. + @param photo The other photo + @return YES if the receiver's values are equal to the other photo's values; otherwise NO + */ +- (BOOL)isEqualToSharePhoto:(FBSDKSharePhoto *)photo; + +/*! + @abstract The user generated caption for the photo. Note that the 'caption' must come from + * the user, as pre-filled content is forbidden by the Platform Policies (2.3). + @return the Photo's caption if exists else returns null. + */ +@property (nonatomic, copy) NSString *caption; + + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSharePhotoContent.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSharePhotoContent.h new file mode 100644 index 0000000..1fd0782 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSharePhotoContent.h @@ -0,0 +1,41 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract A model for photo content to be shared. + */ +@interface FBSDKSharePhotoContent : NSObject + +/*! + @abstract Photos to be shared. + @return Array of the photos (FBSDKSharePhoto) + */ +@property (nonatomic, copy) NSArray *photos; + +/*! + @abstract Compares the receiver to another photo content. + @param content The other content + @return YES if the receiver's values are equal to the other content's values; otherwise NO + */ +- (BOOL)isEqualToSharePhotoContent:(FBSDKSharePhotoContent *)content; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareVideo.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareVideo.h new file mode 100644 index 0000000..2b6ae0c --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareVideo.h @@ -0,0 +1,48 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract A video for sharing. + */ +@interface FBSDKShareVideo : NSObject + +/*! + @abstract Convenience method to build a new video object with a videoURL. + @param videoURL The URL to the video + application + */ ++ (instancetype)videoWithVideoURL:(NSURL *)videoURL; + +/*! + @abstract The file URL to the video. + @return URL that points to the location of the video on disk + */ +@property (nonatomic, copy) NSURL *videoURL; + +/*! + @abstract Compares the receiver to another video. + @param video The other video + @return YES if the receiver's values are equal to the other video's values; otherwise NO + */ +- (BOOL)isEqualToShareVideo:(FBSDKShareVideo *)video; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareVideoContent.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareVideoContent.h new file mode 100644 index 0000000..bead676 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKShareVideoContent.h @@ -0,0 +1,49 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import +#import +#import + +/*! + @abstract A model for video content to be shared. + */ +@interface FBSDKShareVideoContent : NSObject + +/*! + @abstract The photo that represents the video. + @return The photo + */ +@property (nonatomic, copy) FBSDKSharePhoto *previewPhoto; + +/*! + @abstract The video to be shared. + @return The video + */ +@property (nonatomic, copy) FBSDKShareVideo *video; + +/*! + @abstract Compares the receiver to another video content. + @param content The other content + @return YES if the receiver's values are equal to the other content's values; otherwise NO + */ +- (BOOL)isEqualToShareVideoContent:(FBSDKShareVideoContent *)content; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSharing.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSharing.h new file mode 100644 index 0000000..d6d373e --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSharing.h @@ -0,0 +1,110 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +@protocol FBSDKSharingDelegate; + +/*! + @abstract The common interface for components that initiate sharing. + @see FBSDKShareDialog + @see FBSDKMessageDialog + @see FBSDKShareAPI + */ +@protocol FBSDKSharing + +/*! + @abstract The receiver's delegate or nil if it doesn't have a delegate. + */ +@property (nonatomic, weak) id delegate; + +/*! + @abstract The content to be shared. + */ +@property (nonatomic, copy) id shareContent; + +/*! + @abstract A Boolean value that indicates whether the receiver should fail if it finds an error with the share content. + @discussion If NO, the sharer will still be displayed without the data that was mis-configured. For example, an + invalid placeID specified on the shareContent would produce a data error. + */ +@property (nonatomic, assign) BOOL shouldFailOnDataError; + +/*! + @abstract Validates the content on the receiver. + @param errorRef If an error occurs, upon return contains an NSError object that describes the problem. + @return YES if the content is valid, otherwise NO. + */ +- (BOOL)validateWithError:(NSError **)errorRef; + +@end + +/*! + @abstract The common interface for dialogs that initiate sharing. + */ +@protocol FBSDKSharingDialog + +/*! + @abstract A Boolean value that indicates whether the receiver can initiate a share. + @discussion May return NO if the appropriate Facebook app is not installed and is required or an access token is + required but not available. This method does not validate the content on the receiver, so this can be checked before + building up the content. + @see [FBSDKSharing validateWithError:] + @result YES if the receiver can share, otherwise NO. + */ +- (BOOL)canShow; + +/*! + @abstract Shows the dialog. + @result YES if the receiver was able to begin sharing, otherwise NO. + */ +- (BOOL)show; + +@end + +/*! + @abstract A delegate for FBSDKSharing. + @discussion The delegate is notified with the results of the sharer as long as the application has permissions to + receive the information. For example, if the person is not signed into the containing app, the sharer may not be able + to distinguish between completion of a share and cancellation. + */ +@protocol FBSDKSharingDelegate + +/*! + @abstract Sent to the delegate when the share completes without error or cancellation. + @param sharer The FBSDKSharing that completed. + @param results The results from the sharer. This may be nil or empty. + */ +- (void)sharer:(id)sharer didCompleteWithResults:(NSDictionary *)results; + +/*! + @abstract Sent to the delegate when the sharer encounters an error. + @param sharer The FBSDKSharing that completed. + @param error The error. + */ +- (void)sharer:(id)sharer didFailWithError:(NSError *)error; + +/*! + @abstract Sent to the delegate when the sharer is cancelled. + @param sharer The FBSDKSharing that completed. + */ +- (void)sharerDidCancel:(id)sharer; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSharingButton.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSharingButton.h new file mode 100644 index 0000000..a3af423 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSharingButton.h @@ -0,0 +1,35 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract The common interface for sharing buttons. + @see FBSDKSendButton + @see FBSDKShareButton + */ +@protocol FBSDKSharingButton + +/*! + @abstract The content to be shared. + */ +@property (nonatomic, copy) id shareContent; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSharingContent.h b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSharingContent.h new file mode 100644 index 0000000..5f70083 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Headers/FBSDKSharingContent.h @@ -0,0 +1,56 @@ +// Copyright (c) 2014-present, Facebook, Inc. All rights reserved. +// +// You are hereby granted a non-exclusive, worldwide, royalty-free license to use, +// copy, modify, and distribute this software in source code or binary form for use +// in connection with the web services and APIs provided by Facebook. +// +// As with any software that integrates with the Facebook platform, your use of +// this software is subject to the Facebook Developer Principles and Policies +// [http://developers.facebook.com/policy/]. This copyright notice shall be +// included in all copies or substantial portions of the software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +#import + +/*! + @abstract A base interface for content to be shared. + */ +@protocol FBSDKSharingContent + +/*! + @abstract URL for the content being shared. + @discussion This URL will be checked for all link meta tags for linking in platform specific ways. See documentation + for App Links (https://developers.facebook.com/docs/applinks/) + @return URL representation of the content link + */ +@property (nonatomic, copy) NSURL *contentURL; + +/*! + @abstract List of IDs for taggable people to tag with this content. + @description See documentation for Taggable Friends + (https://developers.facebook.com/docs/graph-api/reference/user/taggable_friends) + @return Array of IDs for people to tag (NSString) + */ +@property (nonatomic, copy) NSArray *peopleIDs; + +/*! + @abstract The ID for a place to tag with this content. + @return The ID for the place to tag + */ +@property (nonatomic, copy) NSString *placeID; + +/*! + @abstract A value to be added to the referrer URL when a person follows a link from this shared content on feed. + @return The ref for the content. + */ +@property (nonatomic, copy) NSString *ref; + +@end diff --git a/Frameworks/FBSDKShareKit.framework/Info.plist b/Frameworks/FBSDKShareKit.framework/Info.plist new file mode 100644 index 0000000..55e76a8 Binary files /dev/null and b/Frameworks/FBSDKShareKit.framework/Info.plist differ diff --git a/Frameworks/FBSDKShareKit.framework/Modules/module.modulemap b/Frameworks/FBSDKShareKit.framework/Modules/module.modulemap new file mode 100644 index 0000000..faa8711 --- /dev/null +++ b/Frameworks/FBSDKShareKit.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module FBSDKShareKit { + umbrella header "FBSDKShareKit.h" + + export * + module * { export * } +} diff --git a/Frameworks/TwitterCore.framework/Headers/TWTRAPIErrorCode.h b/Frameworks/TwitterCore.framework/Headers/TWTRAPIErrorCode.h new file mode 100644 index 0000000..d7b0439 --- /dev/null +++ b/Frameworks/TwitterCore.framework/Headers/TWTRAPIErrorCode.h @@ -0,0 +1,148 @@ +// +// TWTRAPIErrorCode.h +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import + +/** + * The NSError domain of errors surfaced by the Twitter API. + */ +FOUNDATION_EXPORT NSString * const TWTRAPIErrorDomain; + +/** + * Error codes surfaced by the Twitter API. + * @see https://dev.twitter.com/docs/error-codes-responses + */ +typedef NS_ENUM(NSUInteger, TWTRAPIErrorCode) { + /** + * Your call could not be completed as dialed. + */ + TWTRAPIErrorCodeCouldNotAuthenticate = 32, + + /** + * Corresponds with an HTTP 404 - the specified resource was not found. + */ + TWTRAPIErrorCodePageNotExist = 34, + + /** + * Not authorized to use this endpoint. + */ + TWTRAPIErrorCodeNotAuthorizedForEndpoint = 37, + + /** + * Corresponds with an HTTP 403 — the access token being used belongs to a suspended user and they can't complete the action you're trying to take + */ + TWTRAPIErrorCodeAccountSuspended = 64, + + /** + * Corresponds to a HTTP request to a retired v1-era URL. + */ + TWTRAPIErrorCodeAPIVersionRetired = 68, + + /** + * The request limit for this resource has been reached for the current rate limit window. + */ + TWTRAPIErrorCodeRateLimitExceeded = 88, + + /** + * The access token used in the request is incorrect or has expired. Used in API v1.1. + */ + TWTRAPIErrorCodeInvalidOrExpiredToken = 89, + + /** + * Only SSL connections are allowed in the API, you should update your request to a secure connection. See [how to connect using SSL](https://dev.twitter.com/docs/security/using-ssl). + */ + TWTRAPIErrorCodeSSLInvalid = 92, + + /** + * Corresponds with an HTTP 503 - Twitter is temporarily over capacity. + */ + TWTRAPIErrorCodeOverCapacity = 130, + + /** + * Corresponds with an HTTP 500 - An unknown internal error occurred. + */ + TWTRAPIErrorCodeInternalError = 131, + + /** + * Corresponds with a HTTP 401 - it means that your oauth_timestamp is either ahead or behind our acceptable range. + */ + TWTRAPIErrorCodeCouldNotAuthenticateTimestampOutOfRange = 135, + + /** + * You have already favorited this status. + */ + TWTRAPIErrorCodeAlreadyFavorited = 139, + + /** + * Corresponds with HTTP 403 — returned when a user cannot follow another user due to some kind of limit. + */ + TWTRAPIErrorCodeCannotFollowOverLimit = 161, + + /** + * Corresponds with HTTP 403 — returned when a Tweet cannot be viewed by the authenticating user, usually due to the Tweet's author having protected their Tweets. + */ + TWTRAPIErrorCodeNotAuthorizedToSeeStatus = 179, + + /** + * Corresponds with HTTP 403 — returned when a Tweet cannot be posted due to the user having no allowance remaining to post. Despite the text in the error message indicating that this error is only returned when a daily limit is reached, this error will be returned whenever a posting limitation has been reached. Posting allowances have roaming windows of time of unspecified duration. + */ + TWTRAPIErrorCodeOverDailyStatusUpdateLimit = 185, + + /** + * The status text has been Tweeted already by the authenticated account. + */ + TWTRAPIErrorCodeStatusIsDuplicate = 187, + + /** + * Typically sent with 1.1 responses with HTTP code 400. The method requires authentication but it was not presented or was wholly invalid. + */ + TWTRAPIErrorCodeBadAuthenticationData = 215, + + /** + * We constantly monitor and adjust our filters to block spam and malicious activity on the Twitter platform. These systems are tuned in real-time. If you get this response our systems have flagged the Tweet or DM as possibly fitting this profile. If you feel that the Tweet or DM you attempted to create was flagged in error, please report the details around that to us by filing a ticket at https://support.twitter.com/forms/platform + */ + TWTRAPIErrorCodeRequestIsAutomated = 226, + + /** + * Returned as a challenge in xAuth when the user has login verification enabled on their account and needs to be directed to twitter.com to [generate a temporary password](https://twitter.com/settings/applications). + */ + TWTRAPIErrorCodeUserMustVerifyLogin = 231, + + /** + * "Bad guest token." The token has probably expired. Try calling `-[Twitter logInGuestWithCompletion:]` again later. + */ + TWTRAPIErrorCodeBadGuestToken = 239, + + /** + * Corresponds to a HTTP request to a retired URL. + */ + TWTRAPIErrorCodeEndpointRetired = 251, + + /** + * Corresponds with HTTP 403 — returned when the application is restricted from POST, PUT, or DELETE actions. See [How to appeal application suspension and other disciplinary actions](https://support.twitter.com/articles/72585). + */ + TWTRAPIErrorCodeApplicationCannotPerformWriteAction = 261, + + /** + * Corresponds with HTTP 403. The authenticated user account cannot mute itself. + */ + TWTRAPIErrorCodeCannotMuteSelf = 271, + + /** + * Corresponds with HTTP 403. The authenticated user account is not muting the account a call is attempting to unmute. + */ + TWTRAPIErrorCodeCannotMuteSpecifiedUser = 272, + + /** + * You have already retweeted this tweet. + */ + TWTRAPIErrorCodeAlreadyRetweeted = 327, + + /** + * Returned in API v1.1 when a request cannot be served due to the application's rate limit having been exhausted for the resource. See [Rate Limiting in API v1.1](https://dev.twitter.com/docs/rate-limiting/1.1). + */ + TWTRAPIErrorCodeTooManyRequests = 429 +}; \ No newline at end of file diff --git a/Frameworks/TwitterCore.framework/Headers/TWTRAuthConfig.h b/Frameworks/TwitterCore.framework/Headers/TWTRAuthConfig.h new file mode 100644 index 0000000..3613a61 --- /dev/null +++ b/Frameworks/TwitterCore.framework/Headers/TWTRAuthConfig.h @@ -0,0 +1,37 @@ +// +// TWTRAuthConfig.h +// TwitterKit +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import + +/** + * Authentication configuration details. Encapsulates credentials required to authenticate a Twitter application. You can obtain your credentials at https://apps.twitter.com/. + */ +@interface TWTRAuthConfig : NSObject + +/** + * The consumer key of the Twitter application. + */ +@property (nonatomic, copy, readonly) NSString *consumerKey; +/** + * The consumer secret of the Twitter application. + */ +@property (nonatomic, copy, readonly) NSString *consumerSecret; + +/** + * Returns an `TWTRAuthConfig` object initialized by copying the values from the consumer key and consumer secret. + * + * @param consumerKey The consumer key. + * @param consumerSecret The consumer secret. + */ +- (instancetype)initWithConsumerKey:(NSString *)consumerKey consumerSecret:(NSString *)consumerSecret; + +/** + * Unavailable. Use `initWithConsumerKey:consumerSecret:` instead. + */ +- (instancetype)init __attribute__((unavailable("Use -initWithConsumerKey:consumerSecret: instead."))); + +@end \ No newline at end of file diff --git a/Frameworks/TwitterCore.framework/Headers/TWTRAuthSession.h b/Frameworks/TwitterCore.framework/Headers/TWTRAuthSession.h new file mode 100644 index 0000000..5fd522f --- /dev/null +++ b/Frameworks/TwitterCore.framework/Headers/TWTRAuthSession.h @@ -0,0 +1,18 @@ +// +// TWTRAuthSession.h +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import + +/** + * Encapsulates the authorization details of an OAuth Session. + */ +@protocol TWTRAuthSession + +@property (nonatomic, readonly, copy) NSString *authToken; +@property (nonatomic, readonly, copy) NSString *authTokenSecret; +@property (nonatomic, readonly, copy) NSString *userID; + +@end diff --git a/Frameworks/TwitterCore.framework/Headers/TWTRConstants.h b/Frameworks/TwitterCore.framework/Headers/TWTRConstants.h new file mode 100644 index 0000000..85cb9e0 --- /dev/null +++ b/Frameworks/TwitterCore.framework/Headers/TWTRConstants.h @@ -0,0 +1,99 @@ +// +// TWTRConstants.h +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import + +#pragma mark - Error messages + +/** + * The NSError domain of errors surfaced by the Twitter SDK. + */ +FOUNDATION_EXPORT NSString * const TWTRErrorDomain; + +/** + * Error codes surfaced by the Twitter SDK. + */ +typedef NS_ENUM(NSInteger, TWTRErrorCode) { + /** + * Unknown error. + */ + TWTRErrorCodeUnknown = -1, + /** + * Authentication has not been set up yet. You must call -[Twitter logInWithCompletion:] or -[Twitter logInGuestWithCompletion:] + */ + TWTRErrorCodeNoAuthentication = 0, + /** + * Twitter has not been initialized yet. Call +[Fabric with:@[TwitterKit]] or -[Twitter startWithConsumerKey:consumerSecret:]. + */ + TWTRErrorCodeNotInitialized = 1, + /** + * User has declined to grant permission to information such as their email address. + */ + TWTRErrorCodeUserDeclinedPermission = 2, + /** + * User has granted permission to their email address but no address is associated with their account. + */ + TWTRErrorCodeUserHasNoEmailAddress = 3, + /** + * A resource has been requested by ID, but that ID was not found. + */ + TWTRErrorCodeInvalidResourceID = 4, + /** + * A request has been issued for an invalid URL. + */ + TWTRErrorCodeInvalidURL = 5, + /** + * Type mismatch in parsing JSON from the Twitter API. + */ + TWTRErrorCodeMismatchedJSONType = 6, + /** + * Fail to save to keychain. + */ + TWTRErrorCodeKeychainSerializationFailure = 7, + /** + * Fail to save to disk. + */ + TWTRErrorCodeDiskSerializationError = 8, + /** + * Error authenticating with the webview. + */ + TWTRErrorCodeWebViewError = 9, + /** + * A required parameter is missing. + */ + TWTRErrorCodeMissingParameter = 10, +}; + +/** + * The NSError domain of errors surfaced by the Twitter SDK during the login operation. + */ +FOUNDATION_EXPORT NSString * const TWTRLogInErrorDomain; + +/** + * Error codes surfaced by the Twitter SDK with the `TWTRLogInErrorDomain` error domain. + */ +typedef NS_ENUM(NSInteger, TWTRLogInErrorCode) { + /** + * Unknown error. + */ + TWTRLogInErrorCodeUnknown = -1, + /** + * User denied login. + */ + TWTRLogInErrorCodeDenied = 0, + /** + * User canceled login. + */ + TWTRLogInErrorCodeCanceled = 1, + /** + * No Twitter account found. + */ + TWTRLogInErrorCodeNoAccounts = 2, + /** + * Reverse auth with linked account failed. + */ + TWTRLogInErrorCodeReverseAuthFailed = 3 +}; diff --git a/Frameworks/TwitterCore.framework/Headers/TWTRCoreOAuthSigning.h b/Frameworks/TwitterCore.framework/Headers/TWTRCoreOAuthSigning.h new file mode 100644 index 0000000..e4ae5dd --- /dev/null +++ b/Frameworks/TwitterCore.framework/Headers/TWTRCoreOAuthSigning.h @@ -0,0 +1,46 @@ +// +// TWTRCoreOAuthSigning.h +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import + +FOUNDATION_EXPORT NSString * const TWTROAuthEchoRequestURLStringKey; +FOUNDATION_EXPORT NSString * const TWTROAuthEchoAuthorizationHeaderKey; + +@protocol TWTRCoreOAuthSigning + +/** + * @name OAuth Echo + */ + +/** + * OAuth Echo is a means to securely delegate OAuth authorization to a third party while interacting with an API. + * For example, you may wish to verify a user's credentials from your app's server (the third party) rather than your app. + * This method provides you with the OAuth signature to add to the third party's request to `URLString`, as well as the formed + * URL with the query string to send that request to. + * This is equivalent to calling `-URLRequestWithMethod:URL:parameters:error:` and getting the URL and the `Authorization` HTTP header out of the request. + * + * @param method Request method, GET, POST, PUT, DELETE, etc. + * @param URLString The full URL of the Twitter endpoint you plan to send a request to. E.g. https://api.twitter.com/1.1/account/verify_credentials.json + * @param parameters Request parameters. + * @param error Error in the `TWTRErrorDomain` domain. The code will be `TWTRErrorCodeInvalidURL` if the `URLString`'s host is not api.twitter.com + * + * @return `nil` if there's an error or a missing required parameter, or a dictionary with the fully formed request URL under `TWTROAuthEchoRequestURLStringKey` (`NSString`), and the `Authorization` header in `TWTROAuthEchoAuthorizationHeaderKey` (`NSString`), to be used to sign the request. + * + * @see More information about OAuth Echo: https://dev.twitter.com/oauth/echo + */ +- (NSDictionary *)OAuthEchoHeadersForRequestMethod:(NSString *)method URLString:(NSString *)URLString parameters:(NSDictionary *)parameters error:(NSError **)error __attribute__((nonnull(1, 2))); + +/** + * This method provides you with the OAuth signature, as well as the formed URL with the query string, to send a request to `verify_credentials`. + * + * @return A dictionary with the fully formed Request URL under `TWTROAuthEchoRequestURLStringKey` (`NSString`), and the `Authorization` header in `TWTROAuthEchoAuthorizationHeaderKey` (`NSString`), to be used to sign the request. + * + * @see More information about OAuth Echo: https://dev.twitter.com/oauth/echo + * @see More information about Verify Credentials: https://dev.twitter.com/rest/reference/get/account/verify_credentials + */ +- (NSDictionary *)OAuthEchoHeadersToVerifyCredentials; + +@end diff --git a/Frameworks/TwitterCore.framework/Headers/TWTRGuestSession.h b/Frameworks/TwitterCore.framework/Headers/TWTRGuestSession.h new file mode 100644 index 0000000..3d42201 --- /dev/null +++ b/Frameworks/TwitterCore.framework/Headers/TWTRGuestSession.h @@ -0,0 +1,48 @@ +// +// TWTRGuestSession.h +// TwitterKit +// +// Created by Joey Carmello on 3/31/15. +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import + +@class TWTRGuestSession; + +/** + * Completion block called when guest login succeeds or fails. + * + * @param guestSession A `TWTRGuestSession` containing the OAuth tokens or nil. + * @param error Error that will be non nil if the authentication request failed. + */ +typedef void (^TWTRGuestLogInCompletion)(TWTRGuestSession *guestSession, NSError *error); + +/** + * `TWTRGuestSession` represents a guest session authenticated with the Twitter API. See `TWTRSession` for user sessions. + */ +@interface TWTRGuestSession : NSObject + +/** + * The bearer access token for guest auth. + */ +@property (nonatomic, copy, readonly) NSString *accessToken; + +/** + * The guest access token. + */ +@property (nonatomic, copy, readonly) NSString *guestToken; + +/** + * Returns an `TWTRGuestSession` object initialized by copying the values from the dictionary or nil if the dictionary is missing. + * + * @param sessionDictionary (required) The dictionary received after successfull authentication from Twitter guest-only authentication. + */ +- (instancetype)initWithSessionDictionary:(NSDictionary *)sessionDictionary; + +/** + * Unavailable. Use `-initWithSessionDictionary:` instead. + */ +- (instancetype)init __attribute__((unavailable("Use -initWithSessionDictionary: instead."))); + +@end diff --git a/Frameworks/TwitterCore.framework/Headers/TwitterCore.h b/Frameworks/TwitterCore.framework/Headers/TwitterCore.h new file mode 100644 index 0000000..c2e76bf --- /dev/null +++ b/Frameworks/TwitterCore.framework/Headers/TwitterCore.h @@ -0,0 +1,22 @@ +// +// TwitterCore.h +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#if __has_feature(modules) +@import CoreData; +@import Foundation; +@import UIKit; +#else +#import +#import +#import +#endif + +#import "TWTRAPIErrorCode.h" +#import "TWTRAuthConfig.h" +#import "TWTRAuthSession.h" +#import "TWTRConstants.h" +#import "TWTRCoreOAuthSigning.h" +#import "TWTRGuestSession.h" diff --git a/Frameworks/TwitterCore.framework/Info.plist b/Frameworks/TwitterCore.framework/Info.plist new file mode 100644 index 0000000..1e2398f --- /dev/null +++ b/Frameworks/TwitterCore.framework/Info.plist @@ -0,0 +1,53 @@ + + + + + BuildMachineOSBuild + 14D136 + CFBundleDevelopmentRegion + English + CFBundleGetInfoString + TwitterCore Framework + CFBundleIdentifier + com.twittercore.sdk.ios + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + TwitterCore + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.6.1 + CFBundleSupportedPlatforms + + iPhoneOS + + CFBundleVersion + 1.6.1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 12F69 + DTPlatformName + iphoneos + DTPlatformVersion + 8.3 + DTSDKBuild + 12F69 + DTSDKName + iphoneos8.3 + DTXcode + 0632 + DTXcodeBuild + 6D2105 + MinimumOSVersion + 7.0 + NSHumanReadableCopyright + Copyright 2015 Twitter Inc. + UIDeviceFamily + + 1 + 2 + + + diff --git a/Frameworks/TwitterCore.framework/Modules/module.modulemap b/Frameworks/TwitterCore.framework/Modules/module.modulemap new file mode 100644 index 0000000..64a5d10 --- /dev/null +++ b/Frameworks/TwitterCore.framework/Modules/module.modulemap @@ -0,0 +1,7 @@ +framework module TwitterCore { + umbrella header "TwitterCore.h" + + export * + module * { export * } +} + diff --git a/Frameworks/TwitterCore.framework/TwitterCore b/Frameworks/TwitterCore.framework/TwitterCore new file mode 100755 index 0000000..dc9f5ce Binary files /dev/null and b/Frameworks/TwitterCore.framework/TwitterCore differ diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRAPIClient.h b/Frameworks/TwitterKit.framework/Headers/TWTRAPIClient.h new file mode 100644 index 0000000..d3dac94 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRAPIClient.h @@ -0,0 +1,121 @@ +// +// TWTRAPIClient.h +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +FOUNDATION_EXPORT NSString * const TWTRTweetsNotLoadedKey; + +@class TWTRUser; +@class TWTRTweet; +@class TWTRAuthConfig; +@class TWTRGuestSession; +@protocol TWTRAuthSession; + +/** + * @name Completion Block Types + */ + +/** + * Completion block called when the load user request succeeds or fails. + * + * @param user The Twitter User. + * @param error Error that will be set if the API request failed. + */ +typedef void (^TWTRLoadUserCompletion)(TWTRUser *user, NSError *error); + +/** + * Completion block called when the load Tweet request succeeds or fails. + * + * @param tweet The Twitter Tweet. + * @param error Error that will be set if the API request failed. + */ +typedef void (^TWTRLoadTweetCompletion)(TWTRTweet *tweet, NSError *error); + +/** + * Completion block called when the load Tweets request succeeds or fails. + * + * @param tweets Tweets that were successfully retrieved. + * @param error Error that will be set if the API request failed. + */ +typedef void (^TWTRLoadTweetsCompletion)(NSArray *tweets, NSError *error); + +/** + * Completion block called when the network request succeeds or fails. + * + * @param response Metadata associated with the response to a URL load request. + * @param data Content data of the response. + * @param connectionError Error object describing the network error that occurred. + */ +typedef void (^TWTRNetworkCompletion)(NSURLResponse *response, NSData *data, NSError *connectionError); + +/** + * Client for consuming the Twitter REST API. Provides methods for common API requests, as well as the ability to create and send custom requests. + */ +@interface TWTRAPIClient : NSObject + +/** + * @name Initialization + */ + +- (instancetype)init __attribute__((unavailable(("Use one of the other `-init...` methods that allow you to provide signing parameters")))); + +/** + * This method is deprecated since TwitterKit v1.4.0. To get an API client, use the one provided by the `Twitter` class. + */ +- (instancetype)initWithConsumerKey:(NSString *)consumerKey consumerSecret:(NSString *)consumerSecret __attribute__((deprecated)); + +/** + * @name Making Requests + */ + +/** + * Returns a signed URL request. + * + * @param method Request method, GET, POST, PUT, DELETE, etc. + * @param URL Request URL. This is the full Twitter API URL. E.g. https://api.twitter.com/1.1/statuses/user_timeline.json + * @param parameters Request parameters. + * @param error Error that will be set if there was an error signing the request. + */ +- (NSURLRequest *)URLRequestWithMethod:(NSString *)method URL:(NSString *)URLString parameters:(NSDictionary *)parameters error:(NSError **)error; + +/** + * Sends a Twitter request. + * + * @param request The request that will be sent asynchronously. + * @param completion Completion block to be called on response. Called on main queue. + */ +- (void)sendTwitterRequest:(NSURLRequest *)request completion:(TWTRNetworkCompletion)completion; + +/** + * @name Common API Actions + */ + +/** + * Loads a Twitter User. + * + * @param userIDString The Twitter user ID of the desired user. + * @param completion Completion block to be called on response. Called on main queue. + */ +- (void)loadUserWithID:(NSString *)userIDString completion:(TWTRLoadUserCompletion)completion; + +/** + * Loads a single Tweet from the network or cache. + * + * @param tweetIDString The ID of the desired Tweet. + * @param completion Completion bock to be called on response. Called on main queue. + */ +- (void)loadTweetWithID:(NSString *)tweetIDString completion:(TWTRLoadTweetCompletion)completion; + +/** + * Loads a series of Tweets in a batch. The completion block will be passed an array of zero or more + * Tweets that loaded successfully. If some Tweets fail to load the array will contain less Tweets than + * number of requested IDs. If any Tweets fail to load, the IDs of the Tweets that did not load will + * be provided in the userInfo dictionary property of the error parameter under `TWTRTweetsNotLoadedKey`. + * + * @param tweetIDStrings An array of Tweet IDs. + * @param completion Completion block to be called on response. Called on main queue. + */ +- (void)loadTweetsWithIDs:(NSArray *)tweetIDStrings completion:(TWTRLoadTweetsCompletion)completion; + +@end diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRCollectionTimelineDataSource.h b/Frameworks/TwitterKit.framework/Headers/TWTRCollectionTimelineDataSource.h new file mode 100644 index 0000000..85f7b65 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRCollectionTimelineDataSource.h @@ -0,0 +1,43 @@ +// +// TWTRCollectionTimelineDataSource.h +// TwitterKit +// +// Created by Steven Hepting on 2/10/15. +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import +#import "TWTRTimelineDataSource.h" + +@class TWTRAPIClient; + +@interface TWTRCollectionTimelineDataSource : NSObject + +/** + * The number of Tweets to request in each query to the Twitter Timeline API when fetching the next batch of Tweets. + */ +@property (nonatomic, assign, readonly) NSInteger maxTweetsPerRequest; + +/** + * Convenience initializer. + * + * @param collectionID (required) The ID of this collection. For example, the ID of this collection: https://twitter.com/TwitterMusic/timelines/393773266801659904 is @"393773266801659904" + * + * @return An instance of TWTRCollectionTimelineDataSource or nil if any of the required parameters is missing. + */ +- (instancetype)initWithCollectionID:(NSString *)collectionID APIClient:(TWTRAPIClient *)client __attribute__((nonnull)); + +/** + * Designated initializer setting all supported values for Collection Timeline Data Source. + * + * @param collectionID (required) The Collection ID value. e.g. @"393773266801659904" + * @param apiClient (required) The API client to use for all network requests. + * @param maxTweetsPerRequest (optional) Number of Tweets to request per batch. A value of 0 uses the server default. + * + * @return An instance of TWTRCollectionTimelineDataSource or nil if any of the required parameters are missing. + */ +- (instancetype)initWithCollectionID:(NSString *)collectionID APIClient:(TWTRAPIClient *)client maxTweetsPerRequest:(NSUInteger)maxTweetsPerRequest __attribute__((nonnull)) NS_DESIGNATED_INITIALIZER; + +- (instancetype)init __unavailable; + +@end diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRComposer.h b/Frameworks/TwitterKit.framework/Headers/TWTRComposer.h new file mode 100644 index 0000000..345d112 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRComposer.h @@ -0,0 +1,69 @@ +// +// TWTRComposer.h +// TwitterKit +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import + +/** + * Possible values for the result parameter of the completionHandler property. + */ +typedef NS_ENUM(NSInteger, TWTRComposerResult) { + /** + * The composer is dismissed without sending the Tweet (i.e. the user selects Cancel, or the account is unavailable). + */ + TWTRComposerResultCancelled, + + /** + * The composer is dismissed and the message is being sent in the background, after the user selects Done. + */ + TWTRComposerResultDone +}; + +/** + * Completion block called when the user finishes composing a Tweet. + */ +typedef void (^TWTRComposerCompletion)(TWTRComposerResult result); + +/** + * The TWTRComposer class presents a view to the user to compose a Tweet. + */ +@interface TWTRComposer : NSObject + +/** + * Sets the initial text for the Tweet composition prior to showing it. + * + * @param text The text to tweet. + * + * @return This will return NO if the receiver has already been presented (and therefore cannot be changed). + */ +- (BOOL)setText:(NSString *)text; + +/** + * Sets an image attachment. + * + * @param image The image to attach. + * + * @return This will return NO if the receiver has already been presented (and therefore cannot be changed). + */ +- (BOOL)setImage:(UIImage *)image; + +/** + * Adds a URL to the contents of the Tweet message. + * + * @param url The URL. + * + * @return This will return NO if the receiver has already been presented (and therefore cannot be changed). + */ +- (BOOL)setURL:(NSURL *)url; + +/** + * Presents the composer, with an optional completion handler. + * + * @param completion The completion handler, which has a single parameter indicating whether the user finished or cancelled the Tweet composition. + */ +- (void)showWithCompletion:(TWTRComposerCompletion)completion; + +@end diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRLogInButton.h b/Frameworks/TwitterKit.framework/Headers/TWTRLogInButton.h new file mode 100644 index 0000000..8ade449 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRLogInButton.h @@ -0,0 +1,34 @@ +// +// TWTRLogInButton.h +// TwitterKit +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import +#import "TWTRSession.h" + +/** + * A Button which launches the sign in to Twitter flow when tapped. + */ +@interface TWTRLogInButton : UIButton + +/** + * The completion block to be called with a `TWTRSession` if successful, + * and a `NSError` if logging in failed or was canceled. + */ +@property (nonatomic, copy) TWTRLogInCompletion logInCompletion; + +/** + * Returns a new log in button which launches Twitter log in when tapped and + * calls `completion` when logging in succeeds or fails. + * + * Internally, this button simply calls `-[Twitter logInWithCompletion:]`. + * + * @param completion The completion to be called with a `TWTRSession` if successful, + * and a `NSError` if logging in failed or was canceled. + * @return An initialized `TWTRLogInButton`. + */ ++ (instancetype)buttonWithLogInCompletion:(TWTRLogInCompletion)completion; + +@end diff --git a/Frameworks/TwitterKit.framework/Headers/TWTROAuthSigning.h b/Frameworks/TwitterKit.framework/Headers/TWTROAuthSigning.h new file mode 100644 index 0000000..31454ef --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTROAuthSigning.h @@ -0,0 +1,41 @@ +// +// TWTROAuthSigning.h +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import + +@class TWTRAuthConfig; +@class TWTRSession; + +/** + * This class provides tools to generate OAuth signatures. + */ +@interface TWTROAuthSigning : NSObject + +/** + * @name Initialization + */ + +/** + * Instantiate a `TWTROAuthSigning` object with the parameters it needs to generate the OAuth signatures. + * + * @param authConfig (required) Encapsulates credentials required to authenticate a Twitter application. + * @param authSession (required) Encapsulated credentials associated with a user session. + * + * @return An initialized `TWTROAuthSigning` object or nil if any of the parameters are missing. + * + * @note If you want to generate OAuth Echo headers to verify Digits' credentials, see `DGTOAuthSigning`. + * + * @see TWTRAuthConfig + * @see TWTRSession + */ +- (instancetype)initWithAuthConfig:(TWTRAuthConfig *)authConfig authSession:(TWTRSession *)authSession NS_DESIGNATED_INITIALIZER; + +/** + * Unavailable. Use `-initWithAuthConfig:authSession:` instead. + */ +- (instancetype)init __attribute__((unavailable("Use -initWithAuthConfig:authSession: instead."))); + +@end diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRSearchTimelineDataSource.h b/Frameworks/TwitterKit.framework/Headers/TWTRSearchTimelineDataSource.h new file mode 100644 index 0000000..c8b672a --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRSearchTimelineDataSource.h @@ -0,0 +1,81 @@ +// +// TWTRSearchTimelineDataSource.h +// TwitterKit +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import +#import "TWTRTimelineDataSource.h" + +@class TWTRAPIClient; + +/** +Data source representing a Search Timeline. Provides TWTRTweet objects to a TWTRTimelineViewController in pages determined by the TWTRTimelineCursor object passed in to the `loadNext:` and `loadPrevious:` methods. + +## Search Queries: + + * `watching now` containing both “watching” and “now”. Default. + * `“happy hour”` containing the exact phrase “happy hour”. + * `love OR hate` containing either “love” or “hate” (or both). + * `beer -root` containing “beer” but not “root”. + * `#haiku` containing the hashtag “haiku”. + * `from:alexiskold`sent from person “alexiskold”. + * `to:techcrunch` sent to person “techcrunch”. + * `@mashable` referencing person “mashable”. + * `flight :(` containing “flight” and with a negative attitude. + * `traffic ?` containing “traffic” and asking a question. + * `movie -scary :)`containing “movie”, but not “scary”, and with a positive attitude. + * `hilarious filter:links` containing “hilarious” and linking to URL. + * `news source:twitterfeed`containing “news” and entered via TwitterFeed + * `superhero since:2010-12-27` containing “superhero” and sent since date “2010-12-27” (year-month-day). + * `ftw until:2010-12-27` containing “ftw” and sent before the date “2010-12-27”. + + @see https://dev.twitter.com/rest/public/search + Not implemented: `geocode`, `result_type` + */ +@interface TWTRSearchTimelineDataSource : NSObject + +/** + * The search query. This matches what you would type into https://twitter.com/search + */ +@property (nonatomic, copy, readonly) NSString *searchQuery; + +/** + * Restricts tweets returned to a given language, specified by its ISO 639-1 code (for example: en, es). Language detection is best-effort. The server defaults to returning Tweets in all languages. + * + * @see http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes + */ +@property (nonatomic, copy, readonly) NSString *languageCode; + +/** + * The number of Tweets to request in each network request for more Tweets. By default requests 30 tweets. If set to `0` the parameter will not be set on the request and the Twitter API will use the default size for the endpoint. + */ +@property (nonatomic, assign, readonly) NSUInteger maxTweetsPerRequest; + +/** + * Convenience initializer. Uses default values for `searchQuery`, `languageCode`, and `maxTweetsPerRequest`. + * + * @param searchQuery (required) The query string that you would type into https://twitter.com/search + * @param client (required) An instance of `TWTRAPIClient` with which API calls will be made. + * + * @return A fully initialized search timeline datasource or `nil` if any of the required parameters are missing. + */ + +- (instancetype)initWithSearchQuery:(NSString *)searchQuery APIClient:(TWTRAPIClient *)client __attribute__((nonnull)); + +/** + * Designated initializer for creating search timeline data sources taking all parameters. + * + * @param searchQuery (required) The query string that you would type into https://twitter.com/search + * @param client (required) An instance of `TWTRAPIClient` with which API calls will be made. + * @param languageCode (optional) The ISO 639-1 language code to restrict Tweets to. A `nil` value will not add the parameter to the server request and so use the server default. + * @param maxTweetsPerRequest (optional) The number of tweets to request in each query to the Twitter API. A value of 0 will not add to the parameters and thus use the server default. + * + * @return A fully initialized search timeline datasource or `nil` if any of the required parameters are missing. + */ +- (instancetype)initWithSearchQuery:(NSString *)searchQuery APIClient:(TWTRAPIClient *)client languageCode:(NSString *)languageCode maxTweetsPerRequest:(NSUInteger)maxTweetsPerRequest __attribute__((nonnull(1,2))) NS_DESIGNATED_INITIALIZER; + +- (instancetype)init __unavailable; + +@end diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRSession.h b/Frameworks/TwitterKit.framework/Headers/TWTRSession.h new file mode 100644 index 0000000..0195691 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRSession.h @@ -0,0 +1,53 @@ +// +// TWTRSession.h +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import +#import +#import + +/** + * TWTRSession represents a user's session authenticated with the Twitter API. + */ +@interface TWTRSession : NSObject + +/** + * The authorization token. + */ +@property (nonatomic, copy, readonly) NSString *authToken; +/** + * The authorization token secret. + */ +@property (nonatomic, copy, readonly) NSString *authTokenSecret; +/** + * The username associated with the access token. + */ +@property (nonatomic, copy, readonly) NSString *userName; +/** + * The user ID associated with the access token. + */ +@property (nonatomic, copy, readonly) NSString *userID; + +/** + * Returns an `TWTRSession` object initialized by copying the values from the dictionary or nil if the dictionary is missing. + * + * @param sessionDictionary (required) The dictionary received after successfull authentication from Twitter OAuth. + */ +- (instancetype)initWithSessionDictionary:(NSDictionary *)sessionDictionary; + +/** + * Unavailable. Use -initWithSessionDictionary: instead. + */ +- (instancetype)init __attribute__((unavailable("Use -initWithSessionDictionary: instead."))); + +@end + +/** + * Completion block called when user login succeeds or fails. + * + * @param session Contains the OAuth tokens and minimal information associated with the logged in user or nil. + * @param error Error that will be non nil if the authentication request failed. + */ +typedef void (^TWTRLogInCompletion)(TWTRSession *session, NSError *error); diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRShareEmailViewController.h b/Frameworks/TwitterKit.framework/Headers/TWTRShareEmailViewController.h new file mode 100644 index 0000000..0a83735 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRShareEmailViewController.h @@ -0,0 +1,37 @@ +// +// TWTRShareEmailViewController.h +// TwitterKit +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import + +/** + * A completion block to be called when the user accepts or denies access to their email address. + * + * @param email The user's email address. This will be nil if the user does not grant access to their email address or your application is not allowed to request email addresses. + * @param error An error that details why a user's email address could not be provided. + */ +typedef void (^TWTRShareEmailCompletion)(NSString *email, NSError *error); + +/** + * The `TWTRShareEmailViewController` class presents a view to the user to request their email address. This is a subclass of `UINavigationController` and must be presented modally. + * + * @note Using `TWTRShareEmailViewController` requires your application to be whitelisted by Twitter. To request access, please visit https://support.twitter.com/forms/platform. + */ +@interface TWTRShareEmailViewController : UINavigationController + +/** + * Completion block called when the user accepts or denies access to their email address. + */ +@property (nonatomic, copy) TWTRShareEmailCompletion completion; + +/** + * Initializer for `TWTRShareEmailViewController`. + * + * @param completion The completion block called when the user either accepts or denies access to their email address. Called on the main thread. + */ +- (instancetype)initWithCompletion:(TWTRShareEmailCompletion)completion; + +@end diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRTimelineDataSource.h b/Frameworks/TwitterKit.framework/Headers/TWTRTimelineDataSource.h new file mode 100644 index 0000000..7248637 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRTimelineDataSource.h @@ -0,0 +1,37 @@ +// +// TWTRTimelineDataSource.h +// TwitterKit +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import "TWTRTimelineType.h" + +@class TWTRTimelineCursor; + +typedef void (^TWTRLoadTimelineCompletion)(NSArray *tweets, TWTRTimelineCursor *cursor, NSError *error); + +/** + * Responsible for building network parameters for requesting a timeline of Tweets. + * + * Implementations of this protocol don't need to be thread-safe. All the methods will be invoked on the main thread. + */ +@protocol TWTRTimelineDataSource + +/** + * Load Tweets before a given position. For time-based timelines this generally + * corresponds to Tweets older than a position. + * + * @param position (optional) The position or Tweet ID before the page + * of Tweets to be loaded. + * @param completion (required) Invoked with the Tweets and the cursor in case of success, or nil + * and an error in case of error. This must be called on the main thread. + */ +- (void)loadPreviousTweetsBeforePosition:(NSString *)position completion:(TWTRLoadTimelineCompletion)completion __attribute__((nonnull(2))); + +/* + * The type of the timeline that this data source represents. + */ +@property (nonatomic, readonly) TWTRTimelineType timelineType; + +@end diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRTimelineType.h b/Frameworks/TwitterKit.framework/Headers/TWTRTimelineType.h new file mode 100644 index 0000000..4c6560d --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRTimelineType.h @@ -0,0 +1,25 @@ +// +// TWTRTimelineType.h +// TwitterKit +// +// Created by Steven Hepting on 3/30/15. +// Copyright (c) 2015 Twitter. All rights reserved. +// + +/* + * Type of timelines that may be loaded and shown to the user. + */ +typedef NS_ENUM(NSUInteger, TWTRTimelineType) { + /* + * User Timeline + */ + TWTRTimelineTypeUser = 1, + /* + * Search Timeline + */ + TWTRTimelineTypeSearch, + /** + * Collection Timeline + */ + TWTRTimelineTypeCollection, +}; diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRTimelineViewController.h b/Frameworks/TwitterKit.framework/Headers/TWTRTimelineViewController.h new file mode 100644 index 0000000..ef2c182 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRTimelineViewController.h @@ -0,0 +1,53 @@ +// +// TWTRTimelineViewController.h +// TwitterKit +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import +#import "TWTRTimelineDataSource.h" + +/** + This class is a `UITableViewController` subclass that displays `TWTRTweetTableViewCell` cells. It handles cell-reuse, cell-configuration, and loading more tweets from the given timeline once the last cell is reached. + + ## Usage + + Initialize this class with any object that conforms to the `TWTRTimelineDataSource` protocol. We provide two such classes, `TWTRUserTimelineDataSource` and `TWTRSearchTimelineDataSource`. These provide `TWTRTweet` objects to this table view which then configures the instances of `TWTRTweetTableViewCell`. + + // Create the data source + TWTRAPIClient *client = [Twitter sharedInstance].APIClient; + TWTRUserTimelineDataSource *dataSource = [[TWTRUserTimelineDataSource alloc] initWithScreenName:@"jack" APIClient:client]; + + // Create the timeline view controller + TWTRTimelineViewController *timeline = [[TWTRTimelineViewController alloc] initWithDataSource:dataSource]; + + ## Loading More + + This class loads the first batch of `TWTRTweet` objects from the Twitter API when `viewWillAppear:` is received. It also handles loading more tweets automatically once the last cell has been shown. + + */ +@interface TWTRTimelineViewController : UITableViewController + +/** + Initializes a timeline view controller. Does not start loading tweets until + `viewWillAppear:` is called. + + This method must be used to initialize this class. The `init` method is unavailable. + + @param dataSource Required. A timeline data source object that conforms to the `TWTRTimelineDataSource` protocol. + + @return A fully initialized `TWTRTimelineViewController` or nil if the data source is missing. + */ +- (instancetype)initWithDataSource:(id)dataSource NS_DESIGNATED_INITIALIZER; + +/** + The source of `TWTRTweet` objects for this `TWTRTimelineViewController`. + + May be set to update the tweets being shown by this table view. Must be set on the main thread. + */ +@property (nonatomic, strong) id dataSource; + +- (instancetype)initWithStyle:(UITableViewStyle)style __attribute__((unavailable("Use -initWithDataSource: instead"))); + +@end diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRTweet.h b/Frameworks/TwitterKit.framework/Headers/TWTRTweet.h new file mode 100644 index 0000000..ece874a --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRTweet.h @@ -0,0 +1,126 @@ +// +// TWTRTweet.h +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import + +@class TWTRTweet; +@class TWTRUser; + +/** + * `TWTRTweet` is an immutable representation of a Tweet. + */ +@interface TWTRTweet : NSObject + +# pragma mark - Properties + +/** + * The ID of the Twitter Tweet. + * @warning This represents the id_str field, which could differ from the value of the id field. + */ +@property (nonatomic, copy, readonly) NSString *tweetID; + +/** + * The date when this Tweet was created. + */ +@property (nonatomic, copy, readonly) NSDate *createdAt; + +/** + * The text of the Tweet. + */ +@property (nonatomic, copy, readonly) NSString *text; + +/** + * The Author of the Tweet. + */ +@property (nonatomic, strong, readonly) TWTRUser *author; + +/** + * The number of times this Tweet was favorited. + */ +@property (nonatomic, assign, readonly) long long favoriteCount; + +/** + * The number of times this Tweet was retweeted. + */ +@property (nonatomic, assign, readonly) long long retweetCount; + +/** + * The Tweet this Tweet was a reply to. + */ +@property (nonatomic, copy, readonly) NSString *inReplyToTweetID; + +/** + * The User ID this Tweet was a reply to. + */ +@property (nonatomic, copy, readonly) NSString *inReplyToUserID; + +/** + * The screen name of the user this Tweet was a reply to. + * @note This doesn't contain the `@` sign before the screen name. + */ +@property (nonatomic, copy, readonly) NSString *inReplyToScreenName; + +/** + * The permalink URL for this Tweet. + * + * Suitable for loading in a `UIWebView`, `WKWebView` or passing to Safari: + * + * `[[UIApplication sharedApplication] openURL:tweet.permalink];` + */ +@property (nonatomic, copy, readonly) NSURL *permalink; + +/** + * Whether this Tweet was favorited by the authenticated user. + * + * @warning The value of this property depends on the authenticated user. + */ +@property (nonatomic, assign, readonly) BOOL isFavorited; + +/** + * Whether this Tweet was retweeted by the authenticated user. + * + * @warning The value of this property depends on the authenticated user. + */ +@property (nonatomic, assign, readonly) BOOL isRetweeted; + +/** + * The Tweet ID of the authenticated user's retweet of this Tweet. This will be `nil` if there is no + * authenticated user or the user has not retweeted this Tweet. + * + * @warning The value of this property depends on the authenticated user. + */ +@property (nonatomic, copy, readonly) NSString *retweetID; + +/** + * The original, fully-hydrated Tweet that was retweeted. This corresponds to the `retweeted_status` API field. + * This is `nil` unless `self.isRetweet == YES`. + */ +@property (nonatomic, strong, readonly) TWTRTweet *retweetedTweet; + +/** + * Indicates whether this Tweet is a retweet of another Tweet. + */ +@property (nonatomic, assign, readonly) BOOL isRetweet; + +# pragma mark - Init + +/** + * Creates a TWTRTweet instance from the dictionary of Twitter API JSON response. + * + * @param dictionary A parsed dictionary of a single Twitter Tweet API JSON response. + * @return TWTRTweet instance. + */ +- (instancetype)initWithJSONDictionary:(NSDictionary *)dictionary; + +/** + * Creates an array of TWTRTweet instances from the array of Twitter API JSON response. + * + * @param array A parsed array of Tweet API JSON responses. + * @return An array of TWTRTweet instances. + */ ++ (NSArray *)tweetsWithJSONArray:(NSArray *)array; + +@end diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRTweetTableViewCell.h b/Frameworks/TwitterKit.framework/Headers/TWTRTweetTableViewCell.h new file mode 100644 index 0000000..61cc0d9 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRTweetTableViewCell.h @@ -0,0 +1,63 @@ +// +// TWTRTweetTableViewCell.h +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import + +@class TWTRTweet; +@class TWTRTweetView; + +/** + * A table view cell subclass which displays a Tweet. + */ +@interface TWTRTweetTableViewCell : UITableViewCell + +/** + * The Tweet view inside this cell. Holds all relevant text and images. + */ +@property (nonatomic, strong, readonly) TWTRTweetView *tweetView; + +/** + * Configures the existing Tweet view with a Tweet. Updates labels, images, and thumbnails. + * + * @param tweet The `TWTRTweet` model object for the Tweet to display. + */ +- (void)configureWithTweet:(TWTRTweet *)tweet; + +/** + * Returns the height calculated using a given width. Usable from a background thread. This is the preferred approach to calculating height for tableview cells. + + - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + TWTRTweet *tweet = self.tweets[indexPath.row]; + + // Grab the height for this cell + CGFloat height = [TWTRTweetTableViewCell heightForTweet:tweet width:CGRectGetWidth(self.view.bounds)]; + return height; + } + + * @param width The table view cell width. + */ ++ (CGFloat)heightForTweet:(TWTRTweet *)tweet width:(CGFloat)width; + +/** + DEPRECATED + + Returns the height calculated using a given width. Generally just for use with prototype cells. + + - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + TWTRTweet *tweet = self.tweets[indexPath.row]; + + // Grab the height for this cell + CGFloat height = [TWTRTweetTableViewCell heightForTweet:tweet width:CGRectGetWidth(self.view.bounds)]; + return height; + } + + @deprecated Use +heightForTweet:width: instead. Deprecated in version 1.3.0 + + @param width The table view cell width. + */ +- (CGFloat)calculatedHeightForWidth:(CGFloat)width __attribute__((deprecated("Use +heightForTweet:width: instead."))); + +@end diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRTweetView.h b/Frameworks/TwitterKit.framework/Headers/TWTRTweetView.h new file mode 100644 index 0000000..4ccf79d --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRTweetView.h @@ -0,0 +1,172 @@ +// +// TWTRTweetView.h +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import +#import "TWTRTweetViewDelegate.h" + +@class TWTRTweet; + +/** + * The style for Tweet views. + */ +typedef NS_ENUM(NSUInteger, TWTRTweetViewStyle) { + /** + * A full-size Tweet view. Displays images if present. + */ + TWTRTweetViewStyleRegular, + /** + * A small Tweet view, primarily designed to be used in table views. + */ + TWTRTweetViewStyleCompact +}; + +/** + * A default combination of colors for Tweet views. + */ +typedef NS_ENUM(NSUInteger, TWTRTweetViewTheme) { + /** + * Official light theme. + */ + TWTRTweetViewThemeLight, + /** + * Official dark theme. + */ + TWTRTweetViewThemeDark, +}; + +/** + `TWTRTweetView` displays a single Tweet to the user. It handles background taps and other actions displayed to the user. + + [[[Twitter sharedInstance] APIClient] loadTweetWithID:@"20" completion:^(TWTRTweet *tweet, NSError *error) { + if (tweet) { + TWTRTweetView *tweetView = [[TWTRTweetView alloc] initWithTweet:tweet]; + [self.view addSubview:tweetView]; + } else { + NSLog(@"Error loading Tweet: %@", [error localizedDescription]); + } + }]; + + ## Interaction + + The `TWTRTweetViewDelegate` is notified: + + - When the background is tapped. + - When a link is selected. + - When the share button is tapped. + - When the share action completes. + + ## Usage in UITableView + + To allow for usage in a `UITableView`, the `configureWithTweet:` method allows configuration of an existing `TWTRTweetView` without having to create a new instance. + + ## Sizing + + When using Auto Layout, feel free to set a width or margin on the Tweet view. The height will be calculated automatically. For old-fashioned frame based layout you may use the standard `sizeThatFits:` method to calculate the appropriate height for a given width: + + // Find the height for a given width (20pts on either side) + CGFloat desiredHeight = [tweetView sizeThatFits:CGSizeMake(self.view.frame.size.width - 40, CGFLOAT_MAX)].height; + + ## UIAppearance + + You may use UIAppearance proxy objects to style certain aspects of Tweet views before those views are added to the view hierarchy. + + // Using UIAppearance Proxy + [TWTRTweetView appearance].theme = TWTRTweetViewThemeDark; + + // Setting colors directly + [TWTRTweetView appearance].primaryTextColor = [UIColor yellowColor]; + [TWTRTweetView appearance].backgroundColor = [UIColor blueColor]; + + _Note:_ You can't change the theme through an appearance proxy after the view has already been added to the view hierarchy. Direct `theme` property access will work though. + */ +@interface TWTRTweetView : UIView + +/** + * Background color of the Tweet view and all text labels (fullname, username, Tweet text, timestamp). + */ +@property (nonatomic, strong) UIColor *backgroundColor UI_APPEARANCE_SELECTOR; + +/** + * Color of Tweet text and full name. + */ +@property (nonatomic, strong) UIColor *primaryTextColor UI_APPEARANCE_SELECTOR; + +/** + * Color of links in Tweet text. + */ +@property (nonatomic, strong) UIColor *linkTextColor UI_APPEARANCE_SELECTOR; + +/** + * Set whether the border should be shown. + */ +@property (nonatomic, assign) BOOL showBorder UI_APPEARANCE_SELECTOR; + +/** + * Setting the theme of the Tweet view will change the color properties accordingly. + * + * Set to `TWTRTweetViewThemeLight` by default. + */ +@property (nonatomic, assign) TWTRTweetViewTheme theme UI_APPEARANCE_SELECTOR; + +/** + * The style of the Tweet. i.e. `TWTRTweetViewStyleRegular` or `TWTRTweetViewStyleCompact`. + */ +@property (nonatomic, assign, readonly) TWTRTweetViewStyle style; + +/** + * The optional delegate to allow presenting a webview with Tweet details. + */ +@property (nonatomic, weak) IBOutlet id delegate; + +/** + * Convenience initializer to configure a compact style Tweet view. + * + * @param tweet The Tweet to display. + * + * @return The fully-configured Tweet view. + */ +- (instancetype)initWithTweet:(TWTRTweet *)tweet; + +/** + * Designated initializer. Initializes view with both Tweet and style. + * + * @param tweet The Tweet to display. + * @param style The style of the Tweet view (regular or compact). + * + * @return The fully configured Tweet view. + */ +- (instancetype)initWithTweet:(TWTRTweet *)tweet style:(TWTRTweetViewStyle)style; + +/** + * Initialization with a frame parameter is not supported. + */ +- (instancetype)initWithFrame:(CGRect)frame __attribute__((unavailable("Use -initWithTweet: instead"))); + +/** + Find the size that fits into a desired space. This is a system method on UIView but implemented on `TWTRTweetView` + + TWTRTweetView *tweetView = [[TWTRTweetView alloc] initWithTweet:tweet]; + + // Make it 280 points wide + CGSize desiredSize = [tweetView sizeThatFits:CGSizeMake(280, CGFLOAT_MAX)]; + tweetView.frame = CGRectMake(PADDING_X, PADDING_Y, 280, desiredSize.height); + + [self.view addSubview:tweetView]; + + @param size The space available. Should generally leave one orientation unconstrained, and the minimum width supported is 200pts. + + @return The size that will fit into the space available. + */ +- (CGSize)sizeThatFits:(CGSize)size; + +/** + * Update all images and label text to fully represent the given Tweet. + * + * @param tweet The Tweet to display. + */ +- (void)configureWithTweet:(TWTRTweet *)tweet; + +@end diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRTweetViewDelegate.h b/Frameworks/TwitterKit.framework/Headers/TWTRTweetViewDelegate.h new file mode 100644 index 0000000..6714837 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRTweetViewDelegate.h @@ -0,0 +1,65 @@ +// +// TWTRTweetViewDelegate.h +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import + +@class TWTRTweetView; +@class TWTRTweet; + +/** + Delegate for `TWTRTweetView` to receive updates on the user interacting with this particular Tweet view. + + // Create the tweet view + TWTRTweetView *tweetView = [[TWTRTweetView alloc] initWithTweet:tweet]; + // Set the delegate + tweetView.delegate = self; + */ +@protocol TWTRTweetViewDelegate + +@optional + +/** + * The tweet view was tapped. Implement to show your own webview if desired using the `permalinkURL` property on the `TWTRTweet` object passed in. + * + * @param tweetView The Tweet view that was tapped. + * @param tweet The Tweet model object being shown. + */ +- (void)tweetView:(TWTRTweetView *)tweetView didSelectTweet:(TWTRTweet *)tweet; + +/** + * A URL in the text of a tweet was tapped. Implement to show your own webview rather than opening Safari. + * + * @param tweetView The Tweet view that was tapped. + * @param url The URL that was tapped. + */ +- (void)tweetView:(TWTRTweetView *)tweetView didTapURL:(NSURL *)url; + +/** + * The Tweet view "Share" button was tapped and the `UIActivityViewController` was shown. + * + * @param tweetView The Tweet view that was tapped. + * @param tweet The Tweet model object being shown. + */ +- (void)tweetView:(TWTRTweetView *)tweetView willShareTweet:(TWTRTweet *)tweet; + +/** + * The share action for a Tweet was completed. + * + * @param tweetView The Tweet view that was tapped. + * @param tweet The Tweet model object being shown. + * @param shareType The share action that was completed. (e.g. `UIActivityTypePostToFacebook`, `UIActivityTypePostToTwitter`, or `UIActivityTypeMail`) + */ +- (void)tweetView:(TWTRTweetView *)tweetView didShareTweet:(TWTRTweet *)tweet withType:(NSString *)shareType; + +/** + * The share action for a Tweet was cancelled. + * + * @param tweetView The tweet view handling the share action. + * @param tweet The tweet model object represented. + */ +- (void)tweetView:(TWTRTweetView *)tweetView cancelledShareTweet:(TWTRTweet *)tweet; + +@end diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRUser.h b/Frameworks/TwitterKit.framework/Headers/TWTRUser.h new file mode 100644 index 0000000..87d00b0 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRUser.h @@ -0,0 +1,85 @@ +// +// TWTRUser.h +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import + +/** + * Represents a user on Twitter. + */ +@interface TWTRUser : NSObject + +# pragma mark - Properties + +/** + * The ID of the Twitter User. + */ +@property (nonatomic, copy, readonly) NSString *userID; + +/** + * The user's name as it appears on their profile. + * + * @warning This can be modified by the user at any time. + */ +@property (nonatomic, copy, readonly) NSString *name; + +/** + * The user's username on Twitter. + * + * @warning This can be modified by the user at any time. + */ +@property (nonatomic, copy, readonly) NSString *screenName; + +/** + * Whether the user has been verified by Twitter. + */ +@property (nonatomic, assign, readonly) BOOL isVerified; + +/** + * Whether the user is protected. + */ +@property (nonatomic, assign, readonly) BOOL isProtected; + +/** + * The HTTPS URL of the user's profile image. + */ +@property (nonatomic, copy, readonly) NSString *profileImageURL; + +/** + * The URL of a smaller version of the user's profile image. + */ +@property (nonatomic, copy, readonly) NSString *profileImageMiniURL; + +/** + * The URL of a larger version of the user's profile image. + */ +@property (nonatomic, copy, readonly) NSString *profileImageLargeURL; + +/** + * The formatted version of the user's `screenName` with the `@` sign for display purposes. + */ +@property (nonatomic, copy, readonly) NSString *formattedScreenName; + +# pragma mark - Init + +/** + * Creates a Twitter user object from the dictionary of Twitter API JSON response. + * + * @param dictionary A parsed dictionary of a single Twitter Tweet API JSON response. + * + * @return An initialized TWTRUser instance. + */ +- (instancetype)initWithJSONDictionary:(NSDictionary *)dictionary; + +/** + * Creates an array of Twitter User instances from the array of Twitter API JSON response. + * + * @param array A parsed array of Twitter User API JSON responses. + * + * @return An array of initialized TWTRTweet instances. + */ ++ (NSArray *)usersWithJSONArray:(NSArray *)array; + +@end \ No newline at end of file diff --git a/Frameworks/TwitterKit.framework/Headers/TWTRUserTimelineDataSource.h b/Frameworks/TwitterKit.framework/Headers/TWTRUserTimelineDataSource.h new file mode 100644 index 0000000..3953489 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TWTRUserTimelineDataSource.h @@ -0,0 +1,75 @@ +// +// TWTRUserTimelineDataSource.h +// TwitterKit +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import +#import "TWTRTimelineDataSource.h" + +@class TWTRAPIClient; + +/** + * This Timeline Data Source provides a list of Tweets roughly consistent with the list on a Users profile page. The difference is that this data source will filter out Tweets that are direct replies to other users by default. + * + * These Tweets are ordered chronologically with the most recent first. + */ +@interface TWTRUserTimelineDataSource : NSObject + +/** + * The screen name of the User whose Tweets are being shown. Either the `screenName` or the `userID` are required. + */ +@property (nonatomic, copy, readonly) NSString *screenName; + +/** + * The userID of the User whose Tweets are being shown. Either the `screenName` or the `userID` are required. + */ +@property (nonatomic, copy, readonly) NSString *userID; + +/** + * The number of Tweets to request in each query to the Twitter Timeline API when fetching the next batch of Tweets. Will request 30 Tweets by default. Setting this value to 0 will use the server default. + */ +@property (nonatomic, assign, readonly) NSUInteger maxTweetsPerRequest; + +/** + * Whether to request replies in the set of Tweets from the server. + * + * Defaults to NO. + */ +@property (nonatomic, assign, readonly) BOOL includeReplies; + +/** + * Whether to request retweets in the set of Tweets from the server. + * + * Defaults to YES. + */ +@property (nonatomic, assign, readonly) BOOL includeRetweets; + +/** + * Convenience initializer. Uses default values for `maxTweetsPerRequest`, `includeReplies` and `includeRetweets`. + * + * @param screenName (required) The screen name of a Twitter User + * @param client (required) The API client which the network requests will made. + * + * @return A fully initialized user timeline datasource or nil. + */ +- (instancetype)initWithScreenName:(NSString *)screenName APIClient:(TWTRAPIClient *)client __attribute__((nonnull)); + +/** + * The designated initialzer accepted values for properties. + * + * @param userID (optional) The user ID of the Twitter User + * @param screenName (optional) The screen name of the Twitter User + * @param APIClient (required) The API client to use for making network requests. + * @param maxTweetsPerRequest (optional) The number of Tweets per batch to request. A value of 0 will use the server default. + * @param includeReplies (optional) Whether replies should be requested + * @param includeRetweets (optional) Whether retweets should be requested + * + * @return A fully initialized user timeline or nil. + */ +- (instancetype)initWithScreenName:(NSString *)screenName userID:(NSString *)userID APIClient:(TWTRAPIClient *)client maxTweetsPerRequest:(NSUInteger)maxTweetsPerRequest includeReplies:(BOOL)includeReplies includeRetweets:(BOOL)includeRetweets __attribute__((nonnull(3))) NS_DESIGNATED_INITIALIZER; + +- (instancetype)init __unavailable; + +@end diff --git a/Frameworks/TwitterKit.framework/Headers/Twitter.h b/Frameworks/TwitterKit.framework/Headers/Twitter.h new file mode 100644 index 0000000..63e4e93 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/Twitter.h @@ -0,0 +1,127 @@ +// +// Twitter.h +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#import +#import "TWTRAPIClient.h" +#import "TWTRSession.h" + +/** + * The central class of the Twitter Kit. + * @note This class can only be used from the main thread. + */ +@interface Twitter : NSObject + +/** + * Returns the Twitter singleton. + * + * @return The Twitter singleton. + */ ++ (Twitter *)sharedInstance; + +/** + * Start Twitter with your consumer key and secret. These will override any credentials + * present in your applications Info.plist. + * + * You do not need to call this method unless you wish to provide credentials other than those + * in your Info.plist. + * + * @param consumerKey Your Twitter application's consumer key. + * @param consumerSecret Your Twitter application's consumer secret. + */ +- (void)startWithConsumerKey:(NSString *)consumerKey consumerSecret:(NSString *)consumerSecret; + +/** + * Client for consuming the Twitter REST API. + * + * This API client is configured with your consumer key and secret if they are available to the Twitter + * object (either via initialization of the Twitter instance or your application's Info.plist). + * + * @warning To make authenticated requests, you need to call `loginWithCompletion:` or `loginGuestWithCompletion:`. + */ +@property (nonatomic, strong, readonly) TWTRAPIClient *APIClient; + +/** + * The current version of this kit. + */ +@property (nonatomic, copy, readonly) NSString *version; + +/** + * The Twitter application consumer key. + * @deprecated This property is deprecated and will be removed in a later release. Please use `authConfig`. + */ +@property (nonatomic, copy, readonly) NSString *consumerKey __attribute__((deprecated("Use `authConfig`. This property will be removed in a later release."))); + +/** + * The Twitter application consumer secret. + * @deprecated This property is deprecated and will be removed in a later release. Please use `authConfig`. + */ +@property (nonatomic, copy, readonly) NSString *consumerSecret __attribute__((deprecated("Use `authConfig`. This property will be removed in a later release."))); + +/** + * Authentication configuration details. Encapsulates the `consumerKey` and `consumerSecret` credentials required to authenticate a Twitter application. + */ +@property (nonatomic, strong, readonly) TWTRAuthConfig *authConfig; + +/** + * @name Authentication + */ + +/** + * Triggers user authentication with Twitter. + * + * This method will present UI to allow the user to log in if there are no saved Twitter login credentials. + * + * @param completion The completion block will be called after authentication is successful or if there is an error. + * @warning This method requires that you have set up your `consumerKey` and `consumerSecret`. + */ +- (void)logInWithCompletion:(TWTRLogInCompletion)completion; + +/** + * Triggers user authentication with Twitter. Allows the developer to specify the presenting view controller. + * + * This method will present UI to allow the user to log in if there are no saved Twitter login credentials. + * + * @param viewController The view controller that will be used to present the authentication view. + * @param completion The completion block will be called after authentication is successful or if there is an error. + * @warning This method requires that you have set up your `consumerKey` and `consumerSecret`. + */ +- (void)logInWithViewController:(UIViewController *)viewController completion:(TWTRLogInCompletion)completion; + +/** + * Log in a guest user. This can be used when the user is not a Twitter user. + * + * This method will not present any UI to the user. + * + * @param completion The completion block will be called after authentication is successful or if there is an error. + * @warning This method requires that you have set up your `consumerKey` and `consumerSecret`. + */ +- (void)logInGuestWithCompletion:(TWTRGuestLogInCompletion)completion; + +/** + * Returns the current user session or nil if there is no logged in user. + * + * @return Returns the current user session or nil if there is no logged in user. + */ +- (TWTRSession *)session; + +/** + * Returns the current guest session or nil if there is no logged in guest. + * + * @return Returns the current guest session or nil if there is no logged in guest. + */ +- (TWTRGuestSession *)guestSession; + +/** + * Deletes the local Twitter user session from this app. This will not remove the system Twitter account nor make a network request to invalidate the session. + */ +- (void)logOut; + +/** + * Deletes the local guest session. Does not make a network request to invalidate the session. + */ +- (void)logOutGuest; + +@end diff --git a/Frameworks/TwitterKit.framework/Headers/TwitterKit.h b/Frameworks/TwitterKit.framework/Headers/TwitterKit.h new file mode 100644 index 0000000..3b2bf24 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Headers/TwitterKit.h @@ -0,0 +1,47 @@ +// +// TwitterKit.h +// +// Copyright (c) 2015 Twitter. All rights reserved. +// + +#if __has_feature(modules) +@import Accounts; +@import Foundation; +@import Social; +@import UIKit; +#else +#import +#import +#import +#import +#endif + +#import + +#import "TWTRAPIClient.h" +#import "TWTRCollectionTimelineDataSource.h" +#import "TWTRComposer.h" +#import "TWTRLogInButton.h" +#import "TWTROAuthSigning.h" +#import "TWTRSearchTimelineDataSource.h" +#import "TWTRShareEmailViewController.h" +#import "TWTRSession.h" +#import "TWTRTimelineDataSource.h" +#import "TWTRTimelineType.h" +#import "TWTRTimelineViewController.h" +#import "TWTRTweet.h" +#import "TWTRTweetTableViewCell.h" +#import "TWTRTweetView.h" +#import "TWTRTweetViewDelegate.h" +#import "TWTRUser.h" +#import "TWTRUserTimelineDataSource.h" +#import "Twitter.h" + +#if __has_include() +#import +#endif + +/** + * `TwitterKit` can be used as an element in the array passed to the `+[Fabric with:]`. + */ +#define TwitterKit [Twitter sharedInstance] diff --git a/Frameworks/TwitterKit.framework/Info.plist b/Frameworks/TwitterKit.framework/Info.plist new file mode 100644 index 0000000..de2ede8 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Info.plist @@ -0,0 +1,53 @@ + + + + + BuildMachineOSBuild + 14D136 + CFBundleDevelopmentRegion + English + CFBundleGetInfoString + Twitter Kit Framework + CFBundleIdentifier + com.twitter.sdk.ios + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + TwitterKit + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.6.1 + CFBundleSupportedPlatforms + + iPhoneOS + + CFBundleVersion + 1.6.1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 12F69 + DTPlatformName + iphoneos + DTPlatformVersion + 8.3 + DTSDKBuild + 12F69 + DTSDKName + iphoneos8.3 + DTXcode + 0632 + DTXcodeBuild + 6D2105 + MinimumOSVersion + 7.0 + NSHumanReadableCopyright + Copyright 2014 Twitter Inc. + UIDeviceFamily + + 1 + 2 + + + diff --git a/Frameworks/TwitterKit.framework/Modules/module.modulemap b/Frameworks/TwitterKit.framework/Modules/module.modulemap new file mode 100644 index 0000000..7eb9c17 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module TwitterKit { + umbrella header "TwitterKit.h" + + export * + module * { export * } +} diff --git a/Frameworks/TwitterKit.framework/Resources b/Frameworks/TwitterKit.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/Frameworks/TwitterKit.framework/TwitterKit b/Frameworks/TwitterKit.framework/TwitterKit new file mode 100755 index 0000000..e2695d7 Binary files /dev/null and b/Frameworks/TwitterKit.framework/TwitterKit differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/TFSScribe.momd/TFSScribe.mom b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/TFSScribe.momd/TFSScribe.mom new file mode 100644 index 0000000..a9a786b Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/TFSScribe.momd/TFSScribe.mom differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/TFSScribe.momd/VersionInfo.plist b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/TFSScribe.momd/VersionInfo.plist new file mode 100644 index 0000000..45677dc Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/TFSScribe.momd/VersionInfo.plist differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ar.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ar.lproj/Localizable.strings new file mode 100644 index 0000000..6e2f181 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ar.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/bn.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/bn.lproj/Localizable.strings new file mode 100644 index 0000000..dc0aa93 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/bn.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/cs.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/cs.lproj/Localizable.strings new file mode 100644 index 0000000..2ff222f Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/cs.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/da.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/da.lproj/Localizable.strings new file mode 100644 index 0000000..00b8488 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/da.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/de.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/de.lproj/Localizable.strings new file mode 100644 index 0000000..6fa77c3 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/de.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/emailshare.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/emailshare.png new file mode 100644 index 0000000..ebaa1eb Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/emailshare.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/emailshare@2x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/emailshare@2x.png new file mode 100644 index 0000000..2546629 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/emailshare@2x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/emailshare@3x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/emailshare@3x.png new file mode 100644 index 0000000..18defd7 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/emailshare@3x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/en-gb.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/en-gb.lproj/Localizable.strings new file mode 100644 index 0000000..7fcb20a Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/en-gb.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/en.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/en.lproj/Localizable.strings new file mode 100644 index 0000000..8e51c5d --- /dev/null +++ b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/en.lproj/Localizable.strings @@ -0,0 +1,53 @@ +/* Label for button to bring up share dialog to share this Tweet in a single Tweet view */ +"tw__share_tweet" = "Share Tweet"; +/* Subject format used to prefill certain sharing options such as Email includes full name (%1$@) and screenname (%2$@) */ +"tw__share_tweet_subject_format" = "Tweet from %1$@ (@%2$@)"; +/* Generic share text format used in all sharing options includes screenname (%1$@) and URL to the Tweet (%2$@) */ +"tw__share_tweet_generic_template_format" = "Check out @%1$@\'s Tweet: %2$@"; +/* Label for Sign in with Twitter button */ +"tw__sign_in_with_twitter_button" = "Log in with Twitter"; +/* Label Email Share Screen negative button */ +"tw__email_share_negative_button" = "Not now"; +/* Label Email Share Screen affirmative button */ +"tw__email_share_affirmative_button" = "Allow"; +/* Heading that appears above the detail message on the share your email screen */ +"tw__email_share_heading" = "Share your email address"; +/* Detail message that includes the app name and username on the share your email screen */ +"tw__email_share_detail_message_format" = "Get updates and other information from %@ when you allow them access to your email on your Twitter account @%@."; +/* Fallback string for detail message in case the app name is not available */ +"tw__email_share_detail_message_this_app" = "this app"; +/* Fallback string for detail message in case the user is not signed in */ +"tw__email_share_detail_message_not_signed_in" = "(not signed in)"; +/* Label for attributing this Tweet was retweeted by the user %@ */ +"tw__tweet_retweeted_by_user" = "Retweeted by %@"; + +/* Timestamps */ + +/* Really short abbreviation for days (plural). 5 days would be '5d' */ +"TIME_SHORT_DAYS_FORMAT" = "%dd"; +/* Really short abbreviation for day (singular). 1 day would be '1d' */ +"TIME_SHORT_DAY_FORMAT" = "%dd"; +/* Really short abbreviation for hours (plural). 5 hours would be '5h' */ +"TIME_SHORT_HOURS_FORMAT" = "%dh"; +/* Really short abbreviation for hour (singular). 1 hour would be '1h' */ +"TIME_SHORT_HOUR_FORMAT" = "%dh"; +/* Really short abbreviation for minutes (plural). 5 minutes would be '5m' */ +"TIME_SHORT_MINUTES_FORMAT" = "%dm"; +/* Really short abbreviation for minute (singular). 1 minute would be '1m' */ +"TIME_SHORT_MINUTE_FORMAT" = "%dm"; +/* Really short abbreviation for seconds (plural). 5 seconds would be '5s' */ +"TIME_SHORT_SECONDS_FORMAT" = "%ds"; +/* Really short abbreviation for second (singular). '1s' */ +"TIME_SHORT_SECOND_FORMAT" = "%ds"; + +/* Accessibility Labels */ + +/* Text spoken out with VoiceOver when a tweet has an image showing */ +"tw__single_image" = "One image attached"; +/* Text spoken out with VoiceOver for selecting the profile image on a regular tweet view */ +"tw__tweet_profile_accessibility" = "Profile"; +/* Text spoken out with VoiceOver for selecting the attached image on a regular tweet view */ +"tw__tweet_image_accessibility" = "Attachment"; + +/* Test String (just for unit tests) */ +"tw__test_string" = "Test"; diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/es.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/es.lproj/Localizable.strings new file mode 100644 index 0000000..e645165 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/es.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/fa.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/fa.lproj/Localizable.strings new file mode 100644 index 0000000..d85e9c2 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/fa.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/fi.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/fi.lproj/Localizable.strings new file mode 100644 index 0000000..fad15a3 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/fi.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/fr.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/fr.lproj/Localizable.strings new file mode 100644 index 0000000..7ff8acd Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/fr.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/he.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/he.lproj/Localizable.strings new file mode 100644 index 0000000..9b9680d Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/he.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/hi.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/hi.lproj/Localizable.strings new file mode 100644 index 0000000..6bd07c7 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/hi.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/hu.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/hu.lproj/Localizable.strings new file mode 100644 index 0000000..d3401d6 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/hu.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/id.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/id.lproj/Localizable.strings new file mode 100644 index 0000000..f2312a9 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/id.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/it.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/it.lproj/Localizable.strings new file mode 100644 index 0000000..029a45d Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/it.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ja.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ja.lproj/Localizable.strings new file mode 100644 index 0000000..7f7f5a5 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ja.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ko.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ko.lproj/Localizable.strings new file mode 100644 index 0000000..a3f237b Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ko.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ms.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ms.lproj/Localizable.strings new file mode 100644 index 0000000..a0171a9 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ms.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/nb.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/nb.lproj/Localizable.strings new file mode 100644 index 0000000..878848e Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/nb.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/nl.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/nl.lproj/Localizable.strings new file mode 100644 index 0000000..0f2f331 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/nl.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/pl.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/pl.lproj/Localizable.strings new file mode 100644 index 0000000..cf0dfcf Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/pl.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/pt.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/pt.lproj/Localizable.strings new file mode 100644 index 0000000..74f567e Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/pt.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ro.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ro.lproj/Localizable.strings new file mode 100644 index 0000000..9cbeefd Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ro.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ru.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ru.lproj/Localizable.strings new file mode 100644 index 0000000..6dd56c5 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ru.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/sv.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/sv.lproj/Localizable.strings new file mode 100644 index 0000000..42519ac Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/sv.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/th.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/th.lproj/Localizable.strings new file mode 100644 index 0000000..33781fe Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/th.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/tl.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/tl.lproj/Localizable.strings new file mode 100644 index 0000000..91b6041 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/tl.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/tr.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/tr.lproj/Localizable.strings new file mode 100644 index 0000000..730f875 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/tr.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo-white.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo-white.png new file mode 100644 index 0000000..b7e4f7c Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo-white.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo-white@2x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo-white@2x.png new file mode 100644 index 0000000..bbfbee7 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo-white@2x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo-white@3x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo-white@3x.png new file mode 100644 index 0000000..3074978 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo-white@3x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo.png new file mode 100644 index 0000000..ea6f7cd Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo@2x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo@2x.png new file mode 100644 index 0000000..2c17c4d Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo@2x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo@3x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo@3x.png new file mode 100644 index 0000000..b969d88 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-logo@3x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error.png new file mode 100644 index 0000000..40d6a35 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error@2x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error@2x.png new file mode 100644 index 0000000..0bfc026 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error@2x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error@3x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error@3x.png new file mode 100644 index 0000000..8dc8747 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error@3x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo.png new file mode 100644 index 0000000..ad4c4b4 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo@2x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo@2x.png new file mode 100644 index 0000000..47ea38b Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo@2x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo@3x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo@3x.png new file mode 100644 index 0000000..db471c6 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo@3x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark.png new file mode 100644 index 0000000..2f2d32e Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark@2x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark@2x.png new file mode 100644 index 0000000..61692b4 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark@2x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark@3x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark@3x.png new file mode 100644 index 0000000..4dda258 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark@3x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light.png new file mode 100644 index 0000000..745d9b6 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light@2x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light@2x.png new file mode 100644 index 0000000..6033368 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light@2x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light@3x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light@3x.png new file mode 100644 index 0000000..0707a13 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light@3x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed.png new file mode 100644 index 0000000..b9c10cc Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed@2x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed@2x.png new file mode 100644 index 0000000..ad77218 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed@2x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed@3x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed@3x.png new file mode 100644 index 0000000..abb6c83 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed@3x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified.png new file mode 100644 index 0000000..74d94a2 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified@2x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified@2x.png new file mode 100644 index 0000000..f783dbe Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified@2x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified@3x.png b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified@3x.png new file mode 100644 index 0000000..31a34ee Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified@3x.png differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/uk.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/uk.lproj/Localizable.strings new file mode 100644 index 0000000..feba7b0 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/uk.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ur.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ur.lproj/Localizable.strings new file mode 100644 index 0000000..74eb578 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/ur.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/vi.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/vi.lproj/Localizable.strings new file mode 100644 index 0000000..3eb0a19 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/vi.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/zh-Hans.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/zh-Hans.lproj/Localizable.strings new file mode 100644 index 0000000..15b99c9 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/zh-Hans.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/zh-Hant.lproj/Localizable.strings b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/zh-Hant.lproj/Localizable.strings new file mode 100644 index 0000000..e01bc78 Binary files /dev/null and b/Frameworks/TwitterKit.framework/Versions/A/Resources/TwitterKitResources.bundle/zh-Hant.lproj/Localizable.strings differ diff --git a/Frameworks/TwitterKit.framework/Versions/Current b/Frameworks/TwitterKit.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/Frameworks/TwitterKit.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/Frameworks/VKSdk.framework/Headers b/Frameworks/VKSdk.framework/Headers new file mode 120000 index 0000000..a177d2a --- /dev/null +++ b/Frameworks/VKSdk.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/Frameworks/VKSdk.framework/VKSdk b/Frameworks/VKSdk.framework/VKSdk new file mode 120000 index 0000000..b07780f --- /dev/null +++ b/Frameworks/VKSdk.framework/VKSdk @@ -0,0 +1 @@ +Versions/Current/VKSdk \ No newline at end of file diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/NSData+MD5.h b/Frameworks/VKSdk.framework/Versions/A/Headers/NSData+MD5.h new file mode 100755 index 0000000..be24d42 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/NSData+MD5.h @@ -0,0 +1,30 @@ +// +// NSData+MD5.h +// +// Copyright (c) 2014 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "NSData+MD5.h" +#ifndef DOXYGEN_SHOULD_SKIP_THIS +@interface NSData (MD5) + +- (NSString *)MD5; + +@end +#endif diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/NSError+VKError.h b/Frameworks/VKSdk.framework/Versions/A/Headers/NSError+VKError.h new file mode 100755 index 0000000..b2b2c34 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/NSError+VKError.h @@ -0,0 +1,51 @@ +// +// NSError+VKError.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import "VKError.h" + +extern NSString *const VKSdkErrorDomain; +extern NSString *const VkErrorDescriptionKey; + +/** +* Category with implementation of VK error +*/ +@interface NSError (VKError) + +/// Returns vk error associated with that NSError +@property(nonatomic, readonly) VKError *vkError; + +/** +Create new NSError with VKError +@param vkError Source error +@return New error with VKSdkErrorDomain domain +*/ ++ (NSError *)errorWithVkError:(VKError *)vkError; + +/** +Copies user info from this NSError into new error, with adding VKError +@param vkError Source error +@return New error with this error domain, code and user info +*/ +- (NSError *)copyWithVkError:(VKError *)vkError; + +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/NSString+MD5.h b/Frameworks/VKSdk.framework/Versions/A/Headers/NSString+MD5.h new file mode 100755 index 0000000..384e5e6 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/NSString+MD5.h @@ -0,0 +1,30 @@ +// +// NSString+MD5.m +// +// Copyright (c) 2014 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "NSString+MD5.h" +#ifndef DOXYGEN_SHOULD_SKIP_THIS +@interface NSString (MD5) + +- (NSString *)MD5; + +@end +#endif diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/OrderedDictionary.h b/Frameworks/VKSdk.framework/Versions/A/Headers/OrderedDictionary.h new file mode 100755 index 0000000..0d5b183 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/OrderedDictionary.h @@ -0,0 +1,36 @@ +// +// OrderedDictionary.h +// OrderedDictionary +// +// Created by Matt Gallagher on 19/12/08. +// Copyright 2008 Matt Gallagher. All rights reserved. +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. Permission is granted to anyone to +// use this software for any purpose, including commercial applications, and to +// alter it and redistribute it freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source +// distribution. +// + +#import + +@interface OrderedDictionary : NSMutableDictionary +{ + NSMutableDictionary *dictionary; + NSMutableArray *array; +} + +- (void)insertObject:(id)anObject forKey:(id)aKey atIndex:(NSUInteger)anIndex; +- (id)keyAtIndex:(NSUInteger)anIndex; +- (NSEnumerator *)reverseKeyEnumerator; + +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKAccessToken.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKAccessToken.h new file mode 100755 index 0000000..f893e40 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKAccessToken.h @@ -0,0 +1,104 @@ +// +// VKAccessToken.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------- +// +// Modified by Ruslan Kavetsky + +#import +#import "VKObject.h" + +/** +Presents VK API access token that used for loading API methods and other stuff. +*/ +@interface VKAccessToken : VKObject + +/// String token for use in request parameters +@property(nonatomic, readonly) NSString *accessToken; + +/// Time when token expires +@property(nonatomic, strong) NSString *expiresIn; + +/// Current user id for this token +@property(nonatomic, strong) NSString *userId; + +/// User secret to sign requests (if nohttps used) +@property(nonatomic, strong) NSString *secret; + +/// If user sets "Always use HTTPS" setting in his profile, it will be true +@property(nonatomic, assign) BOOL httpsRequired; + +/// Indicates time of token creation +@property(nonatomic, assign) NSTimeInterval created; + +/// Return YES if token has expired +@property(nonatomic, assign) BOOL isExpired; + +// Permisiions assosiated with token +@property(nonatomic, strong) NSArray *permissions; + +// User email (if passed) +@property(nonatomic, readwrite, copy) NSString *email; + +/** +Retrieve token from key-value query string +@param urlString string that contains URL-query part with token. E.g. access_token=ffffff&expires_in=0... +@return parsed token +*/ ++ (instancetype)tokenFromUrlString:(NSString *)urlString; + +/** +Create token with existing properties +@param accessToken token string +@param secret secret +@param userId user id +@return new token +*/ ++ (instancetype)tokenWithToken:(NSString *)accessToken secret:(NSString *)secret userId:(NSString *)userId; + +/** +Retrieve token from file. Token must be saved into file with saveTokenToFile method +@param filePath path to file with saved token +@return parsed token +*/ ++ (instancetype)tokenFromFile:(NSString *)filePath; + +/** +Retrieve token from user defaults. Token must be saved to defaults with saveTokenToDefaults method +@param defaultsKey path to file with saved token +@return parsed token +*/ ++ (instancetype)tokenFromDefaults:(NSString *)defaultsKey; + +/** +Save token into specified file +@param filePath path to file with saved token +*/ +- (void)saveTokenToFile:(NSString *)filePath; + +/** +Save token into user defaults by specified key +@param defaultsKey key for defaults +*/ +- (void)saveTokenToDefaults:(NSString *)defaultsKey; + +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKActivity.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKActivity.h new file mode 100755 index 0000000..6679457 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKActivity.h @@ -0,0 +1,32 @@ +// +// VKActivity.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +static NSString *const VKActivityTypePost = @"VKActivityTypePost"; + +/** +* Class for sharing in VK throught UIActivityController +*/ +@interface VKActivity : UIActivity + +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKApi.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApi.h new file mode 100755 index 0000000..37acf50 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApi.h @@ -0,0 +1,115 @@ +// +// VKApi.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import "VKRequest.h" +#import "VKApiUsers.h" +#import "VKApiFriends.h" +#import "VKApiPhotos.h" +#import "VKApiWall.h" +#import "VKApiConst.h" +#import "VKApiCaptcha.h" +#import "VKApiGroups.h" +#import "VKImageParameters.h" +#import "VKApiModels.h" + +/** +Provides access for API parts. +*/ +@interface VKApi : NSObject +/** +https://vk.com/dev/users +Returns object for preparing requests to users part of API +*/ ++ (VKApiUsers *)users; + +/** +https://vk.com/dev/wall +Returns object for preparing requests to wall part of API +*/ ++ (VKApiWall *)wall; + +/** +https://vk.com/dev/photos +Returns object for preparing requests to photos part of API +*/ ++ (VKApiPhotos *)photos; + +/** +https://vk.com/dev/friends +Returns object for preparing requests to friends part of API +*/ ++ (VKApiFriends *)friends; + +/** +https://vk.com/dev/friends +Returns object for preparing requests to groups part of API +*/ ++ (VKApiGroups *)groups; + +/** +Create new request with parameters. See documentation for methods here https://vk.com/dev/methods +@param method API-method name, e.g. audio.get +@param parameters method parameters +@param httpMethod HTTP method for execution, e.g. GET, POST +@return Complete request class for execute or configure method +*/ ++ (VKRequest *)requestWithMethod:(NSString *)method + andParameters:(NSDictionary *)parameters + andHttpMethod:(NSString *)httpMethod; + +/** +Uploads photo for wall post +@param image image used for saving to post +@param parameters parameters for image to be uploaded +@param userId ID of user on which wall image should be posted (or nil) +@param groupId ID of group (without minus sign) on which wall image should be posted (or nil) +*/ ++ (VKRequest *)uploadWallPhotoRequest:(UIImage *)image + parameters:(VKImageParameters *)parameters + userId:(NSInteger)userId + groupId:(NSInteger)groupId; + +/** +Uploads photo in user or group album +@param image image used for saving to post +@param parameters parameters for image to be uploaded +@param albumId target album ID. Required +@param groupId target group ID (positive). May be nil +*/ ++ (VKRequest *)uploadAlbumPhotoRequest:(UIImage *)image + parameters:(VKImageParameters *)parameters + albumId:(NSInteger)albumId + groupId:(NSInteger)groupId; + +/** +Uploads photo for messaging +@param image image used for saving to post +@param parameters parameters for image to be uploaded +@param albumId target album ID. Required +@param groupId target group ID (positive). May be nil +*/ ++ (VKRequest *)uploadMessagePhotoRequest:(UIImage *)image + parameters:(VKImageParameters *)parameters; + + +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiBase.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiBase.h new file mode 100755 index 0000000..94bc354 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiBase.h @@ -0,0 +1,73 @@ +// +// VKApiBase.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import "VKRequest.h" +#import "VKApiConst.h" +#import "VKObject.h" + +/** +* Basic class for all API-requests builders (parts) +*/ +@interface VKApiBase : VKObject { +@private + NSString *_methodGroup; ///< Selected methods group +} +/** +Return group name for current methods builder +@return name of methods group, e.g. users, wall, etc. +*/ +- (NSString *)getMethodGroup; + +/** +Builds request and return it for configure and loading +@param methodName Selected method name +@param methodParameters Selected method parameters +@return request to configure and load +*/ +- (VKRequest *)prepareRequestWithMethodName:(NSString *)methodName + andParameters:(NSDictionary *)methodParameters; + +/** +Builds request and return it for configure and loading +@param methodName Selected method name +@param methodParameters Selected method parameters +@param httpMethod HTTP method for loading request. E.g. GET or POST +@return request to configure and load +*/ +- (VKRequest *)prepareRequestWithMethodName:(NSString *)methodName + andParameters:(NSDictionary *)methodParameters + andHttpMethod:(NSString *)httpMethod; + +/** +Builds request and return it for configure and loading +@param methodName Selected method name +@param methodParameters Selected method parameters +@param httpMethod HTTP method for loading request. E.g. GET or POST +@param modelClass Class of model, based on VKApiObject, for model parsing +@return request to configure and load +*/ +- (VKRequest *)prepareRequestWithMethodName:(NSString *)methodName + andParameters:(NSDictionary *)methodParameters + andHttpMethod:(NSString *)httpMethod + andClassOfModel:(Class)modelClass; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiCaptcha.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiCaptcha.h new file mode 100755 index 0000000..1a1b241 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiCaptcha.h @@ -0,0 +1,34 @@ +// +// VKApiCaptcha.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKApiBase.h" + +/** +Methods for captcha work. Currently, it is 1 method for forcing captcha response +*/ +@interface VKApiCaptcha : VKApiBase +/** +Returns error for captcha debugging +@return Request to load +*/ +- (VKRequest *)force; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiConst.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiConst.h new file mode 100755 index 0000000..53ad867 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiConst.h @@ -0,0 +1,115 @@ +// +// VKApiConst.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +typedef NSString *VKDisplayType; +static VKDisplayType const VK_DISPLAY_IOS = @"ios"; +static VKDisplayType const VK_DISPLAY_MOBILE = @"mobile"; +//Commons +extern NSString *const VK_ORIGINAL_CLIENT_BUNDLE; +extern NSString *const VK_ORIGINAL_HD_CLIENT_BUNDLE; +extern NSString *const VK_DEBUG_CLIENT_BUNDLE; +extern NSString *const VK_API_USER_ID; +extern NSString *const VK_API_USER_IDS; +extern NSString *const VK_API_FIELDS; +extern NSString *const VK_API_SORT; +extern NSString *const VK_API_OFFSET; +extern NSString *const VK_API_COUNT; +extern NSString *const VK_API_OWNER_ID; + +//auth +extern NSString *const VK_API_LANG; +extern NSString *const VK_API_ACCESS_TOKEN; +extern NSString *const VK_API_SIG; + +//get users +extern NSString *const VK_API_NAME_CASE; +extern NSString *const VK_API_ORDER; + +//Get subscriptions +extern NSString *const VK_API_EXTENDED; + +//Search +extern NSString *const VK_API_Q; +extern NSString *const VK_API_CITY; +extern NSString *const VK_API_COUNTRY; +extern NSString *const VK_API_HOMETOWN; +extern NSString *const VK_API_UNIVERSITY_COUNTRY; +extern NSString *const VK_API_UNIVERSITY; +extern NSString *const VK_API_UNIVERSITY_YEAR; +extern NSString *const VK_API_SEX; +extern NSString *const VK_API_STATUS; +extern NSString *const VK_API_AGE_FROM; +extern NSString *const VK_API_AGE_TO; +extern NSString *const VK_API_BIRTH_DAY; +extern NSString *const VK_API_BIRTH_MONTH; +extern NSString *const VK_API_BIRTH_YEAR; +extern NSString *const VK_API_ONLINE; +extern NSString *const VK_API_HAS_PHOTO; +extern NSString *const VK_API_SCHOOL_COUNTRY; +extern NSString *const VK_API_SCHOOL_CITY; +extern NSString *const VK_API_SCHOOL; +extern NSString *const VK_API_SCHOOL_YEAR; +extern NSString *const VK_API_RELIGION; +extern NSString *const VK_API_INTERESTS; +extern NSString *const VK_API_COMPANY; +extern NSString *const VK_API_POSITION; +extern NSString *const VK_API_GROUP_ID; +extern NSString *const VK_API_GROUP_IDS; + +extern NSString *const VK_API_FRIENDS_ONLY; +extern NSString *const VK_API_FROM_GROUP; +extern NSString *const VK_API_MESSAGE; +extern NSString *const VK_API_ATTACHMENT; +extern NSString *const VK_API_ATTACHMENTS; +extern NSString *const VK_API_SERVICES; +extern NSString *const VK_API_SIGNED; +extern NSString *const VK_API_PUBLISH_DATE; +extern NSString *const VK_API_LAT; +extern NSString *const VK_API_LONG; +extern NSString *const VK_API_PLACE_ID; +extern NSString *const VK_API_POST_ID; + +//Errors +extern NSString *const VK_API_ERROR_CODE; +extern NSString *const VK_API_ERROR_MSG; +extern NSString *const VK_API_REQUEST_PARAMS; + +//Captcha +extern NSString *const VK_API_CAPTCHA_IMG; +extern NSString *const VK_API_CAPTCHA_SID; +extern NSString *const VK_API_CAPTCHA_KEY; +extern NSString *const VK_API_REDIRECT_URI; + + +//Photos +extern NSString *const VK_API_PHOTO; +extern NSString *const VK_API_ALBUM_ID; + +//Events +extern NSString *const VKCaptchaAnsweredEvent; + +//Enums +typedef NS_ENUM(NSInteger, VKProgressType) { + VKProgressTypeUpload, + VKProgressTypeDownload +}; + diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiFriends.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiFriends.h new file mode 100755 index 0000000..ff74dcf --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiFriends.h @@ -0,0 +1,32 @@ +// +// VKApiFriends.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKApiBase.h" + +/** +Builds requests for API.users part +*/ +@interface VKApiFriends : VKApiBase +- (VKRequest *)get; + +- (VKRequest *)get:(NSDictionary *)params; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiGroups.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiGroups.h new file mode 100755 index 0000000..76dca97 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiGroups.h @@ -0,0 +1,18 @@ +// +// VKApiGroups.h +// sdk +// +// Created by Roman Truba on 16.07.14. +// Copyright (c) 2014 VK. All rights reserved. +// + +#import "VKApiBase.h" + +@interface VKApiGroups : VKApiBase +/** +https://vk.com/dev/groups.get +@param params use parameters from description with VK_API prefix, e.g. VK_API_GROUP_ID, VK_API_FIELDS +@return Request for load +*/ +- (VKRequest *)getById:(NSDictionary *)params; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiModels.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiModels.h new file mode 100755 index 0000000..4118e53 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiModels.h @@ -0,0 +1,33 @@ +// +// VKApiModels.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or suabstantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKApiObjectArray.h" +#import "VKAudio.h" +#import "VKPhoto.h" +#import "VKLikes.h" +#import "VKUser.h" +#import "VKRelative.h" +#import "VKCounters.h" +#import "VKLikes.h" +#import "VKSchool.h" +#import "VKUniversity.h" +#import "VKGroup.h" \ No newline at end of file diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiObject.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiObject.h new file mode 100755 index 0000000..02aa4de --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiObject.h @@ -0,0 +1,65 @@ +// +// VKApiObject.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import "VKObject.h" + +/** +Helps in objects parsing +*/ +@interface VKPropertyHelper : VKObject +@property(nonatomic, readonly) NSString *propertyName; +@property(nonatomic, readonly) NSString *propertyClassName; +@property(nonatomic, readonly) Class propertyClass; +@property(nonatomic, readonly) BOOL isPrimitive; +@property(nonatomic, readonly) BOOL isModelsArray; +@property(nonatomic, readonly) BOOL isModel; + +- (instancetype)initWith:(objc_property_t)prop; +@end + +@protocol VKApiObject ++ (instancetype)createWithDictionary:(NSDictionary *)dict; + ++ (instancetype)createWithArray:(NSArray *)array; +@end + +/** +Basic class for API objects +*/ +@interface VKApiObject : VKObject +/// If it possible, contains object fields from JSON as it is +@property(nonatomic, strong) NSDictionary *fields; + +/** +Initialize object with API json dictionary. This method tries to set all known properties of current class from dictionare +@param dict API json dictionary +@return Initialized object +*/ +- (instancetype)initWithDictionary:(NSDictionary *)dict; + +/** +Serialize current object into dictionary +@return Key-value dictionary, contains current object +*/ +- (NSDictionary *)serialize; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiObjectArray.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiObjectArray.h new file mode 100755 index 0000000..c24034a --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiObjectArray.h @@ -0,0 +1,80 @@ +// +// VKApiObjectArray.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or suabstantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKApiObject.h" + +/** +Base class for VK API arrays +*/ +@interface VKApiObjectArray : VKApiObject +/// Count of items in array +@property(nonatomic, readonly) NSUInteger count; +/// Parsed array items +@property(nonatomic, strong) NSMutableArray *items; + +/** +Initialize object with API json dictionary. This method tries to set all known properties of current class from dictionary +@param dict API json dictionary +@param objectClass class of items inside of array +@return Initialized object +*/ +- (instancetype)initWithDictionary:(NSDictionary *)dict objectClass:(Class)objectClass; + +/** +Initialize object with API json array. This method tries to set all known properties of current class from array +@param array API json array +@param objectClass class of items inside of array +@return Initialized object +*/ +- (instancetype)initWithArray:(NSArray *)array objectClass:(Class)objectClass; + +/** +Initialize object with any array. items property is sets as passed array, count is a count of items in passed array +@param array API json array +@return Initialized object +*/ +- (instancetype)initWithArray:(NSArray *)array; + +/// Array funtions + +- (id)objectAtIndex:(NSInteger)idx; + +- (id)objectAtIndexedSubscript:(NSUInteger)idx NS_AVAILABLE(10_8, 6_0); + +- (NSEnumerator *)objectEnumerator; + +- (NSEnumerator *)reverseObjectEnumerator; + +- (void)addObject:(id)object; + +- (void)removeObject:(id)object; + +- (void)insertObject:(id)object atIndex:(NSUInteger)index; + +- (id)firstObject; + +- (id)lastObject; + +- (void)serializeTo:(NSMutableDictionary *)dict withName:(NSString *)name; + +- (Class)objectClass; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiPhotos.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiPhotos.h new file mode 100755 index 0000000..bb1af13 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiPhotos.h @@ -0,0 +1,72 @@ +// +// VKApiPhotos.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKApiBase.h" + +/** +Builds requests for API.photos part +*/ +@interface VKApiPhotos : VKApiBase +/** +https://vk.com/dev/photos.getUploadServer +@param albumId album identifier (positive integer) +@return Request for load +*/ +- (VKRequest *)getUploadServer:(NSInteger)albumId; + +/** +https://vk.com/dev/photos.getUploadServer +@param albumId album identifier (positive integer) +@param groupId group identifier (positive integer) +@return Request for load +*/ +- (VKRequest *)getUploadServer:(NSInteger)albumId andGroupId:(NSInteger)groupId; + +/** +https://vk.com/dev/photos.getWallUploadServer +@return Request for load +*/ +- (VKRequest *)getWallUploadServer; + +/** +https://vk.com/dev/photos.getWallUploadServer +@param groupId group identifier (positive integer) +@return Request for load +*/ +- (VKRequest *)getWallUploadServer:(NSInteger)groupId; + + +/** +https://vk.com/dev/photos.save +@param params params received after photo upload, with user id or group id +@return Request for load +*/ +- (VKRequest *)save:(NSDictionary *)params; + +/** +https://vk.com/dev/photos.saveWallPhoto +@param params params received after photo upload, with user id or group id +@return Request for load +*/ +- (VKRequest *)saveWallPhoto:(NSDictionary *)params; + +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiUsers.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiUsers.h new file mode 100755 index 0000000..2b4fa60 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiUsers.h @@ -0,0 +1,87 @@ +// +// VKApiUsers.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKApiBase.h" + +/** +Builds requests for API.users part +*/ +@interface VKApiUsers : VKApiBase +/** +Returns basic information about current user +@return Request for load +*/ +- (VKRequest *)get; + +/** +https://vk.com/dev/users.get +@param params use parameters from description with VK_API prefix, e.g. VK_API_USER_IDS, VK_API_FIELDS, VK_API_NAME_CASE +@return Request for load +*/ +- (VKRequest *)get:(NSDictionary *)params; + +/** +https://vk.com/dev/users.search +@param params use parameters from description with VK_API prefix, e.g. VK_API_Q, VK_API_CITY, VK_API_COUNTRY, etc. +@return Request for load +*/ +- (VKRequest *)search:(NSDictionary *)params; + +/** +https://vk.com/dev/users.isAppUser +@return Request for load +*/ +- (VKRequest *)isAppUser; + +/** +https://vk.com/dev/users.isAppUser +@param userID ID of user to check +@return Request for load +*/ +- (VKRequest *)isAppUser:(NSInteger)userID; + +/** +https://vk.com/dev/users.getSubscriptions +@return Request for load +*/ +- (VKRequest *)getSubscriptions; + +/** +https://vk.com/dev/users.getSubscriptions +@param params use parameters from description with VK_API prefix, e.g. VK_API_USER_ID, VK_API_EXTENDED, etc. +@return Request for load +*/ +- (VKRequest *)getSubscriptions:(NSDictionary *)params; + +/** +https://vk.com/dev/users.getFollowers +@return Request for load +*/ +- (VKRequest *)getFollowers; + +/** +https://vk.com/dev/users.getFollowers +@param params use parameters from description with VK_API prefix, e.g. VK_API_USER_ID, VK_API_OFFSET, etc. +@return Request for load +*/ +- (VKRequest *)getFollowers:(NSDictionary *)params; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiWall.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiWall.h new file mode 100755 index 0000000..621a815 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKApiWall.h @@ -0,0 +1,35 @@ +// +// VKApiWall.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKApiBase.h" + +/** +Builds requests for API.wall part +*/ +@interface VKApiWall : VKApiBase +/** +https://vk.com/dev/wall.post +@param params Use parameters from description with VK_API prefix +@return Request for execution +*/ +- (VKRequest *)post:(NSDictionary *)params; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKAudio.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKAudio.h new file mode 100755 index 0000000..484e8a6 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKAudio.h @@ -0,0 +1,46 @@ +// +// VKAudio.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or suabstantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKApiObjectArray.h" + +@class VKUser; + +@interface VKAudio : VKApiObject + +@property(nonatomic, strong) NSNumber *id; +@property(nonatomic, strong) NSNumber *owner_id; +@property(nonatomic, strong) NSString *artist; +@property(nonatomic, strong) NSString *title; +@property(nonatomic, strong) NSNumber *duration; +@property(nonatomic, strong) NSString *url; +@property(nonatomic, strong) NSNumber *lyrics_id; +@property(nonatomic, strong) NSNumber *album_id; +@property(nonatomic, strong) NSNumber *genre_id; + +@property(nonatomic, assign) BOOL fromCache; +@property(nonatomic, assign) BOOL ignoreCache; + +@end + +@interface VKAudios : VKApiObjectArray +@property(nonatomic, strong) VKUser *user; +@end \ No newline at end of file diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKAuthorizeController.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKAuthorizeController.h new file mode 100755 index 0000000..c6af8a3 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKAuthorizeController.h @@ -0,0 +1,63 @@ +// +// VKAuthorizeController.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import "VKSdk.h" + +/** +Controller for authorization through webview (if VK app not available) +*/ +@interface VKAuthorizeController : UIViewController + +/** +Causes UIWebView in standard UINavigationController be presented in SDK delegate +@param appId Identifier of VK application +@param permissions Permissions that user specified for application +@param revoke If YES, user will see permissions list and allow to logout (if logged in already) +@param displayType Defines view of authorization screen +*/ ++ (void)presentForAuthorizeWithAppId:(NSString *)appId + andPermissions:(NSArray *)permissions + revokeAccess:(BOOL)revoke + displayType:(VKDisplayType)displayType; + +/** +Causes UIWebView in standard UINavigationController be presented for user validation +@param validationError validation error returned by API +*/ ++ (void)presentForValidation:(VKError *)validationError; + +/** +Builds url for oauth authorization +@param redirectUri uri for redirect +@param clientId id of your application +@param scope requested scope for application +@param revoke If YES, user will see permissions list and allow to logout (if logged in already) +@param display select display type +@return Complete url-string for grant authorization +*/ ++ (NSString *)buildAuthorizationUrl:(NSString *)redirectUri + clientId:(NSString *)clientId + scope:(NSString *)scope + revoke:(BOOL)revoke + display:(VKDisplayType)display; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKBatchRequest.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKBatchRequest.h new file mode 100755 index 0000000..bb856e8 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKBatchRequest.h @@ -0,0 +1,66 @@ +// +// VKBatchRequest.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKObject.h" +#import "VKRequest.h" + +/** +Used for execution bunch of methods at time, and receive results of that methods in array +*/ +@interface VKBatchRequest : VKObject { +@private + + NSMutableArray *_requests; + NSMutableArray *_responses; + BOOL _canceled; +} +/// Specify completion block for request +@property(nonatomic, copy) void (^completeBlock)(NSArray *responses); +/// Specity error (HTTP or API) block for request. +@property(nonatomic, copy) void (^errorBlock)(NSError *error); + +/** +Initializes batch processing with requests +@param firstRequest ,... A comma-separated list of requests should be loaded, ending with nil. +@return Prepared request +*/ +- (instancetype)initWithRequests:(VKRequest *)firstRequest, ...NS_REQUIRES_NIL_TERMINATION; + +/** +Initializes batch processing with requests array +@param requests Array of requests should be loaded. +@return Prepared request +*/ +- (instancetype)initWithRequestsArray:(NSArray *)requests; + +/** +Executes batch request +@param completeBlock will receive result of passed requests +@param errorBlock called if any request did fail +*/ +- (void)executeWithResultBlock:(void (^)(NSArray *responses))completeBlock errorBlock:(void (^)(NSError *))errorBlock; + +/** +Cancel current batch operation +*/ +- (void)cancel; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKBundle.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKBundle.h new file mode 100755 index 0000000..5de3bb6 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKBundle.h @@ -0,0 +1,49 @@ +// +// VKBundle.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKObject.h" + +#define VKLocalizedString(s) [VKBundle localizedString:s] +#define VKImageNamed(s) [VKBundle vkLibraryImageNamed:s] + +/** +Class for providing resources from VK SDK Bundle +*/ +@interface VKBundle : VKObject +/** +Returns bundle for VK SDK (by default VKSdkResources) +@return Bundle object or nil +*/ ++ (NSBundle *)vkLibraryResourcesBundle; + +/** +Searches for image in main application bundle, then VK SDK bundle +@param name Name for image to find +@return Founded image object or nil, if file not found +*/ ++ (UIImage *)vkLibraryImageNamed:(NSString *)name; + +/** +* Returns localized string from VK bundle +*/ ++ (NSString *)localizedString:(NSString *)string; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKCaptchaView.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKCaptchaView.h new file mode 100755 index 0000000..bf32325 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKCaptchaView.h @@ -0,0 +1,41 @@ +// +// VKCaptchaView.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import "VKError.h" + +extern CGFloat kCaptchaImageWidth; +extern CGFloat kCaptchaImageHeight; +extern CGFloat kCaptchaViewHeight; + +/** +View for displaying captcha. Don't use it dirrectly. Use VKCaptchaViewController +*/ +@interface VKCaptchaView : UIView +/** +Initializes view with captcha error +@param frame bounds of window where view will be displayed +@param captchaError error for request that causes captcha-check +*/ +- (id)initWithFrame:(CGRect)frame andError:(VKError *)captchaError; + +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKCaptchaViewController.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKCaptchaViewController.h new file mode 100755 index 0000000..ec9d0f0 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKCaptchaViewController.h @@ -0,0 +1,45 @@ +// +// VKCaptchaViewController.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import "VKError.h" + +/** +Controller fo displaying captcha. +*/ +@interface VKCaptchaViewController : UIViewController { +@private + VKError *_captchaError; +} +/** +Initializes controller with captcha url +@param error error for request that causes captcha-check +@returns Prepared controller. Best way to use it - use presentIn: method +*/ ++ (instancetype)captchaControllerWithError:(VKError *)error; + +/** +Presents current view controller in another. Automatically hides when captcha was answered properly +@param viewController Parent view controller +*/ +- (void)presentIn:(UIViewController *)viewController; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKCounters.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKCounters.h new file mode 100755 index 0000000..591cfaa --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKCounters.h @@ -0,0 +1,47 @@ +// +// VKCounters.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or suabstantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKApiObject.h" + +@interface VKCounters : VKApiObject +@property(nonatomic, strong) NSNumber *friends; +@property(nonatomic, strong) NSNumber *messages; +@property(nonatomic, strong) NSNumber *photos; +@property(nonatomic, strong) NSNumber *videos; +@property(nonatomic, strong) NSNumber *notifications; +@property(nonatomic, strong) NSNumber *groups; +@property(nonatomic, strong) NSNumber *gifts; +@property(nonatomic, strong) NSNumber *events; + +@property(nonatomic, strong) NSNumber *albums; +@property(nonatomic, strong) NSNumber *audios; +@property(nonatomic, strong) NSNumber *online_friends; +@property(nonatomic, strong) NSNumber *mutual_friends; +@property(nonatomic, strong) NSNumber *user_videos; +@property(nonatomic, strong) NSNumber *followers; +@property(nonatomic, strong) NSNumber *user_photos; +@property(nonatomic, strong) NSNumber *subscriptions; +@property(nonatomic, strong) NSNumber *documents; +@property(nonatomic, strong) NSNumber *topics; +@property(nonatomic, strong) NSNumber *pages; + +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKError.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKError.h new file mode 100755 index 0000000..2821f75 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKError.h @@ -0,0 +1,83 @@ +// +// VKError.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import "VKObject.h" +#import "VKApiConst.h" + +static int const VK_API_ERROR = -101; +static int const VK_API_CANCELED = -102; +static int const VK_API_REQUEST_NOT_PREPARED = -103; + +@class VKRequest; + +/** +Class for presenting VK SDK and VK API errors +*/ +@interface VKError : VKObject +/// Contains system HTTP error +@property(nonatomic, strong) NSError *httpError; +/// Describes API error +@property(nonatomic, strong) VKError *apiError; +/// Request which caused error +@property(nonatomic, strong) VKRequest *request; + +/// May contains such errors:\n HTTP status code if HTTP error occured;\n VK_API_ERROR if API error occured;\n VK_API_CANCELED if request was canceled;\n VK_API_REQUEST_NOT_PREPARED if error occured while preparing request; +@property(nonatomic, assign) NSInteger errorCode; +/// API error message +@property(nonatomic, strong) NSString *errorMessage; +/// Reason for authorization fail +@property(nonatomic, strong) NSString *errorReason; +/// API parameters passed to request +@property(nonatomic, strong) NSDictionary *requestParams; +/// Captcha identifier for captcha-check +@property(nonatomic, strong) NSString *captchaSid; +/// Image for captcha-check +@property(nonatomic, strong) NSString *captchaImg; +/// Redirection address if validation check required +@property(nonatomic, strong) NSString *redirectUri; + + +/** +Generate new error with code +@param errorCode positive if it's an HTTP error. Negative if it's API or SDK error +*/ ++ (instancetype)errorWithCode:(NSInteger)errorCode; + +/** +Generate API error from JSON +@param JSON Json description of VK API error +*/ ++ (instancetype)errorWithJson:(id)JSON; + +/** +Generate API error from HTTP-query +@param queryParams key-value parameters +*/ ++ (instancetype)errorWithQuery:(NSDictionary *)queryParams; + +/** +Repeats failed captcha request with user entered answer to captcha +@param userEnteredCode answer for captcha +*/ +- (void)answerCaptcha:(NSString *)userEnteredCode; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKGroup.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKGroup.h new file mode 100755 index 0000000..7522d12 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKGroup.h @@ -0,0 +1,123 @@ +// +// VKGroup.h +// sdk +// +// Created by Roman Truba on 16.07.14. +// Copyright (c) 2014 VK. All rights reserved. +// + +#import "VKApiObjectArray.h" +#import "VKUser.h" + +@interface VKGeoPlace : VKApiObject + +@property(nonatomic, strong) NSNumber *id; +@property(nonatomic, strong) NSString *title; +@property(nonatomic, strong) NSNumber *latitude; +@property(nonatomic, strong) NSNumber *longitude; +@property(nonatomic, strong) NSNumber *created; +@property(nonatomic, strong) NSString *icon; +@property(nonatomic, strong) NSNumber *group_id; +@property(nonatomic, strong) NSNumber *group_photo; +@property(nonatomic, strong) NSNumber *checkins; +@property(nonatomic, strong) NSNumber *updated; +@property(nonatomic, strong) NSNumber *type; +@property(nonatomic, strong) NSNumber *country; +@property(nonatomic, strong) NSString *city; +@property(nonatomic, strong) NSString *address; +@property(nonatomic, strong) NSNumber *showmap; +@end + +@interface VKGroupContact : VKApiObject + +@property(nonatomic, strong) NSNumber *user_id; +@property(nonatomic, strong) NSString *desc; +@property(nonatomic, strong) NSString *email; + +@end + +@interface VKGroupContacts : VKApiObjectArray + +@end + +@interface VKGroupLink : VKApiObject + +@property(nonatomic, strong) NSString *url; +@property(nonatomic, strong) NSString *name; +@property(nonatomic, strong) NSString *desc; +@property(nonatomic, strong) NSString *photo_50; +@property(nonatomic, strong) NSString *photo_100; + +@end + +@interface VKGroupLinks : VKApiObjectArray + +@end + +@interface VKGroup : VKApiObject +@property(nonatomic, strong) NSNumber *id; +@property(nonatomic, strong) NSString *name; +@property(nonatomic, strong) NSString *screen_name; +/** +* является ли сообщество закрытым. Возможные значения: +* 0 — открытое; +* 1 — закрытое; +* 2 — частное. +*/ +@property(nonatomic, strong) NSNumber *is_closed; +/** +* тип сообщества: +* group — группа; +* page — публичная страница; +* event — мероприятие. +*/ +@property(nonatomic, strong) NSString *type; +@property(nonatomic, strong) NSNumber *is_admin; +/** +* полномочия текущего пользователя (если is_admin=1): +* 1 — модератор; +* 2 — редактор; +* 3 — администратор. +*/ +@property(nonatomic, strong) NSNumber *admin_level; +@property(nonatomic, strong) NSNumber *is_member; +@property(nonatomic, strong) VKCity *city; +@property(nonatomic, strong) VKCountry *country; +@property(nonatomic, strong) VKGeoPlace *place; +@property(nonatomic, strong) NSString *description; +@property(nonatomic, strong) NSString *wiki_page; +@property(nonatomic, strong) NSNumber *members_count; +@property(nonatomic, strong) VKCounters *counters; +@property(nonatomic, strong) NSNumber *start_date; +@property(nonatomic, strong) NSNumber *end_date; +@property(nonatomic, strong) NSNumber *finish_date; +@property(nonatomic, strong) NSNumber *can_post; +@property(nonatomic, strong) NSNumber *can_see_all_posts; +@property(nonatomic, strong) NSNumber *can_create_topic; +@property(nonatomic, strong) NSNumber *can_upload_doc; +@property(nonatomic, strong) NSString *activity; +@property(nonatomic, strong) NSString *status; +@property(nonatomic, strong) VKAudio *status_audio; +@property(nonatomic, strong) VKGroupContacts *contacts; +@property(nonatomic, strong) VKGroupLinks *links; +@property(nonatomic, strong) NSNumber *fixed_post; +@property(nonatomic, strong) NSNumber *verified; +@property(nonatomic, strong) NSString *site; +@property(nonatomic, strong) NSString *photo_50; +@property(nonatomic, strong) NSString *photo_100; +@property(nonatomic, strong) NSString *photo_200; +@property(nonatomic, strong) NSString *photo_max_orig; +@property(nonatomic, strong) NSNumber *is_request; +@property(nonatomic, strong) NSNumber *is_invite; +@property(nonatomic, strong) VKPhotoArray *photos; +@property(nonatomic, strong) NSNumber *photos_count; +@property(nonatomic, strong) NSNumber *invited_by; +@property(nonatomic, assign) NSInteger invite_state; +@property(nonatomic, strong) NSString *deactivated; +@property(nonatomic, strong) NSNumber *blacklisted; + +@end + +@interface VKGroups : VKApiObjectArray + +@end \ No newline at end of file diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKHTTPClient.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKHTTPClient.h new file mode 100755 index 0000000..afd95aa --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKHTTPClient.h @@ -0,0 +1,131 @@ +// +// VKHttpClient.h +// +// Based on AFNetworking library. +// https://github.com/AFNetworking/AFNetworking +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKObject.h" +@class VKHTTPOperation; + +/** + Class for NSURLRequests generation, made for VK API. + Based on AFNetworking library ( https://github.com/AFNetworking/AFNetworking ) + */ +@interface VKHTTPClient : VKObject + +///------------------------------- +/// @name Initialization +///------------------------------- + +/** + Creates and initializes an `VKHTTPClient` object with the specified base URL. + + @return The newly-initialized HTTP client + */ ++ (instancetype)getClient; + +/** + The operation queue which manages operations enqueued by the HTTP client. + */ +@property (readonly, nonatomic, strong) NSOperationQueue *operationQueue; + +///------------------------------- +/// @name Operations with default headers +///------------------------------- + +/** + Returns the value for the HTTP headers set in request objects created by the HTTP client. + + @param header The HTTP header to return the default value for + + @return The default value for the HTTP header, or `nil` if unspecified + */ +- (NSString *)defaultValueForHeader:(NSString *)header; + +/** + Sets the value for the HTTP headers set in request objects made by the HTTP client. If `nil`, removes the existing value for that header. + + @param header The HTTP header to set a default value for + @param value The value set as default for the specified header, or `nil + */ +- (void)setDefaultHeader:(NSString *)header + value:(NSString *)value; + +///------------------------------- +/// @name Preparing requests +///------------------------------- + +/** + Creates an `NSMutableURLRequest` object with the specified HTTP method and path. + + If the HTTP method is `GET`, `HEAD`, or `DELETE`, the parameters will be used to construct a url-encoded query string that is appended to the request's URL. Otherwise, the parameters will be encoded according to the value of the `parameterEncoding` property, and set as the request body. + + @param method The HTTP method for the request, such as `GET`, `POST`, `PUT`, or `DELETE`. This parameter must not be `nil`. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. If `nil`, no path will be appended to the base URL. + @param parameters The parameters to be either set as a query string for `GET` requests, or the request HTTP body. + @param secure Use HTTPS or not + + @return An `NSMutableURLRequest` object + */ +- (NSMutableURLRequest *)requestWithMethod:(NSString *)method + path:(NSString *)path + parameters:(NSDictionary *)parameters + secure:(BOOL)secure; + +/** + Creates an `NSMutableURLRequest` object with the specified HTTP method and path, and constructs a `multipart/form-data` HTTP body, using the specified parameters and multipart form data block. See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2 + + Multipart form requests are automatically streamed, reading files directly from disk along with in-memory data in a single HTTP body. The resulting `NSMutableURLRequest` object has an `HTTPBodyStream` property, so refrain from setting `HTTPBodyStream` or `HTTPBody` on this request object, as it will clear out the multipart form body stream. + + @param method The HTTP method for the request. This parameter must not be `GET` or `HEAD`, or `nil`. + @param path The path to be appended to the HTTP client's base URL and used as the request URL. + @param images Upload images objects to append + + @return An `NSMutableURLRequest` object + */ +- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method + path:(NSString *)path + images:(NSArray *)images; + +///------------------------------- +/// @name Enqueuing operations +///------------------------------- + +/** + Enqueues an `AFHTTPRequestOperation` to the HTTP client's operation queue. + + @param operation The HTTP request operation to be enqueued. + */ +- (void)enqueueOperation:(NSOperation *)operation; + +/** + Enqueues the specified request operations into a batch. When each request operation finishes, the specified progress block is executed, until all of the request operations have finished, at which point the completion block also executes. + + @param operations The request operations used to be batched and enqueued. + @param progressBlock A block object to be executed upon the completion of each request operation in the batch. This block has no return value and takes two arguments: the number of operations that have already finished execution, and the total number of operations. + @param completionBlock A block object to be executed upon the completion of all of the request operations in the batch. This block has no return value and takes a single argument: the batched request operations. + */ +- (void)enqueueBatchOfHTTPRequestOperations:(NSArray *)operations + progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock + completionBlock:(void (^)(NSArray *operations))completionBlock; + +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKHTTPOperation.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKHTTPOperation.h new file mode 100755 index 0000000..bcb6c5b --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKHTTPOperation.h @@ -0,0 +1,169 @@ +// +// VKHTTPOperation.h +// +// Based on AFNetworking library. +// https://github.com/AFNetworking/AFNetworking +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import "VKOperation.h" + +static NSString *const VKNetworkingOperationDidStart = @"VKNetworkingOperationDidStart"; +@class VKRequest; +/** + VK URL operation subclassing NSOperation. + Based on AFNetworking library ( https://github.com/AFNetworking/AFNetworking ) + */ +@interface VKHTTPOperation : VKOperation +@property (nonatomic, strong) VKRequest *loadingRequest; + +/** + Creates new operation with prepared request. + @param request Prepared VK request to API + @return Initialized operation + */ ++ (instancetype)operationWithRequest:(VKRequest *)request; + +///------------------------------- +/// @name Accessing Run Loop Modes +///------------------------------- + +/** + The run loop modes in which the operation will run on the network thread. By default, this is a single-member set containing `NSRunLoopCommonModes`. + */ +@property (nonatomic, strong) NSSet *runLoopModes; + +///----------------------------------------- +/// @name Getting URL Connection Information +///----------------------------------------- + +/** + The vk request initialized that operation + */ +@property (readonly, nonatomic, weak) VKRequest * vkRequest; +/** + The request used by the operation's connection. + */ +@property (readonly, nonatomic, strong) NSURLRequest *request; + +/** + The error, if any, that occurred in the lifecycle of the request. + */ +@property (readonly, nonatomic, strong) NSError *error; + +///---------------------------- +/// @name Getting Response Data +///---------------------------- + +/** + The data received during the request. + */ +@property (readonly, nonatomic, strong) NSData *responseData; + +/** + The string representation of the response data. + */ +@property (readonly, nonatomic, copy) NSString *responseString; + +/** + The json representation of the response data. + */ +@property (readonly, nonatomic, copy) id responseJson; + +/** + The last HTTP response received by the operation's connection. + */ +@property (readonly, nonatomic, strong) NSHTTPURLResponse *response; + +/** + The callback dispatch queue on success. If `NULL` (default), the main queue is used. + */ +@property (nonatomic, assign) dispatch_queue_t successCallbackQueue; + +/** + The callback dispatch queue on failure. If `NULL` (default), the main queue is used. + */ +@property (nonatomic, assign) dispatch_queue_t failureCallbackQueue; + +/** + Init this operation with URL request + @param urlRequest request to load + @return initialized operation + */ +- (instancetype)initWithURLRequest:(NSURLRequest *)urlRequest; +/** + Pauses the execution of the request operation. + + A paused operation returns `NO` for `-isReady`, `-isExecuting`, and `-isFinished`. As such, it will remain in an `NSOperationQueue` until it is either cancelled or resumed. Pausing a finished, cancelled, or paused operation has no effect. + */ +- (void)pause; + +/** + Whether the request operation is currently paused. + + @return `YES` if the operation is currently paused, otherwise `NO`. + */ +- (BOOL)isPaused; + +/** + Resumes the execution of the paused request operation. + + Pause/Resume behavior varies depending on the underlying implementation for the operation class. In its base implementation, resuming a paused requests restarts the original request. However, since HTTP defines a specification for how to request a specific content range, `AFHTTPRequestOperation` will resume downloading the request from where it left off, instead of restarting the original request. + */ +- (void)resume; + +///---------------------------------------------- +/// @name Configuring Backgrounding Task Behavior +///---------------------------------------------- + +/** + Specifies that the operation should continue execution after the app has entered the background, and the expiration handler for that background task. + + @param handler A handler to be called shortly before the application’s remaining background time reaches 0. The handler is wrapped in a block that cancels the operation, and cleans up and marks the end of execution, unlike the `handler` parameter in `UIApplication -beginBackgroundTaskWithExpirationHandler:`, which expects this to be done in the handler itself. The handler is called synchronously on the main thread, thus blocking the application’s suspension momentarily while the application is notified. + */ +- (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler; + +/** + Sets a callback to be called when an undetermined number of bytes have been uploaded to the server. + + @param block A block object to be called when an undetermined number of bytes have been uploaded to the server. This block has no return value and takes three arguments: the number of bytes written since the last time the upload progress block was called, the total bytes written, and the total bytes expected to be written during the request, as initially determined by the length of the HTTP body. This block may be called multiple times, and will execute on the main thread. + */ +- (void)setUploadProgressBlock:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block; + +/** + Sets a callback to be called when an undetermined number of bytes have been downloaded from the server. + + @param block A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes three arguments: the number of bytes read since the last time the download progress block was called, the total bytes read, and the total bytes expected to be read during the request, as initially determined by the expected content size of the `NSHTTPURLResponse` object. This block may be called multiple times, and will execute on the main thread. + */ +- (void)setDownloadProgressBlock:(void (^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block; + +/** + 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. + + This method should be overridden in subclasses in order to specify the response object passed into the success block. + + @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. + @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. + */ +- (void)setCompletionBlockWithSuccess:(void (^)(VKHTTPOperation *operation, id responseObject))success + failure:(void (^)(VKHTTPOperation *operation, NSError *error))failure; +@end + diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKImageParameters.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKImageParameters.h new file mode 100755 index 0000000..a37f8dc --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKImageParameters.h @@ -0,0 +1,71 @@ +// +// VKImageParameters.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKObject.h" + +/** +Describes image representation type +*/ +typedef enum VKImageType { + /// Sets jpeg representation of image + VKImageTypeJpg, + /// Sets png representation of image + VKImageTypePng +} VKImageType; + +/** +Parameters used for uploading image into VK servers +*/ +@interface VKImageParameters : VKObject + +/// Type of image compression. Can be VKImageTypeJpg or VKImageTypePng. +@property(nonatomic, assign) VKImageType imageType; +/// Quality used for jpg compression. From 0.0 to 1.0 +@property(nonatomic, assign) CGFloat jpegQuality; + +/** +Creates new parameters instance for png image. +@return New instance of parameters +*/ ++ (instancetype)pngImage; + +/** +Creates new parameters instance for jpeg image. +@param quality Used only for VKImageTypeJpg representation. From 0.0 to 1.0 +@return New instance with passed parameters +*/ ++ (instancetype)jpegImageWithQuality:(float)quality; + +/** +Return file extension for selected type +@return png for VKImageTypePng image type, jpg for VKImageTypeJpg image type +*/ +- (NSString *)fileExtension; + +/** +Return mime type +@return parameters mime type +*/ +- (NSString *)mimeType; +@end + + diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKLikes.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKLikes.h new file mode 100755 index 0000000..704fc80 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKLikes.h @@ -0,0 +1,36 @@ +// +// VKLikes.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import "VKApiObject.h" + +/** +Likes type of VK API +*/ +@interface VKLikes : VKApiObject +#ifndef DOXYGEN_SHOULD_SKIP_THIS +@property(nonatomic, strong) NSNumber *count; +@property(nonatomic, strong) NSNumber *user_likes; +@property(nonatomic, strong) NSNumber *can_like; +@property(nonatomic, strong) NSNumber *can_publish; +#endif +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKObject.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKObject.h new file mode 100755 index 0000000..ec2fe82 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKObject.h @@ -0,0 +1,28 @@ +// +// VKObject.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import + +@interface VKObject : NSObject + +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKOperation.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKOperation.h new file mode 100755 index 0000000..9dfacdc --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKOperation.h @@ -0,0 +1,42 @@ +// +// VKOperation.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +typedef enum { + VKOperationPausedState = -1, + VKOperationReadyState = 1, + VKOperationExecutingState = 2, + VKOperationFinishedState = 3, +} VKOperationState; + +/** +Basic class for operations +*/ +@interface VKOperation : NSOperation +/// This operation state. Value from VKOperationState enum +@property(readwrite, nonatomic, assign) VKOperationState state; +/// Operation working lock +@property(readwrite, nonatomic, strong) NSRecursiveLock *lock; +/// Sets dispatch queue for returning result +@property(nonatomic, assign) dispatch_queue_t responseQueue; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKPermissions.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKPermissions.h new file mode 100755 index 0000000..cae8a42 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKPermissions.h @@ -0,0 +1,44 @@ +// +// VKPermissions.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +static NSString *const VK_PER_NOTIFY = @"notify"; +static NSString *const VK_PER_FRIENDS = @"friends"; +static NSString *const VK_PER_PHOTOS = @"photos"; +static NSString *const VK_PER_AUDIO = @"audio"; +static NSString *const VK_PER_VIDEO = @"video"; +static NSString *const VK_PER_DOCS = @"docs"; +static NSString *const VK_PER_NOTES = @"notes"; +static NSString *const VK_PER_PAGES = @"pages"; +static NSString *const VK_PER_STATUS = @"status"; +static NSString *const VK_PER_WALL = @"wall"; +static NSString *const VK_PER_GROUPS = @"groups"; +static NSString *const VK_PER_MESSAGES = @"messages"; +static NSString *const VK_PER_NOTIFICATIONS = @"notifications"; +static NSString *const VK_PER_STATS = @"stats"; +static NSString *const VK_PER_ADS = @"ads"; +static NSString *const VK_PER_OFFLINE = @"offline"; +static NSString *const VK_PER_NOHTTPS = @"nohttps"; +static NSString *const VK_PER_EMAIL = @"email"; + +NSArray *parseVkPermissionsFromInteger(int permissionsValue); diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKPhoto.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKPhoto.h new file mode 100755 index 0000000..73957ff --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKPhoto.h @@ -0,0 +1,55 @@ +// +// VKPhoto.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKApiObject.h" +#import "VKApiObjectArray.h" +#import "VKPhotoSize.h" + +@class VKLikes; + +/** +Photo type of VK API. See descriptions here https://vk.com/dev/photo +*/ +@interface VKPhoto : VKApiObject +@property(nonatomic, strong) NSNumber *id; +@property(nonatomic, strong) NSNumber *album_id; +@property(nonatomic, strong) NSNumber *owner_id; +@property(nonatomic, strong) NSString *photo_75; +@property(nonatomic, strong) NSString *photo_130; +@property(nonatomic, strong) NSString *photo_604; +@property(nonatomic, strong) NSString *photo_807; +@property(nonatomic, strong) NSString *photo_1280; +@property(nonatomic, strong) NSString *photo_2560; +@property(nonatomic, strong) NSNumber *width; +@property(nonatomic, strong) NSNumber *height; +@property(nonatomic, strong) NSString *text; +@property(nonatomic, strong) NSNumber *date; +@property(nonatomic, strong) VKPhotoSizes *sizes; +@property(nonatomic, readonly) NSString *attachmentString; +@end + + +/** +Array of API photos objects +*/ +@interface VKPhotoArray : VKApiObjectArray +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKPhotoSize.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKPhotoSize.h new file mode 100755 index 0000000..e8b4e0a --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKPhotoSize.h @@ -0,0 +1,20 @@ +// +// VKPhotoSize.h +// sdk +// +// Created by Roman Truba on 11.08.14. +// Copyright (c) 2014 VK. All rights reserved. +// + +#import "VKApiObjectArray.h" + +@interface VKPhotoSize : VKApiObject +@property(nonatomic, readwrite, copy) NSString *src; +@property(nonatomic, readwrite, copy) NSNumber *width; +@property(nonatomic, readwrite, copy) NSNumber *height; +@property(nonatomic, readwrite, copy) NSString *type; +@end + +@interface VKPhotoSizes : VKApiObjectArray +- (VKPhotoSize *)photoSizeWithType:(NSString *)type; +@end \ No newline at end of file diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKRelative.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKRelative.h new file mode 100755 index 0000000..00d4f4b --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKRelative.h @@ -0,0 +1,34 @@ +// +// VKRelative.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or suabstantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKApiObjectArray.h" + +@interface VKRelative : VKApiObject + +@property(nonatomic, strong) NSNumber *id; +@property(nonatomic, strong) NSString *type; + +@end + +@interface VKRelativities : VKApiObjectArray + +@end \ No newline at end of file diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKRequest.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKRequest.h new file mode 100755 index 0000000..9918231 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKRequest.h @@ -0,0 +1,176 @@ +// +// VKRequest.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import "VKResponse.h" +#import "VKApiConst.h" +#import "VKObject.h" + + +/** +Creates and debug timings for VKRequest +*/ +@interface VKRequestTiming : VKObject +/// Date of request start +@property(nonatomic, strong) NSDate *startTime; +/// Date of request finished (after all operations) +@property(nonatomic, strong) NSDate *finishTime; +/// Interval of networking load time +@property(nonatomic, assign) NSTimeInterval loadTime; +/// Interval of model parsing time +@property(nonatomic, assign) NSTimeInterval parseTime; +/// Total time, as difference (finishTime - startTime) +@property(nonatomic, readonly) NSTimeInterval totalTime; +@end + +/** +Class for execution API-requests +*/ +@interface VKRequest : VKObject +/// Specify language for API request +@property(nonatomic, copy) NSString *preferredLang; +/// Specify progress for uploading or downloading. Useless for text requests (because gzip encoding bytesTotal will always return -1) + +@property(nonatomic, copy) void (^progressBlock)(VKProgressType progressType, long long bytesLoaded, long long bytesTotal); +/// Specify completion block for request +@property(nonatomic, copy) void (^completeBlock)(VKResponse *response); +/// Specity error (HTTP or API) block for request. +@property(nonatomic, copy) void (^errorBlock)(NSError *error); +/// Specify attempts for request loading if caused HTTP-error. 0 for infinite +@property(nonatomic, assign) int attempts; +/// Use HTTPS requests (by default is YES). If http-request is impossible (user denied no https access), SDK will load https version +@property(nonatomic, assign) BOOL secure; +/// Sets current system language as default for API data +@property(nonatomic, assign) BOOL useSystemLanguage; +/// Set to NO if you don't need automatic model parsing +@property(nonatomic, assign) BOOL parseModel; +/// Set to YES if you need info about request timing +@property(nonatomic, assign) BOOL debugTiming; +/// Timeout for this request +@property(nonatomic, assign) NSInteger requestTimeout; +/// Sets dispatch queue for returning result +@property(nonatomic, assign) dispatch_queue_t responseQueue; +/// Set to YES if you need to freeze current thread for response +@property(nonatomic, assign) BOOL waitUntilDone; +/// Returns method for current request, e.g. users.get +@property(nonatomic, readonly) NSString *methodName; +/// Returns HTTP-method for current request +@property(nonatomic, readonly) NSString *httpMethod; +/// Returns list of method parameters (without common parameters) +@property(nonatomic, readonly) NSDictionary *methodParameters; +/// Returns http operation that can be enqueued +@property(nonatomic, readonly) NSOperation *executionOperation; +/// Returns info about request timings +@property(nonatomic, readonly) VKRequestTiming *requestTiming; +/// Return YES if current request was started +@property(nonatomic, readonly) BOOL isExecuting; + + +///------------------------------- +/// @name Preparing requests +///------------------------------- +/** +Creates new request with parameters. See documentation for methods here https://vk.com/dev/methods +@param method API-method name, e.g. audio.get +@param parameters method parameters +@param httpMethod HTTP method for execution, e.g. GET, POST +@return Complete request object for execute or configure method +*/ ++ (instancetype)requestWithMethod:(NSString *)method + andParameters:(NSDictionary *)parameters + andHttpMethod:(NSString *)httpMethod; + +/** +Creates new request with parameters. See documentation for methods here https://vk.com/dev/methods +@param method API-method name, e.g. audio.get +@param parameters method parameters +@param httpMethod HTTP method for execution, e.g. GET, POST +@param modelClass class for automatic parse +@return Complete request object for execute or configure method +*/ ++ (instancetype)requestWithMethod:(NSString *)method + andParameters:(NSDictionary *)parameters + andHttpMethod:(NSString *)httpMethod + classOfModel:(Class)modelClass; + +/** +Creates new request for upload image to url +@param url url for upload, which was received from special methods +@param photoObjects VKPhoto object describes photos +@return Complete request object for execute +*/ ++ (instancetype)photoRequestWithPostUrl:(NSString *)url + withPhotos:(NSArray *)photoObjects; + +/** +Prepares NSURLRequest and returns prepared url request for current vkrequest +@return Prepared request used for loading +*/ +- (NSURLRequest *)getPreparedRequest; + +///------------------------------- +/// @name Execution +///------------------------------- +/** +Executes that request, and returns result to blocks +@param completeBlock called if there were no HTTP or API errors, returns execution result. +@param errorBlock called immediately if there was API error, or after attempts tries if there was an HTTP error +*/ +- (void)executeWithResultBlock:(void (^)(VKResponse *response))completeBlock + errorBlock:(void (^)(NSError *error))errorBlock; + +/** +Register current request for execute after passed request, if passed request is successful. If it's not, errorBlock will be called. +@param request after which request must be called that request +@param completeBlock called if there were no HTTP or API errors, returns execution result. +@param errorBlock called immediately if there was API error, or after attempts tries if there was an HTTP error +*/ +- (void)executeAfter:(VKRequest *)request + withResultBlock:(void (^)(VKResponse *response))completeBlock + errorBlock:(void (^)(NSError *error))errorBlock; + +/** +Starts loading of prepared request. You can use it instead of executeWithResultBlock +*/ +- (void)start; + +/** +Repeats this request with initial parameters and blocks. +Used attempts will be set to 0. +*/ +- (void)repeat; + +/** +Cancel current request. Result will be not passed. errorBlock will be called with error code +*/ +- (void)cancel; + +///------------------------------- +/// @name Operating with parameters +///------------------------------- +/** +Adds additional parameters to that request +@param extraParameters parameters supposed to be added +*/ +- (void)addExtraParameters:(NSDictionary *)extraParameters; + +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKResponse.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKResponse.h new file mode 100755 index 0000000..1a7d299 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKResponse.h @@ -0,0 +1,41 @@ +// +// VKResponse.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKObject.h" + +@class VKRequest; + +/** +Class presenting answer from API +*/ +@interface VKResponse : VKObject + +/// Request which caused response +@property(nonatomic, weak) VKRequest *request; +/// Json content of response. Can be array or object. +@property(nonatomic, strong) id json; +/// Model parsed from response +@property(nonatomic, strong) id parsedModel; +/// Original response string from server +@property(nonatomic, copy) NSString *responseString; + +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKSchool.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKSchool.h new file mode 100755 index 0000000..1da4c5f --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKSchool.h @@ -0,0 +1,43 @@ +// +// VKSchool.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or suabstantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKApiObjectArray.h" + +@interface VKSchool : VKApiObject + +@property(nonatomic, strong) NSNumber *id; +@property(nonatomic, strong) NSNumber *country; +@property(nonatomic, strong) NSNumber *city; +@property(nonatomic, strong) NSString *name; +@property(nonatomic, strong) NSNumber *year_from; +@property(nonatomic, strong) NSNumber *year_to; +@property(nonatomic, strong) NSNumber *year_graduated; +@property(nonatomic, strong) NSString *Mclass; +@property(nonatomic, strong) NSString *speciality; +@property(nonatomic, strong) NSNumber *type; +@property(nonatomic, strong) NSString *type_str; + +@end + +@interface VKSchools : VKApiObjectArray + +@end \ No newline at end of file diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKSdk.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKSdk.h new file mode 100755 index 0000000..624d609 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKSdk.h @@ -0,0 +1,294 @@ +// +// VKSdk.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// -------------------------------------------------------------------------------- +// +// Modified by Ruslan Kavetsky + +#import +#import "VKAccessToken.h" +#import "VKPermissions.h" +#import "VKUtil.h" +#import "VKApi.h" +#import "VKApiConst.h" +#import "VKSdkVersion.h" +#import "VKCaptchaViewController.h" +#import "VKRequest.h" +#import "VKBatchRequest.h" +#import "NSError+VKError.h" +#import "VKApiModels.h" +#import "VKUploadImage.h" +#import "VKShareDialogController.h" +#import "VKActivity.h" + +/** +Global SDK events delegate protocol. +You should implement it, typically as main view controller or as application delegate. +*/ +@protocol VKSdkDelegate +@required +/** +Calls when user must perform captcha-check +@param captchaError error returned from API. You can load captcha image from captchaImg property. +After user answered current captcha, call answerCaptcha: method with user entered answer. +*/ +- (void)vkSdkNeedCaptchaEnter:(VKError *)captchaError; + +/** +Notifies delegate about existing token has expired +@param expiredToken old token that has expired +*/ +- (void)vkSdkTokenHasExpired:(VKAccessToken *)expiredToken; + +/** +Notifies delegate about user authorization cancelation +@param authorizationError error that describes authorization error +*/ +- (void)vkSdkUserDeniedAccess:(VKError *)authorizationError; + +/** +Pass view controller that should be presented to user. Usually, it's an authorization window +@param controller view controller that must be shown to user +*/ +- (void)vkSdkShouldPresentViewController:(UIViewController *)controller; + +/** +Notifies delegate about receiving new access token +@param newToken new token for API requests +*/ +- (void)vkSdkReceivedNewToken:(VKAccessToken *)newToken; + +@optional +/** +Notifies delegate about receiving predefined token (initializeWithDelegate:andAppId:andCustomToken: token is not nil) +@param token used token for API requests +*/ +- (void)vkSdkAcceptedUserToken:(VKAccessToken *)token; + +/** +Notifies delegate about receiving new access token +@param newToken new token for API requests +*/ +- (void)vkSdkRenewedToken:(VKAccessToken *)newToken; + +/** +Requests delegate about redirect to Safari during authorization procedure. +By default returns YES +*/ +- (BOOL)vkSdkAuthorizationAllowFallbackToSafari; + +/** +Applications which not using VK SDK as main way of authentication should override this method and return NO. +By default returns YES. +*/ +- (BOOL)vkSdkIsBasicAuthorization; + +/** +* Called when a controller presented by SDK will be dismissed +*/ +- (void)vkSdkWillDismissViewController:(UIViewController *)controller; + +/** +* Called when a controller presented by SDK did dismiss +*/ +- (void)vkSdkDidDismissViewController:(UIViewController *)controller; +@end + +/** +Entry point for using VK sdk. Should be initialized at application start +*/ +@interface VKSdk : NSObject + +///------------------------------- +/// @name Delegate +///------------------------------- + +/// Responder for global SDK events +@property(nonatomic, weak) id delegate; + +/// Returns a last app_id used for initializing the SDK +@property(nonatomic, readonly, copy) NSString *currentAppId; + +/// API version for making requests +@property(nonatomic, readonly, copy) NSString *apiVersion; +///------------------------------- +/// @name Initialization +///------------------------------- +/** +Returns instance of VK sdk. You should never use that directly +*/ ++ (instancetype)instance; + +/** +Initialize SDK with responder for global SDK events +@param delegate responder for global SDK events +@param appId your application id (if you haven't, you can create standalone application here https://vk.com/editapp?act=create ) +*/ ++ (void)initializeWithDelegate:(id )delegate + andAppId:(NSString *)appId; + +/** +Initialize SDK with responder for global SDK events and custom token key +(e.g., saved from other source or for some test reasons) +@param delegate responder for global SDK events +@param appId your application id (if you haven't, you can create standalone application here https://vk.com/editapp?act=create ) +@param token custom-created access token +*/ ++ (void)initializeWithDelegate:(id )delegate + andAppId:(NSString *)appId + andCustomToken:(VKAccessToken *)token DEPRECATED_ATTRIBUTE; + +/** +Initialize SDK with responder for global SDK events +@param delegate responder for global SDK events +@param appId your application id (if you haven't, you can create standalone application here https://vk.com/editapp?act=create ) +@param apiVersion if you want to use latest API version, pass required version here +*/ ++ (void)initializeWithDelegate:(id )delegate + andAppId:(NSString *)appId + apiVersion:(NSString *)version; + +///------------------------------- +/// @name Authentication in VK +///------------------------------- + +/** +Starts authorization process. If VKapp is available in system, it will opens and requests access from user. +Otherwise Mobile Safari will be opened for access request. +@param permissions array of permissions for your applications. All permissions you can +*/ ++ (void)authorize:(NSArray *)permissions; + +/** +Starts authorization process. If VKapp is available in system, it will opens and requests access from user. +Otherwise Mobile Safari will be opened for access request. +@param permissions Array of permissions for your applications. All permissions you can +@param revokeAccess If YES, user will allow logout (to change user) +*/ ++ (void)authorize:(NSArray *)permissions revokeAccess:(BOOL)revokeAccess; + +/** +Starts authorization process. +@param permissions Array of permissions for your applications. All permissions you can +@param revokeAccess If YES, user will allow logout (to change user) +@param forceOAuth If YES, SDK will use only oauth authorization through mobile safari. Otherwise, it will try to authorize through VK application +*/ ++ (void)authorize:(NSArray *)permissions revokeAccess:(BOOL)revokeAccess forceOAuth:(BOOL)forceOAuth; + +/** +Starts authorization process. +@param permissions Array of permissions for your applications. All permissions you can +@param revokeAccess If YES, user will allow logout (to change user) +@param forceOAuth If YES, SDK will use only oauth authorization through mobile safari. Otherwise, it will try to authorize through VK application +@param inApp If YES, SDK will try to open modal window with webview to authorize. This method strongly not recommended as user should enter his account data in your application. For use modal view add VKSdkResources.bundle to your project. +*/ ++ (void)authorize:(NSArray *)permissions revokeAccess:(BOOL)revokeAccess forceOAuth:(BOOL)forceOAuth inApp:(BOOL)inApp; + +/** +Starts authorization process. +@param permissions Array of permissions for your applications. All permissions you can +@param revokeAccess If YES, user will allow logout (to change user) +@param forceOAuth If YES, SDK will use only oauth authorization through mobile safari. Otherwise, it will try to authorize through VK application +@param inApp If YES, SDK will try to open modal window with webview to authorize. This method strongly not recommended as user should enter his account data in your application. For use modal view add VKSdkResources.bundle to your project. +@param displayType Defines view of authorization screen +*/ ++ (void)authorize:(NSArray *)permissions revokeAccess:(BOOL)revokeAccess forceOAuth:(BOOL)forceOAuth inApp:(BOOL)inApp display:(VKDisplayType)displayType; + +///------------------------------- +/// @name Access token methods +///------------------------------- + +/** +Set API token to passed +@param token token must be used for API requests +*/ ++ (void)setAccessToken:(VKAccessToken *)token; + +/** +Notify SDK that user denied login +@param error Descripbes error which was happends while trying to recieve token +*/ ++ (void)setAccessTokenError:(VKError *)error; + +/** +Returns token for API requests +@return Received access token or nil, if user not yet authorized +*/ ++ (VKAccessToken *)getAccessToken; + +///------------------------------- +/// @name Other methods +///------------------------------- + +/** +Checks passed URL for access token +@param passedUrl url from external application +@param sourceApplication source application +@return YES if parsed successfully +*/ ++ (BOOL)processOpenURL:(NSURL *)passedUrl fromApplication:(NSString *)sourceApplication; + +/** +* Checks if somebody logged in with SDK +*/ ++ (BOOL)isLoggedIn; + +/** + Make try to read token from defaults and start session again. + */ ++ (BOOL)wakeUpSession; +/** + Try to read token from defaults, then check for required permissions. + */ ++ (BOOL)wakeUpSession:(NSArray *)permissions; + +/** +Forces logout using OAuth (with VKAuthorizeController). Removes all cookies for *.vk.com. +Has no effect for logout in VK app +*/ ++ (void)forceLogout; + +/** +* Checks if there is some application, which may process authorize url +*/ ++ (BOOL)vkAppMayExists; + +/** +Check existing permissions +@param permissions array of permissions you want to check +*/ ++ (BOOL)hasPermissions:(NSArray *)permissions; + +/** +Enables or disables scheduling for requests +*/ ++ (void)setSchedulerEnabled:(BOOL)enabled; + +// Deny allocating more SDK ++ (instancetype)alloc __attribute__((unavailable("alloc not available, call initialize: or instance instead"))); + +- (instancetype)init __attribute__((unavailable("init not available, call initialize: or instance instead"))); + ++ (instancetype)new __attribute__((unavailable("new not available, call initialize: or instance instead"))); + + +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKSdkVersion.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKSdkVersion.h new file mode 100755 index 0000000..e3f45f5 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKSdkVersion.h @@ -0,0 +1,24 @@ +// +// VKSdkVersion.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#define VK_SDK_VERSION @"1.1.7" +#define VK_SDK_API_VERSION @"5.23" diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKShareDialogController.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKShareDialogController.h new file mode 100755 index 0000000..1193f9e --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKShareDialogController.h @@ -0,0 +1,79 @@ +// +// VKShareDialogController.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import "VKObject.h" +#import "VKUploadImage.h" + + +typedef NS_ENUM(NSInteger, VKShareDialogControllerResult) { + VKShareDialogControllerResultCancelled, + VKShareDialogControllerResultDone +}; + +/* + * Link representation for share dialog + */ +@interface VKShareLink : VKObject +/// Use that field for present link description in share dialog interface +@property(nonatomic, copy) NSString *title; +/// Use that field for pass real link to VK. Host of the link will be displayed in share dialog +@property(nonatomic, copy) NSURL *link; + +- (instancetype)initWithTitle:(NSString *)title link:(NSURL *)link; +@end + + +/** +* Creates dialog for sharing some information from your app to user wall in VK +*/ +@interface VKShareDialogController : UIViewController +/// Array of prepared VKUploadImage objects for upload and share. User can remove any attachment +@property(nonatomic, strong) NSArray *uploadImages; + +/// Photos already uploaded to VK. That is array of photos ids: @[ownerid_photoid, ...]; +@property(nonatomic, strong) NSArray *vkImages; + +/// Links attachment for new post +@property(nonatomic, strong) VKShareLink *shareLink; + +/// Text to share. User can change it +@property(nonatomic, copy) NSString *text; + +/// Put only needed scopes into that array. By default equals @[VK_PER_WALL,VK_PER_PHOTOS] +@property(nonatomic, strong) NSArray *requestedScope; + +/// You can receive information about sharing state +@property(nonatomic, copy) void (^completionHandler)(VKShareDialogControllerResult result); + +/// Flag meaning the share viewcontroller manage it's presentation state by itself +@property(nonatomic, assign) BOOL dismissAutomatically; + +/// Force share dialog to use in-app webview authorization +@property(nonatomic, assign) BOOL authorizeInApp; + +/** +Correctly presents current view controller in another +@param viewController Parent view controller +*/ +- (void)presentIn:(UIViewController *)viewController __deprecated; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKUniversity.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUniversity.h new file mode 100755 index 0000000..c73a9b2 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUniversity.h @@ -0,0 +1,42 @@ +// +// VKUniversity.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or suabstantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKApiObjectArray.h" + +@interface VKUniversity : VKApiObject + +@property(nonatomic, strong) NSNumber *id; +@property(nonatomic, strong) NSNumber *country; +@property(nonatomic, strong) NSNumber *city; +@property(nonatomic, strong) NSString *name; +@property(nonatomic, strong) NSNumber *faculty; +@property(nonatomic, strong) NSString *faculty_name; +@property(nonatomic, strong) NSNumber *chair; +@property(nonatomic, strong) NSString *chair_name; +@property(nonatomic, strong) NSNumber *graduation; +@property(nonatomic, strong) NSString *education_form; +@property(nonatomic, strong) NSString *education_status; + +@end + +@interface VKUniversities : VKApiObjectArray +@end \ No newline at end of file diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKUploadImage.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUploadImage.h new file mode 100755 index 0000000..7c16557 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUploadImage.h @@ -0,0 +1,52 @@ +// +// VKUploadImage.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKImageParameters.h" + +/** +Contains image data with image description +*/ +@interface VKUploadImage : VKObject + +/// Bytes of image +@property(nonatomic, strong) NSData *imageData; +/// Source image +@property(nonatomic, strong) UIImage *sourceImage; +/// Image basic info +@property(nonatomic, strong) VKImageParameters *parameters; + +/** +Create new image data representation used for upload +@param data Bytes of image +@param params Image basic info +@return Prepared object for using in upload +*/ ++ (instancetype)uploadImageWithData:(NSData *)data andParams:(VKImageParameters *)params; + +/** +Create new image representation used for upload +@param image Source image +@param params Image basic info +@return Prepared object for using in upload +*/ ++ (instancetype)uploadImageWithImage:(UIImage *)image andParams:(VKImageParameters *)params; +@end \ No newline at end of file diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKUploadMessagesPhotoRequest.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUploadMessagesPhotoRequest.h new file mode 100755 index 0000000..c547564 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUploadMessagesPhotoRequest.h @@ -0,0 +1,28 @@ +// +// VKUploadMessagesPhotoRequest.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#import "VKUploadPhotoBase.h" + +@interface VKUploadMessagesPhotoRequest : VKUploadPhotoBase + +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKUploadPhotoBase.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUploadPhotoBase.h new file mode 100755 index 0000000..c0c6d67 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUploadPhotoBase.h @@ -0,0 +1,52 @@ +// +// VKPhotoUploadBase.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKRequest.h" +#import "VKImageParameters.h" +#import "VKOperation.h" + +/** +Provides common part of photo upload process +*/ +@interface VKUploadPhotoBase : VKRequest +/// ID of album to upload +@property(nonatomic, assign) NSInteger albumId; +/// ID of group to upload +@property(nonatomic, assign) NSInteger groupId; +/// ID of user wall to upload +@property(nonatomic, assign) NSInteger userId; + +/// Passed image parameters +@property(nonatomic, strong) VKImageParameters *imageParameters; +/// Image to upload +@property(nonatomic, strong) UIImage *image; + +- (instancetype)initWithImage:(UIImage *)image parameters:(VKImageParameters *)parameters; +@end + +/** +Special operation for execute upload +*/ +@interface VKUploadImageOperation : VKOperation + ++ (instancetype)operationWithUploadRequest:(VKUploadPhotoBase *)request; +@end \ No newline at end of file diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKUploadPhotoRequest.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUploadPhotoRequest.h new file mode 100755 index 0000000..669dce2 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUploadPhotoRequest.h @@ -0,0 +1,39 @@ +// +// VKUploadPhotoRequest.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKUploadPhotoBase.h" + +/** +Special request for upload photos to specified album +*/ +@interface VKUploadPhotoRequest : VKUploadPhotoBase + +/** +Initializes photo upload request with parameters +@param image Image to upload +@param parameters image parameters for upload +@param albumId ID of album for photo +@param groupId ID of group (without minus sign) on which wall image should be posted (or nil) +@return Completed request for executing +*/ +- (instancetype)initWithImage:(UIImage *)image parameters:(VKImageParameters *)parameters albumId:(NSInteger)albumId groupId:(NSInteger)groupId; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKUploadWallPhotoRequest.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUploadWallPhotoRequest.h new file mode 100755 index 0000000..9f3670c --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUploadWallPhotoRequest.h @@ -0,0 +1,38 @@ +// +// VKUploadWallPhotoRequest.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "VKUploadPhotoBase.h" + +/** +Special request for upload single photo to user wall +*/ +@interface VKUploadWallPhotoRequest : VKUploadPhotoBase +/** +Initializes photo upload request with parameters +@param image Image to upload +@param parameters image parameters for upload +@param userId ID of user on which wall image should be posted (or nil) +@param groupId ID of group (without minus sign) on which wall image should be posted (or nil) +@return Completed request for executing +*/ +- (instancetype)initWithImage:(UIImage *)image parameters:(VKImageParameters *)parameters userId:(NSInteger)userId groupId:(NSInteger)groupId; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKUser.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUser.h new file mode 100755 index 0000000..6bc8f9a --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUser.h @@ -0,0 +1,184 @@ +// +// VKUser.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import "VKApiObject.h" +#import "VKApiObjectArray.h" +#import "VKAudio.h" +#import "VKCounters.h" +#import "VKPhoto.h" +#import "VKSchool.h" +#import "VKUniversity.h" +#import "VKRelative.h" + +@interface VKGeoObject : VKApiObject +@property(nonatomic, strong) NSNumber *id; +@property(nonatomic, strong) NSString *title; +@end + +@interface VKCity : VKGeoObject +@end + +@interface VKCountry : VKGeoObject +@end + +@interface VKPersonal : VKObject +@property(nonatomic, strong) NSArray *langs; +@property(nonatomic, strong) NSNumber *political; +@property(nonatomic, strong) NSString *religion; +@property(nonatomic, strong) NSNumber *life_main; +@property(nonatomic, strong) NSNumber *people_main; +@property(nonatomic, strong) NSString *inspired_by; +@property(nonatomic, strong) NSNumber *smoking; +@property(nonatomic, strong) NSNumber *alcohol; +@end + +/** +User type of VK API. See descriptions here https://vk.com/dev/fields +*/ +@interface VKBanInfo : VKApiObject +/// идентификатор администратора, который добавил пользователя в черный список; +@property(nonatomic, strong) NSNumber *admin_id; +/// дата добавления пользователя в черный список; +@property(nonatomic, strong) NSNumber *date; +/// причина добавления пользователя в черный список; +@property(nonatomic, strong) NSNumber *reason; +/// текст комментария +@property(nonatomic, strong) NSString *comment; +/// дата, когда пользователь будет разбанен. +@property(nonatomic, strong) NSNumber *end_date; +@end + +@interface VKLastSeen : VKApiObject +@property(nonatomic, strong) NSNumber *time; +@property(nonatomic, strong) NSNumber *platform; +@end + +@interface VKExports : VKApiObject +@property(nonatomic, strong) NSNumber *twitter; +@property(nonatomic, strong) NSNumber *facebook; +@property(nonatomic, strong) NSNumber *livejournal; +@property(nonatomic, strong) NSNumber *instagram; +@end + +@interface VKUser : VKApiObject +@property(nonatomic, strong) NSNumber *id; +@property(nonatomic, strong) NSString *first_name; +@property(nonatomic, strong) NSString *last_name; +@property(nonatomic, strong) NSString *first_name_acc; +@property(nonatomic, strong) NSString *last_name_acc; +@property(nonatomic, strong) NSString *first_name_gen; +@property(nonatomic, strong) NSString *last_name_gen; +@property(nonatomic, strong) NSString *first_name_dat; +@property(nonatomic, strong) NSString *last_name_dat; +@property(nonatomic, strong) NSString *first_name_ins; +@property(nonatomic, strong) NSString *last_name_ins; +@property(nonatomic, strong) VKPersonal *personal; +@property(nonatomic, strong) NSNumber *sex; +@property(nonatomic, strong) NSNumber *invited_by; +@property(nonatomic, strong) NSNumber *online; +@property(nonatomic, strong) NSString *bdate; +@property(nonatomic, strong) VKCity *city; +@property(nonatomic, strong) VKCountry *country; +@property(nonatomic, strong) NSMutableArray *lists; +@property(nonatomic, strong) NSString *screen_name; +@property(nonatomic, strong) NSNumber *has_mobile; +@property(nonatomic, strong) NSNumber *rate; +@property(nonatomic, strong) NSString *mobile_phone; +@property(nonatomic, strong) NSString *home_phone; +@property(nonatomic, strong) NSNumber *can_post; +@property(nonatomic, strong) NSNumber *can_see_all_posts; +@property(nonatomic, strong) NSString *status; +@property(nonatomic, strong) VKAudio *status_audio; +@property(nonatomic, assign) bool status_loaded; +@property(nonatomic, strong) VKLastSeen *last_seen; +@property(nonatomic, strong) NSNumber *relation; +@property(nonatomic, strong) VKUser *relation_partner; +@property(nonatomic, strong) VKCounters *counters; +@property(nonatomic, strong) NSString *nickname; +@property(nonatomic, strong) VKExports *exports; +@property(nonatomic, strong) NSNumber *wall_comments; +@property(nonatomic, strong) NSNumber *can_write_private_message; +@property(nonatomic, strong) NSString *phone; +@property(nonatomic, strong) NSNumber *can_call; +@property(nonatomic, strong) NSNumber *online_mobile; +@property(nonatomic, strong) NSNumber *faculty; +@property(nonatomic, strong) NSNumber *university; +@property(nonatomic, strong) VKUniversities *universities; +@property(nonatomic, strong) VKSchools *schools; +@property(nonatomic, strong) NSNumber *graduation; +@property(nonatomic, strong) NSNumber *friendState; +@property(nonatomic, strong) NSString *faculty_name; +@property(nonatomic, strong) NSString *university_name; +@property(nonatomic, strong) NSString *books; +@property(nonatomic, strong) NSString *games; +@property(nonatomic, strong) NSString *interests; +@property(nonatomic, strong) NSString *movies; +@property(nonatomic, strong) NSString *tv; +@property(nonatomic, strong) NSString *about; +@property(nonatomic, strong) NSString *music; +@property(nonatomic, strong) NSString *quoutes; +@property(nonatomic, strong) NSString *activities; +@property(nonatomic, strong) NSString *photo_max; +@property(nonatomic, strong) NSString *photo_50; +@property(nonatomic, strong) NSString *photo_100; +@property(nonatomic, strong) NSString *photo_200; +@property(nonatomic, strong) NSString *photo_200_orig; +@property(nonatomic, strong) NSString *photo_400_orig; +@property(nonatomic, strong) NSString *photo_max_orig; +@property(nonatomic, strong) VKPhotoArray *photos; +@property(nonatomic, strong) NSNumber *photos_count; +@property(nonatomic, strong) VKRelativities *relatives; +@property(nonatomic, assign) NSTimeInterval bdateIntervalSort; +@property(nonatomic, strong) NSNumber *verified; +@property(nonatomic, strong) NSString *deactivated; +@property(nonatomic, strong) NSString *site; +@property(nonatomic, strong) NSString *home_town; +@property(nonatomic, strong) NSNumber *blacklisted; +@property(nonatomic, strong) NSNumber *blacklisted_by_me; +@property(nonatomic, strong) NSString *twitter; +@property(nonatomic, strong) NSString *skype; +@property(nonatomic, strong) NSString *facebook; +@property(nonatomic, strong) NSString *livejournal; +@property(nonatomic, strong) NSString *wall_default; +/// Для метода account.lookupContacts + +@property(nonatomic, strong) NSString *contact; +@property(nonatomic, strong) NSNumber *request_sent; +@property(nonatomic, strong) NSNumber *common_count; + +/// Для метода groups.getBanned +@property(nonatomic, strong) VKBanInfo *ban_info; + +/// audio.get +@property(nonatomic, strong) NSString *name; +@property(nonatomic, strong) NSString *name_gen; + +// getSubscriptions +@property(nonatomic, strong) NSNumber *followers_count; +@end + +/** +Array of API users +*/ +@interface VKUsersArray : VKApiObjectArray +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/Headers/VKUtil.h b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUtil.h new file mode 100755 index 0000000..4267568 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/A/Headers/VKUtil.h @@ -0,0 +1,51 @@ +// +// VKUtil.h +// +// Copyright (c) 2014 VK.com +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#define VK_SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame) +#define VK_SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending) +#define VK_SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending) +#define VK_SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending) +#define VK_SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending) +#define VK_COLOR [UIColor colorWithRed:85.0f / 255 green:133.0f / 255 blue:188.0f / 255 alpha:1.0f] +#define VK_IS_DEVICE_IPAD (UIUserInterfaceIdiomPad == [[UIDevice currentDevice] userInterfaceIdiom]) + +#import + +/** +Various functions +*/ +@interface VKUtil : NSObject +/** +Breaks key=value string to dictionary +@param queryString string with key=value pairs joined by & symbol +@return Dictionary of parameters +*/ ++ (NSDictionary *)explodeQueryString:(NSString *)queryString; + ++ (NSString *)generateGUID; + ++ (NSNumber *)parseNumberString:(id)number; + ++ (UIColor *)colorWithRGB:(NSInteger)rgb; + ++ (NSString *)queryStringFromParams:(NSDictionary *)params; +@end diff --git a/Frameworks/VKSdk.framework/Versions/A/VKSdk b/Frameworks/VKSdk.framework/Versions/A/VKSdk new file mode 100755 index 0000000..d93d564 Binary files /dev/null and b/Frameworks/VKSdk.framework/Versions/A/VKSdk differ diff --git a/Frameworks/VKSdk.framework/Versions/Current b/Frameworks/VKSdk.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/Frameworks/VKSdk.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/Mobily.podspec b/Mobily.podspec old mode 100755 new mode 100644 index e3bd62b..6252f9e --- a/Mobily.podspec +++ b/Mobily.podspec @@ -1,125 +1,34 @@ Pod::Spec.new do |s| - s.name = 'Mobily' - s.version = '0.1.68' - s.summary = 'Mobily framework for iOS' - s.homepage = 'https://github.com/fgengine/mobily-ios' - s.license = { - :type => 'MIT', - :file => 'LICENSE' - } - s.author = { - 'Username' => 'fgengine@gmail.com' - } - s.platform = :ios, 7.0 - s.source = { - :git => 'https://github.com/fgengine/mobily-ios.git', - :tag => s.version.to_s - } - s.default_subspec = 'All' - s.requires_arc = true - - s.subspec 'All' do |ss| - ss.dependency 'Mobily/NS' - ss.dependency 'Mobily/NSRegExpParser' - ss.dependency 'Mobily/CG' - ss.dependency 'Mobily/UI' - ss.dependency 'Mobily/UIViewFieldText' - ss.dependency 'Mobily/UIViewFieldDate' - ss.dependency 'Mobily/UIViewFieldList' - ss.dependency 'Mobily/UIViewImage' - ss.dependency 'Mobily/UIViewScroll' - ss.dependency 'Mobily/UIViewTable' - ss.dependency 'Mobily/UIViewElements' - end - - s.subspec 'Core' do |ss| - ss.public_header_files = 'Classes/Core/**/*.h' - ss.source_files = 'Classes/Core/**/*.{h,m}' - ss.frameworks = 'Foundation' - end - - s.subspec 'NS' do |ss| - ss.public_header_files = 'Classes/NS/Core/**/*.h' - ss.source_files = 'Classes/NS/Core/**/*.{h,m}' - ss.dependency 'Mobily/Core' - end - - s.subspec 'NSRegExpParser' do |ss| - ss.public_header_files = 'Classes/NS/RegExpParser/**/*.h' - ss.source_files = 'Classes/NS/RegExpParser/**/*.{h,m}' - ss.frameworks = 'CoreText' - ss.dependency 'Mobily/NS' - end - - s.subspec 'CG' do |ss| - ss.public_header_files = 'Classes/CG/Core/**/*.h' - ss.source_files = 'Classes/CG/Core/**/*.{h,m}' - ss.frameworks = 'CoreGraphics' - ss.dependency 'Mobily/Core' - end - - s.subspec 'UI' do |ss| - ss.public_header_files = 'Classes/UI/Core/**/*.h' - ss.source_files = 'Classes/UI/Core/**/*.{h,m}' - ss.frameworks = 'UIKit' - ss.dependency 'Mobily/Core' - ss.dependency 'Mobily/NS' - ss.dependency 'Mobily/CG' - end - - s.subspec 'UIControllerDynamicsDrawer' do |ss| - ss.public_header_files = 'Classes/UI/ControllerDynamicsDrawer/**/*.h' - ss.source_files = 'Classes/UI/ControllerDynamicsDrawer/**/*.{h,m}' - ss.dependency 'MSDynamicsDrawerViewController' - ss.dependency 'Mobily/UI' - end - - s.subspec 'UIControllerSlideMenu' do |ss| - ss.public_header_files = 'Classes/UI/ControllerSlideMenu/**/*.h' - ss.source_files = 'Classes/UI/ControllerSlideMenu/**/*.{h,m}' - ss.resources = 'Classes/UI/ControllerSlideMenu/**/*.{png}' - ss.dependency 'Mobily/UI' - end - - s.subspec 'UIViewFieldText' do |ss| - ss.public_header_files = 'Classes/UI/ViewFieldText/**/*.h' - ss.source_files = 'Classes/UI/ViewFieldText/**/*.{h,m}' - ss.dependency 'Mobily/UI' - end - - s.subspec 'UIViewFieldDate' do |ss| - ss.public_header_files = 'Classes/UI/ViewFieldDate/**/*.h' - ss.source_files = 'Classes/UI/ViewFieldDate/**/*.{h,m}' - ss.dependency 'Mobily/UIViewFieldText' - end - - s.subspec 'UIViewFieldList' do |ss| - ss.public_header_files = 'Classes/UI/ViewFieldList/**/*.h' - ss.source_files = 'Classes/UI/ViewFieldList/**/*.{h,m}' - ss.dependency 'Mobily/UIViewFieldText' - end - - s.subspec 'UIViewImage' do |ss| - ss.public_header_files = 'Classes/UI/ViewImage/**/*.h' - ss.source_files = 'Classes/UI/ViewImage/**/*.{h,m}' - ss.dependency 'Mobily/UI' - end - - s.subspec 'UIViewScroll' do |ss| - ss.public_header_files = 'Classes/UI/ViewScroll/**/*.h' - ss.source_files = 'Classes/UI/ViewScroll/**/*.{h,m}' - ss.dependency 'Mobily/UI' - end - - s.subspec 'UIViewTable' do |ss| - ss.public_header_files = 'Classes/UI/ViewTable/**/*.h' - ss.source_files = 'Classes/UI/ViewTable/**/*.{h,m}' - ss.dependency 'Mobily/UI' - end - - s.subspec 'UIViewElements' do |ss| - ss.public_header_files = 'Classes/UI/ViewElements/**/*.h' - ss.source_files = 'Classes/UI/ViewElements/**/*.{h,m}' - ss.dependency 'Mobily/UI' - end -end + s.name = 'Mobily' + s.version = '3.0.0' + s.summary = 'Mobily framework for iOS' + s.homepage = 'https://github.com/fgengine/mobily-ios/tree/v3' + s.license = { + :type => 'MIT', + :file => 'LICENSE' + } + s.author = { + 'username' => 'mobily.crew@gmail.com' + } + s.platform = :ios, 7.0 + s.requires_arc = true + s.default_subspec = 'Core' + + s.subspec 'Core' do |ss| + ss.public_header_files = 'Sources/MobilyCore/**/*.h' + ss.source_files = 'Sources/MobilyCore/**/*.{h,m}' + ss.xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'MOBILY_COCOAPODS_CORE' } + ss.frameworks = 'Foundation', 'CoreGraphics', 'UIKit', 'AVFoundation', 'CoreLocation' + end + + s.subspec 'Social' do |ss| + ss.public_header_files = 'Sources/MobilySocial/**/*.h' + ss.source_files = 'Sources/MobilySocial/**/*.{h,m}' + ss.xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'MOBILY_COCOAPODS_SOCIAL' } + ss.resource = 'Resources/FacebookSDKStrings.bundle', 'Resources/TwitterKitResources.bundle', 'Resources/VKSdkResources.bundle' + ss.vendored_frameworks = 'Frameworks/FBSDKCoreKit.framework', 'Frameworks/FBSDKLoginKit.framework', 'Frameworks/TwitterCore.bundle', 'Frameworks/TwitterKit.framework', 'Frameworks/VKSdk.framework' + ss.frameworks = 'CoreData', 'Accounts', 'Social', 'TwitterKit' + ss.dependency 'Mobily/Core' + ss.library = 'sqlite3' + end +end \ No newline at end of file diff --git a/Mobily.xcodeproj/project.pbxproj b/Mobily.xcodeproj/project.pbxproj index 0ab2ac6..d567110 100644 --- a/Mobily.xcodeproj/project.pbxproj +++ b/Mobily.xcodeproj/project.pbxproj @@ -7,642 +7,1628 @@ objects = { /* Begin PBXBuildFile section */ - 40081AA01A27122300F2FBE6 /* MobilyControllerSlideMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = 40081A8D1A27122200F2FBE6 /* MobilyControllerSlideMenu.m */; }; - 40081AA11A27122300F2FBE6 /* SlideNavigationContorllerAnimatorFade.m in Sources */ = {isa = PBXBuildFile; fileRef = 40081A921A27122200F2FBE6 /* SlideNavigationContorllerAnimatorFade.m */; }; - 40081AA21A27122300F2FBE6 /* SlideNavigationContorllerAnimatorScale.m in Sources */ = {isa = PBXBuildFile; fileRef = 40081A941A27122200F2FBE6 /* SlideNavigationContorllerAnimatorScale.m */; }; - 40081AA31A27122300F2FBE6 /* SlideNavigationContorllerAnimatorScaleAndFade.m in Sources */ = {isa = PBXBuildFile; fileRef = 40081A961A27122200F2FBE6 /* SlideNavigationContorllerAnimatorScaleAndFade.m */; }; - 40081AA41A27122300F2FBE6 /* SlideNavigationContorllerAnimatorSlide.m in Sources */ = {isa = PBXBuildFile; fileRef = 40081A981A27122200F2FBE6 /* SlideNavigationContorllerAnimatorSlide.m */; }; - 40081AA51A27122300F2FBE6 /* SlideNavigationContorllerAnimatorSlideAndFade.m in Sources */ = {isa = PBXBuildFile; fileRef = 40081A9A1A27122200F2FBE6 /* SlideNavigationContorllerAnimatorSlideAndFade.m */; }; - 40081AA61A27122300F2FBE6 /* menu-button.png in Resources */ = {isa = PBXBuildFile; fileRef = 40081A9C1A27122200F2FBE6 /* menu-button.png */; }; - 40081AA71A27122300F2FBE6 /* menu-button@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 40081A9D1A27122300F2FBE6 /* menu-button@2x.png */; }; - 40081AA81A27122300F2FBE6 /* SlideNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 40081A9F1A27122300F2FBE6 /* SlideNavigationController.m */; }; - 400B4D081A19E29900F2B61E /* MobilyViewTable.m in Sources */ = {isa = PBXBuildFile; fileRef = 400B4D071A19E29900F2B61E /* MobilyViewTable.m */; }; - 400B4D0A1A1A0D6700F2B61E /* ExampleControllerMainCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 400B4D091A1A0D6700F2B61E /* ExampleControllerMainCell.xib */; }; - 401FEE5318A3F92800B445EB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 401FEE5218A3F92800B445EB /* Foundation.framework */; }; - 401FEE5518A3F92800B445EB /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 401FEE5418A3F92800B445EB /* CoreGraphics.framework */; }; - 401FEE5718A3F92800B445EB /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 401FEE5618A3F92800B445EB /* UIKit.framework */; }; - 401FEE8918A3FAE600B445EB /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 401FEE8218A3FAE600B445EB /* InfoPlist.strings */; }; - 401FEE8A18A3FAE600B445EB /* ExampleApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEE8518A3FAE600B445EB /* ExampleApplication.m */; }; - 401FEE8B18A3FAE600B445EB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEE8618A3FAE600B445EB /* main.m */; }; - 401FEEF018A3FAF100B445EB /* MobilyCG.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEE9018A3FAF100B445EB /* MobilyCG.m */; }; - 401FEEF118A3FAF100B445EB /* MobilyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEE9718A3FAF100B445EB /* MobilyEvent.m */; }; - 401FEEF318A3FAF100B445EB /* MobilyHttpQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEE9B18A3FAF100B445EB /* MobilyHttpQuery.m */; }; - 401FEEF418A3FAF100B445EB /* MobilyKVO.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEE9D18A3FAF100B445EB /* MobilyKVO.m */; }; - 401FEEF518A3FAF100B445EB /* MobilyNS.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEE9F18A3FAF100B445EB /* MobilyNS.m */; }; - 401FEEF618A3FAF100B445EB /* MobilyStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEEA118A3FAF100B445EB /* MobilyStorage.m */; }; - 401FEEF718A3FAF100B445EB /* MobilyTaskManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEEA318A3FAF100B445EB /* MobilyTaskManager.m */; }; - 401FEEFD18A3FAF100B445EB /* MobilyApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEEB618A3FAF100B445EB /* MobilyApplication.m */; }; - 401FEEFE18A3FAF100B445EB /* MobilyContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEEB818A3FAF100B445EB /* MobilyContext.m */; }; - 401FEEFF18A3FAF100B445EB /* MobilyController.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEEBA18A3FAF100B445EB /* MobilyController.m */; }; - 401FEF0018A3FAF100B445EB /* MobilyControllerNavigation.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEEBC18A3FAF100B445EB /* MobilyControllerNavigation.m */; }; - 401FEF0118A3FAF100B445EB /* MobilyControllerTabBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEEBE18A3FAF100B445EB /* MobilyControllerTabBar.m */; }; - 401FEF0218A3FAF100B445EB /* MobilyControllerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEEC018A3FAF100B445EB /* MobilyControllerView.m */; }; - 401FEF0618A3FAF100B445EB /* MobilyBuilderForm.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEEC818A3FAF100B445EB /* MobilyBuilderForm.m */; }; - 401FEF0718A3FAF100B445EB /* MobilyUI.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEECA18A3FAF100B445EB /* MobilyUI.m */; }; - 401FEF1218A3FAF100B445EB /* MobilyWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEEE018A3FAF100B445EB /* MobilyWindow.m */; }; - 401FEF1A18A3FE3200B445EB /* Application.mobily in Resources */ = {isa = PBXBuildFile; fileRef = 401FEF1818A3FE3200B445EB /* Application.mobily */; }; - 401FEF1B18A3FE3200B445EB /* Presets.mobily in Resources */ = {isa = PBXBuildFile; fileRef = 401FEF1918A3FE3200B445EB /* Presets.mobily */; }; - 4032580B1A0BBBA700949E8F /* MobilyViewScroll.m in Sources */ = {isa = PBXBuildFile; fileRef = 4032580A1A0BBBA700949E8F /* MobilyViewScroll.m */; }; - 407903D01943079600EC8855 /* Mobily.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 407903CF1943079600EC8855 /* Mobily.podspec */; }; - 407903D219464A1E00EC8855 /* MobilyBuilderPreset.m in Sources */ = {isa = PBXBuildFile; fileRef = 407903D119464A1E00EC8855 /* MobilyBuilderPreset.m */; }; - 407989E41947834F00A04686 /* MobilyTransitionController.m in Sources */ = {isa = PBXBuildFile; fileRef = 407989E31947834F00A04686 /* MobilyTransitionController.m */; }; - 407989E7194788EE00A04686 /* MobilyTransitionControllerCards.m in Sources */ = {isa = PBXBuildFile; fileRef = 407989E5194788EE00A04686 /* MobilyTransitionControllerCards.m */; }; - 407989E8194788EE00A04686 /* MobilyTransitionControllerCrossFade.m in Sources */ = {isa = PBXBuildFile; fileRef = 407989E6194788EE00A04686 /* MobilyTransitionControllerCrossFade.m */; }; - 407989EC19484C9700A04686 /* MobilyControllerDynamicsDrawer.m in Sources */ = {isa = PBXBuildFile; fileRef = 407989EB19484C9700A04686 /* MobilyControllerDynamicsDrawer.m */; }; - 40798A2B1948ABAF00A04686 /* MobilyRegExpParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 40798A2A1948ABAF00A04686 /* MobilyRegExpParser.m */; }; - 40798A351948AC0600A04686 /* MobilyViewFieldDate.m in Sources */ = {isa = PBXBuildFile; fileRef = 40798A2E1948AC0600A04686 /* MobilyViewFieldDate.m */; }; - 40798A361948AC0600A04686 /* MobilyViewFieldList.m in Sources */ = {isa = PBXBuildFile; fileRef = 40798A311948AC0600A04686 /* MobilyViewFieldList.m */; }; - 40798A371948AC0600A04686 /* MobilyViewFieldText.m in Sources */ = {isa = PBXBuildFile; fileRef = 40798A341948AC0600A04686 /* MobilyViewFieldText.m */; }; - 40798A3B1948AFC400A04686 /* MobilyViewImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 40798A3A1948AFC400A04686 /* MobilyViewImage.m */; }; - 40798A411948C0F700A04686 /* MobilyViewElementsLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 40798A3E1948C0F700A04686 /* MobilyViewElementsLayout.m */; }; - 40798A421948C0F700A04686 /* MobilyViewElements.m in Sources */ = {isa = PBXBuildFile; fileRef = 40798A401948C0F700A04686 /* MobilyViewElements.m */; }; - 9AA83B7B19E536FF009F6C5F /* ExampleControllerMain.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9AA83B7A19E536FE009F6C5F /* ExampleControllerMain.xib */; }; - C13E78B87D644CF2A6696DA8 /* libPods.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F16AA68F9FE04603B1D99102 /* libPods.a */; }; + 4002F3B31B3D425E00961E90 /* MobilyPressAndHoldGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4002F3B11B3D425E00961E90 /* MobilyPressAndHoldGestureRecognizer.h */; }; + 4002F3B41B3D425E00961E90 /* MobilyPressAndHoldGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4002F3B21B3D425E00961E90 /* MobilyPressAndHoldGestureRecognizer.m */; }; + 4002F3B51B3D425E00961E90 /* MobilyPressAndHoldGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4002F3B21B3D425E00961E90 /* MobilyPressAndHoldGestureRecognizer.m */; }; + 4005C0881B1E13E4009A2185 /* FBSDKCoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4005C07F1B1E13E3009A2185 /* FBSDKCoreKit.framework */; }; + 4005C0891B1E13E4009A2185 /* FBSDKLoginKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4005C0801B1E13E3009A2185 /* FBSDKLoginKit.framework */; }; + 4005C08C1B1E13E4009A2185 /* TwitterCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4005C0831B1E13E4009A2185 /* TwitterCore.framework */; }; + 4005C08D1B1E13E4009A2185 /* TwitterKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4005C0841B1E13E4009A2185 /* TwitterKit.framework */; }; + 4005C08E1B1E13E4009A2185 /* VKSdk.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4005C0851B1E13E4009A2185 /* VKSdk.framework */; }; + 4018900B1B70F08E00440DF7 /* MobilyBadgeView.h in Headers */ = {isa = PBXBuildFile; fileRef = 401890091B70F08E00440DF7 /* MobilyBadgeView.h */; }; + 4018900C1B70F08E00440DF7 /* MobilyBadgeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4018900A1B70F08E00440DF7 /* MobilyBadgeView.m */; }; + 4018900D1B70F08E00440DF7 /* MobilyBadgeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4018900A1B70F08E00440DF7 /* MobilyBadgeView.m */; }; + 4064D18F1B577A6400F2F0FF /* MobilyImageCropController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4064D18D1B577A6400F2F0FF /* MobilyImageCropController.h */; }; + 4064D1901B577A6400F2F0FF /* MobilyImageCropController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4064D18E1B577A6400F2F0FF /* MobilyImageCropController.m */; }; + 4064D1911B577A6400F2F0FF /* MobilyImageCropController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4064D18E1B577A6400F2F0FF /* MobilyImageCropController.m */; }; + 4064D1941B577D0900F2F0FF /* MobilyTouchView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4064D1921B577D0900F2F0FF /* MobilyTouchView.h */; }; + 4064D1951B577D0900F2F0FF /* MobilyTouchView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4064D1931B577D0900F2F0FF /* MobilyTouchView.m */; }; + 4064D1961B577D0900F2F0FF /* MobilyTouchView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4064D1931B577D0900F2F0FF /* MobilyTouchView.m */; }; + 4080D2411B3B44EB00328837 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4080D2401B3B44EB00328837 /* StoreKit.framework */; }; + 4080D2441B3B450000328837 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4080D2401B3B44EB00328837 /* StoreKit.framework */; }; + 4080D2481B3B454200328837 /* MobilyStoreManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4080D2461B3B454200328837 /* MobilyStoreManager.h */; }; + 4080D2491B3B454200328837 /* MobilyStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4080D2471B3B454200328837 /* MobilyStoreManager.m */; }; + 4080D24A1B3B454200328837 /* MobilyStoreManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4080D2471B3B454200328837 /* MobilyStoreManager.m */; }; + 4096BD181B2024DA0048B07E /* MobilyActivityView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC701B2024DA0048B07E /* MobilyActivityView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD191B2024DA0048B07E /* MobilyActivityView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC711B2024DA0048B07E /* MobilyActivityView.m */; }; + 4096BD1A1B2024DA0048B07E /* MobilyActivityView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC711B2024DA0048B07E /* MobilyActivityView.m */; }; + 4096BD1B1B2024DA0048B07E /* MobilyApiManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC721B2024DA0048B07E /* MobilyApiManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD1C1B2024DA0048B07E /* MobilyApiManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC731B2024DA0048B07E /* MobilyApiManager.m */; }; + 4096BD1D1B2024DA0048B07E /* MobilyApiManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC731B2024DA0048B07E /* MobilyApiManager.m */; }; + 4096BD1E1B2024DA0048B07E /* MobilyApiProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC741B2024DA0048B07E /* MobilyApiProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD1F1B2024DA0048B07E /* MobilyApiProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC751B2024DA0048B07E /* MobilyApiProvider.m */; }; + 4096BD201B2024DA0048B07E /* MobilyApiProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC751B2024DA0048B07E /* MobilyApiProvider.m */; }; + 4096BD211B2024DA0048B07E /* MobilyApiRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC761B2024DA0048B07E /* MobilyApiRequest.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD221B2024DA0048B07E /* MobilyApiRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC771B2024DA0048B07E /* MobilyApiRequest.m */; }; + 4096BD231B2024DA0048B07E /* MobilyApiRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC771B2024DA0048B07E /* MobilyApiRequest.m */; }; + 4096BD241B2024DA0048B07E /* MobilyApiResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC781B2024DA0048B07E /* MobilyApiResponse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD251B2024DA0048B07E /* MobilyApiResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC791B2024DA0048B07E /* MobilyApiResponse.m */; }; + 4096BD261B2024DA0048B07E /* MobilyApiResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC791B2024DA0048B07E /* MobilyApiResponse.m */; }; + 4096BD271B2024DA0048B07E /* MobilyApplication.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC7A1B2024DA0048B07E /* MobilyApplication.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD281B2024DA0048B07E /* MobilyApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC7B1B2024DA0048B07E /* MobilyApplication.m */; }; + 4096BD291B2024DA0048B07E /* MobilyApplication.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC7B1B2024DA0048B07E /* MobilyApplication.m */; }; + 4096BD2A1B2024DA0048B07E /* MobilyAudioPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC7C1B2024DA0048B07E /* MobilyAudioPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD2B1B2024DA0048B07E /* MobilyAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC7D1B2024DA0048B07E /* MobilyAudioPlayer.m */; }; + 4096BD2C1B2024DA0048B07E /* MobilyAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC7D1B2024DA0048B07E /* MobilyAudioPlayer.m */; }; + 4096BD2D1B2024DA0048B07E /* MobilyAudioRecorder.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC7E1B2024DA0048B07E /* MobilyAudioRecorder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD2E1B2024DA0048B07E /* MobilyAudioRecorder.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC7F1B2024DA0048B07E /* MobilyAudioRecorder.m */; }; + 4096BD2F1B2024DA0048B07E /* MobilyAudioRecorder.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC7F1B2024DA0048B07E /* MobilyAudioRecorder.m */; }; + 4096BD301B2024DA0048B07E /* MobilyAV.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC801B2024DA0048B07E /* MobilyAV.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD311B2024DA0048B07E /* MobilyBlurView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC811B2024DA0048B07E /* MobilyBlurView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD321B2024DA0048B07E /* MobilyBlurView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC821B2024DA0048B07E /* MobilyBlurView.m */; }; + 4096BD331B2024DA0048B07E /* MobilyBlurView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC821B2024DA0048B07E /* MobilyBlurView.m */; }; + 4096BD341B2024DA0048B07E /* MobilyBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC831B2024DA0048B07E /* MobilyBuilder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD351B2024DA0048B07E /* MobilyBuilderForm.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC841B2024DA0048B07E /* MobilyBuilderForm.m */; }; + 4096BD361B2024DA0048B07E /* MobilyBuilderForm.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC841B2024DA0048B07E /* MobilyBuilderForm.m */; }; + 4096BD371B2024DA0048B07E /* MobilyBuilderPreset.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC851B2024DA0048B07E /* MobilyBuilderPreset.m */; }; + 4096BD381B2024DA0048B07E /* MobilyBuilderPreset.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC851B2024DA0048B07E /* MobilyBuilderPreset.m */; }; + 4096BD391B2024DA0048B07E /* MobilyButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC861B2024DA0048B07E /* MobilyButton.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD3A1B2024DA0048B07E /* MobilyButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC871B2024DA0048B07E /* MobilyButton.m */; }; + 4096BD3B1B2024DA0048B07E /* MobilyButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC871B2024DA0048B07E /* MobilyButton.m */; }; + 4096BD3C1B2024DA0048B07E /* MobilyCA.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC881B2024DA0048B07E /* MobilyCA.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD3D1B2024DA0048B07E /* MobilyCA.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC891B2024DA0048B07E /* MobilyCA.m */; }; + 4096BD3E1B2024DA0048B07E /* MobilyCA.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC891B2024DA0048B07E /* MobilyCA.m */; }; + 4096BD3F1B2024DA0048B07E /* MobilyCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC8A1B2024DA0048B07E /* MobilyCache.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD401B2024DA0048B07E /* MobilyCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC8B1B2024DA0048B07E /* MobilyCache.m */; }; + 4096BD411B2024DA0048B07E /* MobilyCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC8B1B2024DA0048B07E /* MobilyCache.m */; }; + 4096BD421B2024DA0048B07E /* MobilyCG.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC8C1B2024DA0048B07E /* MobilyCG.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD431B2024DA0048B07E /* MobilyCG.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC8D1B2024DA0048B07E /* MobilyCG.m */; }; + 4096BD441B2024DA0048B07E /* MobilyCG.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC8D1B2024DA0048B07E /* MobilyCG.m */; }; + 4096BD451B2024DA0048B07E /* MobilyContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC8E1B2024DA0048B07E /* MobilyContext.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD461B2024DA0048B07E /* MobilyContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC8F1B2024DA0048B07E /* MobilyContext.m */; }; + 4096BD471B2024DA0048B07E /* MobilyContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC8F1B2024DA0048B07E /* MobilyContext.m */; }; + 4096BD481B2024DA0048B07E /* MobilyController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC901B2024DA0048B07E /* MobilyController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD491B2024DA0048B07E /* MobilyController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC911B2024DA0048B07E /* MobilyController.m */; }; + 4096BD4A1B2024DA0048B07E /* MobilyController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC911B2024DA0048B07E /* MobilyController.m */; }; + 4096BD4B1B2024DA0048B07E /* MobilyCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC921B2024DA0048B07E /* MobilyCore.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD4C1B2024DA0048B07E /* MobilyData.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC931B2024DA0048B07E /* MobilyData.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD4D1B2024DA0048B07E /* MobilyDataCell+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC941B2024DA0048B07E /* MobilyDataCell+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 4096BD4E1B2024DA0048B07E /* MobilyDataCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC951B2024DA0048B07E /* MobilyDataCell.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD4F1B2024DA0048B07E /* MobilyDataCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC961B2024DA0048B07E /* MobilyDataCell.m */; }; + 4096BD501B2024DA0048B07E /* MobilyDataCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC961B2024DA0048B07E /* MobilyDataCell.m */; }; + 4096BD511B2024DA0048B07E /* MobilyDataCellSwipe.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC971B2024DA0048B07E /* MobilyDataCellSwipe.m */; }; + 4096BD521B2024DA0048B07E /* MobilyDataCellSwipe.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC971B2024DA0048B07E /* MobilyDataCellSwipe.m */; }; + 4096BD531B2024DA0048B07E /* MobilyDataContainer+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC981B2024DA0048B07E /* MobilyDataContainer+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 4096BD541B2024DA0048B07E /* MobilyDataContainer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BC991B2024DA0048B07E /* MobilyDataContainer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD551B2024DA0048B07E /* MobilyDataContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC9A1B2024DA0048B07E /* MobilyDataContainer.m */; }; + 4096BD561B2024DA0048B07E /* MobilyDataContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC9A1B2024DA0048B07E /* MobilyDataContainer.m */; }; + 4096BD571B2024DA0048B07E /* MobilyDataContainerCalendar.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC9B1B2024DA0048B07E /* MobilyDataContainerCalendar.m */; }; + 4096BD581B2024DA0048B07E /* MobilyDataContainerCalendar.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC9B1B2024DA0048B07E /* MobilyDataContainerCalendar.m */; }; + 4096BD591B2024DA0048B07E /* MobilyDataContainerCalendarDays.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC9C1B2024DA0048B07E /* MobilyDataContainerCalendarDays.m */; }; + 4096BD5A1B2024DA0048B07E /* MobilyDataContainerCalendarDays.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC9C1B2024DA0048B07E /* MobilyDataContainerCalendarDays.m */; }; + 4096BD5B1B2024DA0048B07E /* MobilyDataContainerItems.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC9D1B2024DA0048B07E /* MobilyDataContainerItems.m */; }; + 4096BD5C1B2024DA0048B07E /* MobilyDataContainerItems.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC9D1B2024DA0048B07E /* MobilyDataContainerItems.m */; }; + 4096BD5D1B2024DA0048B07E /* MobilyDataContainerItemsFlow.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC9E1B2024DA0048B07E /* MobilyDataContainerItemsFlow.m */; }; + 4096BD5E1B2024DA0048B07E /* MobilyDataContainerItemsFlow.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC9E1B2024DA0048B07E /* MobilyDataContainerItemsFlow.m */; }; + 4096BD5F1B2024DA0048B07E /* MobilyDataContainerItemsGrid.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC9F1B2024DA0048B07E /* MobilyDataContainerItemsGrid.m */; }; + 4096BD601B2024DA0048B07E /* MobilyDataContainerItemsGrid.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BC9F1B2024DA0048B07E /* MobilyDataContainerItemsGrid.m */; }; + 4096BD611B2024DA0048B07E /* MobilyDataContainerItemsList.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCA01B2024DA0048B07E /* MobilyDataContainerItemsList.m */; }; + 4096BD621B2024DA0048B07E /* MobilyDataContainerItemsList.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCA01B2024DA0048B07E /* MobilyDataContainerItemsList.m */; }; + 4096BD631B2024DA0048B07E /* MobilyDataContainerSections.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCA11B2024DA0048B07E /* MobilyDataContainerSections.m */; }; + 4096BD641B2024DA0048B07E /* MobilyDataContainerSections.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCA11B2024DA0048B07E /* MobilyDataContainerSections.m */; }; + 4096BD651B2024DA0048B07E /* MobilyDataContainerSectionsList.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCA21B2024DA0048B07E /* MobilyDataContainerSectionsList.m */; }; + 4096BD661B2024DA0048B07E /* MobilyDataContainerSectionsList.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCA21B2024DA0048B07E /* MobilyDataContainerSectionsList.m */; }; + 4096BD671B2024DA0048B07E /* MobilyDataItem+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCA31B2024DA0048B07E /* MobilyDataItem+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 4096BD681B2024DA0048B07E /* MobilyDataItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCA41B2024DA0048B07E /* MobilyDataItem.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD691B2024DA0048B07E /* MobilyDataItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCA51B2024DA0048B07E /* MobilyDataItem.m */; }; + 4096BD6A1B2024DA0048B07E /* MobilyDataItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCA51B2024DA0048B07E /* MobilyDataItem.m */; }; + 4096BD6B1B2024DA0048B07E /* MobilyDataRefreshView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCA61B2024DA0048B07E /* MobilyDataRefreshView+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 4096BD6C1B2024DA0048B07E /* MobilyDataRefreshView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCA71B2024DA0048B07E /* MobilyDataRefreshView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD6D1B2024DA0048B07E /* MobilyDataRefreshView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCA81B2024DA0048B07E /* MobilyDataRefreshView.m */; }; + 4096BD6E1B2024DA0048B07E /* MobilyDataRefreshView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCA81B2024DA0048B07E /* MobilyDataRefreshView.m */; }; + 4096BD6F1B2024DA0048B07E /* MobilyDataView+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCA91B2024DA0048B07E /* MobilyDataView+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 4096BD701B2024DA0048B07E /* MobilyDataView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCAA1B2024DA0048B07E /* MobilyDataView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD711B2024DA0048B07E /* MobilyDataView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCAB1B2024DA0048B07E /* MobilyDataView.m */; }; + 4096BD721B2024DA0048B07E /* MobilyDataView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCAB1B2024DA0048B07E /* MobilyDataView.m */; }; + 4096BD731B2024DA0048B07E /* MobilyDateField.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCAC1B2024DA0048B07E /* MobilyDateField.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD741B2024DA0048B07E /* MobilyDateField.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCAD1B2024DA0048B07E /* MobilyDateField.m */; }; + 4096BD751B2024DA0048B07E /* MobilyDateField.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCAD1B2024DA0048B07E /* MobilyDateField.m */; }; + 4096BD761B2024DA0048B07E /* MobilyDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCAE1B2024DA0048B07E /* MobilyDefines.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD771B2024DA0048B07E /* MobilyDialogController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCAF1B2024DA0048B07E /* MobilyDialogController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD781B2024DA0048B07E /* MobilyDialogController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCB01B2024DA0048B07E /* MobilyDialogController.m */; }; + 4096BD791B2024DA0048B07E /* MobilyDialogController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCB01B2024DA0048B07E /* MobilyDialogController.m */; }; + 4096BD7A1B2024DA0048B07E /* MobilyDownloader.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCB11B2024DA0048B07E /* MobilyDownloader.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD7B1B2024DA0048B07E /* MobilyDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCB21B2024DA0048B07E /* MobilyDownloader.m */; }; + 4096BD7C1B2024DA0048B07E /* MobilyDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCB21B2024DA0048B07E /* MobilyDownloader.m */; }; + 4096BD7D1B2024DA0048B07E /* MobilyEvent+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCB31B2024DA0048B07E /* MobilyEvent+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 4096BD7E1B2024DA0048B07E /* MobilyEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCB41B2024DA0048B07E /* MobilyEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD7F1B2024DA0048B07E /* MobilyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCB51B2024DA0048B07E /* MobilyEvent.m */; }; + 4096BD801B2024DA0048B07E /* MobilyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCB51B2024DA0048B07E /* MobilyEvent.m */; }; + 4096BD811B2024DA0048B07E /* MobilyFieldValidation+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCB61B2024DA0048B07E /* MobilyFieldValidation+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 4096BD821B2024DA0048B07E /* MobilyFieldValidation.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCB71B2024DA0048B07E /* MobilyFieldValidation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD831B2024DA0048B07E /* MobilyFieldValidation.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCB81B2024DA0048B07E /* MobilyFieldValidation.m */; }; + 4096BD841B2024DA0048B07E /* MobilyFieldValidation.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCB81B2024DA0048B07E /* MobilyFieldValidation.m */; }; + 4096BD851B2024DA0048B07E /* MobilyGeoLocationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCB91B2024DA0048B07E /* MobilyGeoLocationManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD861B2024DA0048B07E /* MobilyGeoLocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCBA1B2024DA0048B07E /* MobilyGeoLocationManager.m */; }; + 4096BD871B2024DA0048B07E /* MobilyGeoLocationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCBA1B2024DA0048B07E /* MobilyGeoLocationManager.m */; }; + 4096BD881B2024DA0048B07E /* MobilyGrid.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCBB1B2024DA0048B07E /* MobilyGrid.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD891B2024DA0048B07E /* MobilyGrid.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCBC1B2024DA0048B07E /* MobilyGrid.m */; }; + 4096BD8A1B2024DA0048B07E /* MobilyGrid.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCBC1B2024DA0048B07E /* MobilyGrid.m */; }; + 4096BD8B1B2024DA0048B07E /* MobilyHttpQuery+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCBD1B2024DA0048B07E /* MobilyHttpQuery+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 4096BD8C1B2024DA0048B07E /* MobilyHttpQuery.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCBE1B2024DA0048B07E /* MobilyHttpQuery.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD8D1B2024DA0048B07E /* MobilyHttpQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCBF1B2024DA0048B07E /* MobilyHttpQuery.m */; }; + 4096BD8E1B2024DA0048B07E /* MobilyHttpQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCBF1B2024DA0048B07E /* MobilyHttpQuery.m */; }; + 4096BD8F1B2024DA0048B07E /* MobilyImageView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCC01B2024DA0048B07E /* MobilyImageView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD901B2024DA0048B07E /* MobilyImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCC11B2024DA0048B07E /* MobilyImageView.m */; }; + 4096BD911B2024DA0048B07E /* MobilyImageView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCC11B2024DA0048B07E /* MobilyImageView.m */; }; + 4096BD921B2024DA0048B07E /* MobilyKVO.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCC21B2024DA0048B07E /* MobilyKVO.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD931B2024DA0048B07E /* MobilyKVO.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCC31B2024DA0048B07E /* MobilyKVO.m */; }; + 4096BD941B2024DA0048B07E /* MobilyKVO.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCC31B2024DA0048B07E /* MobilyKVO.m */; }; + 4096BD951B2024DA0048B07E /* MobilyListField.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCC41B2024DA0048B07E /* MobilyListField.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD961B2024DA0048B07E /* MobilyListField.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCC51B2024DA0048B07E /* MobilyListField.m */; }; + 4096BD971B2024DA0048B07E /* MobilyListField.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCC51B2024DA0048B07E /* MobilyListField.m */; }; + 4096BD981B2024DA0048B07E /* MobilyLoadedView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCC61B2024DA0048B07E /* MobilyLoadedView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD991B2024DA0048B07E /* MobilyLoadedView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCC71B2024DA0048B07E /* MobilyLoadedView.m */; }; + 4096BD9A1B2024DA0048B07E /* MobilyLoadedView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCC71B2024DA0048B07E /* MobilyLoadedView.m */; }; + 4096BD9B1B2024DA0048B07E /* MobilyLockScreenController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCC81B2024DA0048B07E /* MobilyLockScreenController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD9C1B2024DA0048B07E /* MobilyLockScreenController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCC91B2024DA0048B07E /* MobilyLockScreenController.m */; }; + 4096BD9D1B2024DA0048B07E /* MobilyLockScreenController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCC91B2024DA0048B07E /* MobilyLockScreenController.m */; }; + 4096BD9E1B2024DA0048B07E /* MobilyLockScreenPincodeView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCCA1B2024DA0048B07E /* MobilyLockScreenPincodeView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BD9F1B2024DA0048B07E /* MobilyLockScreenPincodeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCCB1B2024DA0048B07E /* MobilyLockScreenPincodeView.m */; }; + 4096BDA01B2024DA0048B07E /* MobilyLockScreenPincodeView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCCB1B2024DA0048B07E /* MobilyLockScreenPincodeView.m */; }; + 4096BDA11B2024DA0048B07E /* MobilyMap.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCCC1B2024DA0048B07E /* MobilyMap.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDA21B2024DA0048B07E /* MobilyMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCCD1B2024DA0048B07E /* MobilyMap.m */; }; + 4096BDA31B2024DA0048B07E /* MobilyMap.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCCD1B2024DA0048B07E /* MobilyMap.m */; }; + 4096BDA41B2024DA0048B07E /* MobilyModel+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCCE1B2024DA0048B07E /* MobilyModel+Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 4096BDA51B2024DA0048B07E /* MobilyModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCCF1B2024DA0048B07E /* MobilyModel.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDA61B2024DA0048B07E /* MobilyModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCD01B2024DA0048B07E /* MobilyModel.m */; }; + 4096BDA71B2024DA0048B07E /* MobilyModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCD01B2024DA0048B07E /* MobilyModel.m */; }; + 4096BDA81B2024DA0048B07E /* MobilyModelJson.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCD11B2024DA0048B07E /* MobilyModelJson.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDA91B2024DA0048B07E /* MobilyModelJson.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCD21B2024DA0048B07E /* MobilyModelJson.m */; }; + 4096BDAA1B2024DA0048B07E /* MobilyModelJson.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCD21B2024DA0048B07E /* MobilyModelJson.m */; }; + 4096BDAB1B2024DA0048B07E /* MobilyNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCD31B2024DA0048B07E /* MobilyNavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDAC1B2024DA0048B07E /* MobilyNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCD41B2024DA0048B07E /* MobilyNavigationController.m */; }; + 4096BDAD1B2024DA0048B07E /* MobilyNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCD41B2024DA0048B07E /* MobilyNavigationController.m */; }; + 4096BDAE1B2024DA0048B07E /* MobilyNS.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCD51B2024DA0048B07E /* MobilyNS.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDAF1B2024DA0048B07E /* MobilyNS.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCD61B2024DA0048B07E /* MobilyNS.m */; }; + 4096BDB01B2024DA0048B07E /* MobilyNS.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCD61B2024DA0048B07E /* MobilyNS.m */; }; + 4096BDB11B2024DA0048B07E /* MobilyObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCD71B2024DA0048B07E /* MobilyObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDB21B2024DA0048B07E /* MobilyPageControl.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCD81B2024DA0048B07E /* MobilyPageControl.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDB31B2024DA0048B07E /* MobilyPageControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCD91B2024DA0048B07E /* MobilyPageControl.m */; }; + 4096BDB41B2024DA0048B07E /* MobilyPageControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCD91B2024DA0048B07E /* MobilyPageControl.m */; }; + 4096BDB51B2024DA0048B07E /* MobilyPageController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCDA1B2024DA0048B07E /* MobilyPageController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDB61B2024DA0048B07E /* MobilyPageController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCDB1B2024DA0048B07E /* MobilyPageController.m */; }; + 4096BDB71B2024DA0048B07E /* MobilyPageController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCDB1B2024DA0048B07E /* MobilyPageController.m */; }; + 4096BDB81B2024DA0048B07E /* MobilyPopoverController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCDC1B2024DA0048B07E /* MobilyPopoverController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDB91B2024DA0048B07E /* MobilyPopoverController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCDD1B2024DA0048B07E /* MobilyPopoverController.m */; }; + 4096BDBA1B2024DA0048B07E /* MobilyPopoverController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCDD1B2024DA0048B07E /* MobilyPopoverController.m */; }; + 4096BDBB1B2024DA0048B07E /* MobilyRegExpParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCDE1B2024DA0048B07E /* MobilyRegExpParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDBC1B2024DA0048B07E /* MobilyRegExpParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCDF1B2024DA0048B07E /* MobilyRegExpParser.m */; }; + 4096BDBD1B2024DA0048B07E /* MobilyRegExpParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCDF1B2024DA0048B07E /* MobilyRegExpParser.m */; }; + 4096BDBE1B2024DA0048B07E /* MobilyScrollView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCE01B2024DA0048B07E /* MobilyScrollView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDBF1B2024DA0048B07E /* MobilyScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCE11B2024DA0048B07E /* MobilyScrollView.m */; }; + 4096BDC01B2024DA0048B07E /* MobilyScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCE11B2024DA0048B07E /* MobilyScrollView.m */; }; + 4096BDC11B2024DA0048B07E /* MobilySearchBar.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCE21B2024DA0048B07E /* MobilySearchBar.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDC21B2024DA0048B07E /* MobilySearchBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCE31B2024DA0048B07E /* MobilySearchBar.m */; }; + 4096BDC31B2024DA0048B07E /* MobilySearchBar.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCE31B2024DA0048B07E /* MobilySearchBar.m */; }; + 4096BDC41B2024DA0048B07E /* MobilySharedManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCE41B2024DA0048B07E /* MobilySharedManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDC51B2024DA0048B07E /* MobilySharedManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCE51B2024DA0048B07E /* MobilySharedManager.m */; }; + 4096BDC61B2024DA0048B07E /* MobilySharedManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCE51B2024DA0048B07E /* MobilySharedManager.m */; }; + 4096BDC71B2024DA0048B07E /* MobilySlideController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCE61B2024DA0048B07E /* MobilySlideController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDC81B2024DA0048B07E /* MobilySlideController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCE71B2024DA0048B07E /* MobilySlideController.m */; }; + 4096BDC91B2024DA0048B07E /* MobilySlideController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCE71B2024DA0048B07E /* MobilySlideController.m */; }; + 4096BDCA1B2024DA0048B07E /* MobilySpinnerView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCE81B2024DA0048B07E /* MobilySpinnerView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDCB1B2024DA0048B07E /* MobilySpinnerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCE91B2024DA0048B07E /* MobilySpinnerView.m */; }; + 4096BDCC1B2024DA0048B07E /* MobilySpinnerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCE91B2024DA0048B07E /* MobilySpinnerView.m */; }; + 4096BDCD1B2024DA0048B07E /* MobilySpinnerView9CubeGrid.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCEA1B2024DA0048B07E /* MobilySpinnerView9CubeGrid.m */; }; + 4096BDCE1B2024DA0048B07E /* MobilySpinnerView9CubeGrid.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCEA1B2024DA0048B07E /* MobilySpinnerView9CubeGrid.m */; }; + 4096BDCF1B2024DA0048B07E /* MobilySpinnerViewArc.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCEB1B2024DA0048B07E /* MobilySpinnerViewArc.m */; }; + 4096BDD01B2024DA0048B07E /* MobilySpinnerViewArc.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCEB1B2024DA0048B07E /* MobilySpinnerViewArc.m */; }; + 4096BDD11B2024DA0048B07E /* MobilySpinnerViewArcAlt.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCEC1B2024DA0048B07E /* MobilySpinnerViewArcAlt.m */; }; + 4096BDD21B2024DA0048B07E /* MobilySpinnerViewArcAlt.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCEC1B2024DA0048B07E /* MobilySpinnerViewArcAlt.m */; }; + 4096BDD31B2024DA0048B07E /* MobilySpinnerViewBounce.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCED1B2024DA0048B07E /* MobilySpinnerViewBounce.m */; }; + 4096BDD41B2024DA0048B07E /* MobilySpinnerViewBounce.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCED1B2024DA0048B07E /* MobilySpinnerViewBounce.m */; }; + 4096BDD51B2024DA0048B07E /* MobilySpinnerViewChasingDots.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCEE1B2024DA0048B07E /* MobilySpinnerViewChasingDots.m */; }; + 4096BDD61B2024DA0048B07E /* MobilySpinnerViewChasingDots.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCEE1B2024DA0048B07E /* MobilySpinnerViewChasingDots.m */; }; + 4096BDD71B2024DA0048B07E /* MobilySpinnerViewCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCEF1B2024DA0048B07E /* MobilySpinnerViewCircle.m */; }; + 4096BDD81B2024DA0048B07E /* MobilySpinnerViewCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCEF1B2024DA0048B07E /* MobilySpinnerViewCircle.m */; }; + 4096BDD91B2024DA0048B07E /* MobilySpinnerViewCircleFlip.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF01B2024DA0048B07E /* MobilySpinnerViewCircleFlip.m */; }; + 4096BDDA1B2024DA0048B07E /* MobilySpinnerViewCircleFlip.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF01B2024DA0048B07E /* MobilySpinnerViewCircleFlip.m */; }; + 4096BDDB1B2024DA0048B07E /* MobilySpinnerViewFadingCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF11B2024DA0048B07E /* MobilySpinnerViewFadingCircle.m */; }; + 4096BDDC1B2024DA0048B07E /* MobilySpinnerViewFadingCircle.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF11B2024DA0048B07E /* MobilySpinnerViewFadingCircle.m */; }; + 4096BDDD1B2024DA0048B07E /* MobilySpinnerViewFadingCircleAlt.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF21B2024DA0048B07E /* MobilySpinnerViewFadingCircleAlt.m */; }; + 4096BDDE1B2024DA0048B07E /* MobilySpinnerViewFadingCircleAlt.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF21B2024DA0048B07E /* MobilySpinnerViewFadingCircleAlt.m */; }; + 4096BDDF1B2024DA0048B07E /* MobilySpinnerViewPlane.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF31B2024DA0048B07E /* MobilySpinnerViewPlane.m */; }; + 4096BDE01B2024DA0048B07E /* MobilySpinnerViewPlane.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF31B2024DA0048B07E /* MobilySpinnerViewPlane.m */; }; + 4096BDE11B2024DA0048B07E /* MobilySpinnerViewPulse.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF41B2024DA0048B07E /* MobilySpinnerViewPulse.m */; }; + 4096BDE21B2024DA0048B07E /* MobilySpinnerViewPulse.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF41B2024DA0048B07E /* MobilySpinnerViewPulse.m */; }; + 4096BDE31B2024DA0048B07E /* MobilySpinnerViewThreeBounce.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF51B2024DA0048B07E /* MobilySpinnerViewThreeBounce.m */; }; + 4096BDE41B2024DA0048B07E /* MobilySpinnerViewThreeBounce.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF51B2024DA0048B07E /* MobilySpinnerViewThreeBounce.m */; }; + 4096BDE51B2024DA0048B07E /* MobilySpinnerViewWanderingCubes.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF61B2024DA0048B07E /* MobilySpinnerViewWanderingCubes.m */; }; + 4096BDE61B2024DA0048B07E /* MobilySpinnerViewWanderingCubes.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF61B2024DA0048B07E /* MobilySpinnerViewWanderingCubes.m */; }; + 4096BDE71B2024DA0048B07E /* MobilySpinnerViewWave.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF71B2024DA0048B07E /* MobilySpinnerViewWave.m */; }; + 4096BDE81B2024DA0048B07E /* MobilySpinnerViewWave.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF71B2024DA0048B07E /* MobilySpinnerViewWave.m */; }; + 4096BDE91B2024DA0048B07E /* MobilySpinnerViewWordPress.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF81B2024DA0048B07E /* MobilySpinnerViewWordPress.m */; }; + 4096BDEA1B2024DA0048B07E /* MobilySpinnerViewWordPress.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCF81B2024DA0048B07E /* MobilySpinnerViewWordPress.m */; }; + 4096BDEB1B2024DA0048B07E /* MobilyStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCF91B2024DA0048B07E /* MobilyStyle.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDEC1B2024DA0048B07E /* MobilyStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCFA1B2024DA0048B07E /* MobilyStyle.m */; }; + 4096BDED1B2024DA0048B07E /* MobilyStyle.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCFA1B2024DA0048B07E /* MobilyStyle.m */; }; + 4096BDEE1B2024DA0048B07E /* MobilyTabBarController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCFB1B2024DA0048B07E /* MobilyTabBarController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDEF1B2024DA0048B07E /* MobilyTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCFC1B2024DA0048B07E /* MobilyTabBarController.m */; }; + 4096BDF01B2024DA0048B07E /* MobilyTabBarController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCFC1B2024DA0048B07E /* MobilyTabBarController.m */; }; + 4096BDF11B2024DA0048B07E /* MobilyTableView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCFD1B2024DA0048B07E /* MobilyTableView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDF21B2024DA0048B07E /* MobilyTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCFE1B2024DA0048B07E /* MobilyTableView.m */; }; + 4096BDF31B2024DA0048B07E /* MobilyTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BCFE1B2024DA0048B07E /* MobilyTableView.m */; }; + 4096BDF41B2024DA0048B07E /* MobilyTaskManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BCFF1B2024DA0048B07E /* MobilyTaskManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDF51B2024DA0048B07E /* MobilyTaskManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD001B2024DA0048B07E /* MobilyTaskManager.m */; }; + 4096BDF61B2024DA0048B07E /* MobilyTaskManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD001B2024DA0048B07E /* MobilyTaskManager.m */; }; + 4096BDF71B2024DA0048B07E /* MobilyTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BD011B2024DA0048B07E /* MobilyTextField.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDF81B2024DA0048B07E /* MobilyTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD021B2024DA0048B07E /* MobilyTextField.m */; }; + 4096BDF91B2024DA0048B07E /* MobilyTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD021B2024DA0048B07E /* MobilyTextField.m */; }; + 4096BDFA1B2024DA0048B07E /* MobilyTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BD031B2024DA0048B07E /* MobilyTextView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDFB1B2024DA0048B07E /* MobilyTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD041B2024DA0048B07E /* MobilyTextView.m */; }; + 4096BDFC1B2024DA0048B07E /* MobilyTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD041B2024DA0048B07E /* MobilyTextView.m */; }; + 4096BDFD1B2024DA0048B07E /* MobilyTimeout.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BD051B2024DA0048B07E /* MobilyTimeout.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BDFE1B2024DA0048B07E /* MobilyTimeout.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD061B2024DA0048B07E /* MobilyTimeout.m */; }; + 4096BDFF1B2024DA0048B07E /* MobilyTimeout.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD061B2024DA0048B07E /* MobilyTimeout.m */; }; + 4096BE001B2024DA0048B07E /* MobilyTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BD071B2024DA0048B07E /* MobilyTimer.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BE011B2024DA0048B07E /* MobilyTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD081B2024DA0048B07E /* MobilyTimer.m */; }; + 4096BE021B2024DA0048B07E /* MobilyTimer.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD081B2024DA0048B07E /* MobilyTimer.m */; }; + 4096BE031B2024DA0048B07E /* MobilyTransitionController+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BD091B2024DA0048B07E /* MobilyTransitionController+Private.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BE041B2024DA0048B07E /* MobilyTransitionController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BD0A1B2024DA0048B07E /* MobilyTransitionController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BE051B2024DA0048B07E /* MobilyTransitionController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD0B1B2024DA0048B07E /* MobilyTransitionController.m */; }; + 4096BE061B2024DA0048B07E /* MobilyTransitionController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD0B1B2024DA0048B07E /* MobilyTransitionController.m */; }; + 4096BE071B2024DA0048B07E /* MobilyTransitionControllerCards.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD0C1B2024DA0048B07E /* MobilyTransitionControllerCards.m */; }; + 4096BE081B2024DA0048B07E /* MobilyTransitionControllerCards.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD0C1B2024DA0048B07E /* MobilyTransitionControllerCards.m */; }; + 4096BE091B2024DA0048B07E /* MobilyTransitionControllerCrossFade.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD0D1B2024DA0048B07E /* MobilyTransitionControllerCrossFade.m */; }; + 4096BE0A1B2024DA0048B07E /* MobilyTransitionControllerCrossFade.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD0D1B2024DA0048B07E /* MobilyTransitionControllerCrossFade.m */; }; + 4096BE0B1B2024DA0048B07E /* MobilyTransitionControllerSlide.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD0E1B2024DA0048B07E /* MobilyTransitionControllerSlide.m */; }; + 4096BE0C1B2024DA0048B07E /* MobilyTransitionControllerSlide.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD0E1B2024DA0048B07E /* MobilyTransitionControllerSlide.m */; }; + 4096BE0D1B2024DA0048B07E /* MobilyUI.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BD0F1B2024DA0048B07E /* MobilyUI.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BE0E1B2024DA0048B07E /* MobilyUI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD101B2024DA0048B07E /* MobilyUI.m */; }; + 4096BE0F1B2024DA0048B07E /* MobilyUI.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD101B2024DA0048B07E /* MobilyUI.m */; }; + 4096BE101B2024DA0048B07E /* MobilyValidatedObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BD111B2024DA0048B07E /* MobilyValidatedObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BE111B2024DA0048B07E /* MobilyView.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BD121B2024DA0048B07E /* MobilyView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BE121B2024DA0048B07E /* MobilyView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD131B2024DA0048B07E /* MobilyView.m */; }; + 4096BE131B2024DA0048B07E /* MobilyView.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD131B2024DA0048B07E /* MobilyView.m */; }; + 4096BE141B2024DA0048B07E /* MobilyViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BD141B2024DA0048B07E /* MobilyViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BE151B2024DA0048B07E /* MobilyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD151B2024DA0048B07E /* MobilyViewController.m */; }; + 4096BE161B2024DA0048B07E /* MobilyViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD151B2024DA0048B07E /* MobilyViewController.m */; }; + 4096BE171B2024DA0048B07E /* MobilyWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BD161B2024DA0048B07E /* MobilyWindow.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BE181B2024DA0048B07E /* MobilyWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD171B2024DA0048B07E /* MobilyWindow.m */; }; + 4096BE191B2024DA0048B07E /* MobilyWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BD171B2024DA0048B07E /* MobilyWindow.m */; }; + 4096BE261B2024E30048B07E /* MobilySocial.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BE1B1B2024E30048B07E /* MobilySocial.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BE271B2024E30048B07E /* MobilySocialFacebookProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BE1C1B2024E30048B07E /* MobilySocialFacebookProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BE281B2024E30048B07E /* MobilySocialFacebookProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BE1D1B2024E30048B07E /* MobilySocialFacebookProvider.m */; }; + 4096BE291B2024E30048B07E /* MobilySocialFacebookProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BE1D1B2024E30048B07E /* MobilySocialFacebookProvider.m */; }; + 4096BE2A1B2024E30048B07E /* MobilySocialManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BE1E1B2024E30048B07E /* MobilySocialManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BE2B1B2024E30048B07E /* MobilySocialManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BE1F1B2024E30048B07E /* MobilySocialManager.m */; }; + 4096BE2C1B2024E30048B07E /* MobilySocialManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BE1F1B2024E30048B07E /* MobilySocialManager.m */; }; + 4096BE2D1B2024E30048B07E /* MobilySocialProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BE201B2024E30048B07E /* MobilySocialProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BE2E1B2024E30048B07E /* MobilySocialProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BE211B2024E30048B07E /* MobilySocialProvider.m */; }; + 4096BE2F1B2024E30048B07E /* MobilySocialProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BE211B2024E30048B07E /* MobilySocialProvider.m */; }; + 4096BE301B2024E30048B07E /* MobilySocialTwitterProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BE221B2024E30048B07E /* MobilySocialTwitterProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BE311B2024E30048B07E /* MobilySocialTwitterProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BE231B2024E30048B07E /* MobilySocialTwitterProvider.m */; }; + 4096BE321B2024E30048B07E /* MobilySocialTwitterProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BE231B2024E30048B07E /* MobilySocialTwitterProvider.m */; }; + 4096BE331B2024E30048B07E /* MobilySocialVKontakteProvider.h in Headers */ = {isa = PBXBuildFile; fileRef = 4096BE241B2024E30048B07E /* MobilySocialVKontakteProvider.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4096BE341B2024E30048B07E /* MobilySocialVKontakteProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BE251B2024E30048B07E /* MobilySocialVKontakteProvider.m */; }; + 4096BE351B2024E30048B07E /* MobilySocialVKontakteProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 4096BE251B2024E30048B07E /* MobilySocialVKontakteProvider.m */; }; + 40B760391ADFA32000F0CB09 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 40B760341ADFA31F00F0CB09 /* AVFoundation.framework */; }; + 40B7603A1ADFA32000F0CB09 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 40B760351ADFA31F00F0CB09 /* CoreFoundation.framework */; }; + 40B7603B1ADFA32000F0CB09 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 40B760361ADFA31F00F0CB09 /* CoreGraphics.framework */; }; + 40B7603C1ADFA32000F0CB09 /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 40B760371ADFA31F00F0CB09 /* CoreText.framework */; }; + 40B7603D1ADFA32000F0CB09 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 40B760381ADFA31F00F0CB09 /* Foundation.framework */; }; + 40B760421ADFA35600F0CB09 /* Accounts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 40B7603E1ADFA35600F0CB09 /* Accounts.framework */; }; + 40B760431ADFA35600F0CB09 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 40B7603F1ADFA35600F0CB09 /* CoreData.framework */; }; + 40B760441ADFA35600F0CB09 /* Social.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 40B760401ADFA35600F0CB09 /* Social.framework */; }; + 40B760451ADFA35600F0CB09 /* Twitter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 40B760411ADFA35600F0CB09 /* Twitter.framework */; }; + 40D005D81B3BFD1800DD7DA6 /* MobilyStore.h in Headers */ = {isa = PBXBuildFile; fileRef = 40D005D71B3BFD1800DD7DA6 /* MobilyStore.h */; }; + 40D09BEE1B5F819300C9F4CB /* MobilyLayoutView.h in Headers */ = {isa = PBXBuildFile; fileRef = 40D09BEC1B5F819300C9F4CB /* MobilyLayoutView.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 40D09BEF1B5F819300C9F4CB /* MobilyLayoutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40D09BED1B5F819300C9F4CB /* MobilyLayoutView.m */; }; + 40D09BF01B5F819300C9F4CB /* MobilyLayoutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40D09BED1B5F819300C9F4CB /* MobilyLayoutView.m */; }; + 40FF59D71B4421410028CAB2 /* MobilyNotificationManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 40FF59D51B4421410028CAB2 /* MobilyNotificationManager.h */; }; + 40FF59D81B4421410028CAB2 /* MobilyNotificationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40FF59D61B4421410028CAB2 /* MobilyNotificationManager.m */; }; + 40FF59D91B4421410028CAB2 /* MobilyNotificationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 40FF59D61B4421410028CAB2 /* MobilyNotificationManager.m */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 4080D23E1B3B44E500328837 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 40B75B2A1ADEE82900F0CB09 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 40B75EBC1ADF9EE500F0CB09; + remoteInfo = "MobilyCore-Library"; + }; + 4080D2421B3B44F300328837 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 40B75B2A1ADEE82900F0CB09 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4096BC201B20230E0048B07E; + remoteInfo = "MobilyCore-Framework"; + }; + 40B760191ADFA05000F0CB09 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 40B75B2A1ADEE82900F0CB09 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 40B75EBC1ADF9EE500F0CB09; + remoteInfo = MobilyCore; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXFileReference section */ - 2BBC62D562492FDF2CDB1707 /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; - 40081A8C1A27122200F2FBE6 /* MobilyControllerSlideMenu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyControllerSlideMenu.h; sourceTree = ""; }; - 40081A8D1A27122200F2FBE6 /* MobilyControllerSlideMenu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyControllerSlideMenu.m; sourceTree = ""; }; - 40081A901A27122200F2FBE6 /* SlideNavigationContorllerAnimator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlideNavigationContorllerAnimator.h; sourceTree = ""; }; - 40081A911A27122200F2FBE6 /* SlideNavigationContorllerAnimatorFade.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlideNavigationContorllerAnimatorFade.h; sourceTree = ""; }; - 40081A921A27122200F2FBE6 /* SlideNavigationContorllerAnimatorFade.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SlideNavigationContorllerAnimatorFade.m; sourceTree = ""; }; - 40081A931A27122200F2FBE6 /* SlideNavigationContorllerAnimatorScale.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlideNavigationContorllerAnimatorScale.h; sourceTree = ""; }; - 40081A941A27122200F2FBE6 /* SlideNavigationContorllerAnimatorScale.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SlideNavigationContorllerAnimatorScale.m; sourceTree = ""; }; - 40081A951A27122200F2FBE6 /* SlideNavigationContorllerAnimatorScaleAndFade.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlideNavigationContorllerAnimatorScaleAndFade.h; sourceTree = ""; }; - 40081A961A27122200F2FBE6 /* SlideNavigationContorllerAnimatorScaleAndFade.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SlideNavigationContorllerAnimatorScaleAndFade.m; sourceTree = ""; }; - 40081A971A27122200F2FBE6 /* SlideNavigationContorllerAnimatorSlide.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlideNavigationContorllerAnimatorSlide.h; sourceTree = ""; }; - 40081A981A27122200F2FBE6 /* SlideNavigationContorllerAnimatorSlide.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SlideNavigationContorllerAnimatorSlide.m; sourceTree = ""; }; - 40081A991A27122200F2FBE6 /* SlideNavigationContorllerAnimatorSlideAndFade.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlideNavigationContorllerAnimatorSlideAndFade.h; sourceTree = ""; }; - 40081A9A1A27122200F2FBE6 /* SlideNavigationContorllerAnimatorSlideAndFade.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SlideNavigationContorllerAnimatorSlideAndFade.m; sourceTree = ""; }; - 40081A9C1A27122200F2FBE6 /* menu-button.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu-button.png"; sourceTree = ""; }; - 40081A9D1A27122300F2FBE6 /* menu-button@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "menu-button@2x.png"; sourceTree = ""; }; - 40081A9E1A27122300F2FBE6 /* SlideNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SlideNavigationController.h; sourceTree = ""; }; - 40081A9F1A27122300F2FBE6 /* SlideNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SlideNavigationController.m; sourceTree = ""; }; - 400B4D061A19E29900F2B61E /* MobilyViewTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyViewTable.h; sourceTree = ""; }; - 400B4D071A19E29900F2B61E /* MobilyViewTable.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyViewTable.m; sourceTree = ""; }; - 400B4D091A1A0D6700F2B61E /* ExampleControllerMainCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ExampleControllerMainCell.xib; sourceTree = ""; }; - 401FEE4F18A3F92800B445EB /* Mobily.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Mobily.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 401FEE5218A3F92800B445EB /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 401FEE5418A3F92800B445EB /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - 401FEE5618A3F92800B445EB /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - 401FEE8318A3FAE600B445EB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 401FEE8418A3FAE600B445EB /* ExampleApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExampleApplication.h; sourceTree = ""; }; - 401FEE8518A3FAE600B445EB /* ExampleApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExampleApplication.m; sourceTree = ""; }; - 401FEE8618A3FAE600B445EB /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 401FEE8718A3FAE600B445EB /* Mobily-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Mobily-Info.plist"; sourceTree = ""; }; - 401FEE8818A3FAE600B445EB /* Mobily-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Mobily-Prefix.pch"; sourceTree = ""; }; - 401FEE9018A3FAF100B445EB /* MobilyCG.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyCG.m; sourceTree = ""; }; - 401FEE9118A3FAF100B445EB /* MobilyCG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyCG.h; sourceTree = ""; }; - 401FEE9318A3FAF100B445EB /* MobilyCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyCore.h; sourceTree = ""; }; - 401FEE9618A3FAF100B445EB /* MobilyEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyEvent.h; sourceTree = ""; }; - 401FEE9718A3FAF100B445EB /* MobilyEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyEvent.m; sourceTree = ""; }; - 401FEE9A18A3FAF100B445EB /* MobilyHttpQuery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyHttpQuery.h; sourceTree = ""; }; - 401FEE9B18A3FAF100B445EB /* MobilyHttpQuery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyHttpQuery.m; sourceTree = ""; }; - 401FEE9C18A3FAF100B445EB /* MobilyKVO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyKVO.h; sourceTree = ""; }; - 401FEE9D18A3FAF100B445EB /* MobilyKVO.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyKVO.m; sourceTree = ""; }; - 401FEE9E18A3FAF100B445EB /* MobilyNS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyNS.h; sourceTree = ""; }; - 401FEE9F18A3FAF100B445EB /* MobilyNS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyNS.m; sourceTree = ""; }; - 401FEEA018A3FAF100B445EB /* MobilyStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyStorage.h; sourceTree = ""; }; - 401FEEA118A3FAF100B445EB /* MobilyStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyStorage.m; sourceTree = ""; }; - 401FEEA218A3FAF100B445EB /* MobilyTaskManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyTaskManager.h; sourceTree = ""; }; - 401FEEA318A3FAF100B445EB /* MobilyTaskManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTaskManager.m; sourceTree = ""; }; - 401FEEB518A3FAF100B445EB /* MobilyApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyApplication.h; sourceTree = ""; }; - 401FEEB618A3FAF100B445EB /* MobilyApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyApplication.m; sourceTree = ""; }; - 401FEEB718A3FAF100B445EB /* MobilyContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyContext.h; sourceTree = ""; }; - 401FEEB818A3FAF100B445EB /* MobilyContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyContext.m; sourceTree = ""; }; - 401FEEB918A3FAF100B445EB /* MobilyController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyController.h; sourceTree = ""; }; - 401FEEBA18A3FAF100B445EB /* MobilyController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyController.m; sourceTree = ""; }; - 401FEEBB18A3FAF100B445EB /* MobilyControllerNavigation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyControllerNavigation.h; sourceTree = ""; }; - 401FEEBC18A3FAF100B445EB /* MobilyControllerNavigation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyControllerNavigation.m; sourceTree = ""; }; - 401FEEBD18A3FAF100B445EB /* MobilyControllerTabBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyControllerTabBar.h; sourceTree = ""; }; - 401FEEBE18A3FAF100B445EB /* MobilyControllerTabBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyControllerTabBar.m; sourceTree = ""; }; - 401FEEBF18A3FAF100B445EB /* MobilyControllerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyControllerView.h; sourceTree = ""; }; - 401FEEC018A3FAF100B445EB /* MobilyControllerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyControllerView.m; sourceTree = ""; }; - 401FEEC718A3FAF100B445EB /* MobilyBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyBuilder.h; sourceTree = ""; }; - 401FEEC818A3FAF100B445EB /* MobilyBuilderForm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyBuilderForm.m; sourceTree = ""; }; - 401FEEC918A3FAF100B445EB /* MobilyUI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyUI.h; sourceTree = ""; }; - 401FEECA18A3FAF100B445EB /* MobilyUI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyUI.m; sourceTree = ""; }; - 401FEEDF18A3FAF100B445EB /* MobilyWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyWindow.h; sourceTree = ""; }; - 401FEEE018A3FAF100B445EB /* MobilyWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyWindow.m; sourceTree = ""; }; - 401FEF1818A3FE3200B445EB /* Application.mobily */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Application.mobily; sourceTree = ""; }; - 401FEF1918A3FE3200B445EB /* Presets.mobily */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = Presets.mobily; sourceTree = ""; }; - 403258091A0BBBA700949E8F /* MobilyViewScroll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyViewScroll.h; sourceTree = ""; }; - 4032580A1A0BBBA700949E8F /* MobilyViewScroll.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyViewScroll.m; sourceTree = ""; }; - 407903CF1943079600EC8855 /* Mobily.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Mobily.podspec; sourceTree = ""; }; - 407903D119464A1E00EC8855 /* MobilyBuilderPreset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyBuilderPreset.m; sourceTree = ""; }; - 407989E21947834F00A04686 /* MobilyTransitionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyTransitionController.h; sourceTree = ""; }; - 407989E31947834F00A04686 /* MobilyTransitionController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTransitionController.m; sourceTree = ""; }; - 407989E5194788EE00A04686 /* MobilyTransitionControllerCards.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTransitionControllerCards.m; sourceTree = ""; }; - 407989E6194788EE00A04686 /* MobilyTransitionControllerCrossFade.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTransitionControllerCrossFade.m; sourceTree = ""; }; - 407989EA19484C9700A04686 /* MobilyControllerDynamicsDrawer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyControllerDynamicsDrawer.h; sourceTree = ""; }; - 407989EB19484C9700A04686 /* MobilyControllerDynamicsDrawer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyControllerDynamicsDrawer.m; sourceTree = ""; }; - 40798A291948ABAF00A04686 /* MobilyRegExpParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyRegExpParser.h; sourceTree = ""; }; - 40798A2A1948ABAF00A04686 /* MobilyRegExpParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyRegExpParser.m; sourceTree = ""; }; - 40798A2D1948AC0600A04686 /* MobilyViewFieldDate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyViewFieldDate.h; sourceTree = ""; }; - 40798A2E1948AC0600A04686 /* MobilyViewFieldDate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyViewFieldDate.m; sourceTree = ""; }; - 40798A301948AC0600A04686 /* MobilyViewFieldList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyViewFieldList.h; sourceTree = ""; }; - 40798A311948AC0600A04686 /* MobilyViewFieldList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyViewFieldList.m; sourceTree = ""; }; - 40798A331948AC0600A04686 /* MobilyViewFieldText.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyViewFieldText.h; sourceTree = ""; }; - 40798A341948AC0600A04686 /* MobilyViewFieldText.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyViewFieldText.m; sourceTree = ""; }; - 40798A391948AFC400A04686 /* MobilyViewImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyViewImage.h; sourceTree = ""; }; - 40798A3A1948AFC400A04686 /* MobilyViewImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyViewImage.m; sourceTree = ""; }; - 40798A3D1948C0F700A04686 /* MobilyViewElementsLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyViewElementsLayout.h; sourceTree = ""; }; - 40798A3E1948C0F700A04686 /* MobilyViewElementsLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyViewElementsLayout.m; sourceTree = ""; }; - 40798A3F1948C0F700A04686 /* MobilyViewElements.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyViewElements.h; sourceTree = ""; }; - 40798A401948C0F700A04686 /* MobilyViewElements.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyViewElements.m; sourceTree = ""; }; - 5A2438BFA45DA754D1C37067 /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; - 9AA83B7A19E536FE009F6C5F /* ExampleControllerMain.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ExampleControllerMain.xib; sourceTree = ""; }; - F16AA68F9FE04603B1D99102 /* libPods.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPods.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 4002F3B11B3D425E00961E90 /* MobilyPressAndHoldGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyPressAndHoldGestureRecognizer.h; sourceTree = ""; }; + 4002F3B21B3D425E00961E90 /* MobilyPressAndHoldGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyPressAndHoldGestureRecognizer.m; sourceTree = ""; }; + 4005C07D1B1E13E3009A2185 /* Bolts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Bolts.framework; sourceTree = ""; }; + 4005C07E1B1E13E3009A2185 /* FBAudienceNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FBAudienceNetwork.framework; sourceTree = ""; }; + 4005C07F1B1E13E3009A2185 /* FBSDKCoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FBSDKCoreKit.framework; sourceTree = ""; }; + 4005C0801B1E13E3009A2185 /* FBSDKLoginKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FBSDKLoginKit.framework; sourceTree = ""; }; + 4005C0811B1E13E3009A2185 /* FBSDKMessengerShareKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FBSDKMessengerShareKit.framework; sourceTree = ""; }; + 4005C0821B1E13E3009A2185 /* FBSDKShareKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = FBSDKShareKit.framework; sourceTree = ""; }; + 4005C0831B1E13E4009A2185 /* TwitterCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = TwitterCore.framework; sourceTree = ""; }; + 4005C0841B1E13E4009A2185 /* TwitterKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = TwitterKit.framework; sourceTree = ""; }; + 4005C0851B1E13E4009A2185 /* VKSdk.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = VKSdk.framework; sourceTree = ""; }; + 401890091B70F08E00440DF7 /* MobilyBadgeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyBadgeView.h; sourceTree = ""; }; + 4018900A1B70F08E00440DF7 /* MobilyBadgeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyBadgeView.m; sourceTree = ""; }; + 4064D18D1B577A6400F2F0FF /* MobilyImageCropController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyImageCropController.h; sourceTree = ""; }; + 4064D18E1B577A6400F2F0FF /* MobilyImageCropController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyImageCropController.m; sourceTree = ""; }; + 4064D1921B577D0900F2F0FF /* MobilyTouchView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyTouchView.h; sourceTree = ""; }; + 4064D1931B577D0900F2F0FF /* MobilyTouchView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTouchView.m; sourceTree = ""; }; + 4080D2281B3B44AB00328837 /* libMobilyStore.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMobilyStore.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 4080D23C1B3B44B800328837 /* MobilyStore-Framework.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = "MobilyStore-Framework.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 4080D23D1B3B44B800328837 /* MobilyStore.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = MobilyStore.plist; path = /Users/fgengine/Dropbox/ObjC/GamesLooper/VoicyFM/MobilyFramework/Support/MobilyStore.plist; sourceTree = ""; }; + 4080D2401B3B44EB00328837 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; + 4080D2461B3B454200328837 /* MobilyStoreManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyStoreManager.h; sourceTree = ""; }; + 4080D2471B3B454200328837 /* MobilyStoreManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyStoreManager.m; sourceTree = ""; }; + 4096BC211B20230E0048B07E /* MobilyCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MobilyCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 4096BC431B20237D0048B07E /* MobilySocial.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MobilySocial.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 4096BC6D1B2024C00048B07E /* MobilyCore.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = MobilyCore.plist; sourceTree = ""; }; + 4096BC6E1B2024C00048B07E /* MobilySocial.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = MobilySocial.plist; sourceTree = ""; }; + 4096BC701B2024DA0048B07E /* MobilyActivityView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyActivityView.h; sourceTree = ""; }; + 4096BC711B2024DA0048B07E /* MobilyActivityView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyActivityView.m; sourceTree = ""; }; + 4096BC721B2024DA0048B07E /* MobilyApiManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyApiManager.h; sourceTree = ""; }; + 4096BC731B2024DA0048B07E /* MobilyApiManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyApiManager.m; sourceTree = ""; }; + 4096BC741B2024DA0048B07E /* MobilyApiProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyApiProvider.h; sourceTree = ""; }; + 4096BC751B2024DA0048B07E /* MobilyApiProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyApiProvider.m; sourceTree = ""; }; + 4096BC761B2024DA0048B07E /* MobilyApiRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyApiRequest.h; sourceTree = ""; }; + 4096BC771B2024DA0048B07E /* MobilyApiRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyApiRequest.m; sourceTree = ""; }; + 4096BC781B2024DA0048B07E /* MobilyApiResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyApiResponse.h; sourceTree = ""; }; + 4096BC791B2024DA0048B07E /* MobilyApiResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyApiResponse.m; sourceTree = ""; }; + 4096BC7A1B2024DA0048B07E /* MobilyApplication.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyApplication.h; sourceTree = ""; }; + 4096BC7B1B2024DA0048B07E /* MobilyApplication.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyApplication.m; sourceTree = ""; }; + 4096BC7C1B2024DA0048B07E /* MobilyAudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyAudioPlayer.h; sourceTree = ""; }; + 4096BC7D1B2024DA0048B07E /* MobilyAudioPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyAudioPlayer.m; sourceTree = ""; }; + 4096BC7E1B2024DA0048B07E /* MobilyAudioRecorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyAudioRecorder.h; sourceTree = ""; }; + 4096BC7F1B2024DA0048B07E /* MobilyAudioRecorder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyAudioRecorder.m; sourceTree = ""; }; + 4096BC801B2024DA0048B07E /* MobilyAV.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyAV.h; sourceTree = ""; }; + 4096BC811B2024DA0048B07E /* MobilyBlurView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyBlurView.h; sourceTree = ""; }; + 4096BC821B2024DA0048B07E /* MobilyBlurView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyBlurView.m; sourceTree = ""; }; + 4096BC831B2024DA0048B07E /* MobilyBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyBuilder.h; sourceTree = ""; }; + 4096BC841B2024DA0048B07E /* MobilyBuilderForm.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyBuilderForm.m; sourceTree = ""; }; + 4096BC851B2024DA0048B07E /* MobilyBuilderPreset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyBuilderPreset.m; sourceTree = ""; }; + 4096BC861B2024DA0048B07E /* MobilyButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyButton.h; sourceTree = ""; }; + 4096BC871B2024DA0048B07E /* MobilyButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyButton.m; sourceTree = ""; }; + 4096BC881B2024DA0048B07E /* MobilyCA.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyCA.h; sourceTree = ""; }; + 4096BC891B2024DA0048B07E /* MobilyCA.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyCA.m; sourceTree = ""; }; + 4096BC8A1B2024DA0048B07E /* MobilyCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyCache.h; sourceTree = ""; }; + 4096BC8B1B2024DA0048B07E /* MobilyCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyCache.m; sourceTree = ""; }; + 4096BC8C1B2024DA0048B07E /* MobilyCG.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyCG.h; sourceTree = ""; }; + 4096BC8D1B2024DA0048B07E /* MobilyCG.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyCG.m; sourceTree = ""; }; + 4096BC8E1B2024DA0048B07E /* MobilyContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyContext.h; sourceTree = ""; }; + 4096BC8F1B2024DA0048B07E /* MobilyContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyContext.m; sourceTree = ""; }; + 4096BC901B2024DA0048B07E /* MobilyController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyController.h; sourceTree = ""; }; + 4096BC911B2024DA0048B07E /* MobilyController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyController.m; sourceTree = ""; }; + 4096BC921B2024DA0048B07E /* MobilyCore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyCore.h; sourceTree = ""; }; + 4096BC931B2024DA0048B07E /* MobilyData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyData.h; sourceTree = ""; }; + 4096BC941B2024DA0048B07E /* MobilyDataCell+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MobilyDataCell+Private.h"; sourceTree = ""; }; + 4096BC951B2024DA0048B07E /* MobilyDataCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyDataCell.h; sourceTree = ""; }; + 4096BC961B2024DA0048B07E /* MobilyDataCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDataCell.m; sourceTree = ""; }; + 4096BC971B2024DA0048B07E /* MobilyDataCellSwipe.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDataCellSwipe.m; sourceTree = ""; }; + 4096BC981B2024DA0048B07E /* MobilyDataContainer+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MobilyDataContainer+Private.h"; sourceTree = ""; }; + 4096BC991B2024DA0048B07E /* MobilyDataContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyDataContainer.h; sourceTree = ""; }; + 4096BC9A1B2024DA0048B07E /* MobilyDataContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDataContainer.m; sourceTree = ""; }; + 4096BC9B1B2024DA0048B07E /* MobilyDataContainerCalendar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDataContainerCalendar.m; sourceTree = ""; }; + 4096BC9C1B2024DA0048B07E /* MobilyDataContainerCalendarDays.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDataContainerCalendarDays.m; sourceTree = ""; }; + 4096BC9D1B2024DA0048B07E /* MobilyDataContainerItems.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDataContainerItems.m; sourceTree = ""; }; + 4096BC9E1B2024DA0048B07E /* MobilyDataContainerItemsFlow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDataContainerItemsFlow.m; sourceTree = ""; }; + 4096BC9F1B2024DA0048B07E /* MobilyDataContainerItemsGrid.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDataContainerItemsGrid.m; sourceTree = ""; }; + 4096BCA01B2024DA0048B07E /* MobilyDataContainerItemsList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDataContainerItemsList.m; sourceTree = ""; }; + 4096BCA11B2024DA0048B07E /* MobilyDataContainerSections.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDataContainerSections.m; sourceTree = ""; }; + 4096BCA21B2024DA0048B07E /* MobilyDataContainerSectionsList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDataContainerSectionsList.m; sourceTree = ""; }; + 4096BCA31B2024DA0048B07E /* MobilyDataItem+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MobilyDataItem+Private.h"; sourceTree = ""; }; + 4096BCA41B2024DA0048B07E /* MobilyDataItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyDataItem.h; sourceTree = ""; }; + 4096BCA51B2024DA0048B07E /* MobilyDataItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDataItem.m; sourceTree = ""; }; + 4096BCA61B2024DA0048B07E /* MobilyDataRefreshView+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MobilyDataRefreshView+Private.h"; sourceTree = ""; }; + 4096BCA71B2024DA0048B07E /* MobilyDataRefreshView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyDataRefreshView.h; sourceTree = ""; }; + 4096BCA81B2024DA0048B07E /* MobilyDataRefreshView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDataRefreshView.m; sourceTree = ""; }; + 4096BCA91B2024DA0048B07E /* MobilyDataView+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MobilyDataView+Private.h"; sourceTree = ""; }; + 4096BCAA1B2024DA0048B07E /* MobilyDataView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyDataView.h; sourceTree = ""; }; + 4096BCAB1B2024DA0048B07E /* MobilyDataView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDataView.m; sourceTree = ""; }; + 4096BCAC1B2024DA0048B07E /* MobilyDateField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyDateField.h; sourceTree = ""; }; + 4096BCAD1B2024DA0048B07E /* MobilyDateField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDateField.m; sourceTree = ""; }; + 4096BCAE1B2024DA0048B07E /* MobilyDefines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyDefines.h; sourceTree = ""; }; + 4096BCAF1B2024DA0048B07E /* MobilyDialogController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyDialogController.h; sourceTree = ""; }; + 4096BCB01B2024DA0048B07E /* MobilyDialogController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDialogController.m; sourceTree = ""; }; + 4096BCB11B2024DA0048B07E /* MobilyDownloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyDownloader.h; sourceTree = ""; }; + 4096BCB21B2024DA0048B07E /* MobilyDownloader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyDownloader.m; sourceTree = ""; }; + 4096BCB31B2024DA0048B07E /* MobilyEvent+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MobilyEvent+Private.h"; sourceTree = ""; }; + 4096BCB41B2024DA0048B07E /* MobilyEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyEvent.h; sourceTree = ""; }; + 4096BCB51B2024DA0048B07E /* MobilyEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyEvent.m; sourceTree = ""; }; + 4096BCB61B2024DA0048B07E /* MobilyFieldValidation+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MobilyFieldValidation+Private.h"; sourceTree = ""; }; + 4096BCB71B2024DA0048B07E /* MobilyFieldValidation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyFieldValidation.h; sourceTree = ""; }; + 4096BCB81B2024DA0048B07E /* MobilyFieldValidation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyFieldValidation.m; sourceTree = ""; }; + 4096BCB91B2024DA0048B07E /* MobilyGeoLocationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyGeoLocationManager.h; sourceTree = ""; }; + 4096BCBA1B2024DA0048B07E /* MobilyGeoLocationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyGeoLocationManager.m; sourceTree = ""; }; + 4096BCBB1B2024DA0048B07E /* MobilyGrid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyGrid.h; sourceTree = ""; }; + 4096BCBC1B2024DA0048B07E /* MobilyGrid.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyGrid.m; sourceTree = ""; }; + 4096BCBD1B2024DA0048B07E /* MobilyHttpQuery+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MobilyHttpQuery+Private.h"; sourceTree = ""; }; + 4096BCBE1B2024DA0048B07E /* MobilyHttpQuery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyHttpQuery.h; sourceTree = ""; }; + 4096BCBF1B2024DA0048B07E /* MobilyHttpQuery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyHttpQuery.m; sourceTree = ""; }; + 4096BCC01B2024DA0048B07E /* MobilyImageView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyImageView.h; sourceTree = ""; }; + 4096BCC11B2024DA0048B07E /* MobilyImageView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyImageView.m; sourceTree = ""; }; + 4096BCC21B2024DA0048B07E /* MobilyKVO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyKVO.h; sourceTree = ""; }; + 4096BCC31B2024DA0048B07E /* MobilyKVO.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyKVO.m; sourceTree = ""; }; + 4096BCC41B2024DA0048B07E /* MobilyListField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyListField.h; sourceTree = ""; }; + 4096BCC51B2024DA0048B07E /* MobilyListField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyListField.m; sourceTree = ""; }; + 4096BCC61B2024DA0048B07E /* MobilyLoadedView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyLoadedView.h; sourceTree = ""; }; + 4096BCC71B2024DA0048B07E /* MobilyLoadedView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyLoadedView.m; sourceTree = ""; }; + 4096BCC81B2024DA0048B07E /* MobilyLockScreenController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyLockScreenController.h; sourceTree = ""; }; + 4096BCC91B2024DA0048B07E /* MobilyLockScreenController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyLockScreenController.m; sourceTree = ""; }; + 4096BCCA1B2024DA0048B07E /* MobilyLockScreenPincodeView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyLockScreenPincodeView.h; sourceTree = ""; }; + 4096BCCB1B2024DA0048B07E /* MobilyLockScreenPincodeView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyLockScreenPincodeView.m; sourceTree = ""; }; + 4096BCCC1B2024DA0048B07E /* MobilyMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyMap.h; sourceTree = ""; }; + 4096BCCD1B2024DA0048B07E /* MobilyMap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyMap.m; sourceTree = ""; }; + 4096BCCE1B2024DA0048B07E /* MobilyModel+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MobilyModel+Private.h"; sourceTree = ""; }; + 4096BCCF1B2024DA0048B07E /* MobilyModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyModel.h; sourceTree = ""; }; + 4096BCD01B2024DA0048B07E /* MobilyModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyModel.m; sourceTree = ""; }; + 4096BCD11B2024DA0048B07E /* MobilyModelJson.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyModelJson.h; sourceTree = ""; }; + 4096BCD21B2024DA0048B07E /* MobilyModelJson.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyModelJson.m; sourceTree = ""; }; + 4096BCD31B2024DA0048B07E /* MobilyNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyNavigationController.h; sourceTree = ""; }; + 4096BCD41B2024DA0048B07E /* MobilyNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyNavigationController.m; sourceTree = ""; }; + 4096BCD51B2024DA0048B07E /* MobilyNS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyNS.h; sourceTree = ""; }; + 4096BCD61B2024DA0048B07E /* MobilyNS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyNS.m; sourceTree = ""; }; + 4096BCD71B2024DA0048B07E /* MobilyObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyObject.h; sourceTree = ""; }; + 4096BCD81B2024DA0048B07E /* MobilyPageControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyPageControl.h; sourceTree = ""; }; + 4096BCD91B2024DA0048B07E /* MobilyPageControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyPageControl.m; sourceTree = ""; }; + 4096BCDA1B2024DA0048B07E /* MobilyPageController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyPageController.h; sourceTree = ""; }; + 4096BCDB1B2024DA0048B07E /* MobilyPageController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyPageController.m; sourceTree = ""; }; + 4096BCDC1B2024DA0048B07E /* MobilyPopoverController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyPopoverController.h; sourceTree = ""; }; + 4096BCDD1B2024DA0048B07E /* MobilyPopoverController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyPopoverController.m; sourceTree = ""; }; + 4096BCDE1B2024DA0048B07E /* MobilyRegExpParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyRegExpParser.h; sourceTree = ""; }; + 4096BCDF1B2024DA0048B07E /* MobilyRegExpParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyRegExpParser.m; sourceTree = ""; }; + 4096BCE01B2024DA0048B07E /* MobilyScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyScrollView.h; sourceTree = ""; }; + 4096BCE11B2024DA0048B07E /* MobilyScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyScrollView.m; sourceTree = ""; }; + 4096BCE21B2024DA0048B07E /* MobilySearchBar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilySearchBar.h; sourceTree = ""; }; + 4096BCE31B2024DA0048B07E /* MobilySearchBar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySearchBar.m; sourceTree = ""; }; + 4096BCE41B2024DA0048B07E /* MobilySharedManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilySharedManager.h; sourceTree = ""; }; + 4096BCE51B2024DA0048B07E /* MobilySharedManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySharedManager.m; sourceTree = ""; }; + 4096BCE61B2024DA0048B07E /* MobilySlideController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilySlideController.h; sourceTree = ""; }; + 4096BCE71B2024DA0048B07E /* MobilySlideController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySlideController.m; sourceTree = ""; }; + 4096BCE81B2024DA0048B07E /* MobilySpinnerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilySpinnerView.h; sourceTree = ""; }; + 4096BCE91B2024DA0048B07E /* MobilySpinnerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerView.m; sourceTree = ""; }; + 4096BCEA1B2024DA0048B07E /* MobilySpinnerView9CubeGrid.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerView9CubeGrid.m; sourceTree = ""; }; + 4096BCEB1B2024DA0048B07E /* MobilySpinnerViewArc.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerViewArc.m; sourceTree = ""; }; + 4096BCEC1B2024DA0048B07E /* MobilySpinnerViewArcAlt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerViewArcAlt.m; sourceTree = ""; }; + 4096BCED1B2024DA0048B07E /* MobilySpinnerViewBounce.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerViewBounce.m; sourceTree = ""; }; + 4096BCEE1B2024DA0048B07E /* MobilySpinnerViewChasingDots.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerViewChasingDots.m; sourceTree = ""; }; + 4096BCEF1B2024DA0048B07E /* MobilySpinnerViewCircle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerViewCircle.m; sourceTree = ""; }; + 4096BCF01B2024DA0048B07E /* MobilySpinnerViewCircleFlip.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerViewCircleFlip.m; sourceTree = ""; }; + 4096BCF11B2024DA0048B07E /* MobilySpinnerViewFadingCircle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerViewFadingCircle.m; sourceTree = ""; }; + 4096BCF21B2024DA0048B07E /* MobilySpinnerViewFadingCircleAlt.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerViewFadingCircleAlt.m; sourceTree = ""; }; + 4096BCF31B2024DA0048B07E /* MobilySpinnerViewPlane.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerViewPlane.m; sourceTree = ""; }; + 4096BCF41B2024DA0048B07E /* MobilySpinnerViewPulse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerViewPulse.m; sourceTree = ""; }; + 4096BCF51B2024DA0048B07E /* MobilySpinnerViewThreeBounce.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerViewThreeBounce.m; sourceTree = ""; }; + 4096BCF61B2024DA0048B07E /* MobilySpinnerViewWanderingCubes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerViewWanderingCubes.m; sourceTree = ""; }; + 4096BCF71B2024DA0048B07E /* MobilySpinnerViewWave.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerViewWave.m; sourceTree = ""; }; + 4096BCF81B2024DA0048B07E /* MobilySpinnerViewWordPress.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySpinnerViewWordPress.m; sourceTree = ""; }; + 4096BCF91B2024DA0048B07E /* MobilyStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyStyle.h; sourceTree = ""; }; + 4096BCFA1B2024DA0048B07E /* MobilyStyle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyStyle.m; sourceTree = ""; }; + 4096BCFB1B2024DA0048B07E /* MobilyTabBarController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyTabBarController.h; sourceTree = ""; }; + 4096BCFC1B2024DA0048B07E /* MobilyTabBarController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTabBarController.m; sourceTree = ""; }; + 4096BCFD1B2024DA0048B07E /* MobilyTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyTableView.h; sourceTree = ""; }; + 4096BCFE1B2024DA0048B07E /* MobilyTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTableView.m; sourceTree = ""; }; + 4096BCFF1B2024DA0048B07E /* MobilyTaskManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyTaskManager.h; sourceTree = ""; }; + 4096BD001B2024DA0048B07E /* MobilyTaskManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTaskManager.m; sourceTree = ""; }; + 4096BD011B2024DA0048B07E /* MobilyTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyTextField.h; sourceTree = ""; }; + 4096BD021B2024DA0048B07E /* MobilyTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTextField.m; sourceTree = ""; }; + 4096BD031B2024DA0048B07E /* MobilyTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyTextView.h; sourceTree = ""; }; + 4096BD041B2024DA0048B07E /* MobilyTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTextView.m; sourceTree = ""; }; + 4096BD051B2024DA0048B07E /* MobilyTimeout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyTimeout.h; sourceTree = ""; }; + 4096BD061B2024DA0048B07E /* MobilyTimeout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTimeout.m; sourceTree = ""; }; + 4096BD071B2024DA0048B07E /* MobilyTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyTimer.h; sourceTree = ""; }; + 4096BD081B2024DA0048B07E /* MobilyTimer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTimer.m; sourceTree = ""; }; + 4096BD091B2024DA0048B07E /* MobilyTransitionController+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MobilyTransitionController+Private.h"; sourceTree = ""; }; + 4096BD0A1B2024DA0048B07E /* MobilyTransitionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyTransitionController.h; sourceTree = ""; }; + 4096BD0B1B2024DA0048B07E /* MobilyTransitionController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTransitionController.m; sourceTree = ""; }; + 4096BD0C1B2024DA0048B07E /* MobilyTransitionControllerCards.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTransitionControllerCards.m; sourceTree = ""; }; + 4096BD0D1B2024DA0048B07E /* MobilyTransitionControllerCrossFade.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTransitionControllerCrossFade.m; sourceTree = ""; }; + 4096BD0E1B2024DA0048B07E /* MobilyTransitionControllerSlide.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyTransitionControllerSlide.m; sourceTree = ""; }; + 4096BD0F1B2024DA0048B07E /* MobilyUI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyUI.h; sourceTree = ""; }; + 4096BD101B2024DA0048B07E /* MobilyUI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyUI.m; sourceTree = ""; }; + 4096BD111B2024DA0048B07E /* MobilyValidatedObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyValidatedObject.h; sourceTree = ""; }; + 4096BD121B2024DA0048B07E /* MobilyView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyView.h; sourceTree = ""; }; + 4096BD131B2024DA0048B07E /* MobilyView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyView.m; sourceTree = ""; }; + 4096BD141B2024DA0048B07E /* MobilyViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyViewController.h; sourceTree = ""; }; + 4096BD151B2024DA0048B07E /* MobilyViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyViewController.m; sourceTree = ""; }; + 4096BD161B2024DA0048B07E /* MobilyWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyWindow.h; sourceTree = ""; }; + 4096BD171B2024DA0048B07E /* MobilyWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyWindow.m; sourceTree = ""; }; + 4096BE1B1B2024E30048B07E /* MobilySocial.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilySocial.h; sourceTree = ""; }; + 4096BE1C1B2024E30048B07E /* MobilySocialFacebookProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilySocialFacebookProvider.h; sourceTree = ""; }; + 4096BE1D1B2024E30048B07E /* MobilySocialFacebookProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySocialFacebookProvider.m; sourceTree = ""; }; + 4096BE1E1B2024E30048B07E /* MobilySocialManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilySocialManager.h; sourceTree = ""; }; + 4096BE1F1B2024E30048B07E /* MobilySocialManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySocialManager.m; sourceTree = ""; }; + 4096BE201B2024E30048B07E /* MobilySocialProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilySocialProvider.h; sourceTree = ""; }; + 4096BE211B2024E30048B07E /* MobilySocialProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySocialProvider.m; sourceTree = ""; }; + 4096BE221B2024E30048B07E /* MobilySocialTwitterProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilySocialTwitterProvider.h; sourceTree = ""; }; + 4096BE231B2024E30048B07E /* MobilySocialTwitterProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySocialTwitterProvider.m; sourceTree = ""; }; + 4096BE241B2024E30048B07E /* MobilySocialVKontakteProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilySocialVKontakteProvider.h; sourceTree = ""; }; + 4096BE251B2024E30048B07E /* MobilySocialVKontakteProvider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilySocialVKontakteProvider.m; sourceTree = ""; }; + 40B75EBD1ADF9EE500F0CB09 /* libMobilyCore.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMobilyCore.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 40B75EF61ADF9F1C00F0CB09 /* libMobilySocial.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libMobilySocial.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 40B760341ADFA31F00F0CB09 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; }; + 40B760351ADFA31F00F0CB09 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + 40B760361ADFA31F00F0CB09 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 40B760371ADFA31F00F0CB09 /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; }; + 40B760381ADFA31F00F0CB09 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 40B7603E1ADFA35600F0CB09 /* Accounts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Accounts.framework; path = System/Library/Frameworks/Accounts.framework; sourceTree = SDKROOT; }; + 40B7603F1ADFA35600F0CB09 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; + 40B760401ADFA35600F0CB09 /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; }; + 40B760411ADFA35600F0CB09 /* Twitter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Twitter.framework; path = System/Library/Frameworks/Twitter.framework; sourceTree = SDKROOT; }; + 40B7604E1ADFA6A200F0CB09 /* TwitterKitResources.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TwitterKitResources.bundle; sourceTree = ""; }; + 40B7604F1ADFA6A200F0CB09 /* VKSdkResources.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = VKSdkResources.bundle; sourceTree = ""; }; + 40D005D71B3BFD1800DD7DA6 /* MobilyStore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyStore.h; sourceTree = ""; }; + 40D09BEC1B5F819300C9F4CB /* MobilyLayoutView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyLayoutView.h; sourceTree = ""; }; + 40D09BED1B5F819300C9F4CB /* MobilyLayoutView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyLayoutView.m; sourceTree = ""; }; + 40FF59D51B4421410028CAB2 /* MobilyNotificationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MobilyNotificationManager.h; sourceTree = ""; }; + 40FF59D61B4421410028CAB2 /* MobilyNotificationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MobilyNotificationManager.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 401FEE4C18A3F92800B445EB /* Frameworks */ = { + 4080D1C41B3B44AB00328837 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 401FEE5518A3F92800B445EB /* CoreGraphics.framework in Frameworks */, - 401FEE5718A3F92800B445EB /* UIKit.framework in Frameworks */, - 401FEE5318A3F92800B445EB /* Foundation.framework in Frameworks */, - C13E78B87D644CF2A6696DA8 /* libPods.a in Frameworks */, + 4080D2411B3B44EB00328837 /* StoreKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 40081A8B1A27122200F2FBE6 /* ControllerSlideMenu */ = { - isa = PBXGroup; - children = ( - 40081A8E1A27122200F2FBE6 /* SlideNavigationController */, - 40081A8C1A27122200F2FBE6 /* MobilyControllerSlideMenu.h */, - 40081A8D1A27122200F2FBE6 /* MobilyControllerSlideMenu.m */, + 4080D2301B3B44B800328837 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4080D2441B3B450000328837 /* StoreKit.framework in Frameworks */, ); - path = ControllerSlideMenu; - sourceTree = ""; + runOnlyForDeploymentPostprocessing = 0; }; - 40081A8E1A27122200F2FBE6 /* SlideNavigationController */ = { - isa = PBXGroup; - children = ( - 40081A8F1A27122200F2FBE6 /* Animations */, - 40081A9B1A27122200F2FBE6 /* Assets */, - 40081A9E1A27122300F2FBE6 /* SlideNavigationController.h */, - 40081A9F1A27122300F2FBE6 /* SlideNavigationController.m */, + 4096BC1D1B20230E0048B07E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( ); - path = SlideNavigationController; - sourceTree = ""; - }; - 40081A8F1A27122200F2FBE6 /* Animations */ = { - isa = PBXGroup; - children = ( - 40081A901A27122200F2FBE6 /* SlideNavigationContorllerAnimator.h */, - 40081A911A27122200F2FBE6 /* SlideNavigationContorllerAnimatorFade.h */, - 40081A921A27122200F2FBE6 /* SlideNavigationContorllerAnimatorFade.m */, - 40081A931A27122200F2FBE6 /* SlideNavigationContorllerAnimatorScale.h */, - 40081A941A27122200F2FBE6 /* SlideNavigationContorllerAnimatorScale.m */, - 40081A951A27122200F2FBE6 /* SlideNavigationContorllerAnimatorScaleAndFade.h */, - 40081A961A27122200F2FBE6 /* SlideNavigationContorllerAnimatorScaleAndFade.m */, - 40081A971A27122200F2FBE6 /* SlideNavigationContorllerAnimatorSlide.h */, - 40081A981A27122200F2FBE6 /* SlideNavigationContorllerAnimatorSlide.m */, - 40081A991A27122200F2FBE6 /* SlideNavigationContorllerAnimatorSlideAndFade.h */, - 40081A9A1A27122200F2FBE6 /* SlideNavigationContorllerAnimatorSlideAndFade.m */, - ); - path = Animations; - sourceTree = ""; + runOnlyForDeploymentPostprocessing = 0; }; - 40081A9B1A27122200F2FBE6 /* Assets */ = { - isa = PBXGroup; - children = ( - 40081A9C1A27122200F2FBE6 /* menu-button.png */, - 40081A9D1A27122300F2FBE6 /* menu-button@2x.png */, + 4096BC3F1B20237D0048B07E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( ); - path = Assets; - sourceTree = ""; + runOnlyForDeploymentPostprocessing = 0; }; - 400B4D051A19E29900F2B61E /* ViewTable */ = { - isa = PBXGroup; - children = ( - 400B4D061A19E29900F2B61E /* MobilyViewTable.h */, - 400B4D071A19E29900F2B61E /* MobilyViewTable.m */, + 40B75EBA1ADF9EE500F0CB09 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 40B760391ADFA32000F0CB09 /* AVFoundation.framework in Frameworks */, + 40B7603A1ADFA32000F0CB09 /* CoreFoundation.framework in Frameworks */, + 40B7603B1ADFA32000F0CB09 /* CoreGraphics.framework in Frameworks */, + 40B7603C1ADFA32000F0CB09 /* CoreText.framework in Frameworks */, + 40B7603D1ADFA32000F0CB09 /* Foundation.framework in Frameworks */, ); - path = ViewTable; - sourceTree = ""; + runOnlyForDeploymentPostprocessing = 0; }; - 401FEE4618A3F92800B445EB = { - isa = PBXGroup; - children = ( - 401FEE8D18A3FAF100B445EB /* Classes */, - 401FEE8118A3FAE600B445EB /* Mobily */, - 401FEE5118A3F92800B445EB /* Frameworks */, - 401FEE5018A3F92800B445EB /* Products */, - 407903CF1943079600EC8855 /* Mobily.podspec */, - 4F1F86033CDFF14E4568271C /* Pods */, + 40B75EF31ADF9F1C00F0CB09 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 40B760421ADFA35600F0CB09 /* Accounts.framework in Frameworks */, + 40B760431ADFA35600F0CB09 /* CoreData.framework in Frameworks */, + 4005C08C1B1E13E4009A2185 /* TwitterCore.framework in Frameworks */, + 4005C0881B1E13E4009A2185 /* FBSDKCoreKit.framework in Frameworks */, + 4005C08E1B1E13E4009A2185 /* VKSdk.framework in Frameworks */, + 40B760441ADFA35600F0CB09 /* Social.framework in Frameworks */, + 4005C0891B1E13E4009A2185 /* FBSDKLoginKit.framework in Frameworks */, + 40B760451ADFA35600F0CB09 /* Twitter.framework in Frameworks */, + 4005C08D1B1E13E4009A2185 /* TwitterKit.framework in Frameworks */, ); - sourceTree = ""; + runOnlyForDeploymentPostprocessing = 0; }; - 401FEE5018A3F92800B445EB /* Products */ = { +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 4080D2451B3B454200328837 /* MobilyStore */ = { isa = PBXGroup; children = ( - 401FEE4F18A3F92800B445EB /* Mobily.app */, + 40D005D71B3BFD1800DD7DA6 /* MobilyStore.h */, + 4080D2461B3B454200328837 /* MobilyStoreManager.h */, + 4080D2471B3B454200328837 /* MobilyStoreManager.m */, ); - name = Products; + path = MobilyStore; sourceTree = ""; }; - 401FEE5118A3F92800B445EB /* Frameworks */ = { + 4096BC6C1B2024C00048B07E /* Support */ = { isa = PBXGroup; children = ( - 401FEE5218A3F92800B445EB /* Foundation.framework */, - 401FEE5418A3F92800B445EB /* CoreGraphics.framework */, - 401FEE5618A3F92800B445EB /* UIKit.framework */, - F16AA68F9FE04603B1D99102 /* libPods.a */, + 4096BC6D1B2024C00048B07E /* MobilyCore.plist */, + 4096BC6E1B2024C00048B07E /* MobilySocial.plist */, + 4080D23D1B3B44B800328837 /* MobilyStore.plist */, ); - name = Frameworks; + path = Support; sourceTree = ""; }; - 401FEE8118A3FAE600B445EB /* Mobily */ = { + 4096BC6F1B2024DA0048B07E /* MobilyCore */ = { isa = PBXGroup; children = ( - 401FEF1C18A3FE3500B445EB /* Supported files */, - 401FEE8618A3FAE600B445EB /* main.m */, - 401FEE8418A3FAE600B445EB /* ExampleApplication.h */, - 401FEE8518A3FAE600B445EB /* ExampleApplication.m */, - 9AA83B7A19E536FE009F6C5F /* ExampleControllerMain.xib */, - 400B4D091A1A0D6700F2B61E /* ExampleControllerMainCell.xib */, - 401FEF1818A3FE3200B445EB /* Application.mobily */, - 401FEF1918A3FE3200B445EB /* Presets.mobily */, - ); - path = Mobily; - sourceTree = ""; - }; - 401FEE8D18A3FAF100B445EB /* Classes */ = { - isa = PBXGroup; - children = ( - 401FEE9218A3FAF100B445EB /* Core */, - 401FEE9418A3FAF100B445EB /* NS */, - 401FEE8E18A3FAF100B445EB /* CG */, - 401FEEA418A3FAF100B445EB /* UI */, + 4096BC701B2024DA0048B07E /* MobilyActivityView.h */, + 4096BC711B2024DA0048B07E /* MobilyActivityView.m */, + 4096BC721B2024DA0048B07E /* MobilyApiManager.h */, + 4096BC731B2024DA0048B07E /* MobilyApiManager.m */, + 4096BC741B2024DA0048B07E /* MobilyApiProvider.h */, + 4096BC751B2024DA0048B07E /* MobilyApiProvider.m */, + 4096BC761B2024DA0048B07E /* MobilyApiRequest.h */, + 4096BC771B2024DA0048B07E /* MobilyApiRequest.m */, + 4096BC781B2024DA0048B07E /* MobilyApiResponse.h */, + 4096BC791B2024DA0048B07E /* MobilyApiResponse.m */, + 4096BC7A1B2024DA0048B07E /* MobilyApplication.h */, + 4096BC7B1B2024DA0048B07E /* MobilyApplication.m */, + 4096BC7C1B2024DA0048B07E /* MobilyAudioPlayer.h */, + 4096BC7D1B2024DA0048B07E /* MobilyAudioPlayer.m */, + 4096BC7E1B2024DA0048B07E /* MobilyAudioRecorder.h */, + 4096BC7F1B2024DA0048B07E /* MobilyAudioRecorder.m */, + 4096BC801B2024DA0048B07E /* MobilyAV.h */, + 401890091B70F08E00440DF7 /* MobilyBadgeView.h */, + 4018900A1B70F08E00440DF7 /* MobilyBadgeView.m */, + 4096BC811B2024DA0048B07E /* MobilyBlurView.h */, + 4096BC821B2024DA0048B07E /* MobilyBlurView.m */, + 4096BC831B2024DA0048B07E /* MobilyBuilder.h */, + 4096BC841B2024DA0048B07E /* MobilyBuilderForm.m */, + 4096BC851B2024DA0048B07E /* MobilyBuilderPreset.m */, + 4096BC861B2024DA0048B07E /* MobilyButton.h */, + 4096BC871B2024DA0048B07E /* MobilyButton.m */, + 4096BC881B2024DA0048B07E /* MobilyCA.h */, + 4096BC891B2024DA0048B07E /* MobilyCA.m */, + 4096BC8A1B2024DA0048B07E /* MobilyCache.h */, + 4096BC8B1B2024DA0048B07E /* MobilyCache.m */, + 4096BC8C1B2024DA0048B07E /* MobilyCG.h */, + 4096BC8D1B2024DA0048B07E /* MobilyCG.m */, + 4096BC8E1B2024DA0048B07E /* MobilyContext.h */, + 4096BC8F1B2024DA0048B07E /* MobilyContext.m */, + 4096BC901B2024DA0048B07E /* MobilyController.h */, + 4096BC911B2024DA0048B07E /* MobilyController.m */, + 4096BC921B2024DA0048B07E /* MobilyCore.h */, + 4096BC931B2024DA0048B07E /* MobilyData.h */, + 4096BC941B2024DA0048B07E /* MobilyDataCell+Private.h */, + 4096BC951B2024DA0048B07E /* MobilyDataCell.h */, + 4096BC961B2024DA0048B07E /* MobilyDataCell.m */, + 4096BC971B2024DA0048B07E /* MobilyDataCellSwipe.m */, + 4096BC981B2024DA0048B07E /* MobilyDataContainer+Private.h */, + 4096BC991B2024DA0048B07E /* MobilyDataContainer.h */, + 4096BC9A1B2024DA0048B07E /* MobilyDataContainer.m */, + 4096BC9B1B2024DA0048B07E /* MobilyDataContainerCalendar.m */, + 4096BC9C1B2024DA0048B07E /* MobilyDataContainerCalendarDays.m */, + 4096BC9D1B2024DA0048B07E /* MobilyDataContainerItems.m */, + 4096BC9E1B2024DA0048B07E /* MobilyDataContainerItemsFlow.m */, + 4096BC9F1B2024DA0048B07E /* MobilyDataContainerItemsGrid.m */, + 4096BCA01B2024DA0048B07E /* MobilyDataContainerItemsList.m */, + 4096BCA11B2024DA0048B07E /* MobilyDataContainerSections.m */, + 4096BCA21B2024DA0048B07E /* MobilyDataContainerSectionsList.m */, + 4096BCA31B2024DA0048B07E /* MobilyDataItem+Private.h */, + 4096BCA41B2024DA0048B07E /* MobilyDataItem.h */, + 4096BCA51B2024DA0048B07E /* MobilyDataItem.m */, + 4096BCA61B2024DA0048B07E /* MobilyDataRefreshView+Private.h */, + 4096BCA71B2024DA0048B07E /* MobilyDataRefreshView.h */, + 4096BCA81B2024DA0048B07E /* MobilyDataRefreshView.m */, + 4096BCA91B2024DA0048B07E /* MobilyDataView+Private.h */, + 4096BCAA1B2024DA0048B07E /* MobilyDataView.h */, + 4096BCAB1B2024DA0048B07E /* MobilyDataView.m */, + 4096BCAC1B2024DA0048B07E /* MobilyDateField.h */, + 4096BCAD1B2024DA0048B07E /* MobilyDateField.m */, + 4096BCAE1B2024DA0048B07E /* MobilyDefines.h */, + 4096BCAF1B2024DA0048B07E /* MobilyDialogController.h */, + 4096BCB01B2024DA0048B07E /* MobilyDialogController.m */, + 4096BCB11B2024DA0048B07E /* MobilyDownloader.h */, + 4096BCB21B2024DA0048B07E /* MobilyDownloader.m */, + 4096BCB31B2024DA0048B07E /* MobilyEvent+Private.h */, + 4096BCB41B2024DA0048B07E /* MobilyEvent.h */, + 4096BCB51B2024DA0048B07E /* MobilyEvent.m */, + 4096BCB61B2024DA0048B07E /* MobilyFieldValidation+Private.h */, + 4096BCB71B2024DA0048B07E /* MobilyFieldValidation.h */, + 4096BCB81B2024DA0048B07E /* MobilyFieldValidation.m */, + 4096BCB91B2024DA0048B07E /* MobilyGeoLocationManager.h */, + 4096BCBA1B2024DA0048B07E /* MobilyGeoLocationManager.m */, + 4096BCBB1B2024DA0048B07E /* MobilyGrid.h */, + 4096BCBC1B2024DA0048B07E /* MobilyGrid.m */, + 4096BCBD1B2024DA0048B07E /* MobilyHttpQuery+Private.h */, + 4096BCBE1B2024DA0048B07E /* MobilyHttpQuery.h */, + 4096BCBF1B2024DA0048B07E /* MobilyHttpQuery.m */, + 4064D18D1B577A6400F2F0FF /* MobilyImageCropController.h */, + 4064D18E1B577A6400F2F0FF /* MobilyImageCropController.m */, + 4096BCC01B2024DA0048B07E /* MobilyImageView.h */, + 4096BCC11B2024DA0048B07E /* MobilyImageView.m */, + 4096BCC21B2024DA0048B07E /* MobilyKVO.h */, + 4096BCC31B2024DA0048B07E /* MobilyKVO.m */, + 40D09BEC1B5F819300C9F4CB /* MobilyLayoutView.h */, + 40D09BED1B5F819300C9F4CB /* MobilyLayoutView.m */, + 4096BCC41B2024DA0048B07E /* MobilyListField.h */, + 4096BCC51B2024DA0048B07E /* MobilyListField.m */, + 4096BCC61B2024DA0048B07E /* MobilyLoadedView.h */, + 4096BCC71B2024DA0048B07E /* MobilyLoadedView.m */, + 4096BCC81B2024DA0048B07E /* MobilyLockScreenController.h */, + 4096BCC91B2024DA0048B07E /* MobilyLockScreenController.m */, + 4096BCCA1B2024DA0048B07E /* MobilyLockScreenPincodeView.h */, + 4096BCCB1B2024DA0048B07E /* MobilyLockScreenPincodeView.m */, + 4096BCCC1B2024DA0048B07E /* MobilyMap.h */, + 4096BCCD1B2024DA0048B07E /* MobilyMap.m */, + 4096BCCE1B2024DA0048B07E /* MobilyModel+Private.h */, + 4096BCCF1B2024DA0048B07E /* MobilyModel.h */, + 4096BCD01B2024DA0048B07E /* MobilyModel.m */, + 4096BCD11B2024DA0048B07E /* MobilyModelJson.h */, + 4096BCD21B2024DA0048B07E /* MobilyModelJson.m */, + 4096BCD31B2024DA0048B07E /* MobilyNavigationController.h */, + 4096BCD41B2024DA0048B07E /* MobilyNavigationController.m */, + 40FF59D51B4421410028CAB2 /* MobilyNotificationManager.h */, + 40FF59D61B4421410028CAB2 /* MobilyNotificationManager.m */, + 4096BCD51B2024DA0048B07E /* MobilyNS.h */, + 4096BCD61B2024DA0048B07E /* MobilyNS.m */, + 4096BCD71B2024DA0048B07E /* MobilyObject.h */, + 4096BCD81B2024DA0048B07E /* MobilyPageControl.h */, + 4096BCD91B2024DA0048B07E /* MobilyPageControl.m */, + 4096BCDA1B2024DA0048B07E /* MobilyPageController.h */, + 4096BCDB1B2024DA0048B07E /* MobilyPageController.m */, + 4096BCDC1B2024DA0048B07E /* MobilyPopoverController.h */, + 4096BCDD1B2024DA0048B07E /* MobilyPopoverController.m */, + 4002F3B11B3D425E00961E90 /* MobilyPressAndHoldGestureRecognizer.h */, + 4002F3B21B3D425E00961E90 /* MobilyPressAndHoldGestureRecognizer.m */, + 4096BCDE1B2024DA0048B07E /* MobilyRegExpParser.h */, + 4096BCDF1B2024DA0048B07E /* MobilyRegExpParser.m */, + 4096BCE01B2024DA0048B07E /* MobilyScrollView.h */, + 4096BCE11B2024DA0048B07E /* MobilyScrollView.m */, + 4096BCE21B2024DA0048B07E /* MobilySearchBar.h */, + 4096BCE31B2024DA0048B07E /* MobilySearchBar.m */, + 4096BCE41B2024DA0048B07E /* MobilySharedManager.h */, + 4096BCE51B2024DA0048B07E /* MobilySharedManager.m */, + 4096BCE61B2024DA0048B07E /* MobilySlideController.h */, + 4096BCE71B2024DA0048B07E /* MobilySlideController.m */, + 4096BCE81B2024DA0048B07E /* MobilySpinnerView.h */, + 4096BCE91B2024DA0048B07E /* MobilySpinnerView.m */, + 4096BCEA1B2024DA0048B07E /* MobilySpinnerView9CubeGrid.m */, + 4096BCEB1B2024DA0048B07E /* MobilySpinnerViewArc.m */, + 4096BCEC1B2024DA0048B07E /* MobilySpinnerViewArcAlt.m */, + 4096BCED1B2024DA0048B07E /* MobilySpinnerViewBounce.m */, + 4096BCEE1B2024DA0048B07E /* MobilySpinnerViewChasingDots.m */, + 4096BCEF1B2024DA0048B07E /* MobilySpinnerViewCircle.m */, + 4096BCF01B2024DA0048B07E /* MobilySpinnerViewCircleFlip.m */, + 4096BCF11B2024DA0048B07E /* MobilySpinnerViewFadingCircle.m */, + 4096BCF21B2024DA0048B07E /* MobilySpinnerViewFadingCircleAlt.m */, + 4096BCF31B2024DA0048B07E /* MobilySpinnerViewPlane.m */, + 4096BCF41B2024DA0048B07E /* MobilySpinnerViewPulse.m */, + 4096BCF51B2024DA0048B07E /* MobilySpinnerViewThreeBounce.m */, + 4096BCF61B2024DA0048B07E /* MobilySpinnerViewWanderingCubes.m */, + 4096BCF71B2024DA0048B07E /* MobilySpinnerViewWave.m */, + 4096BCF81B2024DA0048B07E /* MobilySpinnerViewWordPress.m */, + 4096BCF91B2024DA0048B07E /* MobilyStyle.h */, + 4096BCFA1B2024DA0048B07E /* MobilyStyle.m */, + 4096BCFB1B2024DA0048B07E /* MobilyTabBarController.h */, + 4096BCFC1B2024DA0048B07E /* MobilyTabBarController.m */, + 4096BCFD1B2024DA0048B07E /* MobilyTableView.h */, + 4096BCFE1B2024DA0048B07E /* MobilyTableView.m */, + 4096BCFF1B2024DA0048B07E /* MobilyTaskManager.h */, + 4096BD001B2024DA0048B07E /* MobilyTaskManager.m */, + 4096BD011B2024DA0048B07E /* MobilyTextField.h */, + 4096BD021B2024DA0048B07E /* MobilyTextField.m */, + 4096BD031B2024DA0048B07E /* MobilyTextView.h */, + 4096BD041B2024DA0048B07E /* MobilyTextView.m */, + 4096BD051B2024DA0048B07E /* MobilyTimeout.h */, + 4096BD061B2024DA0048B07E /* MobilyTimeout.m */, + 4096BD071B2024DA0048B07E /* MobilyTimer.h */, + 4096BD081B2024DA0048B07E /* MobilyTimer.m */, + 4064D1921B577D0900F2F0FF /* MobilyTouchView.h */, + 4064D1931B577D0900F2F0FF /* MobilyTouchView.m */, + 4096BD091B2024DA0048B07E /* MobilyTransitionController+Private.h */, + 4096BD0A1B2024DA0048B07E /* MobilyTransitionController.h */, + 4096BD0B1B2024DA0048B07E /* MobilyTransitionController.m */, + 4096BD0C1B2024DA0048B07E /* MobilyTransitionControllerCards.m */, + 4096BD0D1B2024DA0048B07E /* MobilyTransitionControllerCrossFade.m */, + 4096BD0E1B2024DA0048B07E /* MobilyTransitionControllerSlide.m */, + 4096BD0F1B2024DA0048B07E /* MobilyUI.h */, + 4096BD101B2024DA0048B07E /* MobilyUI.m */, + 4096BD111B2024DA0048B07E /* MobilyValidatedObject.h */, + 4096BD121B2024DA0048B07E /* MobilyView.h */, + 4096BD131B2024DA0048B07E /* MobilyView.m */, + 4096BD141B2024DA0048B07E /* MobilyViewController.h */, + 4096BD151B2024DA0048B07E /* MobilyViewController.m */, + 4096BD161B2024DA0048B07E /* MobilyWindow.h */, + 4096BD171B2024DA0048B07E /* MobilyWindow.m */, ); - path = Classes; + path = MobilyCore; sourceTree = ""; }; - 401FEE8E18A3FAF100B445EB /* CG */ = { + 4096BE1A1B2024E30048B07E /* MobilySocial */ = { isa = PBXGroup; children = ( - 401FEE8F18A3FAF100B445EB /* Core */, + 4096BE1B1B2024E30048B07E /* MobilySocial.h */, + 4096BE1C1B2024E30048B07E /* MobilySocialFacebookProvider.h */, + 4096BE1D1B2024E30048B07E /* MobilySocialFacebookProvider.m */, + 4096BE1E1B2024E30048B07E /* MobilySocialManager.h */, + 4096BE1F1B2024E30048B07E /* MobilySocialManager.m */, + 4096BE201B2024E30048B07E /* MobilySocialProvider.h */, + 4096BE211B2024E30048B07E /* MobilySocialProvider.m */, + 4096BE221B2024E30048B07E /* MobilySocialTwitterProvider.h */, + 4096BE231B2024E30048B07E /* MobilySocialTwitterProvider.m */, + 4096BE241B2024E30048B07E /* MobilySocialVKontakteProvider.h */, + 4096BE251B2024E30048B07E /* MobilySocialVKontakteProvider.m */, ); - path = CG; + path = MobilySocial; sourceTree = ""; }; - 401FEE8F18A3FAF100B445EB /* Core */ = { + 40B75B291ADEE82900F0CB09 = { isa = PBXGroup; children = ( - 401FEE9118A3FAF100B445EB /* MobilyCG.h */, - 401FEE9018A3FAF100B445EB /* MobilyCG.m */, + 40B75F0D1ADF9F5400F0CB09 /* Sources */, + 4096BC6C1B2024C00048B07E /* Support */, + 40B75E2B1ADF82CA00F0CB09 /* Frameworks */, + 40B7604D1ADFA6A200F0CB09 /* Resources */, + 40B75B341ADEE82900F0CB09 /* Products */, ); - path = Core; sourceTree = ""; }; - 401FEE9218A3FAF100B445EB /* Core */ = { + 40B75B341ADEE82900F0CB09 /* Products */ = { isa = PBXGroup; children = ( - 401FEE9318A3FAF100B445EB /* MobilyCore.h */, + 40B75EBD1ADF9EE500F0CB09 /* libMobilyCore.a */, + 40B75EF61ADF9F1C00F0CB09 /* libMobilySocial.a */, + 4096BC211B20230E0048B07E /* MobilyCore.framework */, + 4096BC431B20237D0048B07E /* MobilySocial.framework */, + 4080D2281B3B44AB00328837 /* libMobilyStore.a */, + 4080D23C1B3B44B800328837 /* MobilyStore-Framework.framework */, ); - path = Core; + name = Products; sourceTree = ""; }; - 401FEE9418A3FAF100B445EB /* NS */ = { + 40B75E2B1ADF82CA00F0CB09 /* Frameworks */ = { isa = PBXGroup; children = ( - 401FEE9518A3FAF100B445EB /* Core */, - 40798A281948ABAF00A04686 /* RegExpParser */, + 4080D2401B3B44EB00328837 /* StoreKit.framework */, + 40B7603E1ADFA35600F0CB09 /* Accounts.framework */, + 40B7603F1ADFA35600F0CB09 /* CoreData.framework */, + 40B760401ADFA35600F0CB09 /* Social.framework */, + 40B760411ADFA35600F0CB09 /* Twitter.framework */, + 40B760341ADFA31F00F0CB09 /* AVFoundation.framework */, + 40B760351ADFA31F00F0CB09 /* CoreFoundation.framework */, + 40B760361ADFA31F00F0CB09 /* CoreGraphics.framework */, + 40B760371ADFA31F00F0CB09 /* CoreText.framework */, + 40B760381ADFA31F00F0CB09 /* Foundation.framework */, + 4005C07D1B1E13E3009A2185 /* Bolts.framework */, + 4005C07E1B1E13E3009A2185 /* FBAudienceNetwork.framework */, + 4005C07F1B1E13E3009A2185 /* FBSDKCoreKit.framework */, + 4005C0801B1E13E3009A2185 /* FBSDKLoginKit.framework */, + 4005C0811B1E13E3009A2185 /* FBSDKMessengerShareKit.framework */, + 4005C0821B1E13E3009A2185 /* FBSDKShareKit.framework */, + 4005C0831B1E13E4009A2185 /* TwitterCore.framework */, + 4005C0841B1E13E4009A2185 /* TwitterKit.framework */, + 4005C0851B1E13E4009A2185 /* VKSdk.framework */, ); - path = NS; - sourceTree = ""; - }; - 401FEE9518A3FAF100B445EB /* Core */ = { - isa = PBXGroup; - children = ( - 401FEE9E18A3FAF100B445EB /* MobilyNS.h */, - 401FEE9F18A3FAF100B445EB /* MobilyNS.m */, - 401FEE9C18A3FAF100B445EB /* MobilyKVO.h */, - 401FEE9D18A3FAF100B445EB /* MobilyKVO.m */, - 401FEE9618A3FAF100B445EB /* MobilyEvent.h */, - 401FEE9718A3FAF100B445EB /* MobilyEvent.m */, - 401FEEA018A3FAF100B445EB /* MobilyStorage.h */, - 401FEEA118A3FAF100B445EB /* MobilyStorage.m */, - 401FEEA218A3FAF100B445EB /* MobilyTaskManager.h */, - 401FEEA318A3FAF100B445EB /* MobilyTaskManager.m */, - 401FEE9A18A3FAF100B445EB /* MobilyHttpQuery.h */, - 401FEE9B18A3FAF100B445EB /* MobilyHttpQuery.m */, - ); - path = Core; - sourceTree = ""; - }; - 401FEEA418A3FAF100B445EB /* UI */ = { - isa = PBXGroup; - children = ( - 401FEEB418A3FAF100B445EB /* Core */, - 407989E919484C7000A04686 /* ControllerDynamicsDrawer */, - 40081A8B1A27122200F2FBE6 /* ControllerSlideMenu */, - 40798A321948AC0600A04686 /* ViewFieldText */, - 40798A2C1948AC0600A04686 /* ViewFieldDate */, - 40798A2F1948AC0600A04686 /* ViewFieldList */, - 40798A381948AFC400A04686 /* ViewImage */, - 403258081A0BBBA700949E8F /* ViewScroll */, - 400B4D051A19E29900F2B61E /* ViewTable */, - 40798A3C1948C0F700A04686 /* ViewElements */, - ); - path = UI; - sourceTree = ""; + path = Frameworks; + sourceTree = SOURCE_ROOT; }; - 401FEEB418A3FAF100B445EB /* Core */ = { + 40B75F0D1ADF9F5400F0CB09 /* Sources */ = { isa = PBXGroup; children = ( - 401FEEC918A3FAF100B445EB /* MobilyUI.h */, - 401FEECA18A3FAF100B445EB /* MobilyUI.m */, - 401FEEB718A3FAF100B445EB /* MobilyContext.h */, - 401FEEB818A3FAF100B445EB /* MobilyContext.m */, - 401FEEC718A3FAF100B445EB /* MobilyBuilder.h */, - 407903D119464A1E00EC8855 /* MobilyBuilderPreset.m */, - 401FEEC818A3FAF100B445EB /* MobilyBuilderForm.m */, - 401FEEB518A3FAF100B445EB /* MobilyApplication.h */, - 401FEEB618A3FAF100B445EB /* MobilyApplication.m */, - 401FEEDF18A3FAF100B445EB /* MobilyWindow.h */, - 401FEEE018A3FAF100B445EB /* MobilyWindow.m */, - 401FEEB918A3FAF100B445EB /* MobilyController.h */, - 401FEEBA18A3FAF100B445EB /* MobilyController.m */, - 401FEEBB18A3FAF100B445EB /* MobilyControllerNavigation.h */, - 401FEEBC18A3FAF100B445EB /* MobilyControllerNavigation.m */, - 401FEEBD18A3FAF100B445EB /* MobilyControllerTabBar.h */, - 401FEEBE18A3FAF100B445EB /* MobilyControllerTabBar.m */, - 401FEEBF18A3FAF100B445EB /* MobilyControllerView.h */, - 401FEEC018A3FAF100B445EB /* MobilyControllerView.m */, - 407989E21947834F00A04686 /* MobilyTransitionController.h */, - 407989E31947834F00A04686 /* MobilyTransitionController.m */, - 407989E6194788EE00A04686 /* MobilyTransitionControllerCrossFade.m */, - 407989E5194788EE00A04686 /* MobilyTransitionControllerCards.m */, - ); - path = Core; - sourceTree = ""; - }; - 401FEF1C18A3FE3500B445EB /* Supported files */ = { - isa = PBXGroup; - children = ( - 401FEE8218A3FAE600B445EB /* InfoPlist.strings */, - 401FEE8718A3FAE600B445EB /* Mobily-Info.plist */, - 401FEE8818A3FAE600B445EB /* Mobily-Prefix.pch */, + 4096BC6F1B2024DA0048B07E /* MobilyCore */, + 4096BE1A1B2024E30048B07E /* MobilySocial */, + 4080D2451B3B454200328837 /* MobilyStore */, ); - name = "Supported files"; + path = Sources; sourceTree = ""; }; - 403258081A0BBBA700949E8F /* ViewScroll */ = { + 40B7604D1ADFA6A200F0CB09 /* Resources */ = { isa = PBXGroup; children = ( - 403258091A0BBBA700949E8F /* MobilyViewScroll.h */, - 4032580A1A0BBBA700949E8F /* MobilyViewScroll.m */, + 40B7604E1ADFA6A200F0CB09 /* TwitterKitResources.bundle */, + 40B7604F1ADFA6A200F0CB09 /* VKSdkResources.bundle */, ); - path = ViewScroll; + path = Resources; sourceTree = ""; }; - 407989E919484C7000A04686 /* ControllerDynamicsDrawer */ = { - isa = PBXGroup; - children = ( - 407989EA19484C9700A04686 /* MobilyControllerDynamicsDrawer.h */, - 407989EB19484C9700A04686 /* MobilyControllerDynamicsDrawer.m */, +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 4080D2311B3B44B800328837 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 40D005D81B3BFD1800DD7DA6 /* MobilyStore.h in Headers */, + 4080D2481B3B454200328837 /* MobilyStoreManager.h in Headers */, ); - path = ControllerDynamicsDrawer; - sourceTree = ""; + runOnlyForDeploymentPostprocessing = 0; }; - 40798A281948ABAF00A04686 /* RegExpParser */ = { - isa = PBXGroup; - children = ( - 40798A291948ABAF00A04686 /* MobilyRegExpParser.h */, - 40798A2A1948ABAF00A04686 /* MobilyRegExpParser.m */, + 4096BC1E1B20230E0048B07E /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 4002F3B31B3D425E00961E90 /* MobilyPressAndHoldGestureRecognizer.h in Headers */, + 4096BD2A1B2024DA0048B07E /* MobilyAudioPlayer.h in Headers */, + 4096BD881B2024DA0048B07E /* MobilyGrid.h in Headers */, + 4096BDA81B2024DA0048B07E /* MobilyModelJson.h in Headers */, + 4096BD481B2024DA0048B07E /* MobilyController.h in Headers */, + 4096BD6C1B2024DA0048B07E /* MobilyDataRefreshView.h in Headers */, + 4096BDA51B2024DA0048B07E /* MobilyModel.h in Headers */, + 4096BD4E1B2024DA0048B07E /* MobilyDataCell.h in Headers */, + 4096BD341B2024DA0048B07E /* MobilyBuilder.h in Headers */, + 4018900B1B70F08E00440DF7 /* MobilyBadgeView.h in Headers */, + 4096BD541B2024DA0048B07E /* MobilyDataContainer.h in Headers */, + 4096BE041B2024DA0048B07E /* MobilyTransitionController.h in Headers */, + 4096BD8F1B2024DA0048B07E /* MobilyImageView.h in Headers */, + 4096BE001B2024DA0048B07E /* MobilyTimer.h in Headers */, + 4096BD761B2024DA0048B07E /* MobilyDefines.h in Headers */, + 4096BDCA1B2024DA0048B07E /* MobilySpinnerView.h in Headers */, + 4096BDA11B2024DA0048B07E /* MobilyMap.h in Headers */, + 4096BD681B2024DA0048B07E /* MobilyDataItem.h in Headers */, + 4096BE171B2024DA0048B07E /* MobilyWindow.h in Headers */, + 4096BD181B2024DA0048B07E /* MobilyActivityView.h in Headers */, + 4096BDFA1B2024DA0048B07E /* MobilyTextView.h in Headers */, + 4096BD851B2024DA0048B07E /* MobilyGeoLocationManager.h in Headers */, + 4096BDC11B2024DA0048B07E /* MobilySearchBar.h in Headers */, + 4096BE101B2024DA0048B07E /* MobilyValidatedObject.h in Headers */, + 4096BD981B2024DA0048B07E /* MobilyLoadedView.h in Headers */, + 4096BDBE1B2024DA0048B07E /* MobilyScrollView.h in Headers */, + 4096BD7E1B2024DA0048B07E /* MobilyEvent.h in Headers */, + 4096BD4C1B2024DA0048B07E /* MobilyData.h in Headers */, + 4096BD1B1B2024DA0048B07E /* MobilyApiManager.h in Headers */, + 4096BD8C1B2024DA0048B07E /* MobilyHttpQuery.h in Headers */, + 4096BD951B2024DA0048B07E /* MobilyListField.h in Headers */, + 4096BDF71B2024DA0048B07E /* MobilyTextField.h in Headers */, + 4096BD771B2024DA0048B07E /* MobilyDialogController.h in Headers */, + 4096BD1E1B2024DA0048B07E /* MobilyApiProvider.h in Headers */, + 4096BDB11B2024DA0048B07E /* MobilyObject.h in Headers */, + 4096BE141B2024DA0048B07E /* MobilyViewController.h in Headers */, + 4064D1941B577D0900F2F0FF /* MobilyTouchView.h in Headers */, + 4096BD311B2024DA0048B07E /* MobilyBlurView.h in Headers */, + 4096BE031B2024DA0048B07E /* MobilyTransitionController+Private.h in Headers */, + 4096BDEB1B2024DA0048B07E /* MobilyStyle.h in Headers */, + 4096BD451B2024DA0048B07E /* MobilyContext.h in Headers */, + 4096BD211B2024DA0048B07E /* MobilyApiRequest.h in Headers */, + 4096BE0D1B2024DA0048B07E /* MobilyUI.h in Headers */, + 4096BD4B1B2024DA0048B07E /* MobilyCore.h in Headers */, + 4096BDB51B2024DA0048B07E /* MobilyPageController.h in Headers */, + 4096BD241B2024DA0048B07E /* MobilyApiResponse.h in Headers */, + 4096BD3C1B2024DA0048B07E /* MobilyCA.h in Headers */, + 4096BD731B2024DA0048B07E /* MobilyDateField.h in Headers */, + 4096BD821B2024DA0048B07E /* MobilyFieldValidation.h in Headers */, + 4096BDC71B2024DA0048B07E /* MobilySlideController.h in Headers */, + 40FF59D71B4421410028CAB2 /* MobilyNotificationManager.h in Headers */, + 4096BD391B2024DA0048B07E /* MobilyButton.h in Headers */, + 4096BDB21B2024DA0048B07E /* MobilyPageControl.h in Headers */, + 40D09BEE1B5F819300C9F4CB /* MobilyLayoutView.h in Headers */, + 4096BD301B2024DA0048B07E /* MobilyAV.h in Headers */, + 4064D18F1B577A6400F2F0FF /* MobilyImageCropController.h in Headers */, + 4096BD421B2024DA0048B07E /* MobilyCG.h in Headers */, + 4096BDAE1B2024DA0048B07E /* MobilyNS.h in Headers */, + 4096BD3F1B2024DA0048B07E /* MobilyCache.h in Headers */, + 4096BDEE1B2024DA0048B07E /* MobilyTabBarController.h in Headers */, + 4096BE111B2024DA0048B07E /* MobilyView.h in Headers */, + 4096BD7A1B2024DA0048B07E /* MobilyDownloader.h in Headers */, + 4096BD921B2024DA0048B07E /* MobilyKVO.h in Headers */, + 4096BDF11B2024DA0048B07E /* MobilyTableView.h in Headers */, + 4096BD271B2024DA0048B07E /* MobilyApplication.h in Headers */, + 4096BDC41B2024DA0048B07E /* MobilySharedManager.h in Headers */, + 4096BDB81B2024DA0048B07E /* MobilyPopoverController.h in Headers */, + 4096BD9B1B2024DA0048B07E /* MobilyLockScreenController.h in Headers */, + 4096BDF41B2024DA0048B07E /* MobilyTaskManager.h in Headers */, + 4096BD9E1B2024DA0048B07E /* MobilyLockScreenPincodeView.h in Headers */, + 4096BDBB1B2024DA0048B07E /* MobilyRegExpParser.h in Headers */, + 4096BDAB1B2024DA0048B07E /* MobilyNavigationController.h in Headers */, + 4096BD2D1B2024DA0048B07E /* MobilyAudioRecorder.h in Headers */, + 4096BD701B2024DA0048B07E /* MobilyDataView.h in Headers */, + 4096BDFD1B2024DA0048B07E /* MobilyTimeout.h in Headers */, + 4096BD6F1B2024DA0048B07E /* MobilyDataView+Private.h in Headers */, + 4096BD671B2024DA0048B07E /* MobilyDataItem+Private.h in Headers */, + 4096BDA41B2024DA0048B07E /* MobilyModel+Private.h in Headers */, + 4096BD531B2024DA0048B07E /* MobilyDataContainer+Private.h in Headers */, + 4096BD6B1B2024DA0048B07E /* MobilyDataRefreshView+Private.h in Headers */, + 4096BD4D1B2024DA0048B07E /* MobilyDataCell+Private.h in Headers */, + 4096BD7D1B2024DA0048B07E /* MobilyEvent+Private.h in Headers */, + 4096BD811B2024DA0048B07E /* MobilyFieldValidation+Private.h in Headers */, + 4096BD8B1B2024DA0048B07E /* MobilyHttpQuery+Private.h in Headers */, ); - path = RegExpParser; - sourceTree = ""; + runOnlyForDeploymentPostprocessing = 0; }; - 40798A2C1948AC0600A04686 /* ViewFieldDate */ = { - isa = PBXGroup; - children = ( - 40798A2D1948AC0600A04686 /* MobilyViewFieldDate.h */, - 40798A2E1948AC0600A04686 /* MobilyViewFieldDate.m */, + 4096BC401B20237D0048B07E /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 4096BE271B2024E30048B07E /* MobilySocialFacebookProvider.h in Headers */, + 4096BE2A1B2024E30048B07E /* MobilySocialManager.h in Headers */, + 4096BE331B2024E30048B07E /* MobilySocialVKontakteProvider.h in Headers */, + 4096BE301B2024E30048B07E /* MobilySocialTwitterProvider.h in Headers */, + 4096BE2D1B2024E30048B07E /* MobilySocialProvider.h in Headers */, + 4096BE261B2024E30048B07E /* MobilySocial.h in Headers */, ); - path = ViewFieldDate; - sourceTree = ""; + runOnlyForDeploymentPostprocessing = 0; }; - 40798A2F1948AC0600A04686 /* ViewFieldList */ = { - isa = PBXGroup; - children = ( - 40798A301948AC0600A04686 /* MobilyViewFieldList.h */, - 40798A311948AC0600A04686 /* MobilyViewFieldList.m */, +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 4080D1C31B3B44AB00328837 /* MobilyStore-Library */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4080D2251B3B44AB00328837 /* Build configuration list for PBXNativeTarget "MobilyStore-Library" */; + buildPhases = ( + 4080D1C41B3B44AB00328837 /* Frameworks */, + 4080D1CA1B3B44AB00328837 /* Sources */, ); - path = ViewFieldList; - sourceTree = ""; + buildRules = ( + ); + dependencies = ( + 4080D23F1B3B44E500328837 /* PBXTargetDependency */, + ); + name = "MobilyStore-Library"; + productName = MobilyCore; + productReference = 4080D2281B3B44AB00328837 /* libMobilyStore.a */; + productType = "com.apple.product-type.library.static"; }; - 40798A321948AC0600A04686 /* ViewFieldText */ = { - isa = PBXGroup; - children = ( - 40798A331948AC0600A04686 /* MobilyViewFieldText.h */, - 40798A341948AC0600A04686 /* MobilyViewFieldText.m */, + 4080D2291B3B44B800328837 /* MobilyStore-Framework */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4080D2391B3B44B800328837 /* Build configuration list for PBXNativeTarget "MobilyStore-Framework" */; + buildPhases = ( + 4080D22A1B3B44B800328837 /* Sources */, + 4080D2301B3B44B800328837 /* Frameworks */, + 4080D2311B3B44B800328837 /* Headers */, + 4080D2381B3B44B800328837 /* Resources */, ); - path = ViewFieldText; - sourceTree = ""; + buildRules = ( + ); + dependencies = ( + 4080D2431B3B44F300328837 /* PBXTargetDependency */, + ); + name = "MobilyStore-Framework"; + productName = "MobilySocial-Framework"; + productReference = 4080D23C1B3B44B800328837 /* MobilyStore-Framework.framework */; + productType = "com.apple.product-type.framework"; }; - 40798A381948AFC400A04686 /* ViewImage */ = { - isa = PBXGroup; - children = ( - 40798A391948AFC400A04686 /* MobilyViewImage.h */, - 40798A3A1948AFC400A04686 /* MobilyViewImage.m */, + 4096BC201B20230E0048B07E /* MobilyCore-Framework */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4096BC341B20230F0048B07E /* Build configuration list for PBXNativeTarget "MobilyCore-Framework" */; + buildPhases = ( + 4096BC1C1B20230E0048B07E /* Sources */, + 4096BC1D1B20230E0048B07E /* Frameworks */, + 4096BC1E1B20230E0048B07E /* Headers */, + 4096BC1F1B20230E0048B07E /* Resources */, ); - path = ViewImage; - sourceTree = ""; + buildRules = ( + ); + dependencies = ( + ); + name = "MobilyCore-Framework"; + productName = "MobilyCore-Framework"; + productReference = 4096BC211B20230E0048B07E /* MobilyCore.framework */; + productType = "com.apple.product-type.framework"; }; - 40798A3C1948C0F700A04686 /* ViewElements */ = { - isa = PBXGroup; - children = ( - 40798A3F1948C0F700A04686 /* MobilyViewElements.h */, - 40798A401948C0F700A04686 /* MobilyViewElements.m */, - 40798A3D1948C0F700A04686 /* MobilyViewElementsLayout.h */, - 40798A3E1948C0F700A04686 /* MobilyViewElementsLayout.m */, + 4096BC421B20237D0048B07E /* MobilySocial-Framework */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4096BC561B20237D0048B07E /* Build configuration list for PBXNativeTarget "MobilySocial-Framework" */; + buildPhases = ( + 4096BC3E1B20237D0048B07E /* Sources */, + 4096BC3F1B20237D0048B07E /* Frameworks */, + 4096BC401B20237D0048B07E /* Headers */, + 4096BC411B20237D0048B07E /* Resources */, ); - path = ViewElements; - sourceTree = ""; + buildRules = ( + ); + dependencies = ( + ); + name = "MobilySocial-Framework"; + productName = "MobilySocial-Framework"; + productReference = 4096BC431B20237D0048B07E /* MobilySocial.framework */; + productType = "com.apple.product-type.framework"; }; - 4F1F86033CDFF14E4568271C /* Pods */ = { - isa = PBXGroup; - children = ( - 2BBC62D562492FDF2CDB1707 /* Pods.debug.xcconfig */, - 5A2438BFA45DA754D1C37067 /* Pods.release.xcconfig */, + 40B75EBC1ADF9EE500F0CB09 /* MobilyCore-Library */ = { + isa = PBXNativeTarget; + buildConfigurationList = 40B75ECE1ADF9EE600F0CB09 /* Build configuration list for PBXNativeTarget "MobilyCore-Library" */; + buildPhases = ( + 40B75EBA1ADF9EE500F0CB09 /* Frameworks */, + 40B75EB91ADF9EE500F0CB09 /* Sources */, ); - name = Pods; - sourceTree = ""; + buildRules = ( + ); + dependencies = ( + ); + name = "MobilyCore-Library"; + productName = MobilyCore; + productReference = 40B75EBD1ADF9EE500F0CB09 /* libMobilyCore.a */; + productType = "com.apple.product-type.library.static"; }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 401FEE4E18A3F92800B445EB /* Mobily */ = { + 40B75EF51ADF9F1C00F0CB09 /* MobilySocial-Library */ = { isa = PBXNativeTarget; - buildConfigurationList = 401FEE7B18A3F92800B445EB /* Build configuration list for PBXNativeTarget "Mobily" */; + buildConfigurationList = 40B75F071ADF9F1D00F0CB09 /* Build configuration list for PBXNativeTarget "MobilySocial-Library" */; buildPhases = ( - B5EF831C1EE3466E88C6CC3D /* Check Pods Manifest.lock */, - 401FEE4B18A3F92800B445EB /* Sources */, - 401FEE4C18A3F92800B445EB /* Frameworks */, - 401FEE4D18A3F92800B445EB /* Resources */, - 412AC5C9C0094AEAB4B73BCE /* Copy Pods Resources */, + 40B75EF31ADF9F1C00F0CB09 /* Frameworks */, + 40B75EF21ADF9F1C00F0CB09 /* Sources */, ); buildRules = ( ); dependencies = ( + 40B7601A1ADFA05000F0CB09 /* PBXTargetDependency */, ); - name = Mobily; - productName = Mobily; - productReference = 401FEE4F18A3F92800B445EB /* Mobily.app */; - productType = "com.apple.product-type.application"; + name = "MobilySocial-Library"; + productName = MobilySocial; + productReference = 40B75EF61ADF9F1C00F0CB09 /* libMobilySocial.a */; + productType = "com.apple.product-type.library.static"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ - 401FEE4718A3F92800B445EB /* Project object */ = { + 40B75B2A1ADEE82900F0CB09 /* Project object */ = { isa = PBXProject; attributes = { CLASSPREFIX = Mobily; - LastUpgradeCheck = 0510; - ORGANIZATIONNAME = fgengine; + LastUpgradeCheck = 0700; + ORGANIZATIONNAME = Mobily; + TargetAttributes = { + 4096BC201B20230E0048B07E = { + CreatedOnToolsVersion = 6.3.2; + }; + 4096BC421B20237D0048B07E = { + CreatedOnToolsVersion = 6.3.2; + }; + 40B75EBC1ADF9EE500F0CB09 = { + CreatedOnToolsVersion = 6.3; + }; + 40B75EF51ADF9F1C00F0CB09 = { + CreatedOnToolsVersion = 6.3; + }; + }; }; - buildConfigurationList = 401FEE4A18A3F92800B445EB /* Build configuration list for PBXProject "Mobily" */; + buildConfigurationList = 40B75B2D1ADEE82900F0CB09 /* Build configuration list for PBXProject "Mobily" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); - mainGroup = 401FEE4618A3F92800B445EB; - productRefGroup = 401FEE5018A3F92800B445EB /* Products */; + mainGroup = 40B75B291ADEE82900F0CB09; + productRefGroup = 40B75B341ADEE82900F0CB09 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( - 401FEE4E18A3F92800B445EB /* Mobily */, + 40B75EBC1ADF9EE500F0CB09 /* MobilyCore-Library */, + 40B75EF51ADF9F1C00F0CB09 /* MobilySocial-Library */, + 4080D1C31B3B44AB00328837 /* MobilyStore-Library */, + 4096BC201B20230E0048B07E /* MobilyCore-Framework */, + 4096BC421B20237D0048B07E /* MobilySocial-Framework */, + 4080D2291B3B44B800328837 /* MobilyStore-Framework */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 401FEE4D18A3F92800B445EB /* Resources */ = { + 4080D2381B3B44B800328837 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4096BC1F1B20230E0048B07E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4096BC411B20237D0048B07E /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 401FEF1A18A3FE3200B445EB /* Application.mobily in Resources */, - 400B4D0A1A1A0D6700F2B61E /* ExampleControllerMainCell.xib in Resources */, - 401FEF1B18A3FE3200B445EB /* Presets.mobily in Resources */, - 407903D01943079600EC8855 /* Mobily.podspec in Resources */, - 9AA83B7B19E536FF009F6C5F /* ExampleControllerMain.xib in Resources */, - 40081AA71A27122300F2FBE6 /* menu-button@2x.png in Resources */, - 40081AA61A27122300F2FBE6 /* menu-button.png in Resources */, - 401FEE8918A3FAE600B445EB /* InfoPlist.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ -/* Begin PBXShellScriptBuildPhase section */ - 412AC5C9C0094AEAB4B73BCE /* Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; +/* Begin PBXSourcesBuildPhase section */ + 4080D1CA1B3B44AB00328837 /* Sources */ = { + isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4080D2491B3B454200328837 /* MobilyStoreManager.m in Sources */, ); - inputPaths = ( - ); - name = "Copy Pods Resources"; - outputPaths = ( + runOnlyForDeploymentPostprocessing = 0; + }; + 4080D22A1B3B44B800328837 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4080D24A1B3B454200328837 /* MobilyStoreManager.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; - showEnvVarsInLog = 0; }; - B5EF831C1EE3466E88C6CC3D /* Check Pods Manifest.lock */ = { - isa = PBXShellScriptBuildPhase; + 4096BC1C1B20230E0048B07E /* Sources */ = { + isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 4096BD7C1B2024DA0048B07E /* MobilyDownloader.m in Sources */, + 4096BE061B2024DA0048B07E /* MobilyTransitionController.m in Sources */, + 4096BDE41B2024DA0048B07E /* MobilySpinnerViewThreeBounce.m in Sources */, + 4096BDAD1B2024DA0048B07E /* MobilyNavigationController.m in Sources */, + 4096BDD41B2024DA0048B07E /* MobilySpinnerViewBounce.m in Sources */, + 4096BD6E1B2024DA0048B07E /* MobilyDataRefreshView.m in Sources */, + 4018900D1B70F08E00440DF7 /* MobilyBadgeView.m in Sources */, + 4096BE021B2024DA0048B07E /* MobilyTimer.m in Sources */, + 4096BD601B2024DA0048B07E /* MobilyDataContainerItemsGrid.m in Sources */, + 4096BDCC1B2024DA0048B07E /* MobilySpinnerView.m in Sources */, + 4096BD721B2024DA0048B07E /* MobilyDataView.m in Sources */, + 4096BD231B2024DA0048B07E /* MobilyApiRequest.m in Sources */, + 4096BDB01B2024DA0048B07E /* MobilyNS.m in Sources */, + 4096BDFF1B2024DA0048B07E /* MobilyTimeout.m in Sources */, + 4064D1911B577A6400F2F0FF /* MobilyImageCropController.m in Sources */, + 4096BDBD1B2024DA0048B07E /* MobilyRegExpParser.m in Sources */, + 4096BD2C1B2024DA0048B07E /* MobilyAudioPlayer.m in Sources */, + 4096BD661B2024DA0048B07E /* MobilyDataContainerSectionsList.m in Sources */, + 4096BDD21B2024DA0048B07E /* MobilySpinnerViewArcAlt.m in Sources */, + 4096BD1D1B2024DA0048B07E /* MobilyApiManager.m in Sources */, + 4096BD291B2024DA0048B07E /* MobilyApplication.m in Sources */, + 4096BDDE1B2024DA0048B07E /* MobilySpinnerViewFadingCircleAlt.m in Sources */, + 4096BDA01B2024DA0048B07E /* MobilyLockScreenPincodeView.m in Sources */, + 4096BD8A1B2024DA0048B07E /* MobilyGrid.m in Sources */, + 4096BDCE1B2024DA0048B07E /* MobilySpinnerView9CubeGrid.m in Sources */, + 4096BD5C1B2024DA0048B07E /* MobilyDataContainerItems.m in Sources */, + 4096BD2F1B2024DA0048B07E /* MobilyAudioRecorder.m in Sources */, + 4096BE191B2024DA0048B07E /* MobilyWindow.m in Sources */, + 4096BD971B2024DA0048B07E /* MobilyListField.m in Sources */, + 4096BD641B2024DA0048B07E /* MobilyDataContainerSections.m in Sources */, + 4096BE0A1B2024DA0048B07E /* MobilyTransitionControllerCrossFade.m in Sources */, + 4096BD1A1B2024DA0048B07E /* MobilyActivityView.m in Sources */, + 4096BDE61B2024DA0048B07E /* MobilySpinnerViewWanderingCubes.m in Sources */, + 4096BD9A1B2024DA0048B07E /* MobilyLoadedView.m in Sources */, + 4096BD9D1B2024DA0048B07E /* MobilyLockScreenController.m in Sources */, + 4096BDED1B2024DA0048B07E /* MobilyStyle.m in Sources */, + 4096BD911B2024DA0048B07E /* MobilyImageView.m in Sources */, + 4096BDE81B2024DA0048B07E /* MobilySpinnerViewWave.m in Sources */, + 4096BDAA1B2024DA0048B07E /* MobilyModelJson.m in Sources */, + 4096BD841B2024DA0048B07E /* MobilyFieldValidation.m in Sources */, + 4096BDD81B2024DA0048B07E /* MobilySpinnerViewCircle.m in Sources */, + 4096BD441B2024DA0048B07E /* MobilyCG.m in Sources */, + 4096BD8E1B2024DA0048B07E /* MobilyHttpQuery.m in Sources */, + 4096BDF61B2024DA0048B07E /* MobilyTaskManager.m in Sources */, + 4096BDA71B2024DA0048B07E /* MobilyModel.m in Sources */, + 4096BD791B2024DA0048B07E /* MobilyDialogController.m in Sources */, + 4096BD941B2024DA0048B07E /* MobilyKVO.m in Sources */, + 4096BD201B2024DA0048B07E /* MobilyApiProvider.m in Sources */, + 4096BDC01B2024DA0048B07E /* MobilyScrollView.m in Sources */, + 40D09BF01B5F819300C9F4CB /* MobilyLayoutView.m in Sources */, + 4096BD261B2024DA0048B07E /* MobilyApiResponse.m in Sources */, + 4096BDE21B2024DA0048B07E /* MobilySpinnerViewPulse.m in Sources */, + 4096BDD01B2024DA0048B07E /* MobilySpinnerViewArc.m in Sources */, + 4096BD561B2024DA0048B07E /* MobilyDataContainer.m in Sources */, + 4096BDDC1B2024DA0048B07E /* MobilySpinnerViewFadingCircle.m in Sources */, + 4096BE161B2024DA0048B07E /* MobilyViewController.m in Sources */, + 4064D1961B577D0900F2F0FF /* MobilyTouchView.m in Sources */, + 4096BDC91B2024DA0048B07E /* MobilySlideController.m in Sources */, + 4096BD5A1B2024DA0048B07E /* MobilyDataContainerCalendarDays.m in Sources */, + 4096BD871B2024DA0048B07E /* MobilyGeoLocationManager.m in Sources */, + 4096BDC61B2024DA0048B07E /* MobilySharedManager.m in Sources */, + 4096BD4A1B2024DA0048B07E /* MobilyController.m in Sources */, + 4096BD521B2024DA0048B07E /* MobilyDataCellSwipe.m in Sources */, + 4096BD331B2024DA0048B07E /* MobilyBlurView.m in Sources */, + 4096BD3B1B2024DA0048B07E /* MobilyButton.m in Sources */, + 4096BD471B2024DA0048B07E /* MobilyContext.m in Sources */, + 4096BE0C1B2024DA0048B07E /* MobilyTransitionControllerSlide.m in Sources */, + 4096BDA31B2024DA0048B07E /* MobilyMap.m in Sources */, + 4096BDB41B2024DA0048B07E /* MobilyPageControl.m in Sources */, + 4096BD621B2024DA0048B07E /* MobilyDataContainerItemsList.m in Sources */, + 4096BD381B2024DA0048B07E /* MobilyBuilderPreset.m in Sources */, + 4096BD801B2024DA0048B07E /* MobilyEvent.m in Sources */, + 4002F3B51B3D425E00961E90 /* MobilyPressAndHoldGestureRecognizer.m in Sources */, + 4096BDDA1B2024DA0048B07E /* MobilySpinnerViewCircleFlip.m in Sources */, + 4096BD581B2024DA0048B07E /* MobilyDataContainerCalendar.m in Sources */, + 4096BD3E1B2024DA0048B07E /* MobilyCA.m in Sources */, + 4096BDEA1B2024DA0048B07E /* MobilySpinnerViewWordPress.m in Sources */, + 4096BDF91B2024DA0048B07E /* MobilyTextField.m in Sources */, + 4096BDD61B2024DA0048B07E /* MobilySpinnerViewChasingDots.m in Sources */, + 4096BD751B2024DA0048B07E /* MobilyDateField.m in Sources */, + 4096BD5E1B2024DA0048B07E /* MobilyDataContainerItemsFlow.m in Sources */, + 4096BE081B2024DA0048B07E /* MobilyTransitionControllerCards.m in Sources */, + 4096BD6A1B2024DA0048B07E /* MobilyDataItem.m in Sources */, + 4096BE0F1B2024DA0048B07E /* MobilyUI.m in Sources */, + 4096BD501B2024DA0048B07E /* MobilyDataCell.m in Sources */, + 4096BE131B2024DA0048B07E /* MobilyView.m in Sources */, + 4096BDFC1B2024DA0048B07E /* MobilyTextView.m in Sources */, + 4096BDC31B2024DA0048B07E /* MobilySearchBar.m in Sources */, + 4096BDF31B2024DA0048B07E /* MobilyTableView.m in Sources */, + 40FF59D91B4421410028CAB2 /* MobilyNotificationManager.m in Sources */, + 4096BD411B2024DA0048B07E /* MobilyCache.m in Sources */, + 4096BDF01B2024DA0048B07E /* MobilyTabBarController.m in Sources */, + 4096BDB71B2024DA0048B07E /* MobilyPageController.m in Sources */, + 4096BDBA1B2024DA0048B07E /* MobilyPopoverController.m in Sources */, + 4096BD361B2024DA0048B07E /* MobilyBuilderForm.m in Sources */, + 4096BDE01B2024DA0048B07E /* MobilySpinnerViewPlane.m in Sources */, ); - inputPaths = ( + runOnlyForDeploymentPostprocessing = 0; + }; + 4096BC3E1B20237D0048B07E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4096BE351B2024E30048B07E /* MobilySocialVKontakteProvider.m in Sources */, + 4096BE2C1B2024E30048B07E /* MobilySocialManager.m in Sources */, + 4096BE321B2024E30048B07E /* MobilySocialTwitterProvider.m in Sources */, + 4096BE2F1B2024E30048B07E /* MobilySocialProvider.m in Sources */, + 4096BE291B2024E30048B07E /* MobilySocialFacebookProvider.m in Sources */, ); - name = "Check Pods Manifest.lock"; - outputPaths = ( + runOnlyForDeploymentPostprocessing = 0; + }; + 40B75EB91ADF9EE500F0CB09 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4096BD7B1B2024DA0048B07E /* MobilyDownloader.m in Sources */, + 4096BE051B2024DA0048B07E /* MobilyTransitionController.m in Sources */, + 4096BDE31B2024DA0048B07E /* MobilySpinnerViewThreeBounce.m in Sources */, + 4096BDAC1B2024DA0048B07E /* MobilyNavigationController.m in Sources */, + 4096BDD31B2024DA0048B07E /* MobilySpinnerViewBounce.m in Sources */, + 4096BD6D1B2024DA0048B07E /* MobilyDataRefreshView.m in Sources */, + 4018900C1B70F08E00440DF7 /* MobilyBadgeView.m in Sources */, + 4096BE011B2024DA0048B07E /* MobilyTimer.m in Sources */, + 4096BD5F1B2024DA0048B07E /* MobilyDataContainerItemsGrid.m in Sources */, + 4096BDCB1B2024DA0048B07E /* MobilySpinnerView.m in Sources */, + 4096BD711B2024DA0048B07E /* MobilyDataView.m in Sources */, + 4096BD221B2024DA0048B07E /* MobilyApiRequest.m in Sources */, + 4096BDAF1B2024DA0048B07E /* MobilyNS.m in Sources */, + 4096BDFE1B2024DA0048B07E /* MobilyTimeout.m in Sources */, + 4064D1901B577A6400F2F0FF /* MobilyImageCropController.m in Sources */, + 4096BDBC1B2024DA0048B07E /* MobilyRegExpParser.m in Sources */, + 4096BD2B1B2024DA0048B07E /* MobilyAudioPlayer.m in Sources */, + 4096BD651B2024DA0048B07E /* MobilyDataContainerSectionsList.m in Sources */, + 4096BDD11B2024DA0048B07E /* MobilySpinnerViewArcAlt.m in Sources */, + 4096BD1C1B2024DA0048B07E /* MobilyApiManager.m in Sources */, + 4096BD281B2024DA0048B07E /* MobilyApplication.m in Sources */, + 4096BDDD1B2024DA0048B07E /* MobilySpinnerViewFadingCircleAlt.m in Sources */, + 4096BD9F1B2024DA0048B07E /* MobilyLockScreenPincodeView.m in Sources */, + 4096BD891B2024DA0048B07E /* MobilyGrid.m in Sources */, + 4096BDCD1B2024DA0048B07E /* MobilySpinnerView9CubeGrid.m in Sources */, + 4096BD5B1B2024DA0048B07E /* MobilyDataContainerItems.m in Sources */, + 4096BD2E1B2024DA0048B07E /* MobilyAudioRecorder.m in Sources */, + 4096BE181B2024DA0048B07E /* MobilyWindow.m in Sources */, + 4096BD961B2024DA0048B07E /* MobilyListField.m in Sources */, + 4096BD631B2024DA0048B07E /* MobilyDataContainerSections.m in Sources */, + 4096BE091B2024DA0048B07E /* MobilyTransitionControllerCrossFade.m in Sources */, + 4096BD191B2024DA0048B07E /* MobilyActivityView.m in Sources */, + 4096BDE51B2024DA0048B07E /* MobilySpinnerViewWanderingCubes.m in Sources */, + 4096BD991B2024DA0048B07E /* MobilyLoadedView.m in Sources */, + 4096BD9C1B2024DA0048B07E /* MobilyLockScreenController.m in Sources */, + 4096BDEC1B2024DA0048B07E /* MobilyStyle.m in Sources */, + 4096BD901B2024DA0048B07E /* MobilyImageView.m in Sources */, + 4096BDE71B2024DA0048B07E /* MobilySpinnerViewWave.m in Sources */, + 4096BDA91B2024DA0048B07E /* MobilyModelJson.m in Sources */, + 4096BD831B2024DA0048B07E /* MobilyFieldValidation.m in Sources */, + 4096BDD71B2024DA0048B07E /* MobilySpinnerViewCircle.m in Sources */, + 4096BD431B2024DA0048B07E /* MobilyCG.m in Sources */, + 4096BD8D1B2024DA0048B07E /* MobilyHttpQuery.m in Sources */, + 4096BDF51B2024DA0048B07E /* MobilyTaskManager.m in Sources */, + 4096BDA61B2024DA0048B07E /* MobilyModel.m in Sources */, + 4096BD781B2024DA0048B07E /* MobilyDialogController.m in Sources */, + 4096BD931B2024DA0048B07E /* MobilyKVO.m in Sources */, + 4096BD1F1B2024DA0048B07E /* MobilyApiProvider.m in Sources */, + 4096BDBF1B2024DA0048B07E /* MobilyScrollView.m in Sources */, + 40D09BEF1B5F819300C9F4CB /* MobilyLayoutView.m in Sources */, + 4096BD251B2024DA0048B07E /* MobilyApiResponse.m in Sources */, + 4096BDE11B2024DA0048B07E /* MobilySpinnerViewPulse.m in Sources */, + 4096BDCF1B2024DA0048B07E /* MobilySpinnerViewArc.m in Sources */, + 4096BD551B2024DA0048B07E /* MobilyDataContainer.m in Sources */, + 4096BDDB1B2024DA0048B07E /* MobilySpinnerViewFadingCircle.m in Sources */, + 4096BE151B2024DA0048B07E /* MobilyViewController.m in Sources */, + 4064D1951B577D0900F2F0FF /* MobilyTouchView.m in Sources */, + 4096BDC81B2024DA0048B07E /* MobilySlideController.m in Sources */, + 4096BD591B2024DA0048B07E /* MobilyDataContainerCalendarDays.m in Sources */, + 4096BD861B2024DA0048B07E /* MobilyGeoLocationManager.m in Sources */, + 4096BDC51B2024DA0048B07E /* MobilySharedManager.m in Sources */, + 4096BD491B2024DA0048B07E /* MobilyController.m in Sources */, + 4096BD511B2024DA0048B07E /* MobilyDataCellSwipe.m in Sources */, + 4096BD321B2024DA0048B07E /* MobilyBlurView.m in Sources */, + 4096BD3A1B2024DA0048B07E /* MobilyButton.m in Sources */, + 4096BD461B2024DA0048B07E /* MobilyContext.m in Sources */, + 4096BE0B1B2024DA0048B07E /* MobilyTransitionControllerSlide.m in Sources */, + 4096BDA21B2024DA0048B07E /* MobilyMap.m in Sources */, + 4096BDB31B2024DA0048B07E /* MobilyPageControl.m in Sources */, + 4096BD611B2024DA0048B07E /* MobilyDataContainerItemsList.m in Sources */, + 4096BD371B2024DA0048B07E /* MobilyBuilderPreset.m in Sources */, + 4096BD7F1B2024DA0048B07E /* MobilyEvent.m in Sources */, + 4002F3B41B3D425E00961E90 /* MobilyPressAndHoldGestureRecognizer.m in Sources */, + 4096BDD91B2024DA0048B07E /* MobilySpinnerViewCircleFlip.m in Sources */, + 4096BD571B2024DA0048B07E /* MobilyDataContainerCalendar.m in Sources */, + 4096BD3D1B2024DA0048B07E /* MobilyCA.m in Sources */, + 4096BDE91B2024DA0048B07E /* MobilySpinnerViewWordPress.m in Sources */, + 4096BDF81B2024DA0048B07E /* MobilyTextField.m in Sources */, + 4096BDD51B2024DA0048B07E /* MobilySpinnerViewChasingDots.m in Sources */, + 4096BD741B2024DA0048B07E /* MobilyDateField.m in Sources */, + 4096BD5D1B2024DA0048B07E /* MobilyDataContainerItemsFlow.m in Sources */, + 4096BE071B2024DA0048B07E /* MobilyTransitionControllerCards.m in Sources */, + 4096BD691B2024DA0048B07E /* MobilyDataItem.m in Sources */, + 4096BE0E1B2024DA0048B07E /* MobilyUI.m in Sources */, + 4096BD4F1B2024DA0048B07E /* MobilyDataCell.m in Sources */, + 4096BE121B2024DA0048B07E /* MobilyView.m in Sources */, + 4096BDFB1B2024DA0048B07E /* MobilyTextView.m in Sources */, + 4096BDC21B2024DA0048B07E /* MobilySearchBar.m in Sources */, + 4096BDF21B2024DA0048B07E /* MobilyTableView.m in Sources */, + 40FF59D81B4421410028CAB2 /* MobilyNotificationManager.m in Sources */, + 4096BD401B2024DA0048B07E /* MobilyCache.m in Sources */, + 4096BDEF1B2024DA0048B07E /* MobilyTabBarController.m in Sources */, + 4096BDB61B2024DA0048B07E /* MobilyPageController.m in Sources */, + 4096BDB91B2024DA0048B07E /* MobilyPopoverController.m in Sources */, + 4096BD351B2024DA0048B07E /* MobilyBuilderForm.m in Sources */, + 4096BDDF1B2024DA0048B07E /* MobilySpinnerViewPlane.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n"; - showEnvVarsInLog = 0; }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 401FEE4B18A3F92800B445EB /* Sources */ = { + 40B75EF21ADF9F1C00F0CB09 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 401FEEF618A3FAF100B445EB /* MobilyStorage.m in Sources */, - 40081AA31A27122300F2FBE6 /* SlideNavigationContorllerAnimatorScaleAndFade.m in Sources */, - 40798A361948AC0600A04686 /* MobilyViewFieldList.m in Sources */, - 401FEEFE18A3FAF100B445EB /* MobilyContext.m in Sources */, - 401FEEF118A3FAF100B445EB /* MobilyEvent.m in Sources */, - 401FEF0018A3FAF100B445EB /* MobilyControllerNavigation.m in Sources */, - 40081AA51A27122300F2FBE6 /* SlideNavigationContorllerAnimatorSlideAndFade.m in Sources */, - 40798A411948C0F700A04686 /* MobilyViewElementsLayout.m in Sources */, - 401FEF1218A3FAF100B445EB /* MobilyWindow.m in Sources */, - 401FEEF518A3FAF100B445EB /* MobilyNS.m in Sources */, - 407989E41947834F00A04686 /* MobilyTransitionController.m in Sources */, - 401FEF0718A3FAF100B445EB /* MobilyUI.m in Sources */, - 40798A351948AC0600A04686 /* MobilyViewFieldDate.m in Sources */, - 407903D219464A1E00EC8855 /* MobilyBuilderPreset.m in Sources */, - 40798A421948C0F700A04686 /* MobilyViewElements.m in Sources */, - 407989E7194788EE00A04686 /* MobilyTransitionControllerCards.m in Sources */, - 401FEE8B18A3FAE600B445EB /* main.m in Sources */, - 407989E8194788EE00A04686 /* MobilyTransitionControllerCrossFade.m in Sources */, - 40081AA41A27122300F2FBE6 /* SlideNavigationContorllerAnimatorSlide.m in Sources */, - 401FEF0118A3FAF100B445EB /* MobilyControllerTabBar.m in Sources */, - 401FEEF018A3FAF100B445EB /* MobilyCG.m in Sources */, - 40081AA81A27122300F2FBE6 /* SlideNavigationController.m in Sources */, - 401FEEFF18A3FAF100B445EB /* MobilyController.m in Sources */, - 40081AA01A27122300F2FBE6 /* MobilyControllerSlideMenu.m in Sources */, - 40081AA21A27122300F2FBE6 /* SlideNavigationContorllerAnimatorScale.m in Sources */, - 40081AA11A27122300F2FBE6 /* SlideNavigationContorllerAnimatorFade.m in Sources */, - 401FEF0218A3FAF100B445EB /* MobilyControllerView.m in Sources */, - 401FEEF718A3FAF100B445EB /* MobilyTaskManager.m in Sources */, - 401FEEF318A3FAF100B445EB /* MobilyHttpQuery.m in Sources */, - 401FEF0618A3FAF100B445EB /* MobilyBuilderForm.m in Sources */, - 40798A2B1948ABAF00A04686 /* MobilyRegExpParser.m in Sources */, - 4032580B1A0BBBA700949E8F /* MobilyViewScroll.m in Sources */, - 40798A3B1948AFC400A04686 /* MobilyViewImage.m in Sources */, - 401FEE8A18A3FAE600B445EB /* ExampleApplication.m in Sources */, - 400B4D081A19E29900F2B61E /* MobilyViewTable.m in Sources */, - 407989EC19484C9700A04686 /* MobilyControllerDynamicsDrawer.m in Sources */, - 401FEEFD18A3FAF100B445EB /* MobilyApplication.m in Sources */, - 40798A371948AC0600A04686 /* MobilyViewFieldText.m in Sources */, - 401FEEF418A3FAF100B445EB /* MobilyKVO.m in Sources */, + 4096BE341B2024E30048B07E /* MobilySocialVKontakteProvider.m in Sources */, + 4096BE2B1B2024E30048B07E /* MobilySocialManager.m in Sources */, + 4096BE311B2024E30048B07E /* MobilySocialTwitterProvider.m in Sources */, + 4096BE2E1B2024E30048B07E /* MobilySocialProvider.m in Sources */, + 4096BE281B2024E30048B07E /* MobilySocialFacebookProvider.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXVariantGroup section */ - 401FEE8218A3FAE600B445EB /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 401FEE8318A3FAE600B445EB /* en */, - ); - name = InfoPlist.strings; - sourceTree = ""; +/* Begin PBXTargetDependency section */ + 4080D23F1B3B44E500328837 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 40B75EBC1ADF9EE500F0CB09 /* MobilyCore-Library */; + targetProxy = 4080D23E1B3B44E500328837 /* PBXContainerItemProxy */; + }; + 4080D2431B3B44F300328837 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4096BC201B20230E0048B07E /* MobilyCore-Framework */; + targetProxy = 4080D2421B3B44F300328837 /* PBXContainerItemProxy */; }; -/* End PBXVariantGroup section */ + 40B7601A1ADFA05000F0CB09 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 40B75EBC1ADF9EE500F0CB09 /* MobilyCore-Library */; + targetProxy = 40B760191ADFA05000F0CB09 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - 401FEE7918A3F92800B445EB /* Debug */ = { + 4080D2261B3B44AB00328837 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = MobilyStore; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 4080D2271B3B44AB00328837 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = MobilyStore; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 4080D23A1B3B44B800328837 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = Support/MobilyStore.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "Mobily.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "MobilyStore-Framework"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 4080D23B1B3B44B800328837 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Support/MobilyStore.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "Mobily.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "MobilyStore-Framework"; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 4096BC351B20230F0048B07E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = Support/MobilyCore.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "Mobily.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = MobilyCore; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 4096BC361B20230F0048B07E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Support/MobilyCore.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "Mobily.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = MobilyCore; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 4096BC571B20237D0048B07E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + INFOPLIST_FILE = Support/MobilySocial.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "Mobily.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = MobilySocial; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 4096BC581B20237D0048B07E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = Support/MobilySocial.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "Mobily.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = MobilySocial; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 40B75B471ADEE82A00F0CB09 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -654,11 +1640,17 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_IDENTITY = "iPhone Developer"; COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -668,20 +1660,27 @@ GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(PROJECT_DIR)/Sources/**", + ); + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; }; name = Debug; }; - 401FEE7A18A3F92800B445EB /* Release */ = { + 40B75B481ADEE82A00F0CB09 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; @@ -693,74 +1692,156 @@ CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = YES; + CODE_SIGN_IDENTITY = "iPhone Distribution"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 6.0; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(PROJECT_DIR)/Sources/**", + ); + IPHONEOS_DEPLOYMENT_TARGET = 7.0; + MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; + 40B75ECF1ADF9EE600F0CB09 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = MobilyCore; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 40B75ED01ADF9EE600F0CB09 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = MobilyCore; + SKIP_INSTALL = YES; }; name = Release; }; - 401FEE7C18A3F92800B445EB /* Debug */ = { + 40B75F081ADF9F1D00F0CB09 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 2BBC62D562492FDF2CDB1707 /* Pods.debug.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "Mobily/Mobily-Prefix.pch"; - INFOPLIST_FILE = "Mobily/Mobily-Info.plist"; - PRODUCT_NAME = "$(TARGET_NAME)"; - WRAPPER_EXTENSION = app; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + ); + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = MobilySocial; + SKIP_INSTALL = YES; }; name = Debug; }; - 401FEE7D18A3F92800B445EB /* Release */ = { + 40B75F091ADF9F1D00F0CB09 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5A2438BFA45DA754D1C37067 /* Pods.release.xcconfig */; buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "Mobily/Mobily-Prefix.pch"; - INFOPLIST_FILE = "Mobily/Mobily-Info.plist"; - PRODUCT_NAME = "$(TARGET_NAME)"; - WRAPPER_EXTENSION = app; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Frameworks", + ); + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = MobilySocial; + SKIP_INSTALL = YES; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 401FEE4A18A3F92800B445EB /* Build configuration list for PBXProject "Mobily" */ = { + 4080D2251B3B44AB00328837 /* Build configuration list for PBXNativeTarget "MobilyStore-Library" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4080D2261B3B44AB00328837 /* Debug */, + 4080D2271B3B44AB00328837 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4080D2391B3B44B800328837 /* Build configuration list for PBXNativeTarget "MobilyStore-Framework" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4080D23A1B3B44B800328837 /* Debug */, + 4080D23B1B3B44B800328837 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4096BC341B20230F0048B07E /* Build configuration list for PBXNativeTarget "MobilyCore-Framework" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4096BC351B20230F0048B07E /* Debug */, + 4096BC361B20230F0048B07E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 4096BC561B20237D0048B07E /* Build configuration list for PBXNativeTarget "MobilySocial-Framework" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4096BC571B20237D0048B07E /* Debug */, + 4096BC581B20237D0048B07E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 40B75B2D1ADEE82900F0CB09 /* Build configuration list for PBXProject "Mobily" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 40B75B471ADEE82A00F0CB09 /* Debug */, + 40B75B481ADEE82A00F0CB09 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 40B75ECE1ADF9EE600F0CB09 /* Build configuration list for PBXNativeTarget "MobilyCore-Library" */ = { isa = XCConfigurationList; buildConfigurations = ( - 401FEE7918A3F92800B445EB /* Debug */, - 401FEE7A18A3F92800B445EB /* Release */, + 40B75ECF1ADF9EE600F0CB09 /* Debug */, + 40B75ED01ADF9EE600F0CB09 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 401FEE7B18A3F92800B445EB /* Build configuration list for PBXNativeTarget "Mobily" */ = { + 40B75F071ADF9F1D00F0CB09 /* Build configuration list for PBXNativeTarget "MobilySocial-Library" */ = { isa = XCConfigurationList; buildConfigurations = ( - 401FEE7C18A3F92800B445EB /* Debug */, - 401FEE7D18A3F92800B445EB /* Release */, + 40B75F081ADF9F1D00F0CB09 /* Debug */, + 40B75F091ADF9F1D00F0CB09 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; - rootObject = 401FEE4718A3F92800B445EB /* Project object */; + rootObject = 40B75B2A1ADEE82900F0CB09 /* Project object */; } diff --git a/Mobily.xcodeproj/project.xcworkspace/xcuserdata/fgengine.xcuserdatad/UserInterfaceState.xcuserstate b/Mobily.xcodeproj/project.xcworkspace/xcuserdata/fgengine.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index c52f086..0000000 Binary files a/Mobily.xcodeproj/project.xcworkspace/xcuserdata/fgengine.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/Mobily.xcodeproj/project.xcworkspace/xcuserdata/fgengine.xcuserdatad/WorkspaceSettings.xcsettings b/Mobily.xcodeproj/project.xcworkspace/xcuserdata/fgengine.xcuserdatad/WorkspaceSettings.xcsettings deleted file mode 100644 index bfffcfe..0000000 --- a/Mobily.xcodeproj/project.xcworkspace/xcuserdata/fgengine.xcuserdatad/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,10 +0,0 @@ - - - - - HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges - - SnapshotAutomaticallyBeforeSignificantChanges - - - diff --git a/Mobily.xcodeproj/xcuserdata/dmitrykuzmenko.xcuserdatad/xcschemes/Mobily.xcscheme b/Mobily.xcodeproj/xcuserdata/dmitrykuzmenko.xcuserdatad/xcschemes/Mobily.xcscheme deleted file mode 100644 index 17d4ded..0000000 --- a/Mobily.xcodeproj/xcuserdata/dmitrykuzmenko.xcuserdatad/xcschemes/Mobily.xcscheme +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Mobily.xcodeproj/xcuserdata/dmitrykuzmenko.xcuserdatad/xcschemes/xcschememanagement.plist b/Mobily.xcodeproj/xcuserdata/dmitrykuzmenko.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index e9a0f16..0000000 --- a/Mobily.xcodeproj/xcuserdata/dmitrykuzmenko.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - SchemeUserState - - Mobily.xcscheme - - orderHint - 0 - - - SuppressBuildableAutocreation - - 401FEE4E18A3F92800B445EB - - primary - - - - - diff --git a/Mobily.xcodeproj/xcuserdata/fgengine.xcuserdatad/xcschemes/Mobily.xcscheme b/Mobily.xcodeproj/xcuserdata/fgengine.xcuserdatad/xcschemes/Mobily.xcscheme deleted file mode 100644 index cef95fb..0000000 --- a/Mobily.xcodeproj/xcuserdata/fgengine.xcuserdatad/xcschemes/Mobily.xcscheme +++ /dev/null @@ -1,86 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Mobily.xcodeproj/xcuserdata/fgengine.xcuserdatad/xcschemes/xcschememanagement.plist b/Mobily.xcodeproj/xcuserdata/fgengine.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index b46f2dd..0000000 --- a/Mobily.xcodeproj/xcuserdata/fgengine.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,27 +0,0 @@ - - - - - SchemeUserState - - Mobily.xcscheme - - orderHint - 0 - - - SuppressBuildableAutocreation - - 401FEE4E18A3F92800B445EB - - primary - - - 401FEE6918A3F92800B445EB - - primary - - - - - diff --git a/Mobily.xcworkspace/contents.xcworkspacedata b/Mobily.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 6a7b1f2..0000000 --- a/Mobily.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/Mobily.xcworkspace/xcshareddata/Mobily.xccheckout b/Mobily.xcworkspace/xcshareddata/Mobily.xccheckout deleted file mode 100644 index 28b0074..0000000 --- a/Mobily.xcworkspace/xcshareddata/Mobily.xccheckout +++ /dev/null @@ -1,41 +0,0 @@ - - - - - IDESourceControlProjectFavoriteDictionaryKey - - IDESourceControlProjectIdentifier - 610DC57D-4A5F-40E4-9BB5-C9B9D17E5763 - IDESourceControlProjectName - Mobily - IDESourceControlProjectOriginsDictionary - - 440910C375A8EE7431218974383484AB7779E3EB - https://github.com/fgengine/mobily-ios.git - - IDESourceControlProjectPath - Mobily.xcworkspace - IDESourceControlProjectRelativeInstallPathDictionary - - 440910C375A8EE7431218974383484AB7779E3EB - .. - - IDESourceControlProjectURL - https://github.com/fgengine/mobily-ios.git - IDESourceControlProjectVersion - 111 - IDESourceControlProjectWCCIdentifier - 440910C375A8EE7431218974383484AB7779E3EB - IDESourceControlProjectWCConfigurations - - - IDESourceControlRepositoryExtensionIdentifierKey - public.vcs.git - IDESourceControlWCCIdentifierKey - 440910C375A8EE7431218974383484AB7779E3EB - IDESourceControlWCCName - Mobily-iOS - - - - diff --git a/Mobily.xcworkspace/xcuserdata/dmitrykuzmenko.xcuserdatad/UserInterfaceState.xcuserstate b/Mobily.xcworkspace/xcuserdata/dmitrykuzmenko.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index fe902d0..0000000 Binary files a/Mobily.xcworkspace/xcuserdata/dmitrykuzmenko.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/Mobily.xcworkspace/xcuserdata/dmitrykuzmenko.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Mobily.xcworkspace/xcuserdata/dmitrykuzmenko.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index 15cc49f..0000000 --- a/Mobily.xcworkspace/xcuserdata/dmitrykuzmenko.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - diff --git a/Mobily.xcworkspace/xcuserdata/fgengine.xcuserdatad/UserInterfaceState.xcuserstate b/Mobily.xcworkspace/xcuserdata/fgengine.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index c90ff9a..0000000 Binary files a/Mobily.xcworkspace/xcuserdata/fgengine.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/Mobily.xcworkspace/xcuserdata/fgengine.xcuserdatad/WorkspaceSettings.xcsettings b/Mobily.xcworkspace/xcuserdata/fgengine.xcuserdatad/WorkspaceSettings.xcsettings deleted file mode 100644 index bfffcfe..0000000 --- a/Mobily.xcworkspace/xcuserdata/fgengine.xcuserdatad/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,10 +0,0 @@ - - - - - HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges - - SnapshotAutomaticallyBeforeSignificantChanges - - - diff --git a/Mobily.xcworkspace/xcuserdata/fgengine.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Mobily.xcworkspace/xcuserdata/fgengine.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index ed9a9b4..0000000 --- a/Mobily.xcworkspace/xcuserdata/fgengine.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/Mobily.xcworkspace/xcuserdata/fgengine.xcuserdatad/xcdebugger/Expressions.xcexplist b/Mobily.xcworkspace/xcuserdata/fgengine.xcuserdatad/xcdebugger/Expressions.xcexplist deleted file mode 100644 index 5967b84..0000000 --- a/Mobily.xcworkspace/xcuserdata/fgengine.xcuserdatad/xcdebugger/Expressions.xcexplist +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Mobily/Application.mobily b/Mobily/Application.mobily deleted file mode 100644 index f3cbd1f..0000000 --- a/Mobily/Application.mobily +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/Mobily/ExampleApplication.m b/Mobily/ExampleApplication.m deleted file mode 100644 index 2795041..0000000 --- a/Mobily/ExampleApplication.m +++ /dev/null @@ -1,142 +0,0 @@ -/*--------------------------------------------------*/ -/* */ -/* The MIT License (MIT) */ -/* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ -/* */ -/* Permission is hereby granted, free of charge, */ -/* to any person obtaining a copy of this software */ -/* and associated documentation files */ -/* (the "Software"), to deal in the Software */ -/* without restriction, including without */ -/* limitation the rights to use, copy, modify, */ -/* merge, publish, distribute, sublicense, */ -/* and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished */ -/* to do so, subject to the following conditions: */ -/* */ -/* The above copyright notice and this permission */ -/* notice shall be included in all copies or */ -/* substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ -/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ -/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ -/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ -/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ -/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ -/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ -/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ -/* OTHERWISE, ARISING FROM, OUT OF OR IN */ -/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ -/* OTHER DEALINGS IN THE SOFTWARE. */ -/* */ -/*--------------------------------------------------*/ - -#import "ExampleApplication.h" - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation ExampleApplication - -- (void)setupApplication { - [super setupApplication]; -} - -- (void)dealloc { - MOBILY_SAFE_DEALLOC; -} - -- (BOOL)launchingWithOptions:(NSDictionary *)options { - BOOL result = [super launchingWithOptions:options]; - if(result == YES) { - [_slideView setLeftMenu:_leftView]; - [_slideView setRightMenu:_rightView]; - } - return result; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation ExampleControllerMain - -- (void)setupController { - [super setupController]; - - [self setTitle:@"TITLE"]; - [self setEdgesForExtendedLayout:UIRectEdgeNone]; - - [self setDataSource:@[ @"Data #1", @"Data #2", @"Data #3", - @"Data #4", @"Data #5", @"Data #6", - @"Data #7", @"Data #8", @"Data #9", - @"Data #10", @"Data #11", @"Data #12" ]]; -} - -- (void)dealloc { - MOBILY_SAFE_DEALLOC; -} - -- (BOOL)slideNavigationControllerShouldDisplayLeftMenu { - return YES; -} - -- (BOOL)slideNavigationControllerShouldDisplayRightMenu { - return YES; -} - -- (void)viewDidLoad { - [super viewDidLoad]; - - [_viewTable registerCellClass:[ExampleControllerMainCell class]]; -} - -- (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section { - return [_dataSource count]; -} - -- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath { - ExampleControllerMainCell* cell = [_viewTable dequeueReusableCellWithClass:[ExampleControllerMainCell class]]; - if(cell != nil) { - [cell setModel:[_dataSource objectAtIndex:[indexPath row]]]; - } - return cell; -} - -- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath { - return [ExampleControllerMainCell heightForModel:[_dataSource objectAtIndex:[indexPath row]] tableView:tableView]; -} - -@end - -/*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ - -@implementation ExampleControllerMainCell - -- (void)setupView { - [super setupView]; -} - -- (void)setModel:(id)model { - [super setModel:model]; - - [_viewTitle setText:model]; -} - -- (void)layoutSubviews { - [super layoutSubviews]; - - [_viewTitle setFrame:CGRectInset([[self contentView] bounds], 24.0f, 24.0f)]; - NSLog(@"layoutSubviews"); -} - -@end - -/*--------------------------------------------------*/ diff --git a/Mobily/ExampleControllerMain.xib b/Mobily/ExampleControllerMain.xib deleted file mode 100644 index b78aff7..0000000 --- a/Mobily/ExampleControllerMain.xib +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Mobily/ExampleControllerMainCell.xib b/Mobily/ExampleControllerMainCell.xib deleted file mode 100644 index b739ab1..0000000 --- a/Mobily/ExampleControllerMainCell.xib +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Mobily/Mobily-Info.plist b/Mobily/Mobily-Info.plist deleted file mode 100644 index 1a86834..0000000 --- a/Mobily/Mobily-Info.plist +++ /dev/null @@ -1,46 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - ${PRODUCT_NAME} - CFBundleExecutable - ${EXECUTABLE_NAME} - CFBundleIdentifier - org.fgengine.mobily.${PRODUCT_NAME:rfc1034identifier} - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - ${PRODUCT_NAME} - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - LSRequiresIPhoneOS - - UIRequiredDeviceCapabilities - - armv7 - - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - UIInterfaceOrientationPortraitUpsideDown - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - - diff --git a/Mobily/Presets.mobily b/Mobily/Presets.mobily deleted file mode 100644 index 1b9ba58..0000000 --- a/Mobily/Presets.mobily +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/Mobily/en.lproj/InfoPlist.strings b/Mobily/en.lproj/InfoPlist.strings deleted file mode 100644 index 477b28f..0000000 --- a/Mobily/en.lproj/InfoPlist.strings +++ /dev/null @@ -1,2 +0,0 @@ -/* Localized versions of Info.plist keys */ - diff --git a/PodInstall.command b/PodInstall.command deleted file mode 100755 index 715c9a4..0000000 --- a/PodInstall.command +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -cd "$(dirname "$0")" -pod install \ No newline at end of file diff --git a/PodSpecLint.command b/PodSpecLint.command deleted file mode 100755 index b3b65e7..0000000 --- a/PodSpecLint.command +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -cd "$(dirname "$0")" -pod spec lint ./Mobily.podspec \ No newline at end of file diff --git a/PodSpecPush.command b/PodSpecPush.command deleted file mode 100755 index ba902ff..0000000 --- a/PodSpecPush.command +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -cd "$(dirname "$0")" -pod trunk push ./Mobily.podspec \ No newline at end of file diff --git a/PodUpdate.command b/PodUpdate.command deleted file mode 100755 index 7500529..0000000 --- a/PodUpdate.command +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -cd "$(dirname "$0")" -pod update \ No newline at end of file diff --git a/Podfile b/Podfile deleted file mode 100755 index 98da9d5..0000000 --- a/Podfile +++ /dev/null @@ -1,2 +0,0 @@ -platform :ios, '7.0' -pod 'MSDynamicsDrawerViewController' diff --git a/Podfile.lock b/Podfile.lock deleted file mode 100644 index ccc85b6..0000000 --- a/Podfile.lock +++ /dev/null @@ -1,10 +0,0 @@ -PODS: - - MSDynamicsDrawerViewController (1.5.1) - -DEPENDENCIES: - - MSDynamicsDrawerViewController - -SPEC CHECKSUMS: - MSDynamicsDrawerViewController: 0002059480a4b5ddde7eafbafb958a79a9b0ffaf - -COCOAPODS: 0.34.4 diff --git a/Project/MobilyExample/MobilyExample.xcodeproj/project.pbxproj b/Project/MobilyExample/MobilyExample.xcodeproj/project.pbxproj deleted file mode 100644 index cceb320..0000000 --- a/Project/MobilyExample/MobilyExample.xcodeproj/project.pbxproj +++ /dev/null @@ -1,458 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 46; - objects = { - -/* Begin PBXBuildFile section */ - 401FEDE618A3F82D00B445EB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 401FEDE518A3F82D00B445EB /* Foundation.framework */; }; - 401FEDE818A3F82D00B445EB /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 401FEDE718A3F82D00B445EB /* CoreGraphics.framework */; }; - 401FEDEA18A3F82D00B445EB /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 401FEDE918A3F82D00B445EB /* UIKit.framework */; }; - 401FEDF018A3F82D00B445EB /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 401FEDEE18A3F82D00B445EB /* InfoPlist.strings */; }; - 401FEDF218A3F82D00B445EB /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEDF118A3F82D00B445EB /* main.m */; }; - 401FEDF618A3F82D00B445EB /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEDF518A3F82D00B445EB /* AppDelegate.m */; }; - 401FEDF818A3F82D00B445EB /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 401FEDF718A3F82D00B445EB /* Images.xcassets */; }; - 401FEDFF18A3F82D00B445EB /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 401FEDFE18A3F82D00B445EB /* XCTest.framework */; }; - 401FEE0018A3F82D00B445EB /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 401FEDE518A3F82D00B445EB /* Foundation.framework */; }; - 401FEE0118A3F82D00B445EB /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 401FEDE918A3F82D00B445EB /* UIKit.framework */; }; - 401FEE0918A3F82D00B445EB /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 401FEE0718A3F82D00B445EB /* InfoPlist.strings */; }; - 401FEE0B18A3F82D00B445EB /* MobilyExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 401FEE0A18A3F82D00B445EB /* MobilyExampleTests.m */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 401FEE0218A3F82D00B445EB /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 401FEDDA18A3F82D00B445EB /* Project object */; - proxyType = 1; - remoteGlobalIDString = 401FEDE118A3F82D00B445EB; - remoteInfo = MobilyExample; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 401FEDE218A3F82D00B445EB /* MobilyExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MobilyExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 401FEDE518A3F82D00B445EB /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - 401FEDE718A3F82D00B445EB /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; - 401FEDE918A3F82D00B445EB /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; - 401FEDED18A3F82D00B445EB /* MobilyExample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "MobilyExample-Info.plist"; sourceTree = ""; }; - 401FEDEF18A3F82D00B445EB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 401FEDF118A3F82D00B445EB /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; - 401FEDF318A3F82D00B445EB /* MobilyExample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "MobilyExample-Prefix.pch"; sourceTree = ""; }; - 401FEDF418A3F82D00B445EB /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; - 401FEDF518A3F82D00B445EB /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; - 401FEDF718A3F82D00B445EB /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; - 401FEDFD18A3F82D00B445EB /* MobilyExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MobilyExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 401FEDFE18A3F82D00B445EB /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; - 401FEE0618A3F82D00B445EB /* MobilyExampleTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "MobilyExampleTests-Info.plist"; sourceTree = ""; }; - 401FEE0818A3F82D00B445EB /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 401FEE0A18A3F82D00B445EB /* MobilyExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MobilyExampleTests.m; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 401FEDDF18A3F82D00B445EB /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 401FEDE818A3F82D00B445EB /* CoreGraphics.framework in Frameworks */, - 401FEDEA18A3F82D00B445EB /* UIKit.framework in Frameworks */, - 401FEDE618A3F82D00B445EB /* Foundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 401FEDFA18A3F82D00B445EB /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 401FEDFF18A3F82D00B445EB /* XCTest.framework in Frameworks */, - 401FEE0118A3F82D00B445EB /* UIKit.framework in Frameworks */, - 401FEE0018A3F82D00B445EB /* Foundation.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 401FEDD918A3F82D00B445EB = { - isa = PBXGroup; - children = ( - 401FEDEB18A3F82D00B445EB /* MobilyExample */, - 401FEE0418A3F82D00B445EB /* MobilyExampleTests */, - 401FEDE418A3F82D00B445EB /* Frameworks */, - 401FEDE318A3F82D00B445EB /* Products */, - ); - sourceTree = ""; - }; - 401FEDE318A3F82D00B445EB /* Products */ = { - isa = PBXGroup; - children = ( - 401FEDE218A3F82D00B445EB /* MobilyExample.app */, - 401FEDFD18A3F82D00B445EB /* MobilyExampleTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 401FEDE418A3F82D00B445EB /* Frameworks */ = { - isa = PBXGroup; - children = ( - 401FEDE518A3F82D00B445EB /* Foundation.framework */, - 401FEDE718A3F82D00B445EB /* CoreGraphics.framework */, - 401FEDE918A3F82D00B445EB /* UIKit.framework */, - 401FEDFE18A3F82D00B445EB /* XCTest.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 401FEDEB18A3F82D00B445EB /* MobilyExample */ = { - isa = PBXGroup; - children = ( - 401FEDF418A3F82D00B445EB /* AppDelegate.h */, - 401FEDF518A3F82D00B445EB /* AppDelegate.m */, - 401FEDF718A3F82D00B445EB /* Images.xcassets */, - 401FEDEC18A3F82D00B445EB /* Supporting Files */, - ); - path = MobilyExample; - sourceTree = ""; - }; - 401FEDEC18A3F82D00B445EB /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 401FEDED18A3F82D00B445EB /* MobilyExample-Info.plist */, - 401FEDEE18A3F82D00B445EB /* InfoPlist.strings */, - 401FEDF118A3F82D00B445EB /* main.m */, - 401FEDF318A3F82D00B445EB /* MobilyExample-Prefix.pch */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 401FEE0418A3F82D00B445EB /* MobilyExampleTests */ = { - isa = PBXGroup; - children = ( - 401FEE0A18A3F82D00B445EB /* MobilyExampleTests.m */, - 401FEE0518A3F82D00B445EB /* Supporting Files */, - ); - path = MobilyExampleTests; - sourceTree = ""; - }; - 401FEE0518A3F82D00B445EB /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 401FEE0618A3F82D00B445EB /* MobilyExampleTests-Info.plist */, - 401FEE0718A3F82D00B445EB /* InfoPlist.strings */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 401FEDE118A3F82D00B445EB /* MobilyExample */ = { - isa = PBXNativeTarget; - buildConfigurationList = 401FEE0E18A3F82D00B445EB /* Build configuration list for PBXNativeTarget "MobilyExample" */; - buildPhases = ( - 401FEDDE18A3F82D00B445EB /* Sources */, - 401FEDDF18A3F82D00B445EB /* Frameworks */, - 401FEDE018A3F82D00B445EB /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = MobilyExample; - productName = MobilyExample; - productReference = 401FEDE218A3F82D00B445EB /* MobilyExample.app */; - productType = "com.apple.product-type.application"; - }; - 401FEDFC18A3F82D00B445EB /* MobilyExampleTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 401FEE1118A3F82D00B445EB /* Build configuration list for PBXNativeTarget "MobilyExampleTests" */; - buildPhases = ( - 401FEDF918A3F82D00B445EB /* Sources */, - 401FEDFA18A3F82D00B445EB /* Frameworks */, - 401FEDFB18A3F82D00B445EB /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 401FEE0318A3F82D00B445EB /* PBXTargetDependency */, - ); - name = MobilyExampleTests; - productName = MobilyExampleTests; - productReference = 401FEDFD18A3F82D00B445EB /* MobilyExampleTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 401FEDDA18A3F82D00B445EB /* Project object */ = { - isa = PBXProject; - attributes = { - LastUpgradeCheck = 0500; - ORGANIZATIONNAME = fgengine; - TargetAttributes = { - 401FEDFC18A3F82D00B445EB = { - TestTargetID = 401FEDE118A3F82D00B445EB; - }; - }; - }; - buildConfigurationList = 401FEDDD18A3F82D00B445EB /* Build configuration list for PBXProject "MobilyExample" */; - compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; - hasScannedForEncodings = 0; - knownRegions = ( - en, - ); - mainGroup = 401FEDD918A3F82D00B445EB; - productRefGroup = 401FEDE318A3F82D00B445EB /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 401FEDE118A3F82D00B445EB /* MobilyExample */, - 401FEDFC18A3F82D00B445EB /* MobilyExampleTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 401FEDE018A3F82D00B445EB /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 401FEDF018A3F82D00B445EB /* InfoPlist.strings in Resources */, - 401FEDF818A3F82D00B445EB /* Images.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 401FEDFB18A3F82D00B445EB /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 401FEE0918A3F82D00B445EB /* InfoPlist.strings in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 401FEDDE18A3F82D00B445EB /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 401FEDF618A3F82D00B445EB /* AppDelegate.m in Sources */, - 401FEDF218A3F82D00B445EB /* main.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 401FEDF918A3F82D00B445EB /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 401FEE0B18A3F82D00B445EB /* MobilyExampleTests.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 401FEE0318A3F82D00B445EB /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 401FEDE118A3F82D00B445EB /* MobilyExample */; - targetProxy = 401FEE0218A3F82D00B445EB /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 401FEDEE18A3F82D00B445EB /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 401FEDEF18A3F82D00B445EB /* en */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; - 401FEE0718A3F82D00B445EB /* InfoPlist.strings */ = { - isa = PBXVariantGroup; - children = ( - 401FEE0818A3F82D00B445EB /* en */, - ); - name = InfoPlist.strings; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 401FEE0C18A3F82D00B445EB /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_SYMBOLS_PRIVATE_EXTERN = NO; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 401FEE0D18A3F82D00B445EB /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = YES; - ENABLE_NS_ASSERTIONS = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 7.0; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 401FEE0F18A3F82D00B445EB /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "MobilyExample/MobilyExample-Prefix.pch"; - INFOPLIST_FILE = "MobilyExample/MobilyExample-Info.plist"; - PRODUCT_NAME = "$(TARGET_NAME)"; - WRAPPER_EXTENSION = app; - }; - name = Debug; - }; - 401FEE1018A3F82D00B445EB /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "MobilyExample/MobilyExample-Prefix.pch"; - INFOPLIST_FILE = "MobilyExample/MobilyExample-Info.plist"; - PRODUCT_NAME = "$(TARGET_NAME)"; - WRAPPER_EXTENSION = app; - }; - name = Release; - }; - 401FEE1218A3F82D00B445EB /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; - BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/MobilyExample.app/MobilyExample"; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - "$(DEVELOPER_FRAMEWORKS_DIR)", - ); - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "MobilyExample/MobilyExample-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = "MobilyExampleTests/MobilyExampleTests-Info.plist"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUNDLE_LOADER)"; - WRAPPER_EXTENSION = xctest; - }; - name = Debug; - }; - 401FEE1318A3F82D00B445EB /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = "$(ARCHS_STANDARD_INCLUDING_64_BIT)"; - BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/MobilyExample.app/MobilyExample"; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - "$(DEVELOPER_FRAMEWORKS_DIR)", - ); - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "MobilyExample/MobilyExample-Prefix.pch"; - INFOPLIST_FILE = "MobilyExampleTests/MobilyExampleTests-Info.plist"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUNDLE_LOADER)"; - WRAPPER_EXTENSION = xctest; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 401FEDDD18A3F82D00B445EB /* Build configuration list for PBXProject "MobilyExample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 401FEE0C18A3F82D00B445EB /* Debug */, - 401FEE0D18A3F82D00B445EB /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 401FEE0E18A3F82D00B445EB /* Build configuration list for PBXNativeTarget "MobilyExample" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 401FEE0F18A3F82D00B445EB /* Debug */, - 401FEE1018A3F82D00B445EB /* Release */, - ); - defaultConfigurationIsVisible = 0; - }; - 401FEE1118A3F82D00B445EB /* Build configuration list for PBXNativeTarget "MobilyExampleTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 401FEE1218A3F82D00B445EB /* Debug */, - 401FEE1318A3F82D00B445EB /* Release */, - ); - defaultConfigurationIsVisible = 0; - }; -/* End XCConfigurationList section */ - }; - rootObject = 401FEDDA18A3F82D00B445EB /* Project object */; -} diff --git a/Project/MobilyExample/MobilyExample.xcodeproj/project.xcworkspace/xcuserdata/fgengine.xcuserdatad/UserInterfaceState.xcuserstate b/Project/MobilyExample/MobilyExample.xcodeproj/project.xcworkspace/xcuserdata/fgengine.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index c01b0c5..0000000 Binary files a/Project/MobilyExample/MobilyExample.xcodeproj/project.xcworkspace/xcuserdata/fgengine.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/Project/MobilyExample/MobilyExample.xcodeproj/xcuserdata/fgengine.xcuserdatad/xcschemes/MobilyExample.xcscheme b/Project/MobilyExample/MobilyExample.xcodeproj/xcuserdata/fgengine.xcuserdatad/xcschemes/MobilyExample.xcscheme deleted file mode 100644 index bb007ff..0000000 --- a/Project/MobilyExample/MobilyExample.xcodeproj/xcuserdata/fgengine.xcuserdatad/xcschemes/MobilyExample.xcscheme +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Project/MobilyExample/MobilyExample.xcodeproj/xcuserdata/fgengine.xcuserdatad/xcschemes/xcschememanagement.plist b/Project/MobilyExample/MobilyExample.xcodeproj/xcuserdata/fgengine.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 5693c8a..0000000 --- a/Project/MobilyExample/MobilyExample.xcodeproj/xcuserdata/fgengine.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,27 +0,0 @@ - - - - - SchemeUserState - - MobilyExample.xcscheme - - orderHint - 0 - - - SuppressBuildableAutocreation - - 401FEDE118A3F82D00B445EB - - primary - - - 401FEDFC18A3F82D00B445EB - - primary - - - - - diff --git a/Project/MobilyExample/MobilyExample/AppDelegate.h b/Project/MobilyExample/MobilyExample/AppDelegate.h deleted file mode 100644 index 6c86680..0000000 --- a/Project/MobilyExample/MobilyExample/AppDelegate.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// AppDelegate.h -// MobilyExample -// -// Created by Alexander Trifonov on 06.02.14. -// Copyright (c) 2014 fgengine. All rights reserved. -// - -#import - -@interface AppDelegate : UIResponder - -@property (strong, nonatomic) UIWindow *window; - -@end diff --git a/Project/MobilyExample/MobilyExample/AppDelegate.m b/Project/MobilyExample/MobilyExample/AppDelegate.m deleted file mode 100644 index d78d7e7..0000000 --- a/Project/MobilyExample/MobilyExample/AppDelegate.m +++ /dev/null @@ -1,49 +0,0 @@ -// -// AppDelegate.m -// MobilyExample -// -// Created by Alexander Trifonov on 06.02.14. -// Copyright (c) 2014 fgengine. All rights reserved. -// - -#import "AppDelegate.h" - -@implementation AppDelegate - -- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions -{ - self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - // Override point for customization after application launch. - self.window.backgroundColor = [UIColor whiteColor]; - [self.window makeKeyAndVisible]; - return YES; -} - -- (void)applicationWillResignActive:(UIApplication *)application -{ - // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. - // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. -} - -- (void)applicationDidEnterBackground:(UIApplication *)application -{ - // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. - // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. -} - -- (void)applicationWillEnterForeground:(UIApplication *)application -{ - // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. -} - -- (void)applicationDidBecomeActive:(UIApplication *)application -{ - // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. -} - -- (void)applicationWillTerminate:(UIApplication *)application -{ - // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. -} - -@end diff --git a/Project/MobilyExample/MobilyExample/Images.xcassets/LaunchImage.launchimage/Contents.json b/Project/MobilyExample/MobilyExample/Images.xcassets/LaunchImage.launchimage/Contents.json deleted file mode 100644 index 6f870a4..0000000 --- a/Project/MobilyExample/MobilyExample/Images.xcassets/LaunchImage.launchimage/Contents.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "images" : [ - { - "orientation" : "portrait", - "idiom" : "iphone", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "iphone", - "subtype" : "retina4", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "1x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "1x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/Project/MobilyExample/MobilyExample/MobilyExample-Prefix.pch b/Project/MobilyExample/MobilyExample/MobilyExample-Prefix.pch deleted file mode 100644 index 743435c..0000000 --- a/Project/MobilyExample/MobilyExample/MobilyExample-Prefix.pch +++ /dev/null @@ -1,16 +0,0 @@ -// -// Prefix header -// -// The contents of this file are implicitly included at the beginning of every source file. -// - -#import - -#ifndef __IPHONE_3_0 -#warning "This project uses features only available in iOS SDK 3.0 and later." -#endif - -#ifdef __OBJC__ - #import - #import -#endif diff --git a/Project/MobilyExample/MobilyExample/en.lproj/InfoPlist.strings b/Project/MobilyExample/MobilyExample/en.lproj/InfoPlist.strings deleted file mode 100644 index 477b28f..0000000 --- a/Project/MobilyExample/MobilyExample/en.lproj/InfoPlist.strings +++ /dev/null @@ -1,2 +0,0 @@ -/* Localized versions of Info.plist keys */ - diff --git a/Project/MobilyExample/MobilyExample/main.m b/Project/MobilyExample/MobilyExample/main.m deleted file mode 100644 index 849ef41..0000000 --- a/Project/MobilyExample/MobilyExample/main.m +++ /dev/null @@ -1,18 +0,0 @@ -// -// main.m -// MobilyExample -// -// Created by Alexander Trifonov on 06.02.14. -// Copyright (c) 2014 fgengine. All rights reserved. -// - -#import - -#import "AppDelegate.h" - -int main(int argc, char * argv[]) -{ - @autoreleasepool { - return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); - } -} diff --git a/Project/MobilyExample/MobilyExampleTests/MobilyExampleTests.m b/Project/MobilyExample/MobilyExampleTests/MobilyExampleTests.m deleted file mode 100644 index 207ee06..0000000 --- a/Project/MobilyExample/MobilyExampleTests/MobilyExampleTests.m +++ /dev/null @@ -1,34 +0,0 @@ -// -// MobilyExampleTests.m -// MobilyExampleTests -// -// Created by Alexander Trifonov on 06.02.14. -// Copyright (c) 2014 fgengine. All rights reserved. -// - -#import - -@interface MobilyExampleTests : XCTestCase - -@end - -@implementation MobilyExampleTests - -- (void)setUp -{ - [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. -} - -- (void)tearDown -{ - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -- (void)testExample -{ - XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); -} - -@end diff --git a/Project/MobilyExample/MobilyExampleTests/en.lproj/InfoPlist.strings b/Project/MobilyExample/MobilyExampleTests/en.lproj/InfoPlist.strings deleted file mode 100644 index 477b28f..0000000 --- a/Project/MobilyExample/MobilyExampleTests/en.lproj/InfoPlist.strings +++ /dev/null @@ -1,2 +0,0 @@ -/* Localized versions of Info.plist keys */ - diff --git a/Project/Podfile b/Project/Podfile deleted file mode 100755 index a8b1aba..0000000 --- a/Project/Podfile +++ /dev/null @@ -1,2 +0,0 @@ -platform :ios, '5.0' -pod 'Mobily' diff --git a/Resources/FacebookSDKStrings.bundle/Resources/af.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/af.lproj/FacebookSDK.strings new file mode 100644 index 0000000..89bb711 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/af.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "Goed"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Kanselleer"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Meld asseblief weer by hierdie toepassing aan om jou Facebook-rekening te herkoppel. "; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "Goed"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Die bediener is tydelik besig, probeer asseblief weer."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Hou van"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Hou van"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Kanselleer"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Meld af"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Met Facebook aangemeld"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "As %@ aangemeld"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Meld aan"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Meld met Facebook aan"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Meld af"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Toegang is nie na die Facebook-rekening verleen nie. Verifieer toestelinstellings."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Kan nie aan Facebook koppel nie. Gaan jou netwerkverbinding na en probeer weer."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Jou Facebook-wagwoord het verander. Om jou wagwoord te bevestig, maak Instellings > Facebook oop en tik jou naam."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Die Facebook-rekening is nie op die toestel opgestel nie."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Jou rekening is nie bevestig nie. Meld asseblief by www.facebook.com aan en volg die gegewe instruksies."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Jy kan nie op die oomblik by toepassings aanmeld nie. Meld asseblief by www.facebook.com aan en volg die gegewe instruksies."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Nuut! Jy is in beheer - kies waater inligting jy met toepassings wil deel."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Meld aan"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Stuur"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Deel"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/ar.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/ar.lproj/FacebookSDK.strings new file mode 100644 index 0000000..e257721 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/ar.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "موافق"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "إلغاء"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "يرجى تسجيل الدخول إلى هذا التطبيق مرة أخرى لإعادة الاتصال بحساب فيسبوك."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "موافق"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "الخادم مشغول مؤقتًا، يرجى إعادة المحاولة."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "إعجاب"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "أعجبني"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "إلغاء"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "تسجيل الخروج"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "تم تسجيل الدخول بحساب فيسبوك"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "تم تسجيل الدخول باسم %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "تسجيل الدخول"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "تسجيل الدخول بحساب فيسبوك"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "تسجيل الخروج"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "لم يتم منح إذن الوصول لحساب فيسبوك. تحقق من إعدادات الجهاز."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "تعذر الاتصال بفيسبوك. يُرجى التحقق من الاتصال بالإنترنت وإعادة المحاولة."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "تم تغيير كلمة سر فيسبوك الخاصة بك. لتأكيد كلمة السر، افتح الإعدادات > فيسبوك ثم اضغط على اسمك."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "لم تتم تهيئة حساب فيسبوك على الجهاز."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "لم يتم تأكيد حسابك. يُرجى تسجيل الدخول إلى www.facebook.com واتباع التعليمات الموضحة."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "لا يمكنك تسجيل الدخول إلى التطبيقات حاليًا. يُرجى تسجيل الدخول إلى www.facebook.com واتباع التعليمات الموضحة."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "جديد! أنت المتحكم - اختر المعلومات التي تريد مشاركتها مع التطبيقات."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "تسجيل الدخول"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "إرسال"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "مشاركة"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/bn.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/bn.lproj/FacebookSDK.strings new file mode 100644 index 0000000..47fe484 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/bn.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "ঠিক আছে"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "বাতিল করুন"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "আপনার Facebook অ্যাকাউন্টটিতে পুনরায় সংযোগ করার জন্য অনুগ্রহ করে এই অ্যাপটিতে লগ ইন করুন৷"; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "ঠিক আছে"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "এই সার্ভারটি সাময়িকভাবে ব্যস্ত আছে, অনুগ্রহ করে পুনরায় চেষ্টা করুন৷"; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "পছন্দ করুন"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "পছন্দ করা হয়েছে"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "বাতিল করুন"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "লগ আউট করুন"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Facebook ব্যবহার করে লগ ইন করা হয়েছে"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "%@ হিসাবে লগ ইন করা হয়েছে"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "লগ ইন করুন"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Facebook -এর সাথে লগ ইন করুন"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "লগ আউট করুন"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Facebook অ্যাকাউন্টটিতে অ্যাক্সেস করার অনুমতি নেই৷ ডিভাইস সেটিংস যাচাই করুন৷"; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Facebook-এ সংযোগ করা যাচ্ছে না৷ আপনার নেটওয়ার্ক সংযোগটি পরীক্ষা করুন এবং পুনরায় চেষ্টা করুন৷"; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "আপনার Facebook পাসওয়ার্ডটি পরিবর্তিত হয়েছে৷ আপনার পাসওয়ার্ডটি নিশ্চিত করতে, সেটিংস > Facebook খুলুন এবং আপনার নামটি ট্যাপ করুন৷"; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Facebook অ্যাকাউন্টটি এই ডিভাইসে কনফিগার করা যাযনি৷"; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "আপনার অ্যাকাউন্টটি নিশ্চিত করা যায়নি৷ অনুগ্রহ করে www.facebook.com-এ লগ ইন করুন এবং উল্লিখিত নির্দেশাবলী অনুসরণ করুন৷"; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "এই সময়ে আপনি অ্যাপসে লগ ইন করতে পারবেন না৷ অনুগ্রহ করে www.facebook.com-এ লগ ইন করুন এবং উল্লিখিত নির্দেশাবলী অনুসরণ করুন৷"; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "নতুন! আপনি নিয়ন্ত্রণে আছেন-অ্যাপসের সাথে আপনি কোন তথ্য ভাগ করতে চাইছেন তা চয়ন করুন৷"; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "লগ ইন করুন"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "পাঠান"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "ভাগ করুন"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/cs.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/cs.lproj/FacebookSDK.strings new file mode 100644 index 0000000..cc07f11 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/cs.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Zrušit"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Pokud se chcete ke svému Facebook účtu znovu připojit, přihlaste se k této aplikaci ještě jednou."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Server je dočasně zaneprázdněný, zkuste to znovu."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "To se mi líbí"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Už se mi to líbí"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Zrušit"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Odhlásit"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Přihlášen(a) přes Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Přihlášen(a) jako %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Přihlásit"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Přihlásit se přes Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Odhlásit"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Facebook účtu nebylo oprávnění uděleno. Ověřte nastavení zařízení."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "K Facebooku se nedá připojit. Zkontrolujte připojení k síti a zkuste to znovu."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Vaše heslo na Facebook je změněné. Pokud chcete heslo potvrdit, přejděte do Nastavení > Facebook a klepněte na své jméno."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "V tomto zařízení není Facebook účet konfigurovaný."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Váš účet není potvrzený. Přihlaste se na www. facebook.com a postupujte podle uvedených pokynů."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Do aplikací se v této chvíli přihlásit nemůžete. Přihlaste se na www. facebook.com a postupujte podle uvedených pokynů."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Novinka! Je jen na vás, které informace chcete s aplikacemi sdílet."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Přihlásit"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Odeslat"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Sdílet"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/da.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/da.lproj/FacebookSDK.strings new file mode 100644 index 0000000..d7335e7 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/da.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Annuller"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Log på denne app igen for at genoprette forbindelsen til din Facebook-konto."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Serveren er optaget i øjeblikket. Prøv igen."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Synes godt om"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Synes godt om"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Annuller"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Log af"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Logget på med Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Logget på som %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Log på"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Log på med Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Log af"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Der er ikke blevet givet adgang til Facebook-kontoen. Kontrollér enhedsindstillingerne."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Kunne ikke oprette forbindelse til Facebook. Kontrollér din netværksforbindelse, og prøv igen."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Din Facebook-adgangskode er ændret. For at bekræfte din adgangskode skal du åbne Indstillinger > Facebook og trykke på dit navn."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Facebook-kontoen er ikke blevet konfigureret på enheden."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Din konto er ikke bekræftet. Log på www.facebook.com, og følg instruktionerne."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Du kan ikke logge på apps på nuværende tidspunkt. Log på www.facebook.com, og følg instruktionerne."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Nyhed! Du har styringen – vælg de oplysninger, som du vil dele med apps."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Log på"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Send"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Del"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/de.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/de.lproj/FacebookSDK.strings new file mode 100644 index 0000000..7d42438 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/de.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Abbrechen"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Melde dich bitte erneut bei dieser App an, um die Verbindung mit deinem Facebook-Konto wiederherzustellen."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Der Server ist vorübergehend beschäftigt. Bitte versuche es erneut."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Gefällt mir"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Gefällt dir"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Abbrechen"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Abmelden"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Über Facebook angemeldet"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Als %@ angemeldet"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Anmelden"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Über Facebook anmelden"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Abmelden"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Auf das Facebook-Konto wurde kein Zugriff erteilt. Überprüfe bitte die Geräteeinstellungen."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Verbindung zu Facebook kann nicht hergestellt werden. Bitte überprüfe deine Netzwerkverbindung und versuche es erneut."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Dein Facebook-Passwort hat sich geändert. Öffne „Einstellungen“ > „Facebook“ und tippe auf deinen Namen, um dein Passwort zu bestätigen."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Das Facebook-Konto wurde für dieses Gerät nicht konfiguriert."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Dein Konto wurde nicht bestätigt. Bitte melde dich unter www.facebook.com an und folge den Anweisungen."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Du kannst dich zurzeit nicht bei Apps anmelden. Bitte melde dich unter www.facebook.com an und folge den Anweisungen."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Neu! Es liegt ganz an dir – du kannst dir aussuchen, was du mit Apps teilen möchtest."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Anmelden"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Senden"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Teilen"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/el.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/el.lproj/FacebookSDK.strings new file mode 100644 index 0000000..e6af729 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/el.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Άκυρο"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Συνδεθείτε ξανά σε αυτή την εφαρμογή για να συνδέσετε και πάλι το λογαριασμό σας στο Facebook."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Ο διακομιστής είναι προσωρινά απασχολημένος, προσπαθήστε ξανά."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Μου αρέσει!"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Σας αρέσει"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Άκυρο"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Αποσύνδεση"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Έχει γίνει σύνδεση μέσω Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Έχει γίνει σύνδεση ως %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Σύνδεση"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Σύνδεση μέσω Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Αποσύνδεση"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Δεν έχει παραχωρηθεί πρόσβαση στο λογαριασμό Facebook. Επαληθεύστε τις ρυθμίσεις της συσκευής σας."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Δεν είναι δυνατή η σύνδεση στο Facebook. Ελέγξτε τη σύνδεση στο δίκτυο και προσπαθήστε ξανά."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Ο κωδικός πρόσβασής σας στο Facebook άλλαξε. Για να επιβεβαιώσετε τον κωδικό σας, πηγαίνετε στις Ρυθμίσεις > Facebook και πατήστε το όνομά σας."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Ο λογαριασμός Facebook δεν έχει διαμορφωθεί στη συσκευή."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Ο λογαριασμός σας δεν επιβεβαιώθηκε. Συνδεθείτε στο www.facebook.com και ακολουθήστε τις οδηγίες που εμφανίζονται."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Προς το παρόν δεν μπορείτε να συνδεθείτε σε εφαρμογές. Συνδεθείτε στο www.facebook.com και ακολουθήστε τις οδηγίες που εμφανίζονται."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Νέο! Έχετε τον έλεγχο - επιλέξτε ποιες πληροφορίες θέλετε να κοινοποιούνται στις εφαρμογές."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Σύνδεση"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Αποστολή"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Κοινοποίηση"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/en.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/en.lproj/FacebookSDK.strings new file mode 100644 index 0000000..b10f2e1 Binary files /dev/null and b/Resources/FacebookSDKStrings.bundle/Resources/en.lproj/FacebookSDK.strings differ diff --git a/Resources/FacebookSDKStrings.bundle/Resources/en_GB.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/en_GB.lproj/FacebookSDK.strings new file mode 100644 index 0000000..a5f5ccc --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/en_GB.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Cancel"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Please log in to this app again to reconnect your Facebook account."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "The server is temporarily busy, please try again."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Like"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Liked"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Cancel"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Log out"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Logged in using Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Logged in as %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Log in"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Log in with Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Log out"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Access has not been granted to the Facebook account. Verify device settings."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Unable to connect to Facebook. Please check your network connection and try again."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Your Facebook password has changed. To confirm your password, open Settings > Facebook and tap your name."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "The Facebook account has not been configured on the device."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Your account is not confirmed. Please log in to www.facebook.com and follow the instructions given."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "You cannot log in to apps at this time. Please log in to www.facebook.com and follow the instructions given."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "New! You're in control – choose what info you want to share with apps."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Log In"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Send"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Share"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/es.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/es.lproj/FacebookSDK.strings new file mode 100644 index 0000000..7115ac7 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/es.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "Aceptar"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Cancelar"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Inicia sesión de nuevo en esta aplicación para volver a conectarte a tu cuenta de Facebook."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "Aceptar"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "El servidor está temporalmente ocupado. Vuelve a intentarlo."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Me gusta"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Te gusta"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Cancelar"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Cerrar sesión"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Sesión iniciada con Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Sesión iniciada como %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Inicio de sesión"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Iniciar sesión con Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Salir"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "No se concedió acceso a la cuenta de Facebook. Verifica la configuración del dispositivo."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "No es posible conectarse a Facebook. Comprueba tu conexión a internet y vuelve a intentarlo."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Cambió tu contraseña de Facebook. Para confirmar tu contraseña, abre Configuración > Facebook y toca tu nombre."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "No se configuró la cuenta de Facebook en el dispositivo."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Tu cuenta no está confirmada. Inicia sesión en www.facebook.com y sigue las instrucciones."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "No puedes iniciar sesión en las aplicaciones en este momento. Inicia sesión en www.facebook.com y sigue las instrucciones."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "¡Nuevo! Tú tienes el control: elige qué información quieres compartir con las aplicaciones."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Inicio de sesión"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Enviar"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Compartir"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/es_ES.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/es_ES.lproj/FacebookSDK.strings new file mode 100644 index 0000000..a71804c --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/es_ES.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "Aceptar"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Cancelar"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Vuelve a iniciar sesión en esta aplicación para volver a conectar tu cuenta de Facebook."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "Aceptar"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "El servidor está ocupado temporalmente. Vuelve a intentarlo más tarde."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Me gusta"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Te gusta"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Cancelar"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Salir"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Sesión iniciada con Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Sesión iniciada como %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Inicio de sesión"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Iniciar sesión con Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Salir"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "No se ha otorgado acceso a la cuenta de Facebook. Verifica la configuración del dispositivo."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "No es posible conectarse a Facebook. Comprueba tu conexión de red y vuelve a intentarlo."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Tu contraseña de Facebook ha cambiado. Para confirmar tu contraseña, abre Configuración > Facebook y toca tu nombre."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "La cuenta de Facebook no se ha configurado en el dispositivo."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Tu cuenta no se ha confirmado. Inicia sesión en www.facebook.com y sigue las instrucciones."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "No puedes iniciar sesión en las aplicaciones en este momento. Inicia sesión en www.facebook.com y sigue las instrucciones."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Novedad: Tú eres quien controla y elige la información que quieres compartir con las aplicaciones."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Inicio de sesión"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Enviar"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Compartir"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/fi.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/fi.lproj/FacebookSDK.strings new file mode 100644 index 0000000..12004f6 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/fi.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Peruuta"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Kirjaudu tähän sovellukseen uudelleen, jotta voit yhdistää Facebook-tilisi uudelleen."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Palvelin on tilapäisesti varattu, yritä uudelleen."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Tykkää"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Tykätty"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Peruuta"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Kirjaudu ulos"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Sisäänkirjautunut Facebookin avulla"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Sisäänkirjautunut nimellä %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Kirjaudu sisään"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Kirjaudu sisään Facebookin avulla"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Kirjaudu ulos"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Pääsyä Facebook-tiliin ei ole myönnetty. Tarkista laiteasetukset."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Yhteyttä Facebookiin ei voi muodostaa. Tarkista verkkoyhteys ja yritä sitten uudelleen."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Facebook-salasanasi on vaihdettu. Vahvista salasanasi avaamalla Asetukset > Facebook ja napauttamalla nimeäsi."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Facebook-tiliä ei ole määritetty laitteessa."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Tiliäsi ei ole vahvistettu. Kirjaudu sisään osoitteeseen www.facebook.com ja noudata annettuja ohjeita."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Et pysty kirjautumaan sovelluksiin tällä hetkellä. Kirjaudu sisään osoitteeseen www.facebook.com ja noudata annettuja ohjeita."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Uutta! Sinä päätät – valitse, mitä haluat jakaa sovellusten kanssa."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Kirjaudu sisään"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Lähetä"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Jaa"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/fil.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/fil.lproj/FacebookSDK.strings new file mode 100644 index 0000000..a2e54f0 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/fil.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Kanselahin"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Mangyaring mag-log in muli sa app na ito para ikonekta muli ang iyong Facebook account."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Pansamantalang abala ang server, pakisubukan muli."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Gustuhin"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Nagustuhan"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Kanselahin"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Mag-log Out"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Naka-log in gamit ang Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Naka-log in bilang si %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Mag-log in"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Mag-log in sa pamamagitan ng Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Mag-log out"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Hindi binigyan ng access ang Facebook account. Beripikahin ang mga setting ng device."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Hindi nakakonekta sa Facebook. Tingnan ang iyong koneksyon sa network at subukan muli."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Nagbago ang iyong password sa Facebook. Para makumpirma ang iyong password, buksan ang Mga Setting > Facebook at i-tap ang iyong pangalan."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Hindi na-configure sa device ang Facebook account."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Hindi nakumpirma ang iyong account. Mangyaring mag-log in sa www.facebook.com at sundin ang mga ibinigay na tagubilin."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Hindi ka makakapag-log in sa mga app sa oras na ito. Mangyaring mag-log in sa www.facebook.com at sundin ang mga ibinigay na tagubilin."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Bago! Ikaw ang may kontrol - piliin kung anong impormasyon ang gusto mong ibahagi sa mga app."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Mag-log In"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Ipadala"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Ibahagi"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/fr.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/fr.lproj/FacebookSDK.strings new file mode 100644 index 0000000..954a3ef --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/fr.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Annuler"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Veuillez vous connecter à nouveau à cette application pour reconnecter votre compte Facebook."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Le serveur est temporairement occupé. Veuillez réessayer plus tard."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "J’aime"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "J’aime déjà"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Annuler"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Déconnexion"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Connecté(e) à l’aide de Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Connecté(e) en tant que %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Connexion"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Connexion avec Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Déconnexion"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "L’accès au compte Facebook n’a pas été autorisé. Vérifiez les paramètres de l’appareil."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Connexion à Facebook impossible. Vérifiez votre connexion avant de réessayer."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Votre mot de passe Facebook a changé. Pour confirmer votre mot de passe, ouvrez Paramètres > Facebook et saisissez votre nom."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Le compte Facebook n’a pas été configuré sur l’appareil."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Votre compte n’est pas confirmé. Veuillez vous connecter à www.facebook.com et suivre les instructions indiquées."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Vous ne pouvez pas vous connecter à des applications pour le moment. Veuillez vous connecter à www.facebook.com et suivre les instructions indiquées."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Nouveau ! Choisissez les informations que vous souhaitez partager avec les applications."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Connexion"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Envoyer"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Partager"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/gu.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/gu.lproj/FacebookSDK.strings new file mode 100644 index 0000000..48f2a11 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/gu.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "ઠીક"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "રદ કરો"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "તમારા ફેસબુક ખાતાને ફરીથી કનેક્ટ કરવા માટે કૃપા કરીને આ એપ્લિકેશનમાં ફરી લૉગ ઇન કરો."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "ઠીક"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "સર્વર અસ્થાયીરૂપે વ્યસ્ત છે, કૃપા કરીને ફરી પ્રયાસ કરો."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "પસંદ કરો"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "પસંદ કર્યું"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "રદ કરો"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "લૉગ આઉટ કરો"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "ફેસબુકનો ઉપયોગ કરીને લૉગ ઇન કરો"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "%@ તરીકે લૉગ ઇન થયાં"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "લૉગ ઇન કરો"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "ફેસબુક સાથે લૉગ ઇન કરો"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "લૉગ આઉટ કરો"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "ફેસબુક ખાતા પર ઍક્સેસ આપવામાં આવી નથી. ઉપકરણ સેટિંગ્સ ચકાસો"; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "ફેસબુકથી કનેક્ટ કરવામાં અસમર્થ. તમારું નેટવર્ક કનેક્શન તપાસો અને ફરી પ્રયાસ કરો."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "તમારો ફેસબુક પાસવર્ડ બદલાઈ ગયો છે. તમારા પાસવર્ડની પુષ્ટિ કરવા માટે, સેટિંગ્સ > ફેસબુક ખોલો અને તમારા નામ પર ટૅપ કરો."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "ઉપકરણ પર ફેસબુક ખાતું કન્ફિગર કરવામાં આવ્યું નથી."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "તમારા ખાતાની પુષ્ટિ કરવામાં આવી નથી. કૃપા કરીને www.facebook.com પર લૉગ ઇન કરો અને આપેલા સૂચનોને અનુસરો."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "તમે આ સમયે એપ્લિકેશન્સમાં લૉગ ઇન કરી શકતાં નથી. કૃપા કરીને www.facebook.com પર લૉગ ઇન કરો અને આપેલા સૂચનોને અનુસરો."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "નવું! તમે નિયંત્રણ કરો છો - તમે એપ્લિકેશન્સ સાથે કઈ માહિતી શેર કરવા માંગો છો તે પસંદ કરો."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "લૉગ ઇન કરો"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "મોકલો"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "શેર કરો"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/he.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/he.lproj/FacebookSDK.strings new file mode 100644 index 0000000..dcd6541 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/he.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Cancel"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Please log into this app again to reconnect your Facebook account."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "The server is temporarily busy, please try again."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Like"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Liked"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Cancel"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Log Out"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Logged in using Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Logged in as %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Log in"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Log in with Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Log out"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Access has not been granted to the Facebook account. Verify device settings."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Unable to connect to Facebook. Check your network connection and try again."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Your Facebook password has changed. To confirm your password, open Settings > Facebook and tap your name."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "The Facebook account has not been configured on the device."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Your account is not confirmed. Please log in to www.facebook.com and follow the instructions given."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "You cannot log in to apps at this time. Please log in to www.facebook.com and follow the instructions given."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "New! You're in control - choose what info you want to share with apps."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Log In"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Send"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Share"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/hi.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/hi.lproj/FacebookSDK.strings new file mode 100644 index 0000000..4971bf2 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/hi.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "ठीक"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "रद्द करें"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "अपने Facebook खाते से फिर से कनेक्ट होने के लिए कृपया इस एप्लिकेशन में फिर से लॉग इन करें."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "ठीक"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "सर्वर अस्थायी रूप से व्यस्त है, कृपया फिर से कोशिश करें."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "पसंद करें"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "पसंद किया"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "रद्द करें"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "लॉग आउट करें"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Facebook का उपयोग करके लॉग इन किया हुआ है"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "%@ के रूप में लॉग इन किया हुआ है"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "लॉग इन करें"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Facebook से लॉग इन करें"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "लॉग आउट"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Facebook खाते को एक्सेस नहीं दी गई है. डिवाइस सेटिंग सत्यापित करें."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Facebook से कनेक्ट होने में असमर्थ. कृपया अपने नेटवर्क कनेक्शन की जाँच करें फिर से प्रयास करें."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "आपका Facebook पासवर्ड बदल गया है. अपना पासवर्ड कन्फ़र्म करने के लिए, सेटिंग > Facebook खोलें और अपना नाम टैप करें."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "डिवाइस पर Facebook खाता कॉन्फ़िगर नहीं किया गया है."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "आपका खाता कन्फ़र्म नहीं किया गया है. कृपया www.facebook.com में लॉग इन करें और दिए गए निर्देशों का पालन करें."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "आप इस समय एप्लिकेशन में लॉग इन नहीं कर सकते. कृपया www.facebook.com में लॉग इन करें और दिए गए निर्देशों का पालन करें."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "नया! आप नियंत्रण में हैं - चुनें कि आप एप्लिकेशन से कौन-सी जानकारी साझा करना चाहते हैं."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "लॉग इन करें"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "भेजें"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "साझा करें"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/hr.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/hr.lproj/FacebookSDK.strings new file mode 100644 index 0000000..2c1c146 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/hr.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "U redu"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Odustani"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Ponovo se prijavite u ovu aplikaciju kako biste se ponovo povezali s Facebook računom."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "U redu"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Poslužitelj je privremeno zauzet, pokušajte ponovo."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Sviđa mi se"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Označeno sa "sviđa mi se""; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Odustani"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Odjavi se"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Prijavljen putem Facebooka"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Prijavljen kao %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Prijavi se"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Prijava putem Facebooka"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Odjavi se"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Pristup Facebook računu nije odobren. Provjerite postavke uređaja."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Povezivanje s Facebookom nije uspjelo. Provjerite mrežnu vezu i pokušajte ponovo."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Promijenili ste lozinku za Facebook. Za potvrdu lozinke otvorite Postavke > Facebook i dodirnite svoje ime."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Na uređaju nije konfiguriran račun za Facebook."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Vaš račun nije potvrđen. Prijavite se na www.facebook.com i slijedite upute."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "U ovome trenutku prijava u aplikacije nije moguća. Prijavite se na www.facebook.com i slijedite upute."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Novo! Vi odlučujete – odaberite koje informacije želite podijeliti u aplikacijama."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Prijava"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Pošalji"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Dijeli"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/hu.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/hu.lproj/FacebookSDK.strings new file mode 100644 index 0000000..92ca143 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/hu.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Mégsem"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Kérjük, jelentkezz be újra ebbe az alkalmazásba, ha szeretnéd ismét összekapcsolni a Facebook-fiókoddal."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "A kiszolgáló átmenetileg foglalt, próbáld meg újra."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Tetszik"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Kedveled"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Mégsem"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Kijelentkezés"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Bejelentkezve a Facebook használatával"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Bejelentkezve %@ néven"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Bejelentkezés"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Bejelentkezés a Facebook használatával"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Kijelentkezés"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "A Facebook-fiókhoz nincs megadva a hozzáférés. Ellenőrizd az eszköz beállításait."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Nem sikerült kapcsolódni a Facebookhoz. Ellenőrizd a hálózati kapcsolatot, majd próbáld meg újra."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Facebook-jelszavad megváltozott. A jelszó megerősítéséhez nyisd meg a Settings (Beállítások) > Facebook pontot, és koppints a nevedre."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "A készüléken nincs beállítva a Facebook-fiók."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "A fiókod nincs megerősítve. Jelentkezz be a www.facebook.com címre, és kövesd az utasításokat."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Jelenleg nem tudsz alkalmazásokba bejelentkezni. Jelentkezz be a www.facebook.com címre, és kövesd az utasításokat."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Újdonság! A döntés a kezedben van: kiválaszthatod, hogy milyen adatokat osztasz meg az alkalmazásokkal."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Bejelentkezés"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Küldés"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Megosztás"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/id.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/id.lproj/FacebookSDK.strings new file mode 100644 index 0000000..9d42efb --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/id.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Batal"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Harap masuk ke aplikasi ini lagi untuk menghubungkan kembali akun Facebook Anda."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Server untuk sementara sedang sibuk, harap coba lagi."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Suka"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Disukai"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Batal"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Keluar"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Masuk menggunakan Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Masuk sebagai %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Masuk"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Masuk menggunakan Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Keluar"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Akses belum diberikan ke akun Facebook. Verifikasi pengaturan perangkat."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Tidak dapat terhubung ke Facebook. Periksa koneksi jaringan dan coba lagi."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Kata sandi Facebook Anda telah diubah. Untuk mengonfirmasi kata sandi Anda, buka Pengaturan > Facebook, lalu ketuk nama Anda."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Akun Facebook belum dikonfigurasikan di perangkat."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Akun Anda tidak dikonfirmasi. Masuk ke www.facebook.com dan ikuti petunjuknya."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Saat ini Anda tidak dapat masuk ke aplikasi. Masuk ke www.facebook.com dan ikuti petunjuknya."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Baru! Anda memegang kendali - pilih info yang ingin Anda bagikan dengan aplikasi."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Masuk"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Kirim"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Berbagi"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/it.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/it.lproj/FacebookSDK.strings new file mode 100644 index 0000000..486adfa --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/it.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Annulla"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Effettua di nuovo l'accesso a questa applicazione per riconnettere il tuo account Facebook."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Il server è temporaneamente occupato, riprova."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Mi piace"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Ti piace"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Annulla"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Esci"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Accesso effettuato tramite Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Accesso effettuato come %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Accedi"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Accedi con Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Esci"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "All'account Facebook non è stato concesso l'accesso. Verifica le impostazioni del dispositivo."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Impossibile connettersi a Facebook. Controlla la tua connessione e riprova."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "La tua password di Facebook è stata modificata. Per confermare la password, apri Impostazioni > Facebook e tocca il tuo nome."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "L'account Facebook non è stato configurato nel dispositivo."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Il tuo account non è stato verificato. Accedi a www.facebook.com e segui le istruzioni fornite."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Impossibile accedere alle applicazioni al momento. Accedi a www.facebook.com e segui le istruzioni fornite."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Novità! Il controllo è nelle tue mani: scegli quali informazioni condividere con le applicazioni."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Accedi"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Invia"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Condividi"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/ja.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/ja.lproj/FacebookSDK.strings new file mode 100644 index 0000000..f42333f --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/ja.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "キャンセル"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "このアプリにもう一度ログインして、Facebookアカウントを再接続してください。"; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "サーバーが一時的にビジーです。もう一度お試しください。"; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "いいね!"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "いいね!済み"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "キャンセル"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "ログアウト"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Facebookを使用してログイン中"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "%@としてログイン中"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "ログイン"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Facebookでログイン"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "ログアウト"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Facebookアカウントにアクセス権が与えられていません。デバイス設定を確認してください。"; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Facebookに接続できませんでした。ネットワーク接続を確認してもう一度お試しください。"; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Facebookパスワードが変更されています。パスワードを確認するには、[設定] > [Facebook]の順に開き、名前をタップしてください。"; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "デバイスにFacebookアカウントが構成されていません。"; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "アカウントが確認されません。www.facebook.comにログインし、表示される説明に従ってください。"; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "今はアプリにログインできません。www.facebook.comにログインし、表示される説明に従ってください。"; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "新機能!アプリと共有する情報をコントロールできます。"; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "ログイン"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "送信"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "シェア"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/kn.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/kn.lproj/FacebookSDK.strings new file mode 100644 index 0000000..5fe3947 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/kn.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "ಸರಿ"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "ರದ್ದುಮಾಡು"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "ನಿಮ್ಮ Facebook ಖಾತೆಯನ್ನು ಮರುಸಂಪರ್ಕಗೊಳಿಸಲು ಈ ಅಪ್ಲಿಕೇಶನ್‌ನಲ್ಲಿ ಮತ್ತೊಮ್ಮೆ ಲಾಗಿನ್‌ ಮಾಡಿ."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "ಸರಿ"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "ಸರ್ವರ್ ತಾತ್ಕಾಲಿಕವಾಗಿ ಕಾರ್ಯನಿರತವಾಗಿದೆ, ದಯವಿಟ್ಟು ನಂತರ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "ಇಷ್ಟವಾಗಿದೆ"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "ಇಷ್ಟಪಟ್ಟಿದ್ದಾರೆ"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "ರದ್ದುಮಾಡು"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "ಲಾಗ್‌ ಔಟ್‌"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Facebook ಬಳಸಿಕೊಂಡು ಲಾಗಿನ್‌ ಮಾಡಲಾಗಿದೆ"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "%@ ರಂತೆ ಲಾಗಿನ್‌ ಮಾಡಲಾಗಿದೆ"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "ಲಾಗ್‌ ಇನ್‌"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Facebook ಮೂಲಕ ಲಾಗ್‌ ಇನ್‌ ಮಾಡಿ"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "ಲಾಗ್‌ ಔಟ್‌"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Facebook ಖಾತೆಗೆ ಪ್ರವೇಶವನ್ನು ಅನುಮತಿಸಲಾಗಿಲ್ಲ. ಸಾಧನದ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಪರಿಶೀಲಿಸಿ."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Facebook ಗೆ ಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ನಿಮ್ಮ ನೆಟ್‌ವರ್ಕ್‌ ಸಂಪರ್ಕವನ್ನು ಪರಿಶೀಲಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "ನಿಮ್ಮ Facebook ಪಾಸ್‌ವರ್ಡ್‌ ಬದಲಿಸಲಾಗಿದೆ. ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್‌ ಖಚಿತಪಡಿಸಲು, ಸೆಟ್ಟಿಂಗ್‌ಗಳು > Facebook ತೆರೆಯಿರಿ ಮತ್ತು ನಿಮ್ಮ ಹೆಸರನ್ನು ಟ್ಯಾಪ್‌ ಮಾಡಿ."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Facebook ಖಾತೆಯನ್ನು ಸಾಧನದಲ್ಲಿ ಕಾನ್ಫಿಗರ್ ಮಾಡಲಾಗಿಲ್ಲ."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "ನಿಮ್ಮ ಖಾತೆಯನ್ನು ದೃಢೀಕರಿಸಿಲ್ಲ. ದಯವಿಟ್ಟು www.facebook.com ಗೆ ಲಾಗಿನ್‌ ಮಾಡಿ ಮತ್ತು ಕೆಳಗೆ ನೀಡಿದ ಸೂಚನೆಗಳನ್ನು ಅನುಸರಿಸಿ."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "ನೀವು ಈ ಸಮಯದಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ ಲಾಗಿನ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ದಯವಿಟ್ಟು www.facebook.com ಗೆ ಲಾಗಿನ್‌ ಮಾಡಿ ಮತ್ತು ಕೆಳಗೆ ನೀಡಿದ ಸೂಚನೆಗಳನ್ನು ಅನುಸರಿಸಿ."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "ಹೊಸ! ನೀವು ನಿಯಂತ್ರಣದಲ್ಲಿರುವಿರಿ - ನೀವು ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಬಳಸಿಕೊಂಡು ಹಂಚಿಕೊಳ್ಳಲು ಬಯಸುವ ವಿಷಯವನ್ನು ಆರಿಸಿ."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "ಲಾಗ್‌ ಇನ್‌"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "ಕಳುಹಿಸಿ"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "ಹಂಚಿಕೊಳ್ಳಿ"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/ko.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/ko.lproj/FacebookSDK.strings new file mode 100644 index 0000000..9d06c29 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/ko.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "확인"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "취소"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Facebook 계정을 다시 연결하려면 이 앱에 다시 로그인하세요."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "확인"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "일시적으로 서버 사용량이 많아졌습니다. 다시 시도하세요."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "좋아요"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "좋아요"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "취소"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "로그아웃"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Facebook 계정으로 로그인함"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "%@(으)로 로그인함"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "로그인"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Facebook으로 로그인"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "로그아웃"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Facebook 계정에 대한 액세스가 승인되지 않았습니다. 기기 설정을 확인하세요."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Facebook에 연결할 수 없습니다. 네트워크 연결을 확인하고 다시 시도하세요."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Facebook 비밀번호가 변경되었습니다. 비밀번호를 확인하려면 설정 > Facebook으로 이동하여 이름을 누르세요."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Facebook 계정이 기기에 구성되어 있지 않습니다."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "계정이 확인되지 않았습니다. www.facebook.com에 로그인한 뒤 안내를 따라주세요."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "현재 앱에 로그인할 수 없습니다. www.facebook.com에 로그인한 뒤 안내를 따라주세요."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "새로운 기능! 이제 앱과 어떤 정보를 공유할지 자유롭게 선택할 수 있습니다."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "로그인"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "보내기"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "공유하기"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/ml.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/ml.lproj/FacebookSDK.strings new file mode 100644 index 0000000..140a5ab --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/ml.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "ശരി"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "റദ്ദാക്കുക"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "നിങ്ങളുടെ Facebook അക്കൗണ്ടുമായി വീണ്ടും കണക്‌റ്റുചെയ്യുന്നതിന് ഈ ആപ്ലിക്കേഷനിൽ വീണ്ടും ലോഗിൻ ചെയ്യുക."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "ശരി"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "സെർവർ താൽക്കാലികമായി തിരക്കിലാണ്, വീണ്ടും ശ്രമിക്കുക."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "ലൈക്കുചെയ്യുക"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "ലൈക്കുചെയ്‌‌തു"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "റദ്ദാക്കുക"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "ലോഗ്ഔട്ട് ചെയ്യുക"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Facebook ഉപയോഗിച്ച് ലോഗിൻ ചെയ്‌തു"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "%@ എന്നതായി ലോഗിൻ ചെയ്‌തു"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "ലോഗിൻ ചെയ്യുക"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Facebook ഉപയോഗിച്ച് ലോഗിൻ ചെയ്യുക"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "ലോഗ്ഔട്ട് ചെയ്യുക"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Facebook അക്കൗണ്ടിലേക്ക് ആക്‌സസ് നൽകിയിട്ടില്ല. ഉപകരണ ക്രമീകരണങ്ങൾ പരിശോധിച്ചുറപ്പിക്കുക."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Facebook-ലേക്ക് കണക്‌റ്റുചെയ്യാനായില്ല. നിങ്ങളുടെ നെറ്റ്‌വർക്ക് കണക്ഷൻ പരിശോധിച്ച് വീണ്ടും ശ്രമിക്കുക."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "നിങ്ങളുടെ Facebook പാസ്‌വേഡ് മാറി. പാ‌സ്‌വേഡ് സ്ഥിരീകരിക്കുന്നതിന് ക്രമീകരണങ്ങൾ > Facebook എന്നത് തുറന്ന് പേര് ടാപ്പുചെയ്യുക."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "ഉപകരണത്തിൽ Facebook അക്കൗണ്ട് കോൺഫിഗർ ചെയ്‌തിട്ടില്ല."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "അക്കൗണ്ട് സ്ഥിരീകരിച്ചു. www.facebook.com എന്നതിലേക്ക് ലോഗിൻ ചെയ്‌ത് തന്നിരിക്കുന്ന നിർദ്ദേശങ്ങൾ പാലിക്കുക."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "നിങ്ങൾക്ക് ഈ സമയം ആപ്ലിക്കേഷനുകളിലേക്ക് ലോഗിൻ ചെയ്യാനാവില്ല. www.facebook.com എന്നതിലേക്ക് ലോഗിൻ ചെയ്‌ത് തന്നിരിക്കുന്ന നിർദ്ദേശങ്ങൾ പാലിക്കുക."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "പുതിയത്! നിങ്ങൾ നിയന്ത്രണത്തിലാണ് - നിങ്ങൾക്ക് ആപ്ലിക്കേഷനുകളുമായി പങ്കിടേണ്ടതുണ്ടെങ്കിൽ തിരഞ്ഞെടുക്കുക."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "ലോഗിൻ ചെയ്യുക"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "അയയ്‌ക്കുക"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "പങ്കിടൂ"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/mr.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/mr.lproj/FacebookSDK.strings new file mode 100644 index 0000000..5832896 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/mr.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "ठीक"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "रद्द करा"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "कृपया आपले फेसबुक खाते रीकनेक्ट करण्यासाठी या अनुप्रयोगावर पुन्हा लॉग इन करा."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "ठीक"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "सर्व्हर तात्पुरता व्यस्त आहे, कृपया पुन्हा प्रयत्न करा."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "आवडले"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "आवडलेले"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "रद्द करा"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "लॉग आउट करा"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "फेसबुक वापरून लॉग इन केले"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "%@ म्हणून लॉग इन केले"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "लॉग इन करा"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "फेसबुकसह लॉग इन करा"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "लॉग आउट करा"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "फेसबुक खात्यावर प्रवेशास मंजूरी दिली गेली नाही. डिव्हाइस सेटिंग्ज सत्यापित करा."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "फेसबुकशी कनेक्ट करण्यात अक्षम. आपले नेटवर्क कनेक्शन तपासा आणि पुन्हा प्रयत्न करा."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "आपला फेसबुक पासवर्ड बदलला आहे. आपल्या पासवर्डची पुष्टी करण्यासाठी, सेटिंग्ज > फेसबुक उघडा आणि आपले नाव टॅप करा."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "डिव्हाइसवर फेसबुक खाते कॉन्फिगर केले गेले नाही."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "आपल्या खात्याची पुष्टी झाली नाही. कृपया www.facebook.com वर लॉग इन करा आणि दिलेल्या सूचनांचे अनुसरण करा."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "आपण यावेळी अनुप्रयोगांवर लॉग इन करू शकत नाही. कृपया www.facebook.com वर लॉग इन करा आणि दिलेल्या सूचनांचे अनुसरण करा."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "नवीन! आपण नियंत्रणात आहात - आपण कोणती माहिती अनुप्रयोगांसह शेअर करू इच्छिता ते निवडा."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "लॉग इन करा"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "पाठवा"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "सामायिक करा"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/ms.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/ms.lproj/FacebookSDK.strings new file mode 100644 index 0000000..1c28794 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/ms.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Batal"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Sila log masuk ke aplikasi ini sekali lagi untuk menyambung semula akaun Facebook anda."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Pelayan ini sibuk buat sementara waktu, sila cuba lagi."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Suka"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Disukai"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Batal"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Log Keluar"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Dilog masuk menggunakan Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Dilog masuk sebagai %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Log masuk"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Log masuk dengan Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Log keluar"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Akses ke akaun Facebook tidak diberikan. Sahkan tetapan peranti."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Tidak dapat menyambung ke Facebook. Semak sambungan rangkaian anda dan cuba lagi."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Kata laluan Facebook anda telah ditukar. Untuk mengesahkan kata laluan anda, buka Tetapan > Facebook dan ketik nama anda."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Akaun Facebook masih belum dikonfigurasikan pada peranti."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Akaun anda tidak disahkan. Sila log masuk ke www.facebook.com dan ikuti arahan yang diberi."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Anda tidak boleh log masuk ke aplikasi pada masa ini. Sila log masuk ke www.facebook.com dan ikuti arahan yang diberi."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Baru! Anda yang mengawal - pilih maklumat yang anda ingin kongsi dengan aplikasi."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Log Masuk"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Hantar"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Kongsi"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/nb.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/nb.lproj/FacebookSDK.strings new file mode 100644 index 0000000..a29dae6 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/nb.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Avbryt"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Logg deg inn igjen på denne appen for å koble til Facebook-kontoen på nytt."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Serveren er midlertidig opptatt. Prøv på nytt."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Liker"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Likt"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Avbryt"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Logg ut"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Logget inn med Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Logget inn som %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Logg inn"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Logg inn med Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Logg ut"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Det er ikke gitt tilgang til Facebook-kontoen. Bekreft enhetsinnstillinger."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Kunne ikke koble til Facebook. Kontroller nettverkstilkoblingen, og prøv på nytt."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Facebook-passordet ditt er endret. Bekreft passordet ditt ved å gå til Innstillinger > Facebook og trykke på navnet ditt."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Facebook-kontoen er ikke konfigurert på enheten."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Kontoen din er bekreftet. Logg deg inn på www.facebook.com, og følg instruksjonene."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Du kan ikke logge deg inn på apper for øyeblikket. Logg deg inn på www.facebook.com, og følg instruksjonene."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Nyhet! Du bestemmer – velg hvilke opplysninger du vil dele med appene."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Logg inn"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Send"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Del"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/nl.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/nl.lproj/FacebookSDK.strings new file mode 100644 index 0000000..b5eeceb --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/nl.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Annuleren"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Meld je nogmaals aan bij deze app om verbinding te maken met je Facebook-account."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "De server is tijdelijk niet beschikbaar. Probeer het opnieuw."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Vind ik leuk"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Vind ik leuk"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Annuleren"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Afmelden"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Aangemeld via Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Aangemeld als %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Aanmelden"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Aanmelden met Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Afmelden"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Er is geen toegang verleend aan het Facebook-account. Verifieer de apparaatinstellingen."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Er kan geen verbinding worden gemaakt met Facebook. Controleer je netwerkverbinding en probeer het opnieuw."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Je Facebook-wachtwoord is gewijzigd. Open Instellingen > Facebook en tik op je naam om je wachtwoord te bevestigen."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Het Facebook-account is niet geconfigureerd op het apparaat."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Je account is niet bevestigd. Meld je aan bij www.facebook.com en volg de instructies."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Je kunt je momenteel niet aanmelden bij apps. Meld je aan bij www.facebook.com en volg de instructies."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Nieuw! Jij hebt de controle. Kies welke informatie je met apps wilt delen."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Aanmelden"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Verzenden"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Delen"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/pa.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/pa.lproj/FacebookSDK.strings new file mode 100644 index 0000000..7a04111 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/pa.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "ਠੀਕ"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "ਰੱਦ ਕਰੋ"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "ਕਿਰਪਾ ਕਰਕੇ ਆਪਣੇ Facebook ਖਾਤੇ ਨਾਲ ਮੁੜ ਕਨੈਕਟ ਕਰਨ ਲਈ ਇਸ ਐਪ ਵਿੱਚ ਦੁਬਾਰਾ ਲੌਗ ਇਨ ਕਰੋ।"; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "ਠੀਕ"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "ਇਹ ਸਰਵਰ ਅਸਥਾਈ ਰੂਪ ਵਿੱਚ ਵਿਅਸਤ ਹੈ, ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "ਪਸੰਦ ਕਰੋ"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "ਪਸੰਦ ਕੀਤਾ ਗਿਆ"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "ਰੱਦ ਕਰੋ"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "ਲੌਗ ਆਉਟ ਕਰੋ"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Facebook ਦਾ ਉਪਯੋਗ ਕਰਕੇ ਲੌਗ ਇਨ ਕੀਤਾ ਗਿਆ"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "%@ ਵੱਜੋਂ ਲੌਗ ਇਨ ਕੀਤਾ ਗਿਆ"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "ਲੌਗ ਇਨ ਕਰੋ"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Facebook ਦੇ ਨਾਲ ਲੌਗ ਇਨ ਕਰੋ"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "ਲੌਗ ਆਉਟ ਕਰੋ"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Facebook ਖਾਤੇ ਨੂੰ ਐਕਸੈਸ ਪ੍ਰਦਾਨ ਨਹੀਂ ਕੀਤੀ ਗਈ। ਡਿਵਾਈਸ ਸੈੱਟਿੰਗਜ਼ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ।"; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Facebook ਨਾਲ ਕਨੈਕਟ ਕਰਨ ਵਿੱਚ ਅਸਮਰਥਿਤ ਆਪਣੇ ਨੈੱਟਵਰਕ ਕਨੈਕਸ਼ਨ ਦੀ ਜਾਂਚ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "ਤੁਹਾਡੇ Facebook ਪਾਸਵਰਡ ਨੂੰ ਬਦਲ ਦਿੱਤਾ ਗਿਆ ਹੈ। ਆਪਣੇ ਪਾਸਵਰਡ ਦੀ ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ, ਸੈੱਟਿੰਗਜ਼ > Facebook ਖੋਲ੍ਹੋ ਅਤੇ ਆਪਣੇ ਨਾਂ ਨੂੰ ਟੈਪ ਕਰੋ।"; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Facebook ਖਾਤੇ ਨੂੰ ਡਿਵਾਈਸ 'ਤੇ ਕਨਫ਼ੀਗਰ ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਹੈ।"; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "ਤੁਹਾਡੇ ਖਾਤੇ ਦੀ ਪੁਸ਼ਟੀ ਨਹੀਂ ਕੀਤੀ ਗਈ ਹੈ। ਕਿਰਪਾ ਕਰਕੇ www.facebook.com ਵਿੱਚ ਲੌਗ ਇਨ ਕਰੋ ਅਤੇ ਹੇਠਾਂ ਦਿੱਤੇ ਨਿਰਦੇਸ਼ਾਂ ਦਾ ਪਾਲਣ ਕਰੋ।"; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "ਤੁਸੀਂ ਇਸ ਸਮੇਂ ਐਪ ਵਿੱਚ ਲੌਗ ਇਨ ਨਹੀਂ ਕਰ ਸਕਦੇ ਹੋ। ਕਿਰਪਾ ਕਰਕੇ www.facebook.com ਵਿੱਚ ਲੌਗ ਇਨ ਕਰੋ ਅਤੇ ਹੇਠਾਂ ਦਿੱਤੇ ਨਿਰਦੇਸ਼ਾਂ ਦਾ ਪਾਲਣ ਕਰੋ।"; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "ਨਵਾਂ! ਤੁਸੀਂ ਨਿਯੰਤਰਣ ਵਿੱਚ ਹੋ - ਉਹ ਜਾਣਕਾਰੀ ਚੁਣੋ ਜੋ ਤੁਸੀਂ ਐਪਸ ਦੇ ਨਾਲ ਸਾਂਝੀ ਕਰਨੀ ਚਾਹੁੰਦੇ ਹੋ।"; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "ਲੌਗ ਇਨ ਕਰੋ"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "ਸਾਂਝਾ ਕਰੋ"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "ਭੇਜੋ"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/pl.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/pl.lproj/FacebookSDK.strings new file mode 100644 index 0000000..64453a9 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/pl.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Anuluj"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Zaloguj się jeszcze raz do aplikacji, aby ponownie przyłączyć swoje konto na Facebooku."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Serwer jest zajęty, spróbuj później."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Lubię to!"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Polubione"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Anuluj"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Wyloguj się"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Zalogowano przez Facebooka"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Zalogowano jako %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Zaloguj się"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Zaloguj się przez Facebooka"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Wyloguj się"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Brak dostępu z tego konta na Facebooku. Sprawdź ustawienia urządzenia."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Nie można połączyć się z Facebookiem. Sprawdź połączenie sieciowe i spróbuj ponownie."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Twoje hasło do Facebooka zostało zmienione. Aby potwierdzić hasło, otwórz Ustawienia > Facebook i dotknij swojego imienia i nazwiska."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Na tym urządzeniu nie skonfigurowano konta na Facebooku."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Konto niepotwierdzone. Zaloguj się przez stronę www.facebook.com i postępuj zgodnie ze wskazówkami."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Brak możliwości logowania się do aplikacji. Zaloguj się przez stronę www.facebook.com i postępuj zgodnie ze wskazówkami."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Nowość! Masz pełną kontrolę – określ, jakie informacje chcesz udostępniać aplikacjom."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Zaloguj się"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Wyślij"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Udostępnij"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/pt.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/pt.lproj/FacebookSDK.strings new file mode 100644 index 0000000..06c8177 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/pt.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Cancelar"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Entre nesse aplicativo novamente para reconectar sua conta do Facebook."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "O servidor está temporariamente ocupado. Tente novamente."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Curtir"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Curtiu"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Cancelar"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Sair"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Você entrou usando o Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Conectado como %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Entrar"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Entrar com o Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Sair"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "O acesso à conta do Facebook não foi permitido. Verifique as configurações do dispositivo."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Não foi possível se conectar ao Facebook. Verifique sua conexão de rede e tente novamente."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "A sua senha do Facebook foi alterada. Para confirmar a sua senha, abra Configurações > Facebook e toque no seu nome."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "A conta do Facebook não foi configurada no dispositivo."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "A sua conta não foi confirmada. Entre no site www.facebook.com e siga as instruções fornecidas."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Não é possível entrar em aplicativos neste momento. Entre no site www.facebook.com e siga as instruções fornecidas."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Novidade! Você está no controle - escolha quais informações quer compartilhar com os aplicativos."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Entrar"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Envio"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Compartilhar"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/pt_PT.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/pt_PT.lproj/FacebookSDK.strings new file mode 100644 index 0000000..2414c76 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/pt_PT.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Cancelar"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Volta a iniciar sessão nesta aplicação para te ligares novamente à tua conta do Facebook."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "O servidor está temporariamente ocupado. Tenta novamente."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Gosto"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Gostei"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Cancelar"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Terminar sessão"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Com sessão iniciada através do Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Com sessão iniciada como %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Iniciar sessão"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Iniciar sessão com o Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Terminar a sessão"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "O acesso não foi concedido à conta do Facebook. Verificar as definições do dispositivo."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Não é possível ligar ao Facebook. Verifica a tua ligação à rede e tenta novamente."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "A tua palavra-passe do Facebook foi alterada. Para confirmares a tua palavra-passe, abre as Definições > Facebook e toca no teu nome."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "A conta do Facebook não foi configurada no dispositivo."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "A tua conta não foi confirmada. Inicia sessão em www.facebook.com e segue as instruções indicadas."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Não podes iniciar sessão em aplicações neste momento. Inicia sessão em www.facebook.com e segue as instruções indicadas."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Novidade! Tens o controlo: escolhe a informação que pretendes partilhar com as aplicações."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Iniciar sessão"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Enviar"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Partilhar"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/ru.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/ru.lproj/FacebookSDK.strings new file mode 100644 index 0000000..dc103a1 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/ru.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Отменить"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Войдите в это приложение еще раз, чтобы повторно подключить ваш аккаунт Facebook."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Сервер временно загружен, повторите попытку."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Нравится"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Понравилось"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Отменить"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Выход"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Выполнен вход с помощью Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Вы вошли как %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Вход"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Вход через Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Выход"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Аккаунту Facebook доступ не предоставлен. Проверьте настройки устройства."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Не удалось подключиться к Facebook. Проверьте сетевое подключение и повторите попытку."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Ваш пароль Facebook изменен. Чтобы подтвердить пароль, откройте «Настройки» > Facebook и коснитесь вашего имени."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "На устройстве не настроен аккаунт Facebook."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Ваш аккаунт не подтвержден. Войдите на сайт www.facebook.com и следуйте инструкциям."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Сейчас нельзя войти в приложения. Войдите на сайт www.facebook.com и следуйте инструкциям."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Новинка! У вас все под контролем — выбирайте, какой информацией вы хотите поделиться с приложениями."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Вход в систему"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Отправить"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Поделиться"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/sk.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/sk.lproj/FacebookSDK.strings new file mode 100644 index 0000000..37c632c --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/sk.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Zrušiť"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Ak sa chcete znova pripojiť k svojmu účtu na Facebooku, prihláste sa znova do tejto aplikácie."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Server je dočasne zaneprázdnený – skúste znova."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Páči sa mi to"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Páči sa mi to"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Zrušiť"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Odhlásiť"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Prihlásený cez Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Prihlásený ako %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Prihlásiť sa"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Prihlásiť sa cez Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Odhlásiť sa"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Danému účtu na Facebooku nebol poskytnutý prístup. Skontrolujte nastavenia zariadenia."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Nedá sa pripojiť k Facebooku. Skontrolujte svoje sieťové pripojenie a skúste znova."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Vaše heslo pre Facebook sa zmenilo. Na potvrdenie svojho hesla otvorte Nastavenia > Facebook a ťuknite na svoje meno."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Daný účet na Facebooku nebol nastavený v zariadení."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Váš účet nie je potvrdený. Prihláste sa na stránke www.facebook.com a postupujte podľa pokynov."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Momentálne sa nemôžete prihlásiť do aplikácií. Prihláste sa na stránke www.facebook.com a postupujte podľa pokynov."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Novinka! Máte to pod kontrolou: vyberte, ktoré informácie chcete zdieľať s aplikáciami."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Prihlásenie sa"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Odoslať"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Zdieľať"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/sv.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/sv.lproj/FacebookSDK.strings new file mode 100644 index 0000000..55be750 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/sv.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Avbryt"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Logga in på den här appen igen om du vill ansluta ditt Facebook-konto på nytt."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Servern är upptagen för tillfället. Försök igen."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Gilla"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Gillade"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Avbryt"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Logga ut"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Inloggad med Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Inloggad som %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Logga in"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Logga in med Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Logga ut"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Du har inte fått tillgång till Facebook-kontot. Verifiera enhetsinställningar."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Det går inte att ansluta till Facebook. Kontrollera nätverksanslutningen och försök igen."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Ditt Facebook-lösenord har ändrats. Bekräfta lösenordet genom att öppna Inställningar > Facebook och skriva in ditt namn."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Facebook-konto har inte konfigurerats på enheten."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Ditt konto har inte bekräftats. Logga in på www.facebook.com och följ instruktionerna."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Du kan inte logga in på appar för närvarande. Logga in på www.facebook.com och följ instruktionerna."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Nyhet! Du bestämmer – välj vilken info du vill dela med appar."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Logga in"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Skicka"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Dela"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/ta.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/ta.lproj/FacebookSDK.strings new file mode 100644 index 0000000..8d43f5c --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/ta.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "சரி"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "ரத்துசெய்"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "உங்கள் Facebook கணக்கில் மீண்டும் இணைய, இந்தப் பயன்பாட்டில் மீண்டும் உள்நுழையவும்."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "சரி"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "சேவையகம் தற்காலிகமாக பிஸியாக உள்ளது, மீண்டும் முயற்சிக்கவும்."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "விருப்பம்"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "விரும்பப்பட்டது"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "ரத்துசெய்"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "வெளியேறு"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Facebook மூலம் உள்நுழையப்பட்டுள்ளது"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "%@ இல் உள்நுழைந்துள்ளீர்கள்"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "உள்நுழைவு"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Facebook மூலம் உள்நுழையவும்"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "வெளியேறு"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Facebook கணக்கிற்கு அணுகல் வழங்கப்படவில்லை. சாதன அமைப்புகளைச் சரிபார்க்கவும்."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Facebook இல் இணைய முடியவில்லை. இணைய இணைப்பைச் சரிபார்த்து, மீண்டும் முயற்சிக்கவும்."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Facebook கடவுச்சொல் மாற்றப்பட்டது. கடவுச்சொல்லை உறுதிசெய்ய, அமைப்புகள் > Facebook க்கு சென்று உங்கள் பெயரைத் தட்டவும்."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "சாதனத்தில் Facebook கணக்கு உள்ளமைக்கப்படவில்லை."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "உங்கள் கணக்கு உறுதிசெய்யப்படவில்லை. www.facebook.com இல் உள்நுழைந்து, வழங்கப்பட்டுள்ள வழிமுறைகளைப் பின்பற்றவும்."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "இப்போது பயன்பாடுகளில் உள்நுழைய முடியாது. www.facebook.com இல் உள்நுழைந்து, வழங்கப்பட்டுள்ள வழிமுறைகளைப் பின்பற்றவும்."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "புதிது! உங்கள் கட்டுப்பாட்டில் இருப்பதால், பயன்பாடுகளுடன் பகிர வேண்டிய தகவலைத் தேர்வுசெய்யவும்."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "உள்நுழைவு"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "அனுப்பு"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "பகிர்"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/te.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/te.lproj/FacebookSDK.strings new file mode 100644 index 0000000..80cf883 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/te.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "ఒప్పుకుంటున్నాను"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "రద్దు చేయి"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "దయచేసి మీ Facebook ఖాతాను మళ్లీ కనెక్ట్ చేయడానికి ఈ అప్లికేషన్‌కు మళ్లీ లాగిన్ చేయండి."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "ఒప్పుకుంటున్నాను"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "సర్వర్ తాత్కాలికంగా బిజీగా ఉంది, దయచేసి మళ్లీ ప్రయత్నించండి."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "ఇష్టంగా గుర్తు పెట్టు"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "ఇష్టంగా గుర్తు పెట్టబడింది"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "రద్దు చేయి"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "లాగ్ అవుట్ చేయి"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Facebook ఉపయోగించి లాగిన్ చేసారు"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "%@గా లాగిన్ చేసారు"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "లాగిన్ చేయి"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Facebookతో లాగిన్ చేయి"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "లాగ్ అవుట్ చేయి"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Facebook ఖాతాకు ప్రాప్యత మంజూరు చేయలేదు. పరికర సెట్టింగ్‌లను సరిచూడండి."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Facebookకి కనెక్ట్ చేయడం సాధ్యపడలేదు. మీ నెట్‌వర్క్ కనెక్షన్‌ను తనిఖీ చేసి, మళ్లీ ప్రయత్నించండి."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "మీ Facebook పాస్‌వర్డ్ మారింది. మీ పాస్‌వర్డ్‌ను నిర్ధారించడానికి, సెట్టింగ్‌లు > Facebook తెరిచి, మీ పేరు నొక్కండి."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "పరికరంలో Facebook ఖాతా కాన్ఫిగర్ చేయబడలేదు."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "మీ ఖాతా నిర్ధారించబడలేదు. దయచేసి www.facebook.comకి లాగిన్ చేసి, అందించిన సూచనలను అనుసరించండి."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "ప్రస్తుతం మీరు అప్లికేషన్‌లకు లాగిన్ చేయలేరు. దయచేసి www.facebook.comకి లాగిన్ చేసి, అందించిన సూచనలను అనుసరించండి."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "సరికొత్తది! మీకు నియంత్రణ ఉంది - మీరు అప్లికేషన్‌లతో ఏ సమాచారాన్ని భాగస్వామ్యం చేయాలనుకుంటున్నారో ఎంచుకోండి."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "లాగిన్ చేయండి"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "పంపు"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "భాగస్వామ్యం చేయండి"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/th.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/th.lproj/FacebookSDK.strings new file mode 100644 index 0000000..194d434 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/th.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "ตกลง"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "ยกเลิก"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "โปรดลงชื่อเข้าใช้แอพนี้อีกครั้งเพื่อเชื่อมต่อบัญชีผู้ใช้ Facebook ของคุณใหม่"; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "ตกลง"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "เซิร์ฟเวอร์ไม่พร้อมให้บริการชั่วคราว โปรดลองใหม่อีกครั้ง"; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "ถูกใจ"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "ถูกใจแล้ว"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "ยกเลิก"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "ออกจากระบบ"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "เข้าสู่ระบบโดยใช้ Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "เข้าสู่ระบบในชื่อ %@"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "เข้าสู่ระบบ"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "เข้าสู่ระบบด้วย Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "ออกจากระบบ"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "บัญชีผู้ใช้ Facebook ไม่ได้รับอนุญาตให้เข้าถึง ตรวจสอบการตั้งค่าของอุปกรณ์"; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "ไม่สามารถเชื่อมต่อกับ Facebook ตรวจสอบการเชื่อมต่อเครือข่ายและลองอีกครั้ง"; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "เปลี่ยนรหัสผ่าน Facebook ของคุณแล้ว เพื่อยืนยันรหัสผ่านของคุณ ให้เปิด การตั้งค่า > Facebook แล้วแตะชื่อของคุณ"; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "บัญชีผู้ใช้ Facebook ไม่ได้รับการกำหนดค่าบนอุปกรณ์เครื่องนี้"; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "บัญชีผู้ใช้ของคุณไม่ได้รับการยืนยัน โปรดเข้าสู่ระบบที่ www.facebook.com และทำตามคำแนะนำที่ปรากฏ"; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "คุณไม่สามารถเข้าสู่ระบบของแอพได้ในตอนนี้ โปรดเข้าสู่ระบบที่ www.facebook.com และทำตามคำแนะนำที่ปรากฏ"; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "ใหม่! คุณเป็นฝ่ายควบคุม โปรดเลือกสิ่งที่คุณต้องการแชร์ด้วยแอพ"; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "เข้าสู่ระบบ"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "ส่ง"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "แชร์"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/tr.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/tr.lproj/FacebookSDK.strings new file mode 100644 index 0000000..fb910ea --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/tr.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "Tamam"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "İptal"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Facebook hesabına yeniden bağlanmak için lütfen bu uygulamaya tekrar giriş yap."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "Tamam"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Sunucu geçici olarak meşgul. Lütfen tekrar dene."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Beğen"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Beğendin"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "İptal"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Çıkış Yap"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Facebook ile giriş yapıldı"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "%@ olarak giriş yapıldı"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Giriş yap"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Facebook ile giriş yap"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Çıkış yap"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Facebook hesabına erişim izni verilmedi. Cihaz ayarlarını doğrula."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Facebook'a bağlanılamıyor. Ağ bağlantını kontrol edip tekrar dene."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Facebook şifren değiştirildi. Şifreni onaylamak için Ayarlar > Facebook'u aç ve adına dokunun."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Facebook hesabı cihaz üzerinde yapılandırılmadı."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Hesabın onaylanmadı. Lütfen www.facebook.com adresine giriş yap ve verilen talimatları izle."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Şu an için uygulamalara giriş yapamazsın. Lütfen www.facebook.com adresine giriş yap ve verilen talimatları izle."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Yeni! Kontrol sende. Uygulamalarla paylaşmak istediğin bilgileri seç."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Giriş Yap"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Gönder"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Paylaş"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/vi.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/vi.lproj/FacebookSDK.strings new file mode 100644 index 0000000..684733f --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/vi.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "OK"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "Hủy"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "Vui lòng đăng nhập lại vào ứng dụng này để kết nối lại tài khoản Facebook của bạn."; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "OK"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "Máy chủ hiện đang bận, vui lòng thử lại sau."; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "Thích"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "Đã thích"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "Hủy"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "Đăng xuất"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "Đã đăng nhập bằng Facebook"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "Đã đăng nhập với tư cách là"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "Đăng nhập"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "Đăng nhập bằng Facebook"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "Đăng xuất"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "Quyền truy cập chưa được cấp cho tài khoản Facebook. Xác minh thiết lập của thiết bị."; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "Không thể kết nối với Facebook. Vui lòng kiểm tra kết nối mạng của bạn và thử lại."; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "Mật khẩu Facebook của bạn đã thay đổi. Để xác nhận mật khẩu của bạn, hãy mở Thiết lập > Facebook và nhấn vào tên bạn."; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Tài khoản Facebook chưa được định cấu hình trên thiết bị."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "Tài khoản của bạn không được xác nhận. Vui lòng đăng nhập vào www.facebook.com và làm theo hướng dẫn được cung cấp."; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "Bạn không thể đăng nhập vào các ứng dụng lúc này. Vui lòng đăng nhập vào www.facebook.com và làm theo hướng dẫn được cung cấp."; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "Mới! Bạn đang có quyền kiểm soát - hãy chọn thông tin bạn muốn chia sẻ với các ứng dụng."; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "Đăng nhập"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "Gửi"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "Chia sẻ"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/zh.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/zh.lproj/FacebookSDK.strings new file mode 100644 index 0000000..d765af2 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/zh.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "确定"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "取消"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "请再次登录此应用,以便重新连接您的 Facebook 帐户。"; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "确定"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "服务器暂时繁忙,请重试。"; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "赞"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "赞了"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "取消"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "退出"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "已使用 Facebook 登录"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "已以 %@ 身份登录"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "登录"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "使用 Facebook 登录"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "退出"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "未授予该 Facebook 帐户访问权限。验证设备设置。"; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "无法连接到 Facebook。检查网络连接并重试。"; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "您的 Facebook 密码已更改。要确认密码,请打开设置 > Facebook,并轻触您的姓名。"; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "未在设备上配置 Facebook 帐户。"; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "您的帐户未确认。请登录 www.facebook.com,并按照提供的说明操作。"; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "您此时不能登录应用。请登录 www.facebook.com,并按照提供的说明操作。"; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "新增功能!一切任您掌控 — 选择您想通过应用分享的信息。"; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "登录"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "发送"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "分享"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/zh_Hant_HK.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/zh_Hant_HK.lproj/FacebookSDK.strings new file mode 100644 index 0000000..a080736 --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/zh_Hant_HK.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "確定"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "取消"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "請再次登入此應用程式以重新連接您的 Facebook 帳戶。"; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "確定"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "伺服器暫時忙碌中,請再試一次。"; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "讚好"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "已讚好"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "取消"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "登出"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "使用 Facebook 登入"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "以 %@ 身分登入"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "登入"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "使用 Facebook 登入"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "登出"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "沒有獲得 Facebook 帳戶的存取授權。確認裝置設定。"; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "無法與 Facebook 連線。請檢查網絡連線,然後再試一次。"; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "您的 Facebook 密碼已經變更。要確認密碼,請開啟設定 > Facebook,然後點按您的名稱。"; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "Facebook 帳戶尚未在此裝置上設定。"; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "您的帳戶尚未確認。請登入 www.facebook.com 並依據指示操作。"; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "您現時無法登入應用程式。請登入 www.facebook.com 並依據指示操作。"; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "最新消息!控制權在您 - 選擇您要與應用程式分享的資訊。"; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "登入"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "傳送"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "分享"; diff --git a/Resources/FacebookSDKStrings.bundle/Resources/zh_Hant_TW.lproj/FacebookSDK.strings b/Resources/FacebookSDKStrings.bundle/Resources/zh_Hant_TW.lproj/FacebookSDK.strings new file mode 100644 index 0000000..5c46d6a --- /dev/null +++ b/Resources/FacebookSDKStrings.bundle/Resources/zh_Hant_TW.lproj/FacebookSDK.strings @@ -0,0 +1,71 @@ +/* The title of the label to dismiss the alert when presenting user facing error messages */ +"ErrorRecovery.Alert.OK" = "是"; + +/* The title of the label to decline attempting error recovery */ +"ErrorRecovery.Cancel" = "取消"; + +/* The fallback message to display to recover invalidated tokens */ +"ErrorRecovery.Login.Suggestion" = "請重新登入此應用程式以重新連結您的 Facebook 帳號。"; + +/* The title of the label to start attempting error recovery */ +"ErrorRecovery.OK" = "是"; + +/* The fallback message to display to retry transient errors */ +"ErrorRecovery.Transient.Suggestion" = "伺服器暫時忙碌中,請再試一次。"; + +/* The label for the FBSDKLikeButton when the object is not currently liked. */ +"LikeButton.Like" = "讚"; + +/* The label for the FBSDKLikeButton when the object is currently liked. */ +"LikeButton.Liked" = "說讚"; + +/* The label for the FBSDKLoginButton action sheet to cancel logging out */ +"LoginButton.CancelLogout" = "取消"; + +/* The label for the FBSDKLoginButton action sheet to confirm logging out */ +"LoginButton.ConfirmLogOut" = "登出"; + +/* The fallback string for the FBSDKLoginButton label when the user name is not available yet */ +"LoginButton.LoggedIn" = "已使用 Facebook 登入"; + +/* The format string for the FBSDKLoginButton label when the user is logged in */ +"LoginButton.LoggedInAs" = "以 %@ 身分登入"; + +/* The short label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogIn" = "登入"; + +/* The long label for the FBSDKLoginButton when the user is currently logged out */ +"LoginButton.LogInLong" = "使用 Facebook 登入"; + +/* The label for the FBSDKLoginButton when the user is currently logged in */ +"LoginButton.LogOut" = "登出"; + +/* The user facing error message when the app slider has been disabled and login fails. */ +"LoginError.SystemAccount.Disabled" = "尚未取得授權,無法存取 Facebook 帳號。請確認裝置設定。"; + +/* The user facing error message when the Accounts framework encounters a network error. */ +"LoginError.SystemAccount.Network" = "無法連線到 Facebook。請檢查網路連線,然後再試一次。"; + +/* The user facing error message when the device Facebook account password is incorrect and login fails. */ +"LoginError.SystemAccount.PasswordChange" = "您的 Facebook 密碼已經更改。若要確認您的密碼,請開啟「設定」>「Facebook」,然後點按您的姓名。"; + +/* The user facing error message when the device Facebook account is unavailable and login fails. */ +"LoginError.SystemAccount.Unavailable" = "尚未透過裝置設定 Facebook 帳號。"; + +/* The user facing error message when the Facebook account signed in to the Accounts framework becomes unconfirmed. */ +"LoginError.SystemAccount.UnconfirmedUser" = "您的帳號尚未確認。請登入 www.facebook.com,然後按照指示操作。"; + +/* The user facing error message when the Facebook account signed in to the Accounts framework has been checkpointed. */ +"LoginError.SystemAccount.UserCheckpointed" = "您目前無法登入應用程式。請登入 www.facebook.com,然後按照指示操作。"; + +/* The message of the FBSDKLoginTooltipView */ +"LoginTooltip.Message" = "新消息!您已成功登入,請選擇要與應用程式分享的資訊。"; + +/* Title of the web dialog that prompts the user to log in to Facebook. */ +"LoginWeb.LogInTitle" = "登入"; + +/* The label for FBSDKSendButton */ +"SendButton.Send" = "傳送"; + +/* The label for FBSDKShareButton */ +"ShareButton.Share" = "分享"; diff --git a/Resources/TwitterKitResources.bundle/TFSScribe.momd/TFSScribe.mom b/Resources/TwitterKitResources.bundle/TFSScribe.momd/TFSScribe.mom new file mode 100644 index 0000000..a9a786b Binary files /dev/null and b/Resources/TwitterKitResources.bundle/TFSScribe.momd/TFSScribe.mom differ diff --git a/Resources/TwitterKitResources.bundle/TFSScribe.momd/VersionInfo.plist b/Resources/TwitterKitResources.bundle/TFSScribe.momd/VersionInfo.plist new file mode 100644 index 0000000..45677dc Binary files /dev/null and b/Resources/TwitterKitResources.bundle/TFSScribe.momd/VersionInfo.plist differ diff --git a/Resources/TwitterKitResources.bundle/ar.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/ar.lproj/Localizable.strings new file mode 100644 index 0000000..6e2f181 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/ar.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/bn.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/bn.lproj/Localizable.strings new file mode 100644 index 0000000..dc0aa93 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/bn.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/cs.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/cs.lproj/Localizable.strings new file mode 100644 index 0000000..2ff222f Binary files /dev/null and b/Resources/TwitterKitResources.bundle/cs.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/da.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/da.lproj/Localizable.strings new file mode 100644 index 0000000..00b8488 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/da.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/de.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/de.lproj/Localizable.strings new file mode 100644 index 0000000..6fa77c3 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/de.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/emailshare.png b/Resources/TwitterKitResources.bundle/emailshare.png new file mode 100644 index 0000000..ebaa1eb Binary files /dev/null and b/Resources/TwitterKitResources.bundle/emailshare.png differ diff --git a/Resources/TwitterKitResources.bundle/emailshare@2x.png b/Resources/TwitterKitResources.bundle/emailshare@2x.png new file mode 100644 index 0000000..2546629 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/emailshare@2x.png differ diff --git a/Resources/TwitterKitResources.bundle/emailshare@3x.png b/Resources/TwitterKitResources.bundle/emailshare@3x.png new file mode 100644 index 0000000..18defd7 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/emailshare@3x.png differ diff --git a/Resources/TwitterKitResources.bundle/en-gb.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/en-gb.lproj/Localizable.strings new file mode 100644 index 0000000..7fcb20a Binary files /dev/null and b/Resources/TwitterKitResources.bundle/en-gb.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/en.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/en.lproj/Localizable.strings new file mode 100644 index 0000000..8e51c5d --- /dev/null +++ b/Resources/TwitterKitResources.bundle/en.lproj/Localizable.strings @@ -0,0 +1,53 @@ +/* Label for button to bring up share dialog to share this Tweet in a single Tweet view */ +"tw__share_tweet" = "Share Tweet"; +/* Subject format used to prefill certain sharing options such as Email includes full name (%1$@) and screenname (%2$@) */ +"tw__share_tweet_subject_format" = "Tweet from %1$@ (@%2$@)"; +/* Generic share text format used in all sharing options includes screenname (%1$@) and URL to the Tweet (%2$@) */ +"tw__share_tweet_generic_template_format" = "Check out @%1$@\'s Tweet: %2$@"; +/* Label for Sign in with Twitter button */ +"tw__sign_in_with_twitter_button" = "Log in with Twitter"; +/* Label Email Share Screen negative button */ +"tw__email_share_negative_button" = "Not now"; +/* Label Email Share Screen affirmative button */ +"tw__email_share_affirmative_button" = "Allow"; +/* Heading that appears above the detail message on the share your email screen */ +"tw__email_share_heading" = "Share your email address"; +/* Detail message that includes the app name and username on the share your email screen */ +"tw__email_share_detail_message_format" = "Get updates and other information from %@ when you allow them access to your email on your Twitter account @%@."; +/* Fallback string for detail message in case the app name is not available */ +"tw__email_share_detail_message_this_app" = "this app"; +/* Fallback string for detail message in case the user is not signed in */ +"tw__email_share_detail_message_not_signed_in" = "(not signed in)"; +/* Label for attributing this Tweet was retweeted by the user %@ */ +"tw__tweet_retweeted_by_user" = "Retweeted by %@"; + +/* Timestamps */ + +/* Really short abbreviation for days (plural). 5 days would be '5d' */ +"TIME_SHORT_DAYS_FORMAT" = "%dd"; +/* Really short abbreviation for day (singular). 1 day would be '1d' */ +"TIME_SHORT_DAY_FORMAT" = "%dd"; +/* Really short abbreviation for hours (plural). 5 hours would be '5h' */ +"TIME_SHORT_HOURS_FORMAT" = "%dh"; +/* Really short abbreviation for hour (singular). 1 hour would be '1h' */ +"TIME_SHORT_HOUR_FORMAT" = "%dh"; +/* Really short abbreviation for minutes (plural). 5 minutes would be '5m' */ +"TIME_SHORT_MINUTES_FORMAT" = "%dm"; +/* Really short abbreviation for minute (singular). 1 minute would be '1m' */ +"TIME_SHORT_MINUTE_FORMAT" = "%dm"; +/* Really short abbreviation for seconds (plural). 5 seconds would be '5s' */ +"TIME_SHORT_SECONDS_FORMAT" = "%ds"; +/* Really short abbreviation for second (singular). '1s' */ +"TIME_SHORT_SECOND_FORMAT" = "%ds"; + +/* Accessibility Labels */ + +/* Text spoken out with VoiceOver when a tweet has an image showing */ +"tw__single_image" = "One image attached"; +/* Text spoken out with VoiceOver for selecting the profile image on a regular tweet view */ +"tw__tweet_profile_accessibility" = "Profile"; +/* Text spoken out with VoiceOver for selecting the attached image on a regular tweet view */ +"tw__tweet_image_accessibility" = "Attachment"; + +/* Test String (just for unit tests) */ +"tw__test_string" = "Test"; diff --git a/Resources/TwitterKitResources.bundle/es.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/es.lproj/Localizable.strings new file mode 100644 index 0000000..e645165 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/es.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/fa.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/fa.lproj/Localizable.strings new file mode 100644 index 0000000..d85e9c2 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/fa.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/fi.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/fi.lproj/Localizable.strings new file mode 100644 index 0000000..fad15a3 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/fi.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/fr.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/fr.lproj/Localizable.strings new file mode 100644 index 0000000..7ff8acd Binary files /dev/null and b/Resources/TwitterKitResources.bundle/fr.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/he.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/he.lproj/Localizable.strings new file mode 100644 index 0000000..9b9680d Binary files /dev/null and b/Resources/TwitterKitResources.bundle/he.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/hi.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/hi.lproj/Localizable.strings new file mode 100644 index 0000000..6bd07c7 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/hi.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/hu.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/hu.lproj/Localizable.strings new file mode 100644 index 0000000..d3401d6 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/hu.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/id.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/id.lproj/Localizable.strings new file mode 100644 index 0000000..f2312a9 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/id.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/it.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/it.lproj/Localizable.strings new file mode 100644 index 0000000..029a45d Binary files /dev/null and b/Resources/TwitterKitResources.bundle/it.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/ja.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/ja.lproj/Localizable.strings new file mode 100644 index 0000000..7f7f5a5 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/ja.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/ko.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/ko.lproj/Localizable.strings new file mode 100644 index 0000000..a3f237b Binary files /dev/null and b/Resources/TwitterKitResources.bundle/ko.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/ms.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/ms.lproj/Localizable.strings new file mode 100644 index 0000000..a0171a9 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/ms.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/nb.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/nb.lproj/Localizable.strings new file mode 100644 index 0000000..878848e Binary files /dev/null and b/Resources/TwitterKitResources.bundle/nb.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/nl.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/nl.lproj/Localizable.strings new file mode 100644 index 0000000..0f2f331 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/nl.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/pl.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/pl.lproj/Localizable.strings new file mode 100644 index 0000000..cf0dfcf Binary files /dev/null and b/Resources/TwitterKitResources.bundle/pl.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/pt.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/pt.lproj/Localizable.strings new file mode 100644 index 0000000..74f567e Binary files /dev/null and b/Resources/TwitterKitResources.bundle/pt.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/ro.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/ro.lproj/Localizable.strings new file mode 100644 index 0000000..9cbeefd Binary files /dev/null and b/Resources/TwitterKitResources.bundle/ro.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/ru.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/ru.lproj/Localizable.strings new file mode 100644 index 0000000..6dd56c5 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/ru.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/sv.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/sv.lproj/Localizable.strings new file mode 100644 index 0000000..42519ac Binary files /dev/null and b/Resources/TwitterKitResources.bundle/sv.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/th.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/th.lproj/Localizable.strings new file mode 100644 index 0000000..33781fe Binary files /dev/null and b/Resources/TwitterKitResources.bundle/th.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/tl.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/tl.lproj/Localizable.strings new file mode 100644 index 0000000..91b6041 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/tl.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/tr.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/tr.lproj/Localizable.strings new file mode 100644 index 0000000..730f875 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/tr.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-logo-white.png b/Resources/TwitterKitResources.bundle/twttr-icn-logo-white.png new file mode 100644 index 0000000..b7e4f7c Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-logo-white.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-logo-white@2x.png b/Resources/TwitterKitResources.bundle/twttr-icn-logo-white@2x.png new file mode 100644 index 0000000..bbfbee7 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-logo-white@2x.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-logo-white@3x.png b/Resources/TwitterKitResources.bundle/twttr-icn-logo-white@3x.png new file mode 100644 index 0000000..3074978 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-logo-white@3x.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-logo.png b/Resources/TwitterKitResources.bundle/twttr-icn-logo.png new file mode 100644 index 0000000..ea6f7cd Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-logo.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-logo@2x.png b/Resources/TwitterKitResources.bundle/twttr-icn-logo@2x.png new file mode 100644 index 0000000..2c17c4d Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-logo@2x.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-logo@3x.png b/Resources/TwitterKitResources.bundle/twttr-icn-logo@3x.png new file mode 100644 index 0000000..b969d88 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-logo@3x.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error.png new file mode 100644 index 0000000..40d6a35 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error@2x.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error@2x.png new file mode 100644 index 0000000..0bfc026 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error@2x.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error@3x.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error@3x.png new file mode 100644 index 0000000..8dc8747 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo-error@3x.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo.png new file mode 100644 index 0000000..ad4c4b4 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo@2x.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo@2x.png new file mode 100644 index 0000000..47ea38b Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo@2x.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo@3x.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo@3x.png new file mode 100644 index 0000000..db471c6 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-place-holder-photo@3x.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark.png new file mode 100644 index 0000000..2f2d32e Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark@2x.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark@2x.png new file mode 100644 index 0000000..61692b4 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark@2x.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark@3x.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark@3x.png new file mode 100644 index 0000000..4dda258 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-dark@3x.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light.png new file mode 100644 index 0000000..745d9b6 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light@2x.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light@2x.png new file mode 100644 index 0000000..6033368 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light@2x.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light@3x.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light@3x.png new file mode 100644 index 0000000..0707a13 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-retweeted-by-light@3x.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed.png new file mode 100644 index 0000000..b9c10cc Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed@2x.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed@2x.png new file mode 100644 index 0000000..ad77218 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed@2x.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed@3x.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed@3x.png new file mode 100644 index 0000000..abb6c83 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified-pressed@3x.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified.png new file mode 100644 index 0000000..74d94a2 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified@2x.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified@2x.png new file mode 100644 index 0000000..f783dbe Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified@2x.png differ diff --git a/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified@3x.png b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified@3x.png new file mode 100644 index 0000000..31a34ee Binary files /dev/null and b/Resources/TwitterKitResources.bundle/twttr-icn-tweet-verified@3x.png differ diff --git a/Resources/TwitterKitResources.bundle/uk.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/uk.lproj/Localizable.strings new file mode 100644 index 0000000..feba7b0 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/uk.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/ur.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/ur.lproj/Localizable.strings new file mode 100644 index 0000000..74eb578 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/ur.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/vi.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/vi.lproj/Localizable.strings new file mode 100644 index 0000000..3eb0a19 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/vi.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/zh-Hans.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/zh-Hans.lproj/Localizable.strings new file mode 100644 index 0000000..15b99c9 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/zh-Hans.lproj/Localizable.strings differ diff --git a/Resources/TwitterKitResources.bundle/zh-Hant.lproj/Localizable.strings b/Resources/TwitterKitResources.bundle/zh-Hant.lproj/Localizable.strings new file mode 100644 index 0000000..e01bc78 Binary files /dev/null and b/Resources/TwitterKitResources.bundle/zh-Hant.lproj/Localizable.strings differ diff --git a/Resources/VKSdkResources.bundle/BlueBtn.png b/Resources/VKSdkResources.bundle/BlueBtn.png new file mode 100755 index 0000000..5e74f89 Binary files /dev/null and b/Resources/VKSdkResources.bundle/BlueBtn.png differ diff --git a/Resources/VKSdkResources.bundle/BlueBtn@2x.png b/Resources/VKSdkResources.bundle/BlueBtn@2x.png new file mode 100755 index 0000000..d382611 Binary files /dev/null and b/Resources/VKSdkResources.bundle/BlueBtn@2x.png differ diff --git a/Resources/VKSdkResources.bundle/BlueBtn@3x.png b/Resources/VKSdkResources.bundle/BlueBtn@3x.png new file mode 100755 index 0000000..3091516 Binary files /dev/null and b/Resources/VKSdkResources.bundle/BlueBtn@3x.png differ diff --git a/Resources/VKSdkResources.bundle/BlueBtn_pressed.png b/Resources/VKSdkResources.bundle/BlueBtn_pressed.png new file mode 100755 index 0000000..f930dc0 Binary files /dev/null and b/Resources/VKSdkResources.bundle/BlueBtn_pressed.png differ diff --git a/Resources/VKSdkResources.bundle/BlueBtn_pressed@2x.png b/Resources/VKSdkResources.bundle/BlueBtn_pressed@2x.png new file mode 100755 index 0000000..c7e593c Binary files /dev/null and b/Resources/VKSdkResources.bundle/BlueBtn_pressed@2x.png differ diff --git a/Resources/VKSdkResources.bundle/BlueBtn_pressed@3x.png b/Resources/VKSdkResources.bundle/BlueBtn_pressed@3x.png new file mode 100755 index 0000000..b358902 Binary files /dev/null and b/Resources/VKSdkResources.bundle/BlueBtn_pressed@3x.png differ diff --git a/Resources/VKSdkResources.bundle/Disclosure.png b/Resources/VKSdkResources.bundle/Disclosure.png new file mode 100755 index 0000000..8382e6d Binary files /dev/null and b/Resources/VKSdkResources.bundle/Disclosure.png differ diff --git a/Resources/VKSdkResources.bundle/Disclosure@2x.png b/Resources/VKSdkResources.bundle/Disclosure@2x.png new file mode 100755 index 0000000..15514c2 Binary files /dev/null and b/Resources/VKSdkResources.bundle/Disclosure@2x.png differ diff --git a/Resources/VKSdkResources.bundle/Disclosure@3x.png b/Resources/VKSdkResources.bundle/Disclosure@3x.png new file mode 100755 index 0000000..e9d477d Binary files /dev/null and b/Resources/VKSdkResources.bundle/Disclosure@3x.png differ diff --git a/Resources/VKSdkResources.bundle/Info.plist b/Resources/VKSdkResources.bundle/Info.plist new file mode 100755 index 0000000..bb5f4f9 Binary files /dev/null and b/Resources/VKSdkResources.bundle/Info.plist differ diff --git a/Resources/VKSdkResources.bundle/en.lproj/InfoPlist.strings b/Resources/VKSdkResources.bundle/en.lproj/InfoPlist.strings new file mode 100755 index 0000000..3967e06 Binary files /dev/null and b/Resources/VKSdkResources.bundle/en.lproj/InfoPlist.strings differ diff --git a/Resources/VKSdkResources.bundle/en.lproj/Localizable.strings b/Resources/VKSdkResources.bundle/en.lproj/Localizable.strings new file mode 100755 index 0000000..4bbec45 Binary files /dev/null and b/Resources/VKSdkResources.bundle/en.lproj/Localizable.strings differ diff --git a/Resources/VKSdkResources.bundle/ic_deleteattach.png b/Resources/VKSdkResources.bundle/ic_deleteattach.png new file mode 100755 index 0000000..576e027 Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_deleteattach.png differ diff --git a/Resources/VKSdkResources.bundle/ic_deleteattach@2x.png b/Resources/VKSdkResources.bundle/ic_deleteattach@2x.png new file mode 100755 index 0000000..a7ed2a3 Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_deleteattach@2x.png differ diff --git a/Resources/VKSdkResources.bundle/ic_deletephoto.png b/Resources/VKSdkResources.bundle/ic_deletephoto.png new file mode 100755 index 0000000..bc533ac Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_deletephoto.png differ diff --git a/Resources/VKSdkResources.bundle/ic_deletephoto@2x.png b/Resources/VKSdkResources.bundle/ic_deletephoto@2x.png new file mode 100755 index 0000000..ff13cfe Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_deletephoto@2x.png differ diff --git a/Resources/VKSdkResources.bundle/ic_vk_activity_logo.png b/Resources/VKSdkResources.bundle/ic_vk_activity_logo.png new file mode 100755 index 0000000..dad3f8b Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_vk_activity_logo.png differ diff --git a/Resources/VKSdkResources.bundle/ic_vk_activity_logo@2x.png b/Resources/VKSdkResources.bundle/ic_vk_activity_logo@2x.png new file mode 100755 index 0000000..fb56c8f Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_vk_activity_logo@2x.png differ diff --git a/Resources/VKSdkResources.bundle/ic_vk_activity_logo@2x~ipad.png b/Resources/VKSdkResources.bundle/ic_vk_activity_logo@2x~ipad.png new file mode 100755 index 0000000..c8fc56e Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_vk_activity_logo@2x~ipad.png differ diff --git a/Resources/VKSdkResources.bundle/ic_vk_activity_logo@3x.png b/Resources/VKSdkResources.bundle/ic_vk_activity_logo@3x.png new file mode 100755 index 0000000..0799c8b Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_vk_activity_logo@3x.png differ diff --git a/Resources/VKSdkResources.bundle/ic_vk_activity_logo~ipad.png b/Resources/VKSdkResources.bundle/ic_vk_activity_logo~ipad.png new file mode 100755 index 0000000..6f11074 Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_vk_activity_logo~ipad.png differ diff --git a/Resources/VKSdkResources.bundle/ic_vk_ios7_activity_logo.png b/Resources/VKSdkResources.bundle/ic_vk_ios7_activity_logo.png new file mode 100755 index 0000000..f54787b Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_vk_ios7_activity_logo.png differ diff --git a/Resources/VKSdkResources.bundle/ic_vk_ios7_activity_logo@2x.png b/Resources/VKSdkResources.bundle/ic_vk_ios7_activity_logo@2x.png new file mode 100755 index 0000000..cc5b029 Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_vk_ios7_activity_logo@2x.png differ diff --git a/Resources/VKSdkResources.bundle/ic_vk_ios7_activity_logo@2x~ipad.png b/Resources/VKSdkResources.bundle/ic_vk_ios7_activity_logo@2x~ipad.png new file mode 100755 index 0000000..638c3fe Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_vk_ios7_activity_logo@2x~ipad.png differ diff --git a/Resources/VKSdkResources.bundle/ic_vk_ios7_activity_logo@3x.png b/Resources/VKSdkResources.bundle/ic_vk_ios7_activity_logo@3x.png new file mode 100755 index 0000000..855cca5 Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_vk_ios7_activity_logo@3x.png differ diff --git a/Resources/VKSdkResources.bundle/ic_vk_ios7_activity_logo~ipad.png b/Resources/VKSdkResources.bundle/ic_vk_ios7_activity_logo~ipad.png new file mode 100755 index 0000000..ba471bf Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_vk_ios7_activity_logo~ipad.png differ diff --git a/Resources/VKSdkResources.bundle/ic_vk_logo_nb.png b/Resources/VKSdkResources.bundle/ic_vk_logo_nb.png new file mode 100755 index 0000000..2aca82c Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_vk_logo_nb.png differ diff --git a/Resources/VKSdkResources.bundle/ic_vk_logo_nb@2x.png b/Resources/VKSdkResources.bundle/ic_vk_logo_nb@2x.png new file mode 100755 index 0000000..76295c2 Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_vk_logo_nb@2x.png differ diff --git a/Resources/VKSdkResources.bundle/ic_vk_logo_nb@3x.png b/Resources/VKSdkResources.bundle/ic_vk_logo_nb@3x.png new file mode 100755 index 0000000..29c8adf Binary files /dev/null and b/Resources/VKSdkResources.bundle/ic_vk_logo_nb@3x.png differ diff --git a/Resources/VKSdkResources.bundle/img_newpostattachlink.png b/Resources/VKSdkResources.bundle/img_newpostattachlink.png new file mode 100755 index 0000000..8915dd5 Binary files /dev/null and b/Resources/VKSdkResources.bundle/img_newpostattachlink.png differ diff --git a/Resources/VKSdkResources.bundle/img_newpostattachlink@2x.png b/Resources/VKSdkResources.bundle/img_newpostattachlink@2x.png new file mode 100755 index 0000000..c8c0744 Binary files /dev/null and b/Resources/VKSdkResources.bundle/img_newpostattachlink@2x.png differ diff --git a/Resources/VKSdkResources.bundle/ru.lproj/Localizable.strings b/Resources/VKSdkResources.bundle/ru.lproj/Localizable.strings new file mode 100755 index 0000000..af5200b Binary files /dev/null and b/Resources/VKSdkResources.bundle/ru.lproj/Localizable.strings differ diff --git a/Resources/VKSdkResources.bundle/vk_settings.png b/Resources/VKSdkResources.bundle/vk_settings.png new file mode 100755 index 0000000..738996e Binary files /dev/null and b/Resources/VKSdkResources.bundle/vk_settings.png differ diff --git a/Resources/VKSdkResources.bundle/vk_settings@2x.png b/Resources/VKSdkResources.bundle/vk_settings@2x.png new file mode 100755 index 0000000..f8e24c3 Binary files /dev/null and b/Resources/VKSdkResources.bundle/vk_settings@2x.png differ diff --git a/Mobily/main.m b/Sources/MobilyCore/MobilyAV.h similarity index 86% rename from Mobily/main.m rename to Sources/MobilyCore/MobilyAV.h index cba5928..3b74500 100644 --- a/Mobily/main.m +++ b/Sources/MobilyCore/MobilyAV.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,16 +33,10 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyContext.h" +#import /*--------------------------------------------------*/ -int main(int argc, char* argv[]) { - @autoreleasepool { - [MobilyContext setArgCount:argc argValue:argv]; - [MobilyContext setAccessKey:@"0123456789"]; - return [MobilyContext run]; - } -} +#import /*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyActivityView.h b/Sources/MobilyCore/MobilyActivityView.h new file mode 100644 index 0000000..9ed7048 --- /dev/null +++ b/Sources/MobilyCore/MobilyActivityView.h @@ -0,0 +1,98 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, MobilyActivityViewStyle) { + MobilyActivityViewStyleNone, + MobilyActivityViewStylePlane, + MobilyActivityViewStyleCircleFlip, + MobilyActivityViewStyleBounce, + MobilyActivityViewStyleWave, + MobilyActivityViewStyleWanderingCubes, + MobilyActivityViewStylePulse, + MobilyActivityViewStyleChasingDots, + MobilyActivityViewStyleThreeBounce, + MobilyActivityViewStyleCircle, + MobilyActivityViewStyle9CubeGrid, + MobilyActivityViewStyleWordPress, + MobilyActivityViewStyleFadingCircle, + MobilyActivityViewStyleFadingCircleAlt, + MobilyActivityViewStyleArc, + MobilyActivityViewStyleArcAlt +}; + +/*--------------------------------------------------*/ + +typedef void (^MobilyActivityViewBlock)(); + +/*--------------------------------------------------*/ + +@interface MobilyActivityView : UIView < MobilyObject > + +@property(nonatomic, readonly, assign) MobilyActivityViewStyle style; +@property(nonatomic, readwrite, assign) CGFloat margin; +@property(nonatomic, readwrite, assign) CGFloat spacing; +@property(nonatomic, readwrite, strong) UIColor* panelColor; +@property(nonatomic, readwrite, assign) CGFloat panelCornerRadius; +@property(nonatomic, readwrite, strong) UIColor* spinnerColor; +@property(nonatomic, readwrite, assign) CGFloat spinnerSize; +@property(nonatomic, readwrite, strong) UIColor* textColor; +@property(nonatomic, readwrite, strong) UIFont* textFont; +@property(nonatomic, readonly, assign) CGFloat textWidth; +@property(nonatomic, readwrite, strong) NSString* text; +@property(nonatomic, readonly, assign, getter=isShowed) BOOL showed; + ++ (instancetype)activityViewInView:(UIView*)view style:(MobilyActivityViewStyle)style; ++ (instancetype)activityViewInView:(UIView*)view style:(MobilyActivityViewStyle)style text:(NSString*)text; ++ (instancetype)activityViewInView:(UIView*)view style:(MobilyActivityViewStyle)style text:(NSString*)text textWidth:(NSUInteger)textWidth; + +- (instancetype)initWithInView:(UIView*)view style:(MobilyActivityViewStyle)style text:(NSString*)text textWidth:(NSUInteger)textWidth; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)show; +- (void)showComplete:(MobilyActivityViewBlock)complete; +- (void)showPrepare:(MobilyActivityViewBlock)prepare complete:(MobilyActivityViewBlock)complete; + +- (void)hide; +- (void)hideComplete:(MobilyActivityViewBlock)complete; +- (void)hidePrepare:(MobilyActivityViewBlock)prepare complete:(MobilyActivityViewBlock)complete; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyActivityView.m b/Sources/MobilyCore/MobilyActivityView.m new file mode 100644 index 0000000..0d046be --- /dev/null +++ b/Sources/MobilyCore/MobilyActivityView.m @@ -0,0 +1,331 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyActivityView () { +@protected + UIView* _panelView; + MobilySpinnerView* _spinnerView; + UILabel* _textView; + NSUInteger _showCount; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#define MobilyActivityViewMargin 15.0f +#define MobilyActivityViewSpacing 8.0f +#define MobilyActivityViewBackgroundColor [UIColor colorWithWhite:0.1f alpha:0.2f] +#define MobilyActivityViewPanelColor [UIColor colorWithWhite:0.2f alpha:0.8f] +#define MobilyActivityViewPanelCornerRadius 8.0f +#define MobilyActivityViewSpinnerColor [UIColor colorWithWhite:1.0f alpha:0.8f] +#define MobilyActivityViewSpinnerSize 42.0f +#define MobilyActivityViewTextColor [UIColor colorWithWhite:1.0f alpha:0.8f] +#define MobilyActivityViewTextFont [UIFont boldSystemFontOfSize:[UIFont systemFontSize]] +#define MobilyActivityViewTextWidth NSNotFound +#define MobilyActivityDuration 0.1f + +/*--------------------------------------------------*/ + +@implementation MobilyActivityView + +#pragma mark Init / Free + ++ (instancetype)activityViewInView:(UIView*)view style:(MobilyActivityViewStyle)style { + return [[self alloc] initWithInView:view style:style text:nil textWidth:MobilyActivityViewTextWidth]; +} + ++ (instancetype)activityViewInView:(UIView*)view style:(MobilyActivityViewStyle)style text:(NSString*)text { + return [[self alloc] initWithInView:view style:style text:text textWidth:MobilyActivityViewTextWidth]; +} + ++ (instancetype)activityViewInView:(UIView*)view style:(MobilyActivityViewStyle)style text:(NSString*)text textWidth:(NSUInteger)textWidth { + return [[self alloc] initWithInView:view style:style text:text textWidth:textWidth]; +} + +- (instancetype)initWithInView:(UIView*)view style:(MobilyActivityViewStyle)style text:(NSString*)text textWidth:(NSUInteger)textWidth { + self = [super initWithFrame:view.bounds]; + if(self != nil) { + _style = style; + _margin = MobilyActivityViewMargin; + _spacing = MobilyActivityViewSpacing; + _textWidth = textWidth; + + self.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); + self.backgroundColor = MobilyActivityViewBackgroundColor; + self.alpha = 0.0f; + [view addSubview:self]; + + _panelView = [[MobilyBlurView alloc] initWithFrame:CGRectZero]; + _panelView.tintColor = MobilyActivityViewPanelColor; + _panelView.moCornerRadius = MobilyActivityViewPanelCornerRadius; + _panelView.clipsToBounds = YES; + [self addSubview:_panelView]; + + switch(_style) { + case MobilyActivityViewStylePlane: _spinnerView = [[MobilySpinnerViewPlane alloc] initWithFrame:CGRectZero]; break; + case MobilyActivityViewStyleBounce: _spinnerView = [[MobilySpinnerViewBounce alloc] initWithFrame:CGRectZero]; break; + case MobilyActivityViewStyleWave: _spinnerView = [[MobilySpinnerViewWave alloc] initWithFrame:CGRectZero]; break; + case MobilyActivityViewStyleWanderingCubes: _spinnerView = [[MobilySpinnerViewWanderingCubes alloc] initWithFrame:CGRectZero]; break; + case MobilyActivityViewStylePulse: _spinnerView = [[MobilySpinnerViewPulse alloc] initWithFrame:CGRectZero]; break; + case MobilyActivityViewStyleChasingDots: _spinnerView = [[MobilySpinnerViewChasingDots alloc] initWithFrame:CGRectZero]; break; + case MobilyActivityViewStyleThreeBounce: _spinnerView = [[MobilySpinnerViewThreeBounce alloc] initWithFrame:CGRectZero]; break; + case MobilyActivityViewStyleCircle: _spinnerView = [[MobilySpinnerViewCircle alloc] initWithFrame:CGRectZero]; break; + case MobilyActivityViewStyleCircleFlip: _spinnerView = [[MobilySpinnerViewCircleFlip alloc] initWithFrame:CGRectZero]; break; + case MobilyActivityViewStyle9CubeGrid: _spinnerView = [[MobilySpinnerView9CubeGrid alloc] initWithFrame:CGRectZero]; break; + case MobilyActivityViewStyleWordPress: _spinnerView = [[MobilySpinnerViewWordPress alloc] initWithFrame:CGRectZero]; break; + case MobilyActivityViewStyleFadingCircle: _spinnerView = [[MobilySpinnerViewFadingCircle alloc] initWithFrame:CGRectZero]; break; + case MobilyActivityViewStyleFadingCircleAlt: _spinnerView = [[MobilySpinnerViewFadingCircleAlt alloc] initWithFrame:CGRectZero]; break; + case MobilyActivityViewStyleArc: _spinnerView = [[MobilySpinnerViewArc alloc] initWithFrame:CGRectZero]; break; + case MobilyActivityViewStyleArcAlt: _spinnerView = [[MobilySpinnerViewArcAlt alloc] initWithFrame:CGRectZero]; break; + default: break; + } + if(_spinnerView != nil) { + _spinnerView.color = MobilyActivityViewSpinnerColor; + _spinnerView.size = MobilyActivityViewSpinnerSize; + [_panelView addSubview:_spinnerView]; + } + _textView = [[UILabel alloc] initWithFrame:CGRectZero]; + _textView.backgroundColor = [UIColor clearColor]; + _textView.textColor = MobilyActivityViewTextColor; + _textView.font = MobilyActivityViewTextFont; + _textView.textAlignment = NSTextAlignmentCenter; + _textView.numberOfLines = 0; + _textView.text = text; + [_panelView addSubview:_textView]; + + _showCount = NSNotFound; + + [self setup]; + } + return self; +} + +- (void)setup { +} + +#pragma mark Public override + +- (void)layoutSubviews { + [super layoutSubviews]; + + CGSize spinnerSize = CGSizeMake(self.spinnerSize, self.spinnerSize); + CGSize textSize = [_textView moImplicitSizeForWidth:_textWidth]; + CGSize panelSize = CGSizeMake(_margin + MAX(spinnerSize.width, textSize.width) + _margin, _margin + spinnerSize.height + ((_textView.text.length > 0) ? _spacing + textSize.height : 0.0f) + _margin); + CGFloat spinnerOffset = floorf((panelSize.width - spinnerSize.width) * 0.5f); + + _panelView.frame = MobilyRectMakeCenterPoint(self.moFrameCenter, panelSize.width, panelSize.height); + _spinnerView.frame = CGRectMake(spinnerOffset, _margin, spinnerSize.width, spinnerSize.height); + _textView.frame = CGRectMake(_margin, _margin + spinnerSize.height + _spacing, textSize.width, textSize.height); +} + +#pragma mark Property + +- (void)setMargin:(CGFloat)margin { + if(_margin != margin) { + _margin = margin; + [self setNeedsLayout]; + } +} + +- (void)setSpacing:(CGFloat)spacing { + if(_spacing != spacing) { + _spacing = spacing; + [self setNeedsLayout]; + } +} + +- (void)setPanelColor:(UIColor*)panelColor { + if([_panelView.backgroundColor isEqual:panelColor] == NO) { + _panelView.backgroundColor = panelColor; + [self setNeedsLayout]; + } +} + +- (UIColor*)panelColor { + return _panelView.backgroundColor; +} + +- (void)setPanelCornerRadius:(CGFloat)panelCornerRadius { + if(_panelView.moCornerRadius != panelCornerRadius) { + _panelView.moCornerRadius = panelCornerRadius; + [self setNeedsLayout]; + } +} + +- (CGFloat)panelCornerRadius { + return _panelView.moCornerRadius; +} + +- (void)setSpinnerColor:(UIColor*)spinnerColor { + if([_spinnerView.color isEqual:spinnerColor] == NO) { + _spinnerView.color = spinnerColor; + [self setNeedsLayout]; + } +} + +- (UIColor*)spinnerColor { + return _spinnerView.color; +} + +- (void)setSpinnerSize:(CGFloat)spinnerSize { + if(_spinnerView.size != spinnerSize) { + _spinnerView.size = spinnerSize; + [self setNeedsLayout]; + } +} + +- (CGFloat)spinnerSize { + return _spinnerView.size; +} + +- (void)setTextColor:(UIColor*)textColor { + if([_textView.textColor isEqual:textColor] == NO) { + _textView.textColor = textColor; + [self setNeedsLayout]; + } +} + +- (UIColor*)textColor { + return _textView.textColor; +} + +- (void)setText:(NSString*)text { + if([_textView.text isEqualToString:text] == NO) { + _textView.text = text; + [self setNeedsLayout]; + } +} + +- (NSString*)text { + return _textView.text; +} + +- (void)setTextFont:(UIFont*)textFont { + if([_textView.font isEqual:textFont] == NO) { + _textView.font = textFont; + [self setNeedsLayout]; + } +} + +- (UIFont*)textFont { + return _textView.font; +} + +- (BOOL)isShowed { + return (_showCount != NSNotFound) && (_showCount > 0); +} + +#pragma mark Public + +- (void)show { + [self showPrepare:nil complete:nil]; +} + +- (void)showComplete:(MobilyActivityViewBlock)complete { + [self showPrepare:nil complete:complete]; +} + +- (void)showPrepare:(MobilyActivityViewBlock)prepare complete:(MobilyActivityViewBlock)complete { + if(_showCount == NSNotFound) { + _showCount = 1; + [_spinnerView startAnimating]; + [self layoutIfNeeded]; + [UIView animateWithDuration:MobilyActivityDuration + delay:0.1f + options:(UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionBeginFromCurrentState) + animations:^{ + if(prepare != nil) { + prepare(); + [self layoutIfNeeded]; + } + _panelView.alpha = 1.0f; + self.alpha = 1.0f; + } completion:^(BOOL finished) { + if(complete != nil) { + complete(); + } + }]; + } else if(_showCount != NSNotFound) { + _showCount++; + } +} + +- (void)hide { + [self hidePrepare:nil complete:nil]; +} + +- (void)hideComplete:(MobilyActivityViewBlock)complete { + [self hidePrepare:nil complete:complete]; +} + +- (void)hidePrepare:(MobilyActivityViewBlock)prepare complete:(MobilyActivityViewBlock)complete { + if(_showCount == 1) { + _showCount = NSNotFound; + [self layoutIfNeeded]; + [UIView animateWithDuration:MobilyActivityDuration + delay:0.1f + options:(UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionBeginFromCurrentState) + animations:^{ + if(prepare != nil) { + prepare(); + [self layoutIfNeeded]; + } + _panelView.alpha = 0.0f; + self.alpha = 0.0f; + } completion:^(BOOL finished __unused) { + [_spinnerView stopAnimating]; + if(complete != nil) { + complete(); + } + }]; + } else if(_showCount != NSNotFound) { + _showCount--; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/ViewFieldDate/MobilyViewFieldDate.h b/Sources/MobilyCore/MobilyApiManager.h similarity index 72% rename from Classes/UI/ViewFieldDate/MobilyViewFieldDate.h rename to Sources/MobilyCore/MobilyApiManager.h index 219a78c..b8f17ea 100644 --- a/Classes/UI/ViewFieldDate/MobilyViewFieldDate.h +++ b/Sources/MobilyCore/MobilyApiManager.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,22 +33,30 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyViewFieldText.h" +#import +#import /*--------------------------------------------------*/ -@interface MobilyViewFieldDate : MobilyViewFieldText< MobilyBuilderObject > +@class MobilyApiProvider; +@class MobilyApiRequest; +@class MobilyApiResponse; -@property(nonatomic, readwrite, assign) UIDatePickerMode datePickerMode; -@property(nonatomic, readwrite, strong) NSDateFormatter* dateFormatter; -@property(nonatomic, readwrite, strong) NSLocale* locale; -@property(nonatomic, readwrite, copy) NSCalendar* calendar; -@property(nonatomic, readwrite, strong) NSTimeZone* timeZone; -@property(nonatomic, readwrite, strong) NSDate* minimumDate; -@property(nonatomic, readwrite, strong) NSDate* maximumDate; -@property(nonatomic, readwrite, strong) NSDate* date; +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyApiManager : NSObject < MobilyObject > + +@property(nonatomic, readonly, copy) NSArray* providers; +@property(nonatomic, readwrite, strong) MobilyTaskManager* taskManager; +@property(nonatomic, readwrite, strong) MobilyCache* cache; + ++ (instancetype)shared; + +- (void)setup NS_REQUIRES_SUPER; -- (void)setDate:(NSDate*)date animated:(BOOL)animated; +- (void)registerProvider:(MobilyApiProvider*)provider; +- (void)unregisterProvider:(MobilyApiProvider*)provider; @end diff --git a/Sources/MobilyCore/MobilyApiManager.m b/Sources/MobilyCore/MobilyApiManager.m new file mode 100644 index 0000000..7aebe71 --- /dev/null +++ b/Sources/MobilyCore/MobilyApiManager.m @@ -0,0 +1,123 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyApiManager () { +@protected + NSMutableArray* _providers; + MobilyTaskManager* _taskManager; + MobilyCache* _cache; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#define MOBILY_API_MANAGER_MAX_CONCURRENT_TASK 5 + +/*--------------------------------------------------*/ + +@implementation MobilyApiManager + +#pragma mark Synthesize + +@synthesize taskManager = _taskManager; +@synthesize cache = _cache; + +#pragma mark Singleton + ++ (instancetype)shared { + static id shared = nil; + if(shared == nil) { + @synchronized(self) { + if(shared == nil) { + shared = [self new]; + } + } + } + return shared; +} + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + _taskManager = [MobilyTaskManager new]; + if(_taskManager != nil) { + _taskManager.maxConcurrentTask = MOBILY_API_MANAGER_MAX_CONCURRENT_TASK; + } + _cache = MobilyCache.shared; + [self setup]; + } + return self; +} + +- (void)setup { +} + +#pragma mark Property + +- (NSArray*)providers { + return [_providers copy]; +} + +#pragma mark Public + +- (void)registerProvider:(MobilyApiProvider*)provider { + if([_providers containsObject:provider] == NO) { + [_providers addObject:provider]; + provider.manager = self; + } +} + +- (void)unregisterProvider:(MobilyApiProvider*)provider { + if([_providers containsObject:provider] == YES) { + [_providers removeObject:provider]; + provider.manager = nil; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/ViewImage/MobilyViewImage.h b/Sources/MobilyCore/MobilyApiProvider.h similarity index 63% rename from Classes/UI/ViewImage/MobilyViewImage.h rename to Sources/MobilyCore/MobilyApiProvider.h index 4c81f41..8d448d2 100644 --- a/Classes/UI/ViewImage/MobilyViewImage.h +++ b/Sources/MobilyCore/MobilyApiProvider.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,39 +33,39 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyBuilder.h" +#import /*--------------------------------------------------*/ -typedef void (^MobilyImageLoaderCompleteBlock)(UIImage* image, NSString* imageUrl); -typedef void (^MobilyImageLoaderFailureBlock)(NSString* imageUrl); +@class MobilyApiRequest; +@class MobilyApiResponse; /*--------------------------------------------------*/ -@interface MobilyViewImage : UIImageView< MobilyBuilderObject > +typedef void (^MobilyApiProviderCompleteBlock)(id request, id response); -@property(nonatomic, readwrite, strong) UIImage* defaultImage; -@property(nonatomic, readwrite, strong) NSString* imageUrl; - -- (void)setupView; +/*--------------------------------------------------*/ -- (void)setImageUrl:(NSString*)imageUrl complete:(MobilyImageLoaderCompleteBlock)complete failure:(MobilyImageLoaderFailureBlock)failure; +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyApiProvider : NSObject < MobilyObject > -@end +@property(nonatomic, readwrite, weak) MobilyApiManager* manager; +@property(nonatomic, readwrite, strong) MobilyTaskManager* taskManager; +@property(nonatomic, readwrite, strong) MobilyCache* cache; -/*--------------------------------------------------*/ +@property(nonatomic, readonly, strong) NSString* name; +@property(nonatomic, readonly, strong) NSURL* url; +@property(nonatomic, readonly, strong) NSDictionary* headers; -@interface MobilyImageLoader : NSObject +- (instancetype)initWithName:(NSString*)name url:(NSURL*)url; +- (instancetype)initWithName:(NSString*)name url:(NSURL*)url headers:(NSDictionary*)headers; -+ (BOOL)isExistImageWithImageUrl:(NSString*)imageUrl; -+ (UIImage*)imageWithImageUrl:(NSString*)imageUrl; -+ (void)removeByImageUrl:(NSString*)imageUrl; -+ (void)cleanup; +- (void)setup NS_REQUIRES_SUPER; -+ (void)loadWithImageUrl:(NSString*)imageUrl target:(id)target completeSelector:(SEL)completeSelector failureSelector:(SEL)failureSelector; -+ (void)loadWithImageUrl:(NSString*)imageUrl target:(id)target completeBlock:(MobilyImageLoaderCompleteBlock)completeBlock failureBlock:(MobilyImageLoaderFailureBlock)failureBlock; -+ (void)cancelByImageUrl:(NSString*)imageUrl; -+ (void)cancelByTarget:(id)target; +- (void)sendRequest:(MobilyApiRequest*)request byTarget:(id)target completeSelector:(SEL)completeSelector; +- (void)sendRequest:(MobilyApiRequest*)request byTarget:(id)target completeBlock:(MobilyApiProviderCompleteBlock)completeBlock; +- (void)cancelByRequest:(MobilyApiRequest*)request; +- (void)cancelByTarget:(id)target; @end diff --git a/Sources/MobilyCore/MobilyApiProvider.m b/Sources/MobilyCore/MobilyApiProvider.m new file mode 100644 index 0000000..a47c044 --- /dev/null +++ b/Sources/MobilyCore/MobilyApiProvider.m @@ -0,0 +1,251 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import +#import +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyApiProvider () { +@protected + __weak MobilyApiManager* _manager; + MobilyTaskManager* _taskManager; + MobilyCache* _cache; + NSString* _name; + NSURL* _url; + NSDictionary* _headers; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyApiProviderTask : MobilyTaskHttpQuery + +@property(nonatomic, readwrite, weak) MobilyApiProvider* provider; +@property(nonatomic, readwrite, strong) MobilyApiRequest* request; +@property(nonatomic, readwrite, strong) MobilyApiResponse* response; +@property(nonatomic, readwrite, strong) id target; +@property(nonatomic, readwrite, strong) id< MobilyEvent > completeEvent; +@property(nonatomic, readwrite, assign) NSUInteger numberOfErrors; + +- (instancetype)initWithProvider:(MobilyApiProvider*)provider request:(MobilyApiRequest*)request target:(id)target; +- (instancetype)initWithProvider:(MobilyApiProvider*)provider request:(MobilyApiRequest*)request target:(id)target completeSelector:(SEL)completeSelector; +- (instancetype)initWithProvider:(MobilyApiProvider*)provider request:(MobilyApiRequest*)request target:(id)target completeBlock:(MobilyApiProviderCompleteBlock)completeBlock; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyApiProvider + +#pragma mark Synthesize + +@synthesize manager = _manager; +@synthesize taskManager = _taskManager; +@synthesize cache = _cache; +@synthesize name = _name; +@synthesize url = _url; +@synthesize headers = _headers; + +#pragma mark Init / Free + +- (instancetype)initWithName:(NSString*)name url:(NSURL*)url { + self = [super init]; + if(self != nil) { + _name = name; + _url = url; + [self setup]; + } + return self; +} + +- (instancetype)initWithName:(NSString*)name url:(NSURL*)url headers:(NSDictionary*)headers { + self = [super init]; + if(self != nil) { + _name = name; + _url = url; + _headers = headers; + [self setup]; + } + return self; +} + +- (void)setup { +} + +#pragma mark Property + +- (void)setManager:(MobilyApiManager*)manager { + if(_manager != manager) { + if(_manager != nil) { + [_manager unregisterProvider:self]; + } + _manager = manager; + if(_manager != nil) { + if(_taskManager == nil) { + _taskManager = _manager.taskManager; + } + if(_cache == nil) { + _cache = _manager.cache; + } + [_manager registerProvider:self]; + } + } +} + +#pragma mark Public + +- (void)sendRequest:(MobilyApiRequest*)request byTarget:(id)target completeSelector:(SEL)completeSelector { + [_taskManager addTask:[[MobilyApiProviderTask alloc] initWithProvider:self request:request target:target completeSelector:completeSelector]]; +} + +- (void)sendRequest:(MobilyApiRequest*)request byTarget:(id)target completeBlock:(MobilyApiProviderCompleteBlock)completeBlock { + [_taskManager addTask:[[MobilyApiProviderTask alloc] initWithProvider:self request:request target:target completeBlock:completeBlock]]; +} + +- (void)cancelByRequest:(MobilyApiRequest*)request { + [_taskManager enumirateTasksUsingBlock:^(MobilyApiProviderTask* task, BOOL* stop __unused) { + if([task.request isEqual:request] == YES) { + [task cancel]; + } + }]; +} + +- (void)cancelByTarget:(id)target { + [_taskManager enumirateTasksUsingBlock:^(MobilyApiProviderTask* task, BOOL* stop __unused) { + if(task.target == target) { + [task cancel]; + } + }]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyApiProviderTask + +#pragma mark Synthesize + +@synthesize provider = _provider; +@synthesize request = _request; +@synthesize response = _response; +@synthesize target = _target; +@synthesize completeEvent = _completeEvent; +@synthesize numberOfErrors = _numberOfErrors; + +#pragma mark Init / Free + +- (instancetype)initWithProvider:(MobilyApiProvider*)provider request:(MobilyApiRequest*)request target:(id)target { + self = [super init]; + if(self != nil) { + _provider = provider; + _request = request; + _target = target; + } + return self; +} + +- (instancetype)initWithProvider:(MobilyApiProvider*)provider request:(MobilyApiRequest*)request target:(id)target completeSelector:(SEL)completeSelector { + self = [self initWithProvider:provider request:request target:target]; + if(self != nil) { + _completeEvent = [MobilyEventSelector eventWithTarget:target action:completeSelector inMainThread:YES]; + } + return self; +} + +- (instancetype)initWithProvider:(MobilyApiProvider*)provider request:(MobilyApiRequest*)request target:(id)target completeBlock:(MobilyApiProviderCompleteBlock)completeBlock { + self = [self initWithProvider:provider request:request target:target]; + if(self != nil) { + _completeEvent = [MobilyEventBlock eventWithBlock:^id(id sender, id object) { + if(completeBlock != nil) { + completeBlock(sender, object); + } + return nil; + } inMainQueue:YES]; + } + return self; +} + +- (void)dealloc { + _target = nil; + _completeEvent = nil; +} + +#pragma mark MobilyTaskHttpQuery + +- (BOOL)willStart { + _httpQuery = [_request httpQueryByBaseUrl:_provider.url baseHeaders:_provider.headers]; + return [super willStart]; +} + +- (void)working { + [super working]; + + _response = [_request responseByHttpQuery:self.httpQuery]; + if(_response.isValidResponse == NO) { + if(_request.numberOfRetries == NSNotFound) { + [self setNeedRework]; + } else { + if(_numberOfErrors != _request.numberOfRetries) { + _numberOfErrors = _numberOfErrors + 1; + [self setNeedRework]; + } + } + } +} + +- (void)didComplete { + [super didComplete]; + + [_completeEvent fireSender:_request object:_response]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyApiRequest.h b/Sources/MobilyCore/MobilyApiRequest.h new file mode 100644 index 0000000..96565fb --- /dev/null +++ b/Sources/MobilyCore/MobilyApiRequest.h @@ -0,0 +1,88 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@class MobilyApiResponse; +@class MobilyHttpQuery; + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyApiRequest : MobilyModel + +@property(nonatomic, readwrite, strong) NSString* method; +@property(nonatomic, readwrite, strong) NSString* relativeUrl; +@property(nonatomic, readwrite, strong) NSDictionary* urlParams; +@property(nonatomic, readwrite, strong) NSDictionary* headers; +@property(nonatomic, readwrite, strong) NSDictionary* bodyParams; +@property(nonatomic, readwrite, strong) NSData* body; +@property(nonatomic, readwrite, strong) NSArray* attachments; +@property(nonatomic, readwrite, assign) NSUInteger numberOfRetries; +@property(nonatomic, readwrite, assign) BOOL allowInvalidCertificates; +@property(nonatomic, readwrite, assign) BOOL encodePostParamKey; +@property(nonatomic, readwrite, assign) BOOL encodePostParamValue; + +- (instancetype)initWithGetRelativeUrl:(NSString*)relativeUrl; +- (instancetype)initWithGetRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams; +- (instancetype)initWithGetRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams numberOfRetries:(NSUInteger)numberOfRetries; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl bodyParams:(NSDictionary*)bodyParams; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl bodyParams:(NSDictionary*)bodyParams numberOfRetries:(NSUInteger)numberOfRetries; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments numberOfRetries:(NSUInteger)numberOfRetries; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams numberOfRetries:(NSUInteger)numberOfRetries; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments numberOfRetries:(NSUInteger)numberOfRetries; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams bodyParams:(NSDictionary*)bodyParams; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams bodyParams:(NSDictionary*)bodyParams numberOfRetries:(NSUInteger)numberOfRetries; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments numberOfRetries:(NSUInteger)numberOfRetries; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams numberOfRetries:(NSUInteger)numberOfRetries; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments; +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments numberOfRetries:(NSUInteger)numberOfRetries; +- (instancetype)initWithMethod:(NSString*)method relativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments numberOfRetries:(NSUInteger)numberOfRetries; +- (instancetype)initWithMethod:(NSString*)method relativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams headers:(NSDictionary*)headers body:(NSData*)body attachments:(NSArray*)attachments numberOfRetries:(NSUInteger)numberOfRetries; + +- (MobilyHttpQuery*)httpQueryByBaseUrl:(NSURL*)baseUrl baseHeaders:(NSDictionary*)baseHeaders; +- (MobilyApiResponse*)responseByHttpQuery:(MobilyHttpQuery*)httpQuery; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyApiRequest.m b/Sources/MobilyCore/MobilyApiRequest.m new file mode 100644 index 0000000..7deb51c --- /dev/null +++ b/Sources/MobilyCore/MobilyApiRequest.m @@ -0,0 +1,304 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyApiRequest () { + NSString* _method; + NSString* _relativeUrl; + NSDictionary* _urlParams; + NSDictionary* _headers; + NSDictionary* _bodyParams; + NSData* _body; + NSArray* _attachments; + NSUInteger _numberOfRetries; + BOOL _allowInvalidCertificates; + BOOL _encodePostParamKey; + BOOL _encodePostParamValue; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyApiRequest + +#pragma mark MobilyModel + +@synthesize method = _method; +@synthesize relativeUrl = _relativeUrl; +@synthesize urlParams = _urlParams; +@synthesize headers = _headers; +@synthesize bodyParams = _bodyParams; +@synthesize body = _body; +@synthesize attachments = _attachments; +@synthesize numberOfRetries = _numberOfRetries; +@synthesize allowInvalidCertificates = _allowInvalidCertificates; +@synthesize encodePostParamKey = _encodePostParamKey; +@synthesize encodePostParamValue = _encodePostParamValue; + +#pragma mark MobilyModel + ++ (NSArray*)compareMap { + return @[ + @"method", + @"relativeUrl", + @"urlParams", + @"headers", + @"bodyParams", + @"body", + @"attachments", + @"allowInvalidCertificates" + ]; +} + ++ (NSArray*)serializeMap { + return @[ + @"method", + @"relativeUrl", + @"urlParams", + @"headers", + @"bodyParams", + @"body", + @"attachments", + @"numberOfRetries", + @"allowInvalidCertificates" + ]; +} + +#pragma mark Init / Free + +- (instancetype)initWithGetRelativeUrl:(NSString*)relativeUrl { + return [self initWithMethod:@"GET" relativeUrl:relativeUrl urlParams:nil headers:nil bodyParams:nil attachments:nil numberOfRetries:0]; +} + +- (instancetype)initWithGetRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams { + return [self initWithMethod:@"GET" relativeUrl:relativeUrl urlParams:urlParams headers:nil bodyParams:nil attachments:nil numberOfRetries:0]; +} + +- (instancetype)initWithGetRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams numberOfRetries:(NSUInteger)numberOfRetries { + return [self initWithMethod:@"GET" relativeUrl:relativeUrl urlParams:urlParams headers:nil bodyParams:nil attachments:nil numberOfRetries:numberOfRetries]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl bodyParams:(NSDictionary*)bodyParams { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:nil headers:nil bodyParams:bodyParams attachments:nil numberOfRetries:0]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl bodyParams:(NSDictionary*)bodyParams numberOfRetries:(NSUInteger)numberOfRetries { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:nil headers:nil bodyParams:bodyParams attachments:nil numberOfRetries:numberOfRetries]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:nil headers:nil bodyParams:bodyParams attachments:attachments numberOfRetries:0]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments numberOfRetries:(NSUInteger)numberOfRetries { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:nil headers:nil bodyParams:bodyParams attachments:attachments numberOfRetries:numberOfRetries]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:nil headers:headers bodyParams:bodyParams attachments:nil numberOfRetries:0]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams numberOfRetries:(NSUInteger)numberOfRetries { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:nil headers:headers bodyParams:bodyParams attachments:nil numberOfRetries:numberOfRetries]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:nil headers:headers bodyParams:bodyParams attachments:attachments numberOfRetries:0]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments numberOfRetries:(NSUInteger)numberOfRetries { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:nil headers:headers bodyParams:bodyParams attachments:attachments numberOfRetries:numberOfRetries]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams bodyParams:(NSDictionary*)bodyParams { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:urlParams headers:nil bodyParams:bodyParams attachments:nil numberOfRetries:0]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams bodyParams:(NSDictionary*)bodyParams numberOfRetries:(NSUInteger)numberOfRetries { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:urlParams headers:nil bodyParams:bodyParams attachments:nil numberOfRetries:numberOfRetries]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:urlParams headers:nil bodyParams:bodyParams attachments:attachments numberOfRetries:0]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments numberOfRetries:(NSUInteger)numberOfRetries { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:urlParams headers:nil bodyParams:bodyParams attachments:attachments numberOfRetries:numberOfRetries]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:urlParams headers:headers bodyParams:bodyParams attachments:nil numberOfRetries:0]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams numberOfRetries:(NSUInteger)numberOfRetries { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:urlParams headers:headers bodyParams:bodyParams attachments:nil numberOfRetries:numberOfRetries]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:urlParams headers:headers bodyParams:bodyParams attachments:attachments numberOfRetries:0]; +} + +- (instancetype)initWithPostRelativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments numberOfRetries:(NSUInteger)numberOfRetries { + return [self initWithMethod:@"POST" relativeUrl:relativeUrl urlParams:urlParams headers:headers bodyParams:bodyParams attachments:attachments numberOfRetries:numberOfRetries]; +} + +- (instancetype)initWithMethod:(NSString*)method relativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams headers:(NSDictionary*)headers bodyParams:(NSDictionary*)bodyParams attachments:(NSArray*)attachments numberOfRetries:(NSUInteger)numberOfRetries { + self = [super init]; + if(self != nil) { + _method = method; + _relativeUrl = relativeUrl; + _urlParams = urlParams; + _headers = headers; + _bodyParams = bodyParams; + _attachments = attachments; + _numberOfRetries = numberOfRetries; + _encodePostParamKey = YES; + _encodePostParamValue = YES; + } + return self; +} + +- (instancetype)initWithMethod:(NSString*)method relativeUrl:(NSString*)relativeUrl urlParams:(NSDictionary*)urlParams headers:(NSDictionary*)headers body:(NSData*)body attachments:(NSArray*)attachments numberOfRetries:(NSUInteger)numberOfRetries { + self = [super init]; + if(self != nil) { + _method = method; + _relativeUrl = relativeUrl; + _urlParams = urlParams; + _headers = headers; + _body = body; + _attachments = attachments; + _numberOfRetries = numberOfRetries; + _encodePostParamKey = YES; + _encodePostParamValue = YES; + } + return self; +} + +#pragma mark Debug + +- (NSString*)description { + NSMutableArray* result = NSMutableArray.array; + [result addObject:[NSMutableString stringWithFormat:@"Method = \"%@\";", _method]]; + if(_relativeUrl.length > 0) { + [result addObject:[NSMutableString stringWithFormat:@"RelativeURL = \"%@\";", _relativeUrl]]; + } + if(_urlParams.count > 0) { + NSMutableArray* temp = NSMutableArray.array; + [_urlParams moEach:^(id key, id value) { + [temp addObject:[NSString stringWithFormat:@"\"%@\" = \"%@\";", [key description], [value description]]]; + }]; + [result addObject:[NSString stringWithFormat:@"UrlParams [%@]", [temp componentsJoinedByString:@", "]]]; + } + if(_headers.count > 0) { + NSMutableArray* temp = NSMutableArray.array; + [_headers moEach:^(id key, id value) { + [temp addObject:[NSString stringWithFormat:@"\t\"%@\" = \"%@\";", [key description], [value description]]]; + }]; + [result addObject:[NSString stringWithFormat:@"Headers [%@];", [temp componentsJoinedByString:@", "]]]; + } + if(_bodyParams.count > 0) { + NSMutableArray* temp = NSMutableArray.array; + [_bodyParams moEach:^(id key, id value) { + [temp addObject:[NSString stringWithFormat:@"\t\"%@\" = \"%@\";", [key description], [value description]]]; + }]; + [result addObject:[NSString stringWithFormat:@"BodyParams [%@];", [temp componentsJoinedByString:@", "]]]; + } + if(_attachments.count > 0) { + NSMutableArray* temp = NSMutableArray.array; + for(MobilyHttpAttachment* attachment in _attachments) { + [temp addObject:[attachment description]]; + } + [result addObject:[NSString stringWithFormat:@"Attachments [%@];", [temp componentsJoinedByString:@", "]]]; + } + [result addObject:[NSString stringWithFormat:@"AllowInvalidCertificates %@;", @(_allowInvalidCertificates)]]; + return [result componentsJoinedByString:@", "]; +} + +#pragma mark Public + +- (MobilyHttpQuery*)httpQueryByBaseUrl:(NSURL*)baseUrl baseHeaders:(NSDictionary*)baseHeaders { + MobilyHttpQuery* httpQuery = [MobilyHttpQuery new]; + if(_method.length > 0) { + httpQuery.requestMethod = _method; + } + if(_relativeUrl.length > 0) { + NSMutableString* mutableBaseUrl = [NSMutableString stringWithString:baseUrl.absoluteString]; + if([mutableBaseUrl characterAtIndex:mutableBaseUrl.length - 1] != '/') { + [mutableBaseUrl appendFormat:@"/%@", _relativeUrl]; + } else { + [mutableBaseUrl appendString:_relativeUrl]; + } + httpQuery.requestUrl = [NSURL URLWithString:mutableBaseUrl]; + } else { + httpQuery.requestUrl = baseUrl; + } + if(_urlParams.count > 0) { + httpQuery.requestUrlParams = _urlParams; + } + if(_attachments.count > 0) { + [httpQuery setRequestBodyParams:_bodyParams encodeParamKey:_encodePostParamKey encodeParamValue:_encodePostParamValue boundary:@"MobilyBoundary" attachments:_attachments]; + } else if(_bodyParams.count > 0) { + [httpQuery setRequestBodyParams:_bodyParams encodeParamKey:_encodePostParamKey encodeParamValue:_encodePostParamValue]; + } else if(_body.length > 0) { + [httpQuery setRequestBody:_body]; + } + if(baseHeaders.count > 0) { + [httpQuery addRequestHeaders:baseHeaders]; + } + if(_headers.count > 0) { + [httpQuery addRequestHeaders:_headers]; + } + httpQuery.allowInvalidCertificates = _allowInvalidCertificates; + httpQuery.requestTimeout = 15.0f; + return httpQuery; +} + +- (MobilyApiResponse*)responseByHttpQuery:(MobilyHttpQuery*)httpQuery { + return [[MobilyApiResponse alloc] initWithHttpQuery:httpQuery]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyApiResponse.h b/Sources/MobilyCore/MobilyApiResponse.h new file mode 100644 index 0000000..45d64f5 --- /dev/null +++ b/Sources/MobilyCore/MobilyApiResponse.h @@ -0,0 +1,57 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@class MobilyHttpQuery; + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyApiResponse : MobilyModel + +@property(nonatomic, readwrite, strong) NSError* httpError; +@property(nonatomic, readwrite, assign, getter=isValidResponse) BOOL validResponse; + +- (instancetype)initWithHttpQuery:(MobilyHttpQuery*)httpQuery; + +- (BOOL)fromHttpQuery:(MobilyHttpQuery*)httpQuery; + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyTransitionController.h b/Sources/MobilyCore/MobilyApiResponse.m similarity index 62% rename from Classes/UI/Core/MobilyTransitionController.h rename to Sources/MobilyCore/MobilyApiResponse.m index 14c7e93..8a2175b 100644 --- a/Classes/UI/Core/MobilyTransitionController.h +++ b/Sources/MobilyCore/MobilyApiResponse.m @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -32,54 +32,62 @@ /* OTHER DEALINGS IN THE SOFTWARE. */ /* */ /*--------------------------------------------------*/ - -#import "MobilyBuilder.h" - +#define MOBILY_SOURCE /*--------------------------------------------------*/ -@class MobilyTransitionController; +#import /*--------------------------------------------------*/ -@interface NSString (MobilyTransitionController) - -- (MobilyTransitionController*)convertToTransitionController; +@interface MobilyApiResponse () { + NSError* _httpError; + BOOL _validResponse; +} @end /*--------------------------------------------------*/ - -@interface MobilyTransitionController : NSObject < UIViewControllerAnimatedTransitioning > - -@property(nonatomic, readwrite, assign) NSTimeInterval duration; -@property(nonatomic, readwrite, assign, getter=isReverse) BOOL reverse; - -- (void)setupTransitionController; - -- (void)animateTransition:(id< UIViewControllerContextTransitioning >)transitionContext fromVC:(UIViewController*)fromVC toVC:(UIViewController*)toVC fromView:(UIView*)fromView toView:(UIView*)toView; - -@end - +#pragma mark - /*--------------------------------------------------*/ -@interface MobilyTransitionControllerCrossFade : MobilyTransitionController +@implementation MobilyApiResponse -@end +#pragma mark Synthesize -/*--------------------------------------------------*/ +@synthesize httpError = _httpError; +@synthesize validResponse = _validResponse; -@interface MobilyTransitionControllerCards : MobilyTransitionController +#pragma mark Init / Free -@end +- (instancetype)initWithHttpQuery:(MobilyHttpQuery*)httpQuery { + self = [super init]; + if(self != nil) { + _validResponse = [self fromHttpQuery:httpQuery]; + } + return self; +} -/*--------------------------------------------------*/ +- (void)dealloc { +} -#define MOBILY_DEFINE_VALIDATE_TRANSITION_CONTROLLER(name) \ -- (BOOL)validate##name:(inout id*)value error:(out NSError**)error { \ - if([*value isKindOfClass:[NSString class]] == YES) { \ - *value = [*value convertToTransitionController]; \ - } \ - return [*value isKindOfClass:[MobilyTransitionController class]]; \ +#pragma mark Public + +- (BOOL)fromHttpQuery:(MobilyHttpQuery*)httpQuery { + if(httpQuery.error == nil) { + NSString* responseMimeType = httpQuery.responseMimeType; + if(([responseMimeType isEqualToString:@"application/json"] == YES) || ([responseMimeType isEqualToString:@"text/json"] == YES) || ([responseMimeType isEqualToString:@"text/html"] == YES)) { + id json = httpQuery.responseJson; + if(json != nil) { + [self fromJson:json]; + return YES; + } + } + } else { + self.httpError = httpQuery.error; + } + return NO; } +@end + /*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyApplication.h b/Sources/MobilyCore/MobilyApplication.h new file mode 100644 index 0000000..e66b50c --- /dev/null +++ b/Sources/MobilyCore/MobilyApplication.h @@ -0,0 +1,115 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef NS_OPTIONS(NSUInteger, MobilyApplicationNotificationType) { + MobilyApplicationNotificationTypeNone = 0, + MobilyApplicationNotificationTypeBadge = 1 << 0, + MobilyApplicationNotificationTypeSound = 1 << 1, + MobilyApplicationNotificationTypeAlert = 1 << 2, +}; + +/*--------------------------------------------------*/ + +@interface MobilyApplication : NSObject < MobilyBuilderObject > + +@property(nonatomic, readonly, assign) MobilyApplicationNotificationType notificationType; +@property(nonatomic, readonly, strong) NSArray* notificationCategories; +@property(nonatomic, readonly, assign) UIApplicationState state; +@property(nonatomic, readonly, strong) NSData* deviceToken; + +- (void)setup NS_REQUIRES_SUPER; + +- (BOOL)launchingWithOptions:(NSDictionary*)options; +- (void)terminate; +- (void)receiveMemoryWarning; +- (void)becomeActive; +- (void)resignActive; +- (void)enterForeground; +- (void)enterBackground; +- (void)registerUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings; +- (void)registerForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken; +- (void)failToRegisterForRemoteNotificationsWithError:(NSError*)error; +- (void)receiveRemoteNotification:(NSDictionary*)notification; +- (void)receiveLocalNotification:(UILocalNotification*)notification; +- (void)handleActionWithIdentifier:(NSString*)identifier forLocalNotification:(UILocalNotification*)notification completionHandler:(void(^)())completionHandler; +- (void)handleActionWithIdentifier:(NSString*)identifier forRemoteNotification:(NSDictionary*)notification completionHandler:(void(^)())completionHandler; +- (void)handleEventsForBackgroundURLSession:(NSString*)identifier completionHandler:(void(^)())completionHandler; +- (void)handleWatchKitExtensionRequest:(NSDictionary*)userInfo reply:(void(^)(NSDictionary* replyInfo))reply; + +- (BOOL)openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyApplicationNotificationCategory : NSObject < MobilyBuilderObject > + +@property(nonatomic, readonly, strong) NSString* identifier; +@property(nonatomic, readonly, strong) NSArray* actions; + +- (void)setup NS_REQUIRES_SUPER; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyApplicationNotificationAction : NSObject < MobilyBuilderObject > + +@property(nonatomic, readonly, strong) NSString* identifier; +@property(nonatomic, readonly, strong) NSString* title; +@property(nonatomic, readonly, assign) UIUserNotificationActivationMode activationMode; +@property(nonatomic, readonly, assign, getter=isAuthenticationRequired) BOOL authenticationRequired; +@property(nonatomic, readonly, assign, getter=isDestructive) BOOL destructive; + +- (void)setup NS_REQUIRES_SUPER; + +@end + +/*--------------------------------------------------*/ + +@interface NSString (MobilyApplication) + +- (MobilyApplicationNotificationType)moConvertToApplicationNotificationType; +- (MobilyApplicationNotificationType)moConvertToApplicationNotificationTypeSeparated:(NSString*)separated; + +- (UIUserNotificationActivationMode)moConvertToUserNotificationActivationMode; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyApplication.m b/Sources/MobilyCore/MobilyApplication.m new file mode 100644 index 0000000..2ed6faf --- /dev/null +++ b/Sources/MobilyCore/MobilyApplication.m @@ -0,0 +1,439 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyApplication () + +@property(nonatomic, readwrite, assign) MobilyApplicationNotificationType notificationType; +@property(nonatomic, readwrite, strong) NSArray* notificationCategories; +@property(nonatomic, readwrite, strong) NSData* deviceToken; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyApplicationNotificationCategory () + +@property(nonatomic, readwrite, strong) NSString* identifier; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyApplicationNotificationAction () + +@property(nonatomic, readwrite, strong) NSString* identifier; +@property(nonatomic, readwrite, strong) NSString* title; +@property(nonatomic, readwrite, assign) UIUserNotificationActivationMode activationMode; +@property(nonatomic, readwrite, assign, getter=isAuthenticationRequired) BOOL authenticationRequired; +@property(nonatomic, readwrite, assign, getter=isDestructive) BOOL destructive; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyApplication + +#pragma mark NSKeyValueCoding + +MOBILY_DEFINE_VALIDATE_STRING_BASED(NotificationType, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToApplicationNotificationType]]) + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { +} + +- (void)dealloc { +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return _objectChilds; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:MobilyApplicationNotificationCategory.class] == YES) { + self.notificationCategories = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + } else if([objectChild isKindOfClass:UIWindow.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIWindow.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark Public + +- (BOOL)launchingWithOptions:(NSDictionary* __unused)options { + if(_notificationType != UIRemoteNotificationTypeNone) { + if(UIDevice.moSystemVersion >= 8.0f) { + UIUserNotificationType notificationType = UIUserNotificationTypeNone; + if((_notificationType & MobilyApplicationNotificationTypeBadge) != 0) { + notificationType |= UIUserNotificationTypeBadge; + } + if((_notificationType & MobilyApplicationNotificationTypeSound) != 0) { + notificationType |= UIUserNotificationTypeSound; + } + if((_notificationType & MobilyApplicationNotificationTypeAlert) != 0) { + notificationType |= UIUserNotificationTypeAlert; + } + NSMutableSet* categories = [NSMutableSet set]; + for(MobilyApplicationNotificationCategory* category in _notificationCategories) { + UIMutableUserNotificationCategory* actionCategory = [[UIMutableUserNotificationCategory alloc] init]; + actionCategory.identifier = category.identifier; + if(category.actions.count > 0) { + NSMutableArray* actions = [NSMutableArray array]; + for(MobilyApplicationNotificationAction* categoryAction in category.actions) { + UIMutableUserNotificationAction* action = [[UIMutableUserNotificationAction alloc] init]; + action.identifier = categoryAction.identifier; + action.title = categoryAction.title; + action.activationMode = categoryAction.activationMode; + action.destructive = categoryAction.destructive; + action.authenticationRequired = categoryAction.authenticationRequired; + [actions addObject:action]; + } + [actionCategory setActions:actions forContext:UIUserNotificationActionContextDefault]; + } + [categories addObject:actionCategory]; + } + UIUserNotificationSettings* settings = [UIUserNotificationSettings settingsForTypes:notificationType categories:categories]; + [UIApplication.sharedApplication registerUserNotificationSettings:settings]; + } else { + UIRemoteNotificationType notificationType = UIRemoteNotificationTypeNone; + if((_notificationType & MobilyApplicationNotificationTypeBadge) != 0) { + notificationType |= UIRemoteNotificationTypeBadge; + } + if((_notificationType & MobilyApplicationNotificationTypeSound) != 0) { + notificationType |= UIRemoteNotificationTypeSound; + } + if((_notificationType & MobilyApplicationNotificationTypeAlert) != 0) { + notificationType |= UIRemoteNotificationTypeAlert; + } + [UIApplication.sharedApplication registerForRemoteNotificationTypes:notificationType]; + } + } + if(_objectChilds.count > 0) { + MobilyWindow* window = [_objectChilds moFirstObjectIsClass:UIWindow.class]; + if(window != nil) { + [window makeKeyAndVisible]; + } + } + return YES; +} + +- (void)terminate { +} + +- (void)receiveMemoryWarning { +} + +- (void)becomeActive { +} + +- (void)resignActive { +} + +- (void)enterForeground { +} + +- (void)enterBackground { +} + +- (void)registerUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings { +} + +- (void)registerForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken { + self.deviceToken = deviceToken; +} + +- (void)failToRegisterForRemoteNotificationsWithError:(NSError* __unused)error { +} + +- (void)receiveRemoteNotification:(NSDictionary* __unused)notification { +} + +- (void)receiveLocalNotification:(UILocalNotification* __unused)notification { +} + +- (void)handleActionWithIdentifier:(NSString* __unused)identifier forLocalNotification:(UILocalNotification* __unused)notification completionHandler:(void(^)())completionHandler { + completionHandler(); +} + +- (void)handleActionWithIdentifier:(NSString* __unused)identifier forRemoteNotification:(NSDictionary* __unused)notification completionHandler:(void(^)())completionHandler { + completionHandler(); +} + +- (void)handleEventsForBackgroundURLSession:(NSString*)identifier completionHandler:(void(^)())completionHandler { +} + +- (void)handleWatchKitExtensionRequest:(NSDictionary*)userInfo reply:(void(^)(NSDictionary* replyInfo))reply { +} + +- (BOOL)openURL:(NSURL* __unused)url sourceApplication:(NSString* __unused)sourceApplication annotation:(id __unused)annotation { + return NO; +} + +#pragma mark Property + +- (UIApplicationState)state { + return UIApplication.sharedApplication.applicationState; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyApplicationNotificationCategory + +#pragma mark NSKeyValueCoding + +MOBILY_DEFINE_VALIDATE_STRING(Identifier) + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { +} + +- (void)dealloc { +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return _objectChilds; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:MobilyApplicationNotificationAction.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:MobilyApplicationNotificationAction.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark Property + +- (NSArray*)actions { + return _objectChilds; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyApplicationNotificationAction + +#pragma mark NSKeyValueCoding + +MOBILY_DEFINE_VALIDATE_STRING(Identifier) +MOBILY_DEFINE_VALIDATE_STRING(Title) +MOBILY_DEFINE_VALIDATE_STRING_BASED(ActivationMode, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToUserNotificationActivationMode]]) +MOBILY_DEFINE_VALIDATE_BOOL(AuthenticationRequired) +MOBILY_DEFINE_VALIDATE_BOOL(Destructive) + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { +} + +- (void)dealloc { +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return _objectChilds; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation NSString (MobilyApplication) + +- (MobilyApplicationNotificationType)moConvertToApplicationNotificationType { + return [self moConvertToApplicationNotificationTypeSeparated:@"|"]; +} + +- (MobilyApplicationNotificationType)moConvertToApplicationNotificationTypeSeparated:(NSString*)separated { + MobilyApplicationNotificationType result = MobilyApplicationNotificationTypeNone; + NSString* value = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([value isEqualToString:@"all"] == YES) { + result = MobilyApplicationNotificationTypeBadge | MobilyApplicationNotificationTypeSound | MobilyApplicationNotificationTypeAlert; + } else { + NSArray* keys = [value componentsSeparatedByString:separated]; + for(NSString* key in keys) { + NSString* temp = [key stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if([temp isEqualToString:@"badge"] == YES) { + result |= MobilyApplicationNotificationTypeBadge; + } else if([temp isEqualToString:@"sound"] == YES) { + result |= MobilyApplicationNotificationTypeSound; + } else if([temp isEqualToString:@"alert"] == YES) { + result |= MobilyApplicationNotificationTypeAlert; + } + } + } + return result; +} + + +- (UIUserNotificationActivationMode)moConvertToUserNotificationActivationMode { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"background"] == YES) { + return UIUserNotificationActivationModeBackground; + } + return UIUserNotificationActivationModeForeground; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyAudioPlayer.h b/Sources/MobilyCore/MobilyAudioPlayer.h new file mode 100644 index 0000000..5e36ec3 --- /dev/null +++ b/Sources/MobilyCore/MobilyAudioPlayer.h @@ -0,0 +1,117 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef void(^MobilyAudioPlayerBlock)(); +typedef void(^MobilyAudioPlayerErrorBlock)(NSError* error); + +/*--------------------------------------------------*/ + +@protocol MobilyAudioPlayerDelegate; + +/*--------------------------------------------------*/ + +@interface MobilyAudioPlayer : NSObject < MobilyObject > + +@property(nonatomic, readonly, strong) NSError* error; +@property(nonatomic, readonly, strong) NSURL* url; +@property(nonatomic, readonly, assign) NSUInteger numberOfChannels; +@property(nonatomic, readwrite, assign) NSTimeInterval currentTime; +@property(nonatomic, readonly, assign) NSTimeInterval duration; +@property(nonatomic, readwrite, assign) CGFloat volume; +@property(nonatomic, readwrite, assign) CGFloat pan; +@property(nonatomic, readwrite, assign) BOOL enableRate; +@property(nonatomic, readwrite, assign) CGFloat rate; +@property(nonatomic, readwrite, assign) NSInteger numberOfLoops; +@property(nonatomic, readwrite, assign, getter=isMeteringEnabled) BOOL meteringEnabled; +@property(nonatomic, readonly, assign) CGFloat peakPower; +@property(nonatomic, readonly, assign) CGFloat averagePower; + +@property(nonatomic, readonly, assign, getter=isPrepared) BOOL prepared; +@property(nonatomic, readonly, assign, getter=isPlaying) BOOL playing; +@property(nonatomic, readonly, assign, getter=isPaused) BOOL paused; + +@property(nonatomic, readwrite, weak) id< MobilyAudioPlayerDelegate > delegate; +@property(nonatomic, readwrite, copy) MobilyAudioPlayerBlock preparedBlock; +@property(nonatomic, readwrite, copy) MobilyAudioPlayerBlock cleanedBlock; +@property(nonatomic, readwrite, copy) MobilyAudioPlayerBlock playingBlock; +@property(nonatomic, readwrite, copy) MobilyAudioPlayerBlock stopedBlock; +@property(nonatomic, readwrite, copy) MobilyAudioPlayerBlock finishedBlock; +@property(nonatomic, readwrite, copy) MobilyAudioPlayerBlock resumedBlock; +@property(nonatomic, readwrite, copy) MobilyAudioPlayerBlock pausedBlock; +@property(nonatomic, readwrite, copy) MobilyAudioPlayerErrorBlock decodeErrorBlock; + +- (void)setup NS_REQUIRES_SUPER; + +- (BOOL)prepareWithData:(NSData*)data; +- (BOOL)prepareWithName:(NSString*)name; +- (BOOL)prepareWithPath:(NSString*)path name:(NSString*)name; +- (BOOL)prepareWithUrl:(NSURL*)url; +- (void)prepareWithUrl:(NSURL*)url success:(MobilyAudioPlayerBlock)success failure:(MobilyAudioPlayerBlock)failure; +- (void)clean; + +- (BOOL)play; +- (void)stop; + +- (void)resume; +- (void)pause; + +- (void)updateMeters; + +- (CGFloat)peakPowerForChannel:(NSUInteger)channelNumber; +- (CGFloat)averagePowerForChannel:(NSUInteger)channelNumber; + +@end + +/*--------------------------------------------------*/ + +@protocol MobilyAudioPlayerDelegate < NSObject > + +@optional +-(void)audioPlayerDidPrepared:(MobilyAudioPlayer*)audioPlayer; +-(void)audioPlayerDidCleaned:(MobilyAudioPlayer*)audioPlayer; +-(void)audioPlayerDidPlaying:(MobilyAudioPlayer*)audioPlayer; +-(void)audioPlayerDidStoped:(MobilyAudioPlayer*)audioPlayer; +-(void)audioPlayerDidFinished:(MobilyAudioPlayer*)audioPlayer; +-(void)audioPlayerDidPaused:(MobilyAudioPlayer*)audioPlayer; +-(void)audioPlayerDidResumed:(MobilyAudioPlayer*)audioPlayer; +-(void)audioPlayer:(MobilyAudioPlayer*)audioPlayer didDecodeError:(NSError*)encodeError; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyAudioPlayer.m b/Sources/MobilyCore/MobilyAudioPlayer.m new file mode 100644 index 0000000..a84bed8 --- /dev/null +++ b/Sources/MobilyCore/MobilyAudioPlayer.m @@ -0,0 +1,395 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyAudioPlayer () < AVAudioPlayerDelegate > + +@property(nonatomic, readwrite, strong) NSError* error; +@property(nonatomic, readwrite, strong) NSURL* url; +@property(nonatomic, readwrite, assign, getter=isPrepared) BOOL prepared; +@property(nonatomic, readwrite, assign, getter=isPlaying) BOOL playing; +@property(nonatomic, readwrite, assign, getter=isPaused) BOOL paused; + +@property(nonatomic, readwrite, strong) AVAudioPlayer* player; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyAudioPlayer + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder* __unused)coder { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { +} + +#pragma mark Property + +- (void)setPlayer:(AVAudioPlayer*)player { + if(_player != player) { + if(_player != nil) { + _player.delegate = nil; + } + _player = player; + if(_player != nil) { + _player.delegate = self; + } + } +} + +- (NSUInteger)numberOfChannels { + return _player.numberOfChannels; +} + +- (void)setCurrentTime:(NSTimeInterval)currentTime { + _player.currentTime = currentTime; +} + +- (NSTimeInterval)currentTime { + return _player.currentTime; +} + +- (NSTimeInterval)duration { + return _player.duration; +} + +- (void)setVolume:(CGFloat)volume { + _player.volume = volume; +} + +- (CGFloat)volume { + return _player.volume; +} + +- (void)setPan:(CGFloat)pan { + _player.pan = pan; +} + +- (CGFloat)pan { + return _player.pan; +} + +- (void)setEnableRate:(BOOL)enableRate { + _player.enableRate = enableRate; +} + +- (BOOL)enableRate { + return _player.enableRate; +} + +- (void)setRate:(CGFloat)rate { + _player.rate = rate; +} + +- (CGFloat)rate { + return _player.rate; +} + +- (void)setNumberOfLoops:(NSInteger)numberOfLoops { + _player.numberOfLoops = numberOfLoops; +} + +- (NSInteger)numberOfLoops { + return _player.numberOfLoops; +} + +- (void)setMeteringEnabled:(BOOL)meteringEnabled { + _player.meteringEnabled = meteringEnabled; +} + +- (BOOL)isMeteringEnabled { + return _player.isMeteringEnabled; +} + +- (CGFloat)peakPower { + CGFloat result = 0.0f; + if(_prepared == YES) { + NSUInteger numberOfChannels = _player.numberOfChannels; + for(NSUInteger channel = 0; channel < numberOfChannels; channel++) { + result += [_player peakPowerForChannel:channel]; + } + result /= numberOfChannels; + } + return result; +} + +- (CGFloat)averagePower { + CGFloat result = 0.0f; + if(_prepared == YES) { + NSUInteger numberOfChannels = _player.numberOfChannels; + for(NSUInteger channel = 0; channel < numberOfChannels; channel++) { + result += [_player averagePowerForChannel:channel]; + } + result /= numberOfChannels; + } + return result; +} + +#pragma mark Public + +- (BOOL)prepareWithData:(NSData*)data { + if(_prepared == NO) { + NSError* error = nil; + self.player = [[AVAudioPlayer alloc] initWithData:data error:&error]; + if(_player != nil) { + self.error = nil; + if([_player prepareToPlay] == YES) { + self.prepared = YES; + if([_delegate respondsToSelector:@selector(audioPlayerDidPrepared:)] == YES) { + [_delegate audioPlayerDidPrepared:self]; + } else if(_preparedBlock != nil) { + _preparedBlock(); + } + } else { + self.player = nil; + } + } else if(error != nil) { + self.error = error; + NSLog(@"MobilyAudioPlayer::prepareWithData: Error=%@", error.localizedDescription); + } + } + return _prepared; +} + +- (BOOL)prepareWithName:(NSString*)name { + return [self prepareWithPath:NSBundle.mainBundle.resourcePath name:name]; +} + +- (BOOL)prepareWithPath:(NSString*)path name:(NSString*)name { + return [self prepareWithUrl:[NSURL URLWithString:[path stringByAppendingPathComponent:name]]]; +} + +- (BOOL)prepareWithUrl:(NSURL*)url { + if(_prepared == NO) { + NSError* error = nil; + self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error]; + if(_player != nil) { + self.error = nil; + if([_player prepareToPlay] == YES) { + self.url = url; + self.prepared = YES; + if([_delegate respondsToSelector:@selector(audioPlayerDidPrepared:)] == YES) { + [_delegate audioPlayerDidPrepared:self]; + } else if(_preparedBlock != nil) { + _preparedBlock(); + } + } else { + self.player = nil; + } + } else if(error != nil) { + self.error = error; + NSLog(@"MobilyAudioPlayer::prepareWithUrl:%@ Error=%@", url, error.localizedDescription); + } + } + return _prepared; +} + +- (void)prepareWithUrl:(NSURL*)url success:(MobilyAudioPlayerBlock)success failure:(MobilyAudioPlayerBlock)failure { + if((_prepared == NO) && ([_url isEqual:url] == NO)) { + if(_player.url != nil) { + [[MobilyDownloader shared] cancelByTarget:self]; + } + [[MobilyDownloader shared] downloadWithUrl:url byTarget:self completeBlock:^(NSData* data, NSURL* url) { + NSError* error = nil; + self.player = [[AVAudioPlayer alloc] initWithData:data error:&error]; + if(_player != nil) { + self.error = nil; + if([_player prepareToPlay] == YES) { + self.url = url; + self.prepared = YES; + if([_delegate respondsToSelector:@selector(audioPlayerDidPrepared:)] == YES) { + [_delegate audioPlayerDidPrepared:self]; + } else if(_preparedBlock != nil) { + _preparedBlock(); + } + if(success != nil) { + success(); + } + } else { + self.player = nil; + } + } else if(error != nil) { + self.error = error; + NSLog(@"MobilyAudioPlayer::prepareWithUrl:%@ Error=%@", url, error.localizedDescription); + } + if((_prepared == NO) && (failure != nil)) { + failure(); + } + } failureBlock:^(NSURL* url __unused) { + if(failure != nil) { + failure(); + } + }]; + } +} + +- (void)clean { + if(_prepared == YES) { + [self stop]; + self.prepared = NO; + self.player = nil; + self.url = nil; + if([_delegate respondsToSelector:@selector(audioPlayerDidCleaned:)] == YES) { + [_delegate audioPlayerDidCleaned:self]; + } else if(_cleanedBlock != nil) { + _cleanedBlock(); + } + } +} + +- (BOOL)play { + if((_prepared == YES) && (_playing == NO)) { + if([_player play] == YES) { + self.playing = YES; + if([_delegate respondsToSelector:@selector(audioPlayerDidPlaying:)] == YES) { + [_delegate audioPlayerDidPlaying:self]; + } else if(_playingBlock != nil) { + _playingBlock(); + } + } + } + return _player.isPlaying; +} + +- (void)stop { + if((_prepared == YES) && (_playing == YES)) { + self.playing = NO; + self.paused = NO; + _player.currentTime = 0.0f; + [_player stop]; + if([_delegate respondsToSelector:@selector(audioPlayerDidStoped:)] == YES) { + [_delegate audioPlayerDidStoped:self]; + } else if(_stopedBlock != nil) { + _stopedBlock(); + } + } +} + +- (void)resume { + if((_prepared == YES) && (_playing == YES) && (_paused == YES)) { + if([_player play] == YES) { + self.paused = NO; + if([_delegate respondsToSelector:@selector(audioPlayerDidResumed:)] == YES) { + [_delegate audioPlayerDidResumed:self]; + } else if(_resumedBlock != nil) { + _resumedBlock(); + } + } + } +} + +- (void)pause { + if((_prepared == YES) && (_playing == YES) && (_paused == NO)) { + self.paused = YES; + [_player pause]; + if([_delegate respondsToSelector:@selector(audioPlayerDidPaused:)] == YES) { + [_delegate audioPlayerDidPaused:self]; + } else if(_pausedBlock != nil) { + _pausedBlock(); + } + } +} + +- (void)updateMeters { + if(_prepared == YES) { + [_player updateMeters]; + } +} + +- (CGFloat)peakPowerForChannel:(NSUInteger)channelNumber { + CGFloat result = 0.0f; + if(_prepared == YES) { + result = [_player peakPowerForChannel:channelNumber]; + } + return result; +} + +- (CGFloat)averagePowerForChannel:(NSUInteger)channelNumber { + CGFloat result = 0.0f; + if(_prepared == YES) { + result = [_player averagePowerForChannel:channelNumber]; + } + return result; +} + +#pragma mark AVAudioPlayerDelegate + +- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer* __unused)player successfully:(BOOL __unused)successfully { + self.playing = NO; + if([_delegate respondsToSelector:@selector(audioPlayerDidFinished:)] == YES) { + [_delegate audioPlayerDidFinished:self]; + } else if(_finishedBlock != nil) { + _finishedBlock(); + } +} + +- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer* __unused)player error:(NSError*)error { +#if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) + NSLog(@"MobilyAudioPlayer::EncodeErrorDidOccur:%@", error); +#endif + if([_delegate respondsToSelector:@selector(audioPlayer:didDecodeError:)] == YES) { + [_delegate audioPlayer:self didDecodeError:error]; + } else if(_decodeErrorBlock != nil) { + _decodeErrorBlock(error); + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyAudioRecorder.h b/Sources/MobilyCore/MobilyAudioRecorder.h new file mode 100644 index 0000000..1d84f4d --- /dev/null +++ b/Sources/MobilyCore/MobilyAudioRecorder.h @@ -0,0 +1,114 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef void(^MobilyAudioRecorderBlock)(); +typedef void(^MobilyAudioRecorderErrorBlock)(NSError* error); + +/*--------------------------------------------------*/ + +@protocol MobilyAudioRecorderDelegate; + +/*--------------------------------------------------*/ + +@interface MobilyAudioRecorder : NSObject < MobilyObject > + +@property(nonatomic, readonly, strong) NSError* error; +@property(nonatomic, readwrite, assign) AudioFormatID format; +@property(nonatomic, readwrite, assign) AVAudioQuality quality; +@property(nonatomic, readwrite, assign) NSUInteger bitRate; +@property(nonatomic, readwrite, assign) NSUInteger numberOfChannels; +@property(nonatomic, readwrite, assign) CGFloat sampleRate; +@property(nonatomic, readonly, strong) NSURL* url; +@property(nonatomic, readonly, assign) NSTimeInterval duration; +@property(nonatomic, readwrite, assign, getter=isMeteringEnabled) BOOL meteringEnabled; +@property(nonatomic, readonly, assign) CGFloat peakPower; +@property(nonatomic, readonly, assign) CGFloat averagePower; + +@property(nonatomic, readonly, assign, getter=isPrepared) BOOL prepared; +@property(nonatomic, readonly, assign, getter=isStarted) BOOL started; +@property(nonatomic, readonly, assign, getter=isRecording) BOOL recording; +@property(nonatomic, readonly, assign, getter=isPaused) BOOL paused; + +@property(nonatomic, readwrite, weak) id< MobilyAudioRecorderDelegate > delegate; +@property(nonatomic, readwrite, copy) MobilyAudioRecorderBlock preparedBlock; +@property(nonatomic, readwrite, copy) MobilyAudioRecorderBlock cleanedBlock; +@property(nonatomic, readwrite, copy) MobilyAudioRecorderBlock startedBlock; +@property(nonatomic, readwrite, copy) MobilyAudioRecorderBlock stopedBlock; +@property(nonatomic, readwrite, copy) MobilyAudioRecorderBlock finishedBlock; +@property(nonatomic, readwrite, copy) MobilyAudioRecorderBlock resumedBlock; +@property(nonatomic, readwrite, copy) MobilyAudioRecorderBlock pausedBlock; +@property(nonatomic, readwrite, copy) MobilyAudioRecorderErrorBlock encodeErrorBlock; + +- (void)setup NS_REQUIRES_SUPER; + +- (BOOL)prepareWithName:(NSString*)name; +- (BOOL)prepareWithPath:(NSString*)path name:(NSString*)name; +- (BOOL)prepareWithUrl:(NSURL*)url; +- (void)clean; + +- (BOOL)start; +- (void)stop; + +- (void)resume; +- (void)pause; + +- (void)updateMeters; + +- (CGFloat)peakPowerForChannel:(NSUInteger)channelNumber; +- (CGFloat)averagePowerForChannel:(NSUInteger)channelNumber; + +@end + +/*--------------------------------------------------*/ + +@protocol MobilyAudioRecorderDelegate < NSObject > + +@optional +-(void)audioRecorderDidPrepared:(MobilyAudioRecorder*)audioRecorder; +-(void)audioRecorderDidCleaned:(MobilyAudioRecorder*)audioRecorder; +-(void)audioRecorderDidStarted:(MobilyAudioRecorder*)audioRecorder; +-(void)audioRecorderDidStoped:(MobilyAudioRecorder*)audioRecorder; +-(void)audioRecorderDidFinished:(MobilyAudioRecorder*)audioRecorder; +-(void)audioRecorderDidPaused:(MobilyAudioRecorder*)audioRecorder; +-(void)audioRecorderDidResumed:(MobilyAudioRecorder*)audioRecorder; +-(void)audioRecorder:(MobilyAudioRecorder*)audioRecorder didEncodeError:(NSError*)encodeError; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyAudioRecorder.m b/Sources/MobilyCore/MobilyAudioRecorder.m new file mode 100644 index 0000000..8bc75c7 --- /dev/null +++ b/Sources/MobilyCore/MobilyAudioRecorder.m @@ -0,0 +1,304 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyAudioRecorder () < AVAudioRecorderDelegate > + +@property(nonatomic, readwrite, strong) NSError* error; +@property(nonatomic, readwrite, assign) NSTimeInterval duration; + +@property(nonatomic, readwrite, assign, getter=isPrepared) BOOL prepared; +@property(nonatomic, readwrite, assign, getter=isStarted) BOOL started; +@property(nonatomic, readwrite, assign, getter=isWaitFinished) BOOL waitFinished; +@property(nonatomic, readwrite, assign, getter=isPaused) BOOL paused; + +@property(nonatomic, readwrite, strong) AVAudioRecorder* recorder; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyAudioRecorder + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder* __unused)coder { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + self.format = kAudioFormatAppleIMA4; + self.quality = AVAudioQualityMin; + self.sampleRate = 44100.0f; + self.numberOfChannels = 1; + self.bitRate = 12800.0f; +} + +#pragma mark Property + +- (void)setRecorder:(AVAudioRecorder*)recorder { + if(_recorder != recorder) { + if(_recorder != nil) { + _recorder.delegate = nil; + } + _recorder = recorder; + if(_recorder != nil) { + _recorder.delegate = self; + } + } +} + +- (BOOL)isRecording { + return _recorder.isRecording; +} + +- (NSURL*)url { + return _recorder.url; +} + +- (NSTimeInterval)duration { + if(_recorder.isRecording == YES) { + self.duration = _recorder.currentTime; + } + return _duration; +} + +- (void)setMeteringEnabled:(BOOL)meteringEnabled { + _recorder.meteringEnabled = meteringEnabled; +} + +- (BOOL)isMeteringEnabled { + return _recorder.isMeteringEnabled; +} + +- (CGFloat)peakPower { + CGFloat result = 0.0f; + if(_prepared == YES) { + for(NSUInteger channel = 0; channel < _numberOfChannels; channel++) { + result += [_recorder peakPowerForChannel:channel]; + } + result /= _numberOfChannels; + } + return result; +} + +- (CGFloat)averagePower { + CGFloat result = 0.0f; + if(_prepared == YES) { + for(NSUInteger channel = 0; channel < _numberOfChannels; channel++) { + result += [_recorder averagePowerForChannel:channel]; + } + result /= _numberOfChannels; + } + return result; +} + +#pragma mark Public + +- (BOOL)prepareWithName:(NSString*)name { + return [self prepareWithPath:NSFileManager.moDocumentDirectory name:name]; +} + +- (BOOL)prepareWithPath:(NSString*)path name:(NSString*)name { + return [self prepareWithUrl:[NSURL URLWithString:[path stringByAppendingPathComponent:name]]]; +} + +- (BOOL)prepareWithUrl:(NSURL*)url { + if(_prepared == NO) { + NSError* error = nil; + self.recorder = [[AVAudioRecorder alloc] initWithURL:url settings:[self recorderSettings] error:&error]; + if(_recorder != nil) { + self.error = nil; + if([_recorder prepareToRecord] == YES) { + self.prepared = YES; + if([_delegate respondsToSelector:@selector(audioRecorderDidPrepared:)] == YES) { + [_delegate audioRecorderDidPrepared:self]; + } else if(_preparedBlock != nil) { + _preparedBlock(); + } + } + } else if(error != nil) { + self.error = error; + NSLog(@"MobilyAudioRecorder::prepareWithUrl:%@ Error=%@", url, error.localizedDescription); + } + } + return _prepared; +} + +- (void)clean { + if(_prepared == YES) { + [self stop]; + self.prepared = NO; + self.recorder = nil; + if([_delegate respondsToSelector:@selector(audioRecorderDidCleaned:)] == YES) { + [_delegate audioRecorderDidCleaned:self]; + } else if(_cleanedBlock != nil) { + _cleanedBlock(); + } + } +} + +- (BOOL)start { + if((_prepared == YES) && (_started == NO)) { + if([_recorder record] == YES) { + self.started = YES; + if([_delegate respondsToSelector:@selector(audioRecorderDidStarted:)] == YES) { + [_delegate audioRecorderDidStarted:self]; + } else if(_startedBlock != nil) { + _startedBlock(); + } + } + } + return _started; +} + +- (void)stop { + if((_prepared == YES) && (_started == YES) && (_waitFinished == NO)) { + self.duration = _recorder.currentTime; + self.waitFinished = YES; + [_recorder stop]; + if([_delegate respondsToSelector:@selector(audioRecorderDidStoped:)] == YES) { + [_delegate audioRecorderDidStoped:self]; + } else if(_stopedBlock != nil) { + _stopedBlock(); + } + } +} + +- (void)pause { + if((_prepared == YES) && (_started == YES) && (_paused == NO)) { + self.paused = YES; + self.duration = _recorder.currentTime; + [_recorder pause]; + if([_delegate respondsToSelector:@selector(audioRecorderDidPaused:)] == YES) { + [_delegate audioRecorderDidPaused:self]; + } else if(_pausedBlock != nil) { + _pausedBlock(); + } + } +} + +- (void)resume { + if((_prepared == YES) && (_started == YES) && (_paused == YES)) { + self.paused = NO; + [_recorder record]; + if([_delegate respondsToSelector:@selector(audioRecorderDidResumed:)] == YES) { + [_delegate audioRecorderDidResumed:self]; + } else if(_resumedBlock != nil) { + _resumedBlock(); + } + } +} + +- (void)updateMeters { + if(_prepared == YES) { + [_recorder updateMeters]; + } +} + +- (CGFloat)peakPowerForChannel:(NSUInteger)channelNumber { + CGFloat result = 0.0f; + if(_prepared == YES) { + result = [_recorder peakPowerForChannel:channelNumber]; + } + return result; +} + +- (CGFloat)averagePowerForChannel:(NSUInteger)channelNumber { + CGFloat result = 0.0f; + if(_prepared == YES) { + result = [_recorder averagePowerForChannel:channelNumber]; + } + return result; +} + +#pragma mark Private + +- (NSDictionary*)recorderSettings { + return @{ + AVFormatIDKey: @(_format), + AVEncoderAudioQualityKey : @(_quality), + AVEncoderBitRateKey : @(_bitRate), + AVNumberOfChannelsKey : @(_numberOfChannels), + AVSampleRateKey : @(_sampleRate), + }; +} + +#pragma mark AVAudioRecorderDelegate + +- (void)audioRecorderDidFinishRecording:(AVAudioRecorder* __unused)recorder successfully:(BOOL __unused)successfully { + self.waitFinished = NO; + self.started = NO; + self.paused = NO; + if([_delegate respondsToSelector:@selector(audioRecorderDidFinished:)] == YES) { + [_delegate audioRecorderDidFinished:self]; + } else if(_finishedBlock != nil) { + _finishedBlock(); + } +} + +- (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder* __unused)recorder error:(NSError* __unused)error { +#if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) + NSLog(@"MobilyAudioRecorder::EncodeErrorDidOccur:%@", error); +#endif + if([_delegate respondsToSelector:@selector(audioRecorder:didEncodeError:)] == YES) { + [_delegate audioRecorder:self didEncodeError:error]; + } else if(_encodeErrorBlock != nil) { + _encodeErrorBlock(error); + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyBadgeView.h b/Sources/MobilyCore/MobilyBadgeView.h new file mode 100644 index 0000000..3a81821 --- /dev/null +++ b/Sources/MobilyCore/MobilyBadgeView.h @@ -0,0 +1,57 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyBadgeView : UIView< MobilyBuilderObject > + +@property(nonatomic, readwrite, copy) IBInspectable NSString* text; +@property(nonatomic, readwrite, assign) IBInspectable UIEdgeInsets textInsets; +@property(nonatomic, readwrite, strong) IBInspectable UIColor* textColor; +@property(nonatomic, readwrite, strong) IBInspectable UIFont* textFont; +@property(nonatomic, readwrite, strong) IBInspectable UIColor* textShadowColor; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat textShadowRadius; +@property(nonatomic, readwrite, assign) IBInspectable CGSize textShadowOffset; + +@property(nonatomic, readwrite, assign) IBInspectable CGSize minimumSize; +@property(nonatomic, readwrite, assign) IBInspectable CGSize maximumSize; + +- (void)setup NS_REQUIRES_SUPER; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyBadgeView.m b/Sources/MobilyCore/MobilyBadgeView.m new file mode 100644 index 0000000..d83c327 --- /dev/null +++ b/Sources/MobilyCore/MobilyBadgeView.m @@ -0,0 +1,365 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyBadgeView () + +@property(nonatomic, readwrite, strong) UILabel* label; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintLabelTop; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintLabelBottom; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintLabelLeft; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintLabelRight; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintMinWidth; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintMinHeight; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintMaxWidth; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintMaxHeight; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyBadgeView + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; + +#pragma mark Init / Free + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + self.userInteractionEnabled = NO; + self.backgroundColor = [UIColor redColor]; + self.moCornerRadius = 9.0f; + self.clipsToBounds = YES; + [self setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisHorizontal]; + [self setContentHuggingPriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical]; + + _textInsets = UIEdgeInsetsMake(0.0f, 4.0f, 0.0f, 4.0f); + _minimumSize = CGSizeMake(18.0f, 18.0f); + _maximumSize = CGSizeMake((_minimumSize.width * 3.0f), _minimumSize.height); + + self.label = [[UILabel alloc] initWithFrame:UIEdgeInsetsInsetRect(self.bounds, _textInsets)]; +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return self.subviews; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + [self addSubview:(UIView*)objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + [self moRemoveSubview:(UIView*)objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark Public override + +- (CGSize)sizeThatFits:(CGSize)size { + if(self.translatesAutoresizingMaskIntoConstraints == NO) { + return [super sizeThatFits:size]; + } + CGSize available = CGSizeMake(size.width, size.height); + if(_minimumSize.width > 0.0f) { + available.width = MAX(_minimumSize.width, available.width); + } + if(_minimumSize.height > 0.0f) { + available.height = MAX(_minimumSize.height, available.height); + } + if(_maximumSize.width > 0.0f) { + available.width = MIN(_maximumSize.width, available.width); + } + if(_maximumSize.height > 0.0f) { + available.height = MIN(_maximumSize.height, available.height); + } + CGSize result = [_label sizeThatFits:CGSizeMake(available.width - (_textInsets.left + _textInsets.right), available.height - (_textInsets.top + _textInsets.bottom))]; + result.width += (_textInsets.left + _textInsets.right); + result.height += (_textInsets.top + _textInsets.bottom); + if(_minimumSize.width > 0.0f) { + result.width = MAX(_minimumSize.width, result.width); + } + if(_minimumSize.height > 0.0f) { + result.height = MAX(_minimumSize.height, result.height); + } + if(_maximumSize.width > 0.0f) { + result.width = MIN(_maximumSize.width, result.width); + } + if(_maximumSize.height > 0.0f) { + result.height = MIN(_maximumSize.height, result.height); + } + return result; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + if(self.translatesAutoresizingMaskIntoConstraints == YES) { + _label.frame = UIEdgeInsetsInsetRect(self.bounds, _textInsets); + } +} + +- (void)updateConstraints { + if(self.translatesAutoresizingMaskIntoConstraints == NO) { + if(_label != nil) { + if(_constraintLabelTop == nil) { + self.constraintLabelTop = [_label moAddConstraintAttribute:NSLayoutAttributeTop relation:NSLayoutRelationEqual attribute:NSLayoutAttributeTop constant:_textInsets.top]; + } else { + _constraintLabelTop.constant = _textInsets.top; + } + if(_constraintLabelBottom == nil) { + self.constraintLabelBottom = [_label moAddConstraintAttribute:NSLayoutAttributeBottom relation:NSLayoutRelationEqual attribute:NSLayoutAttributeBottom constant:-_textInsets.bottom]; + } else { + _constraintLabelBottom.constant = -_textInsets.bottom; + } + if(_constraintLabelLeft == nil) { + self.constraintLabelLeft = [_label moAddConstraintAttribute:NSLayoutAttributeLeft relation:NSLayoutRelationEqual attribute:NSLayoutAttributeLeft constant:_textInsets.left]; + } else { + _constraintLabelLeft.constant = _textInsets.left; + } + if(_constraintLabelRight == nil) { + self.constraintLabelRight = [_label moAddConstraintAttribute:NSLayoutAttributeRight relation:NSLayoutRelationEqual attribute:NSLayoutAttributeRight constant:-_textInsets.right]; + } else { + _constraintLabelRight.constant = -_textInsets.right; + } + } else { + self.constraintLabelTop = nil; + self.constraintLabelBottom = nil; + self.constraintLabelLeft = nil; + self.constraintLabelRight = nil; + } + if(_minimumSize.width > 0.0f) { + if(_constraintMinWidth == nil) { + self.constraintMinWidth = [self moAddConstraintAttribute:NSLayoutAttributeWidth relation:NSLayoutRelationGreaterThanOrEqual constant:_minimumSize.width]; + } else { + _constraintMinWidth.constant = _minimumSize.width; + } + } else { + self.constraintMinWidth = nil; + } + if(_maximumSize.width > 0.0f) { + if(_constraintMaxWidth == nil) { + self.constraintMaxWidth = [self moAddConstraintAttribute:NSLayoutAttributeWidth relation:NSLayoutRelationLessThanOrEqual constant:_maximumSize.width]; + } else { + _constraintMaxWidth.constant = _maximumSize.width; + } + } else { + self.constraintMaxWidth = nil; + } + if(_minimumSize.height > 0.0f) { + if(_constraintMinHeight == nil) { + self.constraintMinHeight = [self moAddConstraintAttribute:NSLayoutAttributeHeight relation:NSLayoutRelationGreaterThanOrEqual constant:_minimumSize.height]; + } else { + _constraintMinHeight.constant = _minimumSize.height; + } + } else { + self.constraintMinHeight = nil; + } + if(_maximumSize.height > 0.0f) { + if(_constraintMaxHeight == nil) { + self.constraintMaxHeight = [self moAddConstraintAttribute:NSLayoutAttributeHeight relation:NSLayoutRelationLessThanOrEqual constant:_maximumSize.height]; + } else { + _constraintMaxHeight.constant = _maximumSize.height; + } + } else { + self.constraintMaxHeight = nil; + } + } else { + self.constraintLabelTop = nil; + self.constraintLabelBottom = nil; + self.constraintLabelLeft = nil; + self.constraintLabelRight = nil; + self.constraintMinWidth = nil; + self.constraintMaxWidth = nil; + self.constraintMinHeight = nil; + self.constraintMaxHeight = nil; + } + [super updateConstraints]; +} + +#pragma mark Property override + +- (void)setTranslatesAutoresizingMaskIntoConstraints:(BOOL)translatesAutoresizingMaskIntoConstraints { + if(self.translatesAutoresizingMaskIntoConstraints != translatesAutoresizingMaskIntoConstraints) { + [super setTranslatesAutoresizingMaskIntoConstraints:translatesAutoresizingMaskIntoConstraints]; + if(_label != nil) { + _label.translatesAutoresizingMaskIntoConstraints = self.translatesAutoresizingMaskIntoConstraints; + } + [self setNeedsUpdateConstraints]; + [self setNeedsLayout]; + } +} + +#pragma mark Property public + +- (void)setText:(NSString*)text { + _label.text = text; + self.hidden = (text == nil); +} + +- (NSString*)text { + return _label.text; +} + +- (void)setTextInsets:(UIEdgeInsets)textInsets { + if(UIEdgeInsetsEqualToEdgeInsets(_textInsets, textInsets) == NO) { + _textInsets = textInsets; + [self setNeedsUpdateConstraints]; + } +} + +- (void)setTextColor:(UIColor*)textColor { + _label.textColor = textColor; +} + +- (UIColor*)textColor { + return _label.textColor; +} + +- (void)setTextFont:(UIFont*)textFont { + _label.font = textFont; +} + +- (UIFont*)textFont { + return _label.font; +} + +- (void)setTextShadowColor:(UIColor*)textShadowColor { + _label.moShadowColor = textShadowColor; +} + +- (UIColor*)textShadowColor { + return _label.moShadowColor; +} + +- (void)setTextShadowRadius:(CGFloat)textShadowRadius { + _label.moShadowRadius = textShadowRadius; +} + +- (CGFloat)textShadowRadius { + return _label.moShadowRadius; +} + +- (void)setTextShadowOffset:(CGSize)textShadowOffset { + _label.moShadowOffset = textShadowOffset; +} + +- (CGSize)textShadowOffset { + return _label.moShadowOffset; +} + +- (void)setMinimumSize:(CGSize)minimumSize { + if(CGSizeEqualToSize(_minimumSize, minimumSize) == NO) { + _minimumSize = minimumSize; + [self setNeedsUpdateConstraints]; + } +} + +- (void)setMaximumSize:(CGSize)maximumSize { + if(CGSizeEqualToSize(_maximumSize, maximumSize) == NO) { + _maximumSize = maximumSize; + [self setNeedsUpdateConstraints]; + } +} + +#pragma mark Property private + +- (void)setLabel:(UILabel*)label { + if(_label != label) { + if(_label != nil) { + [_label removeFromSuperview]; + } + _label = label; + if(_label != nil) { + _label.translatesAutoresizingMaskIntoConstraints = self.translatesAutoresizingMaskIntoConstraints; + _label.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _label.textAlignment = NSTextAlignmentCenter; + _label.font = [UIFont systemFontOfSize:12.0f]; + _label.textColor = [UIColor whiteColor]; + [self addSubview:_label]; + } + [self setNeedsUpdateConstraints]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyBlurView.h b/Sources/MobilyCore/MobilyBlurView.h new file mode 100755 index 0000000..8d2249a --- /dev/null +++ b/Sources/MobilyCore/MobilyBlurView.h @@ -0,0 +1,59 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyBlurView : UIView< MobilyBuilderObject > + +@property(nonatomic, readwrite, assign, getter = isBlurEnabled) IBInspectable BOOL blurEnabled; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat blurRadius; +@property(nonatomic, readwrite, assign) IBInspectable NSUInteger blurIterations; +@property(nonatomic, readwrite, assign, getter = isDynamic) IBInspectable BOOL dynamic; +@property(nonatomic, readwrite, assign) IBInspectable NSTimeInterval updateInterval; +@property(nonatomic, readwrite, weak) IBOutlet UIView* underlyingView; + ++ (void)setBlurEnabled:(BOOL)blurEnabled; ++ (void)setUpdatesEnabled; ++ (void)setUpdatesDisabled; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)updateAsynchronously:(BOOL)async completion:(MobilySimpleBlock)completion; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyBlurView.m b/Sources/MobilyCore/MobilyBlurView.m new file mode 100755 index 0000000..f0d0288 --- /dev/null +++ b/Sources/MobilyCore/MobilyBlurView.m @@ -0,0 +1,546 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@class MobilyBlurLayer; + +/*--------------------------------------------------*/ + +@interface MobilyBlurView () + +@property(nonatomic, readwrite, strong) NSDate* lastUpdate; + +- (CALayer*)underlyingLayer; +- (MobilyBlurLayer*)blurLayer; +- (MobilyBlurLayer*)blurPresentationLayer; + +- (UIImage*)snapshotOfUnderlyingView; +- (BOOL)shouldUpdate; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyBlurScheduler : NSObject + +@property(nonatomic, readwrite, assign) BOOL blurEnabled; +@property(nonatomic, readwrite, strong) NSMutableArray* blurViews; +@property(nonatomic, readwrite, assign) NSUInteger blurViewIndex; +@property(nonatomic, readwrite, assign) NSUInteger updatesEnabled; +@property(nonatomic, readwrite, assign) BOOL updating; + ++ (instancetype)sharedInstance; + +- (void)setBlurEnabled:(BOOL)blurEnabled; +- (void)setUpdatesEnabled; +- (void)setUpdatesDisabled; + +- (void)addBlurView:(MobilyBlurView*)blurView; +- (void)removeBlurView:(MobilyBlurView*)blurView; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyBlurLayer: CALayer + +@property(nonatomic, readwrite, assign) CGFloat blurRadius; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyBlurView + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; + +#pragma mark Init / Free + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + _blurEnabled = YES; + self.blurLayer.blurRadius = 20.0f; + _blurIterations = 4; + _dynamic = YES; + _updateInterval = 0.1f; + self.layer.magnificationFilter = @"linear"; +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return self.subviews; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + [self addSubview:(UIView*)objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + [self moRemoveSubview:(UIView*)objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark Public static override + ++ (Class)layerClass { + return [MobilyBlurLayer class]; +} + +#pragma mark Public static + ++ (void)setBlurEnabled:(BOOL)blurEnabled { + MobilyBlurScheduler.sharedInstance.blurEnabled = blurEnabled; +} + ++ (void)setUpdatesEnabled { + [MobilyBlurScheduler.sharedInstance setUpdatesEnabled]; +} + ++ (void)setUpdatesDisabled { + [MobilyBlurScheduler.sharedInstance setUpdatesDisabled]; +} + +#pragma mark Property public + +- (void)setBlurEnabled:(BOOL)blurEnabled { + if (_blurEnabled != blurEnabled) { + _blurEnabled = blurEnabled; + [self schedule]; + if(_blurEnabled == YES) { + [self setNeedsDisplay]; + } + } +} + +- (void)setBlurRadius:(CGFloat)blurRadius { + self.blurLayer.blurRadius = blurRadius; +} + +- (CGFloat)blurRadius { + return self.blurLayer.blurRadius; +} + +- (void)setBlurIterations:(NSUInteger)blurIterations { + if(_blurIterations != blurIterations) { + _blurIterations = blurIterations; + [self setNeedsDisplay]; + } +} + +- (void)setDynamic:(BOOL)dynamic { + if (_dynamic != dynamic) { + _dynamic = dynamic; + [self schedule]; + if(dynamic == NO) { + [self setNeedsDisplay]; + } + } +} + +- (void)setUpdateInterval:(NSTimeInterval)updateInterval { + _updateInterval = updateInterval; + if(_updateInterval <= MOBILY_EPSILON) { + _updateInterval = 1.0f / 60.0f; + } +} + +- (UIView*)underlyingView { + if(_underlyingView == nil) { + return self.superview; + } + return _underlyingView; +} + +#pragma mark Property private + +- (CALayer*)underlyingLayer { + return self.underlyingView.layer; +} + +- (CALayer*)underlyingPresentationLayer { + CALayer* underlyingLayer = self.underlyingLayer; + CALayer* presentationLayer = underlyingLayer.presentationLayer; + if(presentationLayer == nil) { + return underlyingLayer; + } + return presentationLayer; +} + +- (MobilyBlurLayer*)blurLayer { + return (MobilyBlurLayer*)self.layer; +} + +- (MobilyBlurLayer*)blurPresentationLayer { + MobilyBlurLayer* blurLayer = self.blurLayer; + MobilyBlurLayer* presentationLayer = (MobilyBlurLayer*)blurLayer.presentationLayer; + if(presentationLayer == nil) { + return blurLayer; + } + return presentationLayer; +} + +#pragma mark Public override + +- (void)didMoveToSuperview { + [super didMoveToSuperview]; + [self.layer setNeedsDisplay]; +} + +- (void)didMoveToWindow { + [super didMoveToWindow]; + [self schedule]; +} + +- (void)setNeedsDisplay { + [super setNeedsDisplay]; + [self.layer setNeedsDisplay]; +} + +#pragma mark Public + +- (void)updateAsynchronously:(BOOL)async completion:(MobilySimpleBlock)completion { + if([self shouldUpdate] == YES) { + UIImage *snapshot = [self snapshotOfUnderlyingView]; + if(async == YES) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + UIImage* blurredImage = [self blurredSnapshot:snapshot radius:self.blurRadius]; + dispatch_sync(dispatch_get_main_queue(), ^{ + [self setLayerContents:blurredImage]; + if(completion) { + completion(); + } + }); + }); + } else { + [self setLayerContents:[self blurredSnapshot:snapshot radius:self.blurPresentationLayer.blurRadius]]; + if(completion) { + completion(); + } + } + } else if(completion) { + completion(); + } +} + +#pragma mark Private + +- (void)schedule { + if((self.window != nil) && (_blurEnabled == YES) && (_dynamic == YES)) { + [MobilyBlurScheduler.sharedInstance addBlurView:self]; + } else { + [MobilyBlurScheduler.sharedInstance removeBlurView:self]; + } +} + +- (BOOL)shouldUpdate { + if(_blurEnabled == NO) { + return NO; + } + MobilyBlurLayer* blurLayer = self.blurPresentationLayer; + if(CGRectIsEmpty(blurLayer.bounds) == YES) { + return NO; + } + CALayer* underlyingLayer = self.underlyingLayer; + if((underlyingLayer == nil) || (underlyingLayer.hidden == YES) || (CGRectIsEmpty(underlyingLayer.bounds) == YES)) { + return NO; + } + return YES; +} + +- (UIImage*)snapshotOfUnderlyingView { + CALayer* blurLayer = self.blurLayer; + MobilyBlurLayer* blurPresentationLayer = self.blurPresentationLayer; + CALayer* underlyingLayer = self.underlyingLayer; + CGRect bounds = [blurPresentationLayer convertRect:blurPresentationLayer.bounds toLayer:underlyingLayer]; + _lastUpdate = [NSDate date]; + CGFloat scale = 0.5f; + if(_blurIterations > 0) { + CGFloat blockSize = 12.0f / _blurIterations; + scale = blockSize / MAX(blockSize * 2.0f, blurPresentationLayer.blurRadius); + scale = 1.0f / floorf(1.0f / scale); + } + CGSize size = bounds.size; + switch(self.contentMode) { + case UIViewContentModeScaleToFill: + case UIViewContentModeScaleAspectFill: + case UIViewContentModeScaleAspectFit: + case UIViewContentModeRedraw: { + size.width = floorf(size.width * scale) / scale; + size.height = floorf(size.height * scale) / scale; + break; + } + default: { + scale = 1.0f; + break; + } + } + while((blurLayer.superlayer != nil) && (blurLayer.superlayer != underlyingLayer)) { + blurLayer = blurLayer.superlayer; + } + NSMutableArray* hiddenLayers = [NSMutableArray array]; + NSArray* underlyingSublayers = underlyingLayer.sublayers; + NSUInteger index = [underlyingSublayers indexOfObject:blurLayer]; + if(index != NSNotFound) { + for(NSUInteger i = index; i < underlyingSublayers.count; i++) { + CALayer *layer = underlyingSublayers[i]; + if(layer.hidden == NO) { + layer.hidden = YES; + [hiddenLayers addObject:layer]; + } + } + } + UIImage* snapshot = nil; + if(floorf(size.width) * floorf(size.height) > MOBILY_EPSILON) { + UIGraphicsBeginImageContextWithOptions(size, NO, scale); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextTranslateCTM(context, -bounds.origin.x, -bounds.origin.y); + [underlyingLayer renderInContext:context]; + snapshot = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + } + for(CALayer* layer in hiddenLayers) { + layer.hidden = NO; + } + return snapshot; +} + +- (UIImage*)blurredSnapshot:(UIImage*)snapshot radius:(CGFloat)blurRadius { + return [snapshot moBlurredImageWithRadius:blurRadius iterations:_blurIterations tintColor:self.tintColor]; +} + +- (void)setLayerContents:(UIImage*)image { + self.layer.contents = (id)image.CGImage; + self.layer.contentsScale = image.scale; +} + +#pragma mark CALayerDelegate + +- (void)displayLayer:(CALayer* __unused)layer { + [self updateAsynchronously:NO completion:NULL]; +} + +- (id< CAAction >)actionForLayer:(CALayer*)layer forKey:(NSString*)key { + if([key isEqualToString:@"blurRadius"] == YES) { + CAAnimation *action = (CAAnimation*)[super actionForLayer:layer forKey:@"backgroundColor"]; + if((NSNull*)action != [NSNull null]) { + CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:key]; + animation.fromValue = [layer.presentationLayer valueForKey:key]; + animation.beginTime = action.beginTime; + animation.duration = action.duration; + animation.speed = action.speed; + animation.timeOffset = action.timeOffset; + animation.repeatCount = action.repeatCount; + animation.repeatDuration = action.repeatDuration; + animation.autoreverses = action.autoreverses; + animation.fillMode = action.fillMode; + animation.timingFunction = action.timingFunction; + animation.delegate = action.delegate; + return animation; + } + } + return [super actionForLayer:layer forKey:key]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyBlurScheduler + +#pragma mark Singleton + ++ (instancetype)sharedInstance { + static MobilyBlurScheduler *sharedInstance = nil; + if(sharedInstance == nil) { + sharedInstance = [[MobilyBlurScheduler alloc] init]; + } + return sharedInstance; +} + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + _blurEnabled = YES; + _blurViews = [NSMutableArray array]; + _updatesEnabled = 1; + } + return self; +} + +#pragma mark Public + +- (void)setBlurEnabled:(BOOL)blurEnabled { + if(_blurEnabled != blurEnabled) { + _blurEnabled = blurEnabled; + if(_blurEnabled == YES) { + for(MobilyBlurView* blurView in _blurViews) { + [blurView setNeedsDisplay]; + } + [self updateAsynchronously]; + } + } +} + +- (void)setUpdatesEnabled { + _updatesEnabled++; + [self updateAsynchronously]; +} + +- (void)setUpdatesDisabled { + _updatesEnabled--; +} + +- (void)addBlurView:(MobilyBlurView*)blurView { + if([_blurViews containsObject:blurView] == NO) { + [_blurViews addObject:blurView]; + [self updateAsynchronously]; + } +} + +- (void)removeBlurView:(MobilyBlurView*)blurView { + NSUInteger index = [_blurViews indexOfObject:blurView]; + if(index != NSNotFound) { + if(index <= _blurViewIndex) { + _blurViewIndex--; + } + [_blurViews removeObjectAtIndex:index]; + } +} + +- (void)updateAsynchronously { + if((_blurEnabled == YES) && (_updatesEnabled > 0) && (_updating == NO)) { + NSUInteger blurViewsCount = _blurViews.count; + if(blurViewsCount > 0) { + NSTimeInterval timeUntilNextUpdate = 1.0f / 60.0f; + _blurViewIndex = _blurViewIndex % blurViewsCount; + for(NSUInteger i = _blurViewIndex; i < blurViewsCount; i++) { + MobilyBlurView* view = _blurViews[i]; + if((view.window != nil) && (view.hidden == NO) && (view.alpha >= 0.05f) && (view.dynamic == YES) && ([view shouldUpdate] == YES)) { + NSTimeInterval nextUpdate = [view.lastUpdate timeIntervalSinceNow] + view.updateInterval; + if((view.lastUpdate == nil) || (nextUpdate <= 0)) { + self.updating = YES; + [view updateAsynchronously:YES completion:^{ + self.updating = NO; + _blurViewIndex = i + 1; + [self updateAsynchronously]; + }]; + return; + } else { + timeUntilNextUpdate = MIN(timeUntilNextUpdate, nextUpdate); + } + } + } + _blurViewIndex = 0; + [self performSelector:@selector(updateAsynchronously) withObject:nil afterDelay:timeUntilNextUpdate inModes:@[ NSDefaultRunLoopMode, UITrackingRunLoopMode ]]; + } + } +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyBlurLayer + ++ (BOOL)needsDisplayForKey:(NSString*)key { + if([key isEqualToString:@"blurRadius"] == YES) { + return YES; + } else if([key isEqualToString:@"bounds"] == YES) { + return YES; + } else if([key isEqualToString:@"position"] == YES) { + return YES; + } + return [super needsDisplayForKey:key]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyBuilder.h b/Sources/MobilyCore/MobilyBuilder.h similarity index 89% rename from Classes/UI/Core/MobilyBuilder.h rename to Sources/MobilyCore/MobilyBuilder.h index aef7a1f..7282aa8 100644 --- a/Classes/UI/Core/MobilyBuilder.h +++ b/Sources/MobilyCore/MobilyBuilder.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,7 +33,7 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyUI.h" +#import /*--------------------------------------------------*/ @@ -63,19 +63,20 @@ + (id)objectFromFilename:(NSString*)filename owner:(id)owner; -+ (id< MobilyBuilderObject >)object:(id)object forName:(NSString*)name; -+ (id< MobilyBuilderObject >)object:(id)object forSelector:(SEL)selector; ++ (id< MobilyBuilderObject >)object:(id< MobilyBuilderObject >)object forName:(NSString*)name; ++ (id< MobilyBuilderObject >)object:(id< MobilyBuilderObject >)object forSelector:(SEL)selector; @end /*--------------------------------------------------*/ -@protocol MobilyBuilderObject < NSObject > +@protocol MobilyBuilderObject < MobilyObject > @property(nonatomic, readwrite, strong) NSString* objectName; @property(nonatomic, readwrite, weak) id objectParent; @property(nonatomic, readwrite, strong) NSArray* objectChilds; +@property(nonatomic, readonly, strong) NSArray* relatedObjects; - (void)addObjectChild:(id< MobilyBuilderObject >)objectChild; - (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild; diff --git a/Classes/UI/Core/MobilyBuilderForm.m b/Sources/MobilyCore/MobilyBuilderForm.m similarity index 56% rename from Classes/UI/Core/MobilyBuilderForm.m rename to Sources/MobilyCore/MobilyBuilderForm.m index a73c0bd..26e846e 100644 --- a/Classes/UI/Core/MobilyBuilderForm.m +++ b/Sources/MobilyCore/MobilyBuilderForm.m @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -32,8 +32,10 @@ /* OTHER DEALINGS IN THE SOFTWARE. */ /* */ /*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ -#import "MobilyBuilder.h" +#import /*--------------------------------------------------*/ @@ -54,11 +56,12 @@ + (BOOL)object:(id)object outletName:(NSString*)outletName outletObject:(id< Mob #pragma mark - /*--------------------------------------------------*/ -@interface MobilyBuilderFormXML : NSObject < NSXMLParserDelegate > - -@property(nonatomic, readwrite, strong) NSMutableArray* stackFormObjects; -@property(nonatomic, readwrite, strong) id< MobilyBuilderObject > lastFormObject; -@property(nonatomic, readwrite, strong) id< MobilyBuilderObject > rootFormObject; +@interface MobilyBuilderFormXML : NSObject < NSXMLParserDelegate > { + NSMutableArray* _stackFormObjects; + id< MobilyBuilderObject > _lastFormObject; + id< MobilyBuilderObject > _rootFormObject; + NSUInteger _ignoreSubObject; +} - (id)objectFromFilename:(NSString*)filename owner:(id)owner; @@ -73,28 +76,28 @@ @implementation MobilyBuilderForm #pragma mark Public + (id)objectFromFilename:(NSString*)filename owner:(id)owner { - MobilyBuilderFormXML* loader = [[MobilyBuilderFormXML alloc] init]; + MobilyBuilderFormXML* loader = [MobilyBuilderFormXML new]; if(loader != nil) { return [loader objectFromFilename:filename owner:owner]; } return nil; } -+ (id< MobilyBuilderObject >)object:(id)object forName:(NSString*)name { - __block id< MobilyBuilderObject > result = nil; ++ (id< MobilyBuilderObject >)object:(id< MobilyBuilderObject >)object forName:(NSString*)name { + id< MobilyBuilderObject > result = nil; if([object respondsToSelector:@selector(objectName)] == YES) { - if([[object objectName] isEqualToString:name] == YES) { + if([object.objectName isEqualToString:name] == YES) { result = object; } else { - [[object objectChilds] enumerateObjectsUsingBlock:^(id objectChild, NSUInteger objectIndex, BOOL* stop) { + for(id objectChild in object.objectChilds) { if([objectChild respondsToSelector:@selector(objectForName:)] == YES) { id tempObjectChild = [objectChild objectForName:name]; if(tempObjectChild != nil) { result = tempObjectChild; - *stop = YES; + break; } } - }]; + } } } return result; @@ -113,20 +116,22 @@ + (id)objectFromFilename:(NSString*)filename owner:(id)owner { #pragma mark Private +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + (BOOL)object:(id)object outletName:(NSString*)outletName outletObject:(id< MobilyBuilderObject >)outletObject { BOOL isLinked = NO; - @try { - [object setValue:outletObject forKey:outletName]; + SEL setter = NSSelectorFromString([NSString stringWithFormat:@"set%@:", outletName.moStringByUppercaseFirstCharacterString]); + if([object respondsToSelector:setter] == YES) { + [object performSelector:setter withObject:outletObject]; isLinked = YES; } - @catch(NSException* exception) { - id objectParent = [object objectParent]; - if(objectParent != nil) { - isLinked = [self object:objectParent outletName:outletName outletObject:outletObject]; - } + id objectParent = [object objectParent]; + if(objectParent != nil) { + isLinked = [self object:objectParent outletName:outletName outletObject:outletObject]; } return isLinked; } +#pragma clang diagnostic pop @end @@ -136,42 +141,33 @@ + (BOOL)object:(id)object outletName:(NSString*)outletName outletObject:(id< Mob @implementation MobilyBuilderFormXML -#pragma mark Standart +#pragma mark Init / Free -- (id)init { +- (instancetype)init { self = [super init]; if(self != nil) { - [self setStackFormObjects:[NSMutableArray array]]; + _stackFormObjects = NSMutableArray.array; } return self; } -- (void)dealloc { - [self setStackFormObjects:nil]; - [self setRootFormObject:nil]; - [self setLastFormObject:nil]; - - MOBILY_SAFE_DEALLOC; -} - #pragma mark Private - (id)objectFromFilename:(NSString*)filename owner:(id)owner { id result = nil; #if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_INFO) != 0) - NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate]; + NSTimeInterval now = NSDate.timeIntervalSinceReferenceDate; #endif - NSFileManager* fileManager = [NSFileManager defaultManager]; - NSString* filePath = [[NSBundle mainBundle] pathForResource:filename ofType:MOBILY_BUILDER_FORM_FILE_EXTENSION]; - if([fileManager fileExistsAtPath:filePath] == YES) { + NSString* filePath = [NSBundle.mainBundle pathForResource:filename ofType:MOBILY_BUILDER_FORM_FILE_EXTENSION]; + if([NSFileManager.defaultManager fileExistsAtPath:filePath] == YES) { NSData* data = [NSData dataWithContentsOfFile:filePath]; if(data != nil) { - [self setLastFormObject:owner]; + _lastFormObject = owner; NSXMLParser* parser = [[NSXMLParser alloc] initWithData:data]; if(parser != nil) { - [parser setDelegate:self]; + parser.delegate = self; if([parser parse] == YES) { result = _rootFormObject; } @@ -179,7 +175,7 @@ - (id)objectFromFilename:(NSString*)filename owner:(id)owner { } } #if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_INFO) != 0) - NSTimeInterval delta = [NSDate timeIntervalSinceReferenceDate] - now; + NSTimeInterval delta = NSDate.timeIntervalSinceReferenceDate - now; NSLog(@"MobilyLoader:%@ (%lu ms)", filename, (unsigned long)(delta * 1000)); #endif return result; @@ -187,54 +183,65 @@ - (id)objectFromFilename:(NSString*)filename owner:(id)owner { #pragma mark NSXMLParserDelegate -- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributes { - Class targetClass = nil; - Class defaultClass = NSClassFromString([NSString stringWithFormat:MOBILY_BUILDER_FORM_CLASS, elementName]); - if(defaultClass != nil) { - targetClass = defaultClass; - } else { +- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString* __unused)namespaceURI qualifiedName:(NSString* __unused)qualifiedName attributes:(NSDictionary*)attributes { + if(_ignoreSubObject == 0) { + Class targetClass = nil; Class customClass = NSClassFromString(elementName); if(customClass != nil) { targetClass = customClass; + } else { + Class defaultClass = NSClassFromString([NSString stringWithFormat:MOBILY_BUILDER_FORM_CLASS, elementName]); + if(defaultClass != nil) { + targetClass = defaultClass; + } } - } - id target = nil; - if([targetClass conformsToProtocol:@protocol(MobilyBuilderObject)] == YES) { - target = [[targetClass alloc] init]; - } - if(target != nil) { - if(_rootFormObject == nil) { - [self setRootFormObject:target]; - } - [target setObjectParent:_lastFormObject]; - NSString* targetName = [attributes objectForKey:@"name"]; - if([targetName length] > 0) { - [target setObjectName:targetName]; - [MobilyBuilderForm object:target outletName:targetName outletObject:target]; + id< MobilyBuilderObject > target = nil; + if([targetClass conformsToProtocol:@protocol(MobilyBuilderObject)] == YES) { + target = [targetClass new]; } - if([attributes count] > 0) { - NSDictionary* mixinAttirutes = [MobilyBuilderPreset mixinAttributes:attributes]; - if([mixinAttirutes count] > 0) { - [MobilyBuilderPreset applyPresetAttributes:mixinAttirutes object:target]; + if(target != nil) { + if(_rootFormObject == nil) { + _rootFormObject = target; + } + target.objectParent = _lastFormObject; + NSString* targetName = attributes[@"name"]; + if(targetName.length > 0) { + target.objectName = targetName; + [MobilyBuilderForm object:_lastFormObject outletName:targetName outletObject:target]; } + if(attributes.count > 0) { + NSDictionary* mixinAttirutes = [MobilyBuilderPreset mixinAttributes:attributes]; + if(mixinAttirutes.count > 0) { + [MobilyBuilderPreset applyPresetAttributes:mixinAttirutes object:target]; + } + } + [target willLoadObjectChilds]; + + [_lastFormObject addObjectChild:target]; + [_stackFormObjects addObject:target]; + _lastFormObject = target; + } else { +#if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) + NSLog(@"Not found class: '%@'; lineNumber: %ld; columnNumber: %ld", elementName, (long)parser.lineNumber, (long)parser.columnNumber); +#endif + _ignoreSubObject = 1; } - [target willLoadObjectChilds]; - - [_lastFormObject addObjectChild:target]; - [_stackFormObjects addObject:target]; - [self setLastFormObject:target]; } else { #if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) - NSLog(@"Not found class: '%@'; lineNumber: %ld; columnNumber: %ld", elementName, (long)[parser lineNumber], (long)[parser columnNumber]); + NSLog(@"Ignore loading element: '%@'; lineNumber: %ld; columnNumber: %ld", elementName, (long)parser.lineNumber, (long)parser.columnNumber); #endif - [parser abortParsing]; + _ignoreSubObject++; } } -- (void)parser:(NSXMLParser*)parser didEndElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName { - [_lastFormObject didLoadObjectChilds]; - [_stackFormObjects removeObject:_lastFormObject]; - _lastFormObject = [_stackFormObjects lastObject]; +- (void)parser:(NSXMLParser* __unused)parser didEndElement:(NSString* __unused)elementName namespaceURI:(NSString* __unused)namespaceURI qualifiedName:(NSString* __unused)qualifiedName { + if(_ignoreSubObject == 0) { + [_lastFormObject didLoadObjectChilds]; + [_stackFormObjects removeObject:_lastFormObject]; + _lastFormObject = [_stackFormObjects lastObject]; + } else { + _ignoreSubObject--; + } } @end diff --git a/Classes/UI/Core/MobilyBuilderPreset.m b/Sources/MobilyCore/MobilyBuilderPreset.m similarity index 65% rename from Classes/UI/Core/MobilyBuilderPreset.m rename to Sources/MobilyCore/MobilyBuilderPreset.m index b4ccc14..567a6b7 100644 --- a/Classes/UI/Core/MobilyBuilderPreset.m +++ b/Sources/MobilyCore/MobilyBuilderPreset.m @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -32,8 +32,10 @@ /* OTHER DEALINGS IN THE SOFTWARE. */ /* */ /*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ -#import "MobilyBuilder.h" +#import /*--------------------------------------------------*/ @@ -64,15 +66,20 @@ - (BOOL)loadFromFilename:(NSString*)filename; @end +/*--------------------------------------------------*/ + +typedef BOOL (*MobilyBuilderPreset_ValidateImp)(id, SEL, id*); +typedef void (*MobilyBuilderPreset_SetterImp)(id, SEL, id); + /*--------------------------------------------------*/ #pragma mark - /*--------------------------------------------------*/ @implementation MobilyBuilderPreset -#pragma mark Standart +#pragma mark Init / Free -- (id)init { +- (instancetype)init { self = [super init]; if(self != nil) { } @@ -80,14 +87,13 @@ - (id)init { } - (void)dealloc { - MOBILY_SAFE_DEALLOC; } #pragma mark Public + (void)registerAttributes:(NSDictionary*)attributes { - NSString* name = [attributes objectForKey:@"name"]; - if([name isKindOfClass:[NSString class]] == YES) { + NSString* name = attributes[@"name"]; + if([name isKindOfClass:NSString.class] == YES) { NSMutableDictionary* presetAttributes = [NSMutableDictionary dictionaryWithDictionary:attributes]; [presetAttributes removeObjectForKey:@"name"]; @@ -100,34 +106,34 @@ + (void)registerAttributes:(NSDictionary*)attributes { } + (void)registerByName:(NSString*)name attributes:(NSDictionary*)attributes { - NSMutableDictionary* finalAttributes = [NSMutableDictionary dictionary]; - [attributes enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSString* value, BOOL* stop) { + NSMutableDictionary* finalAttributes = NSMutableDictionary.dictionary; + [attributes enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSString* value, BOOL* stop __unused) { if(([value hasPrefix:@"${"] == YES) && ([value hasSuffix:@"}"] == YES)) { - NSString* path = [value substringWithRange:NSMakeRange(2, [value length] - 3)]; + NSString* path = [value substringWithRange:NSMakeRange(2, value.length - 3)]; NSArray* partPath = [path componentsSeparatedByString:@"."]; - if([partPath count] == 2) { + if(partPath.count == 2) { if(MOBILY_BUILDER_PRESET != nil) { - NSDictionary* preset = [MOBILY_BUILDER_PRESET objectForKey:[partPath objectAtIndex:0]]; - NSString* presetValue = [preset objectForKey:[partPath objectAtIndex:1]]; + NSDictionary* preset = MOBILY_BUILDER_PRESET[partPath[0]]; + NSString* presetValue = preset[partPath[1]]; if(presetValue != nil) { - [finalAttributes setObject:presetValue forKey:key]; + finalAttributes[key] = presetValue; } else { - [finalAttributes setObject:value forKey:key]; + finalAttributes[key] = value; } } else { - [finalAttributes setObject:value forKey:key]; + finalAttributes[key] = value; } } else { - [finalAttributes setObject:value forKey:key]; + finalAttributes[key] = value; } } else { - [finalAttributes setObject:value forKey:key]; + finalAttributes[key] = value; } }]; if(MOBILY_BUILDER_PRESET == nil) { - MOBILY_BUILDER_PRESET = MOBILY_SAFE_RETAIN([NSMutableDictionary dictionaryWithObject:finalAttributes forKey:name]); + MOBILY_BUILDER_PRESET = [NSMutableDictionary dictionaryWithObject:finalAttributes forKey:name]; } else { - [MOBILY_BUILDER_PRESET setObject:finalAttributes forKey:name]; + MOBILY_BUILDER_PRESET[name] = finalAttributes; } } @@ -138,21 +144,21 @@ + (void)unregisterByName:(NSString*)name { } + (NSDictionary*)mixinAttributes:(NSDictionary*)attributes { - __block NSMutableDictionary* result = [NSMutableDictionary dictionaryWithDictionary:attributes]; - NSString* name = [result objectForKey:@"name"]; - if([name isKindOfClass:[NSString class]] == YES) { + NSMutableDictionary* result = [NSMutableDictionary dictionaryWithDictionary:attributes]; + NSString* name = result[@"name"]; + if([name isKindOfClass:NSString.class] == YES) { [result removeObjectForKey:@"name"]; } - NSString* preset = [result objectForKey:@"preset"]; - if([preset isKindOfClass:[NSString class]] == YES) { + NSString* preset = result[@"preset"]; + if([preset isKindOfClass:NSString.class] == YES) { if(MOBILY_BUILDER_PRESET != nil) { NSArray* presets = [preset componentsSeparatedByString:@"|"]; - [presets enumerateObjectsUsingBlock:^(NSString* name, NSUInteger index, BOOL* stop) { - NSDictionary* presetAttributes = [MOBILY_BUILDER_PRESET objectForKey:name]; + for(NSString* name in presets) { + NSDictionary* presetAttributes = MOBILY_BUILDER_PRESET[name]; if(presetAttributes != nil) { [result addEntriesFromDictionary:presetAttributes]; } - }]; + } } [result removeObjectForKey:@"preset"]; } @@ -161,7 +167,7 @@ + (NSDictionary*)mixinAttributes:(NSDictionary*)attributes { + (NSDictionary*)mixinByName:(NSString*)name attributes:(NSDictionary*)attributes { if(MOBILY_BUILDER_PRESET != nil) { - NSDictionary* preset = [MOBILY_BUILDER_PRESET objectForKey:name]; + NSDictionary* preset = MOBILY_BUILDER_PRESET[name]; if(preset != nil) { NSMutableDictionary* result = [NSMutableDictionary dictionaryWithDictionary:preset]; if(result != nil) { @@ -175,7 +181,7 @@ + (NSDictionary*)mixinByName:(NSString*)name attributes:(NSDictionary*)attribute + (BOOL)loadFromFilename:(NSString*)filename { BOOL result = NO; - MobilyBuilderPresetXML* preset = [[MobilyBuilderPresetXML alloc] init]; + MobilyBuilderPresetXML* preset = [MobilyBuilderPresetXML new]; if(preset != nil) { result = [preset loadFromFilename:filename]; } @@ -183,8 +189,8 @@ + (BOOL)loadFromFilename:(NSString*)filename { } + (void)applyPreset:(NSString*)preset object:(id)object { - NSDictionary* presetAttributes = [MOBILY_BUILDER_PRESET objectForKey:preset]; - if([presetAttributes count] > 0) { + NSDictionary* presetAttributes = MOBILY_BUILDER_PRESET[preset]; + if(presetAttributes.count > 0) { [self applyPresetAttributes:presetAttributes object:object]; } } @@ -194,36 +200,48 @@ + (void)applyPresetAttributes:(NSDictionary*)presetAttributes object:(id)object if(characterSet == nil) { characterSet = [NSCharacterSet characterSetWithCharactersInString:@":-"]; } - [presetAttributes enumerateKeysAndObjectsUsingBlock:^(NSString* key, id value, BOOL* stop) { - __block NSString* validKey = [NSString string]; + [presetAttributes enumerateKeysAndObjectsUsingBlock:^(NSString* key, id value, BOOL* stop __unused) { + NSString* property = NSString.string; NSArray* components = [key componentsSeparatedByCharactersInSet:characterSet]; - if([components count] > 1) { - [components enumerateObjectsUsingBlock:^(NSString* component, NSUInteger index, BOOL* stop) { - validKey = [validKey stringByAppendingString:[component stringByUppercaseFirstCharacterString]]; - }]; - validKey = [validKey stringByLowercaseFirstCharacterString]; + if(components.count > 1) { + for(NSString* component in components) { + property = [property stringByAppendingString:component.moStringByUppercaseFirstCharacterString]; + } + property = property.moStringByLowercaseFirstCharacterString; } else { - validKey = [key stringByLowercaseFirstCharacterString]; + property = key.moStringByLowercaseFirstCharacterString; } - if([validKey length] > 0) { - if([object validateValue:&value forKey:validKey error:nil] == YES) { - @try { - [object setValue:value forKey:validKey]; - } - @catch(NSException *exception) { + if(property.length > 0) { + if([self applyPresetProperty:property value:value object:object] == NO) { + NSString* moProperty = [NSString stringWithFormat:@"mo%@", property.moStringByUppercaseFirstCharacterString]; + if([self applyPresetProperty:moProperty value:value object:object] == NO) { #if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) - NSLog(@"Failure set value in property: '%@=%@'; object: '%@'", validKey, value, object); + NSLog(@"Failure set value in property: '%@=%@'; object: '%@'", property, value, object); #endif } - } else { -#if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) - NSLog(@"Not found property: '%@=%@'; object: '%@'", validKey, value, object); -#endif } } }]; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" ++ (BOOL)applyPresetProperty:(NSString*)property value:(id)value object:(id)object { + SEL validateSelector = NSSelectorFromString([NSString stringWithFormat:@"validate%@:", property.moStringByUppercaseFirstCharacterString]); + if([object respondsToSelector:validateSelector] == YES) { + value = [object performSelector:validateSelector withObject:value]; + } + if(value != nil) { + @try { + [object setValue:value forKey:property]; + } + @catch(NSException* exception) { + } + } + return (value != nil); +} +#pragma clang diagnostic pop + @end /*--------------------------------------------------*/ @@ -232,9 +250,9 @@ + (void)applyPresetAttributes:(NSDictionary*)presetAttributes object:(id)object @implementation MobilyBuilderPresetXML -#pragma mark Standart +#pragma mark Init / Free -- (id)init { +- (instancetype)init { self = [super init]; if(self != nil) { } @@ -242,7 +260,6 @@ - (id)init { } - (void)dealloc { - MOBILY_SAFE_DEALLOC; } #pragma mark Private @@ -250,18 +267,18 @@ - (void)dealloc { - (BOOL)loadFromFilename:(NSString*)filename { BOOL result = NO; #if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_INFO) != 0) - NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate]; + NSTimeInterval now = NSDate.timeIntervalSinceReferenceDate; #endif - NSURL* url = [[NSBundle mainBundle] URLForResource:filename withExtension:MOBILY_BUILDER_PRESET_FILE_EXTENSION]; + NSURL* url = [NSBundle.mainBundle URLForResource:filename withExtension:MOBILY_BUILDER_PRESET_FILE_EXTENSION]; if(url != nil) { NSXMLParser* parser = [[NSXMLParser alloc] initWithContentsOfURL:url]; if(parser != nil) { - [parser setDelegate:self]; + parser.delegate = self; result = [parser parse]; } } #if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_INFO) != 0) - NSTimeInterval delta = [NSDate timeIntervalSinceReferenceDate] - now; + NSTimeInterval delta = NSDate.timeIntervalSinceReferenceDate - now; NSLog(@"MobilyLoader:%@ (%lu ms)", filename, (unsigned long)(delta * 1000)); #endif return result; @@ -269,13 +286,13 @@ - (BOOL)loadFromFilename:(NSString*)filename { #pragma mark NSXMLParserDelegate -- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName attributes:(NSDictionary*)attributes { +- (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName namespaceURI:(NSString* __unused)namespaceURI qualifiedName:(NSString* __unused)qualifiedName attributes:(NSDictionary*)attributes { if(_isFoundedRoot == NO) { if([elementName isEqualToString:MOBILY_BUILDER_PRESET_ROOT_NAME] == YES) { _isFoundedRoot = YES; } else { #if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) - NSLog(@"Unsupported element name: '%@'; lineNumber: %ld; columnNumber: %ld", elementName, (long)[parser lineNumber], (long)[parser columnNumber]); + NSLog(@"Unsupported element name: '%@'; lineNumber: %ld; columnNumber: %ld", elementName, (long)parser.lineNumber, (long)parser.columnNumber); #endif [parser abortParsing]; } @@ -284,14 +301,14 @@ - (void)parser:(NSXMLParser*)parser didStartElement:(NSString*)elementName names [MobilyBuilderPreset registerAttributes:attributes]; } else { #if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) - NSLog(@"Unsupported element name: '%@'; lineNumber: %ld; columnNumber: %ld", elementName, (long)[parser lineNumber], (long)[parser columnNumber]); + NSLog(@"Unsupported element name: '%@'; lineNumber: %ld; columnNumber: %ld", elementName, (long)parser.lineNumber, (long)parser.columnNumber); #endif [parser abortParsing]; } } } -- (void)parser:(NSXMLParser*)parser didEndElement:(NSString*)elementName namespaceURI:(NSString*)namespaceURI qualifiedName:(NSString*)qualifiedName { +- (void)parser:(NSXMLParser* __unused)parser didEndElement:(NSString*)elementName namespaceURI:(NSString* __unused)namespaceURI qualifiedName:(NSString* __unused)qualifiedName { if(_isFoundedRoot == YES) { if([elementName isEqualToString:MOBILY_BUILDER_PRESET_ROOT_NAME] == YES) { _isFoundedRoot = NO; diff --git a/Sources/MobilyCore/MobilyButton.h b/Sources/MobilyCore/MobilyButton.h new file mode 100644 index 0000000..5706dad --- /dev/null +++ b/Sources/MobilyCore/MobilyButton.h @@ -0,0 +1,108 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSInteger, MobilyButtonImageAlignment) { + MobilyButtonImageAlignmentLeft, + MobilyButtonImageAlignmentRight, + MobilyButtonImageAlignmentTop, + MobilyButtonImageAlignmentBottom +}; + +typedef NS_ENUM(NSInteger, MobilyButtonBadgeAlias) { + MobilyButtonBadgeAliasTitle, + MobilyButtonBadgeAliasImage, + MobilyButtonBadgeAliasContent +}; + +typedef NS_ENUM(NSInteger, MobilyButtonBadgeHorizontalAlignment) { + MobilyButtonBadgeHorizontalAlignmentLeft, + MobilyButtonBadgeHorizontalAlignmentCenter, + MobilyButtonBadgeHorizontalAlignmentRight +}; + +typedef NS_ENUM(NSInteger, MobilyButtonBadgeVerticalAlignment) { + MobilyButtonBadgeVerticalAlignmentTop, + MobilyButtonBadgeVerticalAlignmentCenter, + MobilyButtonBadgeVerticalAlignmentBottom +}; + +/*--------------------------------------------------*/ + +@class MobilyBadgeView; + +/*--------------------------------------------------*/ + +@interface MobilyButton : UIButton< MobilyBuilderObject > + +@property(nonatomic, readwrite, assign) IBInspectable MobilyButtonImageAlignment imageAlignment; + +@property(nonatomic, readwrite, strong) IBInspectable UIColor* normalBackgroundColor; +@property(nonatomic, readwrite, strong) IBInspectable UIColor* selectedBackgroundColor; +@property(nonatomic, readwrite, strong) IBInspectable UIColor* highlightedBackgroundColor; +@property(nonatomic, readwrite, strong) IBInspectable UIColor* disabledBackgroundColor; +@property(nonatomic, readonly, strong) UIColor* currentBackgroundColor; + +@property(nonatomic, readwrite, strong) IBInspectable UIColor* normalBorderColor; +@property(nonatomic, readwrite, strong) IBInspectable UIColor* selectedBorderColor; +@property(nonatomic, readwrite, strong) IBInspectable UIColor* highlightedBorderColor; +@property(nonatomic, readwrite, strong) IBInspectable UIColor* disabledBorderColor; +@property(nonatomic, readonly, strong) UIColor* currentBorderColor; + +@property(nonatomic, readwrite, assign) IBInspectable CGFloat normalBorderWidth; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat selectedBorderWidth; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat highlightedBorderWidth; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat disabledBorderWidth; +@property(nonatomic, readonly, assign) CGFloat currentBorderWidth; + +@property(nonatomic, readwrite, assign) IBInspectable CGFloat normalCornerRadius; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat selectedCornerRadius; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat highlightedCornerRadius; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat disabledCornerRadius; +@property(nonatomic, readonly, assign) CGFloat currentCornerRadius; + +@property(nonatomic, readonly, strong) MobilyBadgeView* badgeView; +@property(nonatomic, readwrite, assign) IBInspectable MobilyButtonBadgeAlias badgeAlias; +@property(nonatomic, readwrite, assign) IBInspectable MobilyButtonBadgeHorizontalAlignment badgeHorizontalAlignment; +@property(nonatomic, readwrite, assign) IBInspectable MobilyButtonBadgeVerticalAlignment badgeVerticalAlignment; + +- (void)setup NS_REQUIRES_SUPER; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyButton.m b/Sources/MobilyCore/MobilyButton.m new file mode 100644 index 0000000..8dc08bc --- /dev/null +++ b/Sources/MobilyCore/MobilyButton.m @@ -0,0 +1,700 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyButton () + +@property(nonatomic, readwrite, strong) MobilyBadgeView* badgeView; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintBadgeCenterX; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintBadgeCenterY; + +- (void)_updateCurrentState; + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyButton + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; +@synthesize badgeView = _badgeView; + +#pragma mark NSKeyValueCoding + +#pragma mark Init / Free + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + _badgeAlias = MobilyButtonBadgeAliasTitle; + _badgeHorizontalAlignment = MobilyButtonBadgeHorizontalAlignmentRight; + _badgeVerticalAlignment = MobilyButtonBadgeVerticalAlignmentTop; +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return self.subviews; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + [self addSubview:(UIView*)objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + [self moRemoveSubview:(UIView*)objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark Property + +- (void)setTitle:(NSString*)title forState:(UIControlState)state { + [super setTitle:title forState:state]; + [self setNeedsLayout]; +} + +- (void)setAttributedTitle:(NSAttributedString*)attributedTitle forState:(UIControlState)state { + [super setAttributedTitle:attributedTitle forState:state]; + [self setNeedsLayout]; +} + +- (void)setTitleEdgeInsets:(UIEdgeInsets)titleEdgeInsets { + [super setTitleEdgeInsets:titleEdgeInsets]; + [self setNeedsLayout]; +} + +- (void)setImage:(UIImage*)image forState:(UIControlState)state { + [super setImage:image forState:state]; + [self setNeedsLayout]; +} + +- (void)setImageEdgeInsets:(UIEdgeInsets)imageEdgeInsets { + [super setImageEdgeInsets:imageEdgeInsets]; + [self setNeedsLayout]; +} + +- (void)setEnabled:(BOOL)enabled { + if(self.enabled != enabled) { + super.enabled = enabled; + [self _updateCurrentState]; + [self setNeedsLayout]; + } +} + +- (void)setSelected:(BOOL)selected { + if(self.selected != selected) { + super.selected = selected; + [self _updateCurrentState]; + [self setNeedsLayout]; + } +} + +- (void)setHighlighted:(BOOL)highlighted { + if(self.highlighted != highlighted) { + super.highlighted = highlighted; + [self _updateCurrentState]; + [self setNeedsLayout]; + } +} + +- (void)setImageAlignment:(MobilyButtonImageAlignment)imageAlignment { + if(_imageAlignment != imageAlignment) { + _imageAlignment = imageAlignment; + [self setNeedsLayout]; + } +} + +- (void)setNormalBackgroundColor:(UIColor*)normalBackgroundColor { + if([_normalBackgroundColor isEqual:normalBackgroundColor] == NO) { + _normalBackgroundColor = normalBackgroundColor; + [self _updateCurrentState]; + } +} + +- (void)setSelectedBackgroundColor:(UIColor*)selectedBackgroundColor { + if([_selectedBackgroundColor isEqual:selectedBackgroundColor] == NO) { + _selectedBackgroundColor = selectedBackgroundColor; + [self _updateCurrentState]; + } +} + +- (void)setHighlightedBackgroundColor:(UIColor*)highlightedBackgroundColor { + if([_highlightedBackgroundColor isEqual:highlightedBackgroundColor] == NO) { + _highlightedBackgroundColor = highlightedBackgroundColor; + [self _updateCurrentState]; + } +} + +- (void)setDisabledBackgroundColor:(UIColor*)disabledBackgroundColor { + if([_disabledBackgroundColor isEqual:disabledBackgroundColor] == NO) { + _disabledBackgroundColor = disabledBackgroundColor; + [self _updateCurrentState]; + } +} + +- (UIColor*)currentBackgroundColor { + if(_normalBackgroundColor != nil) { + if(self.isEnabled == NO) { + if(_disabledBackgroundColor != nil) { + return _disabledBackgroundColor; + } + return [_normalBackgroundColor moMultiplyBrightness:0.85f]; + } else if(self.isHighlighted == YES) { + if(_highlightedBackgroundColor != nil) { + return _highlightedBackgroundColor; + } + return [_normalBackgroundColor moMultiplyBrightness:1.35f]; + } else if(self.isSelected == YES) { + if(_selectedBackgroundColor != nil) { + return _selectedBackgroundColor; + } + return [_normalBackgroundColor moMultiplyBrightness:1.10f]; + } + } + return _normalBackgroundColor; +} + +- (void)setNormalBorderColor:(UIColor*)normalBorderColor { + if([_normalBorderColor isEqual:normalBorderColor] == NO) { + _normalBorderColor = normalBorderColor; + [self _updateCurrentState]; + } +} + +- (void)setSelectedBorderColor:(UIColor*)selectedBorderColor { + if([_selectedBorderColor isEqual:selectedBorderColor] == NO) { + _selectedBorderColor = selectedBorderColor; + [self _updateCurrentState]; + } +} + +- (void)setHighlightedBorderColor:(UIColor*)highlightedBorderColor { + if([_highlightedBorderColor isEqual:highlightedBorderColor] == NO) { + _highlightedBorderColor = highlightedBorderColor; + [self _updateCurrentState]; + } +} + +- (void)setDisabledBorderColor:(UIColor*)disabledBorderColor { + if([_disabledBorderColor isEqual:disabledBorderColor] == NO) { + _disabledBorderColor = disabledBorderColor; + [self _updateCurrentState]; + } +} + +- (UIColor*)currentBorderColor { + if(_normalBorderColor != nil) { + if(self.isEnabled == NO) { + if(_disabledBorderColor != nil) { + return _disabledBorderColor; + } + return [_normalBorderColor moMultiplyBrightness:0.85f]; + } else if(self.isHighlighted == YES) { + if(_highlightedBorderColor != nil) { + return _highlightedBorderColor; + } + return [_normalBorderColor moMultiplyBrightness:1.35f]; + } else if(self.isSelected == YES) { + if(_selectedBorderColor != nil) { + return _selectedBorderColor; + } + return [_normalBorderColor moMultiplyBrightness:1.10f]; + } + } + return _normalBorderColor; +} + +- (void)setNormalBorderWidth:(CGFloat)normalBorderWidth { + if(_normalBorderWidth != normalBorderWidth) { + _normalBorderWidth = normalBorderWidth; + [self _updateCurrentState]; + } +} + +- (void)setSelectedBorderWidth:(CGFloat)selectedBorderWidth { + if(_selectedBorderWidth != selectedBorderWidth) { + _selectedBorderWidth = selectedBorderWidth; + [self _updateCurrentState]; + } +} + +- (void)setHighlightedBorderWidth:(CGFloat)highlightedBorderWidth { + if(_highlightedBorderWidth != highlightedBorderWidth) { + _highlightedBorderWidth = highlightedBorderWidth; + [self _updateCurrentState]; + } +} + +- (void)setDisabledBorderWidth:(CGFloat)disabledBorderWidth { + if(_disabledBorderWidth != disabledBorderWidth) { + _disabledBorderWidth = disabledBorderWidth; + [self _updateCurrentState]; + } +} + +- (CGFloat)currentBorderWidth { + if(_normalBorderWidth != 0.0f) { + if(self.isEnabled == NO) { + if(_disabledBorderWidth > MOBILY_EPSILON) { + return _disabledBorderWidth; + } + } else if(self.isHighlighted == YES) { + if(_highlightedBorderWidth > MOBILY_EPSILON) { + return _highlightedBorderWidth; + } + } else if(self.isSelected == YES) { + if(_selectedBorderWidth > MOBILY_EPSILON) { + return _selectedBorderWidth; + } + } + } + return _normalBorderWidth; +} + +- (void)setNormalCornerRadius:(CGFloat)normalCornerRadius { + if(_normalCornerRadius != normalCornerRadius) { + _normalCornerRadius = normalCornerRadius; + [self _updateCurrentState]; + } +} + +- (void)setSelectedCornerRadius:(CGFloat)selectedCornerRadius { + if(_selectedCornerRadius != selectedCornerRadius) { + _selectedCornerRadius = selectedCornerRadius; + [self _updateCurrentState]; + } +} + +- (void)setHighlightedCornerRadius:(CGFloat)highlightedCornerRadius { + if(_highlightedCornerRadius != highlightedCornerRadius) { + _highlightedCornerRadius = highlightedCornerRadius; + [self _updateCurrentState]; + } +} + +- (void)setDisabledCornerRadius:(CGFloat)disabledCornerRadius { + if(_disabledCornerRadius != disabledCornerRadius) { + _disabledCornerRadius = disabledCornerRadius; + [self _updateCurrentState]; + } +} + +- (CGFloat)currentCornerRadius { + if(_normalCornerRadius != 0.0f) { + if(self.isEnabled == NO) { + if(_disabledCornerRadius > MOBILY_EPSILON) { + return _disabledCornerRadius; + } + } else if(self.isHighlighted == YES) { + if(_highlightedCornerRadius > MOBILY_EPSILON) { + return _highlightedCornerRadius; + } + } else if(self.isSelected == YES) { + if(_selectedCornerRadius > MOBILY_EPSILON) { + return _selectedCornerRadius; + } + } + } + return _normalCornerRadius; +} + +- (void)setBadgeView:(MobilyBadgeView*)badgeView { + if(_badgeView != badgeView) { + if(_badgeView != nil) { + [_badgeView removeFromSuperview]; + } + _badgeView = badgeView; + if(_badgeView != nil) { + _badgeView.translatesAutoresizingMaskIntoConstraints = YES; + _badgeView.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin; + [self addSubview:_badgeView]; + } + [self setNeedsUpdateConstraints]; + } +} + +- (MobilyBadgeView*)badgeView { + if(_badgeView == nil) { + self.badgeView = [MobilyBadgeView new]; + } + return _badgeView; +} + +- (void)setBadgeAlias:(MobilyButtonBadgeAlias)badgeAlias { + if(_badgeAlias != badgeAlias) { + _badgeAlias = badgeAlias; + [self setNeedsUpdateConstraints]; + } +} + +- (void)setBadgeHorizontalAlignment:(MobilyButtonBadgeHorizontalAlignment)badgeHorizontalAlignment { + if(_badgeHorizontalAlignment != badgeHorizontalAlignment) { + _badgeHorizontalAlignment = badgeHorizontalAlignment; + [self setNeedsUpdateConstraints]; + } +} + +- (void)setBadgeVerticalAlignment:(MobilyButtonBadgeVerticalAlignment)badgeVerticalAlignment { + if(_badgeVerticalAlignment != badgeVerticalAlignment) { + _badgeVerticalAlignment = badgeVerticalAlignment; + [self setNeedsUpdateConstraints]; + } +} + +#pragma mark Public override + +- (void)didMoveToSuperview { + [super didMoveToSuperview]; + + if(self.superview != nil) { + [self setNeedsLayout]; + } +} + +- (void)didMoveToWindow { + [super didMoveToWindow]; + + if(self.superview != nil) { + [self setNeedsLayout]; + } +} + +- (void)layoutSubviews { + [super layoutSubviews]; + if(((self.currentTitle.length > 0) || (self.currentAttributedTitle.length > 0)) && (self.currentImage != nil)) { + CGRect contentRect = [self contentRectForBounds:self.bounds]; + self.titleLabel.frame = [self titleRectForContentRect:contentRect]; + self.imageView.frame = [self imageRectForContentRect:contentRect]; + } + if(_badgeView != nil) { + UIView* view = nil; + switch(_badgeAlias) { + case MobilyButtonBadgeAliasContent: view = self; break; + case MobilyButtonBadgeAliasTitle: view = self.titleLabel; break; + case MobilyButtonBadgeAliasImage: view = self.imageView; break; + } + CGPoint anchor = CGPointZero; + switch(_badgeHorizontalAlignment) { + case MobilyButtonBadgeHorizontalAlignmentLeft: anchor.x = CGRectGetMinX(view.bounds); break; + case MobilyButtonBadgeHorizontalAlignmentCenter: anchor.x = CGRectGetMidX(view.bounds); break; + case MobilyButtonBadgeHorizontalAlignmentRight: anchor.x = CGRectGetMaxX(view.bounds); break; + } + switch(_badgeVerticalAlignment) { + case MobilyButtonBadgeVerticalAlignmentTop: anchor.y = CGRectGetMinY(view.bounds); break; + case MobilyButtonBadgeVerticalAlignmentCenter: anchor.y = CGRectGetMidY(view.bounds); break; + case MobilyButtonBadgeVerticalAlignmentBottom: anchor.y = CGRectGetMaxY(view.bounds); break; + } + [_badgeView sizeToFit]; + _badgeView.moFrameCenter = [view convertPoint:anchor toView:self]; + } +} + +- (CGSize)sizeThatFits:(CGSize __unused)size { + return [self intrinsicContentSize]; +} + +- (CGSize)intrinsicContentSize { + if(((self.currentTitle.length > 0) || (self.currentAttributedTitle.length > 0)) && (self.currentImage != nil)) { + CGSize boundsSize = CGSizeMake(FLT_MAX, FLT_MAX); + if(self.superview != nil) { + boundsSize = self.superview.frame.size; + } + UIEdgeInsets contentEdgeInsets = self.contentEdgeInsets; + UIEdgeInsets titleEdgeInsets = self.titleEdgeInsets; + UIEdgeInsets imageEdgeInsets = self.imageEdgeInsets; + CGRect contentRect = [super contentRectForBounds:CGRectMake(0.0f, 0.0f, boundsSize.width, boundsSize.height)]; + CGRect titleRect = [super titleRectForContentRect:contentRect]; + CGRect imageRect = [super imageRectForContentRect:contentRect]; + CGSize fullTitleSize = CGSizeMake(titleEdgeInsets.left + titleRect.size.width + titleEdgeInsets.right, titleEdgeInsets.top + titleRect.size.height + titleEdgeInsets.bottom); + CGSize fullImageSize = CGSizeMake(imageEdgeInsets.left + imageRect.size.width + imageEdgeInsets.right, imageEdgeInsets.top + imageRect.size.height + imageEdgeInsets.bottom); + CGSize result = CGSizeMake(contentEdgeInsets.left + contentEdgeInsets.right, contentEdgeInsets.top + contentEdgeInsets.bottom); + switch(_imageAlignment) { + case MobilyButtonImageAlignmentLeft: + case MobilyButtonImageAlignmentRight: + result.width += fullTitleSize.width + fullImageSize.width; + result.height += MAX(fullTitleSize.height, fullImageSize.height); + break; + case MobilyButtonImageAlignmentTop: + case MobilyButtonImageAlignmentBottom: + result.width += MAX(fullTitleSize.width, fullImageSize.width); + result.height += fullTitleSize.height + fullImageSize.height; + break; + } + return result; + } + return [super intrinsicContentSize]; +} + +- (CGRect)titleRectForContentRect:(CGRect)contentRect { + if(((self.currentTitle.length > 0) || (self.currentAttributedTitle.length > 0)) && (self.currentImage != nil)) { + CGRect titleRect = [super titleRectForContentRect:CGRectMake(0.0f, 0.0f, FLT_MAX, FLT_MAX)]; + CGRect imageRect = [super imageRectForContentRect:CGRectMake(0.0f, 0.0f, FLT_MAX, FLT_MAX)]; + [self _layoutContentRect:contentRect imageRect:&imageRect imageEdgeInsets:self.imageEdgeInsets imageSize:self.currentImage.size titleRect:&titleRect titleEdgeInsets:self.titleEdgeInsets]; + return titleRect; + } + return [super titleRectForContentRect:contentRect]; +} + +- (CGRect)imageRectForContentRect:(CGRect)contentRect { + if(((self.currentTitle.length > 0) || (self.currentAttributedTitle.length > 0)) && (self.currentImage != nil)) { + CGRect titleRect = [super titleRectForContentRect:CGRectMake(0.0f, 0.0f, FLT_MAX, FLT_MAX)]; + CGRect imageRect = [super imageRectForContentRect:CGRectMake(0.0f, 0.0f, FLT_MAX, FLT_MAX)]; + [self _layoutContentRect:contentRect imageRect:&imageRect imageEdgeInsets:self.imageEdgeInsets imageSize:self.currentImage.size titleRect:&titleRect titleEdgeInsets:self.titleEdgeInsets]; + return imageRect; + } + return [super imageRectForContentRect:contentRect]; +} + +#pragma mark Private + +- (void)_layoutContentRect:(CGRect)contentRect imageRect:(CGRect*)imageRect imageEdgeInsets:(UIEdgeInsets)imageEdgeInsets imageSize:(CGSize)imageSize titleRect:(CGRect*)titleRect titleEdgeInsets:(UIEdgeInsets)titleEdgeInsets { + imageRect->size.width = imageSize.width; + imageRect->size.height = imageSize.height; + CGSize fullImageSize = CGSizeMake(imageEdgeInsets.left + imageRect->size.width + imageEdgeInsets.right, imageEdgeInsets.top + imageRect->size.height + imageEdgeInsets.bottom); + CGSize fullTitleSize = CGSizeMake(titleEdgeInsets.left + titleRect->size.width + titleEdgeInsets.right, titleEdgeInsets.top + titleRect->size.height + titleEdgeInsets.bottom); + CGSize fullSize = CGSizeMake(fullImageSize.width + fullTitleSize.width, fullImageSize.height + fullTitleSize.height); + switch(self.contentHorizontalAlignment) { + case UIControlContentHorizontalAlignmentLeft: { + switch(_imageAlignment) { + case MobilyButtonImageAlignmentTop: + case MobilyButtonImageAlignmentBottom: + imageRect->origin.x = contentRect.origin.x + imageEdgeInsets.left; + titleRect->origin.x = contentRect.origin.x + titleEdgeInsets.left; + break; + case MobilyButtonImageAlignmentLeft: + imageRect->origin.x = contentRect.origin.x + imageEdgeInsets.left; + titleRect->origin.x = (imageRect->origin.x + imageRect->size.width + imageEdgeInsets.right) + titleEdgeInsets.left; + break; + case MobilyButtonImageAlignmentRight: + titleRect->origin.x = contentRect.origin.x + titleEdgeInsets.left; + imageRect->origin.x = (titleRect->origin.x + titleRect->size.width + titleEdgeInsets.right) + imageEdgeInsets.left; + break; + } + break; + } + case UIControlContentHorizontalAlignmentCenter: { + switch(_imageAlignment) { + case MobilyButtonImageAlignmentTop: + case MobilyButtonImageAlignmentBottom: + imageRect->origin.x = (contentRect.origin.x + (contentRect.size.width * 0.5f)) - (imageRect->size.width * 0.5f); + titleRect->origin.x = (contentRect.origin.x + (contentRect.size.width * 0.5f)) - (titleRect->size.width * 0.5f); + break; + case MobilyButtonImageAlignmentLeft: + imageRect->origin.x = ((contentRect.origin.x + (contentRect.size.width * 0.5f)) - (fullSize.width * 0.5f)) + imageEdgeInsets.left; + titleRect->origin.x = (imageRect->origin.x + imageRect->size.width + imageEdgeInsets.right) + titleEdgeInsets.left; + break; + case MobilyButtonImageAlignmentRight: + titleRect->origin.x = ((contentRect.origin.x + (contentRect.size.width * 0.5f)) - (fullSize.width * 0.5f)) + titleEdgeInsets.left; + imageRect->origin.x = (titleRect->origin.x + titleRect->size.width + titleEdgeInsets.right) + imageEdgeInsets.left; + break; + } + break; + } + case UIControlContentHorizontalAlignmentRight: { + switch(_imageAlignment) { + case MobilyButtonImageAlignmentTop: + case MobilyButtonImageAlignmentBottom: + imageRect->origin.x = (contentRect.origin.x + contentRect.size.width) - (imageRect->size.width + imageEdgeInsets.right); + titleRect->origin.x = (contentRect.origin.x + contentRect.size.width) - (titleRect->size.width + titleEdgeInsets.right); + break; + case MobilyButtonImageAlignmentLeft: + titleRect->origin.x = (contentRect.origin.x + contentRect.size.width) - (titleRect->size.width + titleEdgeInsets.right); + imageRect->origin.x = (titleRect->origin.x - titleEdgeInsets.left) - (imageRect->size.width + imageEdgeInsets.right); + break; + case MobilyButtonImageAlignmentRight: + imageRect->origin.x = (contentRect.origin.x + contentRect.size.width) - (imageRect->size.width + imageEdgeInsets.right); + titleRect->origin.x = (imageRect->origin.x - imageEdgeInsets.left) - (titleRect->size.width + titleEdgeInsets.right); + break; + } + break; + } + case UIControlContentHorizontalAlignmentFill: { + switch(_imageAlignment) { + case MobilyButtonImageAlignmentLeft: + imageRect->origin.x = contentRect.origin.x + imageEdgeInsets.left; + titleRect->origin.x = (imageRect->origin.x + imageRect->size.width + imageEdgeInsets.right) + titleEdgeInsets.left; + titleRect->size.width = contentRect.size.width - (imageEdgeInsets.left + imageRect->size.width + imageEdgeInsets.right + titleEdgeInsets.left + titleEdgeInsets.right); + break; + case MobilyButtonImageAlignmentRight: + titleRect->origin.x = contentRect.origin.x + titleEdgeInsets.left; + titleRect->size.width = contentRect.size.width - (imageEdgeInsets.left + imageRect->size.width + imageEdgeInsets.right + titleEdgeInsets.left + titleEdgeInsets.right); + imageRect->origin.x = (titleRect->origin.x + titleRect->size.width + titleEdgeInsets.right) + imageEdgeInsets.left; + break; + default: + imageRect->origin.x = contentRect.origin.x + imageEdgeInsets.left; + imageRect->size.width = contentRect.size.width - (imageEdgeInsets.left + imageEdgeInsets.right); + titleRect->origin.x = contentRect.origin.x + titleEdgeInsets.left; + titleRect->size.width = contentRect.size.width - (titleEdgeInsets.left + titleEdgeInsets.right); + break; + } + break; + } + } + switch(self.contentVerticalAlignment) { + case UIControlContentVerticalAlignmentTop: { + switch(_imageAlignment) { + case MobilyButtonImageAlignmentTop: + imageRect->origin.y = contentRect.origin.y + imageEdgeInsets.top; + titleRect->origin.y = (imageRect->origin.y + imageRect->size.height + imageEdgeInsets.bottom) + titleEdgeInsets.top; + break; + case MobilyButtonImageAlignmentBottom: + imageRect->origin.y = (contentRect.origin.y + contentRect.size.height) + imageEdgeInsets.top; + titleRect->origin.y = (imageRect->origin.y - imageEdgeInsets.top) + titleEdgeInsets.bottom; + break; + case MobilyButtonImageAlignmentLeft: + case MobilyButtonImageAlignmentRight: + imageRect->origin.y = contentRect.origin.y + imageEdgeInsets.top; + titleRect->origin.y = contentRect.origin.y + titleEdgeInsets.top; + break; + } + break; + } + case UIControlContentVerticalAlignmentCenter: { + switch(_imageAlignment) { + case MobilyButtonImageAlignmentTop: + imageRect->origin.y = ((contentRect.origin.y + (contentRect.size.height * 0.5f)) - (fullSize.height * 0.5f)) + imageEdgeInsets.top; + titleRect->origin.y = (imageRect->origin.y + imageRect->size.height + imageEdgeInsets.bottom) + titleEdgeInsets.top; + break; + case MobilyButtonImageAlignmentBottom: + titleRect->origin.y = ((contentRect.origin.y + (contentRect.size.height * 0.5f)) - (fullSize.height * 0.5f)) + titleEdgeInsets.top; + imageRect->origin.y = (titleRect->origin.y + titleRect->size.height + titleEdgeInsets.bottom) + imageEdgeInsets.top; + break; + case MobilyButtonImageAlignmentLeft: + case MobilyButtonImageAlignmentRight: + imageRect->origin.y = (contentRect.origin.y + (contentRect.size.height * 0.5f)) - (imageRect->size.height * 0.5f); + titleRect->origin.y = (contentRect.origin.y + (contentRect.size.height * 0.5f)) - (titleRect->size.height * 0.5f); + break; + } + break; + } + case UIControlContentVerticalAlignmentBottom: { + switch(_imageAlignment) { + case MobilyButtonImageAlignmentTop: + titleRect->origin.y = (contentRect.origin.y + contentRect.size.height) - (titleRect->size.width + titleEdgeInsets.bottom); + imageRect->origin.y = (titleRect->origin.y - titleEdgeInsets.top) - (imageRect->size.height + imageEdgeInsets.bottom); + break; + case MobilyButtonImageAlignmentBottom: + imageRect->origin.y = (contentRect.origin.y + contentRect.size.height) - (imageRect->size.width + imageEdgeInsets.bottom); + titleRect->origin.y = (imageRect->origin.y - imageEdgeInsets.top) - (titleRect->size.height + titleEdgeInsets.bottom); + break; + case MobilyButtonImageAlignmentLeft: + case MobilyButtonImageAlignmentRight: + imageRect->origin.y = (contentRect.origin.y + contentRect.size.height) - (imageRect->size.height + imageEdgeInsets.bottom); + titleRect->origin.y = (contentRect.origin.y + contentRect.size.height) - (titleRect->size.height + titleEdgeInsets.bottom); + break; + } + break; + } + case UIControlContentVerticalAlignmentFill: { + switch(_imageAlignment) { + case MobilyButtonImageAlignmentTop: + imageRect->origin.y = contentRect.origin.y + imageEdgeInsets.top; + titleRect->origin.y = (imageRect->origin.y + imageRect->size.height + imageEdgeInsets.bottom) + titleEdgeInsets.top; + titleRect->size.height = contentRect.size.height - (imageEdgeInsets.top + imageRect->size.height + imageEdgeInsets.bottom + titleEdgeInsets.top + titleEdgeInsets.bottom); + break; + case MobilyButtonImageAlignmentBottom: + titleRect->origin.y = contentRect.origin.y + titleEdgeInsets.top; + titleRect->size.height = contentRect.size.height - (imageEdgeInsets.top + imageRect->size.height + imageEdgeInsets.bottom + titleEdgeInsets.top + titleEdgeInsets.bottom); + imageRect->origin.y = (titleRect->origin.y + titleRect->size.height + titleEdgeInsets.bottom) + imageEdgeInsets.top; + break; + default: + imageRect->origin.y = contentRect.origin.y + imageEdgeInsets.top; + imageRect->size.height = contentRect.size.height - (imageEdgeInsets.top + imageEdgeInsets.bottom); + titleRect->origin.y = contentRect.origin.y + titleEdgeInsets.top; + titleRect->size.height = contentRect.size.height - (titleEdgeInsets.top + titleEdgeInsets.bottom); + break; + } + break; + } + } +} + +- (void)_updateCurrentState { + UIColor* backgroundColor = [self currentBackgroundColor]; + if(backgroundColor != nil) { + self.backgroundColor = backgroundColor; + } + self.moBorderColor = [self currentBorderColor]; + self.moBorderWidth = [self currentBorderWidth]; + self.moCornerRadius = [self currentCornerRadius]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyCA.h b/Sources/MobilyCore/MobilyCA.h new file mode 100644 index 0000000..4d60275 --- /dev/null +++ b/Sources/MobilyCore/MobilyCA.h @@ -0,0 +1,47 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#ifndef MOBILY_CA +#define MOBILY_CA +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +CATransform3D MobilyTransform3DRotationWithPerspective(CGFloat perspective, CGFloat angle, CGFloat x, CGFloat y, CGFloat z); + +/*--------------------------------------------------*/ +#endif +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyCA.m b/Sources/MobilyCore/MobilyCA.m new file mode 100644 index 0000000..e25c236 --- /dev/null +++ b/Sources/MobilyCore/MobilyCA.m @@ -0,0 +1,48 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#include + +/*--------------------------------------------------*/ + +CATransform3D MobilyTransform3DRotationWithPerspective(CGFloat perspective, CGFloat angle, CGFloat x, CGFloat y, CGFloat z) { + CATransform3D transform = CATransform3DIdentity; + transform.m34 = perspective; + return CATransform3DRotate(transform, angle, x, y, z); +} + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyCG.h b/Sources/MobilyCore/MobilyCG.h new file mode 100644 index 0000000..8878517 --- /dev/null +++ b/Sources/MobilyCore/MobilyCG.h @@ -0,0 +1,132 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#ifndef MOBILY_CG +#define MOBILY_CG +/*--------------------------------------------------*/ + +#import +#import +#import +#import + +/*--------------------------------------------------*/ + +typedef struct { + CGPoint start; + CGPoint end; +} MobilyLineSegment; + +/*--------------------------------------------------*/ + +@interface NSString (MobilyCG) + +- (CGPoint)moConvertToPoint; +- (CGPoint)moConvertToPointSeparated:(NSString*)separated; +- (CGSize)moConvertToSize; +- (CGSize)moConvertToSizeSeparated:(NSString*)separated; +- (CGRect)moConvertToRect; +- (CGRect)moConvertToRectSeparated:(NSString*)separated; + +@end + +/*--------------------------------------------------*/ + +#define MOBILY_DEG_TO_RAD 0.0174532925f + +/*--------------------------------------------------*/ + +CGFloat MobilyFloatNearestMore(CGFloat value, CGFloat step); + +/*--------------------------------------------------*/ + +CG_EXTERN const CGPoint MobilyPointInfinity; + +bool MobilyPointIsInfinity(CGPoint point); + +CGPoint MobilyPointAdd(CGPoint point, CGFloat value); +CGPoint MobilyPointSub(CGPoint point, CGFloat value); +CGPoint MobilyPointMul(CGPoint point, CGFloat value); +CGPoint MobilyPointDiv(CGPoint point, CGFloat value); +CGPoint MobilyPointAddPoint(CGPoint point1, CGPoint point2); +CGPoint MobilyPointSubPoint(CGPoint point1, CGPoint point2); +CGPoint MobilyPointMulPoint(CGPoint point1, CGPoint point2); +CGPoint MobilyPointDivPoint(CGPoint point1, CGPoint point2); + +CGPoint MobilyPointRotateAroundPoint(CGPoint point, CGPoint pivot, CGFloat angle); + +CGFloat MobilyPointDistance(CGPoint p1, CGPoint p2); + +/*--------------------------------------------------*/ + +CGSize MobilySizeNearestMore(CGSize size, CGFloat step); +CGSize MobilySizeAdd(CGSize size, CGFloat value); +CGSize MobilySizeSub(CGSize size, CGFloat value); +CGSize MobilySizeMul(CGSize size, CGFloat value); +CGSize MobilySizeDiv(CGSize size, CGFloat value); + +/*--------------------------------------------------*/ + +CGRect MobilyRectMakeOriginAndSize(CGPoint origin, CGSize size); +CGRect MobilyRectMakeCenterPoint(CGPoint center, CGFloat width, CGFloat height); + +CGRect MobilyRectAdd(CGRect rect, CGFloat value); +CGRect MobilyRectSub(CGRect rect, CGFloat value); +CGRect MobilyRectMul(CGRect rect, CGFloat value); +CGRect MobilyRectDiv(CGRect rect, CGFloat value); +CGRect MobilyRectLerp(CGRect rect1, CGRect rect2, CGFloat t); +CGRect MobilyRectAspectFillFromBoundsAndSize(CGRect bounds, CGSize size); +CGRect MobilyRectAspectFitFromBoundsAndSize(CGRect bounds, CGSize size); + +CGRect MobilyRectScaleAroundPoint(CGRect rect, CGPoint point, CGFloat sx, CGFloat sy); + +CGPoint MobilyRectGetTopLeftPoint(CGRect rect); +CGPoint MobilyRectGetTopCenterPoint(CGRect rect); +CGPoint MobilyRectGetTopRightPoint(CGRect rect); +CGPoint MobilyRectGetLeftPoint(CGRect rect); +CGPoint MobilyRectGetCenterPoint(CGRect rect); +CGPoint MobilyRectGetRightPoint(CGRect rect); +CGPoint MobilyRectGetBottomLeftPoint(CGRect rect); +CGPoint MobilyRectGetBottomCenterPoint(CGRect rect); +CGPoint MobilyRectGetBottomRightPoint(CGRect rect); + +/*--------------------------------------------------*/ + +MobilyLineSegment MobilyLineSegmentMake(CGPoint start, CGPoint end); +MobilyLineSegment MobilyLineSegmentRotateAroundPoint(MobilyLineSegment line, CGPoint pivot, CGFloat angle); +CGPoint MobilyLineSegmentIntersection(MobilyLineSegment ls1, MobilyLineSegment ls2); + +/*--------------------------------------------------*/ +#endif +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyCG.m b/Sources/MobilyCore/MobilyCG.m new file mode 100644 index 0000000..7c25d1f --- /dev/null +++ b/Sources/MobilyCore/MobilyCG.m @@ -0,0 +1,386 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#include + +/*--------------------------------------------------*/ + +#include + +/*--------------------------------------------------*/ + +@implementation NSString (MobilyCG) + +- (CGPoint)moConvertToPoint { + return [self moConvertToPointSeparated:@";"]; +} + +- (CGPoint)moConvertToPointSeparated:(NSString*)separated { + CGPoint result = CGPointZero; + static NSNumberFormatter* formatter = nil; + if(formatter == nil) { + formatter = [NSNumberFormatter new]; + formatter.numberStyle = NSNumberFormatterDecimalStyle; + } + NSArray* array = [self componentsSeparatedByString:separated]; + switch(array.count) { + case 1: { + result.x = [[formatter numberFromString:array[0]] floatValue]; + result.y = result.x; + break; + } + case 2: { + result.x = [[formatter numberFromString:array[0]] floatValue]; + result.y = [[formatter numberFromString:array[1]] floatValue]; + break; + } + default: + break; + } + return result; +} + +- (CGSize)moConvertToSize { + return [self moConvertToSizeSeparated:@";"]; +} + +- (CGSize)moConvertToSizeSeparated:(NSString*)separated { + CGSize result = CGSizeZero; + static NSNumberFormatter* formatter = nil; + if(formatter == nil) { + formatter = [NSNumberFormatter new]; + formatter.numberStyle = NSNumberFormatterDecimalStyle; + } + NSArray* array = [self componentsSeparatedByString:separated]; + switch(array.count) { + case 1: { + result.width = [[formatter numberFromString:array[0]] floatValue]; + result.height = result.width; + break; + } + case 2: { + result.width = [[formatter numberFromString:array[0]] floatValue]; + result.height = [[formatter numberFromString:array[1]] floatValue]; + break; + } + default: + break; + } + return result; +} + +- (CGRect)moConvertToRect { + return [self moConvertToRectSeparated:@";"]; +} + +- (CGRect)moConvertToRectSeparated:(NSString*)separated { + CGRect result = CGRectZero; + static NSNumberFormatter* formatter = nil; + if(formatter == nil) { + formatter = [NSNumberFormatter new]; + formatter.numberStyle = NSNumberFormatterDecimalStyle; + } + NSArray* array = [self componentsSeparatedByString:separated]; + switch(array.count) { + case 1: { + result.size.width = [[formatter numberFromString:array[0]] floatValue]; + result.size.height = result.size.width; + break; + } + case 2: { + result.size.width = [[formatter numberFromString:array[0]] floatValue]; + result.size.height = [[formatter numberFromString:array[1]] floatValue]; + break; + } + case 3: { + result.origin.x = [[formatter numberFromString:array[0]] floatValue]; + result.origin.y = [[formatter numberFromString:array[1]] floatValue]; + result.size.width = [[formatter numberFromString:array[2]] floatValue]; + result.size.height = result.size.width; + break; + } + case 4: { + result.origin.x = [[formatter numberFromString:array[0]] floatValue]; + result.origin.y = [[formatter numberFromString:array[1]] floatValue]; + result.size.width = [[formatter numberFromString:array[2]] floatValue]; + result.size.height = [[formatter numberFromString:array[3]] floatValue]; + break; + } + default: + break; + } + return result; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +CGFloat MobilyFloatNearestMore(CGFloat value, CGFloat step) { + CGFloat result = step; + while(result < value) { + result += step; + } + return result; +} + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +const CGPoint MobilyPointInfinity = { INFINITY, INFINITY }; + +bool MobilyPointIsInfinity(CGPoint point) { + return CGPointEqualToPoint(point, MobilyPointInfinity); +} + +CGPoint MobilyPointAdd(CGPoint point, CGFloat value) { + return CGPointMake(point.x + value, point.y + value); +} + +CGPoint MobilyPointSub(CGPoint point, CGFloat value) { + return CGPointMake(point.x - value, point.y - value); +} + +CGPoint MobilyPointMul(CGPoint point, CGFloat value) { + return CGPointMake(point.x * value, point.y * value); +} + +CGPoint MobilyPointDiv(CGPoint point, CGFloat value) { + return CGPointMake(point.x / value, point.y / value); +} + +CGPoint MobilyPointAddPoint(CGPoint point1, CGPoint point2) { + return CGPointMake(point1.x + point2.x, point1.y + point2.y); +} + +CGPoint MobilyPointSubPoint(CGPoint point1, CGPoint point2) { + return CGPointMake(point1.x - point2.x, point1.y - point2.y); +} + +CGPoint MobilyPointMulPoint(CGPoint point1, CGPoint point2) { + return CGPointMake(point1.x * point2.x, point1.y * point2.y); +} + +CGPoint MobilyPointDivPoint(CGPoint point1, CGPoint point2) { + return CGPointMake(point1.x / point2.x, point1.y / point2.y); +} + +CGPoint MobilyPointRotateAroundPoint(CGPoint point, CGPoint pivot, CGFloat angle) { + point = CGPointApplyAffineTransform(point, CGAffineTransformMakeTranslation(-pivot.x, -pivot.y)); + point = CGPointApplyAffineTransform(point, CGAffineTransformMakeRotation(angle)); + point = CGPointApplyAffineTransform(point, CGAffineTransformMakeTranslation(pivot.x, pivot.y)); + return point; +} + +CGFloat MobilyPointDistance(CGPoint p1, CGPoint p2) { + return MOBILY_SQRT(MOBILY_POW(p1.x - p2.x, 2) + MOBILY_POW(p1.y - p2.y, 2)); +} + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +CGSize MobilySizeNearestMore(CGSize size, CGFloat step) { + return CGSizeMake(MobilyFloatNearestMore(size.width, step), MobilyFloatNearestMore(size.height, step)); +} + +CGSize MobilySizeAdd(CGSize size, CGFloat value) { + return CGSizeMake(size.width + value, size.height + value); +} + +CGSize MobilySizeSub(CGSize size, CGFloat value) { + return CGSizeMake(size.width - value, size.height - value); +} + +CGSize MobilySizeMul(CGSize size, CGFloat value) { + return CGSizeMake(size.width * value, size.height * value); +} + +CGSize MobilySizeDiv(CGSize size, CGFloat value) { + return CGSizeMake(size.width / value, size.height / value); +} + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +CGRect MobilyRectMakeOriginAndSize(CGPoint origin, CGSize size) { + return CGRectMake(origin.x, origin.y, size.width, size.height); +} + +CGRect MobilyRectMakeCenterPoint(CGPoint center, CGFloat width, CGFloat height) { + return CGRectMake(center.x - (width * 0.5f), center.y - (height * 0.5f), width, height); +} + +CGRect MobilyRectAdd(CGRect rect, CGFloat value) { + return CGRectMake(rect.origin.x + value, rect.origin.y + value, rect.size.width + value, rect.size.height + value); +} + +CGRect MobilyRectSub(CGRect rect, CGFloat value) { + return CGRectMake(rect.origin.x - value, rect.origin.y - value, rect.size.width - value, rect.size.height - value); +} + +CGRect MobilyRectMul(CGRect rect, CGFloat value) { + return CGRectMake(rect.origin.x * value, rect.origin.y * value, rect.size.width * value, rect.size.height * value); +} + +CGRect MobilyRectDiv(CGRect rect, CGFloat value) { + return CGRectMake(rect.origin.x / value, rect.origin.y / value, rect.size.width / value, rect.size.height / value); +} + +CGRect MobilyRectLerp(CGRect rect1, CGRect rect2, CGFloat t) { + return CGRectMake( + ((1.0f - t) * rect1.origin.x) + (t * rect2.origin.x), + ((1.0f - t) * rect1.origin.y) + (t * rect2.origin.y), + ((1.0f - t) * rect1.size.width) + (t * rect2.size.width), + ((1.0f - t) * rect1.size.height) + (t * rect2.size.height) + ); +} + +CGRect MobilyRectAspectFillFromBoundsAndSize(CGRect bounds, CGSize size) { + CGFloat iw = MOBILY_FLOOR(size.width); + CGFloat ih = MOBILY_FLOOR(size.height); + CGFloat bw = MOBILY_FLOOR(bounds.size.width); + CGFloat bh = MOBILY_FLOOR(bounds.size.height); + CGFloat fw = bw / iw; + CGFloat fh = bh / ih; + CGFloat scale = (fw > fh) ? fw : fh; + CGFloat rw = iw * scale; + CGFloat rh = ih * scale; + CGFloat rx = (bw - rw) * 0.5f; + CGFloat ry = (bh - rh) * 0.5f; + return CGRectMake(bounds.origin.x + rx, bounds.origin.y + ry, rw, rh); +} + +CGRect MobilyRectAspectFitFromBoundsAndSize(CGRect bounds, CGSize size) { + CGFloat iw = MOBILY_FLOOR(size.width); + CGFloat ih = MOBILY_FLOOR(size.height); + CGFloat bw = MOBILY_FLOOR(bounds.size.width); + CGFloat bh = MOBILY_FLOOR(bounds.size.height); + CGFloat fw = bw / iw; + CGFloat fh = bh / ih; + CGFloat scale = (fw < fh) ? fw : fh; + CGFloat rw = iw * scale; + CGFloat rh = ih * scale; + CGFloat rx = (bw - rw) * 0.5f; + CGFloat ry = (bh - rh) * 0.5f; + return CGRectMake(bounds.origin.x + rx, bounds.origin.y + ry, rw, rh); +} + +CGRect MobilyRectScaleAroundPoint(CGRect rect, CGPoint point, CGFloat sx, CGFloat sy) { + rect = CGRectApplyAffineTransform(rect, CGAffineTransformMakeTranslation(-point.x, -point.y)); + rect = CGRectApplyAffineTransform(rect, CGAffineTransformMakeScale(sx, sy)); + rect = CGRectApplyAffineTransform(rect, CGAffineTransformMakeTranslation(point.x, point.y)); + return rect; +} + +CGPoint MobilyRectGetTopLeftPoint(CGRect rect) { + return CGPointMake(CGRectGetMinX(rect), CGRectGetMinY(rect)); +} + +CGPoint MobilyRectGetTopCenterPoint(CGRect rect) { + return CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect)); +} + +CGPoint MobilyRectGetTopRightPoint(CGRect rect) { + return CGPointMake(CGRectGetMaxX(rect), CGRectGetMinY(rect)); +} + +CGPoint MobilyRectGetLeftPoint(CGRect rect) { + return CGPointMake(CGRectGetMinX(rect), CGRectGetMidY(rect)); +} + +CGPoint MobilyRectGetCenterPoint(CGRect rect) { + return CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect)); +} + +CGPoint MobilyRectGetRightPoint(CGRect rect) { + return CGPointMake(CGRectGetMaxX(rect), CGRectGetMidY(rect)); +} + +CGPoint MobilyRectGetBottomLeftPoint(CGRect rect) { + return CGPointMake(CGRectGetMinX(rect), CGRectGetMaxY(rect)); +} + +CGPoint MobilyRectGetBottomCenterPoint(CGRect rect) { + return CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect)); +} + +CGPoint MobilyRectGetBottomRightPoint(CGRect rect) { + return CGPointMake(CGRectGetMaxX(rect), CGRectGetMaxY(rect)); +} + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +MobilyLineSegment MobilyLineSegmentMake(CGPoint start, CGPoint end) { + return (MobilyLineSegment){ start, end }; +} + +MobilyLineSegment MobilyLineSegmentRotateAroundPoint(MobilyLineSegment line, CGPoint pivot, CGFloat angle) { + return MobilyLineSegmentMake(MobilyPointRotateAroundPoint(line.start, pivot, angle), MobilyPointRotateAroundPoint(line.end, pivot, angle)); +} + +CGPoint MobilyLineSegmentIntersection(MobilyLineSegment ls1, MobilyLineSegment ls2) { + CGFloat x1 = ls1.start.x, y1 = ls1.start.y; + CGFloat x2 = ls1.end.x, y2 = ls1.end.y; + CGFloat x3 = ls2.start.x, y3 = ls2.start.y; + CGFloat x4 = ls2.end.x, y4 = ls2.end.y; + CGFloat numeratorA = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3); + CGFloat numeratorB = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3); + CGFloat denominator = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); + if((MOBILY_FABS(numeratorA) < MOBILY_EPSILON) && (MOBILY_FABS(numeratorB) < MOBILY_EPSILON) && (MOBILY_FABS(denominator) < MOBILY_EPSILON)) { + return CGPointMake((x1 + x2) * 0.5f, (y1 + y2) * 0.5f); + } + if(MOBILY_FABS(denominator) < MOBILY_EPSILON) { + return MobilyPointInfinity; + } + CGFloat uA = numeratorA / denominator; + CGFloat uB = numeratorB / denominator; + if((uA < 0.0f) || (uA > 1.0f) || (uB < 0.0f) || (uB > 1.0f)) { + return MobilyPointInfinity; + } + return CGPointMake(x1 + uA * (x2 - x1), y1 + uA * (y2 - y1)); +} + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyCache.h b/Sources/MobilyCore/MobilyCache.h new file mode 100644 index 0000000..8a8d3ef --- /dev/null +++ b/Sources/MobilyCore/MobilyCache.h @@ -0,0 +1,81 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef void (^MobilyCacheDataForKey)(NSData* data); +typedef void (^MobilyCacheComplete)(); + +/*--------------------------------------------------*/ + +@interface MobilyCache : NSObject< MobilyObject > + +@property(nonatomic, readonly, copy) NSString* name; +@property(nonatomic, readwrite, assign) NSUInteger memoryCapacity; +@property(nonatomic, readonly, assign) NSTimeInterval memoryStorageInterval; +@property(nonatomic, readwrite, assign) NSUInteger discCapacity; +@property(nonatomic, readonly, assign) NSTimeInterval discStorageInterval; +@property(nonatomic, readonly, assign) NSUInteger currentMemoryUsage; +@property(nonatomic, readonly, assign) NSUInteger currentDiscUsage; + ++ (instancetype)shared; + +- (instancetype)initWithName:(NSString*)name; +- (instancetype)initWithName:(NSString*)name memoryCapacity:(NSUInteger)memoryCapacity discCapacity:(NSUInteger)discCapacity; +- (instancetype)initWithName:(NSString*)name memoryCapacity:(NSUInteger)memoryCapacity memoryStorageInterval:(NSTimeInterval)memoryStorageInterval discCapacity:(NSUInteger)discCapacity discStorageInterval:(NSTimeInterval)discStorageInterval; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)setCacheData:(NSData*)data forKey:(NSString*)key; +- (void)setCacheData:(NSData*)data forKey:(NSString*)key complete:(MobilyCacheComplete)complete; +- (void)setCacheData:(NSData*)data forKey:(NSString*)key memoryStorageInterval:(NSTimeInterval)memoryStorageInterval; +- (void)setCacheData:(NSData*)data forKey:(NSString*)key memoryStorageInterval:(NSTimeInterval)memoryStorageInterval complete:(MobilyCacheComplete)complete; +- (void)setCacheData:(NSData*)data forKey:(NSString*)key discStorageInterval:(NSTimeInterval)discStorageInterval; +- (void)setCacheData:(NSData*)data forKey:(NSString*)key discStorageInterval:(NSTimeInterval)discStorageInterval complete:(MobilyCacheComplete)complete; +- (void)setCacheData:(NSData*)data forKey:(NSString*)key memoryStorageInterval:(NSTimeInterval)memoryStorageInterval discStorageInterval:(NSTimeInterval)discStorageInterval; +- (void)setCacheData:(NSData*)data forKey:(NSString*)key memoryStorageInterval:(NSTimeInterval)memoryStorageInterval discStorageInterval:(NSTimeInterval)discStorageInterval complete:(MobilyCacheComplete)complete; +- (NSData*)cacheDataForKey:(NSString*)key; +- (void)cacheDataForKey:(NSString*)key complete:(MobilyCacheDataForKey)complete; + +- (void)removeCacheDataForKey:(NSString*)key; +- (void)removeCacheDataForKey:(NSString*)key complete:(MobilyCacheComplete)complete; +- (void)removeAllCachedData; +- (void)removeAllCachedDataComplete:(MobilyCacheComplete)complete; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyCache.m b/Sources/MobilyCore/MobilyCache.m new file mode 100644 index 0000000..4920636 --- /dev/null +++ b/Sources/MobilyCore/MobilyCache.m @@ -0,0 +1,565 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyCache () < MobilyTimerDelegate > + +@property(nonatomic, readwrite, copy) NSString* name; +@property(nonatomic, readwrite, strong) NSString* fileName; +@property(nonatomic, readwrite, strong) NSString* filePath; +@property(nonatomic, readwrite, assign) NSTimeInterval memoryStorageInterval; +@property(nonatomic, readwrite, assign) NSTimeInterval discStorageInterval; +@property(nonatomic, readwrite, assign) NSUInteger currentMemoryUsage; +@property(nonatomic, readwrite, assign) NSUInteger currentDiscUsage; + +@property(nonatomic, readwrite, strong) MobilyTimer* timer; +@property(nonatomic, readwrite, strong) NSMutableArray* items; + +- (void)removeObsoleteItemsInViewOfReserveSize:(NSUInteger)reserveSize; +- (void)removeObsoleteItems; +- (void)saveItems; + +- (void)notificationReceiveMemoryWarning:(NSNotification*)notification; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyCacheItem : MobilyModel + +@property(nonatomic, readwrite, weak) MobilyCache* cache; +@property(nonatomic, readwrite, strong) NSString* key; +@property(nonatomic, readwrite, strong) NSString* fileName; +@property(nonatomic, readonly, strong) NSString* filePath; +@property(nonatomic, readonly, strong) NSData* data; +@property(nonatomic, readonly, assign) NSUInteger size; +@property(nonatomic, readonly, assign) NSTimeInterval memoryStorageInterval; +@property(nonatomic, readonly, assign) NSTimeInterval memoryStorageTime; +@property(nonatomic, readonly, assign) NSTimeInterval discStorageInterval; +@property(nonatomic, readonly, assign) NSTimeInterval discStorageTime; +@property(nonatomic, readonly, assign, getter=isInMemory) BOOL inMemory; + +- (instancetype)initWithCache:(MobilyCache*)cache key:(NSString*)key data:(NSData*)data memoryStorageInterval:(NSTimeInterval)memoryStorageInterval discStorageInterval:(NSTimeInterval)discStorageInterval; + +- (void)updateData:(NSData*)data memoryStorageInterval:(NSTimeInterval)memoryStorageInterval discStorageInterval:(NSTimeInterval)discStorageInterval; + +- (void)saveToDiscCache; +- (void)clearFromMemoryCache; +- (void)clearFromDiscCache; +- (void)clearFromAllCache; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#define MOBILY_CACHE_NAME @"MobilyCache" +#define MOBILY_CACHE_EXTENSION @"cache" +#define MOBILY_CACHE_MEMORY_CAPACITY (1024 * 1024) * 30 +#define MOBILY_CACHE_MEMORY_STORAGE_INTERVAL (60 * 10) +#define MOBILY_CACHE_DISC_CAPACITY (1024 * 1024) * 500 +#define MOBILY_CACHE_DISC_STORAGE_INTERVAL ((60 * 60) * 24) * 7 + +/*--------------------------------------------------*/ + +@implementation MobilyCache + +#pragma mark Singleton + ++ (instancetype)shared { + static id shared = nil; + if(shared == nil) { + @synchronized(self) { + if(shared == nil) { + NSBundle* bundle = NSBundle.mainBundle; + NSString* name = [bundle moObjectForInfoDictionaryKey:@"MobilyCacheName" defaultValue:MOBILY_CACHE_NAME]; + NSNumber* memoryCapacity = [bundle moObjectForInfoDictionaryKey:@"MobilyCacheMemoryCapacity" defaultValue:@(MOBILY_CACHE_MEMORY_CAPACITY)]; + NSNumber* memoryStorageInterval = [bundle moObjectForInfoDictionaryKey:@"MobilyCacheMemoryStorageInterval" defaultValue:@(MOBILY_CACHE_MEMORY_STORAGE_INTERVAL)]; + NSNumber* discCapacity = [bundle moObjectForInfoDictionaryKey:@"MobilyCacheDiscCapacity" defaultValue:@(MOBILY_CACHE_DISC_CAPACITY)]; + NSNumber* discStorageInterval = [bundle moObjectForInfoDictionaryKey:@"MobilyCacheDiscStorageInterval" defaultValue:@(MOBILY_CACHE_DISC_STORAGE_INTERVAL)]; + shared = [[self alloc] initWithName:name memoryCapacity:memoryCapacity.unsignedIntegerValue memoryStorageInterval:memoryStorageInterval.doubleValue discCapacity:discCapacity.unsignedIntegerValue discStorageInterval:discStorageInterval.doubleValue]; + } + } + } + return shared; +} + +#pragma mark Init / Free + +- (instancetype)init { + return [self initWithName:MOBILY_CACHE_NAME memoryCapacity:MOBILY_CACHE_MEMORY_CAPACITY memoryStorageInterval:MOBILY_CACHE_MEMORY_STORAGE_INTERVAL discCapacity:MOBILY_CACHE_DISC_CAPACITY discStorageInterval:MOBILY_CACHE_DISC_STORAGE_INTERVAL]; +} + +- (instancetype)initWithName:(NSString*)name { + return [self initWithName:name memoryCapacity:MOBILY_CACHE_MEMORY_CAPACITY memoryStorageInterval:MOBILY_CACHE_MEMORY_STORAGE_INTERVAL discCapacity:MOBILY_CACHE_DISC_CAPACITY discStorageInterval:MOBILY_CACHE_DISC_STORAGE_INTERVAL]; +} + +- (instancetype)initWithName:(NSString*)name memoryCapacity:(NSUInteger)memoryCapacity discCapacity:(NSUInteger)discCapacity { + return [self initWithName:name memoryCapacity:memoryCapacity memoryStorageInterval:MOBILY_CACHE_MEMORY_STORAGE_INTERVAL discCapacity:discCapacity discStorageInterval:MOBILY_CACHE_DISC_STORAGE_INTERVAL]; +} + +- (instancetype)initWithName:(NSString*)name memoryCapacity:(NSUInteger)memoryCapacity memoryStorageInterval:(NSTimeInterval)memoryStorageInterval discCapacity:(NSUInteger)discCapacity discStorageInterval:(NSTimeInterval)discStorageInterval { + self = [super init]; + if(self != nil) { + self.name = name; + self.fileName = [[[_name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString] moStringByMD5]; + self.filePath = [MobilyStorage.moFileSystemDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", _fileName, MOBILY_CACHE_EXTENSION]]; + self.memoryCapacity = (memoryCapacity > discCapacity) ? discCapacity : memoryCapacity; + self.memoryStorageInterval = (memoryStorageInterval > discStorageInterval) ? discStorageInterval : memoryStorageInterval; + self.discCapacity = (discCapacity > memoryCapacity) ? discCapacity : memoryCapacity; + self.discStorageInterval = (discStorageInterval > memoryStorageInterval) ? discStorageInterval : memoryStorageInterval; + self.timer = [MobilyTimer timerWithInterval:MIN(_memoryStorageInterval, _discStorageInterval) repeat:NSNotFound]; + self.items = NSMutableArray.array; + if([NSFileManager.defaultManager fileExistsAtPath:_filePath] == YES) { + id items = [NSKeyedUnarchiver unarchiveObjectWithFile:_filePath]; + if([items isKindOfClass:NSArray.class] == YES) { + _items.array = items; + } + } + for(MobilyCacheItem* item in _items) { + item.cache = self; + } + [self removeObsoleteItems]; + + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(notificationReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; + + [self setup]; + } + return self; +} + +- (void)setup { +} + +- (void)dealloc { + [NSNotificationCenter.defaultCenter removeObserver:self]; + + self.name = nil; + self.timer = nil; + self.items = nil; +} + +#pragma mark Property + +- (void)setMemoryCapacity:(NSUInteger)memoryCapacity { + if(_memoryCapacity != memoryCapacity) { + BOOL needRemoveObsoleteItems = (_memoryCapacity > memoryCapacity); + _memoryCapacity = memoryCapacity; + if(needRemoveObsoleteItems == YES) { + [self removeObsoleteItems]; + } + } +} + +- (void)setDiscCapacity:(NSUInteger)discCapacity { + if(_discCapacity != discCapacity) { + BOOL needRemoveObsoleteItems = (_discCapacity > discCapacity); + _discCapacity = discCapacity; + if(needRemoveObsoleteItems == YES) { + [self removeObsoleteItems]; + } + } +} + +- (void)setTimer:(MobilyTimer*)timer { + if(_timer != timer) { + if(_timer != nil) { + [timer stop]; + } + _timer = timer; + if(_timer != nil) { + _timer.delegate = self; + [_timer start]; + } + } +} + +#pragma mark Public + +- (void)setCacheData:(NSData*)data forKey:(NSString*)key { + [self setCacheData:data forKey:key memoryStorageInterval:_memoryStorageInterval discStorageInterval:_discStorageInterval]; +} + +- (void)setCacheData:(NSData*)data forKey:(NSString*)key complete:(MobilyCacheComplete)complete { + [self setCacheData:data forKey:key memoryStorageInterval:_memoryStorageInterval discStorageInterval:_discStorageInterval complete:complete]; +} + +- (void)setCacheData:(NSData*)data forKey:(NSString*)key memoryStorageInterval:(NSTimeInterval)memoryStorageInterval { + [self setCacheData:data forKey:key memoryStorageInterval:memoryStorageInterval discStorageInterval:_discStorageInterval]; +} + +- (void)setCacheData:(NSData*)data forKey:(NSString*)key memoryStorageInterval:(NSTimeInterval)memoryStorageInterval complete:(MobilyCacheComplete)complete { + [self setCacheData:data forKey:key memoryStorageInterval:memoryStorageInterval discStorageInterval:_discStorageInterval complete:complete]; +} + +- (void)setCacheData:(NSData*)data forKey:(NSString*)key discStorageInterval:(NSTimeInterval)discStorageInterval { + [self setCacheData:data forKey:key memoryStorageInterval:_memoryStorageInterval discStorageInterval:discStorageInterval]; +} + +- (void)setCacheData:(NSData*)data forKey:(NSString*)key discStorageInterval:(NSTimeInterval)discStorageInterval complete:(MobilyCacheComplete)complete { + [self setCacheData:data forKey:key memoryStorageInterval:_memoryStorageInterval discStorageInterval:discStorageInterval complete:complete]; +} + +- (void)setCacheData:(NSData*)data forKey:(NSString*)key memoryStorageInterval:(NSTimeInterval)memoryStorageInterval discStorageInterval:(NSTimeInterval)discStorageInterval { + @synchronized(_items) { + MobilyCacheItem* foundedItem = nil; + for(MobilyCacheItem* item in _items) { + if([item.key isEqualToString:key] == YES) { + foundedItem = item; + break; + } + } + if(((_currentMemoryUsage + data.length) > _memoryCapacity) || ((_currentDiscUsage + data.length) > _discCapacity)) { + [self removeObsoleteItemsInViewOfReserveSize:data.length]; + } + if(foundedItem == nil) { + [_items addObject:[[MobilyCacheItem alloc] initWithCache:self key:key data:data memoryStorageInterval:(memoryStorageInterval > discStorageInterval) ? discStorageInterval : memoryStorageInterval discStorageInterval:discStorageInterval]]; + } else { + [foundedItem updateData:data memoryStorageInterval:(memoryStorageInterval > discStorageInterval) ? discStorageInterval : memoryStorageInterval discStorageInterval:discStorageInterval]; + } + [self saveItems]; + } +} + +- (void)setCacheData:(NSData*)data forKey:(NSString*)key memoryStorageInterval:(NSTimeInterval)memoryStorageInterval discStorageInterval:(NSTimeInterval)discStorageInterval complete:(MobilyCacheComplete)complete { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self setCacheData:data forKey:key memoryStorageInterval:memoryStorageInterval discStorageInterval:discStorageInterval]; + if(complete != nil) { + complete(); + } + }); +} + +- (NSData*)cacheDataForKey:(NSString*)key { + NSData* result = nil; + @synchronized(_items) { + for(MobilyCacheItem* item in _items) { + if([item.key isEqualToString:key] == YES) { + result = item.data; + break; + } + } + } + return result; +} + +- (void)cacheDataForKey:(NSString*)key complete:(MobilyCacheDataForKey)complete { + if(complete != nil) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + complete([self cacheDataForKey:key]); + }); + } +} + +- (void)removeCacheDataForKey:(NSString*)key { + @synchronized(_items) { + MobilyCacheItem* foundedItem = nil; + for(MobilyCacheItem* item in _items) { + if([item.key isEqualToString:key] == YES) { + foundedItem = item; + break; + } + } + if(foundedItem != nil) { + [foundedItem clearFromAllCache]; + [_items removeObject:foundedItem]; + [self saveItems]; + } + } +} + +- (void)removeCacheDataForKey:(NSString*)key complete:(MobilyCacheComplete)complete { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self removeCacheDataForKey:key]; + if(complete != nil) { + complete(); + } + }); +} + +- (void)removeAllCachedData { + @synchronized(_items) { + if(_items.count > 0) { + for(MobilyCacheItem* item in _items) { + [item clearFromAllCache]; + } + [_items removeAllObjects]; + [self saveItems]; + } + } +} + +- (void)removeAllCachedDataComplete:(MobilyCacheComplete)complete { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self removeAllCachedData]; + if(complete != nil) { + complete(); + } + }); +} + +#pragma mark Private + +- (void)removeObsoleteItemsInViewOfReserveSize:(NSUInteger)reserveSize { + NSUInteger currentMemoryUsage = 0; + NSUInteger currentDiscUsage = 0; + if(_items.count > 0) { + NSTimeInterval now = NSDate.timeIntervalSinceReferenceDate; + NSMutableArray* removedMemoryItems = NSMutableArray.array; + NSMutableArray* removedDiscItems = NSMutableArray.array; + [_items sortUsingComparator:^NSComparisonResult(MobilyCacheItem* item1, MobilyCacheItem* item2) { + if(item1.discStorageTime > item2.discStorageTime) { + return NSOrderedDescending; + } else if(item1.discStorageTime < item2.discStorageTime) { + return NSOrderedAscending; + } else { + if(item1.memoryStorageTime > item2.memoryStorageTime) { + return NSOrderedDescending; + } else if(item1.memoryStorageTime < item2.memoryStorageTime) { + return NSOrderedAscending; + } else { + if(item1.size > item2.size) { + return NSOrderedDescending; + } else if(item1.size < item2.size) { + return NSOrderedAscending; + } + } + } + return NSOrderedSame; + }]; + for(MobilyCacheItem* item in _items) { + if((item.discStorageTime > now) && (((currentDiscUsage + reserveSize) + item.size) <= _discCapacity)) { + if((item.memoryStorageTime > now) && (((currentMemoryUsage + reserveSize) + item.size) <= _memoryCapacity)) { + if([item isInMemory] == YES) { + currentMemoryUsage += item.size; + } + } else { + [removedMemoryItems addObject:item]; + } + currentDiscUsage += item.size; + } else { + [removedDiscItems addObject:item]; + } + } + if(removedMemoryItems.count > 0) { + for(MobilyCacheItem* item in removedMemoryItems) { + [item clearFromMemoryCache]; + } + } + if(removedDiscItems.count > 0) { + for(MobilyCacheItem* item in removedDiscItems) { + [item clearFromAllCache]; + } + [_items removeObjectsInArray:removedDiscItems]; + [self saveItems]; + } + } + self.currentMemoryUsage = currentMemoryUsage; + self.currentDiscUsage = currentDiscUsage; +} + +- (void)removeObsoleteItems { + [self removeObsoleteItemsInViewOfReserveSize:0]; +} + +- (void)saveItems { + [NSKeyedArchiver archiveRootObject:_items toFile:_filePath]; +} + +#pragma mark NSNotificationCenter + +- (void)notificationReceiveMemoryWarning:(NSNotification* __unused)notification { + for(MobilyCacheItem* item in _items) { + [item clearFromMemoryCache]; + } + self.currentMemoryUsage = 0; +} + +#pragma mark MobilyTimerDelegate + +-(void)timerDidRepeat:(MobilyTimer* __unused)timer { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [self removeObsoleteItems]; + }); +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#define MOBILY_CACHE_ITEM_EXTENSION @"data" + +/*--------------------------------------------------*/ + +@implementation MobilyCacheItem + +#pragma mark Synthesize + +@synthesize cache = _cache; +@synthesize key = _key; +@synthesize fileName = _fileName; +@synthesize filePath = _filePath; +@synthesize data = _data; +@synthesize size = _size; +@synthesize memoryStorageInterval = _memoryStorageInterval; +@synthesize memoryStorageTime =_memoryStorageTime; +@synthesize discStorageInterval = _discStorageInterval; +@synthesize discStorageTime = _discStorageTime; +@synthesize inMemory = _inMemory; + +#pragma mark Init / Free + +- (instancetype)initWithCache:(MobilyCache*)cache key:(NSString*)key data:(NSData*)data memoryStorageInterval:(NSTimeInterval)memoryStorageInterval discStorageInterval:(NSTimeInterval)discStorageInterval { + self = [super init]; + if(self != nil) { + _cache = cache; + _key = [key stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + _fileName = _key.lowercaseString.moStringByMD5; + _filePath = [MobilyStorage.moFileSystemDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", _fileName, MOBILY_CACHE_ITEM_EXTENSION]]; + _data = data; + _size = _data.length; + _memoryStorageInterval = memoryStorageInterval; + _memoryStorageTime = MOBILY_CEIL(NSDate.timeIntervalSinceReferenceDate + memoryStorageInterval); + _discStorageInterval = discStorageInterval; + _discStorageTime = MOBILY_CEIL(NSDate.timeIntervalSinceReferenceDate + discStorageInterval); + + _cache.currentMemoryUsage = _cache.currentMemoryUsage + _size; + [self saveToDiscCache]; + } + return self; +} + +- (void)dealloc { + [self clearFromMemoryCache]; +} + +#pragma mark MobilyModel + ++ (NSArray*)compareMap { + return @[ + @"key", + ]; +} + ++ (NSArray*)serializeMap { + return @[ + @"key", + @"fileName", + @"size", + @"memoryStorageInterval", + @"memoryStorageTime", + @"discStorageInterval", + @"discStorageTime" + ]; +} + +#pragma mark Property + +- (void)setFileName:(NSString*)fileName { + if([_fileName isEqualToString:fileName] == NO) { + _fileName = fileName; + if(_fileName != nil) { + _filePath = [MobilyStorage.moFileSystemDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", _fileName, MOBILY_CACHE_ITEM_EXTENSION]]; + } else { + _filePath = nil; + } + } +} + +- (NSData*)data { + if((_data == nil) && (_filePath != nil)) { + _data = [NSData dataWithContentsOfFile:_filePath]; + if(_data != nil) { + _cache.currentMemoryUsage = _cache.currentMemoryUsage + _size; + } + } + return _data; +} + +- (BOOL)isInMemory { + return (_data != nil); +} + +#pragma mark Private + +- (void)updateData:(NSData*)data memoryStorageInterval:(NSTimeInterval)memoryStorageInterval discStorageInterval:(NSTimeInterval)discStorageInterval { + _cache.currentMemoryUsage = _cache.currentMemoryUsage - _size; + _data = data; + _size = data.length; + _cache.currentMemoryUsage = _cache.currentMemoryUsage + _size; + _memoryStorageInterval = memoryStorageInterval; + _memoryStorageTime = MOBILY_CEIL(NSDate.timeIntervalSinceReferenceDate + memoryStorageInterval); + _discStorageInterval = discStorageInterval; + _discStorageTime = MOBILY_CEIL(NSDate.timeIntervalSinceReferenceDate + discStorageInterval); + [self saveToDiscCache]; +} + +- (void)saveToDiscCache { + if([_data writeToFile:_filePath atomically:YES] == YES) { + _cache.currentDiscUsage = _cache.currentDiscUsage + _size; + } +} + +- (void)clearFromMemoryCache { + _cache.currentMemoryUsage = _cache.currentMemoryUsage - _size; + _data = nil; +} + +- (void)clearFromDiscCache { + if([NSFileManager.defaultManager removeItemAtPath:_filePath error:nil] == YES) { + _cache.currentDiscUsage = _cache.currentDiscUsage - _size; + } +} + +- (void)clearFromAllCache { + [self clearFromMemoryCache]; + [self clearFromDiscCache]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyContext.h b/Sources/MobilyCore/MobilyContext.h similarity index 88% rename from Classes/UI/Core/MobilyContext.h rename to Sources/MobilyCore/MobilyContext.h index f8f2b98..b531230 100644 --- a/Classes/UI/Core/MobilyContext.h +++ b/Sources/MobilyCore/MobilyContext.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,19 +33,25 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyApplication.h" +#import /*--------------------------------------------------*/ @interface MobilyContext : NSObject < MobilyBuilderObject > + (void)setArgCount:(int)argCount argValue:(char**)argValue; ++ (void)setApplicationClass:(Class)applicationClass; ++ (Class)applicationClass; + (void)setAccessKey:(NSString*)accessKey; ++ (NSString*)accessKey; + (int)run; + (id)application; ++ (BOOL)loadWithOptions:(NSDictionary*)options; ++ (void)unload; + @end /*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyContext.m b/Sources/MobilyCore/MobilyContext.m new file mode 100644 index 0000000..0952dfe --- /dev/null +++ b/Sources/MobilyCore/MobilyContext.m @@ -0,0 +1,295 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +#define MOBILY_FILE_PRESETS @"Presets" +#define MOBILY_FILE_APPLICATION @"Application" + +/*--------------------------------------------------*/ + +@interface MobilyContext () < UIApplicationDelegate > + +@property(nonatomic, readwrite, strong) MobilyApplication* application; + +- (BOOL)loadWithOptions:(NSDictionary*)options; +- (void)unload; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +static MobilyApplication* MOBILY_APPLICATION = nil; +static int MOBILY_YARG_COUNT = 0; +static char** MOBILY_YARG_VALUE = nil; +static Class MOBILY_APPLICATION_CLASS = NULL; +static NSString* MOBILY_ACCESS_KEY = nil; + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyContext + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { +} + +- (void)dealloc { + self.application = nil; +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return _objectChilds; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIViewController.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIViewController.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark Property + +- (void)setApplication:(MobilyApplication*)application { + if(_application != application) { + _application = application; + MOBILY_APPLICATION = _application; + } +} + +#pragma mark Public + ++ (void)setArgCount:(int)argCount argValue:(char**)argValue { + MOBILY_YARG_COUNT = argCount; + MOBILY_YARG_VALUE = argValue; +} + ++ (void)setApplicationClass:(Class)applicationClass { + MOBILY_APPLICATION_CLASS = applicationClass; +} + ++ (Class)applicationClass { + return MOBILY_APPLICATION_CLASS; +} + ++ (void)setAccessKey:(NSString*)accessKey { + MOBILY_ACCESS_KEY = accessKey; +} + ++ (NSString*)accessKey { + return MOBILY_ACCESS_KEY; +} + ++ (int)run { + return UIApplicationMain(MOBILY_YARG_COUNT, MOBILY_YARG_VALUE, nil, NSStringFromClass(MobilyContext.class)); +} + ++ (id)application { + return MOBILY_APPLICATION; +} + ++ (BOOL)loadWithOptions:(NSDictionary*)options { + id appDelegate = [UIApplication.sharedApplication delegate]; + if([appDelegate isKindOfClass:MobilyContext.class] == YES) { + return [(MobilyContext*)appDelegate loadWithOptions:options]; + } + return NO; +} + ++ (void)unload { + id appDelegate = [UIApplication.sharedApplication delegate]; + if([appDelegate isKindOfClass:MobilyContext.class] == YES) { + [(MobilyContext*)appDelegate unload]; + } +} + +#pragma mark Private + +- (BOOL)loadWithOptions:(NSDictionary*)options { + [MobilyBuilderPreset loadFromFilename:MOBILY_FILE_PRESETS]; + + if([MOBILY_APPLICATION_CLASS isSubclassOfClass:MobilyApplication.class] == YES) { + self.application = [MOBILY_APPLICATION_CLASS new]; + if(_application != nil) { + [_application launchingWithOptions:options]; + } + } else { + id mobilyApplication = [MobilyBuilderForm objectFromFilename:MOBILY_FILE_APPLICATION owner:self]; + if([mobilyApplication isKindOfClass:MobilyApplication.class] == YES) { + self.application = mobilyApplication; + if(_application != nil) { + [_application launchingWithOptions:options]; + } + } else { +#if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) + NSLog(@"Failure loading '%@'", MOBILY_FILE_APPLICATION); +#endif + } + } + return (_application != nil); +} + +- (void)unload { + if(_application != nil) { + [_application terminate]; + self.application = nil; + } +} + +#pragma mark UIApplicationDelegate + +- (void)setWindow:(UIWindow*)window { + [window makeKeyWindow]; +} + +- (UIWindow*)window { + return UIApplication.sharedApplication.keyWindow; +} + +- (BOOL)application:(UIApplication* __unused)application didFinishLaunchingWithOptions:(NSDictionary*)options { + return [self loadWithOptions:options]; +} + +- (void)applicationWillTerminate:(UIApplication* __unused)application { + [self unload]; +} + +- (void)applicationDidReceiveMemoryWarning:(UIApplication* __unused)application { + [_application receiveMemoryWarning]; +} + +- (void)applicationDidBecomeActive:(UIApplication* __unused)application { + [_application becomeActive]; +} + +- (void)applicationWillResignActive:(UIApplication* __unused)application { + [_application resignActive]; +} + +- (void)applicationWillEnterForeground:(UIApplication* __unused)application { + [_application enterForeground]; +} + +- (void)applicationDidEnterBackground:(UIApplication* __unused)application { + [_application enterBackground]; +} + +- (void)application:(UIApplication* __unused)application didRegisterUserNotificationSettings:(UIUserNotificationSettings*)notificationSettings { + [_application registerUserNotificationSettings:notificationSettings]; +} + +- (void)application:(UIApplication* __unused)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken { + [_application registerForRemoteNotificationsWithDeviceToken:deviceToken]; +} + +- (void)application:(UIApplication* __unused)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error { + [_application failToRegisterForRemoteNotificationsWithError:error]; +} + +- (void)application:(UIApplication* __unused)application didReceiveRemoteNotification:(NSDictionary*)notification { + [_application receiveRemoteNotification:notification]; +} + +- (void)application:(UIApplication* __unused)application didReceiveLocalNotification:(UILocalNotification*)notification { + [_application receiveLocalNotification:notification]; +} + +- (void)application:(UIApplication* __unused)application handleActionWithIdentifier:(NSString*)identifier forLocalNotification:(UILocalNotification*)notification completionHandler:(void(^)())completionHandler { + [_application handleActionWithIdentifier:identifier forLocalNotification:notification completionHandler:completionHandler]; +} + +- (void)application:(UIApplication* __unused)application handleActionWithIdentifier:(NSString*)identifier forRemoteNotification:(NSDictionary*)userInfo completionHandler:(void(^)())completionHandler { + [_application handleActionWithIdentifier:identifier forRemoteNotification:userInfo completionHandler:completionHandler]; +} + +- (void)application:(UIApplication*)application handleEventsForBackgroundURLSession:(NSString*)identifier completionHandler:(void(^)())completionHandler { + [_application handleEventsForBackgroundURLSession:identifier completionHandler:completionHandler]; +} + +- (void)application:(UIApplication*)application handleWatchKitExtensionRequest:(NSDictionary*)userInfo reply:(void(^)(NSDictionary* replyInfo))reply { + [_application handleWatchKitExtensionRequest:userInfo reply:reply]; +} + +- (BOOL)application:(UIApplication* __unused)application openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation { + return [_application openURL:url sourceApplication:sourceApplication annotation:annotation]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyController.h b/Sources/MobilyCore/MobilyController.h similarity index 88% rename from Classes/UI/Core/MobilyController.h rename to Sources/MobilyCore/MobilyController.h index 272fd0f..d056057 100644 --- a/Classes/UI/Core/MobilyController.h +++ b/Sources/MobilyCore/MobilyController.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,14 +33,17 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyBuilder.h" -#import "MobilyTransitionController.h" +#import +#import /*--------------------------------------------------*/ @interface MobilyController : UIViewController< MobilyBuilderObject > +@property(nonatomic, readonly, weak) id app; + @property(nonatomic, readonly, assign, getter=isAppeared) BOOL appeared; +@property(nonatomic, readwrite, assign, getter=isStatusBarHidden) BOOL statusBarHidden; @property(nonatomic, readwrite, assign) UIStatusBarStyle statusBarStyle; @property(nonatomic, readwrite, assign) UIStatusBarAnimation statusBarAnimation; @property(nonatomic, readwrite, assign, getter=isNavigationBarHidden) BOOL navigationBarHidden; @@ -53,10 +56,14 @@ @property(nonatomic, readwrite, strong) id< MobilyEvent > eventWillDisappear; @property(nonatomic, readwrite, strong) id< MobilyEvent > eventDidDisappear; -- (void)setupController; +- (void)setup NS_REQUIRES_SUPER; - (void)setNavigationBarHidden:(BOOL)navigationBarHidden animated:(BOOL)animated; +- (void)setNeedUpdate; +- (void)update NS_REQUIRES_SUPER; +- (void)clear NS_REQUIRES_SUPER; + @end /*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyController.m b/Sources/MobilyCore/MobilyController.m similarity index 54% rename from Classes/UI/Core/MobilyController.m rename to Sources/MobilyCore/MobilyController.m index d3a693d..d2ebd9d 100644 --- a/Classes/UI/Core/MobilyController.m +++ b/Sources/MobilyCore/MobilyController.m @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -32,17 +32,22 @@ /* OTHER DEALINGS IN THE SOFTWARE. */ /* */ /*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ -#import "MobilyController.h" -#import "MobilyControllerNavigation.h" -#import "MobilyControllerTabBar.h" -#import "MobilyEvent.h" +#import +#import +#import +#import +#import /*--------------------------------------------------*/ @interface MobilyController () < UIViewControllerTransitioningDelegate > @property(nonatomic, readwrite, assign, getter=isAppeared) BOOL appeared; +@property(nonatomic, readwrite, assign, getter=isNeedUpdate) BOOL needUpdate; +@property(nonatomic, readwrite, assign) BOOL updating; @end @@ -52,12 +57,15 @@ @interface MobilyController () < UIViewControllerTransitioningDelegate > @implementation MobilyController +#pragma mark Synthesize + @synthesize objectName = _objectName; @synthesize objectParent = _objectParent; @synthesize objectChilds = _objectChilds; #pragma mark NSKeyValueCoding +MOBILY_DEFINE_VALIDATE_BOOL(StatusBarHidden) MOBILY_DEFINE_VALIDATE_STATUS_BAR_STYLE(StatusBarStyle) MOBILY_DEFINE_VALIDATE_STATUS_BAR_ANIMATION(StatusBarAnimation) MOBILY_DEFINE_VALIDATE_BOOL(NavigationBarHidden) @@ -69,43 +77,47 @@ @implementation MobilyController MOBILY_DEFINE_VALIDATE_EVENT(EventWillDisappear) MOBILY_DEFINE_VALIDATE_EVENT(EventDidDisappear) -#pragma mark Standart +#pragma mark Init / Free -- (id)initWithCoder:(NSCoder*)coder { +- (instancetype)initWithCoder:(NSCoder*)coder { self = [super initWithCoder:coder]; if(self != nil) { - [self setupController]; + [self setup]; } return self; } -- (id)initWithNibName:(NSString*)nib bundle:(NSBundle*)bundle { +- (instancetype)initWithNibName:(NSString*)nib bundle:(NSBundle*)bundle { self = [super initWithNibName:nib bundle:bundle]; if(self != nil) { - [self setupController]; + [self setup]; } return self; } +- (void)setup { + self.needUpdate = YES; +} + - (void)dealloc { - [self setObjectName:nil]; - [self setObjectParent:nil]; - [self setObjectChilds:nil]; - - MOBILY_SAFE_DEALLOC; + [NSNotificationCenter.defaultCenter removeObserver:self]; } #pragma mark MobilyBuilderObject +- (NSArray*)relatedObjects { + return self.childViewControllers; +} + - (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIViewController class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andAddingObject:objectChild]]; + if([objectChild isKindOfClass:UIViewController.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; } } - (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIViewController class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andRemovingObject:objectChild]]; + if([objectChild isKindOfClass:UIViewController.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; } } @@ -123,35 +135,90 @@ - (void)didLoadObjectChilds { return [MobilyBuilderForm object:self forSelector:selector]; } -#pragma mark Public +#pragma mark Property -- (void)setupController { +- (void)setView:(UIView*)view { + super.view = view; + if(view != nil) { + view.clipsToBounds = YES; + } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if((UIDevice.moSystemVersion >= 6.0f) && (view == nil)) { + [self viewDidUnload]; + } +#pragma clang diagnostic pop } -#pragma mark Property +- (id)app { + return MobilyContext.application; +} -- (BOOL)isAppeared { - return (_appeared > 0); +- (void)setStatusBarHidden:(BOOL)statusBarHidden { + if(_statusBarHidden != statusBarHidden) { + _statusBarHidden = statusBarHidden; + [self setNeedsStatusBarAppearanceUpdate]; + } +} + +- (void)setStatusBarStyle:(UIStatusBarStyle)statusBarStyle { + if(_statusBarStyle != statusBarStyle) { + _statusBarStyle = statusBarStyle; + [self setNeedsStatusBarAppearanceUpdate]; + } +} + +- (void)setStatusBarAnimation:(UIStatusBarAnimation)statusBarAnimation { + if(_statusBarAnimation != statusBarAnimation) { + _statusBarAnimation = statusBarAnimation; + [self setNeedsStatusBarAppearanceUpdate]; + } } - (void)setNavigationBarHidden:(BOOL)navigationBarHidden { [self setNavigationBarHidden:navigationBarHidden animated:NO]; } +#pragma mark Public + - (void)setNavigationBarHidden:(BOOL)navigationBarHidden animated:(BOOL)animated { if(_navigationBarHidden != navigationBarHidden) { _navigationBarHidden = navigationBarHidden; - if([self isViewLoaded] == YES) { - [[self navigationController] setNavigationBarHidden:_navigationBarHidden animated:animated]; + if(self.isViewLoaded == YES) { + [self.navigationController setNavigationBarHidden:_navigationBarHidden animated:animated]; } } } +- (void)setNeedUpdate { + if(_updating == NO) { + self.updating = YES; + [self clear]; + if(self.isAppeared == YES) { + [self update]; + } else { + self.needUpdate = YES; + } + [self.relatedObjects moEach:^(id object) { + if([object respondsToSelector:@selector(setNeedUpdate)] == YES) { + [object setNeedUpdate]; + } + }]; + self.updating = NO; + } +} + +- (void)update { +} + +- (void)clear { +} + #pragma mark UIViewController - (BOOL)prefersStatusBarHidden { - return NO; + return _statusBarHidden; } - (UIStatusBarStyle)preferredStatusBarStyle { @@ -164,60 +231,84 @@ - (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { - (void)viewDidLoad { [super viewDidLoad]; - + [_eventDidLoad fireSender:self object:nil]; } - (void)viewDidUnload { - [super viewDidUnload]; - [_eventDidUnload fireSender:self object:nil]; + [self setNeedUpdate]; + + [super viewDidUnload]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; + [self.view layoutIfNeeded]; - [_eventWillAppear fireSender:self object:nil]; - [self setAppeared:_appeared + 1]; + if(_appeared == NO) { + [_eventWillAppear fireSender:self object:nil]; + self.appeared = YES; + if(self.isNeedUpdate == YES) { + self.needUpdate = NO; + [self clear]; + [self update]; + } + } } - (void)viewDidAppear:(BOOL)animated { - [super viewDidAppear:animated]; - [_eventDidAppear fireSender:self object:nil]; + + [super viewDidAppear:animated]; } - (void)viewWillDisappear:(BOOL)animated { - [super viewWillDisappear:animated]; - [_eventWillDisappear fireSender:self object:nil]; + + [super viewWillDisappear:animated]; } - (void)viewDidDisappear:(BOOL)animated { + if(_appeared == YES) { + self.appeared = NO; + [_eventDidDisappear fireSender:self object:nil]; + } [super viewDidDisappear:animated]; - - [self setAppeared:_appeared - 1]; - [_eventDidDisappear fireSender:self object:nil]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; - [self unloadViewIfPossible]; + [self moUnloadViewIfPossible]; } #pragma mark UIViewControllerTransitioningDelegate -- (id< UIViewControllerAnimatedTransitioning >)animationControllerForPresentedController:(UIViewController*)presented presentingController:(UIViewController*)presenting sourceController:(UIViewController*)source { +- (id< UIViewControllerAnimatedTransitioning >)animationControllerForPresentedController:(UIViewController* __unused)presented presentingController:(UIViewController* __unused)presenting sourceController:(UIViewController* __unused)source { + if(_transitionModal != nil) { + _transitionModal.operation = MobilyTransitionOperationPresent; + } + return _transitionModal; +} + +- (id< UIViewControllerAnimatedTransitioning >)animationControllerForDismissedController:(UIViewController* __unused)dismissed { + if(_transitionModal != nil) { + _transitionModal.operation = MobilyTransitionOperationDismiss; + } + return _transitionModal; +} + +- (id< UIViewControllerInteractiveTransitioning >)interactionControllerForPresentation:(id< UIViewControllerAnimatedTransitioning > __unused)animator { if(_transitionModal != nil) { - [_transitionModal setReverse:NO]; + _transitionModal.operation = MobilyTransitionOperationDismiss; } return _transitionModal; } -- (id< UIViewControllerAnimatedTransitioning >)animationControllerForDismissedController:(UIViewController*)dismissed { +- (id< UIViewControllerInteractiveTransitioning >)interactionControllerForDismissal:(id< UIViewControllerAnimatedTransitioning > __unused)animator { if(_transitionModal != nil) { - [_transitionModal setReverse:YES]; + _transitionModal.operation = MobilyTransitionOperationDismiss; } return _transitionModal; } diff --git a/Sources/MobilyCore/MobilyCore.h b/Sources/MobilyCore/MobilyCore.h new file mode 100644 index 0000000..8768512 --- /dev/null +++ b/Sources/MobilyCore/MobilyCore.h @@ -0,0 +1,100 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import +#import + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyData.h b/Sources/MobilyCore/MobilyData.h new file mode 100644 index 0000000..721fb7a --- /dev/null +++ b/Sources/MobilyCore/MobilyData.h @@ -0,0 +1,57 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import +#import +#import + +/*--------------------------------------------------*/ + +typedef NS_OPTIONS(NSUInteger, MobilyDataViewPosition) { + MobilyDataViewPositionNone = 0, + MobilyDataViewPositionTop = 1 << 0, + MobilyDataViewPositionCenteredVertically = 1 << 1, + MobilyDataViewPositionBottom = 1 << 2, + MobilyDataViewPositionLeft = 1 << 3, + MobilyDataViewPositionCenteredHorizontally = 1 << 4, + MobilyDataViewPositionRight = 1 << 5, + MobilyDataViewPositionCentered = MobilyDataViewPositionCenteredVertically | MobilyDataViewPositionCenteredHorizontally, + MobilyDataViewPositionInsideVertically = (MobilyDataViewPositionTop | MobilyDataViewPositionCenteredVertically | MobilyDataViewPositionBottom), + MobilyDataViewPositionInsideHorizontally = (MobilyDataViewPositionLeft | MobilyDataViewPositionCenteredHorizontally | MobilyDataViewPositionRight), + MobilyDataViewPositionInside = MobilyDataViewPositionInsideVertically | MobilyDataViewPositionInsideHorizontally, +}; + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataCell+Private.h b/Sources/MobilyCore/MobilyDataCell+Private.h new file mode 100644 index 0000000..bd506e3 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataCell+Private.h @@ -0,0 +1,165 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyDataCell () { +@protected + NSString* _identifier; + __weak MobilyDataView* _view; + __weak MobilyDataItem* _item; + BOOL _selected; + BOOL _highlighted; + BOOL _editing; + UILongPressGestureRecognizer* _pressGestureRecognizer; + UITapGestureRecognizer* _tapGestureRecognizer; + UILongPressGestureRecognizer* _longPressGestureRecognizer; + UIView* _rootView; + UIOffset _rootOffsetOfCenter; + UIOffset _rootMarginSize; + NSLayoutConstraint* _constraintRootViewCenterX; + NSLayoutConstraint* _constraintRootViewCenterY; + NSLayoutConstraint* _constraintRootViewWidth; + NSLayoutConstraint* _constraintRootViewHeight; +} + +@property(nonatomic, readwrite, weak) MobilyDataView* view; +@property(nonatomic, readwrite, strong) UILongPressGestureRecognizer* pressGestureRecognizer; +@property(nonatomic, readwrite, strong) UITapGestureRecognizer* tapGestureRecognizer; +@property(nonatomic, readwrite, strong) UILongPressGestureRecognizer* longPressGestureRecognizer; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewCenterX; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewCenterY; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewWidth; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewHeight; + +- (void)_pressed; +- (void)_longPressed; + +- (void)_handlerPressGestureRecognizer:(UILongPressGestureRecognizer*)gestureRecognizer; +- (void)_handlerTapGestureRecognizer:(UITapGestureRecognizer*)gestureRecognizer; +- (void)_handlerLongPressGestureRecognizer:(UILongPressGestureRecognizer*)gestureRecognizer; + +@end + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, MobilyDataCellSwipeDirection) { + MobilyDataCellSwipeDirectionUnknown, + MobilyDataCellSwipeDirectionLeft, + MobilyDataCellSwipeDirectionRight +}; + +/*--------------------------------------------------*/ + +@interface MobilyDataCellSwipe () { +@protected + UIPanGestureRecognizer* _panGestureRecognizer; + BOOL _swipeEnabled; + MobilyDataSwipeCellStyle _swipeStyle; + CGFloat _swipeThreshold; + CGFloat _swipeVelocity; + CGFloat _swipeSpeed; + BOOL _swipeDragging; + BOOL _swipeDecelerating; + BOOL _showedLeftSwipeView; + BOOL _leftSwipeEnabled; + UIView* _leftSwipeView; + CGFloat _leftSwipeOffset; + CGFloat _leftSwipeSize; + CGFloat _leftSwipeStretchSize; + CGFloat _leftSwipeStretchMinThreshold; + CGFloat _leftSwipeStretchMaxThreshold; + BOOL _showedRightSwipeView; + BOOL _rightSwipeEnabled; + UIView* _rightSwipeView; + CGFloat _rightSwipeOffset; + CGFloat _rightSwipeSize; + CGFloat _rightSwipeStretchSize; + CGFloat _rightSwipeStretchMinThreshold; + CGFloat _rightSwipeStretchMaxThreshold; + NSLayoutConstraint* _constraintLeftSwipeViewOffsetX; + NSLayoutConstraint* _constraintLeftSwipeViewCenterY; + NSLayoutConstraint* _constraintLeftSwipeViewWidth; + NSLayoutConstraint* _constraintLeftSwipeViewHeight; + NSLayoutConstraint* _constraintRightSwipeViewOffsetX; + NSLayoutConstraint* _constraintRightSwipeViewCenterY; + NSLayoutConstraint* _constraintRightSwipeViewWidth; + NSLayoutConstraint* _constraintRightSwipeViewHeight; + CGFloat _panSwipeLastOffset; + CGFloat _panSwipeLastVelocity; + CGFloat _panSwipeProgress; + CGFloat _panSwipeLeftWidth; + CGFloat _panSwipeRightWidth; + MobilyDataCellSwipeDirection _panSwipeDirection; +} + +@property(nonatomic, readwrite, strong) UIPanGestureRecognizer* panGestureRecognizer; +@property(nonatomic, readwrite, getter=isSwipeDragging) BOOL swipeDragging; +@property(nonatomic, readwrite, getter=isSwipeDecelerating) BOOL swipeDecelerating; + +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintLeftSwipeViewOffsetX; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintLeftSwipeViewCenterY; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintLeftSwipeViewWidth; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintLeftSwipeViewHeight; + +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRightSwipeViewOffsetX; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRightSwipeViewCenterY; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRightSwipeViewWidth; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRightSwipeViewHeight; + +@property(nonatomic, readwrite, assign) CGFloat panSwipeLastOffset; +@property(nonatomic, readwrite, assign) CGFloat panSwipeLastVelocity; +@property(nonatomic, readwrite, assign) CGFloat panSwipeProgress; +@property(nonatomic, readwrite, assign) CGFloat panSwipeLeftWidth; +@property(nonatomic, readwrite, assign) CGFloat panSwipeRightWidth; +@property(nonatomic, readwrite, assign) MobilyDataCellSwipeDirection panSwipeDirection; + +- (UIOffset)_rootViewOffsetOfCenterBySwipeProgress:(CGFloat)swipeProgress; +- (CGFloat)_leftViewOffsetBySwipeProgress:(CGFloat)swipeProgress; +- (CGFloat)_leftViewSizeBySwipeProgress:(CGFloat)swipeProgress; +- (CGFloat)_rightViewOffsetBySwipeProgress:(CGFloat)swipeProgress; +- (CGFloat)_rightViewSizeBySwipeProgress:(CGFloat)swipeProgress; + +- (void)_updateSwipeProgress:(CGFloat)swipeProgress speed:(CGFloat)speed endedSwipe:(BOOL)endedSwipe; + +- (void)_handlerPanGestureRecognizer:(UIPanGestureRecognizer*)gestureRecognizer; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataCell.h b/Sources/MobilyCore/MobilyDataCell.h new file mode 100644 index 0000000..0aa21a7 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataCell.h @@ -0,0 +1,154 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@class MobilyDataView; +@class MobilyDataItem; + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyDataCell : UIView< MobilyObject, UIGestureRecognizerDelegate, MobilySearchBarDelegate > + +@property(nonatomic, readonly, strong) NSString* identifier; +@property(nonatomic, readonly, weak) MobilyDataView* view; +@property(nonatomic, readwrite, weak) MobilyDataItem* item; +@property(nonatomic, readwrite, assign, getter=isSelected) BOOL selected; +@property(nonatomic, readwrite, assign, getter=isHighlighted) BOOL highlighted; +@property(nonatomic, readwrite, assign, getter=isEditing) BOOL editing; + +@property(nonatomic, readonly, strong) UILongPressGestureRecognizer* pressGestureRecognizer; +@property(nonatomic, readonly, strong) UITapGestureRecognizer* tapGestureRecognizer; +@property(nonatomic, readonly, strong) UILongPressGestureRecognizer* longPressGestureRecognizer; + +@property(nonatomic, readwrite, strong) IBOutlet UIView* rootView; +@property(nonatomic, readwrite, assign) UIOffset rootOffsetOfCenter; +@property(nonatomic, readwrite, assign) UIOffset rootMarginSize; + +@property(nonatomic, readonly, strong) NSArray* orderedSubviews; + ++ (CGSize)sizeForItem:(id)item availableSize:(CGSize)size; ++ (UILayoutPriority)fittingHorizontalPriority; ++ (UILayoutPriority)fittingVerticalPriority; + +- (instancetype)initWithIdentifier:(NSString*)identifier; +- (instancetype)initWithIdentifier:(NSString*)identifier nib:(UINib*)nib; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)prepareForUse; +- (void)prepareForUnuse; + +- (BOOL)containsEventForKey:(id)key; +- (BOOL)containsEventForIdentifier:(NSString*)identifier forKey:(id)key; + +- (void)fireEventForKey:(id)key byObject:(id)object; +- (id)fireEventForKey:(id)key byObject:(id)object orDefault:(id)orDefault; +- (void)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object; +- (id)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault; + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated NS_REQUIRES_SUPER; +- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated NS_REQUIRES_SUPER; +- (void)setEditing:(BOOL)editing animated:(BOOL)animated NS_REQUIRES_SUPER; + +- (void)validateLayoutForBounds:(CGRect)bounds; +- (void)invalidateLayoutForBounds:(CGRect)bounds; + +@end + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, MobilyDataSwipeCellStyle) { + MobilyDataSwipeCellStyleStands, + MobilyDataSwipeCellStyleLeaves, + MobilyDataSwipeCellStylePushes, + MobilyDataSwipeCellStyleStretch +}; + +/*--------------------------------------------------*/ + +@interface MobilyDataCellSwipe : MobilyDataCell + +@property(nonatomic, readonly, strong) UIPanGestureRecognizer* panGestureRecognizer; + +@property(nonatomic, readwrite, getter=isSwipeEnabled) BOOL swipeEnabled; +@property(nonatomic, readwrite, assign) IBInspectable MobilyDataSwipeCellStyle swipeStyle; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat swipeThreshold; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat swipeVelocity; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat swipeSpeed; +@property(nonatomic, readonly, getter=isSwipeDragging) BOOL swipeDragging; +@property(nonatomic, readonly, getter=isSwipeDecelerating) BOOL swipeDecelerating; + +@property(nonatomic, readwrite, assign, getter=isShowedLeftSwipeView) IBInspectable BOOL showedLeftSwipeView; +@property(nonatomic, readwrite, assign, getter=isLeftSwipeEnabled) IBInspectable BOOL leftSwipeEnabled; +@property(nonatomic, readwrite, strong) IBOutlet UIView* leftSwipeView; +@property(nonatomic, readwrite, assign) CGFloat leftSwipeOffset; +@property(nonatomic, readwrite, assign) CGFloat leftSwipeSize; +@property(nonatomic, readwrite, assign) CGFloat leftSwipeStretchSize; +@property(nonatomic, readwrite, assign) CGFloat leftSwipeStretchMinThreshold; +@property(nonatomic, readwrite, assign) CGFloat leftSwipeStretchMaxThreshold; + +@property(nonatomic, readwrite, assign, getter=isShowedRightSwipeView) IBInspectable BOOL showedRightSwipeView; +@property(nonatomic, readwrite, assign, getter=isRightSwipeEnabled) IBInspectable BOOL rightSwipeEnabled; +@property(nonatomic, readwrite, strong) IBOutlet UIView* rightSwipeView; +@property(nonatomic, readwrite, assign) CGFloat rightSwipeOffset; +@property(nonatomic, readwrite, assign) CGFloat rightSwipeSize; +@property(nonatomic, readwrite, assign) CGFloat rightSwipeStretchSize; +@property(nonatomic, readwrite, assign) CGFloat rightSwipeStretchMinThreshold; +@property(nonatomic, readwrite, assign) CGFloat rightSwipeStretchMaxThreshold; + +- (void)setShowedLeftSwipeView:(BOOL)showedLeftSwipeView animated:(BOOL)animated; +- (void)setShowedRightSwipeView:(BOOL)showedRightSwipeView animated:(BOOL)animated; +- (void)hideAnySwipeViewAnimated:(BOOL)animated; + +- (void)willBeganSwipe NS_REQUIRES_SUPER; +- (void)didBeganSwipe NS_REQUIRES_SUPER; +- (void)movingSwipe:(CGFloat)progress NS_REQUIRES_SUPER; +- (void)willEndedSwipe:(CGFloat)progress NS_REQUIRES_SUPER; +- (void)didEndedSwipe:(CGFloat)progress NS_REQUIRES_SUPER; + +- (CGFloat)endedSwipeProgress:(CGFloat)progress; + +@end + +/*--------------------------------------------------*/ + +extern NSString* MobilyDataCellPressed; +extern NSString* MobilyDataCellLongPressed; + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataCell.m b/Sources/MobilyCore/MobilyDataCell.m new file mode 100644 index 0000000..0c79545 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataCell.m @@ -0,0 +1,421 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyDataCell + +#pragma mark Synthesize + +@synthesize identifier = _identifier; +@synthesize view = _view; +@synthesize item = _item; +@synthesize selected = _selected; +@synthesize highlighted = _highlighted; +@synthesize editing = _editing; +@synthesize pressGestureRecognizer = _pressGestureRecognizer; +@synthesize tapGestureRecognizer = _tapGestureRecognizer; +@synthesize longPressGestureRecognizer = _longPressGestureRecognizer; +@synthesize rootView = _rootView; +@synthesize rootOffsetOfCenter = _rootOffsetOfCenter; +@synthesize rootMarginSize = _rootMarginSize; +@synthesize constraintRootViewCenterX = _constraintRootViewCenterX; +@synthesize constraintRootViewCenterY = _constraintRootViewCenterY; +@synthesize constraintRootViewWidth = _constraintRootViewWidth; +@synthesize constraintRootViewHeight = _constraintRootViewHeight; + +#pragma mark Calculating size + ++ (CGSize)sizeForItem:(MobilyDataItem*)item availableSize:(CGSize)size { + static NSMutableDictionary* cacheCells = nil; + if(cacheCells == nil) { + cacheCells = [NSMutableDictionary dictionary]; + } + NSString* identifier = item.identifier; + id cell = cacheCells[identifier]; + if (cell == nil) { + cell = [[item.view.registersViews[identifier] alloc] initWithIdentifier:identifier]; + cacheCells[identifier] = cell; + } + [cell setFrame:CGRectMake(0.0f, 0.0f, size.width, size.height)]; + [cell setSelected:item.selected]; + [cell setHighlighted:item.highlighted]; + [cell setEditing:item.editing]; + [cell setItem:item]; + [cell setNeedsLayout]; + [cell layoutIfNeeded]; + if(UIDevice.moSystemVersion >= 8.0f) { + return [cell systemLayoutSizeFittingSize:CGSizeMake(size.width, size.height) withHorizontalFittingPriority:[self fittingHorizontalPriority] verticalFittingPriority:[self fittingVerticalPriority]]; + } + return [cell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; +} + ++ (UILayoutPriority)fittingHorizontalPriority { + return UILayoutPriorityRequired; +} + ++ (UILayoutPriority)fittingVerticalPriority { + return UILayoutPriorityFittingSizeLevel; +} + +#pragma mark Init / Free + +- (instancetype)initWithIdentifier:(NSString*)identifier { + return [self initWithIdentifier:identifier nib:[UINib moNibWithClass:self.class bundle:nil]]; +} + +- (instancetype)initWithIdentifier:(NSString*)identifier nib:(UINib*)nib { + self = [super init]; + if(self != nil) { + _identifier = identifier; + if(nib != nil) { + [nib instantiateWithOwner:self options:nil]; + } + [self setup]; + } + return self; +} + +- (void)setup { + self.clipsToBounds = YES; + self.hidden = YES; + self.pressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_handlerPressGestureRecognizer:)]; + self.tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_handlerTapGestureRecognizer:)]; + self.longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(_handlerLongPressGestureRecognizer:)]; +} + +#pragma mark UIView + +- (void)updateConstraints { + if(_rootView != nil) { + if(_constraintRootViewCenterX == nil) { + self.constraintRootViewCenterX = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:_rootOffsetOfCenter.horizontal]; + } + if(_constraintRootViewCenterY == nil) { + self.constraintRootViewCenterY = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:_rootOffsetOfCenter.vertical]; + } + if(_constraintRootViewWidth == nil) { + self.constraintRootViewWidth = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0f constant:_rootMarginSize.horizontal]; + } + if(_constraintRootViewHeight == nil) { + self.constraintRootViewHeight = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0f constant:_rootMarginSize.vertical]; + } + } else { + self.constraintRootViewCenterX = nil; + self.constraintRootViewCenterY = nil; + self.constraintRootViewWidth = nil; + self.constraintRootViewHeight = nil; + } + [super updateConstraints]; +} + +#pragma mark Property + +- (void)setItem:(MobilyDataItem*)item { + if(_item != item) { + if(_item != nil) { + [self prepareForUnuse]; + self.hidden = YES; + } + _item = item; + if(_item != nil) { + self.hidden = NO; + [self prepareForUse]; + } + } +} + +- (void)setSelected:(BOOL)selected { + [self setSelected:selected animated:NO]; +} + +- (void)setHighlighted:(BOOL)highlighted { + [self setHighlighted:highlighted animated:NO]; +} + +- (void)setEditing:(BOOL)editing { + [self setEditing:editing animated:NO]; +} + +- (void)setPressGestureRecognizer:(UILongPressGestureRecognizer*)pressGestureRecognizer { + if(_pressGestureRecognizer != pressGestureRecognizer) { + if(_pressGestureRecognizer != nil) { + [_rootView removeGestureRecognizer:_pressGestureRecognizer]; + } + _pressGestureRecognizer = pressGestureRecognizer; + if(_pressGestureRecognizer != nil) { + _pressGestureRecognizer.delaysTouchesBegan = YES; + _pressGestureRecognizer.delaysTouchesEnded = YES; + _pressGestureRecognizer.minimumPressDuration = 0.01f; + _pressGestureRecognizer.delegate = self; + [_rootView addGestureRecognizer:_pressGestureRecognizer]; + } + } +} + +- (void)setTapGestureRecognizer:(UITapGestureRecognizer*)tapGestureRecognizer { + if(_tapGestureRecognizer != tapGestureRecognizer) { + if(_tapGestureRecognizer != nil) { + [_rootView removeGestureRecognizer:_tapGestureRecognizer]; + } + _tapGestureRecognizer = tapGestureRecognizer; + if(_tapGestureRecognizer != nil) { + _tapGestureRecognizer.delaysTouchesBegan = YES; + _tapGestureRecognizer.delaysTouchesEnded = YES; + _tapGestureRecognizer.delegate = self; + [_rootView addGestureRecognizer:_tapGestureRecognizer]; + } + } +} + +- (void)setLongPressGestureRecognizer:(UILongPressGestureRecognizer*)longPressGestureRecognizer { + if(_longPressGestureRecognizer != longPressGestureRecognizer) { + if(_longPressGestureRecognizer != nil) { + [_rootView removeGestureRecognizer:_longPressGestureRecognizer]; + } + _longPressGestureRecognizer = longPressGestureRecognizer; + if(_longPressGestureRecognizer != nil) { + _longPressGestureRecognizer.delaysTouchesBegan = YES; + _longPressGestureRecognizer.delaysTouchesEnded = YES; + _longPressGestureRecognizer.delegate = self; + [_rootView addGestureRecognizer:_longPressGestureRecognizer]; + } + } +} + +- (void)setRootView:(UIView*)rootView { + if(_rootView != rootView) { + if(_rootView != nil) { + [_rootView removeFromSuperview]; + } + _rootView = rootView; + if(_rootView != nil) { + _rootView.translatesAutoresizingMaskIntoConstraints = NO; + } + [self moSetSubviews:self.orderedSubviews]; + [self setNeedsUpdateConstraints]; + } +} + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRootViewCenterX, constraintRootViewCenterX, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRootViewCenterY, constraintRootViewCenterY, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRootViewWidth, constraintRootViewWidth, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRootViewHeight, constraintRootViewHeight, self, { +}, { +}) + +- (void)setRootOffsetOfCenter:(UIOffset)rootOffsetOfCenter { + if(UIOffsetEqualToOffset(_rootOffsetOfCenter, rootOffsetOfCenter) == NO) { + _rootOffsetOfCenter = rootOffsetOfCenter; + if(_constraintRootViewCenterX != nil) { + _constraintRootViewCenterX.constant = _rootOffsetOfCenter.horizontal; + } + if(_constraintRootViewCenterY != nil) { + _constraintRootViewCenterY.constant = _rootOffsetOfCenter.vertical; + } + } +} + +- (void)setRootMarginSize:(UIOffset)rootMarginSize { + if(UIOffsetEqualToOffset(_rootMarginSize, rootMarginSize) == NO) { + _rootMarginSize = rootMarginSize; + if(_constraintRootViewWidth != nil) { + _constraintRootViewWidth.constant = _rootMarginSize.horizontal; + } + if(_constraintRootViewHeight != nil) { + _constraintRootViewHeight.constant = _rootMarginSize.vertical; + } + } +} + +- (NSArray*)orderedSubviews { + if(_rootView != nil) { + return @[ _rootView ]; + } + return @[ ]; +} + +#pragma mark Public + +- (void)prepareForUse { +} + +- (void)prepareForUnuse { +} + +- (BOOL)containsEventForKey:(id)key { + return [_view containsEventForKey:key]; +} + +- (BOOL)containsEventForIdentifier:(NSString*)identifier forKey:(id)key { + return [_view containsEventForIdentifier:identifier forKey:key]; +} + +- (void)fireEventForKey:(id)key byObject:(id)object { + [_view fireEventForIdentifier:_identifier forKey:key bySender:self byObject:object]; +} + +- (id)fireEventForKey:(id)key byObject:(id)object orDefault:(id)orDefault { + return [_view fireEventForIdentifier:_identifier forKey:key bySender:self byObject:object orDefault:orDefault]; +} + +- (void)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object { + [_view fireEventForIdentifier:_identifier forKey:key bySender:sender byObject:object]; +} + +- (id)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault { + return [_view fireEventForIdentifier:_identifier forKey:key bySender:sender byObject:object orDefault:orDefault]; +} + +- (void)setSelected:(BOOL)selected animated:(BOOL __unused)animated { + _selected = selected; +} + +- (void)setHighlighted:(BOOL)highlighted animated:(BOOL __unused)animated { + _highlighted = highlighted; +} + +- (void)setEditing:(BOOL)editing animated:(BOOL __unused)animated { + _editing = editing; +} + +- (void)validateLayoutForBounds:(CGRect __unused)bounds { +} + +- (void)invalidateLayoutForBounds:(CGRect __unused)bounds { +} + +#pragma mark Private + +- (void)_pressed { + [_view _pressedItem:_item animated:YES]; + [self fireEventForKey:MobilyDataCellPressed byObject:_item]; +} + +- (void)_longPressed { + [self fireEventForKey:MobilyDataCellLongPressed byObject:_item]; +} + +- (void)_handlerPressGestureRecognizer:(UILongPressGestureRecognizer*)gestureRecognizer { + if(gestureRecognizer.state == UIGestureRecognizerStateBegan) { + if(_highlighted == NO) { + [_item setHighlighted:YES animated:NO]; + } + } else if(_highlighted == YES) { + [_item setHighlighted:NO animated:NO]; + } +} + +- (void)_handlerTapGestureRecognizer:(UITapGestureRecognizer*)gestureRecognizer { + if(gestureRecognizer.state == UIGestureRecognizerStateEnded) { + [self _pressed]; + } +} + +- (void)_handlerLongPressGestureRecognizer:(UILongPressGestureRecognizer*)gestureRecognizer { + if(gestureRecognizer.state == UIGestureRecognizerStateBegan) { + [self.tapGestureRecognizer requireGestureRecognizerToFail:gestureRecognizer]; + [self _longPressed]; + } +} + +#pragma mark UIGestureRecognizerDelegate + +- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer { + if((_view.isDragging == YES) || (_view.isDecelerating == YES)) { + return NO; + } + return YES; +} + +- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer { + return YES; +} + +- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldReceiveTouch:(UITouch*)touch { + UIView* view = touch.view; + if([view isKindOfClass:[UIControl class]] == YES) { + return NO; + } + return (view == _rootView) || (view.canBecomeFirstResponder == NO); +} + +#pragma mark MobilySearchBarDelegate + +- (void)searchBarBeginSearch:(MobilySearchBar*)searchBar { +} + +- (void)searchBarEndSearch:(MobilySearchBar*)searchBar { +} + +- (void)searchBarBeginEditing:(MobilySearchBar*)searchBar { +} + +- (void)searchBar:(MobilySearchBar*)searchBar textChanged:(NSString*)textChanged { +} + +- (void)searchBarEndEditing:(MobilySearchBar*)searchBar { +} + +- (void)searchBarPressedClear:(MobilySearchBar*)searchBar { +} + +- (void)searchBarPressedReturn:(MobilySearchBar*)searchBar { +} + +- (void)searchBarPressedCancel:(MobilySearchBar*)searchBar { +} + +@end + +/*--------------------------------------------------*/ + +NSString* MobilyDataCellPressed = @"MobilyDataCellPressed"; +NSString* MobilyDataCellLongPressed = @"MobilyDataCellLongPressed"; + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataCellSwipe.m b/Sources/MobilyCore/MobilyDataCellSwipe.m new file mode 100644 index 0000000..3e0b32a --- /dev/null +++ b/Sources/MobilyCore/MobilyDataCellSwipe.m @@ -0,0 +1,714 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyDataCellSwipe + +#pragma mark Synthesize + +@synthesize panGestureRecognizer = _panGestureRecognizer; +@synthesize swipeEnabled = _swipeEnabled; +@synthesize swipeStyle = _swipeStyle; +@synthesize swipeThreshold = _swipeThreshold; +@synthesize swipeVelocity = _swipeVelocity; +@synthesize swipeSpeed = _swipeSpeed; +@synthesize swipeDragging = _swipeDragging; +@synthesize swipeDecelerating = _swipeDecelerating; +@synthesize showedLeftSwipeView = _showedLeftSwipeView; +@synthesize leftSwipeEnabled = _leftSwipeEnabled; +@synthesize leftSwipeView = _leftSwipeView; +@synthesize leftSwipeOffset = _leftSwipeOffset; +@synthesize leftSwipeSize = _leftSwipeSize; +@synthesize leftSwipeStretchSize = _leftSwipeStretchSize; +@synthesize leftSwipeStretchMinThreshold = _leftSwipeStretchMinThreshold; +@synthesize leftSwipeStretchMaxThreshold = _leftSwipeStretchMaxThreshold; +@synthesize showedRightSwipeView = _showedRightSwipeView; +@synthesize rightSwipeEnabled = _rightSwipeEnabled; +@synthesize rightSwipeView = _rightSwipeView; +@synthesize rightSwipeOffset = _rightSwipeOffset; +@synthesize rightSwipeSize = _rightSwipeSize; +@synthesize rightSwipeStretchSize = _rightSwipeStretchSize; +@synthesize rightSwipeStretchMinThreshold = _rightSwipeStretchMinThreshold; +@synthesize rightSwipeStretchMaxThreshold = _rightSwipeStretchMaxThreshold; +@synthesize constraintLeftSwipeViewOffsetX = _constraintLeftSwipeViewOffsetX; +@synthesize constraintLeftSwipeViewCenterY = _constraintLeftSwipeViewCenterY; +@synthesize constraintLeftSwipeViewWidth = _constraintLeftSwipeViewWidth; +@synthesize constraintLeftSwipeViewHeight = _constraintLeftSwipeViewHeight; +@synthesize constraintRightSwipeViewOffsetX = _constraintRightSwipeViewOffsetX; +@synthesize constraintRightSwipeViewCenterY = _constraintRightSwipeViewCenterY; +@synthesize constraintRightSwipeViewWidth = _constraintRightSwipeViewWidth; +@synthesize constraintRightSwipeViewHeight = _constraintRightSwipeViewHeight; +@synthesize panSwipeLastOffset = _panSwipeLastOffset; +@synthesize panSwipeLastVelocity = _panSwipeLastVelocity; +@synthesize panSwipeProgress = _panSwipeProgress; +@synthesize panSwipeLeftWidth = _panSwipeLeftWidth; +@synthesize panSwipeRightWidth = _panSwipeRightWidth; +@synthesize panSwipeDirection = _panSwipeDirection; + +#pragma mark Init / Free + +- (void)setup { + [super setup]; + + self.panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(_handlerPanGestureRecognizer:)]; + + _swipeEnabled = YES; + _swipeStyle = MobilyDataSwipeCellStyleLeaves; + _swipeThreshold = 2.0f; + _swipeSpeed = 1050.0f; + _swipeVelocity = 570.0f; + _leftSwipeEnabled = YES; + _leftSwipeSize = -1.0f; + _leftSwipeStretchSize = 128.0f; + _leftSwipeStretchMinThreshold = 0.2f; + _leftSwipeStretchMaxThreshold = 0.6f; + _rightSwipeEnabled = YES; + _rightSwipeSize = -1.0f; + _rightSwipeStretchSize = 128.0f; + _rightSwipeStretchMinThreshold = 0.2f; + _rightSwipeStretchMaxThreshold = 0.6f; + _rootOffsetOfCenter = [self _rootViewOffsetOfCenterBySwipeProgress:0.0f]; + _leftSwipeOffset = [self _leftViewOffsetBySwipeProgress:0.0f]; + _rightSwipeOffset = [self _rightViewOffsetBySwipeProgress:0.0f]; +} + +- (void)dealloc { +} + +#pragma mark UIView + +- (void)updateConstraints { + if(_leftSwipeView != nil) { + if(_leftSwipeSize >= 0.0f) { + if(_constraintLeftSwipeViewWidth == nil) { + self.constraintLeftSwipeViewWidth = [NSLayoutConstraint constraintWithItem:_leftSwipeView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:_leftSwipeSize]; + } + } else { + self.constraintLeftSwipeViewWidth = nil; + } + if(_constraintLeftSwipeViewOffsetX == nil) { + self.constraintLeftSwipeViewOffsetX = [NSLayoutConstraint constraintWithItem:_leftSwipeView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:_leftSwipeOffset]; + } + if(_constraintLeftSwipeViewCenterY == nil) { + self.constraintLeftSwipeViewCenterY = [NSLayoutConstraint constraintWithItem:_leftSwipeView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]; + } + if(_constraintLeftSwipeViewHeight == nil) { + self.constraintLeftSwipeViewHeight = [NSLayoutConstraint constraintWithItem:_leftSwipeView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]; + } + } else { + self.constraintLeftSwipeViewOffsetX = nil; + self.constraintLeftSwipeViewCenterY = nil; + self.constraintLeftSwipeViewWidth = nil; + self.constraintLeftSwipeViewHeight = nil; + } + if(_rightSwipeView != nil) { + if(_rightSwipeSize >= 0.0f) { + if(_constraintRightSwipeViewWidth == nil) { + self.constraintRightSwipeViewWidth = [NSLayoutConstraint constraintWithItem:_rightSwipeView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:_rightSwipeSize]; + } + } else { + self.constraintRightSwipeViewWidth = nil; + } + if(_constraintRightSwipeViewOffsetX == nil) { + self.constraintRightSwipeViewOffsetX = [NSLayoutConstraint constraintWithItem:_rightSwipeView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:_rightSwipeOffset]; + } + if(_constraintRightSwipeViewCenterY == nil) { + self.constraintRightSwipeViewCenterY = [NSLayoutConstraint constraintWithItem:_rightSwipeView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]; + } + if(_constraintRightSwipeViewHeight == nil) { + self.constraintRightSwipeViewHeight = [NSLayoutConstraint constraintWithItem:_rightSwipeView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]; + } + } else { + self.constraintRightSwipeViewOffsetX = nil; + self.constraintRightSwipeViewCenterY = nil; + self.constraintRightSwipeViewWidth = nil; + self.constraintRightSwipeViewHeight = nil; + } + [super updateConstraints]; +} + +#pragma mark Property + +- (NSArray*)orderedSubviews { + NSMutableArray* result = NSMutableArray.array; + switch(_swipeStyle) { + case MobilyDataSwipeCellStyleStands: + case MobilyDataSwipeCellStyleStretch: { + if(_leftSwipeView != nil) { + [result addObject:_leftSwipeView]; + } + if(_rightSwipeView != nil) { + [result addObject:_rightSwipeView]; + } + if(self.rootView != nil) { + [result addObject:self.rootView]; + } + break; + } + case MobilyDataSwipeCellStyleLeaves: + case MobilyDataSwipeCellStylePushes: { + if(self.rootView != nil) { + [result addObject:self.rootView]; + } + if(_leftSwipeView != nil) { + [result addObject:_leftSwipeView]; + } + if(_rightSwipeView != nil) { + [result addObject:_rightSwipeView]; + } + break; + } + } + return result; +} + +- (void)setEditing:(BOOL)editing animated:(BOOL)animated { + [super setEditing:editing animated:animated]; + + if(editing == NO) { + [self hideAnySwipeViewAnimated:animated]; + } +} + +- (void)setRootView:(UIView*)rootView { + super.rootView = rootView; + + self.rootOffsetOfCenter = [self _rootViewOffsetOfCenterBySwipeProgress:0.0f]; +} + +- (void)setPanGestureRecognizer:(UIPanGestureRecognizer*)panGestureRecognizer { + if(_panGestureRecognizer != panGestureRecognizer) { + if(_panGestureRecognizer != nil) { + [_rootView removeGestureRecognizer:_panGestureRecognizer]; + } + _panGestureRecognizer = panGestureRecognizer; + if(_panGestureRecognizer != nil) { + _panGestureRecognizer.delaysTouchesBegan = YES; + _panGestureRecognizer.delaysTouchesEnded = YES; + _panGestureRecognizer.delegate = self; + [_rootView addGestureRecognizer:_panGestureRecognizer]; + } + } +} + +- (void)setSwipeStyle:(MobilyDataSwipeCellStyle)swipeStyle { + if(_swipeStyle != swipeStyle) { + self.constraintLeftSwipeViewOffsetX = nil; + self.constraintLeftSwipeViewCenterY = nil; + self.constraintLeftSwipeViewWidth = nil; + self.constraintLeftSwipeViewHeight = nil; + self.constraintRightSwipeViewOffsetX = nil; + self.constraintRightSwipeViewCenterY = nil; + self.constraintRightSwipeViewWidth = nil; + self.constraintRightSwipeViewHeight = nil; + _swipeStyle = swipeStyle; + [self moSetSubviews:self.orderedSubviews]; + self.rootOffsetOfCenter = [self _rootViewOffsetOfCenterBySwipeProgress:0.0f]; + self.leftSwipeOffset = [self _leftViewOffsetBySwipeProgress:0.0f]; + self.rightSwipeOffset = [self _rightViewOffsetBySwipeProgress:0.0f]; + [self setNeedsUpdateConstraints]; + } +} + +- (void)setShowedLeftSwipeView:(BOOL)showedSwipeLeft { + [self setShowedLeftSwipeView:showedSwipeLeft animated:NO]; +} + +- (void)setLeftSwipeView:(UIView*)leftSwipeView { + if(_leftSwipeView != leftSwipeView) { + if(_leftSwipeView != nil) { + [_leftSwipeView removeFromSuperview]; + } + _leftSwipeView = leftSwipeView; + if(_leftSwipeView != nil) { + _leftSwipeView.translatesAutoresizingMaskIntoConstraints = NO; + [self moSetSubviews:self.orderedSubviews]; + } + self.leftSwipeOffset = [self _leftViewOffsetBySwipeProgress:0.0f]; + [self setNeedsUpdateConstraints]; + } +} + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintLeftSwipeViewOffsetX, constraintLeftSwipeViewOffsetX, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintLeftSwipeViewCenterY, constraintLeftSwipeViewCenterY, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintLeftSwipeViewWidth, constraintLeftSwipeViewWidth, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintLeftSwipeViewHeight, constraintLeftSwipeViewHeight, self, { +}, { +}) + +- (void)setLeftSwipeOffset:(CGFloat)leftSwipeOffset { + if(_leftSwipeOffset != leftSwipeOffset) { + _leftSwipeOffset = leftSwipeOffset; + if(_constraintLeftSwipeViewOffsetX != nil) { + _constraintLeftSwipeViewOffsetX.constant = _leftSwipeOffset; + } + } +} + +- (void)setLeftSwipeSize:(CGFloat)leftSwipeSize { + if(_leftSwipeSize != leftSwipeSize) { + _leftSwipeSize = leftSwipeSize; + if(_leftSwipeSize < 0.0f) { + [self setNeedsUpdateConstraints]; + } else if(_constraintLeftSwipeViewWidth != nil) { + _constraintLeftSwipeViewWidth.constant = _leftSwipeSize; + } + } +} + +- (void)setShowedRightSwipeView:(BOOL)showedRightSwipeView { + [self setShowedRightSwipeView:showedRightSwipeView animated:NO]; +} + +- (void)setRightSwipeView:(UIView*)rightSwipeView { + if(_rightSwipeView != rightSwipeView) { + if(_rightSwipeView != nil) { + [_rightSwipeView removeFromSuperview]; + } + _rightSwipeView = rightSwipeView; + if(_rightSwipeView != nil) { + _rightSwipeView.translatesAutoresizingMaskIntoConstraints = NO; + [self moSetSubviews:self.orderedSubviews]; + } + self.rightSwipeOffset = [self _rightViewOffsetBySwipeProgress:0.0f]; + [self setNeedsUpdateConstraints]; + } +} + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRightSwipeViewOffsetX, constraintRightSwipeViewOffsetX, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRightSwipeViewCenterY, constraintRightSwipeViewCenterY, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRightSwipeViewWidth, constraintRightSwipeViewWidth, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRightSwipeViewHeight, constraintRightSwipeViewHeight, self, { +}, { +}) + +- (void)setRightSwipeOffset:(CGFloat)rightSwipeOffset { + if(_rightSwipeOffset != rightSwipeOffset) { + _rightSwipeOffset = rightSwipeOffset; + if(_constraintRightSwipeViewOffsetX != nil) { + _constraintRightSwipeViewOffsetX.constant = _rightSwipeOffset; + } + } +} + +- (void)setRightSwipeSize:(CGFloat)rightSwipeSize { + if(_rightSwipeSize != rightSwipeSize) { + _rightSwipeSize = rightSwipeSize; + if(_rightSwipeSize < 0.0f) { + [self setNeedsUpdateConstraints]; + } else if(_constraintRightSwipeViewWidth != nil) { + _constraintRightSwipeViewWidth.constant = _rightSwipeSize; + } + } +} + +#pragma mark Public + +- (void)setShowedLeftSwipeView:(BOOL)showedLeftSwipeView animated:(BOOL)animated { + if(_showedLeftSwipeView != showedLeftSwipeView) { + _showedLeftSwipeView = showedLeftSwipeView; + _showedRightSwipeView = NO; + + CGFloat needSwipeProgress = (showedLeftSwipeView == YES) ? -1.0f : 0.0f; + [self _updateSwipeProgress:needSwipeProgress + speed:(animated == YES) ? _leftSwipeView.moFrameWidth * MOBILY_FABS(needSwipeProgress - _panSwipeProgress) : MOBILY_EPSILON + endedSwipe:NO]; + } +} + +- (void)setShowedRightSwipeView:(BOOL)showedRightSwipeView animated:(BOOL)animated { + if(_showedRightSwipeView != showedRightSwipeView) { + _showedRightSwipeView = showedRightSwipeView; + _showedLeftSwipeView = NO; + + CGFloat needSwipeProgress = (_showedRightSwipeView == YES) ? 1.0f : 0.0f; + [self _updateSwipeProgress:needSwipeProgress + speed:(animated == YES) ? _rightSwipeView.moFrameWidth * MOBILY_FABS(needSwipeProgress - _panSwipeProgress) : MOBILY_EPSILON + endedSwipe:NO]; + } +} + +- (void)hideAnySwipeViewAnimated:(BOOL)animated { + [self setShowedLeftSwipeView:NO animated:animated]; + [self setShowedRightSwipeView:NO animated:animated]; +} + +- (void)willBeganSwipe { +} + +- (void)didBeganSwipe { + self.swipeDragging = YES; +} + +- (void)movingSwipe:(CGFloat __unused)progress { +} + +- (void)willEndedSwipe:(CGFloat __unused)progress { + self.swipeDragging = NO; + self.swipeDecelerating = YES; +} + +- (void)didEndedSwipe:(CGFloat)progress { + _showedLeftSwipeView = (progress < 0.0f) ? YES : NO; + _showedRightSwipeView = (progress > 0.0f) ? YES : NO; + self.swipeDecelerating = NO; + + [self.item setEditing:((_showedLeftSwipeView == YES) || (_showedRightSwipeView == YES)) animated:YES]; +} + +- (CGFloat)endedSwipeProgress:(CGFloat)progress { + CGFloat minProgress = (_panSwipeDirection == MobilyDataCellSwipeDirectionLeft) ? -1.0f : 0.0f; + CGFloat maxProgress = (_panSwipeDirection == MobilyDataCellSwipeDirectionRight) ? 1.0f : 0.0f; + if(_swipeStyle == MobilyDataSwipeCellStyleStretch) { + if(progress < 0.0f) { + if(_panSwipeDirection == MobilyDataCellSwipeDirectionLeft) { + if(progress < -_leftSwipeStretchMaxThreshold) { + progress = -1.0f; + } else if(progress < -_leftSwipeStretchMinThreshold) { + progress = -(_leftSwipeStretchSize / _rootView.moFrameWidth); + } else { + progress = 0.0f; + } + } else { + progress = 0.0f; + } + } else if(progress > 0.0f) { + if(_panSwipeDirection == MobilyDataCellSwipeDirectionRight) { + if(progress > _rightSwipeStretchMaxThreshold) { + progress = 1.0f; + } else if(progress > _rightSwipeStretchMinThreshold) { + progress = (_rightSwipeStretchSize / _rootView.moFrameWidth); + } else { + progress = 0.0f; + } + } else { + progress = 0.0f; + } + } + } else { + progress = roundf(progress); + } + return MIN(MAX(minProgress, progress), maxProgress); +} + +#pragma mark Private override + +- (void)_pressed { + if(_showedLeftSwipeView == YES) { + [self setShowedLeftSwipeView:NO animated:YES]; + } else if(_showedRightSwipeView == YES) { + [self setShowedRightSwipeView:NO animated:YES]; + } else { + [super _pressed]; + } +} + +- (void)_longPressed { + if(_showedLeftSwipeView == YES) { + [self setShowedLeftSwipeView:NO animated:YES]; + } else if(_showedRightSwipeView == YES) { + [self setShowedRightSwipeView:NO animated:YES]; + } else { + [super _longPressed]; + } +} + +#pragma mark Private + +- (UIOffset)_rootViewOffsetOfCenterBySwipeProgress:(CGFloat)swipeProgress { + switch(_swipeStyle) { + case MobilyDataSwipeCellStyleStands: + case MobilyDataSwipeCellStyleLeaves: + if(swipeProgress < 0.0f) { + return UIOffsetMake(_leftSwipeView.moFrameWidth * -swipeProgress, 0.0f); + } else if(swipeProgress > 0.0f) { + return UIOffsetMake(-_rightSwipeView.moFrameWidth * swipeProgress, 0.0f); + } + break; + case MobilyDataSwipeCellStyleStretch: + if(swipeProgress < 0.0f) { + return UIOffsetMake(_rootView.moFrameWidth * -swipeProgress, 0.0f); + } else if(swipeProgress > 0.0f) { + return UIOffsetMake(-_rootView.moFrameWidth * swipeProgress, 0.0f); + } + break; + case MobilyDataSwipeCellStylePushes: + break; + } + return UIOffsetMake(0.0f, 0.0f); +} + +- (CGFloat)_leftViewOffsetBySwipeProgress:(CGFloat)swipeProgress { + CGFloat leftWidth = _leftSwipeView.moFrameWidth; + switch(_swipeStyle) { + case MobilyDataSwipeCellStyleStands: + return 0.0f; + case MobilyDataSwipeCellStyleLeaves: + case MobilyDataSwipeCellStylePushes: + if(swipeProgress < 0.0f) { + return -leftWidth + (leftWidth * (-swipeProgress)); + } + break; + case MobilyDataSwipeCellStyleStretch: + return 0.0f; + } + return -leftWidth; +} + +- (CGFloat)_leftViewSizeBySwipeProgress:(CGFloat)swipeProgress { + switch(_swipeStyle) { + case MobilyDataSwipeCellStyleStretch: + if(swipeProgress < 0.0f) { + return _rootView.moFrameWidth * -swipeProgress; + } + return 0.0f; + default: + break; + } + return -1.0f; +} + +- (CGFloat)_rightViewOffsetBySwipeProgress:(CGFloat)swipeProgress { + CGFloat rigthWidth = _rightSwipeView.moFrameWidth; + switch(_swipeStyle) { + case MobilyDataSwipeCellStyleStands: + return 0.0f; + case MobilyDataSwipeCellStyleLeaves: + case MobilyDataSwipeCellStylePushes: + if(swipeProgress > 0.0f) { + return rigthWidth * (1.0f - swipeProgress); + } + break; + case MobilyDataSwipeCellStyleStretch: + return 0.0f; + } + return rigthWidth; +} + +- (CGFloat)_rightViewSizeBySwipeProgress:(CGFloat)swipeProgress { + switch(_swipeStyle) { + case MobilyDataSwipeCellStyleStretch: + if(swipeProgress > 0.0f) { + return _rootView.moFrameWidth * swipeProgress; + } + return 0.0f; + default: + break; + } + return -1.0f; +} + +- (void)_updateSwipeProgress:(CGFloat)swipeProgress speed:(CGFloat)speed endedSwipe:(BOOL)endedSwipe { + CGFloat minSwipeProgress = (_panSwipeDirection == MobilyDataCellSwipeDirectionLeft) ? -1.0f : 0.0f; + CGFloat maxSwipeProgress = (_panSwipeDirection == MobilyDataCellSwipeDirectionRight) ? 1.0f : 0.0f; + CGFloat normalizedSwipeProgress = MIN(MAX(minSwipeProgress, swipeProgress), maxSwipeProgress); + if(_panSwipeProgress != normalizedSwipeProgress) { + _panSwipeProgress = normalizedSwipeProgress; + self.rootOffsetOfCenter = [self _rootViewOffsetOfCenterBySwipeProgress:_panSwipeProgress]; + self.leftSwipeOffset = [self _leftViewOffsetBySwipeProgress:_panSwipeProgress]; + self.leftSwipeSize = [self _leftViewSizeBySwipeProgress:_panSwipeProgress]; + self.rightSwipeOffset = [self _rightViewOffsetBySwipeProgress:_panSwipeProgress]; + self.rightSwipeSize = [self _rightViewSizeBySwipeProgress:_panSwipeProgress]; + [self setNeedsUpdateConstraints]; + + if(endedSwipe == YES) { + [self willEndedSwipe:_panSwipeProgress]; + } + [UIView animateWithDuration:MOBILY_FABS(speed) / _swipeSpeed + delay:0.0f + options:UIViewAnimationOptionBeginFromCurrentState + animations:^{ + [self movingSwipe:_panSwipeProgress]; + [self layoutIfNeeded]; + } completion:^(BOOL finished __unused) { + if(endedSwipe == YES) { + [self didEndedSwipe:_panSwipeProgress]; + } + }]; + } else { + if(endedSwipe == YES) { + [self willEndedSwipe:_panSwipeProgress]; + [self didEndedSwipe:_panSwipeProgress]; + } + } +} + +- (void)_handlerPanGestureRecognizer:(UIPanGestureRecognizer*)gestureRecognizer { + if(_swipeDecelerating == NO) { + CGPoint translation = [gestureRecognizer translationInView:self]; + CGPoint velocity = [gestureRecognizer velocityInView:self]; + switch([gestureRecognizer state]) { + case UIGestureRecognizerStateBegan: { + [self willBeganSwipe]; + self.panSwipeLastOffset = translation.x; + self.panSwipeLastVelocity = velocity.x; + switch(_swipeStyle) { + case MobilyDataSwipeCellStyleStands: + case MobilyDataSwipeCellStyleLeaves: + case MobilyDataSwipeCellStylePushes: + self.panSwipeLeftWidth = -_leftSwipeView.moFrameWidth; + self.panSwipeRightWidth = _rightSwipeView.moFrameWidth; + break; + case MobilyDataSwipeCellStyleStretch: + self.panSwipeLeftWidth = (_leftSwipeView != nil) ? -_rootView.moFrameWidth : 0.0f; + self.panSwipeRightWidth = (_rightSwipeView != nil) ? _rootView.moFrameWidth : 0.0f; + break; + } + self.panSwipeDirection = MobilyDataCellSwipeDirectionUnknown; + break; + } + case UIGestureRecognizerStateChanged: { + CGFloat delta = _panSwipeLastOffset - translation.x; + if(_panSwipeDirection == MobilyDataCellSwipeDirectionUnknown) { + switch(_swipeStyle) { + case MobilyDataSwipeCellStyleStands: + case MobilyDataSwipeCellStyleLeaves: + case MobilyDataSwipeCellStylePushes: + if((_leftSwipeEnabled == YES) && (_showedLeftSwipeView == YES) && (_leftSwipeView != nil) && (delta > _swipeThreshold)) { + self.panSwipeDirection = MobilyDataCellSwipeDirectionLeft; + [self didBeganSwipe]; + } else if((_rightSwipeEnabled == YES) && (_showedRightSwipeView == YES) && (_rightSwipeView != nil) && (delta < -_swipeThreshold)) { + self.panSwipeDirection = MobilyDataCellSwipeDirectionRight; + [self didBeganSwipe]; + } else if((_leftSwipeEnabled == YES) && (_showedLeftSwipeView == NO) && (_leftSwipeView != nil) && (delta < -_swipeThreshold)) { + self.panSwipeDirection = MobilyDataCellSwipeDirectionLeft; + [self didBeganSwipe]; + } else if((_rightSwipeEnabled == YES) && (_showedRightSwipeView == NO) && (_rightSwipeView != nil) && (delta > _swipeThreshold)) { + self.panSwipeDirection = MobilyDataCellSwipeDirectionRight; + [self didBeganSwipe]; + } + break; + case MobilyDataSwipeCellStyleStretch: + if(((_leftSwipeEnabled == YES) && (_leftSwipeView != nil) && (delta < -_swipeThreshold)) || (_showedLeftSwipeView == YES)) { + self.panSwipeDirection = MobilyDataCellSwipeDirectionLeft; + [self didBeganSwipe]; + } else if(((_rightSwipeEnabled == YES) && (_rightSwipeView != nil) && (delta > _swipeThreshold)) || (_showedRightSwipeView == YES)) { + self.panSwipeDirection = MobilyDataCellSwipeDirectionRight; + [self didBeganSwipe]; + } + break; + } + } + if(_panSwipeDirection != MobilyDataCellSwipeDirectionUnknown) { + if(_panSwipeDirection == MobilyDataCellSwipeDirectionLeft) { + CGFloat localDelta = MIN(MAX(_panSwipeLeftWidth, delta), -_panSwipeLeftWidth); + [self _updateSwipeProgress:_panSwipeProgress - (localDelta / _panSwipeLeftWidth) speed:localDelta endedSwipe:NO]; + [self movingSwipe:_panSwipeProgress]; + } else if(_panSwipeDirection == MobilyDataCellSwipeDirectionRight) { + CGFloat localDelta = MIN(MAX(-_panSwipeRightWidth, delta), _panSwipeRightWidth); + [self _updateSwipeProgress:_panSwipeProgress + (localDelta / _panSwipeRightWidth) speed:localDelta endedSwipe:NO]; + [self movingSwipe:_panSwipeProgress]; + } + self.panSwipeLastOffset = translation.x; + self.panSwipeLastVelocity = velocity.x; + } + break; + } + case UIGestureRecognizerStateEnded: + case UIGestureRecognizerStateCancelled: { + CGFloat swipeProgress = [self endedSwipeProgress:_panSwipeProgress - (_panSwipeLastVelocity / _swipeVelocity)]; + if(_panSwipeDirection == MobilyDataCellSwipeDirectionLeft) { + [self _updateSwipeProgress:swipeProgress speed:_panSwipeLeftWidth * MOBILY_FABS(swipeProgress - _panSwipeProgress) endedSwipe:YES]; + } else if(_panSwipeDirection == MobilyDataCellSwipeDirectionRight) { + [self _updateSwipeProgress:swipeProgress speed:_panSwipeRightWidth * MOBILY_FABS(swipeProgress - _panSwipeProgress) endedSwipe:YES]; + } + break; + } + default: { + break; + } + } + } +} + +#pragma mark UIGestureRecognizerDelegate + +- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer { + BOOL result = [super gestureRecognizerShouldBegin:gestureRecognizer]; + if(result == YES) { + if(gestureRecognizer == _panGestureRecognizer) { + if((_swipeEnabled == YES) && (_swipeDragging == NO) && (_swipeDecelerating == NO)) { + if([self.item.view shouldBeganEditItem:self.item] == YES) { + CGPoint translation = [_panGestureRecognizer translationInView:self]; + CGFloat absX = MOBILY_FABS(translation.x); + CGFloat absY = MOBILY_FABS(translation.y); + if(absX >= absY) { + if((_leftSwipeEnabled == YES) && (_leftSwipeView != nil)) { + return YES; + } else if((_rightSwipeEnabled == YES) && (_rightSwipeView != nil)) { + return YES; + } + } + } + } + return NO; + } + } + return result; +} + +- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer { + if((gestureRecognizer == _panGestureRecognizer) && ([self.rootView.gestureRecognizers containsObject:otherGestureRecognizer] == NO)) { + return NO; + } + return [super gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataContainer+Private.h b/Sources/MobilyCore/MobilyDataContainer+Private.h new file mode 100644 index 0000000..1c70c9a --- /dev/null +++ b/Sources/MobilyCore/MobilyDataContainer+Private.h @@ -0,0 +1,232 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyDataContainer () { +@protected + __weak MobilyDataView* _view; + __weak MobilyDataContainer* _parent; + BOOL _hidden; + BOOL _allowAutoAlign; + UIEdgeInsets _alignInsets; + MobilyDataContainerAlign _alignPosition; + UIOffset _alignThreshold; + CGRect _frame; +} + +@property(nonatomic, readwrite, weak) MobilyDataView* view; +@property(nonatomic, readwrite, weak) MobilyDataContainer* parent; + +- (void)_willChangeView; +- (void)_didChangeView; +- (void)_willChangeParent; +- (void)_didChangeParent; + +- (void)_willBeginDragging; +- (void)_didScrollDragging:(BOOL)dragging decelerating:(BOOL)decelerating; +- (void)_willEndDraggingWithVelocity:(CGPoint)velocity contentOffset:(inout CGPoint*)contentOffset contentSize:(CGSize)contentSize visibleSize:(CGSize)visibleSize; +- (void)_didEndDraggingWillDecelerate:(BOOL)decelerate; +- (void)_willBeginDecelerating; +- (void)_didEndDecelerating; +- (void)_didEndScrollingAnimation; + +- (void)_didBeginUpdateAnimated:(BOOL)animated; +- (void)_didEndUpdateAnimated:(BOOL)animated; + +- (CGPoint)_alignPointWithContentOffset:(CGPoint)contentOffset contentSize:(CGSize)contentSize visibleSize:(CGSize)visibleSize; +- (CGPoint)_alignWithVelocity:(CGPoint)velocity contentOffset:(CGPoint)contentOffset contentSize:(CGSize)contentSize visibleSize:(CGSize)visibleSize; + +- (CGRect)_validateLayoutForAvailableFrame:(CGRect)frame; +- (void)_willLayoutForBounds:(CGRect)bounds; +- (void)_didLayoutForBounds:(CGRect)bounds; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerSections () { +@protected + NSMutableArray* _sections; +} + +- (CGRect)_validateSectionsForAvailableFrame:(CGRect)frame; +- (void)_willSectionsLayoutForBounds:(CGRect)bounds; +- (void)_didSectionsLayoutForBounds:(CGRect)bounds; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerSectionsList () { + MobilyDataContainerOrientation _orientation; + UIEdgeInsets _margin; + UIOffset _spacing; + BOOL _pagingEnabled; + MobilyDataContainer* _currentSection; +} + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerItems () { +@protected + NSMutableArray* _entries; + BOOL _reverse; +} + +- (void)_prependEntry:(MobilyDataItem*)entry; +- (void)_prependEntries:(NSArray*)entries; +- (void)_appendEntry:(MobilyDataItem*)entry; +- (void)_appendEntries:(NSArray*)entries; +- (void)_insertEntry:(MobilyDataItem*)entry atIndex:(NSUInteger)index; +- (void)_insertEntries:(NSArray*)entries atIndex:(NSUInteger)index; +- (void)_replaceOriginEntry:(MobilyDataItem*)originEntry withEntry:(MobilyDataItem*)entry; +- (void)_replaceOriginEntries:(NSArray*)originEntries withEntries:(NSArray*)entries; +- (void)_deleteEntry:(MobilyDataItem*)entry; +- (void)_deleteEntries:(NSArray*)entries; +- (void)_deleteAllEntries; + +- (CGRect)_validateEntriesForAvailableFrame:(CGRect)frame; +- (void)_willEntriesLayoutForBounds:(CGRect)bounds; +- (void)_didEntriesLayoutForBounds:(CGRect)bounds; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerItemsList () { + MobilyDataContainerOrientation _orientation; + UIEdgeInsets _margin; + UIOffset _spacing; + CGSize _defaultSize; + NSMutableArray* _items; +} + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerItemsFlow () { + MobilyDataContainerOrientation _orientation; + UIEdgeInsets _margin; + UIOffset _spacing; + CGSize _defaultSize; + NSMutableArray* _items; +} + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerItemsGrid () { + MobilyDataContainerOrientation _orientation; + UIEdgeInsets _margin; + UIOffset _spacing; + CGSize _defaultColumnSize; + CGSize _defaultRowSize; + NSUInteger _numberOfColumns; + NSUInteger _numberOfRows; + NSMutableArray* _headerColumns; + NSMutableArray* _footerColumns; + NSMutableArray* _headerRows; + NSMutableArray* _footerRows; + MobilyMutableGrid* _content; +} + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerCalendar () { +@protected + NSCalendar* _calendar; + BOOL _canShowMonth; + BOOL _canSelectMonth; + UIEdgeInsets _monthMargin; + CGFloat _monthHeight; + CGFloat _monthSpacing; + BOOL _canShowWeekdays; + BOOL _canSelectWeekdays; + UIEdgeInsets _weekdaysMargin; + CGFloat _weekdaysHeight; + UIOffset _weekdaysSpacing; + BOOL _canShowDays; + BOOL _canSelectDays; + BOOL _canSelectPreviousDays; + BOOL _canSelectNextDays; + UIEdgeInsets _daysMargin; + CGFloat _daysHeight; + UIOffset _daysSpacing; + NSDate* _beginDate; + NSDate* _endDate; + NSDate* _displayBeginDate; + NSDate* _displayEndDate; + MobilyDataItemCalendarMonth* _monthItem; + NSMutableArray* _weekdayItems; + MobilyMutableGrid* _dayItems; +} + +@property(nonatomic, readwrite, strong) NSCalendar* calendar; +@property(nonatomic, readwrite, strong) NSDate* beginDate; +@property(nonatomic, readwrite, strong) NSDate* endDate; +@property(nonatomic, readwrite, strong) MobilyDataItemCalendarMonth* monthItem; +@property(nonatomic, readwrite, strong) NSMutableArray* weekdayItems; +@property(nonatomic, readwrite, strong) MobilyMutableGrid* dayItems; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerCalendarDays () { +@protected + NSCalendar* _calendar; + MobilyDataContainerOrientation _orientation; + UIEdgeInsets _margin; + UIOffset _spacing; + CGSize _defaultSize; +} + +@property(nonatomic, readwrite, strong) NSCalendar* calendar; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataContainer.h b/Sources/MobilyCore/MobilyDataContainer.h new file mode 100644 index 0000000..5335332 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataContainer.h @@ -0,0 +1,394 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@class MobilyDataView; +@class MobilyDataContainer; +@class MobilyDataItem; +@class MobilyDataCell; + +/*--------------------------------------------------*/ + +@class MobilyMap; +@class MobilyGrid; + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, MobilyDataContainerOrientation) { + MobilyDataContainerOrientationVertical, + MobilyDataContainerOrientationHorizontal, +}; + +typedef NS_OPTIONS(NSUInteger, MobilyDataContainerAlign) { + MobilyDataContainerAlignNone = MobilyDataViewPositionNone, + MobilyDataContainerAlignTop = MobilyDataViewPositionTop, + MobilyDataContainerAlignCenteredVertically = MobilyDataViewPositionCenteredVertically, + MobilyDataContainerAlignBottom = MobilyDataViewPositionBottom, + MobilyDataContainerAlignLeft = MobilyDataViewPositionLeft, + MobilyDataContainerAlignCenteredHorizontally = MobilyDataViewPositionCenteredHorizontally, + MobilyDataContainerAlignRight = MobilyDataViewPositionRight, + MobilyDataContainerAlignCentered = MobilyDataContainerAlignCenteredVertically | MobilyDataContainerAlignCenteredHorizontally, +}; + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyDataContainer : NSObject< MobilyObject, MobilySearchBarDelegate > + +@property(nonatomic, readonly, weak) MobilyDataView* view; +@property(nonatomic, readonly, weak) MobilyDataContainer* parent; +@property(nonatomic, readonly, assign) CGRect frame; +@property(nonatomic, readwrite, assign, getter=isHidden) BOOL hidden; +@property(nonatomic, readonly, assign, getter=isHiddenInHierarchy) BOOL hiddenInHierarchy; +@property(nonatomic, readwrite, assign) BOOL allowAutoAlign; +@property(nonatomic, readwrite, assign) UIEdgeInsets alignInsets; +@property(nonatomic, readwrite, assign) MobilyDataContainerAlign alignPosition; +@property(nonatomic, readwrite, assign) UIOffset alignThreshold; + +- (void)setup NS_REQUIRES_SUPER; + +- (NSArray*)allItems; + +- (MobilyDataItem*)itemForPoint:(CGPoint)point; +- (MobilyDataItem*)itemForData:(id)data; +- (MobilyDataCell*)cellForData:(id)data; + +- (BOOL)containsEventForKey:(id)key; +- (BOOL)containsEventForIdentifier:(NSString*)identifier forKey:(id)key; + +- (void)fireEventForKey:(id)key byObject:(id)object; +- (void)fireEventForIdentifier:(NSString*)identifier forKey:(id)key byObject:(id)object; +- (id)fireEventForKey:(id)key byObject:(id)object orDefault:(id)orDefault; +- (id)fireEventForIdentifier:(NSString*)identifier forKey:(id)key byObject:(id)object orDefault:(id)orDefault; +- (void)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object; +- (void)fireEventForIdentifier:(NSString*)identifier forKey:(id)key bySender:(id)sender byObject:(id)object; +- (id)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault; +- (id)fireEventForIdentifier:(NSString*)identifier forKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault; + +- (CGPoint)alignPoint; +- (void)align; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerSections : MobilyDataContainer + +@property(nonatomic, readonly, strong) NSArray* sections; + +- (void)prependSection:(MobilyDataContainer*)section; +- (void)appendSection:(MobilyDataContainer*)section; +- (void)insertSection:(MobilyDataContainer*)section atIndex:(NSUInteger)index; +- (void)replaceOriginSection:(MobilyDataContainer*)originSection withSection:(MobilyDataContainer*)section; +- (void)deleteSection:(MobilyDataContainer*)section; +- (void)deleteAllSections; + +- (void)scrollToSection:(MobilyDataContainer*)section scrollPosition:(MobilyDataViewPosition)scrollPosition animated:(BOOL)animated; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerSectionsList : MobilyDataContainerSections + +@property(nonatomic, readwrite, assign) MobilyDataContainerOrientation orientation; +@property(nonatomic, readwrite, assign) UIEdgeInsets margin; +@property(nonatomic, readwrite, assign) UIOffset spacing; +@property(nonatomic, readwrite, assign) BOOL pagingEnabled; +@property(nonatomic, readwrite, assign) NSUInteger currentSectionIndex; +@property(nonatomic, readwrite, strong) MobilyDataContainer* currentSection; + ++ (instancetype)containerWithOrientation:(MobilyDataContainerOrientation)orientation; + +- (instancetype)initWithOrientation:(MobilyDataContainerOrientation)orientation; + +- (void)setCurrentSectionIndex:(NSUInteger)currentSectionIndex animated:(BOOL)animated; +- (void)setCurrentSection:(MobilyDataContainer*)currentSection animated:(BOOL)animated; + +@end + +/*--------------------------------------------------*/ + +extern NSString* MobilyDataContainerCurrentSectionChanged; + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerItems : MobilyDataContainer + +@property(nonatomic, readonly, strong) NSArray* entries; +@property(nonatomic, readwrite, assign) BOOL reverse; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerItemsList : MobilyDataContainerItems + +@property(nonatomic, readwrite, assign) MobilyDataContainerOrientation orientation; +@property(nonatomic, readwrite, assign) UIEdgeInsets margin; +@property(nonatomic, readwrite, assign) UIOffset spacing; +@property(nonatomic, readwrite, assign) CGSize defaultSize; +@property(nonatomic, readwrite, strong) MobilyDataItem* header; +@property(nonatomic, readwrite, strong) MobilyDataItem* footer; +@property(nonatomic, readonly, strong) NSArray* items; + ++ (instancetype)containerWithOrientation:(MobilyDataContainerOrientation)orientation; + +- (instancetype)initWithOrientation:(MobilyDataContainerOrientation)orientation; + +- (MobilyDataItem*)prependIdentifier:(NSString*)identifier byData:(id)data; +- (void)prependItem:(MobilyDataItem*)item; +- (void)prependItems:(NSArray*)items; +- (MobilyDataItem*)appendIdentifier:(NSString*)identifier byData:(id)data; +- (void)appendItem:(MobilyDataItem*)item; +- (void)appendItems:(NSArray*)items; +- (MobilyDataItem*)insertIdentifier:(NSString*)identifier byData:(id)data atIndex:(NSUInteger)index; +- (void)insertItem:(MobilyDataItem*)item atIndex:(NSUInteger)index; +- (void)insertItems:(NSArray*)items atIndex:(NSUInteger)index; +- (void)replaceOriginItem:(MobilyDataItem*)originItem withItem:(MobilyDataItem*)item; +- (void)replaceOriginItems:(NSArray*)originItems withItems:(NSArray*)items; +- (void)deleteItem:(MobilyDataItem*)item; +- (void)deleteItems:(NSArray*)items; +- (void)deleteAllItems; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerItemsFlow : MobilyDataContainerItems + +@property(nonatomic, readwrite, assign) MobilyDataContainerOrientation orientation; +@property(nonatomic, readwrite, assign) UIEdgeInsets margin; +@property(nonatomic, readwrite, assign) UIOffset spacing; +@property(nonatomic, readwrite, assign) CGSize defaultSize; +@property(nonatomic, readwrite, strong) MobilyDataItem* header; +@property(nonatomic, readwrite, strong) MobilyDataItem* footer; +@property(nonatomic, readonly, strong) NSArray* items; + ++ (instancetype)containerWithOrientation:(MobilyDataContainerOrientation)orientation; + +- (instancetype)initWithOrientation:(MobilyDataContainerOrientation)orientation; + +- (void)prependIdentifier:(NSString*)identifier byData:(id)data; +- (void)prependItem:(MobilyDataItem*)item; +- (void)prependItems:(NSArray*)items; +- (void)appendIdentifier:(NSString*)identifier byData:(id)data; +- (void)appendItem:(MobilyDataItem*)item; +- (void)appendItems:(NSArray*)items; +- (void)insertIdentifier:(NSString*)identifier byData:(id)data atIndex:(NSUInteger)index; +- (void)insertItem:(MobilyDataItem*)item atIndex:(NSUInteger)index; +- (void)insertItems:(NSArray*)items atIndex:(NSUInteger)index; +- (void)replaceOriginItem:(MobilyDataItem*)originItem withItem:(MobilyDataItem*)item; +- (void)replaceOriginItems:(NSArray*)originItems withItems:(NSArray*)items; +- (void)deleteItem:(MobilyDataItem*)item; +- (void)deleteItems:(NSArray*)items; +- (void)deleteAllItems; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerItemsGrid : MobilyDataContainerItems + +@property(nonatomic, readwrite, assign) MobilyDataContainerOrientation orientation; +@property(nonatomic, readwrite, assign) UIEdgeInsets margin; +@property(nonatomic, readwrite, assign) UIOffset spacing; +@property(nonatomic, readwrite, assign) CGSize defaultColumnSize; +@property(nonatomic, readwrite, assign) CGSize defaultRowSize; +@property(nonatomic, readonly, assign) NSUInteger numberOfColumns; +@property(nonatomic, readonly, assign) NSUInteger numberOfRows; +@property(nonatomic, readonly, strong) NSArray* headerColumns; +@property(nonatomic, readonly, strong) NSArray* footerColumns; +@property(nonatomic, readonly, strong) NSArray* headerRows; +@property(nonatomic, readonly, strong) NSArray* footerRows; +@property(nonatomic, readonly, strong) MobilyGrid* content; + ++ (instancetype)containerWithOrientation:(MobilyDataContainerOrientation)orientation; + +- (instancetype)initWithOrientation:(MobilyDataContainerOrientation)orientation; + +- (void)prependColumnIdentifier:(NSString*)identifier byData:(id)data; +- (void)prependColumn:(MobilyDataItem*)column; +- (void)prependColumnIdentifier:(NSString*)identifier byHeaderData:(id)headerData byFooterData:(id)footerData; +- (void)prependColumnHeaderIdentifier:(NSString*)columnIdentifier byHeaderData:(id)headerData andFooterIdentifier:(NSString*)footerIdentifier byFooterData:(id)footerData; +- (void)prependColumnHeader:(MobilyDataItem*)header andColumnFooter:(MobilyDataItem*)columnFooter; +- (void)appendColumnIdentifier:(NSString*)identifier byData:(id)data; +- (void)appendColumn:(MobilyDataItem*)column; +- (void)appendColumnIdentifier:(NSString*)identifier byHeaderData:(id)headerData byFooterData:(id)footerData; +- (void)appendColumnHeaderIdentifier:(NSString*)columnIdentifier byHeaderData:(id)headerData andFooterIdentifier:(NSString*)footerIdentifier byFooterData:(id)footerData; +- (void)appendColumnHeader:(MobilyDataItem*)header andColumnFooter:(MobilyDataItem*)columnFooter; +- (void)insertColumnIdentifier:(NSString*)identifier byData:(id)data atIndex:(NSUInteger)index; +- (void)insertColumn:(MobilyDataItem*)column atIndex:(NSUInteger)index; +- (void)insertColumnIdentifier:(NSString*)identifier byHeaderData:(id)headerData byFooterData:(id)footerData atIndex:(NSUInteger)index; +- (void)insertColumnHeaderIdentifier:(NSString*)columnIdentifier byHeaderData:(id)headerData andFooterIdentifier:(NSString*)footerIdentifier byFooterData:(id)footerData atIndex:(NSUInteger)index; +- (void)insertColumnHeader:(MobilyDataItem*)header andColumnFooter:(MobilyDataItem*)columnFooter atIndex:(NSUInteger)index; +- (void)deleteColumn:(MobilyDataItem*)column; +- (void)deleteAllColumns; + +- (void)prependRowIdentifier:(NSString*)identifier byData:(id)data; +- (void)prependRow:(MobilyDataItem*)row; +- (void)prependRowIdentifier:(NSString*)identifier byHeaderData:(id)headerData byFooterData:(id)footerData; +- (void)prependRowHeaderIdentifier:(NSString*)rowIdentifier byHeaderData:(id)headerData andFooterIdentifier:(NSString*)footerIdentifier byFooterData:(id)footerData; +- (void)prependRowHeader:(MobilyDataItem*)rowHeader andRowFooter:(MobilyDataItem*)rowFooter; +- (void)appendRowIdentifier:(NSString*)identifier byData:(id)data; +- (void)appendRow:(MobilyDataItem*)row; +- (void)appendRowIdentifier:(NSString*)rowIdentifier byHeaderData:(id)headerData byFooterData:(id)footerData; +- (void)appendRowHeaderIdentifier:(NSString*)rowIdentifier byHeaderData:(id)headerData andFooterIdentifier:(NSString*)footerIdentifier byFooterData:(id)footerData; +- (void)appendRowHeader:(MobilyDataItem*)rowHeader andRowFooter:(MobilyDataItem*)rowFooter; +- (void)insertRowIdentifier:(NSString*)identifier byData:(id)data atIndex:(NSUInteger)index; +- (void)insertRow:(MobilyDataItem*)row atIndex:(NSUInteger)index; +- (void)insertRowIdentifier:(NSString*)rowIdentifier byHeaderData:(id)headerData byFooterData:(id)footerData atIndex:(NSUInteger)index; +- (void)insertRowHeaderIdentifier:(NSString*)rowIdentifier byHeaderData:(id)headerData andFooterIdentifier:(NSString*)footerIdentifier byFooterData:(id)footerData atIndex:(NSUInteger)index; +- (void)insertRowHeader:(MobilyDataItem*)rowHeader andRowFooter:(MobilyDataItem*)rowFooter atIndex:(NSUInteger)index; +- (void)deleteRow:(MobilyDataItem*)row; +- (void)deleteAllRows; + +- (void)insertContentIdentifier:(NSString*)identifier byData:(id)data atColumn:(NSUInteger)column atRow:(NSUInteger)row; +- (void)insertContent:(MobilyDataItem*)content atColumn:(NSUInteger)column atRow:(NSUInteger)row; +- (void)deleteContentAtColumn:(NSUInteger)column atRow:(NSUInteger)row; +- (void)deleteAllContent; + +@end + +/*--------------------------------------------------*/ + +@class MobilyDataItemCalendarMonth; +@class MobilyDataItemCalendarWeekday; +@class MobilyDataItemCalendarDay; + +/*--------------------------------------------------*/ + +typedef id (^MobilyDataContainerCalendarMonthCreateBlock)(NSDate* beginDate, NSDate* endDate); +typedef id (^MobilyDataContainerCalendarWeekdayCreateBlock)(NSDate* date, NSUInteger index); +typedef id (^MobilyDataContainerCalendarDayCreateBlock)(NSDate* date); + +typedef void (^MobilyDataContainerCalendarEachDayItemsBlock)(MobilyDataItemCalendarDay* dayItem); + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerCalendar : MobilyDataContainerItems + +@property(nonatomic, readonly, strong) NSCalendar* calendar; +@property(nonatomic, readonly, strong) NSDate* beginDate; +@property(nonatomic, readonly, strong) NSDate* endDate; +@property(nonatomic, readonly, strong) NSDate* displayBeginDate; +@property(nonatomic, readonly, strong) NSDate* displayEndDate; + +@property(nonatomic, readwrite, assign) BOOL canShowMonth; +@property(nonatomic, readwrite, assign) BOOL canSelectMonth; +@property(nonatomic, readwrite, assign) UIEdgeInsets monthMargin; +@property(nonatomic, readwrite, assign) CGFloat monthHeight; +@property(nonatomic, readwrite, assign) CGFloat monthSpacing; + +@property(nonatomic, readwrite, assign) BOOL canShowWeekdays; +@property(nonatomic, readwrite, assign) BOOL canSelectWeekdays; +@property(nonatomic, readwrite, assign) UIEdgeInsets weekdaysMargin; +@property(nonatomic, readwrite, assign) CGFloat weekdaysHeight; +@property(nonatomic, readwrite, assign) UIOffset weekdaysSpacing; + +@property(nonatomic, readwrite, assign) BOOL canShowDays; +@property(nonatomic, readwrite, assign) BOOL canSelectDays; +@property(nonatomic, readwrite, assign) BOOL canSelectPreviousDays; +@property(nonatomic, readwrite, assign) BOOL canSelectNextDays; +@property(nonatomic, readwrite, assign) BOOL canSelectEarlierDays; +@property(nonatomic, readwrite, assign) BOOL canSelectCurrentDay; +@property(nonatomic, readwrite, assign) BOOL canSelectAfterDays; +@property(nonatomic, readwrite, assign) UIEdgeInsets daysMargin; +@property(nonatomic, readwrite, assign) CGFloat daysHeight; +@property(nonatomic, readwrite, assign) UIOffset daysSpacing; + ++ (instancetype)containerWithCalendar:(NSCalendar*)calendar; + +- (instancetype)initWithCalendar:(NSCalendar*)calendar; + +- (MobilyDataItemCalendarWeekday*)weekdayItemForDate:(NSDate*)date; +- (MobilyDataItemCalendarDay*)dayItemForDate:(NSDate*)date; + +- (void)prepareBeginDate:(NSDate*)beginDate endDate:(NSDate*)endDate; +- (void)prepareBeginDate:(NSDate*)beginDate endDate:(NSDate*)endDate dayBlock:(MobilyDataContainerCalendarDayCreateBlock)dayBlock; +- (void)prepareBeginDate:(NSDate*)beginDate endDate:(NSDate*)endDate monthBlock:(MobilyDataContainerCalendarMonthCreateBlock)monthBlock weekdayBlock:(MobilyDataContainerCalendarWeekdayCreateBlock)weekdayBlock dayBlock:(MobilyDataContainerCalendarDayCreateBlock)dayBlock; +- (void)replaceDate:(NSDate*)date data:(id)data; +- (void)cleanup; + +- (void)eachDayItemsWithWeekdayItem:(MobilyDataItemCalendarWeekday*)weekdayItem block:(MobilyDataContainerCalendarEachDayItemsBlock)block; +- (void)eachWeekdayByDayItem:(MobilyDataItemCalendarDay*)dayItem block:(MobilyDataContainerCalendarEachDayItemsBlock)block; +- (void)eachWeekByDayItem:(MobilyDataItemCalendarDay*)dayItem block:(MobilyDataContainerCalendarEachDayItemsBlock)block; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataContainerCalendarDays : MobilyDataContainerItems + +@property(nonatomic, readonly, strong) NSCalendar* calendar; + +@property(nonatomic, readwrite, assign) MobilyDataContainerOrientation orientation; +@property(nonatomic, readwrite, assign) UIEdgeInsets margin; +@property(nonatomic, readwrite, assign) UIOffset spacing; +@property(nonatomic, readwrite, assign) CGSize defaultSize; +@property(nonatomic, readonly, strong) NSArray* days; + ++ (instancetype)containerWithCalendar:(NSCalendar*)calendar orientation:(MobilyDataContainerOrientation)orientation; + +- (instancetype)initWithCalendar:(NSCalendar*)calendar orientation:(MobilyDataContainerOrientation)orientation; + +- (MobilyDataItemCalendarDay*)dayItemForDate:(NSDate*)date; +- (MobilyDataItemCalendarDay*)nearestDayItemForDate:(NSDate*)date; + +- (void)prepareBeginDate:(NSDate*)beginDate endDate:(NSDate*)endDate interval:(NSTimeInterval)interval data:(id)data; +- (void)prependToDate:(NSDate*)date interval:(NSTimeInterval)interval data:(id)data; +- (void)prependDate:(NSDate*)date data:(id)data; +- (void)appendToDate:(NSDate*)date interval:(NSTimeInterval)interval data:(id)data; +- (void)appendDate:(NSDate*)date data:(id)data; +- (void)insertDate:(NSDate*)date data:(id)data atIndex:(NSUInteger)index; +- (void)replaceDate:(NSDate*)date data:(id)data; +- (void)deleteBeginDate:(NSDate*)beginDate endDate:(NSDate*)endDate; +- (void)deleteDate:(NSDate*)date; +- (void)deleteAllDates; + +- (void)scrollToDate:(NSDate*)date scrollPosition:(MobilyDataViewPosition)scrollPosition animated:(BOOL)animated; + +@end + +/*--------------------------------------------------*/ + +extern NSString* MobilyDataContainerCalendarMonthIdentifier; +extern NSString* MobilyDataContainerCalendarWeekdayIdentifier; +extern NSString* MobilyDataContainerCalendarDayIdentifier; + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataContainer.m b/Sources/MobilyCore/MobilyDataContainer.m new file mode 100644 index 0000000..dff8c68 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataContainer.m @@ -0,0 +1,298 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyDataContainer + +#pragma mark Synthesize + +@synthesize view = _view; +@synthesize parent = _parent; +@synthesize frame = _frame; +@synthesize hidden = _hidden; +@synthesize allowAutoAlign = _allowAutoAlign; +@synthesize alignInsets = _alignInsets; +@synthesize alignPosition = _alignPosition; +@synthesize alignThreshold = _alignThreshold; + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + _alignPosition = MobilyDataContainerAlignNone; + _alignThreshold = UIOffsetMake(20.0f, 20.0f); +} + +- (void)dealloc { +} + +#pragma mark Property + +- (void)setView:(MobilyDataView*)view { + if(_view != view) { + [self _willChangeView]; + _view = view; + [self _didChangeView]; + } +} + +- (void)setParent:(MobilyDataContainer*)parent { + if(_parent != parent) { + [self _willChangeParent]; + _parent = parent; + [self _didChangeParent]; + } +} + +- (CGRect)frame { + [_view validateLayoutIfNeed]; + return _frame; +} + +- (void)setHidden:(BOOL)hidden { + if(_hidden != hidden) { + _hidden = hidden; + [_view setNeedValidateLayout]; + } +} + +- (BOOL)isHiddenInHierarchy { + if(_hidden == YES) { + return YES; + } + return (_parent != nil) ? _parent.hiddenInHierarchy : NO; +} + +#pragma mark Property private + +- (void)_willChangeView { +} + +- (void)_didChangeView { +} + +- (void)_willChangeParent { +} + +- (void)_didChangeParent { + if(_parent != nil) { + self.view = _parent.view; + } +} + +- (void)_willBeginDragging { +} + +- (void)_didScrollDragging:(BOOL)dragging decelerating:(BOOL)decelerating { +} + +- (void)_willEndDraggingWithVelocity:(CGPoint)velocity contentOffset:(inout CGPoint*)contentOffset contentSize:(CGSize)contentSize visibleSize:(CGSize)visibleSize { + if(_allowAutoAlign == YES) { + *contentOffset = [self _alignWithVelocity:velocity contentOffset:*contentOffset contentSize:contentSize visibleSize:visibleSize]; + } +} + +- (void)_didEndDraggingWillDecelerate:(BOOL __unused)decelerate { +} + +- (void)_willBeginDecelerating { +} + +- (void)_didEndDecelerating { +} + +- (void)_didEndScrollingAnimation { +} + +- (void)_didBeginUpdateAnimated:(BOOL __unused)animated { +} + +- (void)_didEndUpdateAnimated:(BOOL __unused)animated { + if(_allowAutoAlign == YES) { + [self align]; + } +} + +- (CGPoint)_alignPointWithContentOffset:(CGPoint)contentOffset contentSize:(CGSize)contentSize visibleSize:(CGSize)visibleSize { + CGPoint alignPoint = CGPointZero; + CGRect visibleRect = CGRectMake(_alignInsets.left, _alignInsets.top, visibleSize.width - (_alignInsets.left + _alignInsets.right), visibleSize.height - (_alignInsets.top + _alignInsets.bottom)); + if((_alignPosition & MobilyDataContainerAlignLeft) != 0) { + alignPoint.x = contentOffset.x + visibleRect.origin.x; + } else if((_alignPosition & MobilyDataContainerAlignCenteredHorizontally) != 0) { + alignPoint.x = contentOffset.x + (visibleRect.origin.x + (visibleRect.size.width * 0.5f)); + } else if((_alignPosition & MobilyDataContainerAlignRight) != 0) { + alignPoint.x = contentOffset.x + (visibleRect.origin.x + visibleRect.size.width); + } else { + alignPoint.x = contentOffset.x; + } + if((_alignPosition & MobilyDataContainerAlignTop) != 0) { + alignPoint.y = contentOffset.y + visibleRect.origin.y; + } else if((_alignPosition & MobilyDataContainerAlignCenteredVertically) != 0) { + alignPoint.y = contentOffset.y + (visibleRect.origin.y + (visibleRect.size.height * 0.5f)); + } else if((_alignPosition & MobilyDataContainerAlignBottom) != 0) { + alignPoint.y = contentOffset.y + (visibleRect.origin.y + visibleRect.size.height); + } else { + alignPoint.y = contentOffset.y; + } + return alignPoint; +} + +- (CGPoint)_alignWithVelocity:(CGPoint __unused)velocity contentOffset:(CGPoint)contentOffset contentSize:(CGSize __unused)contentSize visibleSize:(CGSize __unused)visibleSize { + return contentOffset; +} + +- (CGRect)_validateLayoutForAvailableFrame:(CGRect __unused)frame { + return CGRectNull; +} + +- (void)_willLayoutForBounds:(CGRect __unused)bounds { +} + +- (void)_didLayoutForBounds:(CGRect __unused)bounds { +} + +#pragma mark Public + +- (NSArray*)allItems { + return @[]; +} + +- (MobilyDataItem*)itemForPoint:(CGPoint __unused)point { + return nil; +} + +- (MobilyDataItem*)itemForData:(id __unused)data { + return nil; +} + +- (MobilyDataCell*)cellForData:(id)data { + MobilyDataItem* item = [self itemForData:data]; + if(item != nil) { + return item.cell; + } + return nil; +} + +- (BOOL)containsEventForKey:(id)key { + return [_view containsEventForKey:key]; +} + +- (BOOL)containsEventForIdentifier:(NSString*)identifier forKey:(id)key { + return [_view containsEventForIdentifier:identifier forKey:key]; +} + +- (void)fireEventForKey:(id)key byObject:(id)object { + [_view fireEventForKey:key bySender:self byObject:object]; +} + +- (void)fireEventForIdentifier:(NSString*)identifier forKey:(id)key byObject:(id)object { + [_view fireEventForIdentifier:identifier forKey:key bySender:self byObject:object]; +} + +- (id)fireEventForKey:(id)key byObject:(id)object orDefault:(id)orDefault { + return [_view fireEventForKey:key bySender:self byObject:object orDefault:orDefault]; +} + +- (id)fireEventForIdentifier:(NSString*)identifier forKey:(id)key byObject:(id)object orDefault:(id)orDefault { + return [_view fireEventForIdentifier:identifier forKey:key bySender:self byObject:object orDefault:orDefault]; +} + +- (void)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object { + [_view fireEventForKey:key bySender:sender byObject:object]; +} + +- (void)fireEventForIdentifier:(NSString*)identifier forKey:(id)key bySender:(id)sender byObject:(id)object { + [_view fireEventForIdentifier:identifier forKey:key bySender:sender byObject:object]; +} + +- (id)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault { + return [_view fireEventForKey:key bySender:sender byObject:object orDefault:orDefault]; +} + +- (id)fireEventForIdentifier:(NSString*)identifier forKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault { + return [_view fireEventForIdentifier:identifier forKey:key bySender:sender byObject:object orDefault:orDefault]; +} + +- (CGPoint)alignPoint { + return [self _alignPointWithContentOffset:_view.contentOffset contentSize:_view.contentSize visibleSize:_view.moBoundsSize]; +} + +- (void)align { + if((_view.dragging == NO) && (_view.decelerating == NO)) { + [_view setContentOffset:[self _alignWithVelocity:CGPointZero contentOffset:_view.contentOffset contentSize:_view.contentSize visibleSize:_view.moBoundsSize] animated:YES]; + } +} + +#pragma mark MobilySearchBarDelegate + +- (void)searchBarBeginSearch:(MobilySearchBar*)searchBar { +} + +- (void)searchBarEndSearch:(MobilySearchBar*)searchBar { +} + +- (void)searchBarBeginEditing:(MobilySearchBar*)searchBar { +} + +- (void)searchBar:(MobilySearchBar*)searchBar textChanged:(NSString*)textChanged { +} + +- (void)searchBarEndEditing:(MobilySearchBar*)searchBar { +} + +- (void)searchBarPressedClear:(MobilySearchBar*)searchBar { +} + +- (void)searchBarPressedReturn:(MobilySearchBar*)searchBar { +} + +- (void)searchBarPressedCancel:(MobilySearchBar*)searchBar { +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataContainerCalendar.m b/Sources/MobilyCore/MobilyDataContainerCalendar.m new file mode 100644 index 0000000..ab89051 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataContainerCalendar.m @@ -0,0 +1,564 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyDataContainerCalendar + +#pragma mark Synthesize + +@synthesize calendar = _calendar; +@synthesize canShowMonth = _canShowMonth; +@synthesize canSelectMonth = _canSelectMonth; +@synthesize monthMargin = _monthMargin; +@synthesize monthHeight = _monthHeight; +@synthesize monthSpacing = _monthSpacing; +@synthesize canShowWeekdays = _canShowWeekdays; +@synthesize canSelectWeekdays = _canSelectWeekdays; +@synthesize weekdaysMargin = _weekdaysMargin; +@synthesize weekdaysHeight = _weekdaysHeight; +@synthesize weekdaysSpacing = _weekdaysSpacing; +@synthesize canShowDays = _canShowDays; +@synthesize canSelectDays = _canSelectDays; +@synthesize canSelectPreviousDays = _canSelectPreviousDays; +@synthesize canSelectNextDays = _canSelectNextDays; +@synthesize canSelectEarlierDays = _canSelectEarlierDays; +@synthesize canSelectCurrentDay = _canSelectCurrentDay; +@synthesize canSelectAfterDays = _canSelectAfterDays; +@synthesize daysMargin = _daysMargin; +@synthesize daysHeight = _daysHeight; +@synthesize daysSpacing = _daysSpacing; +@synthesize beginDate = _beginDate; +@synthesize endDate = _endDate; +@synthesize displayBeginDate = _displayBeginDate; +@synthesize displayEndDate = _displayEndDate; +@synthesize monthItem = _monthItem; +@synthesize weekdayItems = _weekdayItems; +@synthesize dayItems = _dayItems; + +#pragma mark Init / Free + ++ (instancetype)containerWithCalendar:(NSCalendar*)calendar { + return [[self alloc] initWithCalendar:calendar]; +} + +- (instancetype)initWithCalendar:(NSCalendar*)calendar { + self = [super init]; + if(self != nil) { + _calendar = calendar; + _canShowMonth = YES; + _canSelectMonth = NO; + _monthMargin = UIEdgeInsetsZero; + _monthHeight = 64.0f; + _monthSpacing = 0.0f; + _canShowWeekdays = YES; + _canSelectWeekdays = NO; + _weekdaysMargin = UIEdgeInsetsZero; + _weekdaysHeight = 21.0f; + _weekdaysSpacing = UIOffsetZero; + _canShowDays = YES; + _canSelectDays = YES; + _canSelectPreviousDays = NO; + _canSelectNextDays = NO; + _canSelectEarlierDays = YES; + _canSelectCurrentDay = YES; + _canSelectAfterDays = YES; + _daysMargin = UIEdgeInsetsZero; + _daysHeight = 44.0f; + _daysSpacing = UIOffsetZero; + _weekdayItems = NSMutableArray.array; + _dayItems = MobilyMutableGrid.grid; + } + return self; +} + +#pragma mark Property + +- (void)setCanShowMonth:(BOOL)canShowMonth { + if(_canShowMonth != canShowMonth) { + _canShowMonth = canShowMonth; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setCanSelectMonth:(BOOL)canSelectMonth { + if(_canSelectMonth != canSelectMonth) { + _canSelectMonth = canSelectMonth; + if(_monthItem != nil) { + _monthItem.allowsSelection = _canSelectMonth; + } + } +} + +- (void)setMonthMargin:(UIEdgeInsets)monthMargin { + if(UIEdgeInsetsEqualToEdgeInsets(_monthMargin, monthMargin) == NO) { + _monthMargin = monthMargin; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setMonthHeight:(CGFloat)monthHeight { + if(_monthHeight != monthHeight) { + _monthHeight = monthHeight; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setMonthSpacing:(CGFloat)monthSpacing { + if(_monthSpacing != monthSpacing) { + _monthSpacing = monthSpacing; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setCanShowWeekdays:(BOOL)canShowWeekdays { + if(_canShowWeekdays != canShowWeekdays) { + _canShowWeekdays = canShowWeekdays; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setCanSelectWeekdays:(BOOL)canSelectWeekdays { + if(_canSelectWeekdays != canSelectWeekdays) { + _canSelectWeekdays = canSelectWeekdays; + [_weekdayItems moEach:^(MobilyDataItemCalendarWeekday* weekdayItem) { + weekdayItem.allowsSelection = _canSelectWeekdays; + }]; + } +} + +- (void)setWeekdaysMargin:(UIEdgeInsets)weekdaysMargin { + if(UIEdgeInsetsEqualToEdgeInsets(_weekdaysMargin, weekdaysMargin) == NO) { + _weekdaysMargin = weekdaysMargin; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setWeekdaysHeight:(CGFloat)weekdaysHeight { + if(_weekdaysHeight != weekdaysHeight) { + _weekdaysHeight = weekdaysHeight; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setWeekdaysSpacing:(UIOffset)weekdaysSpacing { + if(UIOffsetEqualToOffset(_weekdaysSpacing, weekdaysSpacing) == NO) { + _weekdaysSpacing = weekdaysSpacing; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setCanShowDays:(BOOL)canShowDays { + if(_canShowDays != canShowDays) { + _canShowDays = canShowDays; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setCanSelectDays:(BOOL)canSelectDays { + if(_canSelectDays != canSelectDays) { + _canSelectDays = canSelectDays; + [_weekdayItems moEach:^(MobilyDataItemCalendarDay* dayItem) { + if(([dayItem.date moIsAfterOrSame:_beginDate] == YES) && ([dayItem.date moIsEarlierOrSame:_endDate] == YES)) { + dayItem.allowsSelection = _canSelectDays; + } + }]; + } +} + +- (void)setCanSelectPreviousDays:(BOOL)canSelectPreviousDays { + if(_canSelectPreviousDays != canSelectPreviousDays) { + _canSelectPreviousDays = canSelectPreviousDays; + [_weekdayItems moEach:^(MobilyDataItemCalendarDay* dayItem) { + if([dayItem.date moIsAfter:_endDate] == YES) { + dayItem.allowsSelection = _canSelectNextDays; + } + }]; + } +} + +- (void)setCanSelectNextDays:(BOOL)canSelectNextDays { + if(_canSelectNextDays != canSelectNextDays) { + _canSelectNextDays = canSelectNextDays; + [_weekdayItems moEach:^(MobilyDataItemCalendarDay* dayItem) { + if([dayItem.date moIsEarlier:_beginDate] == YES) { + dayItem.allowsSelection = _canSelectPreviousDays; + } + }]; + } +} + +- (void)setCanSelectEarlierDays:(BOOL)canSelectEarlierDays { + if(_canSelectEarlierDays != canSelectEarlierDays) { + _canSelectEarlierDays = canSelectEarlierDays; + + NSDate* now = NSDate.date.moWithoutTime; + [_weekdayItems moEach:^(MobilyDataItemCalendarDay* dayItem) { + if([dayItem.date moIsEarlier:now] == YES) { + dayItem.allowsSelection = _canSelectEarlierDays; + } + }]; + } +} + +- (void)setCanSelectAfterDays:(BOOL)canSelectAfterDays { + if(_canSelectAfterDays != canSelectAfterDays) { + _canSelectAfterDays = canSelectAfterDays; + + NSDate* now = NSDate.date.moWithoutTime; + [_weekdayItems moEach:^(MobilyDataItemCalendarDay* dayItem) { + if([dayItem.date moIsAfter:now] == YES) { + dayItem.allowsSelection = _canSelectAfterDays; + } + }]; + } +} + +- (void)setDaysMargin:(UIEdgeInsets)daysMargin { + if(UIEdgeInsetsEqualToEdgeInsets(_daysMargin, daysMargin) == NO) { + _daysMargin = daysMargin; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setDaysHeight:(CGFloat)daysHeight { + if(_daysHeight != daysHeight) { + _daysHeight = daysHeight; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setDaysSpacing:(UIOffset)daysSpacing { + if(UIOffsetEqualToOffset(_daysSpacing, daysSpacing) == NO) { + _daysSpacing = daysSpacing; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +#pragma mark Public + +- (MobilyDataItemCalendarWeekday*)weekdayItemForDate:(NSDate*)date { + NSDateComponents* dateComponents = [_calendar components:NSCalendarUnitWeekday fromDate:date]; + for(MobilyDataItemCalendarWeekday* weekdayItem in _weekdayItems) { + NSDateComponents* weekdayComponents = [_calendar components:NSCalendarUnitWeekday fromDate:weekdayItem.date]; + if(weekdayComponents.weekday == dateComponents.weekday) { + return weekdayItem; + } + } + return nil; +} + +- (MobilyDataItemCalendarDay*)dayItemForDate:(NSDate*)date { + NSDate* beginDate = date.moBeginningOfDay; + __block MobilyDataItemCalendarDay* result = nil; + [_dayItems enumerateColumnsRowsUsingBlock:^(MobilyDataItemCalendarDay* dayItem, NSUInteger column __unused, NSUInteger row __unused, BOOL* stopColumn, BOOL* stopRow) { + if([dayItem.date isEqualToDate:beginDate] == YES) { + result = dayItem; + *stopColumn = YES; + *stopRow = YES; + } + }]; + return result; +} + +- (void)prepareBeginDate:(NSDate*)beginDate endDate:(NSDate*)endDate { + [self prepareBeginDate:beginDate endDate:endDate monthBlock:^id(NSDate* beginDate, NSDate* endDate) { + return [NSNull null]; + } weekdayBlock:^id(NSDate* date, NSUInteger index) { + return [NSNull null]; + } dayBlock:^id(NSDate* date) { + return [NSNull null]; + }]; +} + +- (void)prepareBeginDate:(NSDate*)beginDate endDate:(NSDate*)endDate dayBlock:(MobilyDataContainerCalendarDayCreateBlock)dayBlock { + [self prepareBeginDate:beginDate endDate:endDate monthBlock:^id(NSDate* beginDate, NSDate* endDate) { + return [NSNull null]; + } weekdayBlock:^id(NSDate* date, NSUInteger index) { + return [NSNull null]; + } dayBlock:dayBlock]; +} + +- (void)prepareBeginDate:(NSDate*)beginDate endDate:(NSDate*)endDate monthBlock:(MobilyDataContainerCalendarMonthCreateBlock)monthBlock weekdayBlock:(MobilyDataContainerCalendarWeekdayCreateBlock)weekdayBlock dayBlock:(MobilyDataContainerCalendarDayCreateBlock)dayBlock { + if(([_beginDate isEqualToDate:beginDate] == NO) || ([_endDate isEqualToDate:endDate] == NO)) { + [self cleanup]; + _beginDate = beginDate; + _displayBeginDate = _beginDate.moBeginningOfWeek; + _endDate = endDate; + _displayEndDate = endDate.moEndOfWeek; + if(_canShowMonth == YES) { + _monthItem = [MobilyDataItemCalendarMonth itemWithCalendar:_calendar beginDate:_beginDate endDate:_endDate displayBeginDate:_displayBeginDate displayEndDate:_displayEndDate data:monthBlock(_beginDate, _endDate)]; + _monthItem.allowsSelection = _canSelectMonth; + [self _appendEntry:_monthItem]; + } + if(_canShowWeekdays == YES) { + NSDate* weekdayDate = _beginDate.moBeginningOfWeek; + for(NSUInteger weekdayIndex = 0; weekdayIndex < 7; weekdayIndex++) { + MobilyDataItemCalendarWeekday* weekdayItem; + if(_canShowMonth == YES) { + weekdayItem = [MobilyDataItemCalendarWeekday itemWithMonthItem:_monthItem date:weekdayDate data:weekdayBlock(weekdayDate, weekdayIndex)]; + } else { + weekdayItem = [MobilyDataItemCalendarWeekday itemWithCalendar:_calendar date:weekdayDate data:weekdayBlock(weekdayDate, weekdayIndex)]; + } + weekdayItem.allowsSelection = _canSelectWeekdays; + [_weekdayItems addObject:weekdayItem]; + [self _appendEntry:weekdayItem]; + weekdayDate = weekdayDate.moNextDay; + } + } + if(_canShowDays == YES) { + NSDate* now = NSDate.date.moWithoutTime; + NSDate* beginDayDate = [_displayBeginDate copy]; + NSDate* endDayDate = [_displayEndDate copy]; + NSInteger weekOfMonth = [beginDayDate moWeeksToDate:endDayDate.moNextSecond]; + if(weekOfMonth > 0) { + [_dayItems setNumberOfColumns:7 numberOfRows:weekOfMonth]; + for(NSUInteger weekIndex = 0; weekIndex < weekOfMonth; weekIndex++) { + for(NSUInteger weekdayIndex = 0; weekdayIndex < 7; weekdayIndex++) { + MobilyDataItemCalendarDay* dayItem; + if(_canShowWeekdays == YES) { + dayItem = [MobilyDataItemCalendarDay itemWithWeekdayItem:_weekdayItems[weekdayIndex] date:beginDayDate data:dayBlock(beginDayDate)]; + } else { + dayItem = [MobilyDataItemCalendarDay itemWithCalendar:_calendar date:beginDayDate data:dayBlock(beginDayDate)]; + } + if([dayItem.date moIsEarlier:_beginDate] == YES) { + dayItem.allowsSelection = (_canSelectDays == YES) ? _canSelectPreviousDays : _canSelectDays; + } else if([dayItem.date moIsAfter:_endDate] == YES) { + dayItem.allowsSelection = (_canSelectDays == YES) ? _canSelectNextDays : _canSelectDays; + } else { + if([dayItem.date moIsEarlier:now] == YES) { + dayItem.allowsSelection = (_canSelectDays == YES) ? _canSelectEarlierDays : _canSelectDays; + } else if([dayItem.date moIsAfter:now] == YES) { + dayItem.allowsSelection = (_canSelectDays == YES) ? _canSelectAfterDays : _canSelectDays; + } else { + dayItem.allowsSelection = (_canSelectDays == YES) ? _canSelectCurrentDay : _canSelectDays; + } + } + [_dayItems setObject:dayItem atColumn:weekdayIndex atRow:weekIndex]; + [self _appendEntry:dayItem]; + beginDayDate = beginDayDate.moNextDay; + } + } + } + } + } +} + +- (void)replaceDate:(NSDate*)date data:(id)data { + __block NSUInteger foundColumn = NSNotFound, foundRow = NSNotFound; + [_dayItems enumerateColumnsRowsUsingBlock:^(MobilyDataItemCalendarDay* day, NSUInteger column, NSUInteger row, BOOL* stopColumn, BOOL* stopRow) { + if([day.date isEqualToDate:date] == YES) { + foundColumn = column; + foundRow = row; + *stopColumn = YES; + *stopRow = YES; + } + }]; + if((foundColumn != NSNotFound) && (foundRow != NSNotFound)) { + MobilyDataItemCalendarDay* oldDayItem = [_dayItems objectAtColumn:foundColumn atRow:foundRow]; + MobilyDataItemCalendarDay* newDayItem; + if(oldDayItem.weekdayItem != nil) { + newDayItem = [MobilyDataItemCalendarDay itemWithWeekdayItem:oldDayItem.weekdayItem date:date data:data]; + } else { + newDayItem = [MobilyDataItemCalendarDay itemWithCalendar:oldDayItem.calendar date:date data:data]; + } + newDayItem.allowsSelection = oldDayItem.allowsSelection; + [_dayItems setObject:newDayItem atColumn:foundColumn atRow:foundRow]; + [self _replaceOriginEntry:oldDayItem withEntry:newDayItem]; + } +} + +- (void)cleanup { + if(_monthItem != nil) { + [self _deleteEntry:_monthItem]; + _monthItem = nil; + } + if(_weekdayItems.count > 0) { + [self _deleteEntries:_weekdayItems]; + [_weekdayItems removeAllObjects]; + } + if(_dayItems.count > 0) { + [self _deleteEntries:_dayItems.objects]; + [_dayItems removeAllObjects]; + } + _beginDate = nil; + _endDate = nil; +} + +- (void)eachDayItemsWithWeekdayItem:(MobilyDataItemCalendarWeekday*)weekdayItem block:(MobilyDataContainerCalendarEachDayItemsBlock)block { + NSUInteger weekdayIndex = [_weekdayItems indexOfObject:weekdayItem]; + if(weekdayIndex != NSNotFound) { + [_dayItems moEach:^(MobilyDataItemCalendarDay* dayItem, NSUInteger column __unused, NSUInteger row __unused) { + block(dayItem); + } byColumn:weekdayIndex]; + } +} + +- (void)eachWeekdayByDayItem:(MobilyDataItemCalendarDay*)dayItem block:(MobilyDataContainerCalendarEachDayItemsBlock)block { + NSUInteger dayIndex = NSNotFound; + [_dayItems findObjectUsingBlock:^BOOL(MobilyDataItemCalendarDay* item) { + return dayItem == item; + } inColumn:&dayIndex inRow:NULL]; + if(dayIndex != NSNotFound) { + [_dayItems moEach:^(MobilyDataItemCalendarDay* item, NSUInteger column, NSUInteger row) { + block(item); + } byColumn:dayIndex]; + } +} + +- (void)eachWeekByDayItem:(MobilyDataItemCalendarDay*)dayItem block:(MobilyDataContainerCalendarEachDayItemsBlock)block { + NSUInteger weekIndex = NSNotFound; + [_dayItems findObjectUsingBlock:^BOOL(MobilyDataItemCalendarDay* item) { + return dayItem == item; + } inColumn:NULL inRow:&weekIndex]; + if(weekIndex != NSNotFound) { + [_dayItems moEach:^(MobilyDataItemCalendarDay* item, NSUInteger column, NSUInteger row) { + block(item); + } byRow:weekIndex]; + } +} + +#pragma mark Private override + +- (CGRect)_validateEntriesForAvailableFrame:(CGRect)frame { + BOOL canShowMonth = _canShowMonth; + UIEdgeInsets monthMargin = (canShowMonth == YES) ? _monthMargin : UIEdgeInsetsZero; + CGFloat monthHeight = (canShowMonth == YES) ? _monthHeight - (monthMargin.top + monthMargin.bottom) : 0.0f; + CGFloat monthSpacing = (canShowMonth == YES) ? _monthSpacing : 0.0f; + BOOL canShowWeekdays = _canShowWeekdays; + UIEdgeInsets weekdaysMargin = (canShowWeekdays == YES) ? _weekdaysMargin : UIEdgeInsetsZero; + CGFloat weekdaysHeight = (canShowWeekdays == YES) ? _weekdaysHeight - (weekdaysMargin.top + weekdaysMargin.bottom) : 0.0f; + UIOffset weekdaysSpacing = (canShowWeekdays == YES) ? _weekdaysSpacing : UIOffsetZero; + BOOL canShowDays = _canShowDays; + UIEdgeInsets daysMargin = (canShowDays == YES) ? _daysMargin : UIEdgeInsetsZero; + CGFloat daysHeight = (canShowDays == YES) ? _daysHeight - (daysMargin.top + daysMargin.bottom) : 0.0f; + UIOffset daysSpacing = (canShowDays == YES) ? _daysSpacing : UIOffsetZero; + CGFloat monthWidth = frame.size.width - (monthMargin.left + monthMargin.right); + CGFloat availableWeekdaysWidth = monthWidth - (weekdaysMargin.left + weekdaysMargin.right) - (weekdaysSpacing.horizontal * 6); + CGFloat defaultWeekdaysWidth = MOBILY_FLOOR(availableWeekdaysWidth / 7); + CGFloat lastWeekdaysWidth = availableWeekdaysWidth - (defaultWeekdaysWidth * 6); + CGFloat availableDaysWidth = monthWidth - (daysMargin.left + daysMargin.right) - (daysSpacing.horizontal * 6); + CGFloat defaultDaysWidth = MOBILY_FLOOR(availableDaysWidth / 7); + CGFloat lastDaysWidth = availableDaysWidth - (defaultDaysWidth * 6); + __block CGPoint offset = CGPointMake(frame.origin.x + monthMargin.left, frame.origin.y + monthMargin.top); + __block CGSize cumulative = CGSizeMake(monthWidth, 0.0f); + if(canShowMonth == YES) { + _monthItem.updateFrame = CGRectMake(offset.x, offset.y, monthWidth, monthHeight); + cumulative.height += monthHeight; + offset.y += monthHeight; + } + if(canShowWeekdays == YES) { + NSUInteger lastIndex = _weekdayItems.count - 1; + __block CGFloat weekdayOffset = offset.x + weekdaysMargin.left; + cumulative.height += weekdaysMargin.top; + offset.y += weekdaysMargin.top; + [_weekdayItems moEachWithIndex:^(MobilyDataItemCalendarWeekday* weekdayItem, NSUInteger index) { + if(index != lastIndex) { + weekdayItem.updateFrame = CGRectMake(weekdayOffset, offset.y, defaultWeekdaysWidth, weekdaysHeight); + weekdayOffset += defaultWeekdaysWidth + weekdaysSpacing.horizontal; + } else { + weekdayItem.updateFrame = CGRectMake(weekdayOffset, offset.y, lastWeekdaysWidth, weekdaysHeight); + cumulative.height += weekdaysHeight + weekdaysSpacing.vertical; + offset.y += weekdaysHeight + weekdaysSpacing.vertical; + } + }]; + cumulative.height += weekdaysMargin.bottom - weekdaysSpacing.vertical; + offset.y += weekdaysMargin.bottom - weekdaysSpacing.vertical; + } + if(canShowDays == YES) { + NSUInteger lastColumn = _dayItems.numberOfColumns - 1; + __block CGFloat dayOffset = offset.x + daysMargin.left; + cumulative.height += daysMargin.top; + offset.y += daysMargin.top; + [_dayItems eachRowsColumns:^(MobilyDataItemCalendarDay* dayItem, NSUInteger column, NSUInteger row __unused) { + if(column != lastColumn) { + dayItem.updateFrame = CGRectMake(dayOffset, offset.y, defaultDaysWidth, daysHeight); + dayOffset += defaultDaysWidth + daysSpacing.horizontal; + } else { + dayItem.updateFrame = CGRectMake(dayOffset, offset.y, lastDaysWidth, daysHeight); + cumulative.height += daysHeight + daysSpacing.vertical; + offset.y += daysHeight + daysSpacing.vertical; + dayOffset = offset.x + daysMargin.left; + } + }]; + cumulative.height += daysMargin.bottom - daysSpacing.vertical; + offset.y += daysMargin.bottom - daysSpacing.vertical; + } + if(canShowMonth == YES) { + cumulative.height += monthSpacing - monthSpacing; + } + return CGRectMake(frame.origin.x, frame.origin.y, monthMargin.left + cumulative.width + monthMargin.right, monthMargin.top + cumulative.height + monthMargin.bottom); +} + +- (void)_willEntriesLayoutForBounds:(CGRect __unused)bounds { +} + +@end + +/*--------------------------------------------------*/ + +NSString* MobilyDataContainerCalendarMonthIdentifier = @"MobilyDataContainerCalendarMonthIdentifier"; +NSString* MobilyDataContainerCalendarWeekdayIdentifier = @"MobilyDataContainerCalendarWeekdayIdentifier"; +NSString* MobilyDataContainerCalendarDayIdentifier = @"MobilyDataContainerCalendarDayIdentifier"; + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataContainerCalendarDays.m b/Sources/MobilyCore/MobilyDataContainerCalendarDays.m new file mode 100644 index 0000000..2fb4424 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataContainerCalendarDays.m @@ -0,0 +1,252 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyDataContainerCalendarDays + +#pragma mark Synthesize + +@synthesize calendar = _calendar; +@synthesize orientation = _orientation; +@synthesize margin = _margin; +@synthesize spacing = _spacing; +@synthesize defaultSize = _defaultSize; + +#pragma mark Init / Free + ++ (instancetype)containerWithCalendar:(NSCalendar*)calendar orientation:(MobilyDataContainerOrientation)orientation { + return [[self alloc] initWithCalendar:calendar orientation:orientation]; +} + +- (instancetype)initWithCalendar:(NSCalendar*)calendar orientation:(MobilyDataContainerOrientation)orientation { + self = [super init]; + if(self != nil) { + if(calendar != nil) { + _calendar = calendar; + } + _orientation = orientation; + } + return self; +} + +- (void)setup { + [super setup]; + + _calendar = NSCalendar.currentCalendar; + _orientation = MobilyDataContainerOrientationVertical; + _margin = UIEdgeInsetsZero; + _spacing = UIOffsetZero; + _defaultSize = CGSizeMake(44.0f, 44.0f); +} + +#pragma mark Property + +- (void)setOrientation:(MobilyDataContainerOrientation)orientation { + if(_orientation != orientation) { + _orientation = orientation; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setMargin:(UIEdgeInsets)margin { + if(UIEdgeInsetsEqualToEdgeInsets(_margin, margin) == NO) { + _margin = margin; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setSpacing:(UIOffset)spacing { + if(UIOffsetEqualToOffset(_spacing, spacing) == NO) { + _spacing = spacing; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (NSArray*)days { + return _entries; +} + +#pragma mark Public + +- (MobilyDataItemCalendarDay*)dayItemForDate:(NSDate*)date { + for(MobilyDataItemCalendarDay* calendarDay in _entries) { + if([date isEqualToDate:calendarDay.date] == YES) { + return calendarDay; + } + } + return nil; +} + +- (MobilyDataItemCalendarDay*)nearestDayItemForDate:(NSDate*)date { + MobilyDataItemCalendarDay* prevCalendarDay = nil; + for(MobilyDataItemCalendarDay* calendarDay in _entries) { + switch([date compare:calendarDay.date]) { + case NSOrderedDescending: prevCalendarDay = calendarDay; break; + case NSOrderedSame: return calendarDay; + case NSOrderedAscending: if(prevCalendarDay != nil) { return prevCalendarDay; } break; + } + } + return nil; +} + +- (void)prepareBeginDate:(NSDate*)beginDate endDate:(NSDate*)endDate interval:(NSTimeInterval)interval data:(id)data { + NSTimeInterval timeInterval = beginDate.timeIntervalSince1970; + NSTimeInterval endTimeInterval = endDate.timeIntervalSince1970; + while(endTimeInterval - timeInterval > 0.0f) { + NSDate* date = [NSDate dateWithTimeIntervalSince1970:timeInterval]; + MobilyDataItemCalendarDay* calendarDay = [self dayItemForDate:date]; + if(calendarDay == nil) { + [self appendDate:date data:data]; + } + timeInterval += interval; + } + [_entries sortUsingComparator:^NSComparisonResult(MobilyDataItemCalendarDay* calendarDay1, MobilyDataItemCalendarDay* calendarDay2) { + return [calendarDay1.date compare:calendarDay2.date]; + }]; +} + +- (void)prependToDate:(NSDate*)date interval:(NSTimeInterval)interval data:(id)data { + [self prepareBeginDate:date endDate:(_entries.count > 0) ? [_entries.firstObject date] : [NSDate date] interval:interval data:data]; +} + +- (void)prependDate:(NSDate*)date data:(id)data { + [self _prependEntry:[MobilyDataItemCalendarDay itemWithCalendar:_calendar date:date data:data]]; +} + +- (void)appendToDate:(NSDate*)date interval:(NSTimeInterval)interval data:(id)data { + [self prepareBeginDate:(_entries.count > 0) ? [_entries.lastObject date] : [NSDate date] endDate:date interval:interval data:data]; +} + +- (void)appendDate:(NSDate*)date data:(id)data { + [self _appendEntry:[MobilyDataItemCalendarDay itemWithCalendar:_calendar date:date data:data]]; +} + +- (void)insertDate:(NSDate*)date data:(id)data atIndex:(NSUInteger)index { + [self _insertEntry:[MobilyDataItemCalendarDay itemWithCalendar:_calendar date:date data:data] atIndex:index]; +} + +- (void)replaceDate:(NSDate*)date data:(id)data { + NSUInteger index = [_entries indexOfObjectPassingTest:^BOOL(MobilyDataItemCalendarDay* calendarDay, NSUInteger index __unused, BOOL* stop __unused) { + return [calendarDay.date isEqualToDate:date]; + }]; + if(index != NSNotFound) { + [self _replaceOriginEntry:_entries[index] withEntry:[MobilyDataItemCalendarDay itemWithCalendar:_calendar date:date data:data]]; + } +} + +- (void)deleteBeginDate:(NSDate*)beginDate endDate:(NSDate*)endDate { + NSTimeInterval beginTimeInterval = beginDate.timeIntervalSince1970; + NSTimeInterval endTimeInterval = endDate.timeIntervalSince1970; + NSIndexSet* indexSet = [_entries indexesOfObjectsPassingTest:^BOOL(MobilyDataItemCalendarDay* calendarDay, NSUInteger index __unused, BOOL* stop __unused) { + NSComparisonResult timeInterval = calendarDay.date.timeIntervalSince1970; + if((timeInterval >= beginTimeInterval) || (timeInterval <= endTimeInterval)) { + return YES; + } + return NO; + }]; + if(indexSet.count > 0) { + [self _deleteEntries:[_entries objectsAtIndexes:indexSet]]; + } +} + +- (void)deleteDate:(NSDate*)date { + NSUInteger index = [_entries indexOfObjectPassingTest:^BOOL(MobilyDataItemCalendarDay* calendarDay, NSUInteger index __unused, BOOL* stop __unused) { + return [calendarDay.date isEqualToDate:date]; + }]; + if(index != NSNotFound) { + [self _deleteEntry:_entries[index]]; + } +} + +- (void)deleteAllDates { + [self _deleteAllEntries]; +} + +- (void)scrollToDate:(NSDate*)date scrollPosition:(MobilyDataViewPosition)scrollPosition animated:(BOOL)animated { + MobilyDataItem* calendarDay = [self nearestDayItemForDate:date]; + if(calendarDay != nil) { + [_view scrollToItem:calendarDay scrollPosition:scrollPosition animated:animated]; + } +} + +#pragma mark Private override + +- (CGRect)_validateEntriesForAvailableFrame:(CGRect)frame { + CGPoint offset = CGPointMake(frame.origin.x + _margin.left, frame.origin.y + _margin.top); + CGSize restriction = CGSizeMake(frame.size.width - (_margin.left + _margin.right), frame.size.height - (_margin.top + _margin.bottom)); + CGSize cumulative = CGSizeZero; + switch(_orientation) { + case MobilyDataContainerOrientationVertical: { + cumulative.width = restriction.width; + for(MobilyDataItemCalendarDay* calendarDay in _entries) { + CGSize entrySize = [calendarDay sizeForAvailableSize:CGSizeMake(restriction.width, (_defaultSize.height > 0) ? _defaultSize.height : FLT_MAX)]; + if((entrySize.width >= 0.0f) && (entrySize.height >= 0.0f)) { + calendarDay.updateFrame = CGRectMake(offset.x, offset.y + cumulative.height, restriction.width, entrySize.height); + cumulative.height += entrySize.height + _spacing.vertical; + } + } + cumulative.height -= _spacing.vertical; + break; + } + case MobilyDataContainerOrientationHorizontal: { + cumulative.height = restriction.height; + for(MobilyDataItemCalendarDay* calendarDay in _entries) { + CGSize entrySize = [calendarDay sizeForAvailableSize:CGSizeMake((_defaultSize.width > 0) ? _defaultSize.width : FLT_MAX, restriction.height)]; + if((entrySize.width >= 0.0f) && (entrySize.height >= 0.0f)) { + calendarDay.updateFrame = CGRectMake(offset.x + cumulative.width, offset.y, entrySize.width, restriction.height); + cumulative.width += entrySize.width + _spacing.horizontal; + } + } + cumulative.width -= _spacing.horizontal; + break; + } + } + return CGRectMake(frame.origin.x, frame.origin.y, _margin.left + cumulative.width + _margin.right, _margin.top + cumulative.height + _margin.bottom); +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataContainerItems.m b/Sources/MobilyCore/MobilyDataContainerItems.m new file mode 100644 index 0000000..20b80d1 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataContainerItems.m @@ -0,0 +1,336 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyDataContainerItems + +#pragma mark Synthesize + +@synthesize entries = _entries; +@synthesize reverse = _reverse; + +#pragma mark Init / Free + +- (void)setup { + [super setup]; + + _entries = NSMutableArray.array; +} + +#pragma mark Private property private + +- (void)_willChangeView { +} + +- (void)_didChangeView { + for(MobilyDataItem* entry in _entries) { + entry.view = _view; + } +} + +#pragma mark Property + +- (void)setReverse:(BOOL)reverse { + if(_reverse != reverse) { + _reverse = reverse; + [_view setNeedValidateLayout]; + } +} + +#pragma mark Private override + +- (void)_didBeginUpdateAnimated:(BOOL)animated { + [super _didBeginUpdateAnimated:animated]; + for(MobilyDataItem* entry in _entries) { + [entry didBeginUpdateAnimated:animated]; + } +} + +- (void)_didEndUpdateAnimated:(BOOL)animated { + for(MobilyDataItem* entry in _entries) { + [entry didEndUpdateAnimated:animated]; + } + [super _didEndUpdateAnimated:animated]; +} + +- (CGRect)_validateLayoutForAvailableFrame:(CGRect)frame { + _frame = [self _validateEntriesForAvailableFrame:frame]; + return _frame; +} + +- (void)_willLayoutForBounds:(CGRect)bounds { + [self _willEntriesLayoutForBounds:CGRectIntersection(bounds, _frame)]; +} + +- (void)_didLayoutForBounds:(CGRect)bounds { + [self _didEntriesLayoutForBounds:CGRectIntersection(bounds, _frame)]; +} + +#pragma mark Public override + +- (NSArray*)allItems { + return [_entries copy]; +} + +- (MobilyDataItem*)itemForPoint:(CGPoint)point { + for(MobilyDataItem* entry in _entries) { + if(CGRectContainsPoint(entry.frame, point) == YES) { + return entry; + } + } + return nil; +} + +- (MobilyDataItem*)itemForData:(id)data { + for(MobilyDataItem* entry in _entries) { + id entryData = entry.data; + if([entryData isEqual:data] == YES) { + return entry; + } + } + return nil; +} + +#pragma mark Private + +- (void)_prependEntry:(MobilyDataItem*)entry { + [_entries insertObject:entry atIndex:0]; + entry.parent = self; + if(_view != nil) { + [_view _didInsertItems:@[ entry ]]; + } +} + +- (void)_prependEntries:(NSArray*)entries { + [_entries insertObjects:entries atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, entries.count)]]; + for(MobilyDataItem* entry in entries) { + entry.parent = self; + } + if(_view != nil) { + [_view _didInsertItems:entries]; + } +} + +- (void)_appendEntry:(MobilyDataItem*)entry { + [_entries addObject:entry]; + entry.parent = self; + if(_view != nil) { + [_view _didInsertItems:@[ entry ]]; + } +} + +- (void)_appendEntries:(NSArray*)entries { + [_entries addObjectsFromArray:entries]; + for(MobilyDataItem* entry in entries) { + entry.parent = self; + } + if(_view != nil) { + [_view _didInsertItems:entries]; + } +} + +- (void)_insertEntry:(MobilyDataItem*)entry atIndex:(NSUInteger)index { + [_entries insertObject:entry atIndex:index]; + entry.parent = self; + if(_view != nil) { + [_view _didInsertItems:@[ entry ]]; + } +} + +- (void)_insertEntries:(NSArray*)entries atIndex:(NSUInteger)index { + [_entries insertObjects:entries atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, entries.count)]]; + for(MobilyDataItem* entry in entries) { + entry.parent = self; + } + if(_view != nil) { + [_view _didInsertItems:entries]; + } +} + +- (void)_replaceOriginEntry:(MobilyDataItem*)originEntry withEntry:(MobilyDataItem*)entry { + NSUInteger index = [_entries indexOfObject:originEntry]; + entry.parent = self; + _entries[index] = entry; + if(_view != nil) { + [_view _didReplaceOriginItems:@[ originEntry ] withItems:@[ entry ]]; + } +} + +- (void)_replaceOriginEntries:(NSArray*)originEntries withEntries:(NSArray*)entries { + NSIndexSet* indexSet = [_entries indexesOfObjectsPassingTest:^BOOL(MobilyDataItem* originEntry, NSUInteger index __unused, BOOL* stop __unused) { + return [originEntries containsObject:originEntry]; + }]; + for(MobilyDataItem* entry in entries) { + entry.parent = self; + } + [_entries replaceObjectsAtIndexes:indexSet withObjects:entries]; + if(_view != nil) { + [_view _didReplaceOriginItems:originEntries withItems:entries]; + } +} + +- (void)_deleteEntry:(MobilyDataItem*)entry { + [_entries removeObject:entry]; + if(_view != nil) { + [_view _didDeleteItems:@[ entry ]]; + } +} + +- (void)_deleteEntries:(NSArray*)entries { + [_entries removeObjectsInArray:entries]; + if(_view != nil) { + [_view _didDeleteItems:entries]; + } +} + +- (void)_deleteAllEntries { + [self _deleteEntries:[_entries copy]]; +} + +- (CGPoint)_alignWithVelocity:(CGPoint __unused)velocity contentOffset:(CGPoint)contentOffset contentSize:(CGSize)contentSize visibleSize:(CGSize)visibleSize { + if((_allowAutoAlign == YES) && (_hidden == NO)) { + CGPoint alingPoint = [self _alignPointWithContentOffset:contentOffset contentSize:contentSize visibleSize:visibleSize]; + if(CGRectContainsPoint(_frame, alingPoint) == YES) { + for(MobilyDataItem* item in _entries) { + if(item.allowsAlign == YES) { + CGPoint alingItemCorner = CGPointZero; + if((_alignPosition & MobilyDataContainerAlignLeft) != 0) { + alingItemCorner.x = CGRectGetMinX(item.updateFrame); + } else if((_alignPosition & MobilyDataContainerAlignCenteredHorizontally) != 0) { + alingItemCorner.x = CGRectGetMidX(item.updateFrame); + } else if((_alignPosition & MobilyDataContainerAlignRight) != 0) { + alingItemCorner.x = CGRectGetMaxX(item.updateFrame); + } else { + alingItemCorner.x = alingPoint.x; + } + if((_alignPosition & MobilyDataContainerAlignTop) != 0) { + alingItemCorner.y = CGRectGetMinY(item.updateFrame); + } else if((_alignPosition & MobilyDataContainerAlignCenteredVertically) != 0) { + alingItemCorner.y = CGRectGetMidY(item.updateFrame); + } else if((_alignPosition & MobilyDataContainerAlignBottom) != 0) { + alingItemCorner.y = CGRectGetMaxY(item.updateFrame); + } else { + alingItemCorner.y = alingPoint.y; + } + CGFloat dx = alingPoint.x - alingItemCorner.x; + CGFloat dy = alingPoint.y - alingItemCorner.y; + if((MOBILY_FABS(alingItemCorner.x - contentOffset.x) > MOBILY_EPSILON) && (MOBILY_FABS(dx) <= _alignThreshold.horizontal)) { + contentOffset.x -= dx; + alingPoint.x -= dx; + } + if((MOBILY_FABS(alingItemCorner.y - contentOffset.y) > MOBILY_EPSILON) && (MOBILY_FABS(dy) <= _alignThreshold.vertical)) { + contentOffset.y -= dy; + alingPoint.y -= dy; + } + } + } + contentOffset.x = MAX(0.0f, MIN(contentOffset.x, contentSize.width - visibleSize.width)); + contentOffset.y = MAX(0.0f, MIN(contentOffset.y, contentSize.height - visibleSize.height)); + } + } + return contentOffset; +} + +- (CGRect)_validateEntriesForAvailableFrame:(CGRect __unused)frame { + return CGRectNull; +} + +- (void)_willEntriesLayoutForBounds:(CGRect __unused)bounds { +} + +- (void)_didEntriesLayoutForBounds:(CGRect)bounds { + for(MobilyDataItem* entry in _entries) { + [entry validateLayoutForBounds:bounds]; + } +} + +#pragma mark MobilySearchBarDelegate + +- (void)searchBarBeginSearch:(MobilySearchBar*)searchBar { + for(MobilyDataItem* entry in _entries) { + [entry searchBarBeginSearch:searchBar]; + } +} + +- (void)searchBarEndSearch:(MobilySearchBar*)searchBar { + for(MobilyDataItem* entry in _entries) { + [entry searchBarEndSearch:searchBar]; + } +} + +- (void)searchBarBeginEditing:(MobilySearchBar*)searchBar { + for(MobilyDataItem* entry in _entries) { + [entry searchBarBeginEditing:searchBar]; + } +} + +- (void)searchBar:(MobilySearchBar*)searchBar textChanged:(NSString*)textChanged { + for(MobilyDataItem* entry in _entries) { + [entry searchBar:searchBar textChanged:textChanged]; + } +} + +- (void)searchBarEndEditing:(MobilySearchBar*)searchBar { + for(MobilyDataItem* entry in _entries) { + [entry searchBarEndEditing:searchBar]; + } +} + +- (void)searchBarPressedClear:(MobilySearchBar*)searchBar { + for(MobilyDataItem* entry in _entries) { + [entry searchBarPressedClear:searchBar]; + } +} + +- (void)searchBarPressedReturn:(MobilySearchBar*)searchBar { + for(MobilyDataItem* entry in _entries) { + [entry searchBarPressedReturn:searchBar]; + } +} + +- (void)searchBarPressedCancel:(MobilySearchBar*)searchBar { + for(MobilyDataItem* entry in _entries) { + [entry searchBarPressedCancel:searchBar]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataContainerItemsFlow.m b/Sources/MobilyCore/MobilyDataContainerItemsFlow.m new file mode 100644 index 0000000..7ae278c --- /dev/null +++ b/Sources/MobilyCore/MobilyDataContainerItemsFlow.m @@ -0,0 +1,385 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyDataContainerItemsFlow + +#pragma mark Synthesize + +@synthesize orientation = _orientation; +@synthesize margin = _margin; +@synthesize spacing = _spacing; +@synthesize defaultSize = _defaultSize; +@synthesize header = _header; +@synthesize footer = _footer; +@synthesize items = _items; + +#pragma mark Init / Free + ++ (instancetype)containerWithOrientation:(MobilyDataContainerOrientation)orientation { + return [[self alloc] initWithOrientation:orientation]; +} + +- (instancetype)initWithOrientation:(MobilyDataContainerOrientation)orientation { + self = [super init]; + if(self != nil) { + _orientation = orientation; + } + return self; +} + +- (void)setup { + [super setup]; + + _orientation = MobilyDataContainerOrientationVertical; + _margin = UIEdgeInsetsZero; + _spacing = UIOffsetZero; + _defaultSize = CGSizeMake(44.0f, 44.0f); + _items = NSMutableArray.array; +} + +#pragma mark Property + +- (void)setOrientation:(MobilyDataContainerOrientation)orientation { + if(_orientation != orientation) { + _orientation = orientation; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setMargin:(UIEdgeInsets)margin { + if(UIEdgeInsetsEqualToEdgeInsets(_margin, margin) == NO) { + _margin = margin; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setSpacing:(UIOffset)spacing { + if(UIOffsetEqualToOffset(_spacing, spacing) == NO) { + _spacing = spacing; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setDefaultSize:(CGSize)defaultSize { + if(CGSizeEqualToSize(_defaultSize, defaultSize) == NO) { + _defaultSize = defaultSize; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setHeader:(MobilyDataItem*)header { + if(_header != header) { + if(_header != nil) { + [self _deleteEntry:_header]; + } + _header = header; + if(_header != nil) { + [self _appendEntry:_header]; + } + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setFooter:(MobilyDataItem*)footer { + if(_footer != footer) { + if(_footer != nil) { + [self _deleteEntry:_footer]; + } + _footer = footer; + if(_footer != nil) { + [self _appendEntry:_footer]; + } + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +#pragma mark Public + +- (void)prependIdentifier:(NSString*)identifier byData:(id)data { + [self prependItem:[MobilyDataItem itemWithIdentifier:identifier order:0 data:data]]; +} + +- (void)prependItem:(MobilyDataItem*)item { + [_items insertObject:item atIndex:0]; + if(_header != nil) { + [self _insertEntry:item atIndex:[_entries indexOfObject:_header] + 1]; + } else { + [self _prependEntry:item]; + } +} + +- (void)prependItems:(NSArray*)items { + [_items insertObjects:items atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, items.count)]]; + if(_header != nil) { + [self _insertEntries:items atIndex:[_entries indexOfObject:_header] + 1]; + } else { + [self _prependEntries:items]; + } +} + +- (void)appendIdentifier:(NSString*)identifier byData:(id)data { + [self appendItem:[MobilyDataItem itemWithIdentifier:identifier order:0 data:data]]; +} + +- (void)appendItem:(MobilyDataItem*)item { + [_items addObject:item]; + if(_footer != nil) { + [self _insertEntry:item atIndex:[_entries indexOfObject:_footer] - 1]; + } else { + [self _appendEntry:item]; + } +} + +- (void)appendItems:(NSArray*)items { + [_items addObjectsFromArray:items]; + if(_footer != nil) { + [self _insertEntries:items atIndex:[_entries indexOfObject:_footer] - 1]; + } else { + [self _appendEntries:items]; + } +} + +- (void)insertIdentifier:(NSString*)identifier byData:(id)data atIndex:(NSUInteger)index { + [self insertItem:[MobilyDataItem itemWithIdentifier:identifier order:0 data:data] atIndex:index]; +} + +- (void)insertItem:(MobilyDataItem*)item atIndex:(NSUInteger)index { + [_items insertObject:item atIndex:index]; + if(_header != nil) { + index = MAX(index, [_entries indexOfObject:_header] + 1); + } + if(_footer != nil) { + index = MIN(index, [_entries indexOfObject:_footer] - 1); + } + [self _insertEntry:item atIndex:index]; +} + +- (void)insertItems:(NSArray*)items atIndex:(NSUInteger)index { + [_items insertObjects:items atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, items.count)]]; + if(_header != nil) { + index = MAX(index, [_entries indexOfObject:_header] + 1); + } + if(_footer != nil) { + index = MIN(index, [_entries indexOfObject:_footer] - 1); + } + [self _insertEntries:items atIndex:index]; +} + +- (void)replaceOriginItem:(MobilyDataItem*)originItem withItem:(MobilyDataItem*)item { + NSUInteger index = [_items indexOfObject:originItem]; + if(index != NSNotFound) { + _items[index] = item; + [self _replaceOriginEntry:originItem withEntry:item]; + } +} + +- (void)replaceOriginItems:(NSArray*)originItems withItems:(NSArray*)items { + NSIndexSet* indexSet = [_items indexesOfObjectsPassingTest:^BOOL(MobilyDataItem* originItem, NSUInteger index __unused, BOOL* stop __unused) { + return [originItems containsObject:originItem]; + }]; + if(indexSet.count == items.count) { + [_items replaceObjectsAtIndexes:indexSet withObjects:items]; + [self _replaceOriginEntries:originItems withEntries:items]; + } +} + +- (void)deleteItem:(MobilyDataItem*)item { + if([_items containsObject:item] == YES) { + [_items removeObject:item]; + [self _deleteEntry:item]; + } +} + +- (void)deleteItems:(NSArray*)items { + if([_items moContainsObjectsInArray:items] == YES) { + [_items removeObjectsInArray:items]; + [self _deleteEntries:items]; + } +} + +- (void)deleteAllItems { + if(_items.count > 0) { + NSArray* items = [NSArray arrayWithArray:_items]; + [self _deleteEntries:items]; + [_items removeAllObjects]; + } +} + +#pragma mark Private override + +- (CGRect)_validateEntriesForAvailableFrame:(CGRect)frame { + CGPoint offset = CGPointMake(frame.origin.x + _margin.left, frame.origin.y + _margin.top); + CGSize restriction = CGSizeMake(frame.size.width - (_margin.left + _margin.right), frame.size.height - (_margin.top + _margin.bottom)); + CGSize cumulative = CGSizeZero, cumulativeRow = CGSizeZero; + NSUInteger countOfRow = 0; + switch(_orientation) { + case MobilyDataContainerOrientationVertical: { + for(MobilyDataItem* entry in _entries) { + CGSize entrySize = [entry sizeForAvailableSize:CGSizeMake(restriction.width, (_defaultSize.height > 0) ? _defaultSize.height : FLT_MAX)]; + if((entrySize.width >= 0.0f) && (entrySize.height >= 0.0f) && (entry.hidden == NO)) { + if((countOfRow > 0) && (cumulativeRow.width + entrySize.width > restriction.width)) { + offset.x = 0.0f; + offset.y += cumulativeRow.height + _spacing.vertical; + cumulative.width = MAX(restriction.width, _margin.left + cumulativeRow.width + _margin.right); + cumulative.height += cumulativeRow.height + _spacing.vertical; + cumulativeRow = CGSizeZero; + countOfRow = 0; + } + entry.updateFrame = CGRectMake(offset.x, offset.y, entrySize.width, entrySize.height); + offset.x += entrySize.width + _spacing.horizontal; + cumulativeRow.width += entrySize.width + _spacing.horizontal; + cumulativeRow.height = MAX(entrySize.height, cumulativeRow.height); + countOfRow++; + } + } + cumulative.width -= _spacing.horizontal; + cumulative.height -= _spacing.vertical; + break; + } + case MobilyDataContainerOrientationHorizontal: { + for(MobilyDataItem* entry in _entries) { + CGSize entrySize = [entry sizeForAvailableSize:CGSizeMake((_defaultSize.width > 0) ? _defaultSize.width : FLT_MAX, restriction.height)]; + if((entrySize.width >= 0.0f) && (entrySize.height >= 0.0f) && (entry.hidden == NO)) { + if((countOfRow > 0) && (cumulativeRow.height + entrySize.height > restriction.height)) { + offset.x += cumulativeRow.width + _spacing.horizontal; + offset.y = 0.0f; + cumulative.width = cumulativeRow.width + _spacing.horizontal; + cumulative.height += MAX(restriction.height, _margin.top + cumulativeRow.height + _margin.bottom); + cumulativeRow = CGSizeZero; + countOfRow = 0; + } + entry.updateFrame = CGRectMake(offset.x, offset.y, entrySize.width, entrySize.height); + offset.y += entrySize.height + _spacing.vertical; + cumulativeRow.width = MAX(entrySize.width, cumulativeRow.width); + cumulativeRow.height += entrySize.height + _spacing.vertical; + countOfRow++; + } + } + cumulative.width -= _spacing.horizontal; + cumulative.height -= _spacing.vertical; + break; + } + } + return CGRectMake(frame.origin.x, frame.origin.y, _margin.left + cumulative.width + _margin.right, _margin.top + cumulative.height + _margin.bottom); +} + +- (void)_willEntriesLayoutForBounds:(CGRect)bounds { + switch(_orientation) { + case MobilyDataContainerOrientationVertical: { + CGFloat boundsBefore = bounds.origin.y; + CGFloat boundsAfter = bounds.origin.y + bounds.size.height; + CGFloat entriesBefore = _frame.origin.y; + CGFloat entriesAfter = _frame.origin.y + _frame.size.height; + if((_header != nil) && (_header.hidden == NO)) { + CGRect headerFrame = _header.updateFrame; + headerFrame.origin.y = boundsBefore; + if((_footer != nil) && (_footer.hidden == NO)) { + CGRect footerFrame = _footer.updateFrame; + headerFrame.origin.y = MIN(headerFrame.origin.y, (boundsAfter - (_spacing.vertical + footerFrame.size.height)) - headerFrame.size.height); + } else { + headerFrame.origin.y = MIN(headerFrame.origin.y, boundsAfter - headerFrame.size.height); + } + headerFrame.origin.y = MAX(entriesBefore, MIN(headerFrame.origin.y, entriesAfter - headerFrame.size.height)); + _header.displayFrame = headerFrame; + } + if((_footer != nil) && (_footer.hidden == NO)) { + CGRect footerFrame = _footer.updateFrame; + footerFrame.origin.y = boundsAfter - footerFrame.size.height; + if((_header != nil) && (_header.hidden == NO)) { + CGRect headerFrame = _header.updateFrame; + footerFrame.origin.y = MAX(footerFrame.origin.y, (boundsBefore + _spacing.vertical) + headerFrame.size.height); + } else { + footerFrame.origin.y = MAX(footerFrame.origin.y, boundsBefore); + } + footerFrame.origin.y = MAX(entriesBefore, MIN(footerFrame.origin.y, entriesAfter - footerFrame.size.height)); + _footer.displayFrame = footerFrame; + } + break; + } + case MobilyDataContainerOrientationHorizontal: { + CGFloat boundsBefore = bounds.origin.x; + CGFloat boundsAfter = bounds.origin.x + bounds.size.width; + CGFloat entriesBefore = _frame.origin.x; + CGFloat entriesAfter = _frame.origin.x + _frame.size.width; + if((_header != nil) && (_header.hidden == NO)) { + CGRect headerFrame = _header.updateFrame; + headerFrame.origin.x = boundsBefore; + if((_footer != nil) && (_footer.hidden == NO)) { + CGRect footerFrame = _footer.updateFrame; + headerFrame.origin.x = MIN(headerFrame.origin.x, (boundsAfter - (_spacing.horizontal + footerFrame.size.width)) - headerFrame.size.width); + } else { + headerFrame.origin.x = MIN(headerFrame.origin.x, boundsAfter - headerFrame.size.width); + } + headerFrame.origin.x = MAX(entriesBefore, MIN(headerFrame.origin.x, entriesAfter - headerFrame.size.width)); + _header.displayFrame = headerFrame; + } + if((_footer != nil) && (_footer.hidden == NO)) { + CGRect footerFrame = _footer.updateFrame; + footerFrame.origin.x = boundsAfter - footerFrame.size.width; + if((_header != nil) && (_header.hidden == NO)) { + CGRect headerFrame = _header.updateFrame; + footerFrame.origin.x = MAX(footerFrame.origin.x, (boundsBefore + _spacing.horizontal) + headerFrame.size.width); + } else { + footerFrame.origin.x = MAX(footerFrame.origin.x, boundsBefore); + } + footerFrame.origin.x = MAX(entriesBefore, MIN(footerFrame.origin.x, entriesAfter - footerFrame.size.width)); + _footer.displayFrame = footerFrame; + } + break; + } + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataContainerItemsGrid.m b/Sources/MobilyCore/MobilyDataContainerItemsGrid.m new file mode 100644 index 0000000..3f205f3 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataContainerItemsGrid.m @@ -0,0 +1,531 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyDataContainerItemsGrid + +#pragma mark Synthesize + +@synthesize orientation = _orientation; +@synthesize margin = _margin; +@synthesize spacing = _spacing; +@synthesize defaultColumnSize = _defaultColumnSize; +@synthesize defaultRowSize = _defaultRowSize; +@synthesize numberOfColumns = _numberOfColumns; +@synthesize numberOfRows = _numberOfRows; +@synthesize headerColumns = _headerColumns; +@synthesize footerColumns = _footerColumns; +@synthesize headerRows = _headerRows; +@synthesize footerRows = _footerRows; +@synthesize content = _content; + +#pragma mark Init / Free + ++ (instancetype)containerWithOrientation:(MobilyDataContainerOrientation)orientation { + return [[self alloc] initWithOrientation:orientation]; +} + +- (instancetype)initWithOrientation:(MobilyDataContainerOrientation)orientation { + self = [super init]; + if(self != nil) { + _orientation = orientation; + } + return self; +} + +- (void)setup { + [super setup]; + + _orientation = MobilyDataContainerOrientationVertical; + _margin = UIEdgeInsetsZero; + _spacing = UIOffsetZero; + _defaultColumnSize = CGSizeMake(128.0f, 64.0f); + _defaultRowSize = CGSizeMake(64.0f, 44.0f); + _numberOfColumns = 0; + _numberOfRows = 0; + _headerColumns = NSMutableArray.array; + _footerColumns = NSMutableArray.array; + _headerRows = NSMutableArray.array; + _footerRows = NSMutableArray.array; + _content = MobilyMutableGrid.grid; +} + +#pragma mark Property + +- (void)setOrientation:(MobilyDataContainerOrientation)orientation { + if(_orientation != orientation) { + _orientation = orientation; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setMargin:(UIEdgeInsets)margin { + if(UIEdgeInsetsEqualToEdgeInsets(_margin, margin) == NO) { + _margin = margin; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setSpacing:(UIOffset)spacing { + if(UIOffsetEqualToOffset(_spacing, spacing) == NO) { + _spacing = spacing; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setDefaultColumnSize:(CGSize)defaultColumnSize { + if(CGSizeEqualToSize(_defaultColumnSize, defaultColumnSize) == NO) { + _defaultColumnSize = defaultColumnSize; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setDefaultRowSize:(CGSize)defaultRowSize { + if(CGSizeEqualToSize(_defaultRowSize, defaultRowSize) == NO) { + _defaultRowSize = defaultRowSize; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +#pragma mark Public + +- (void)prependColumnIdentifier:(NSString*)identifier byData:(id)data { + [self prependColumnHeader:[MobilyDataItem itemWithIdentifier:identifier order:1 data:data] + andColumnFooter:nil]; +} + +- (void)prependColumn:(MobilyDataItem*)column { + [self prependColumnHeader:column + andColumnFooter:nil]; +} + +- (void)prependColumnIdentifier:(NSString*)identifier byHeaderData:(id)headerData byFooterData:(id)footerData { + [self prependColumnHeader:[MobilyDataItem itemWithIdentifier:identifier order:1 data:headerData] + andColumnFooter:[MobilyDataItem itemWithIdentifier:identifier order:1 data:footerData]]; +} + +- (void)prependColumnHeaderIdentifier:(NSString*)columnIdentifier byHeaderData:(id)headerData andFooterIdentifier:(NSString*)footerIdentifier byFooterData:(id)footerData { + [self prependColumnHeader:[MobilyDataItem itemWithIdentifier:columnIdentifier order:1 data:headerData] + andColumnFooter:[MobilyDataItem itemWithIdentifier:footerIdentifier order:1 data:footerData]]; +} + +- (void)prependColumnHeader:(MobilyDataItem*)header andColumnFooter:(MobilyDataItem*)footer { + if(header != nil) { + [_headerColumns insertObject:header atIndex:0]; + [self _prependEntry:header]; + } + if(footer != nil) { + [_footerColumns insertObject:footer atIndex:0]; + [self _prependEntry:footer]; + } + if(header != nil) { + [_content insertColumn:[_headerColumns indexOfObject:header] objects:nil]; + } else if(footer != nil) { + [_content insertColumn:[_footerColumns indexOfObject:footer] objects:nil]; + } +} + +- (void)appendColumnIdentifier:(NSString*)identifier byData:(id)data { + [self appendColumnHeader:[MobilyDataItem itemWithIdentifier:identifier order:1 data:data] + andColumnFooter:nil]; +} + +- (void)appendColumn:(MobilyDataItem*)column { + [self appendColumnHeader:column + andColumnFooter:nil]; +} + +- (void)appendColumnIdentifier:(NSString*)identifier byHeaderData:(id)headerData byFooterData:(id)footerData { + [self appendColumnHeader:[MobilyDataItem itemWithIdentifier:identifier order:1 data:headerData] + andColumnFooter:[MobilyDataItem itemWithIdentifier:identifier order:1 data:footerData]]; +} + +- (void)appendColumnHeaderIdentifier:(NSString*)columnIdentifier byHeaderData:(id)headerData andFooterIdentifier:(NSString*)footerIdentifier byFooterData:(id)footerData { + [self appendColumnHeader:[MobilyDataItem itemWithIdentifier:columnIdentifier order:1 data:headerData] + andColumnFooter:[MobilyDataItem itemWithIdentifier:footerIdentifier order:1 data:footerData]]; +} + +- (void)appendColumnHeader:(MobilyDataItem*)header andColumnFooter:(MobilyDataItem*)footer { + if(header != nil) { + [_headerColumns addObject:header]; + [self _appendEntry:header]; + } + if(footer != nil) { + [_footerColumns addObject:footer]; + [self _appendEntry:footer]; + } + if(header != nil) { + [_content insertColumn:[_headerColumns indexOfObject:header] objects:nil]; + } else if(footer != nil) { + [_content insertColumn:[_footerColumns indexOfObject:footer] objects:nil]; + } +} + +- (void)insertColumnIdentifier:(NSString*)identifier byData:(id)data atIndex:(NSUInteger)index { + [self insertColumnHeader:[MobilyDataItem itemWithIdentifier:identifier order:1 data:data] + andColumnFooter:nil + atIndex:index]; +} + +- (void)insertColumn:(MobilyDataItem*)column atIndex:(NSUInteger)index { + [self insertColumnHeader:column + andColumnFooter:nil + atIndex:index]; +} + +- (void)insertColumnIdentifier:(NSString*)identifier byHeaderData:(id)headerData byFooterData:(id)footerData atIndex:(NSUInteger)index { + [self insertColumnHeader:[MobilyDataItem itemWithIdentifier:identifier order:1 data:headerData] + andColumnFooter:[MobilyDataItem itemWithIdentifier:identifier order:1 data:footerData] + atIndex:index]; +} + +- (void)insertColumnHeaderIdentifier:(NSString*)columnIdentifier byHeaderData:(id)headerData andFooterIdentifier:(NSString*)footerIdentifier byFooterData:(id)footerData atIndex:(NSUInteger)index { + [self insertColumnHeader:[MobilyDataItem itemWithIdentifier:columnIdentifier order:1 data:headerData] + andColumnFooter:[MobilyDataItem itemWithIdentifier:footerIdentifier order:1 data:footerData] + atIndex:index]; +} + +- (void)insertColumnHeader:(MobilyDataItem*)header andColumnFooter:(MobilyDataItem*)footer atIndex:(NSUInteger)index { + if(header != nil) { + [_headerColumns insertObject:header atIndex:index]; + [self _insertEntry:header atIndex:index]; + } + if(footer != nil) { + [_footerColumns insertObject:footer atIndex:index]; + [self _insertEntry:footer atIndex:index]; + } + if(header != nil) { + [_content insertColumn:index objects:nil]; + } else if(footer != nil) { + [_content insertColumn:index objects:nil]; + } +} + +- (void)deleteColumn:(MobilyDataItem*)column { + NSUInteger headerIndex = [_headerColumns indexOfObject:column]; + NSUInteger footerIndex = [_footerColumns indexOfObject:column]; + NSUInteger index = (headerIndex != NSNotFound) ? headerIndex : footerIndex; + if(headerIndex != NSNotFound) { + [_headerColumns removeObjectAtIndex:index]; + [self _deleteEntry:_headerColumns[index]]; + } + if(footerIndex != NSNotFound) { + [_footerColumns removeObjectAtIndex:index]; + [self _deleteEntry:_footerColumns[index]]; + } +} + +- (void)deleteAllColumns { + if(_headerColumns.count > 0) { + NSArray* headerColumns = [NSArray arrayWithArray:_headerColumns]; + [self _deleteEntries:headerColumns]; + [_headerColumns removeAllObjects]; + } + if(_footerColumns.count > 0) { + NSArray* footerColumns = [NSArray arrayWithArray:_footerColumns]; + [self _deleteEntries:footerColumns]; + [_footerColumns removeAllObjects]; + } + if(_content.numberOfColumns > 0) { + NSArray* cells = [NSArray arrayWithArray:_content.objects]; + [self _deleteEntries:cells]; + [_content removeAllObjects]; + } +} + +- (void)prependRowIdentifier:(NSString*)identifier byData:(id)data { + [self prependRowHeader:[MobilyDataItem itemWithIdentifier:identifier order:1 data:data] + andRowFooter:nil]; +} + +- (void)prependRow:(MobilyDataItem*)column { + [self prependRowHeader:column + andRowFooter:nil]; +} + +- (void)prependRowIdentifier:(NSString*)identifier byHeaderData:(id)headerData byFooterData:(id)footerData { + [self prependRowHeader:[MobilyDataItem itemWithIdentifier:identifier order:1 data:headerData] + andRowFooter:[MobilyDataItem itemWithIdentifier:identifier order:1 data:footerData]]; +} + +- (void)prependRowHeaderIdentifier:(NSString*)columnIdentifier byHeaderData:(id)headerData andFooterIdentifier:(NSString*)footerIdentifier byFooterData:(id)footerData { + [self prependRowHeader:[MobilyDataItem itemWithIdentifier:columnIdentifier order:1 data:headerData] + andRowFooter:[MobilyDataItem itemWithIdentifier:footerIdentifier order:1 data:footerData]]; +} + +- (void)prependRowHeader:(MobilyDataItem*)header andRowFooter:(MobilyDataItem*)footer { + if(header != nil) { + [_headerRows insertObject:header atIndex:0]; + [self _prependEntry:header]; + } + if(footer != nil) { + [_footerRows insertObject:footer atIndex:0]; + [self _prependEntry:footer]; + } + if(header != nil) { + [_content insertRow:[_headerRows indexOfObject:header] objects:nil]; + } else if(footer != nil) { + [_content insertRow:[_footerRows indexOfObject:footer] objects:nil]; + } +} + +- (void)appendRowIdentifier:(NSString*)identifier byData:(id)data { + [self appendRowHeader:[MobilyDataItem itemWithIdentifier:identifier order:1 data:data] + andRowFooter:nil]; +} + +- (void)appendRow:(MobilyDataItem*)row { + [self appendRowHeader:row + andRowFooter:nil]; +} + +- (void)appendRowIdentifier:(NSString*)identifier byHeaderData:(id)headerData byFooterData:(id)footerData { + [self appendRowHeader:[MobilyDataItem itemWithIdentifier:identifier order:1 data:headerData] + andRowFooter:[MobilyDataItem itemWithIdentifier:identifier order:1 data:footerData]]; +} + +- (void)appendRowHeaderIdentifier:(NSString*)columnIdentifier byHeaderData:(id)headerData andFooterIdentifier:(NSString*)footerIdentifier byFooterData:(id)footerData { + [self appendRowHeader:[MobilyDataItem itemWithIdentifier:columnIdentifier order:1 data:headerData] + andRowFooter:[MobilyDataItem itemWithIdentifier:footerIdentifier order:1 data:footerData]]; +} + +- (void)appendRowHeader:(MobilyDataItem*)header andRowFooter:(MobilyDataItem*)footer { + if(header != nil) { + [_headerRows addObject:header]; + [self _appendEntry:header]; + } + if(footer != nil) { + [_footerRows addObject:footer]; + [self _appendEntry:footer]; + } + if(header != nil) { + [_content insertRow:[_headerRows indexOfObject:header] objects:nil]; + } else if(footer != nil) { + [_content insertRow:[_footerRows indexOfObject:footer] objects:nil]; + } +} + +- (void)insertRowIdentifier:(NSString*)identifier byData:(id)data atIndex:(NSUInteger)index { + [self insertRowHeader:[MobilyDataItem itemWithIdentifier:identifier order:1 data:data] + andRowFooter:nil + atIndex:index]; +} + +- (void)insertRow:(MobilyDataItem*)row atIndex:(NSUInteger)index { + [self insertRowHeader:row + andRowFooter:nil + atIndex:index]; +} + +- (void)insertRowIdentifier:(NSString*)identifier byHeaderData:(id)headerData byFooterData:(id)footerData atIndex:(NSUInteger)index { + [self insertRowHeader:[MobilyDataItem itemWithIdentifier:identifier order:1 data:headerData] + andRowFooter:[MobilyDataItem itemWithIdentifier:identifier order:1 data:footerData] + atIndex:index]; +} + +- (void)insertRowHeaderIdentifier:(NSString*)columnIdentifier byHeaderData:(id)headerData andFooterIdentifier:(NSString*)footerIdentifier byFooterData:(id)footerData atIndex:(NSUInteger)index { + [self insertRowHeader:[MobilyDataItem itemWithIdentifier:columnIdentifier order:1 data:headerData] + andRowFooter:[MobilyDataItem itemWithIdentifier:footerIdentifier order:1 data:footerData] + atIndex:index]; +} + +- (void)insertRowHeader:(MobilyDataItem*)header andRowFooter:(MobilyDataItem*)footer atIndex:(NSUInteger)index { + if(header != nil) { + [_headerRows insertObject:header atIndex:index]; + [self _insertEntry:header atIndex:index]; + } + if(footer != nil) { + [_footerRows insertObject:footer atIndex:index]; + [self _insertEntry:footer atIndex:index]; + } + if(header != nil) { + [_content insertRow:index objects:nil]; + } else if(footer != nil) { + [_content insertRow:index objects:nil]; + } +} + +- (void)deleteRow:(MobilyDataItem*)row { + NSUInteger headerIndex = [_headerRows indexOfObject:row]; + NSUInteger footerIndex = [_footerRows indexOfObject:row]; + NSUInteger index = (headerIndex != NSNotFound) ? headerIndex : footerIndex; + if(headerIndex != NSNotFound) { + [_headerRows removeObjectAtIndex:index]; + [self _deleteEntry:_headerRows[index]]; + } + if(footerIndex != NSNotFound) { + [_footerRows removeObjectAtIndex:index]; + [self _deleteEntry:_footerRows[index]]; + } +} + +- (void)deleteAllRows { + if(_headerRows.count > 0) { + NSArray* headerRows = [NSArray arrayWithArray:_headerRows]; + [self _deleteEntries:headerRows]; + [_headerRows removeAllObjects]; + } + if(_footerRows.count > 0) { + NSArray* footerRows = [NSArray arrayWithArray:_footerRows]; + [self _deleteEntries:footerRows]; + [_footerRows removeAllObjects]; + } + if(_content.numberOfRows > 0) { + NSArray* cells = [NSArray arrayWithArray:_content.objects]; + [self _deleteEntries:cells]; + [_content removeAllObjects]; + } +} + +- (void)insertContentIdentifier:(NSString*)identifier byData:(id)data atColumn:(NSUInteger)column atRow:(NSUInteger)row { + [self insertContent:[MobilyDataItem itemWithIdentifier:identifier order:0 data:data] + atColumn:column + atRow:row]; +} + +- (void)insertContent:(MobilyDataItem*)content atColumn:(NSUInteger)column atRow:(NSUInteger)row { + [_content setObject:content atColumn:column atRow:row]; + [self _appendEntry:content]; +} + +- (void)deleteContentAtColumn:(NSUInteger)column atRow:(NSUInteger)row { + MobilyDataItem* cell = [_content objectAtColumn:column atRow:row]; + if(cell != nil) { + [_content setObject:nil atColumn:column atRow:row]; + [self _deleteEntry:cell]; + } +} + +- (void)deleteAllContent { + if(_headerRows.count > 0) { + NSArray* headerRows = [NSArray arrayWithArray:_headerRows]; + [self _deleteEntries:headerRows]; + [_headerRows removeAllObjects]; + } + if(_footerRows.count > 0) { + NSArray* footerRows = [NSArray arrayWithArray:_footerRows]; + [self _deleteEntries:footerRows]; + [_footerRows removeAllObjects]; + } + if(_content.numberOfRows > 0) { + NSArray* cells = [NSArray arrayWithArray:_content.objects]; + [self _deleteEntries:cells]; + [_content setObjects:nil]; + } +} + +#pragma mark Private override + +- (CGRect)_validateEntriesForAvailableFrame:(CGRect)frame { + CGFloat maxColumnHeight = 0.0f; + NSMutableArray* columnsSize = [NSMutableArray array]; + for(MobilyDataItem* headerColumn in _headerColumns) { + CGSize itemSize = [headerColumn sizeForAvailableSize:_defaultColumnSize]; + if((itemSize.width > 0.0f) && (itemSize.height > 0.0f)) { + [columnsSize addObject:[NSValue valueWithCGSize:itemSize]]; + maxColumnHeight = MAX(maxColumnHeight, itemSize.height); + } + } + // CGFloat footerColumnHeight = 0.0f; + for(MobilyDataItem* footerColumn in _footerColumns) { + CGSize itemSize = [footerColumn sizeForAvailableSize:_defaultColumnSize]; + if((itemSize.width > 0.0f) && (itemSize.height > 0.0f)) { + maxColumnHeight = MAX(maxColumnHeight, itemSize.height); + } + } + CGFloat maxRowWidth = 0.0f; + NSMutableArray* rowsSize = [NSMutableArray array]; + for(MobilyDataItem* headerRow in _headerRows) { + CGSize itemSize = [headerRow sizeForAvailableSize:_defaultRowSize]; + if((itemSize.width > 0.0f) && (itemSize.height > 0.0f)) { + [rowsSize addObject:[NSValue valueWithCGSize:itemSize]]; + maxRowWidth = MAX(maxRowWidth, itemSize.width); + } + } + // CGFloat footerRowWidth = 0.0f; + for(MobilyDataItem* footerRow in _footerRows) { + CGSize itemSize = [footerRow sizeForAvailableSize:_defaultRowSize]; + if((itemSize.width > 0.0f) && (itemSize.height > 0.0f)) { + maxRowWidth = MAX(maxRowWidth, itemSize.width); + } + } + /* + CGSize contentSize = CGSizeZero; + [_content eachColumnsRows:^(id object, NSUInteger column, NSUInteger row) { + }]; + CGPoint offset = CGPointMake(frame.origin.x + _margin.left, frame.origin.y + _margin.top); + CGPoint headerOffset = CGPointMake(offset.x + headerRowSize.width, offset.y + headerColumnSize.height); + CGPoint footerOffset = CGPointMake(headerOffset.x + contentSize.width, headerOffset.y + contentSize.height); + [_headerColumns eachWithIndex:^(MobilyDataItem* headerColumn, NSUInteger index) { + headerColumn.updateFrame = CGRectMake(headerOffset.x + (headerColumnSize.width * index), offset.y, headerColumnSize.width, headerColumnSize.height); + }]; + [_footerColumns eachWithIndex:^(MobilyDataItem* footerColumn, NSUInteger index) { + footerColumn.updateFrame = CGRectMake(footerOffset.x + (footerColumnSize.width * index), offset.y, footerColumnSize.width, footerColumnSize.height); + }]; + [_headerRows eachWithIndex:^(MobilyDataItem* headerRow, NSUInteger index) { + headerRow.updateFrame = CGRectMake(offset.x, headerOffset.y + (headerRowSize.height * index), headerRowSize.width, headerRowSize.height); + }]; + [_footerRows eachWithIndex:^(MobilyDataItem* footerRow, NSUInteger index) { + footerRow.updateFrame = CGRectMake(offset.x, footerOffset.y + (footerRowSize.height * index), footerRowSize.width, footerRowSize.height); + }]; + return CGRectMake(frame.origin.x, + frame.origin.y, + _margin.left + headerRowSize.width + contentSize.width + footerRowSize.width + _margin.right, + _margin.top + headerColumnSize.height + contentSize.height + footerRowSize.height + _margin.bottom); + */ + return CGRectZero; +} + +- (void)_willEntriesLayoutForBounds:(CGRect __unused)bounds { +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataContainerItemsList.m b/Sources/MobilyCore/MobilyDataContainerItemsList.m new file mode 100644 index 0000000..21789a0 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataContainerItemsList.m @@ -0,0 +1,423 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyDataContainerItemsList + +#pragma mark Synthesize + +@synthesize orientation = _orientation; +@synthesize margin = _margin; +@synthesize spacing = _spacing; +@synthesize defaultSize = _defaultSize; +@synthesize header = _header; +@synthesize footer = _footer; +@synthesize items = _items; + +#pragma mark Init / Free + ++ (instancetype)containerWithOrientation:(MobilyDataContainerOrientation)orientation { + return [[self alloc] initWithOrientation:orientation]; +} + +- (instancetype)initWithOrientation:(MobilyDataContainerOrientation)orientation { + self = [super init]; + if(self != nil) { + _orientation = orientation; + } + return self; +} + +- (void)setup { + [super setup]; + + _orientation = MobilyDataContainerOrientationVertical; + _margin = UIEdgeInsetsZero; + _spacing = UIOffsetZero; + _defaultSize = CGSizeMake(44.0f, 44.0f); + _items = NSMutableArray.array; +} + +- (void)dealloc { +} + +#pragma mark Property + +- (void)setOrientation:(MobilyDataContainerOrientation)orientation { + if(_orientation != orientation) { + _orientation = orientation; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setMargin:(UIEdgeInsets)margin { + if(UIEdgeInsetsEqualToEdgeInsets(_margin, margin) == NO) { + _margin = margin; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setDefaultSize:(CGSize)defaultSize { + if(CGSizeEqualToSize(_defaultSize, defaultSize) == NO) { + _defaultSize = defaultSize; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setSpacing:(UIOffset)spacing { + if(UIOffsetEqualToOffset(_spacing, spacing) == NO) { + _spacing = spacing; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setHeader:(MobilyDataItem*)header { + if(_header != header) { + if(_header != nil) { + [self _deleteEntry:_header]; + } + _header = header; + if(_header != nil) { + [self _appendEntry:_header]; + } + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setFooter:(MobilyDataItem*)footer { + if(_footer != footer) { + if(_footer != nil) { + [self _deleteEntry:_footer]; + } + _footer = footer; + if(_footer != nil) { + [self _appendEntry:_footer]; + } + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +#pragma mark Public + +- (MobilyDataItem*)prependIdentifier:(NSString*)identifier byData:(id)data { + MobilyDataItem* item = [MobilyDataItem itemWithIdentifier:identifier order:0 data:data]; + [self prependItem:item]; + return item; +} + +- (void)prependItem:(MobilyDataItem*)item { + [_items insertObject:item atIndex:0]; + if(_header != nil) { + [self _insertEntry:item atIndex:[_entries indexOfObject:_header] + 1]; + } else { + [self _prependEntry:item]; + } +} + +- (void)prependItems:(NSArray*)items { + [_items insertObjects:items atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, items.count)]]; + if(_header != nil) { + [self _insertEntries:items atIndex:[_entries indexOfObject:_header] + 1]; + } else { + [self _prependEntries:items]; + } +} + +- (MobilyDataItem*)appendIdentifier:(NSString*)identifier byData:(id)data { + MobilyDataItem* item = [MobilyDataItem itemWithIdentifier:identifier order:0 data:data]; + [self appendItem:item]; + return item; +} + +- (void)appendItem:(MobilyDataItem*)item { + [_items addObject:item]; + if(_footer != nil) { + [self _insertEntry:item atIndex:[_entries indexOfObject:_footer] - 1]; + } else { + [self _appendEntry:item]; + } +} + +- (void)appendItems:(NSArray*)items { + [_items addObjectsFromArray:items]; + if(_footer != nil) { + [self _insertEntries:items atIndex:[_entries indexOfObject:_footer] - 1]; + } else { + [self _appendEntries:items]; + } +} + +- (MobilyDataItem*)insertIdentifier:(NSString*)identifier byData:(id)data atIndex:(NSUInteger)index { + MobilyDataItem* item = [MobilyDataItem itemWithIdentifier:identifier order:0 data:data]; + [self insertItem:item atIndex:index]; + return item; +} + +- (void)insertItem:(MobilyDataItem*)item atIndex:(NSUInteger)index { + [_items insertObject:item atIndex:index]; + if(_header != nil) { + index = MAX(index, [_entries indexOfObject:_header] + 1); + } + if(_footer != nil) { + index = MIN(index, [_entries indexOfObject:_footer] - 1); + } + [self _insertEntry:item atIndex:index]; +} + +- (void)insertItems:(NSArray*)items atIndex:(NSUInteger)index { + [_items insertObjects:items atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, items.count)]]; + if(_header != nil) { + index = MAX(index, [_entries indexOfObject:_header] + 1); + } + if(_footer != nil) { + index = MIN(index, [_entries indexOfObject:_footer] - 1); + } + [self _insertEntries:items atIndex:index]; +} + +- (void)replaceOriginItem:(MobilyDataItem*)originItem withItem:(MobilyDataItem*)item { + NSUInteger index = [_items indexOfObject:originItem]; + if(index != NSNotFound) { + _items[index] = item; + [self _replaceOriginEntry:originItem withEntry:item]; + } +} + +- (void)replaceOriginItems:(NSArray*)originItems withItems:(NSArray*)items { + NSIndexSet* indexSet = [_items indexesOfObjectsPassingTest:^BOOL(MobilyDataItem* originItem, NSUInteger index __unused, BOOL* stop __unused) { + return [originItems containsObject:originItem]; + }]; + if(indexSet.count == items.count) { + [_items replaceObjectsAtIndexes:indexSet withObjects:items]; + [self _replaceOriginEntries:originItems withEntries:items]; + } +} + +- (void)deleteItem:(MobilyDataItem*)item { + if([_items containsObject:item] == YES) { + [_items removeObject:item]; + [self _deleteEntry:item]; + } +} + +- (void)deleteItems:(NSArray*)items { + if([_items moContainsObjectsInArray:items] == YES) { + [_items removeObjectsInArray:items]; + [self _deleteEntries:items]; + } +} + +- (void)deleteAllItems { + if(_items.count > 0) { + NSArray* items = [NSArray arrayWithArray:_items]; + [_items removeAllObjects]; + [self _deleteEntries:items]; + } +} + +#pragma mark Private override + +- (CGRect)_validateEntriesForAvailableFrame:(CGRect)frame { + __block CGPoint offset = CGPointMake(frame.origin.x + _margin.left, frame.origin.y + _margin.top); + CGSize restriction = CGSizeMake(frame.size.width - (_margin.left + _margin.right), frame.size.height - (_margin.top + _margin.bottom)); + CGSize cumulative = CGSizeZero; + switch(_orientation) { + case MobilyDataContainerOrientationVertical: { + CGFloat availableHeight = (_defaultSize.height > 0) ? _defaultSize.height : FLT_MAX; + cumulative.width = restriction.width; + if(_reverse == NO) { + for(MobilyDataItem* entry in _entries) { + CGSize entrySize = [entry sizeForAvailableSize:CGSizeMake(restriction.width, availableHeight)]; + if((entrySize.width >= 0.0f) && (entrySize.height >= 0.0f) && (entry.hidden == NO)) { + entry.updateFrame = CGRectMake(offset.x, offset.y, restriction.width, entrySize.height); + cumulative.height += entrySize.height + _spacing.vertical; + offset.y += entrySize.height + _spacing.vertical; + } + } + if(cumulative.height > MOBILY_EPSILON) { + cumulative.height -= _spacing.vertical; + } + } else { + for(MobilyDataItem* entry in _entries) { + CGSize entrySize = [entry sizeForAvailableSize:CGSizeMake(restriction.width, availableHeight)]; + if((entrySize.width >= 0.0f) && (entrySize.height >= 0.0f) && (entry.hidden == NO)) { + cumulative.height += entrySize.height + _spacing.vertical; + } + } + if(frame.size.height > cumulative.height) { + cumulative.height = frame.size.height; + } else if(cumulative.height > MOBILY_EPSILON) { + cumulative.height -= _spacing.vertical; + } + offset.y += cumulative.height; + [_entries moEach:^(MobilyDataItem* entry) { + CGSize entrySize = [entry sizeForAvailableSize:CGSizeMake(restriction.width, availableHeight)]; + if((entrySize.width >= 0.0f) && (entrySize.height >= 0.0f) && (entry.hidden == NO)) { + entry.updateFrame = CGRectMake(offset.x, offset.y - entrySize.height, restriction.width, entrySize.height); + offset.y -= entrySize.height + _spacing.vertical; + } + } options:NSEnumerationReverse]; + } + break; + } + case MobilyDataContainerOrientationHorizontal: { + CGFloat availableWidth = (_defaultSize.width > 0) ? _defaultSize.width : FLT_MAX; + cumulative.height = restriction.height; + if(_reverse == NO) { + for(MobilyDataItem* entry in _entries) { + CGSize entrySize = [entry sizeForAvailableSize:CGSizeMake(availableWidth, restriction.height)]; + if((entrySize.width >= 0.0f) && (entrySize.height >= 0.0f) && (entry.hidden == NO)) { + entry.updateFrame = CGRectMake(offset.x, offset.y, entrySize.width, restriction.height); + cumulative.width += entrySize.width + _spacing.horizontal; + offset.x += entrySize.width + _spacing.horizontal; + } + } + if(cumulative.width > MOBILY_EPSILON) { + cumulative.width -= _spacing.horizontal; + } + } else { + for(MobilyDataItem* entry in _entries) { + CGSize entrySize = [entry sizeForAvailableSize:CGSizeMake(availableWidth, restriction.height)]; + if((entrySize.width >= 0.0f) && (entrySize.height >= 0.0f) && (entry.hidden == NO)) { + cumulative.width += entrySize.width + _spacing.horizontal; + } + } + if(frame.size.width > cumulative.width) { + cumulative.width = frame.size.width; + } else if(cumulative.width > MOBILY_EPSILON) { + cumulative.width -= _spacing.horizontal; + } + offset.y += cumulative.width; + [_entries moEach:^(MobilyDataItem* entry) { + CGSize entrySize = [entry sizeForAvailableSize:CGSizeMake(availableWidth, restriction.height)]; + if((entrySize.width >= 0.0f) && (entrySize.height >= 0.0f) && (entry.hidden == NO)) { + entry.updateFrame = CGRectMake(offset.x - entrySize.width, offset.y, entrySize.width, restriction.height); + offset.x -= entrySize.width + _spacing.horizontal; + } + } options:NSEnumerationReverse]; + } + break; + } + } + return CGRectMake(frame.origin.x, frame.origin.y, _margin.left + cumulative.width + _margin.right, _margin.top + cumulative.height + _margin.bottom); +} + +- (void)_willEntriesLayoutForBounds:(CGRect)bounds { + switch(_orientation) { + case MobilyDataContainerOrientationVertical: { + CGFloat boundsBefore = bounds.origin.y; + CGFloat boundsAfter = bounds.origin.y + bounds.size.height; + CGFloat entriesBefore = _frame.origin.y; + CGFloat entriesAfter = _frame.origin.y + _frame.size.height; + if((_header != nil) && (_header.hidden == NO)) { + CGRect headerFrame = _header.updateFrame; + headerFrame.origin.y = boundsBefore; + if((_footer != nil) && (_footer.hidden == NO)) { + CGRect footerFrame = _footer.updateFrame; + headerFrame.origin.y = MIN(headerFrame.origin.y, (boundsAfter - (_spacing.vertical + footerFrame.size.height)) - headerFrame.size.height); + } else { + headerFrame.origin.y = MIN(headerFrame.origin.y, boundsAfter - headerFrame.size.height); + } + headerFrame.origin.y = MAX(entriesBefore, MIN(headerFrame.origin.y, entriesAfter - headerFrame.size.height)); + _header.displayFrame = headerFrame; + } + if((_footer != nil) && (_footer.hidden == NO)) { + CGRect footerFrame = _footer.updateFrame; + footerFrame.origin.y = boundsAfter - footerFrame.size.height; + if((_header != nil) && (_header.hidden == NO)) { + CGRect headerFrame = _header.updateFrame; + footerFrame.origin.y = MAX(footerFrame.origin.y, (boundsBefore + _spacing.vertical) + headerFrame.size.height); + } else { + footerFrame.origin.y = MAX(footerFrame.origin.y, boundsBefore); + } + footerFrame.origin.y = MAX(entriesBefore, MIN(footerFrame.origin.y, entriesAfter - footerFrame.size.height)); + _footer.displayFrame = footerFrame; + } + break; + } + case MobilyDataContainerOrientationHorizontal: { + CGFloat boundsBefore = bounds.origin.x; + CGFloat boundsAfter = bounds.origin.x + bounds.size.width; + CGFloat entriesBefore = _frame.origin.x; + CGFloat entriesAfter = _frame.origin.x + _frame.size.width; + if((_header != nil) && (_header.hidden == NO)) { + CGRect headerFrame = _header.updateFrame; + headerFrame.origin.x = boundsBefore; + if((_footer != nil) && (_footer.hidden == NO)) { + CGRect footerFrame = _footer.updateFrame; + headerFrame.origin.x = MIN(headerFrame.origin.x, (boundsAfter - (_spacing.horizontal + footerFrame.size.width)) - headerFrame.size.width); + } else { + headerFrame.origin.x = MIN(headerFrame.origin.x, boundsAfter - headerFrame.size.width); + } + headerFrame.origin.x = MAX(entriesBefore, MIN(headerFrame.origin.x, entriesAfter - headerFrame.size.width)); + _header.displayFrame = headerFrame; + } + if((_footer != nil) && (_footer.hidden == NO)) { + CGRect footerFrame = _footer.updateFrame; + footerFrame.origin.x = boundsAfter - footerFrame.size.width; + if((_header != nil) && (_header.hidden == NO)) { + CGRect headerFrame = _header.updateFrame; + footerFrame.origin.x = MAX(footerFrame.origin.x, (boundsBefore + _spacing.horizontal) + headerFrame.size.width); + } else { + footerFrame.origin.x = MAX(footerFrame.origin.x, boundsBefore); + } + footerFrame.origin.x = MAX(entriesBefore, MIN(footerFrame.origin.x, entriesAfter - footerFrame.size.width)); + _footer.displayFrame = footerFrame; + } + break; + } + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataContainerSections.m b/Sources/MobilyCore/MobilyDataContainerSections.m new file mode 100644 index 0000000..1a5f12a --- /dev/null +++ b/Sources/MobilyCore/MobilyDataContainerSections.m @@ -0,0 +1,309 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyDataContainerSections + +#pragma mark Synthesize + +@synthesize sections = _sections; + +#pragma mark Init / Free + +- (void)setup { + [super setup]; + + _sections = NSMutableArray.array; +} + +#pragma mark Private propert private + +- (void)_willChangeView { +} + +- (void)_didChangeView { + for(MobilyDataContainer* section in _sections) { + section.view = _view; + } +} + +#pragma mark Private override + +- (void)_didBeginUpdateAnimated:(BOOL)animated { + [super _didBeginUpdateAnimated:animated]; + for(MobilyDataContainer* section in _sections) { + [section _didBeginUpdateAnimated:animated]; + } +} + +- (void)_didEndUpdateAnimated:(BOOL)animated { + for(MobilyDataContainer* section in _sections) { + [section _didEndUpdateAnimated:animated]; + } + [super _didEndUpdateAnimated:animated]; +} + +- (CGRect)_validateLayoutForAvailableFrame:(CGRect)frame { + _frame = [self _validateSectionsForAvailableFrame:frame]; + return _frame; +} + +- (void)_willLayoutForBounds:(CGRect)bounds { + CGRect intersect = CGRectIntersection(bounds, _frame); + if(CGRectIsEmpty(intersect) == NO) { + [self _willSectionsLayoutForBounds:intersect]; + } +} + +- (void)_didLayoutForBounds:(CGRect)bounds { + CGRect intersect = CGRectIntersection(bounds, _frame); + if(CGRectIsEmpty(intersect) == NO) { + [self _didSectionsLayoutForBounds:intersect]; + } +} + +#pragma mark Public override + +- (NSArray*)allItems { + NSMutableArray* result = NSMutableArray.array; + for(MobilyDataContainer* section in _sections) { + [result addObjectsFromArray:section.allItems]; + } + return result; +} + +- (MobilyDataItem*)itemForPoint:(CGPoint)point { + for(MobilyDataContainer* section in _sections) { + MobilyDataItem* item = [section itemForPoint:point]; + if(item != nil) { + return item; + } + } + return nil; +} + +- (MobilyDataItem*)itemForData:(id)data { + for(MobilyDataContainer* section in _sections) { + MobilyDataItem* item = [section itemForData:data]; + if(item != nil) { + return item; + } + } + return nil; +} + +#pragma mark Public + +- (void)prependSection:(MobilyDataContainer*)section { + section.parent = self; + [_sections insertObject:section atIndex:0]; + if(_view != nil) { + [_view _didInsertItems:section.allItems]; + } +} + +- (void)appendSection:(MobilyDataContainer*)section { + section.parent = self; + [_sections addObject:section]; + if(_view != nil) { + [_view _didInsertItems:section.allItems]; + } +} + +- (void)insertSection:(MobilyDataContainer*)section atIndex:(NSUInteger)index { + section.parent = self; + [_sections insertObject:section atIndex:index]; + if(_view != nil) { + [_view _didInsertItems:section.allItems]; + } +} + +- (void)replaceOriginSection:(MobilyDataContainer*)originSection withSection:(MobilyDataContainer*)section { + NSUInteger index = [_sections indexOfObject:originSection]; + if(index != NSNotFound) { + section.parent = self; + _sections[index] = section; + if(_view != nil) { + [_view _didReplaceOriginItems:originSection.allItems withItems:section.allItems]; + } + } +} + +- (void)deleteSection:(MobilyDataContainer*)section { + [_sections removeObject:section]; + if(_view != nil) { + [_view _didDeleteItems:section.allItems]; + } +} + +- (void)deleteAllSections { + if(_view != nil) { + NSArray* allItems = self.allItems; + [_sections removeAllObjects]; + [_view _didDeleteItems:allItems]; + } else { + [_sections removeAllObjects]; + } +} + +- (void)scrollToSection:(MobilyDataContainer*)section scrollPosition:(MobilyDataViewPosition)scrollPosition animated:(BOOL)animated { + [_view scrollToRect:section.frame scrollPosition:scrollPosition animated:animated]; +} + +#pragma mark Private override + +- (CGPoint)_alignWithVelocity:(CGPoint)velocity contentOffset:(CGPoint)contentOffset contentSize:(CGSize)contentSize visibleSize:(CGSize)visibleSize { + if((_allowAutoAlign == YES) && (_hidden == NO)) { + CGPoint alingPoint = [self _alignPointWithContentOffset:contentOffset contentSize:contentSize visibleSize:visibleSize]; + if(CGRectContainsPoint(_frame, alingPoint) == YES) { + for(MobilyDataContainer* section in _sections) { + if(section.allowAutoAlign == YES) { + CGPoint alingSectionCorner = CGPointZero; + if((_alignPosition & MobilyDataContainerAlignLeft) != 0) { + alingSectionCorner.x = CGRectGetMinX(section.frame); + } else if((_alignPosition & MobilyDataContainerAlignCenteredHorizontally) != 0) { + alingSectionCorner.x = CGRectGetMidX(section.frame); + } else if((_alignPosition & MobilyDataContainerAlignRight) != 0) { + alingSectionCorner.x = CGRectGetMaxX(section.frame); + } else { + alingSectionCorner.x = alingPoint.x; + } + if((_alignPosition & MobilyDataContainerAlignTop) != 0) { + alingSectionCorner.y = CGRectGetMinY(section.frame); + } else if((_alignPosition & MobilyDataContainerAlignCenteredVertically) != 0) { + alingSectionCorner.y = CGRectGetMidY(section.frame); + } else if((_alignPosition & MobilyDataContainerAlignBottom) != 0) { + alingSectionCorner.y = CGRectGetMaxY(section.frame); + } else { + alingSectionCorner.y = alingPoint.y; + } + CGFloat dx = alingPoint.x - alingSectionCorner.x; + CGFloat dy = alingPoint.y - alingSectionCorner.y; + if((MOBILY_FABS(alingSectionCorner.x - contentOffset.x) > MOBILY_EPSILON) && (MOBILY_FABS(dx) <= _alignThreshold.horizontal)) { + contentOffset.x -= dx; + alingPoint.x -= dx; + } + if((MOBILY_FABS(alingSectionCorner.y - contentOffset.y) > MOBILY_EPSILON) && (MOBILY_FABS(dy) <= _alignThreshold.vertical)) { + contentOffset.y -= dy; + alingPoint.y -= dy; + } + } + } + contentOffset.x = MAX(0.0f, MIN(contentOffset.x, contentSize.width - visibleSize.width)); + contentOffset.y = MAX(0.0f, MIN(contentOffset.y, contentSize.height - visibleSize.height)); + } + } + if(CGRectContainsPoint(_frame, contentOffset) == YES) { + for(MobilyDataContainer* section in _sections) { + contentOffset = [section _alignWithVelocity:velocity contentOffset:contentOffset contentSize:contentSize visibleSize:visibleSize]; + } + } + return contentOffset; +} + +- (CGRect)_validateSectionsForAvailableFrame:(CGRect __unused)frame { + return CGRectNull; +} + +- (void)_willSectionsLayoutForBounds:(CGRect)bounds { + for(MobilyDataContainer* section in _sections) { + [section _willLayoutForBounds:bounds]; + } +} + +- (void)_didSectionsLayoutForBounds:(CGRect)bounds { + for(MobilyDataContainer* section in _sections) { + [section _didLayoutForBounds:bounds]; + } +} + +#pragma mark MobilySearchBarDelegate + +- (void)searchBarBeginSearch:(MobilySearchBar*)searchBar { + for(MobilyDataContainer* section in _sections) { + [section searchBarBeginSearch:searchBar]; + } +} + +- (void)searchBarEndSearch:(MobilySearchBar*)searchBar { + for(MobilyDataContainer* section in _sections) { + [section searchBarEndSearch:searchBar]; + } +} + +- (void)searchBarBeginEditing:(MobilySearchBar*)searchBar { + for(MobilyDataContainer* section in _sections) { + [section searchBarBeginEditing:searchBar]; + } +} + +- (void)searchBar:(MobilySearchBar*)searchBar textChanged:(NSString*)textChanged { + for(MobilyDataContainer* section in _sections) { + [section searchBar:searchBar textChanged:textChanged]; + } +} + +- (void)searchBarEndEditing:(MobilySearchBar*)searchBar { + for(MobilyDataContainer* section in _sections) { + [section searchBarEndEditing:searchBar]; + } +} + +- (void)searchBarPressedClear:(MobilySearchBar*)searchBar { + for(MobilyDataContainer* section in _sections) { + [section searchBarPressedClear:searchBar]; + } +} + +- (void)searchBarPressedReturn:(MobilySearchBar*)searchBar { + for(MobilyDataContainer* section in _sections) { + [section searchBarPressedReturn:searchBar]; + } +} + +- (void)searchBarPressedCancel:(MobilySearchBar*)searchBar { + for(MobilyDataContainer* section in _sections) { + [section searchBarPressedCancel:searchBar]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataContainerSectionsList.m b/Sources/MobilyCore/MobilyDataContainerSectionsList.m new file mode 100644 index 0000000..69bd7b6 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataContainerSectionsList.m @@ -0,0 +1,251 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyDataContainerSectionsList + +#pragma mark Synthesize + +@synthesize orientation = _orientation; +@synthesize margin = _margin; +@synthesize spacing = _spacing; +@synthesize pagingEnabled = _pagingEnabled; +@synthesize currentSection = _currentSection; + +#pragma mark Init / Free + ++ (instancetype)containerWithOrientation:(MobilyDataContainerOrientation)orientation { + return [[self alloc] initWithOrientation:orientation]; +} + +- (instancetype)initWithOrientation:(MobilyDataContainerOrientation)orientation { + self = [super init]; + if(self != nil) { + _orientation = orientation; + } + return self; +} + +- (void)setup { + [super setup]; + + _margin = UIEdgeInsetsZero; + _spacing = UIOffsetZero; +} + +#pragma mark Property + +- (void)setAllowAutoAlign:(BOOL)allowAutoAlign { + if(_allowAutoAlign != allowAutoAlign) { + [super setAllowAutoAlign:allowAutoAlign]; + if(_pagingEnabled == YES) { + self.pagingEnabled = NO; + } + } +} + +- (void)setOrientation:(MobilyDataContainerOrientation)orientation { + if(_orientation != orientation) { + _orientation = orientation; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setMargin:(UIEdgeInsets)margin { + if(UIEdgeInsetsEqualToEdgeInsets(_margin, margin) == NO) { + _margin = margin; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setSpacing:(UIOffset)spacing { + if(UIOffsetEqualToOffset(_spacing, spacing) == NO) { + _spacing = spacing; + if(_view != nil) { + [_view setNeedValidateLayout]; + } + } +} + +- (void)setPagingEnabled:(BOOL)pagingEnabled { + if(_pagingEnabled != pagingEnabled) { + if(_pagingEnabled == YES) { + _currentSection = nil; + } + _pagingEnabled = pagingEnabled; + _allowAutoAlign = _pagingEnabled; + if(_pagingEnabled == YES) { + [self align]; + } + } +} + +- (void)setCurrentSectionIndex:(NSUInteger)currentSectionIndex { + [self setCurrentSection:_sections[currentSectionIndex] animated:NO]; +} + +- (void)setCurrentSectionIndex:(NSUInteger)currentSectionIndex animated:(BOOL)animated { + [self setCurrentSection:_sections[currentSectionIndex] animated:animated]; +} + +- (NSUInteger)currentSectionIndex { + return [_sections indexOfObjectIdenticalTo:_currentSection]; +} + +- (void)setCurrentSection:(MobilyDataContainer*)currentSection { + [self setCurrentSection:currentSection animated:NO]; +} + +- (void)setCurrentSection:(MobilyDataContainer*)currentSection animated:(BOOL)animated { + if(_currentSection != currentSection) { + _currentSection = currentSection; + if((_pagingEnabled == YES) && (_currentSection != nil)) { + [self scrollToSection:_currentSection scrollPosition:(MobilyDataViewPosition)_alignPosition animated:animated]; + } + } +} + +#pragma mark Public override + +- (void)replaceOriginSection:(MobilyDataContainer*)originSection withSection:(MobilyDataContainer*)section { + if((_pagingEnabled == YES) && (_currentSection == originSection)) { + _currentSection = section; + } + [super replaceOriginSection:originSection withSection:section]; +} + +- (void)deleteSection:(MobilyDataContainer*)section { + if((_pagingEnabled == YES) && (_currentSection == section)) { + _currentSection = [_sections moNextObjectOfObject:_currentSection]; + } + [super deleteSection:section]; +} + +- (void)deleteAllSections { + if(_pagingEnabled == YES) { + _currentSection = nil; + } + [super deleteAllSections]; +} + +#pragma mark Private override + +- (void)_didEndDraggingWillDecelerate:(BOOL __unused)decelerate { + [super _didEndDraggingWillDecelerate:decelerate]; + + if((_pagingEnabled == YES) && (decelerate == NO)) { + CGPoint alignPoint = [self alignPoint]; + for(MobilyDataContainer* section in _sections) { + if(CGRectContainsPoint(section.frame, alignPoint) == YES) { + _currentSection = section; + [self fireEventForKey:MobilyDataContainerCurrentSectionChanged byObject:_currentSection]; + break; + } + } + } +} + +- (void)_didEndDecelerating { + [super _didEndDecelerating]; + + if(_pagingEnabled == YES) { + CGPoint alignPoint = [self alignPoint]; + for(MobilyDataContainer* section in _sections) { + if(CGRectContainsPoint(section.frame, alignPoint) == YES) { + _currentSection = section; + [self fireEventForKey:MobilyDataContainerCurrentSectionChanged byObject:_currentSection]; + break; + } + } + } +} + +- (void)_didEndUpdateAnimated:(BOOL)animated { + [super _didEndUpdateAnimated:animated]; + + if((_pagingEnabled == YES) && (_currentSection != nil)) { + [self scrollToSection:_currentSection scrollPosition:(MobilyDataViewPosition)_alignPosition animated:animated]; + } +} + +- (CGRect)_validateSectionsForAvailableFrame:(CGRect)frame { + CGPoint offset = CGPointMake(frame.origin.x + _margin.left, frame.origin.y + _margin.top); + CGSize restriction = CGSizeMake(frame.size.width - (_margin.left + _margin.right), frame.size.height - (_margin.left + _margin.right)); + CGSize cumulative = CGSizeZero; + switch(_orientation) { + case MobilyDataContainerOrientationVertical: { + for(MobilyDataContainer* container in _sections) { + CGRect containerFrame = [container _validateLayoutForAvailableFrame:CGRectMake(offset.x, offset.y, restriction.width, restriction.height)]; + if((CGRectIsNull(containerFrame) == NO) && (container.hidden == NO)) { + offset.y = (containerFrame.origin.y + containerFrame.size.height) + _spacing.vertical; + cumulative.width = MAX(containerFrame.size.width, restriction.width); + cumulative.height += containerFrame.size.height + _spacing.vertical; + } + } + cumulative.height -= _spacing.vertical; + break; + } + case MobilyDataContainerOrientationHorizontal: { + for(MobilyDataContainer* container in _sections) { + CGRect containerFrame = [container _validateLayoutForAvailableFrame:CGRectMake(offset.x, offset.y, restriction.width, restriction.height)]; + if((CGRectIsNull(containerFrame) == NO) && (container.hidden == NO)) { + offset.x = (containerFrame.origin.x + containerFrame.size.width) + _spacing.horizontal; + cumulative.width += containerFrame.size.width + _spacing.horizontal; + cumulative.height = MAX(containerFrame.size.height, restriction.height); + } + } + cumulative.width -= _spacing.horizontal; + break; + } + } + return CGRectMake(frame.origin.x, frame.origin.y, _margin.left + cumulative.width + _margin.right, _margin.top + cumulative.height + _margin.bottom); +} + +@end + +/*--------------------------------------------------*/ + +NSString* MobilyDataContainerCurrentSectionChanged = @"MobilyDataContainerCurrentSectionChanged"; + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataItem+Private.h b/Sources/MobilyCore/MobilyDataItem+Private.h new file mode 100644 index 0000000..46e822b --- /dev/null +++ b/Sources/MobilyCore/MobilyDataItem+Private.h @@ -0,0 +1,136 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyDataItem () { +@protected + __weak MobilyDataView* _view; + __weak MobilyDataContainer* _parent; + NSString* _identifier; + NSUInteger _order; + id _data; + CGSize _size; + BOOL _needUpdateSize; + CGRect _originFrame; + CGRect _updateFrame; + CGRect _displayFrame; + CGRect _frame; + BOOL _hidden; + BOOL _allowsAlign; + BOOL _allowsSelection; + BOOL _allowsHighlighting; + BOOL _allowsEditing; + BOOL _selected; + BOOL _highlighted; + BOOL _editing; + MobilyDataCell* _cell; +} + +@property(nonatomic, readwrite, weak) MobilyDataView* view; +@property(nonatomic, readwrite, weak) MobilyDataContainer* parent; +@property(nonatomic, readwrite, strong) NSString* identifier; +@property(nonatomic, readwrite, assign) CGSize size; +@property(nonatomic, readwrite, assign) BOOL needUpdateSize; +@property(nonatomic, readwrite, strong) MobilyDataCell* cell; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataItemCalendar () { +@protected + __weak NSCalendar* _calendar; +} + +- (instancetype)initWithIdentifier:(NSString*)identifier order:(NSUInteger)order calendar:(NSCalendar*)calendar data:(id)data; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataItemCalendarMonth () { +@protected + NSDate* _beginDate; + NSDate* _endDate; + NSDate* _displayBeginDate; + NSDate* _displayEndDate; +} + ++ (instancetype)itemWithCalendar:(NSCalendar*)calendar beginDate:(NSDate*)beginDate endDate:(NSDate*)endDate displayBeginDate:(NSDate*)displayBeginDate displayEndDate:(NSDate*)displayEndDate data:(id)data; + +- (instancetype)initWithCalendar:(NSCalendar*)calendar beginDate:(NSDate*)beginDate endDate:(NSDate*)endDate displayBeginDate:(NSDate*)displayBeginDate displayEndDate:(NSDate*)displayEndDate data:(id)data; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataItemCalendarWeekday () { +@protected + __weak MobilyDataItemCalendarMonth* _monthItem; + NSDate* _date; +} + ++ (instancetype)itemWithCalendar:(NSCalendar*)calendar date:(NSDate*)date data:(id)data; ++ (instancetype)itemWithMonthItem:(MobilyDataItemCalendarMonth*)monthItem date:(NSDate*)date data:(id)data; + +- (instancetype)initWithCalendar:(NSCalendar*)calendar date:(NSDate*)date data:(id)data; +- (instancetype)initWithMonthItem:(MobilyDataItemCalendarMonth*)monthItem date:(NSDate*)date data:(id)data; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataItemCalendarDay () { +@protected + __weak MobilyDataItemCalendarMonth* _monthItem; + __weak MobilyDataItemCalendarWeekday* _weekdayItem; + NSDate* _date; +} + ++ (instancetype)itemWithCalendar:(NSCalendar*)calendar date:(NSDate*)date data:(id)data; ++ (instancetype)itemWithWeekdayItem:(MobilyDataItemCalendarWeekday*)weekdayItem date:(NSDate*)date data:(id)data; + +- (instancetype)initWithCalendar:(NSCalendar*)calendar date:(NSDate*)date data:(id)data; +- (instancetype)initWithWeekdayItem:(MobilyDataItemCalendarWeekday*)weekdayItem date:(NSDate*)date data:(id)data; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataItem.h b/Sources/MobilyCore/MobilyDataItem.h new file mode 100644 index 0000000..0e1626a --- /dev/null +++ b/Sources/MobilyCore/MobilyDataItem.h @@ -0,0 +1,143 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@class MobilyDataView; +@class MobilyDataContainer; +@class MobilyDataCell; + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyDataItem : NSObject< MobilyObject, NSCopying, MobilySearchBarDelegate > + +@property(nonatomic, readonly, weak) MobilyDataView* view; +@property(nonatomic, readonly, weak) MobilyDataContainer* parent; +@property(nonatomic, readonly, strong) NSString* identifier; +@property(nonatomic, readonly, assign) NSUInteger order; +@property(nonatomic, readwrite, strong) id data; +@property(nonatomic, readwrite, assign) CGRect originFrame; +@property(nonatomic, readwrite, assign) CGRect updateFrame; +@property(nonatomic, readwrite, assign) CGRect displayFrame; +@property(nonatomic, readonly, assign) CGRect frame; +@property(nonatomic, readwrite, assign, getter=isHidden) BOOL hidden; +@property(nonatomic, readonly, assign, getter=isHiddenInHierarchy) BOOL hiddenInHierarchy; +@property(nonatomic, readwrite, assign) BOOL allowsAlign; +@property(nonatomic, readwrite, assign) BOOL allowsSelection; +@property(nonatomic, readwrite, assign) BOOL allowsHighlighting; +@property(nonatomic, readwrite, assign) BOOL allowsEditing; +@property(nonatomic, readwrite, assign, getter=isSelected) BOOL selected; +@property(nonatomic, readwrite, assign, getter=isHighlighted) BOOL highlighted; +@property(nonatomic, readwrite, assign, getter=isEditing) BOOL editing; +@property(nonatomic, readonly, strong) MobilyDataCell* cell; + ++ (instancetype)itemWithDataItem:(MobilyDataItem*)dataItem; ++ (instancetype)itemWithIdentifier:(NSString*)identifier order:(NSUInteger)order data:(id)data; ++ (NSArray*)dataItemsWithIdentifier:(NSString*)identifier order:(NSUInteger)order dataArray:(NSArray*)dataArray; + +- (instancetype)initWithDataItem:(MobilyDataItem*)dataItem; +- (instancetype)initWithIdentifier:(NSString*)identifier order:(NSUInteger)order data:(id)data; + +- (void)setup NS_REQUIRES_SUPER; + +- (BOOL)containsEventForKey:(id)key; +- (BOOL)containsEventForIdentifier:(NSString*)identifier forKey:(id)key; + +- (void)fireEventForKey:(id)key byObject:(id)object; +- (id)fireEventForKey:(id)key byObject:(id)object orDefault:(id)orDefault; +- (void)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object; +- (id)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault; + +- (void)didBeginUpdateAnimated:(BOOL)animated; +- (void)didEndUpdateAnimated:(BOOL)animated; + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated NS_REQUIRES_SUPER; +- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated NS_REQUIRES_SUPER; +- (void)setEditing:(BOOL)editing animated:(BOOL)animated NS_REQUIRES_SUPER; + +- (void)setNeedUpdateSize; +- (CGSize)sizeForAvailableSize:(CGSize)size; + +- (void)setNeedUpdateCell; + +- (void)appear; +- (void)disappear; +- (void)validateLayoutForBounds:(CGRect)bounds; +- (void)invalidateLayoutForBounds:(CGRect)bounds; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataItemCalendar : MobilyDataItem + +@property(nonatomic, readonly, weak) NSCalendar* calendar; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataItemCalendarMonth : MobilyDataItemCalendar + +@property(nonatomic, readonly, strong) NSDate* beginDate; +@property(nonatomic, readonly, strong) NSDate* endDate; +@property(nonatomic, readonly, strong) NSDate* displayBeginDate; +@property(nonatomic, readonly, strong) NSDate* displayEndDate; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataItemCalendarWeekday : MobilyDataItemCalendar + +@property(nonatomic, readonly, weak) MobilyDataItemCalendarMonth* monthItem; +@property(nonatomic, readonly, strong) NSDate* date; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataItemCalendarDay : MobilyDataItemCalendar + +@property(nonatomic, readonly, weak) MobilyDataItemCalendarMonth* monthItem; +@property(nonatomic, readonly, weak) MobilyDataItemCalendarWeekday* weekdayItem; +@property(nonatomic, readonly, strong) NSDate* date; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataItem.m b/Sources/MobilyCore/MobilyDataItem.m new file mode 100644 index 0000000..7d3ba77 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataItem.m @@ -0,0 +1,552 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyDataItem + +#pragma mark Synthesize + +@synthesize view = _view; +@synthesize parent = _parent; +@synthesize identifier = _identifier; +@synthesize data = _data; +@synthesize size = _size; +@synthesize needUpdateSize = _needUpdateSize; +@synthesize originFrame = _originFrame; +@synthesize updateFrame = _updateFrame; +@synthesize displayFrame = _displayFrame; +@synthesize order = _order; +@synthesize hidden = _hidden; +@synthesize allowsAlign = _allowsAlign; +@synthesize allowsSelection = _allowsSelection; +@synthesize allowsHighlighting = _allowsHighlighting; +@synthesize allowsEditing = _allowsEditing; +@synthesize selected = _selected; +@synthesize highlighted = _highlighted; +@synthesize editing = _editing; +@synthesize cell = _cell; + +#pragma mark Init / Free + ++ (instancetype)itemWithDataItem:(MobilyDataItem*)dataItem { + return [[self alloc] initWithDataItem:dataItem]; +} + ++ (instancetype)itemWithIdentifier:(NSString*)identifier order:(NSUInteger)order data:(id)data { + return [[self alloc] initWithIdentifier:identifier order:order data:data]; +} + ++ (NSArray*)dataItemsWithIdentifier:(NSString*)identifier order:(NSUInteger)order dataArray:(NSArray*)dataArray { + NSMutableArray* items = [NSMutableArray arrayWithCapacity:dataArray.count]; + for(id data in dataArray) { + [items addObject:[self itemWithIdentifier:identifier order:order data:data]]; + } + return items; +} + +- (instancetype)initWithDataItem:(MobilyDataItem*)dataItem { + self = [super init]; + if(self != nil) { + _identifier = dataItem.identifier; + _order = dataItem.order; + _data = dataItem.data; + _size = dataItem.size; + _needUpdateSize = dataItem.needUpdateSize; + _originFrame = dataItem.originFrame; + _updateFrame = dataItem.updateFrame; + _displayFrame = dataItem.displayFrame; + _hidden = dataItem.hidden; + _allowsSelection = dataItem.allowsSelection; + _allowsHighlighting = dataItem.allowsHighlighting; + _allowsEditing = dataItem.allowsEditing; + _needUpdateSize = YES; + + [self setup]; + } + return self; +} + +- (instancetype)initWithIdentifier:(NSString*)identifier order:(NSUInteger)order data:(id)data { + self = [super init]; + if(self != nil) { + _identifier = identifier; + _order = order; + _data = data; + _size = CGSizeZero; + _needUpdateSize = YES; + _originFrame = CGRectNull; + _updateFrame = CGRectNull; + _displayFrame = CGRectNull; + _allowsSelection = YES; + _allowsHighlighting = YES; + _allowsEditing = YES; + + [self setup]; + } + return self; +} + +- (void)setup { +} + +- (void)dealloc { +} + +#pragma mark NSCopying + +- (id)copy { + return [self copyWithZone:NSDefaultMallocZone()]; +} + +- (id)copyWithZone:(NSZone*)zone { + return [[self.class allocWithZone:zone] initWithDataItem:self]; +} + +#pragma mark Property + +- (void)setParent:(MobilyDataContainer*)parent { + if(_parent != parent) { + _parent = parent; + if(_parent != nil) { + self.view = parent.view; + } else { + self.view = nil; + } + } +} + +- (void)setCell:(MobilyDataCell*)cell { + if(_cell != cell) { + if(_cell != nil) { + [UIView performWithoutAnimation:^{ + _cell.item = nil; + }]; + } + _cell = cell; + if(_cell != nil) { + [UIView performWithoutAnimation:^{ + _cell.frame = self.frame; + _cell.selected = _selected; + _cell.highlighted = _highlighted; + _cell.editing = _editing; + _cell.item = self; + [_cell layoutIfNeeded]; + }]; + } + } +} + +- (CGRect)originFrame { + [_view validateLayoutIfNeed]; + return _originFrame; +} + +- (void)setUpdateFrame:(CGRect)updateFrame { + if(CGRectEqualToRect(_updateFrame, updateFrame) == NO) { + _updateFrame = updateFrame; + if(CGRectIsNull(_originFrame) == YES) { + _originFrame = _updateFrame; + } + if((_cell != nil) && ((CGRectIsNull(_updateFrame) == NO) && (CGRectIsNull(_displayFrame) == YES))) { + _cell.frame = _updateFrame; + } + } +} + +- (CGRect)updateFrame { + [_view validateLayoutIfNeed]; + return _updateFrame; +} + +- (void)setDisplayFrame:(CGRect)displayFrame { + if(CGRectEqualToRect(_displayFrame, displayFrame) == NO) { + _displayFrame = displayFrame; + if((_cell != nil) && (CGRectIsNull(_displayFrame) == NO)) { + _cell.frame = _displayFrame; + } + } +} + +- (CGRect)displayFrame { + [_view validateLayoutIfNeed]; + if(CGRectIsNull(_displayFrame) == YES) { + return _updateFrame; + } + return _displayFrame; +} + +- (CGRect)frame { + [_view validateLayoutIfNeed]; + if(CGRectIsNull(_displayFrame) == NO) { + return _displayFrame; + } else if(CGRectIsNull(_updateFrame) == NO) { + return _updateFrame; + } + return _originFrame; +} + +- (void)setHidden:(BOOL)hidden { + if(_hidden != hidden) { + _hidden = hidden; + [_view setNeedValidateLayout]; + } +} + +- (BOOL)isHiddenInHierarchy { + if(_hidden == YES) { + return YES; + } + return (_parent != nil) ? _parent.hiddenInHierarchy : NO; +} + +- (void)setSelected:(BOOL)selected { + [self setSelected:selected animated:NO]; +} + +- (void)setHighlighted:(BOOL)highlighted { + [self setHighlighted:highlighted animated:NO]; +} + +- (void)setEditing:(BOOL)editing { + [self setEditing:editing animated:NO]; +} + +#pragma mark Public + +- (BOOL)containsEventForKey:(id)key { + return [_view containsEventForKey:key]; +} + +- (BOOL)containsEventForIdentifier:(NSString*)identifier forKey:(id)key { + return [_view containsEventForIdentifier:identifier forKey:key]; +} + +- (void)fireEventForKey:(id)key byObject:(id)object { + [_view fireEventForIdentifier:_identifier forKey:key bySender:self byObject:object]; +} + +- (id)fireEventForKey:(id)key byObject:(id)object orDefault:(id)orDefault { + return [_view fireEventForIdentifier:_identifier forKey:key bySender:self byObject:object orDefault:orDefault]; +} + +- (void)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object { + [_view fireEventForIdentifier:_identifier forKey:key bySender:sender byObject:object]; +} + +- (id)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault { + return [_view fireEventForIdentifier:_identifier forKey:key bySender:sender byObject:object orDefault:orDefault]; +} + +- (void)didBeginUpdateAnimated:(BOOL __unused)animated { +} + +- (void)didEndUpdateAnimated:(BOOL __unused)animated { + self.originFrame = _updateFrame; + if(_cell != nil) { + _cell.frame = self.frame; + } +} + +- (void)setSelected:(BOOL)selected animated:(BOOL)animated { + if(_selected != selected) { + _selected = selected; + if(_cell != nil) { + if(_selected == YES) { + [_view selectItem:self animated:animated]; + } else { + [_view deselectItem:self animated:animated]; + } + } + if(_cell != nil) { + [_cell setSelected:_selected animated:animated]; + } + } +} + +- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated { + if(_highlighted != highlighted) { + _highlighted = highlighted; + if(_cell != nil) { + if(_highlighted == YES) { + [_view highlightItem:self animated:animated]; + } else { + [_view unhighlightItem:self animated:animated]; + } + } + if(_cell != nil) { + [_cell setHighlighted:_highlighted animated:animated]; + } + } +} + +- (void)setEditing:(BOOL)editing animated:(BOOL)animated { + if(_editing != editing) { + _editing = editing; + if(_cell != nil) { + if(_editing == YES) { + [_view beganEditItem:self animated:animated]; + } else { + [_view endedEditItem:self animated:animated]; + } + [_cell setEditing:_editing animated:animated]; + } + } +} + +- (void)setNeedUpdateSize { + if(_needUpdateSize == NO) { + _needUpdateSize = YES; + [_view setNeedValidateLayout]; + } +} + +- (CGSize)sizeForAvailableSize:(CGSize)size { + if(_needUpdateSize == YES) { + _needUpdateSize = NO; + + Class cellClass = [_view cellClassWithItem:self]; + if(cellClass != nil) { + _size = [cellClass sizeForItem:self availableSize:size]; + } + } + return _size; +} + +- (void)setNeedUpdateCell { + if(_cell != nil) { + MobilyDataCell* cell = _cell; + self.cell = nil; + self.cell = cell; + } +} + +- (void)appear { + [_view _appearItem:self]; +} + +- (void)disappear { + [_view _disappearItem:self]; +} + +- (void)validateLayoutForBounds:(CGRect)bounds { + if(_cell == nil) { + if((CGRectIntersectsRect(bounds, CGRectUnion(_originFrame, self.frame)) == YES) && (self.hiddenInHierarchy == NO)) { + [self appear]; + } + } else { + [_cell validateLayoutForBounds:bounds]; + } +} + +- (void)invalidateLayoutForBounds:(CGRect)bounds { + if(_cell != nil) { + if((CGRectIntersectsRect(bounds, self.frame) == NO) || (self.hiddenInHierarchy == YES)) { + [self disappear]; + } else { + [_cell invalidateLayoutForBounds:bounds]; + } + } +} + +#pragma mark MobilySearchBarDelegate + +- (void)searchBarBeginSearch:(MobilySearchBar*)searchBar { + [_cell searchBarBeginSearch:searchBar]; +} + +- (void)searchBarEndSearch:(MobilySearchBar*)searchBar { + [_cell searchBarEndSearch:searchBar]; +} + +- (void)searchBarBeginEditing:(MobilySearchBar*)searchBar { + [_cell searchBarBeginEditing:searchBar]; +} + +- (void)searchBar:(MobilySearchBar*)searchBar textChanged:(NSString*)textChanged { + [_cell searchBar:searchBar textChanged:textChanged]; +} + +- (void)searchBarEndEditing:(MobilySearchBar*)searchBar { + [_cell searchBarEndEditing:searchBar]; +} + +- (void)searchBarPressedClear:(MobilySearchBar*)searchBar { + [_cell searchBarPressedClear:searchBar]; +} + +- (void)searchBarPressedReturn:(MobilySearchBar*)searchBar { + [_cell searchBarPressedReturn:searchBar]; +} + +- (void)searchBarPressedCancel:(MobilySearchBar*)searchBar { + [_cell searchBarPressedCancel:searchBar]; +} + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyDataItemCalendar + +#pragma mark Synthesize + +@synthesize calendar = _calendar; + +#pragma mark Init / Free + +- (instancetype)initWithIdentifier:(NSString*)identifier order:(NSUInteger)order calendar:(NSCalendar*)calendar data:(id)data { + self = [super initWithIdentifier:identifier order:order data:data]; + if(self != nil) { + _calendar = calendar; + } + return self; +} + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyDataItemCalendarMonth + +#pragma mark Synthesize + +@synthesize beginDate = _beginDate; +@synthesize endDate = _endDate; +@synthesize displayBeginDate = _displayBeginDate; +@synthesize displayEndDate = _displayEndDate; + +#pragma mark Init / Free + ++ (instancetype)itemWithCalendar:(NSCalendar*)calendar beginDate:(NSDate*)beginDate endDate:(NSDate*)endDate displayBeginDate:(NSDate*)displayBeginDate displayEndDate:(NSDate*)displayEndDate data:(id)data { + return [[self alloc] initWithCalendar:calendar beginDate:beginDate endDate:endDate displayBeginDate:displayBeginDate displayEndDate:displayEndDate data:data]; +} + +- (instancetype)initWithCalendar:(NSCalendar*)calendar beginDate:(NSDate*)beginDate endDate:(NSDate*)endDate displayBeginDate:(NSDate*)displayBeginDate displayEndDate:(NSDate*)displayEndDate data:(id)data { + self = [super initWithIdentifier:MobilyDataContainerCalendarMonthIdentifier order:3 calendar:calendar data:data]; + if(self != nil) { + _beginDate = beginDate; + _endDate = endDate; + _displayBeginDate = displayBeginDate; + _displayEndDate = displayEndDate; + } + return self; +} + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyDataItemCalendarWeekday + +#pragma mark Synthesize + +@synthesize monthItem = _monthItem; +@synthesize date = _date; + +#pragma mark Init / Free + ++ (instancetype)itemWithCalendar:(NSCalendar*)calendar date:(NSDate*)date data:(id)data { + return [[self alloc] initWithCalendar:calendar date:date data:data]; +} + ++ (instancetype)itemWithMonthItem:(MobilyDataItemCalendarMonth*)monthItem date:(NSDate*)date data:(id)data { + return [[self alloc] initWithMonthItem:monthItem date:date data:data]; +} + +- (instancetype)initWithCalendar:(NSCalendar*)calendar date:(NSDate*)date data:(id)data { + self = [super initWithIdentifier:MobilyDataContainerCalendarWeekdayIdentifier order:2 calendar:calendar data:data]; + if(self != nil) { + _date = date; + } + return self; +} + +- (instancetype)initWithMonthItem:(MobilyDataItemCalendarMonth*)monthItem date:(NSDate*)date data:(id)data { + self = [super initWithIdentifier:MobilyDataContainerCalendarWeekdayIdentifier order:2 calendar:monthItem.calendar data:data]; + if(self != nil) { + _monthItem = monthItem; + _date = date; + } + return self; +} + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyDataItemCalendarDay + +#pragma mark Synthesize + +@synthesize monthItem = _monthItem; +@synthesize weekdayItem = _weekdayItem; +@synthesize date = _date; + +#pragma mark Init / Free + ++ (instancetype)itemWithCalendar:(NSCalendar*)calendar date:(NSDate*)date data:(id)data { + return [[self alloc] initWithCalendar:calendar date:date data:data]; +} + ++ (instancetype)itemWithWeekdayItem:(MobilyDataItemCalendarWeekday*)weekdayItem date:(NSDate*)date data:(id)data { + return [[self alloc] initWithWeekdayItem:weekdayItem date:date data:data]; +} + +- (instancetype)initWithCalendar:(NSCalendar*)calendar date:(NSDate*)date data:(id)data { + self = [super initWithIdentifier:MobilyDataContainerCalendarDayIdentifier order:1 calendar:calendar data:data]; + if(self != nil) { + _date = date; + } + return self; +} + +- (instancetype)initWithWeekdayItem:(MobilyDataItemCalendarWeekday*)weekdayItem date:(NSDate*)date data:(id)data { + self = [super initWithIdentifier:MobilyDataContainerCalendarDayIdentifier order:1 calendar:weekdayItem.calendar data:data]; + if(self != nil) { + _monthItem = weekdayItem.monthItem; + _weekdayItem = weekdayItem; + _date = date; + } + return self; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataRefreshView+Private.h b/Sources/MobilyCore/MobilyDataRefreshView+Private.h new file mode 100644 index 0000000..d5acc48 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataRefreshView+Private.h @@ -0,0 +1,66 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +typedef void(^MobilyDataRefreshViewCompleteBlock)(BOOL finished); + +/*--------------------------------------------------*/ + +@interface MobilyDataRefreshView () { +@protected + MobilyDataRefreshViewType _type; + __weak MobilyDataView* _view; + __weak NSLayoutConstraint* _constraintOffset; + __weak NSLayoutConstraint* _constraintSize; + MobilyDataRefreshViewState _state; + CGFloat _size; + CGFloat _threshold; +} + +@property(nonatomic, readwrite, weak) MobilyDataView* view; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintOffset; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintSize; +@property(nonatomic, readwrite, assign) MobilyDataRefreshViewState state; + +- (void)_showAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataRefreshViewCompleteBlock)complete; +- (void)_hideAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataRefreshViewCompleteBlock)complete; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataRefreshView.h b/Sources/MobilyCore/MobilyDataRefreshView.h new file mode 100644 index 0000000..504cd11 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataRefreshView.h @@ -0,0 +1,83 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@class MobilyDataView; + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, MobilyDataRefreshViewType) { + MobilyDataRefreshViewTypeTop, + MobilyDataRefreshViewTypeBottom, + MobilyDataRefreshViewTypeLeft, + MobilyDataRefreshViewTypeRight +}; + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, MobilyDataRefreshViewState) { + MobilyDataRefreshViewStateIdle, + MobilyDataRefreshViewStatePull, + MobilyDataRefreshViewStateRelease, + MobilyDataRefreshViewStateLoading, + MobilyDataRefreshViewStateDisable +}; + +/*----------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyDataRefreshView : UIView< MobilyBuilderObject > + +@property(nonatomic, readwrite, assign) MobilyDataRefreshViewType type; +@property(nonatomic, readonly, weak) MobilyDataView* view; +@property(nonatomic, readonly, weak) NSLayoutConstraint* constraintOffset; +@property(nonatomic, readonly, weak) NSLayoutConstraint* constraintSize; +@property(nonatomic, readonly, assign) MobilyDataRefreshViewState state; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat size; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat threshold; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)didIdle; +- (void)didPull; +- (void)didRelease; +- (void)didLoading; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataRefreshView.m b/Sources/MobilyCore/MobilyDataRefreshView.m new file mode 100644 index 0000000..460b3ba --- /dev/null +++ b/Sources/MobilyCore/MobilyDataRefreshView.m @@ -0,0 +1,263 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyDataRefreshView + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; +@synthesize type = _type; +@synthesize view = _view; +@synthesize constraintOffset = _constraintOffset; +@synthesize constraintSize = _constraintSize; +@synthesize state = _state; +@synthesize size = _size; +@synthesize threshold = _threshold; + +#pragma mark NSKeyValueCoding + +#pragma mark Init / Free + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + _threshold = 64.0f; + _size = 52.0f; +} + +- (void)dealloc { + self.objectName = nil; + self.objectParent = nil; + self.objectChilds = nil; +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return self.subviews; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark UIView + +#pragma mark Property + +- (void)setState:(MobilyDataRefreshViewState)state { + if(_state != state) { + _state = state; + switch(_state) { + case MobilyDataRefreshViewStateIdle: [self didIdle]; break; + case MobilyDataRefreshViewStatePull: [self didPull]; break; + case MobilyDataRefreshViewStateRelease: [self didRelease]; break; + case MobilyDataRefreshViewStateLoading: [self didLoading]; break; + default: break; + } + } +} + +- (void)setSize:(CGFloat)size { + if(_size != size) { + _size = size; + if(_state == MobilyDataRefreshViewStateLoading) { + _constraintSize.constant = _size; + } + } +} + +#pragma mark Public + +- (void)didIdle { +} + +- (void)didPull { +} + +- (void)didRelease { +} + +- (void)didLoading { +} + +#pragma mark Private + +- (void)_showAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataRefreshViewCompleteBlock)complete { + if(_state != MobilyDataRefreshViewStateLoading) { + self.state = MobilyDataRefreshViewStateLoading; + + UIEdgeInsets refreshViewInsets = _view.refreshViewInsets; + CGPoint contentOffset = _view.contentOffset; + switch(_type) { + case MobilyDataRefreshViewTypeTop: refreshViewInsets.top = _size; refreshViewInsets.bottom = -_size; break; + case MobilyDataRefreshViewTypeBottom: refreshViewInsets.top = -_size; refreshViewInsets.bottom = _size; break; + case MobilyDataRefreshViewTypeLeft: refreshViewInsets.left = _size; refreshViewInsets.right = -_size; break; + case MobilyDataRefreshViewTypeRight: refreshViewInsets.left = -_size; refreshViewInsets.right = _size; break; + } + if(_view.isTracking == NO) { + contentOffset.x -= refreshViewInsets.left; + contentOffset.y -= refreshViewInsets.top; + } + _constraintOffset.constant = 0.0f; + _constraintSize.constant = _size; + if(animated == YES) { + [UIView animateWithDuration:MOBILY_FABS(_size - _constraintSize.constant) / MOBILY_FABS(velocity) + delay:0.01f + options:(UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut) + animations:^{ + _view.refreshViewInsets = refreshViewInsets; + _view.contentOffset = contentOffset; + [self.superview layoutIfNeeded]; + } + completion:^(BOOL finished) { + if(complete != nil) { + complete(finished); + } + }]; + } else { + _view.refreshViewInsets = refreshViewInsets; + _view.contentOffset = contentOffset; + if(complete != nil) { + complete(YES); + } + } + } else { + if(complete != nil) { + complete(YES); + } + } +} + +- (void)_hideAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataRefreshViewCompleteBlock)complete { + if(_state != MobilyDataRefreshViewStateIdle) { + self.state = MobilyDataRefreshViewStateIdle; + + UIEdgeInsets refreshViewInsets = _view.refreshViewInsets; + switch(_type) { + case MobilyDataRefreshViewTypeTop: refreshViewInsets.top = 0.0f; refreshViewInsets.bottom = 0.0f; break; + case MobilyDataRefreshViewTypeBottom: refreshViewInsets.top = 0.0f; refreshViewInsets.bottom = 0.0f; break; + case MobilyDataRefreshViewTypeLeft: refreshViewInsets.left = 0.0f; refreshViewInsets.right = 0.0f; break; + case MobilyDataRefreshViewTypeRight: refreshViewInsets.left = 0.0f; refreshViewInsets.right = 0.0f; break; + } + switch(_type) { + case MobilyDataRefreshViewTypeTop: + case MobilyDataRefreshViewTypeLeft: + _constraintOffset.constant = -_size; + _constraintSize.constant = _size; + break; + case MobilyDataRefreshViewTypeBottom: + case MobilyDataRefreshViewTypeRight: + _constraintOffset.constant = _size; + _constraintSize.constant = _size; + break; + } + if(animated == YES) { + [UIView animateWithDuration:_size / MOBILY_FABS(velocity) + delay:0.00f + options:(UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut) + animations:^{ + _view.refreshViewInsets = refreshViewInsets; + [self.superview layoutIfNeeded]; + } + completion:^(BOOL finished) { + if(complete != nil) { + complete(finished); + } + }]; + } else { + _view.refreshViewInsets = refreshViewInsets; + if(complete != nil) { + complete(YES); + } + } + } else { + if(complete != nil) { + complete(YES); + } + } +} + +@end + +/*--------------------------------------------------*/ + +NSString* MobilyDataRefreshViewTriggered = @"MobilyDataRefreshViewTriggered"; + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataView+Private.h b/Sources/MobilyCore/MobilyDataView+Private.h new file mode 100644 index 0000000..00b44ac --- /dev/null +++ b/Sources/MobilyCore/MobilyDataView+Private.h @@ -0,0 +1,261 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import +#import +#import +#import + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, MobilyDataViewDirection) { + MobilyDataViewDirectionUnknown, + MobilyDataViewDirectionHorizontal, + MobilyDataViewDirectionVertical +}; + +/*--------------------------------------------------*/ + +@class MobilyDataViewDelegateProxy; +@class MobilyDataContentView; + +/*--------------------------------------------------*/ + +@interface MobilyDataView () { +@protected + MobilyDataViewDelegateProxy* _delegateProxy; + MobilyDataContentView* _contentView; + CGFloat _velocity; + CGFloat _velocityMin; + CGFloat _velocityMax; + BOOL _allowsSelection; + BOOL _allowsMultipleSelection; + BOOL _allowsOnceSelection; + BOOL _allowsEditing; + BOOL _allowsMultipleEditing; + BOOL _bouncesTop; + BOOL _bouncesLeft; + BOOL _bouncesRight; + BOOL _bouncesBottom; + MobilyDataViewDirection _scrollDirection; + CGPoint _scrollBeginPosition; + MobilyDataContainer* _container; + UIEdgeInsets _containerInsets; + NSMutableArray* _visibleItems; + NSMutableArray* _selectedItems; + NSMutableArray* _highlightedItems; + NSMutableArray* _editingItems; + NSMutableDictionary* _registersViews; + MobilyEvents* _registersEvents; + NSMutableDictionary* _queueCells; + NSMutableArray* _queueBatch; + NSMutableArray* _reloadedBeforeItems; + NSMutableArray* _reloadedAfterItems; + NSMutableArray* _deletedItems; + NSMutableArray* _insertedItems; + BOOL _animating; + BOOL _updating; + BOOL _invalidLayout; + __weak MobilyPageControl* _pageControl; + BOOL _searchBarIteractionEnabled; + BOOL _showedSearchBar; + MobilyDataViewSearchBarStyle _searchBarStyle; + CGFloat _searchBarOverlayLastPosition; + __weak MobilySearchBar* _searchBar; + CGFloat _searchBarInset; + __weak NSLayoutConstraint* _constraintSearchBarTop; + __weak NSLayoutConstraint* _constraintSearchBarLeft; + __weak NSLayoutConstraint* _constraintSearchBarRight; + __weak NSLayoutConstraint* _constraintSearchBarSize; + BOOL _topRefreshIteractionEnabled; + __weak MobilyDataRefreshView* _topRefreshView; + __weak NSLayoutConstraint* _constraintTopRefreshTop; + __weak NSLayoutConstraint* _constraintTopRefreshLeft; + __weak NSLayoutConstraint* _constraintTopRefreshRight; + __weak NSLayoutConstraint* _constraintTopRefreshSize; + BOOL _bottomRefreshIteractionEnabled; + __weak MobilyDataRefreshView* _bottomRefreshView; + __weak NSLayoutConstraint* _constraintBottomRefreshBottom; + __weak NSLayoutConstraint* _constraintBottomRefreshLeft; + __weak NSLayoutConstraint* _constraintBottomRefreshRight; + __weak NSLayoutConstraint* _constraintBottomRefreshSize; + BOOL _leftRefreshIteractionEnabled; + __weak MobilyDataRefreshView* _leftRefreshView; + __weak NSLayoutConstraint* _constraintLeftRefreshTop; + __weak NSLayoutConstraint* _constraintLeftRefreshBottom; + __weak NSLayoutConstraint* _constraintLeftRefreshLeft; + __weak NSLayoutConstraint* _constraintLeftRefreshSize; + BOOL _rightRefreshIteractionEnabled; + __weak MobilyDataRefreshView* _rightRefreshView; + __weak NSLayoutConstraint* _constraintRightRefreshTop; + __weak NSLayoutConstraint* _constraintRightRefreshBottom; + __weak NSLayoutConstraint* _constraintRightRefreshRight; + __weak NSLayoutConstraint* _constraintRightRefreshSize; + UIEdgeInsets _refreshViewInsets; + BOOL _canDraggingSearchBar; + BOOL _canDraggingTopRefresh; + BOOL _canDraggingBottomRefresh; + BOOL _canDraggingLeftRefresh; + BOOL _canDraggingRightRefresh; +} + +@property(nonatomic, readwrite, strong) MobilyDataViewDelegateProxy* delegateProxy; +@property(nonatomic, readonly, strong) MobilyDataContentView* contentView; +@property(nonatomic, readwrite, assign) MobilyDataViewDirection scrollDirection; +@property(nonatomic, readwrite, assign) CGPoint scrollBeginPosition; + +@property(nonatomic, readwrite, strong) NSMutableDictionary* registersViews; +@property(nonatomic, readwrite, strong) MobilyEvents* registersEvents; +@property(nonatomic, readwrite, strong) NSMutableDictionary* queueCells; +@property(nonatomic, readwrite, strong) NSMutableArray* queueBatch; +@property(nonatomic, readwrite, strong) NSMutableArray* reloadedBeforeItems; +@property(nonatomic, readwrite, strong) NSMutableArray* reloadedAfterItems; +@property(nonatomic, readwrite, strong) NSMutableArray* deletedItems; +@property(nonatomic, readwrite, strong) NSMutableArray* insertedItems; +@property(nonatomic, readwrite, assign, getter=isAnimating) BOOL animating; +@property(nonatomic, readwrite, assign, getter=isUpdating) BOOL updating; +@property(nonatomic, readwrite, assign) BOOL invalidLayout; + +@property(nonatomic, readwrite, assign) CGFloat searchBarInset; +@property(nonatomic, readwrite, assign) CGFloat searchBarOverlayLastPosition; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintSearchBarTop; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintSearchBarLeft; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintSearchBarRight; + +@property(nonatomic, readwrite, assign) UIEdgeInsets refreshViewInsets; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintTopRefreshTop; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintTopRefreshLeft; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintTopRefreshRight; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintTopRefreshSize; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintBottomRefreshBottom; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintBottomRefreshLeft; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintBottomRefreshRight; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintBottomRefreshSize; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintLeftRefreshTop; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintLeftRefreshBottom; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintLeftRefreshLeft; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintLeftRefreshSize; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintRightRefreshTop; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintRightRefreshBottom; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintRightRefreshRight; +@property(nonatomic, readwrite, weak) NSLayoutConstraint* constraintRightRefreshSize; + +@property(nonatomic, readwrite, assign) BOOL canDraggingSearchBar; +@property(nonatomic, readwrite, assign) BOOL canDraggingTopRefresh; +@property(nonatomic, readwrite, assign) BOOL canDraggingBottomRefresh; +@property(nonatomic, readwrite, assign) BOOL canDraggingLeftRefresh; +@property(nonatomic, readwrite, assign) BOOL canDraggingRightRefresh; + +- (void)_receiveMemoryWarning; + +- (void)_pressedItem:(MobilyDataItem*)item animated:(BOOL)animated; + +- (void)_selectItem:(MobilyDataItem*)item user:(BOOL)user animated:(BOOL)animated; +- (void)_deselectItem:(MobilyDataItem*)item user:(BOOL)user animated:(BOOL)animated; +- (void)_deselectAllItemsUser:(BOOL)user animated:(BOOL)animated; + +- (void)_appearItem:(MobilyDataItem*)item; +- (void)_disappearItem:(MobilyDataItem*)item; + +- (void)_didInsertItems:(NSArray*)items; +- (void)_didDeleteItems:(NSArray*)items; +- (void)_didReplaceOriginItems:(NSArray*)originItems withItems:(NSArray*)items; + +- (void)_validateLayout; +- (void)_layoutForVisible; + +- (void)_updateSuperviewConstraints; +- (void)_updateInsets; + +- (void)_willBeginDragging; +- (void)_didScrollDragging:(BOOL)dragging decelerating:(BOOL)decelerating; +- (void)_willEndDraggingWithVelocity:(CGPoint)velocity contentOffset:(inout CGPoint*)contentOffset contentSize:(CGSize)contentSize visibleSize:(CGSize)visibleSize; +- (void)_didEndDraggingWillDecelerate:(BOOL)decelerate; +- (void)_willBeginDecelerating; +- (void)_didEndDecelerating; +- (void)_didEndScrollingAnimation; + +- (void)_showSearchBarAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete; +- (void)_hideSearchBarAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete; + +- (void)_showTopRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete; +- (void)_hideTopRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete; +- (void)_showBottomRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete; +- (void)_hideBottomRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete; +- (void)_showLeftRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete; +- (void)_hideLeftRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete; +- (void)_showRightRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete; +- (void)_hideRightRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete; + +- (void)_batchUpdate:(MobilyDataViewUpdateBlock)update animated:(BOOL)animated; +- (void)_batchComplete:(MobilyDataViewUpdateBlock)complete animated:(BOOL)animated; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataContentView : UIView< MobilyObject > + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataBatch : NSObject< MobilyObject > + +@property(nonatomic, readonly, assign) NSTimeInterval duration; +@property(nonatomic, readonly, copy) MobilyDataViewUpdateBlock update; +@property(nonatomic, readonly, copy) MobilyDataViewCompleteBlock complete; + +- (instancetype)initWithDuration:(NSTimeInterval)duration update:(MobilyDataViewUpdateBlock)update complete:(MobilyDataViewCompleteBlock)complete; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyDataViewDelegateProxy : NSObject< UIScrollViewDelegate > { +@protected + __weak MobilyDataView* _view; + __weak id< UIScrollViewDelegate > _delegate; +} + +@property(nonatomic, readwrite, weak) MobilyDataView* view; +@property(nonatomic, readwrite, weak) id< UIScrollViewDelegate > delegate; + +- (instancetype)initWithDataView:(MobilyDataView*)view; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataView.h b/Sources/MobilyCore/MobilyDataView.h new file mode 100644 index 0000000..b9a1de6 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataView.h @@ -0,0 +1,234 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@class MobilyDataContainer; +@class MobilyDataItem; +@class MobilyDataCell; +@class MobilyDataRefreshView; + +/*--------------------------------------------------*/ + +typedef void(^MobilyDataViewUpdateBlock)(); +typedef void(^MobilyDataViewCompleteBlock)(BOOL finished); + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, MobilyDataViewSearchBarStyle) { + MobilyDataViewSearchBarStyleStatic, + MobilyDataViewSearchBarStyleInside, + MobilyDataViewSearchBarStyleOverlay +}; + +/*--------------------------------------------------*/ + +@protocol MobilyDataRefreshView; + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyDataView : UIScrollView< MobilyBuilderObject, MobilySearchBarDelegate > + +@property(nonatomic, readwrite, assign) IBInspectable CGFloat velocity; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat velocityMin; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat velocityMax; + +@property(nonatomic, readwrite, assign) IBInspectable BOOL allowsSelection; +@property(nonatomic, readwrite, assign) IBInspectable BOOL allowsOnceSelection; +@property(nonatomic, readwrite, assign) IBInspectable BOOL allowsMultipleSelection; +@property(nonatomic, readwrite, assign) IBInspectable BOOL allowsEditing; +@property(nonatomic, readwrite, assign) IBInspectable BOOL allowsMultipleEditing; +@property(nonatomic, readwrite, assign) IBInspectable BOOL bouncesTop; +@property(nonatomic, readwrite, assign) IBInspectable BOOL bouncesLeft; +@property(nonatomic, readwrite, assign) IBInspectable BOOL bouncesRight; +@property(nonatomic, readwrite, assign) IBInspectable BOOL bouncesBottom; + +@property(nonatomic, readwrite, strong) MobilyDataContainer* container; +@property(nonatomic, readwrite, assign) UIEdgeInsets containerInsets; +@property(nonatomic, readonly, strong) NSArray* visibleItems; +@property(nonatomic, readonly, strong) NSArray* visibleCells; +@property(nonatomic, readonly, strong) NSArray* selectedItems; +@property(nonatomic, readonly, strong) NSArray* selectedCells; +@property(nonatomic, readonly, strong) NSArray* highlightedItems; +@property(nonatomic, readonly, strong) NSArray* highlightedCells; +@property(nonatomic, readonly, strong) NSArray* editingItems; +@property(nonatomic, readonly, strong) NSArray* editingCells; +@property(nonatomic, readonly, assign, getter=isAnimating) BOOL animating; +@property(nonatomic, readonly, assign, getter=isUpdating) BOOL updating; + +@property(nonatomic, readwrite, weak) IBOutlet MobilyPageControl* pageControl; + +@property(nonatomic, readwrite, assign) IBInspectable BOOL searchBarIteractionEnabled; +@property(nonatomic, readwrite, assign, getter=isShowedSearchBar) IBInspectable BOOL showedSearchBar; +@property(nonatomic, readwrite, assign) IBInspectable MobilyDataViewSearchBarStyle searchBarStyle; +@property(nonatomic, readwrite, weak) IBOutlet MobilySearchBar* searchBar; +@property(nonatomic, readonly, assign) CGFloat searchBarInset; + +@property(nonatomic, readwrite, assign) IBInspectable BOOL topRefreshIteractionEnabled; +@property(nonatomic, readwrite, weak) IBOutlet MobilyDataRefreshView* topRefreshView; +@property(nonatomic, readwrite, assign) IBInspectable BOOL bottomRefreshIteractionEnabled; +@property(nonatomic, readwrite, weak) IBOutlet MobilyDataRefreshView* bottomRefreshView; +@property(nonatomic, readwrite, assign) IBInspectable BOOL leftRefreshIteractionEnabled; +@property(nonatomic, readwrite, weak) IBOutlet MobilyDataRefreshView* leftRefreshView; +@property(nonatomic, readwrite, assign) IBInspectable BOOL rightRefreshIteractionEnabled; +@property(nonatomic, readwrite, weak) IBOutlet MobilyDataRefreshView* rightRefreshView; +@property(nonatomic, readonly, assign) UIEdgeInsets refreshViewInsets; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)registerIdentifier:(NSString*)identifier withViewClass:(Class)viewClass; +- (void)unregisterIdentifier:(NSString*)identifier; +- (void)unregisterAllIdentifiers; + +- (void)registerEventWithTarget:(id)target action:(SEL)action forKey:(id)key; +- (void)registerEventWithTarget:(id)target action:(SEL)action forIdentifier:(NSString*)identifier forKey:(id)key; +- (void)registerEventWithBlock:(MobilyEventBlockType)block forKey:(id)key; +- (void)registerEventWithBlock:(MobilyEventBlockType)block forIdentifier:(NSString*)identifier forKey:(id)key; +- (void)registerEvent:(id< MobilyEvent >)event forKey:(id)key; +- (void)registerEvent:(id< MobilyEvent >)event forIdentifier:(NSString*)identifier forKey:(id)key; +- (void)unregisterEventForKey:(id)key; +- (void)unregisterEventForIdentifier:(NSString*)identifier forKey:(id)key; +- (void)unregisterEventsForIdentifier:(NSString*)identifier; +- (void)unregisterAllEvents; + +- (BOOL)containsEventForKey:(id)key; +- (BOOL)containsEventForIdentifier:(NSString*)identifier forKey:(id)key; + +- (void)fireEventForKey:(id)key byObject:(id)object; +- (void)fireEventForIdentifier:(NSString*)identifier forKey:(id)key byObject:(id)object; +- (id)fireEventForKey:(id)key byObject:(id)object orDefault:(id)orDefault; +- (id)fireEventForIdentifier:(NSString*)identifier forKey:(id)key byObject:(id)object orDefault:(id)orDefault; +- (void)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object; +- (void)fireEventForIdentifier:(NSString*)identifier forKey:(id)key bySender:(id)sender byObject:(id)object; +- (id)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault; +- (id)fireEventForIdentifier:(NSString*)identifier forKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault; + +- (Class)cellClassWithItem:(MobilyDataItem*)item; + +- (void)dequeueCellWithItem:(MobilyDataItem*)item; +- (void)enqueueCellWithItem:(MobilyDataItem*)item; + +- (MobilyDataItem*)itemForPoint:(CGPoint)point; +- (MobilyDataItem*)itemForData:(id)data; +- (MobilyDataCell*)cellForData:(id)data; + +- (BOOL)isSelectedItem:(MobilyDataItem*)item; +- (BOOL)shouldSelectItem:(MobilyDataItem*)item; +- (BOOL)shouldDeselectItem:(MobilyDataItem*)item; + +- (void)selectItem:(MobilyDataItem*)item animated:(BOOL)animated; +- (void)deselectItem:(MobilyDataItem*)item animated:(BOOL)animated; +- (void)deselectAllItemsAnimated:(BOOL)animated; + +- (BOOL)isHighlightedItem:(MobilyDataItem*)item; +- (BOOL)shouldHighlightItem:(MobilyDataItem*)item; +- (BOOL)shouldUnhighlightItem:(MobilyDataItem*)item; + +- (void)highlightItem:(MobilyDataItem*)item animated:(BOOL)animated; +- (void)unhighlightItem:(MobilyDataItem*)item animated:(BOOL)animated; +- (void)unhighlightAllItemsAnimated:(BOOL)animated; + +- (BOOL)isEditingItem:(MobilyDataItem*)item; +- (BOOL)shouldBeganEditItem:(MobilyDataItem*)item; +- (BOOL)shouldEndedEditItem:(MobilyDataItem*)item; + +- (void)beganEditItem:(MobilyDataItem*)item animated:(BOOL)animated; +- (void)endedEditItem:(MobilyDataItem*)item animated:(BOOL)animated; +- (void)endedEditAllItemsAnimated:(BOOL)animated; + +- (void)batchUpdate:(MobilyDataViewUpdateBlock)update; +- (void)batchUpdate:(MobilyDataViewUpdateBlock)update complete:(MobilyDataViewCompleteBlock)complete; +- (void)batchDuration:(NSTimeInterval)duration update:(MobilyDataViewUpdateBlock)update; +- (void)batchDuration:(NSTimeInterval)duration update:(MobilyDataViewUpdateBlock)update complete:(MobilyDataViewCompleteBlock)complete; + +- (void)setNeedValidateLayout; +- (void)validateLayoutIfNeed; + +- (void)setNeedLayoutForVisible; +- (void)layoutForVisibleIfNeed; + +- (void)scrollToItem:(MobilyDataItem*)item scrollPosition:(MobilyDataViewPosition)scrollPosition animated:(BOOL)animated; +- (void)scrollToRect:(CGRect)rect scrollPosition:(MobilyDataViewPosition)scrollPosition animated:(BOOL)animated; + +- (void)showSearchBarAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete; +- (void)hideSearchBarAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete; + +- (void)showTopRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete; +- (void)hideTopRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete; +- (void)showBottomRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete; +- (void)hideBottomRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete; +- (void)showLeftRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete; +- (void)hideLeftRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete; +- (void)showRightRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete; +- (void)hideRightRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete; + +@end + +/*--------------------------------------------------*/ + +extern NSString* MobilyDataViewSelectItem; +extern NSString* MobilyDataViewDeselectItem; + +/*--------------------------------------------------*/ + +extern NSString* MobilyDataViewSearchBegin; +extern NSString* MobilyDataViewSearchEnd; +extern NSString* MobilyDataViewSearchBeginEditing; +extern NSString* MobilyDataViewSearchTextChanged; +extern NSString* MobilyDataViewSearchEndEditing; +extern NSString* MobilyDataViewSearchPressedClear; +extern NSString* MobilyDataViewSearchPressedReturn; +extern NSString* MobilyDataViewSearchPressedCancel; + +/*--------------------------------------------------*/ + +extern NSString* MobilyDataViewTopRefreshTriggered; +extern NSString* MobilyDataViewBottomRefreshTriggered; +extern NSString* MobilyDataViewLeftRefreshTriggered; +extern NSString* MobilyDataViewRightRefreshTriggered; + +/*--------------------------------------------------*/ + +extern NSString* MobilyDataViewAnimateRestore; +extern NSString* MobilyDataViewAnimateInsert; +extern NSString* MobilyDataViewAnimateDelete; +extern NSString* MobilyDataViewAnimateReplaceOut; +extern NSString* MobilyDataViewAnimateReplaceIn; + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDataView.m b/Sources/MobilyCore/MobilyDataView.m new file mode 100644 index 0000000..d955487 --- /dev/null +++ b/Sources/MobilyCore/MobilyDataView.m @@ -0,0 +1,2333 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@implementation MobilyDataView + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; +@synthesize delegateProxy = _delegateProxy; +@synthesize contentView = _contentView; +@synthesize velocity = _velocity; +@synthesize velocityMin = _velocityMin; +@synthesize velocityMax = _velocityMax; +@synthesize allowsSelection = _allowsSelection; +@synthesize allowsMultipleSelection = _allowsMultipleSelection; +@synthesize allowsOnceSelection = _allowsOnceSelection; +@synthesize allowsEditing = _allowsEditing; +@synthesize allowsMultipleEditing = _allowsMultipleEditing; +@synthesize bouncesTop = _bouncesTop; +@synthesize bouncesLeft = _bouncesLeft; +@synthesize bouncesRight = _bouncesRight; +@synthesize bouncesBottom = _bouncesBottom; +@synthesize scrollDirection = _scrollDirection; +@synthesize scrollBeginPosition = _scrollBeginPosition; +@synthesize container = _container; +@synthesize containerInsets = _containerInsets; +@synthesize visibleItems = _visibleItems; +@synthesize selectedItems = _selectedItems; +@synthesize highlightedItems = _highlightedItems; +@synthesize editingItems = _editingItems; +@synthesize registersViews = _registersViews; +@synthesize registersEvents = _registersEvents; +@synthesize queueCells = _queueCells; +@synthesize queueBatch = _queueBatch; +@synthesize reloadedBeforeItems = _reloadedBeforeItems; +@synthesize reloadedAfterItems = _reloadedAfterItems; +@synthesize deletedItems = _deletedItems; +@synthesize insertedItems = _insertedItems; +@synthesize animating = _animating; +@synthesize updating = _updating; +@synthesize invalidLayout = _invalidLayout; +@synthesize pageControl = _pageControl; +@synthesize searchBarIteractionEnabled = _searchBarIteractionEnabled; +@synthesize showedSearchBar = _showedSearchBar; +@synthesize searchBar = _searchBar; +@synthesize searchBarStyle = _searchBarStyle; +@synthesize searchBarInset = _searchBarInset; +@synthesize searchBarOverlayLastPosition = _searchBarOverlayLastPosition; +@synthesize refreshViewInsets = _refreshViewInsets; +@synthesize constraintSearchBarTop = _constraintSearchBarTop; +@synthesize constraintSearchBarLeft = _constraintSearchBarLeft; +@synthesize constraintSearchBarRight = _constraintSearchBarRight; +@synthesize topRefreshIteractionEnabled = _topRefreshIteractionEnabled; +@synthesize topRefreshView = _topRefreshView; +@synthesize constraintTopRefreshTop = _constraintTopRefreshTop; +@synthesize constraintTopRefreshLeft = _constraintTopRefreshLeft; +@synthesize constraintTopRefreshRight = _constraintTopRefreshRight; +@synthesize constraintTopRefreshSize = _constraintTopRefreshSize; +@synthesize bottomRefreshIteractionEnabled = _bottomRefreshIteractionEnabled; +@synthesize bottomRefreshView = _bottomRefreshView; +@synthesize constraintBottomRefreshBottom = _constraintBottomRefreshBottom; +@synthesize constraintBottomRefreshLeft = _constraintBottomRefreshLeft; +@synthesize constraintBottomRefreshRight = _constraintBottomRefreshRight; +@synthesize constraintBottomRefreshSize = _constraintBottomRefreshSize; +@synthesize leftRefreshIteractionEnabled = _leftRefreshIteractionEnabled; +@synthesize leftRefreshView = _leftRefreshView; +@synthesize constraintLeftRefreshTop = _constraintLeftRefreshTop; +@synthesize constraintLeftRefreshBottom = _constraintLeftRefreshBottom; +@synthesize constraintLeftRefreshLeft = _constraintLeftRefreshLeft; +@synthesize constraintLeftRefreshSize = _constraintLeftRefreshSize; +@synthesize rightRefreshIteractionEnabled = _rightRefreshIteractionEnabled; +@synthesize rightRefreshView = _rightRefreshView; +@synthesize constraintRightRefreshTop = _constraintRightRefreshTop; +@synthesize constraintRightRefreshBottom = _constraintRightRefreshBottom; +@synthesize constraintRightRefreshRight = _constraintRightRefreshRight; +@synthesize constraintRightRefreshSize = _constraintRightRefreshSize; +@synthesize canDraggingSearchBar = _canDraggingSearchBar; +@synthesize canDraggingTopRefresh = _canDraggingTopRefresh; +@synthesize canDraggingBottomRefresh = _canDraggingBottomRefresh; +@synthesize canDraggingLeftRefresh = _canDraggingLeftRefresh; +@synthesize canDraggingRightRefresh = _canDraggingRightRefresh; + +#pragma mark NSKeyValueCoding + +#pragma mark Init / Free + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + self.delegateProxy = [MobilyDataViewDelegateProxy new]; + + if(UIDevice.moIsIPhone == YES) { + _velocity = 400.0f; + _velocityMin = 300.0f; + _velocityMax = 900.0f; + } else if(UIDevice.moIsIPad == YES) { + _velocity = 2000.0f; + _velocityMin = 3000.0f; + _velocityMax = 6000.0f; + } + + _bouncesTop = YES; + _bouncesLeft = YES; + _bouncesRight = YES; + _bouncesBottom = YES; + + _allowsSelection = YES; + _allowsEditing = YES; + + _visibleItems = NSMutableArray.array; + _selectedItems = NSMutableArray.array; + _highlightedItems = NSMutableArray.array; + _editingItems = NSMutableArray.array; + _registersViews = NSMutableDictionary.dictionary; + _registersEvents = [MobilyEvents new]; + _queueCells = NSMutableDictionary.dictionary; + _queueBatch = NSMutableArray.array; + _reloadedBeforeItems = NSMutableArray.array; + _reloadedAfterItems = NSMutableArray.array; + _deletedItems = NSMutableArray.array; + _insertedItems = NSMutableArray.array; + + _searchBarIteractionEnabled = YES; + _showedSearchBar = NO; + _searchBarStyle = MobilyDataViewSearchBarStyleOverlay; + _topRefreshIteractionEnabled = YES; + _bottomRefreshIteractionEnabled = YES; + _leftRefreshIteractionEnabled = YES; + _rightRefreshIteractionEnabled = YES; + + [self moRegisterAdjustmentResponder]; + + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(_receiveMemoryWarning) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; +} + +- (void)dealloc { + [NSNotificationCenter.defaultCenter removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; + + [self moUnregisterAdjustmentResponder]; +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return self.subviews; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark UIView + +- (void)layoutSubviews { + [super layoutSubviews]; + + [self validateLayoutIfNeed]; + [self _layoutForVisible]; +} + +- (void)didMoveToSuperview { + [super didMoveToSuperview]; + + [self _updateSuperviewConstraints]; +} + +#pragma mark Property + +- (void)setFrame:(CGRect)frame { + CGRect prev = self.frame; + if(CGSizeEqualToSize(prev.size, frame.size) == NO) { + [self setNeedValidateLayout]; + } + super.frame = frame; +} + +- (void)setBounds:(CGRect)bounds { + CGRect prev = self.bounds; + if(CGSizeEqualToSize(prev.size, bounds.size) == NO) { + [self setNeedValidateLayout]; + } + super.bounds = bounds; +} + +- (void)setContentInset:(UIEdgeInsets)contentInset { + UIEdgeInsets oldContentInset = self.contentInset; + if(UIEdgeInsetsEqualToEdgeInsets(oldContentInset, contentInset) == NO) { + CGFloat x = contentInset.left - oldContentInset.left; + CGFloat y = contentInset.top - oldContentInset.top; + self.scrollBeginPosition = CGPointMake(_scrollBeginPosition.x + x, _scrollBeginPosition.y + y); + self.searchBarOverlayLastPosition += y; + [super setContentInset:contentInset]; + [self setNeedsLayout]; + } +} + +- (void)setContentSize:(CGSize)contentSize { + [super setContentSize:contentSize]; + CGFloat width = (contentSize.width > MOBILY_EPSILON) ? contentSize.width : self.frame.size.width; + CGFloat height = (contentSize.height > MOBILY_EPSILON) ? contentSize.height : self.frame.size.height; + self.contentView.moFrameSize = CGSizeMake(width, height); +} + +- (void)setDelegateProxy:(MobilyDataViewDelegateProxy*)delegateProxy { + if(_delegateProxy != delegateProxy) { + if(_delegateProxy != nil) { + _delegateProxy.view = nil; + } + super.delegate = nil; + _delegateProxy = delegateProxy; + super.delegate = _delegateProxy; + if(_delegateProxy != nil) { + _delegateProxy.view = self; + } + } +} + +- (void)setDelegate:(id< UIScrollViewDelegate >)delegate { + if(_delegateProxy.delegate != delegate) { + super.delegate = nil; + _delegateProxy.delegate = delegate; + super.delegate = _delegateProxy; + } +} + +- (id< UIScrollViewDelegate >)delegate { + return _delegateProxy.delegate; +} + +- (MobilyDataContentView*)contentView { + if(_contentView == nil) { + CGSize contentSize = self.contentSize; + CGFloat width = (contentSize.width > MOBILY_EPSILON) ? contentSize.width : self.frame.size.width; + CGFloat height = (contentSize.height > MOBILY_EPSILON) ? contentSize.height : self.frame.size.height; + _contentView = [[MobilyDataContentView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, width, height)]; + [self addSubview:_contentView]; + } + return _contentView; +} + +- (void)setContainer:(MobilyDataContainer*)container { + if(_container != container) { + if(_container != nil) { + [self setNeedValidateLayout]; + [UIView performWithoutAnimation:^{ + [self deselectAllItemsAnimated:NO]; + [self unhighlightAllItemsAnimated:NO]; + if(_visibleItems.count > 0) { + for(MobilyDataItem* item in _visibleItems) { + [self enqueueCellWithItem:item]; + } + [_visibleItems removeAllObjects]; + } + }]; + _container.view = nil; + [self validateLayoutIfNeed]; + } + _container = container; + if(_container != nil) { + [self setNeedValidateLayout]; + _container.view = self; + [UIView performWithoutAnimation:^{ + [self validateLayoutIfNeed]; + [self _layoutForVisible]; + }]; + } + } +} + +- (void)setContainerInsets:(UIEdgeInsets)containerInsets { + if(UIEdgeInsetsEqualToEdgeInsets(_containerInsets, containerInsets) == NO) { + _containerInsets = containerInsets; + [self _updateInsets]; + } +} + +- (NSArray*)visibleItems { + [_visibleItems sortUsingComparator:^NSComparisonResult(MobilyDataItem* item1, MobilyDataItem* item2) { + if(item1.order < item2.order) { + return NSOrderedAscending; + } else if(item1.order > item2.order) { + return NSOrderedDescending; + } + return NSOrderedSame; + }]; + return _visibleItems; +} + +- (NSArray*)visibleCells { + NSMutableArray* result = NSMutableArray.array; + for(MobilyDataItem* item in self.visibleItems) { + [result addObject:item.view]; + } + return [NSArray arrayWithArray:result]; +} + +- (NSArray*)selectedItems { + return _selectedItems; +} + +- (NSArray*)selectedCells { + NSMutableArray* result = NSMutableArray.array; + for(MobilyDataItem* item in _selectedItems) { + MobilyDataCell* cell = item.cell; + if(cell != nil) { + [result addObject:cell]; + } + } + return result; +} + +- (NSArray*)highlightedItems { + return _highlightedItems; +} + +- (NSArray*)highlightedCells { + NSMutableArray* result = NSMutableArray.array; + for(MobilyDataItem* item in _highlightedItems) { + MobilyDataCell* cell = item.cell; + if(cell != nil) { + [result addObject:cell]; + } + } + return result; +} + +- (NSArray*)editingItems { + return _editingItems; +} + +- (NSArray*)editingCells { + NSMutableArray* result = NSMutableArray.array; + for(MobilyDataItem* item in _editingItems) { + MobilyDataCell* cell = item.cell; + if(cell != nil) { + [result addObject:cell]; + } + } + return result; +} + +- (void)setShowedSearchBar:(BOOL)showedSearchBar { + if(showedSearchBar == YES) { + [self showSearchBarAnimated:NO complete:nil]; + } else { + [self hideSearchBarAnimated:NO complete:nil]; + } +} + +- (void)setSearchBarStyle:(MobilyDataViewSearchBarStyle)searchBarStyle { + if(_searchBarStyle != searchBarStyle) { + if(_searchBar != nil) { + self.constraintSearchBarTop = nil; + self.constraintSearchBarLeft = nil; + self.constraintSearchBarRight = nil; + } + _searchBarStyle = searchBarStyle; + if(_searchBar != nil) { + [self _updateSuperviewConstraints]; + } + self.searchBarInset = (_showedSearchBar == YES) ? _searchBar.moFrameHeight : 0.0f; + } +} + +- (void)setSearchBar:(MobilySearchBar*)searchBar { + if(_searchBar != searchBar) { + if(_searchBar != nil) { + self.constraintSearchBarTop = nil; + self.constraintSearchBarLeft = nil; + self.constraintSearchBarRight = nil; + [_searchBar removeFromSuperview]; + } + _searchBar = searchBar; + if(_searchBar != nil) { + _searchBar.translatesAutoresizingMaskIntoConstraints = NO; + _searchBar.delegate = self; + if(self.superview != nil) { + [self.superview insertSubview:_searchBar aboveSubview:self]; + [self _updateSuperviewConstraints]; + } + } + self.searchBarInset = (_showedSearchBar == YES) ? _searchBar.moFrameHeight : 0.0f; + } +} + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintSearchBarTop, constraintSearchBarTop, self.superview, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintSearchBarLeft, constraintSearchBarLeft, self.superview, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintSearchBarRight, constraintSearchBarRight, self.superview, { +}, { +}) + +- (void)setSearchBarInset:(CGFloat)searchBarInset { + if(_searchBarInset != searchBarInset) { + _searchBarInset = searchBarInset; + [self _updateInsets]; + } +} + +- (void)setTopRefreshView:(MobilyDataRefreshView*)topRefreshView { + if(_topRefreshView != topRefreshView) { + if(_topRefreshView != nil) { + self.constraintTopRefreshTop = nil; + self.constraintTopRefreshLeft = nil; + self.constraintTopRefreshRight = nil; + self.constraintTopRefreshSize = nil; + [_topRefreshView removeFromSuperview]; + _topRefreshView.view = nil; + } + _topRefreshView = topRefreshView; + if(_topRefreshView != nil) { + _topRefreshView.translatesAutoresizingMaskIntoConstraints = NO; + _topRefreshView.type = MobilyDataRefreshViewTypeTop; + _topRefreshView.view = self; + if(self.superview != nil) { + [self.superview insertSubview:_topRefreshView belowSubview:self]; + [self _updateSuperviewConstraints]; + } + } + } +} + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintTopRefreshTop, constraintTopRefreshTop, self.superview, { +}, { + _topRefreshView.constraintOffset = _constraintTopRefreshTop; +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintTopRefreshLeft, constraintTopRefreshLeft, self.superview, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintTopRefreshRight, constraintTopRefreshRight, self.superview, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintTopRefreshSize, constraintTopRefreshSize, self.superview, { +}, { + _topRefreshView.constraintSize = _constraintTopRefreshSize; +}) + +- (void)setBottomRefreshView:(MobilyDataRefreshView*)bottomRefreshView { + if(_bottomRefreshView != bottomRefreshView) { + if(_bottomRefreshView != nil) { + self.constraintBottomRefreshBottom = nil; + self.constraintBottomRefreshLeft = nil; + self.constraintBottomRefreshRight = nil; + self.constraintBottomRefreshSize = nil; + [_bottomRefreshView removeFromSuperview]; + _bottomRefreshView.view = nil; + } + _bottomRefreshView = bottomRefreshView; + if(_bottomRefreshView != nil) { + _bottomRefreshView.translatesAutoresizingMaskIntoConstraints = NO; + _bottomRefreshView.type = MobilyDataRefreshViewTypeBottom; + _bottomRefreshView.view = self; + if(self.superview != nil) { + [self.superview insertSubview:_bottomRefreshView belowSubview:self]; + [self _updateSuperviewConstraints]; + } + } + } +} + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintBottomRefreshBottom, constraintBottomRefreshBottom, self.superview, { +}, { + _bottomRefreshView.constraintOffset = _constraintBottomRefreshBottom; +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintBottomRefreshLeft, constraintBottomRefreshLeft, self.superview, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintBottomRefreshRight, constraintBottomRefreshRight, self.superview, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintBottomRefreshSize, constraintBottomRefreshSize, self.superview, { +}, { + _bottomRefreshView.constraintSize = _constraintBottomRefreshSize; +}) + +- (void)setLeftRefreshView:(MobilyDataRefreshView*)leftRefreshView { + if(_leftRefreshView != leftRefreshView) { + if(_leftRefreshView != nil) { + self.constraintLeftRefreshBottom = nil; + self.constraintLeftRefreshLeft = nil; + self.constraintLeftRefreshTop = nil; + self.constraintLeftRefreshSize = nil; + [_leftRefreshView removeFromSuperview]; + _leftRefreshView.view = nil; + } + _leftRefreshView = leftRefreshView; + if(_leftRefreshView != nil) { + _leftRefreshView.translatesAutoresizingMaskIntoConstraints = NO; + _leftRefreshView.type = MobilyDataRefreshViewTypeLeft; + _leftRefreshView.view = self; + if(self.superview != nil) { + [self.superview insertSubview:_leftRefreshView belowSubview:self]; + [self _updateSuperviewConstraints]; + } + } + } +} + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintLeftRefreshTop, constraintLeftRefreshTop, self.superview, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintLeftRefreshBottom, constraintLeftRefreshBottom, self.superview, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintLeftRefreshLeft, constraintLeftRefreshLeft, self.superview, { +}, { + _leftRefreshView.constraintOffset = _constraintLeftRefreshLeft; +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintLeftRefreshSize, constraintLeftRefreshSize, self.superview, { +}, { + _leftRefreshView.constraintSize = _constraintLeftRefreshSize; +}) + +- (void)setRightRefreshView:(MobilyDataRefreshView*)rightRefreshView { + if(_rightRefreshView != rightRefreshView) { + if(_rightRefreshView != nil) { + self.constraintRightRefreshTop = nil; + self.constraintRightRefreshBottom = nil; + self.constraintRightRefreshRight = nil; + self.constraintRightRefreshSize = nil; + [_rightRefreshView removeFromSuperview]; + _rightRefreshView.view = nil; + } + _rightRefreshView = rightRefreshView; + if(_rightRefreshView != nil) { + _rightRefreshView.translatesAutoresizingMaskIntoConstraints = NO; + _rightRefreshView.type = MobilyDataRefreshViewTypeRight; + _rightRefreshView.view = self; + if(self.superview != nil) { + [self.superview insertSubview:_rightRefreshView belowSubview:self]; + [self _updateSuperviewConstraints]; + } + } + } +} + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRightRefreshTop, constraintRightRefreshTop, self.superview, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRightRefreshBottom, constraintRightRefreshBottom, self.superview, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRightRefreshRight, constraintRightRefreshRight, self.superview, { +}, { + _rightRefreshView.constraintOffset = _constraintRightRefreshRight; +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRightRefreshSize, constraintRightRefreshSize, self.superview, { +}, { + _rightRefreshView.constraintSize = _constraintRightRefreshSize; +}) + +- (void)setRefreshViewInsets:(UIEdgeInsets)refreshViewInsets { + if(UIEdgeInsetsEqualToEdgeInsets(_refreshViewInsets, refreshViewInsets) == NO) { + _refreshViewInsets = refreshViewInsets; + [self _updateInsets]; + } +} + +#pragma mark Public + +- (void)registerIdentifier:(NSString*)identifier withViewClass:(Class)viewClass { +#if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) + if(_registersViews[identifier] != nil) { + NSLog(@"ERROR: [%@:%@] %@ - %@", self.class, NSStringFromSelector(_cmd), identifier, viewClass); + return; + } +#endif + _registersViews[identifier] = viewClass; +} + +- (void)unregisterIdentifier:(NSString*)identifier { +#if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) + if(_registersViews[identifier] == nil) { + NSLog(@"ERROR: [%@:%@] %@", self.class, NSStringFromSelector(_cmd), identifier); + return; + } +#endif + [_registersViews removeObjectForKey:identifier]; +} + +- (void)unregisterAllIdentifiers { + [_registersViews removeAllObjects]; +} + +- (void)registerEventWithTarget:(id)target action:(SEL)action forKey:(id)key { + [_registersEvents addEventWithTarget:target action:action forKey:key]; +} + +- (void)registerEventWithTarget:(id)target action:(SEL)action forIdentifier:(NSString*)identifier forKey:(id)key { + [_registersEvents addEventWithTarget:target action:action forGroup:identifier forKey:key]; +} + +- (void)registerEventWithBlock:(MobilyEventBlockType)block forKey:(id)key { + [_registersEvents addEventWithBlock:block forKey:key]; +} + +- (void)registerEventWithBlock:(MobilyEventBlockType)block forIdentifier:(NSString*)identifier forKey:(id)key { + [_registersEvents addEventWithBlock:block forGroup:identifier forKey:key]; +} + +- (void)registerEvent:(id< MobilyEvent >)event forKey:(id)key { + [_registersEvents addEvent:event forKey:key]; +} + +- (void)registerEvent:(id< MobilyEvent >)event forIdentifier:(NSString*)identifier forKey:(id)key { + [_registersEvents addEvent:event forGroup:identifier forKey:key]; +} + +- (void)unregisterEventForKey:(id)key { + [_registersEvents removeEventForKey:key]; +} + +- (void)unregisterEventForIdentifier:(NSString*)identifier forKey:(id)key { + [_registersEvents removeEventInGroup:identifier forKey:key]; +} + +- (void)unregisterEventsForIdentifier:(NSString*)identifier { + [_registersEvents removeEventsForGroup:identifier]; +} + +- (void)unregisterAllEvents { + [_registersEvents removeAllEvents]; +} + +- (BOOL)containsEventForKey:(id)key { + return [_registersEvents containsEventForKey:key]; +} + +- (BOOL)containsEventForIdentifier:(NSString*)identifier forKey:(id)key { + return [_registersEvents containsEventInGroup:identifier forKey:key]; +} + +- (BOOL)containsEventForKey:(id)key forIdentifier:(NSString*)identifier { + return [_registersEvents containsEventInGroup:identifier forKey:key]; +} + +- (void)fireEventForKey:(id)key byObject:(id)object { + [_registersEvents fireEventForKey:key bySender:self byObject:object]; +} + +- (void)fireEventForIdentifier:(NSString*)identifier forKey:(id)key byObject:(id)object { + [_registersEvents fireEventInGroup:identifier forKey:key bySender:self byObject:object]; +} + +- (id)fireEventForKey:(id)key byObject:(id)object orDefault:(id)orDefault { + return [_registersEvents fireEventForKey:key bySender:self byObject:object orDefault:orDefault]; +} + +- (id)fireEventForIdentifier:(NSString*)identifier forKey:(id)key byObject:(id)object orDefault:(id)orDefault { + return [_registersEvents fireEventInGroup:identifier forKey:key bySender:self byObject:object orDefault:orDefault]; +} + +- (void)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object { + [_registersEvents fireEventForKey:key bySender:sender byObject:object]; +} + +- (void)fireEventForIdentifier:(NSString*)identifier forKey:(id)key bySender:(id)sender byObject:(id)object { + [_registersEvents fireEventInGroup:identifier forKey:key bySender:sender byObject:object]; +} + +- (id)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault { + return [_registersEvents fireEventForKey:key bySender:sender byObject:object orDefault:orDefault]; +} + +- (id)fireEventForIdentifier:(NSString*)identifier forKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault { + return [_registersEvents fireEventInGroup:identifier forKey:key bySender:sender byObject:object orDefault:orDefault]; +} + +- (Class)cellClassWithItem:(MobilyDataItem*)item { + return _registersViews[item.identifier]; +} + +- (void)dequeueCellWithItem:(MobilyDataItem*)item { + if(item.cell == nil) { + NSString* identifier = item.identifier; + NSMutableArray* queue = _queueCells[identifier]; + MobilyDataCell* cell = [queue lastObject]; + if(cell == nil) { + cell = [[_registersViews[identifier] alloc] initWithIdentifier:identifier]; + if(cell != nil) { + cell.view = self; + __block NSUInteger viewIndex = NSNotFound; + [self.contentView.subviews enumerateObjectsUsingBlock:^(UIView* view, NSUInteger index, BOOL* stop) { + if([view isKindOfClass:MobilyDataCell.class] == YES) { + MobilyDataCell* existCell = (MobilyDataCell*)view; + if(item.order > existCell.item.order) { + viewIndex = index; + } else if(item.order <= existCell.item.order) { + *stop = YES; + } + } + }]; + if(viewIndex != NSNotFound) { + [self.contentView insertSubview:cell atIndex:viewIndex + 1]; + } else { + [self.contentView insertSubview:cell atIndex:0]; + } + } + } else { + [queue removeLastObject]; + } + item.cell = cell; + } +} + +- (void)enqueueCellWithItem:(MobilyDataItem*)item { + MobilyDataCell* cell = item.cell; + if(cell != nil) { + NSString* identifier = item.identifier; + NSMutableArray* queue = _queueCells[identifier]; + if(queue == nil) { + _queueCells[identifier] = [NSMutableArray arrayWithObject:cell]; + } else { + [queue addObject:cell]; + } + item.cell = nil; + } +} + +- (MobilyDataItem*)itemForPoint:(CGPoint)point { + [self validateLayoutIfNeed]; + return [_container itemForPoint:point]; +} + +- (MobilyDataItem*)itemForData:(id)data { + return [_container itemForData:data]; +} + +- (MobilyDataCell*)cellForData:(id)data { + return [_container cellForData:data]; +} + +- (BOOL)isSelectedItem:(MobilyDataItem*)item { + return [_selectedItems containsObject:item]; +} + +- (BOOL)shouldSelectItem:(MobilyDataItem*)item { + if(_allowsSelection == YES) { + if(item.allowsSelection == YES) { + if([self isSelectedItem:item] == NO) { + return YES; + } + } + } + return NO; +} + +- (BOOL)shouldDeselectItem:(MobilyDataItem* __unused)item { + if([self isSelectedItem:item] == YES) { + return YES; + } + return NO; +} + +- (void)selectItem:(MobilyDataItem*)item animated:(BOOL)animated { + [self _selectItem:item user:NO animated:animated]; +} + +- (void)deselectItem:(MobilyDataItem*)item animated:(BOOL)animated { + [self _deselectItem:item user:NO animated:animated]; +} + +- (void)deselectAllItemsAnimated:(BOOL)animated { + [self _deselectAllItemsUser:NO animated:animated]; +} + +- (BOOL)isHighlightedItem:(MobilyDataItem*)item { + return [_highlightedItems containsObject:item]; +} + +- (BOOL)shouldHighlightItem:(MobilyDataItem*)item { + return item.allowsHighlighting; +} + +- (BOOL)shouldUnhighlightItem:(MobilyDataItem* __unused)item { + return YES; +} + +- (void)highlightItem:(MobilyDataItem*)item animated:(BOOL)animated { + if([_highlightedItems containsObject:item] == NO) { + if([self shouldHighlightItem:item] == YES) { + [_highlightedItems addObject:item]; + [item setHighlighted:YES animated:animated]; + } + } +} + +- (void)unhighlightItem:(MobilyDataItem*)item animated:(BOOL)animated { + if([_highlightedItems containsObject:item] == YES) { + if([self shouldUnhighlightItem:item] == YES) { + [_highlightedItems removeObject:item]; + [item setHighlighted:NO animated:animated]; + } + } +} + +- (void)unhighlightAllItemsAnimated:(BOOL)animated { + if(_highlightedItems.count > 0) { + [_highlightedItems moEach:^(MobilyDataItem* item) { + if([self shouldUnhighlightItem:item] == YES) { + [_highlightedItems removeObject:item]; + [item setHighlighted:NO animated:animated]; + } + }]; + } +} + +- (BOOL)isEditingItem:(MobilyDataItem*)item { + return [_editingItems containsObject:item]; +} + +- (BOOL)shouldBeganEditItem:(MobilyDataItem*)item { + if(_allowsEditing == YES) { + return item.allowsEditing; + } + return NO; +} + +- (BOOL)shouldEndedEditItem:(MobilyDataItem* __unused)item { + return _allowsEditing; +} + +- (void)beganEditItem:(MobilyDataItem*)item animated:(BOOL)animated { + if([_editingItems containsObject:item] == NO) { + if([self shouldBeganEditItem:item] == YES) { + if(_allowsMultipleEditing == YES) { + [_editingItems addObject:item]; + [item setEditing:YES animated:animated]; + } else { + if(_editingItems.count > 0) { + [[_editingItems copy] moEach:^(MobilyDataItem* item) { + if([self shouldEndedEditItem:item] == YES) { + [_editingItems removeObject:item]; + [item setEditing:NO animated:animated]; + } + }]; + } + [_editingItems addObject:item]; + [item setEditing:YES animated:animated]; + } + } + } +} + +- (void)endedEditItem:(MobilyDataItem*)item animated:(BOOL)animated { + if([_editingItems containsObject:item] == YES) { + if([self shouldEndedEditItem:item] == YES) { + [_editingItems removeObject:item]; + [item setEditing:NO animated:animated]; + } + } +} + +- (void)endedEditAllItemsAnimated:(BOOL)animated { + if(_editingItems.count > 0) { + [[_editingItems copy] moEach:^(MobilyDataItem* item) { + if([self shouldEndedEditItem:item] == YES) { + [_editingItems removeObject:item]; + [item setEditing:NO animated:animated]; + } + }]; + } +} + +- (void)batchUpdate:(MobilyDataViewUpdateBlock)update { + [self batchDuration:0.0f update:update complete:nil]; +} + +- (void)batchUpdate:(MobilyDataViewUpdateBlock)update complete:(MobilyDataViewCompleteBlock)complete { + [self batchDuration:0.0f update:update complete:complete]; +} + +- (void)batchDuration:(NSTimeInterval)duration update:(MobilyDataViewUpdateBlock)update { + [self batchDuration:duration update:update complete:nil]; +} + +- (void)batchDuration:(NSTimeInterval)duration update:(MobilyDataViewUpdateBlock)update complete:(MobilyDataViewCompleteBlock)complete { + if(_updating == NO) { + if(duration > MOBILY_EPSILON) { + [UIView animateWithDuration:duration + delay:0.0f + options:UIViewAnimationOptionCurveEaseInOut + animations:^{ + [self _batchUpdate:update animated:YES]; + } + completion:nil]; + [MobilyTimeout executeBlock:^{ + [self _batchComplete:^() { + if(complete != nil) { + complete(YES); + } + } animated:YES]; + } afterDelay:duration]; + } else { + [self _batchUpdate:^{ + if(update != nil) { + update(); + } + [self _batchComplete:^() { + if(complete != nil) { + complete(YES); + } + } animated:NO]; + } animated:NO]; + } + } else { + [_queueBatch addObject:[[MobilyDataBatch alloc] initWithDuration:duration update:update complete:complete]]; + } +} + +- (void)setNeedValidateLayout { + self.invalidLayout = YES; + [self setNeedsLayout]; +} + +- (void)validateLayoutIfNeed { + if(_invalidLayout == YES) { + [self _validateLayout]; + self.invalidLayout = NO; + } +} + +- (void)setNeedLayoutForVisible { + [self setNeedsLayout]; +} + +- (void)layoutForVisibleIfNeed { + [self layoutIfNeeded]; +} + +- (void)scrollToItem:(MobilyDataItem*)item scrollPosition:(MobilyDataViewPosition)scrollPosition animated:(BOOL)animated { + [self scrollToRect:[item updateFrame] scrollPosition:scrollPosition animated:animated]; +} + +- (void)scrollToRect:(CGRect)rect scrollPosition:(MobilyDataViewPosition)scrollPosition animated:(BOOL)animated { + [self validateLayoutIfNeed]; + NSUInteger vPosition = scrollPosition & (MobilyDataViewPositionTop | MobilyDataViewPositionCenteredVertically | MobilyDataViewPositionBottom); + NSUInteger hPosition = scrollPosition & (MobilyDataViewPositionLeft | MobilyDataViewPositionCenteredHorizontally | MobilyDataViewPositionRight); + CGRect viewport = self.bounds; + CGPoint offset = rect.origin; + switch(vPosition) { + case MobilyDataViewPositionCenteredVertically: { + offset.y = rect.origin.y - ((viewport.size.height * 0.5f) - (rect.size.height * 0.5f)); + break; + } + case MobilyDataViewPositionBottom: { + offset.y = rect.origin.y - (viewport.size.height - rect.size.height); + break; + } + case MobilyDataViewPositionInsideVertically: { + if(offset.y + rect.size.height > viewport.origin.y + viewport.size.height) { + offset.y = rect.origin.y - (viewport.size.height - rect.size.height); + } else if(offset.y > viewport.origin.y) { + offset.y = viewport.origin.y; + } + break; + } + } + switch(hPosition) { + case MobilyDataViewPositionCenteredHorizontally: { + offset.x = rect.origin.x - ((viewport.size.width * 0.5f) - (rect.size.width * 0.5f)); + break; + } + case MobilyDataViewPositionRight: { + offset.x = rect.origin.x - (viewport.size.width - rect.size.width); + break; + } + case MobilyDataViewPositionInsideHorizontally: { + if(offset.x + rect.size.width > viewport.origin.x + viewport.size.width) { + offset.x = rect.origin.x - (viewport.size.width - rect.size.width); + } else if(offset.x > viewport.origin.x) { + offset.x = viewport.origin.x; + } + break; + } + } + [self scrollRectToVisible:CGRectMake(offset.x, offset.y, viewport.size.width, viewport.size.height) animated:animated]; +} + +- (void)showSearchBarAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete { + [self _showSearchBarAnimated:animated velocity:_velocity complete:complete]; +} + +- (void)hideSearchBarAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete { + [self _hideSearchBarAnimated:animated velocity:_velocity complete:complete]; +} + +- (void)showTopRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete { + [self _showTopRefreshAnimated:animated velocity:_velocity complete:complete]; +} + +- (void)hideTopRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete { + [self _hideTopRefreshAnimated:animated velocity:_velocity complete:complete]; +} + +- (void)showBottomRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete { + [self _showBottomRefreshAnimated:animated velocity:_velocity complete:complete]; +} + +- (void)hideBottomRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete { + [self _hideBottomRefreshAnimated:animated velocity:_velocity complete:complete]; +} + +- (void)showLeftRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete { + [self _showLeftRefreshAnimated:animated velocity:_velocity complete:complete]; +} + +- (void)hideLeftRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete { + [self _hideLeftRefreshAnimated:animated velocity:_velocity complete:complete]; +} + +- (void)showRightRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete { + [self _showRightRefreshAnimated:animated velocity:_velocity complete:complete]; +} + +- (void)hideRightRefreshAnimated:(BOOL)animated complete:(MobilyDataViewCompleteBlock)complete { + [self _hideRightRefreshAnimated:animated velocity:_velocity complete:complete]; +} + +#pragma mark Private + +- (void)_receiveMemoryWarning { + [_queueCells moEach:^(NSString* identifier, NSArray* cells) { + for(MobilyDataCell* cell in cells) { + [cell removeFromSuperview]; + cell.view = nil; + } + }]; + [_queueCells removeAllObjects]; +} + +- (void)_pressedItem:(MobilyDataItem*)item animated:(BOOL)animated { + if(_allowsOnceSelection == YES) { + [self _selectItem:item user:YES animated:animated]; + } else { + if([self isSelectedItem:item] == NO) { + [self _selectItem:item user:YES animated:animated]; + } else { + [self _deselectItem:item user:YES animated:animated]; + } + } + [self endedEditItem:item animated:animated]; +} + +- (void)_selectItem:(MobilyDataItem*)item user:(BOOL)user animated:(BOOL)animated { + if([self shouldSelectItem:item] == YES) { + if(_allowsMultipleSelection == YES) { + [_selectedItems addObject:item]; + [item setSelected:YES animated:animated]; + if(user == YES) { + [self fireEventForIdentifier:item.identifier forKey:MobilyDataViewSelectItem byObject:item]; + } + } else { + if(_selectedItems.count > 0) { + [[_selectedItems copy] moEach:^(MobilyDataItem* item) { + [self _deselectItem:item user:user animated:animated]; + }]; + } + [_selectedItems addObject:item]; + [item setSelected:YES animated:animated]; + if(user == YES) { + [self fireEventForIdentifier:item.identifier forKey:MobilyDataViewSelectItem byObject:item]; + } + } + } +} + +- (void)_deselectItem:(MobilyDataItem*)item user:(BOOL)user animated:(BOOL)animated { + if([self shouldDeselectItem:item] == YES) { + [_selectedItems removeObject:item]; + [item setSelected:NO animated:animated]; + if(user == YES) { + [self fireEventForIdentifier:item.identifier forKey:MobilyDataViewDeselectItem byObject:item]; + } + } +} + +- (void)_deselectAllItemsUser:(BOOL)user animated:(BOOL)animated { + if(_selectedItems.count > 0) { + [[_selectedItems copy] moEach:^(MobilyDataItem* item) { + if([self shouldDeselectItem:item] == YES) { + [_selectedItems removeObject:item]; + [item setSelected:NO animated:animated]; + if(user == YES) { + [self fireEventForIdentifier:item.identifier forKey:MobilyDataViewDeselectItem byObject:item]; + } + } + }]; + } +} + +- (void)_appearItem:(MobilyDataItem*)item { + [_visibleItems addObject:item]; + [self dequeueCellWithItem:item]; +} + +- (void)_disappearItem:(MobilyDataItem*)item { + [_visibleItems removeObject:item]; + [self enqueueCellWithItem:item]; +} + +- (void)_didInsertItems:(NSArray*)items { + if(_updating == YES) { + [_insertedItems addObjectsFromArray:items]; + } + [self setNeedValidateLayout]; +} + +- (void)_didDeleteItems:(NSArray*)items { + [_visibleItems removeObjectsInArray:items]; + [_selectedItems removeObjectsInArray:items]; + [_highlightedItems removeObjectsInArray:items]; + [_editingItems removeObjectsInArray:items]; + if(_updating == YES) { + [_deletedItems addObjectsFromArray:items]; + } else { + if([self containsEventForKey:MobilyDataViewAnimateRestore] == YES) { + [self fireEventForKey:MobilyDataViewAnimateRestore byObject:items]; + for(MobilyDataItem* item in items) { + [self enqueueCellWithItem:item]; + } + } else { + for(MobilyDataItem* item in items) { + MobilyDataCell* cell = item.cell; + if(cell != nil) { + cell.moZPosition = 0.0f; + cell.alpha = 1.0f; + } + [self enqueueCellWithItem:item]; + } + } + } + [self setNeedValidateLayout]; +} + +- (void)_didReplaceOriginItems:(NSArray*)originItems withItems:(NSArray*)items { + [_visibleItems removeObjectsInArray:originItems]; + [_selectedItems removeObjectsInArray:originItems]; + [_highlightedItems removeObjectsInArray:originItems]; + [_editingItems removeObjectsInArray:originItems]; + if(_updating == YES) { + [_reloadedBeforeItems addObjectsFromArray:originItems]; + [_reloadedAfterItems addObjectsFromArray:items]; + } else { + if([self containsEventForKey:MobilyDataViewAnimateRestore] == YES) { + [self fireEventForKey:MobilyDataViewAnimateRestore byObject:items]; + for(MobilyDataItem* item in items) { + [self enqueueCellWithItem:item]; + } + } else { + for(MobilyDataItem* item in originItems) { + MobilyDataCell* cell = item.cell; + if(cell != nil) { + cell.moZPosition = 0.0f; + cell.alpha = 1.0f; + } + [self enqueueCellWithItem:item]; + } + } + } + [self setNeedValidateLayout]; +} + +- (void)_validateLayout { + CGRect layoutRect = CGRectZero; + if(_container != nil) { + layoutRect = [_container _validateLayoutForAvailableFrame:MobilyRectMakeOriginAndSize(CGPointZero, self.moFrameSize)]; + } + self.contentSize = layoutRect.size; +} + +- (void)_layoutForVisible { + CGRect bounds = self.bounds; + [_container _willLayoutForBounds:bounds]; + [_visibleItems enumerateObjectsUsingBlock:^(MobilyDataItem* item, NSUInteger itemIndex __unused, BOOL* itemStop __unused) { + [item invalidateLayoutForBounds:bounds]; + }]; + [_container _didLayoutForBounds:bounds]; +} + +- (void)_updateSuperviewConstraints { + if(_searchBar != nil) { + if(_constraintSearchBarTop == nil) { + if(_showedSearchBar == YES) { + self.constraintSearchBarTop = [NSLayoutConstraint constraintWithItem:_searchBar attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]; + } else { + self.constraintSearchBarTop = [NSLayoutConstraint constraintWithItem:_searchBar attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]; + } + } + if(_constraintSearchBarLeft == nil) { + if(_leftRefreshView != nil) { + self.constraintSearchBarLeft = [NSLayoutConstraint constraintWithItem:_searchBar attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:_leftRefreshView attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]; + } else { + self.constraintSearchBarLeft = [NSLayoutConstraint constraintWithItem:_searchBar attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]; + } + } + if(_constraintSearchBarRight == nil) { + if(_rightRefreshView != nil) { + self.constraintSearchBarRight = [NSLayoutConstraint constraintWithItem:_searchBar attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:_rightRefreshView attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]; + } else { + self.constraintSearchBarRight = [NSLayoutConstraint constraintWithItem:_searchBar attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]; + } + } + } else { + self.constraintSearchBarTop = nil; + self.constraintSearchBarLeft = nil; + self.constraintSearchBarRight = nil; + } + if(_topRefreshView != nil) { + if(_constraintTopRefreshTop == nil) { + if(_searchBar != nil) { + self.constraintTopRefreshTop = [NSLayoutConstraint constraintWithItem:_topRefreshView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:_searchBar attribute:NSLayoutAttributeBottom multiplier:1.0f constant:-_topRefreshView.size]; + } else { + self.constraintTopRefreshTop = [NSLayoutConstraint constraintWithItem:_topRefreshView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:-_topRefreshView.size]; + } + } + if(_constraintTopRefreshLeft == nil) { + self.constraintTopRefreshLeft = [NSLayoutConstraint constraintWithItem:_topRefreshView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]; + } + if(_constraintTopRefreshRight == nil) { + self.constraintTopRefreshRight = [NSLayoutConstraint constraintWithItem:_topRefreshView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]; + } + if(_constraintTopRefreshSize == nil) { + self.constraintTopRefreshSize = [NSLayoutConstraint constraintWithItem:_topRefreshView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:_topRefreshView.size]; + } + } else { + self.constraintTopRefreshTop = nil; + self.constraintTopRefreshLeft = nil; + self.constraintTopRefreshRight = nil; + self.constraintTopRefreshSize = nil; + } + if(_bottomRefreshView != nil) { + if(_constraintBottomRefreshBottom == nil) { + self.constraintBottomRefreshBottom = [NSLayoutConstraint constraintWithItem:_bottomRefreshView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0f constant:_bottomRefreshView.size]; + } + if(_constraintBottomRefreshLeft == nil) { + self.constraintBottomRefreshLeft = [NSLayoutConstraint constraintWithItem:_bottomRefreshView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]; + } + if(_constraintBottomRefreshRight == nil) { + self.constraintBottomRefreshRight = [NSLayoutConstraint constraintWithItem:_bottomRefreshView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]; + } + if(_constraintBottomRefreshSize == nil) { + self.constraintBottomRefreshSize = [NSLayoutConstraint constraintWithItem:_bottomRefreshView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:_bottomRefreshView.size]; + } + } else { + self.constraintBottomRefreshBottom = nil; + self.constraintBottomRefreshLeft = nil; + self.constraintBottomRefreshRight = nil; + self.constraintBottomRefreshSize = nil; + } + if(_leftRefreshView != nil) { + if(_constraintLeftRefreshTop == nil) { + self.constraintLeftRefreshTop = [NSLayoutConstraint constraintWithItem:_leftRefreshView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]; + } + if(_constraintLeftRefreshBottom == nil) { + self.constraintLeftRefreshBottom = [NSLayoutConstraint constraintWithItem:_leftRefreshView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; + } + if(_constraintLeftRefreshLeft == nil) { + self.constraintLeftRefreshLeft = [NSLayoutConstraint constraintWithItem:_leftRefreshView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:-_leftRefreshView.size]; + } + if(_constraintLeftRefreshSize == nil) { + self.constraintLeftRefreshSize = [NSLayoutConstraint constraintWithItem:_leftRefreshView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:_leftRefreshView.size]; + } + } else { + self.constraintLeftRefreshTop = nil; + self.constraintLeftRefreshBottom = nil; + self.constraintLeftRefreshLeft = nil; + self.constraintLeftRefreshSize = nil; + } + if(_rightRefreshView != nil) { + if(_constraintRightRefreshTop == nil) { + self.constraintRightRefreshTop = [NSLayoutConstraint constraintWithItem:_rightRefreshView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]; + } + if(_constraintRightRefreshBottom == nil) { + self.constraintRightRefreshBottom = [NSLayoutConstraint constraintWithItem:_rightRefreshView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; + } + if(_constraintRightRefreshRight == nil) { + self.constraintRightRefreshRight = [NSLayoutConstraint constraintWithItem:_rightRefreshView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:_rightRefreshView.size]; + } + if(_constraintRightRefreshSize == nil) { + self.constraintRightRefreshSize = [NSLayoutConstraint constraintWithItem:_rightRefreshView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:_rightRefreshView.size]; + } + } else { + self.constraintRightRefreshTop = nil; + self.constraintRightRefreshBottom = nil; + self.constraintRightRefreshRight = nil; + self.constraintRightRefreshSize = nil; + } + [self.superview layoutIfNeeded]; +} + +- (void)_updateInsets { + UIEdgeInsets scrollInsets = UIEdgeInsetsMake(_containerInsets.top + _searchBarInset + _refreshViewInsets.top, _containerInsets.left + _refreshViewInsets.left, _containerInsets.bottom + _refreshViewInsets.bottom, _containerInsets.right + _refreshViewInsets.right); + UIEdgeInsets contentInset = UIEdgeInsetsMake(_containerInsets.top + _searchBarInset, _containerInsets.left, _containerInsets.bottom, _containerInsets.right); + if(self.dragging == NO) { + contentInset.top += _refreshViewInsets.top; + contentInset.bottom += _refreshViewInsets.bottom; + contentInset.left += _refreshViewInsets.left; + contentInset.right += _refreshViewInsets.right; + } + self.scrollIndicatorInsets = scrollInsets; + self.contentInset = contentInset; +} + +- (void)_willBeginDragging { + self.scrollBeginPosition = self.contentOffset; + if(self.directionalLockEnabled == YES) { + self.scrollDirection = MobilyDataViewDirectionUnknown; + } + if(self.pagingEnabled == NO) { + if(_canDraggingSearchBar == NO) { + if((_searchBar != nil) && (_searchBarIteractionEnabled == YES)) { + switch(_searchBarStyle) { + case MobilyDataViewSearchBarStyleStatic: + self.canDraggingSearchBar = NO; + break; + case MobilyDataViewSearchBarStyleInside: + self.canDraggingSearchBar = ((_searchBar.searching == NO) && (_searchBar.editing == NO)); + break; + case MobilyDataViewSearchBarStyleOverlay: { + CGFloat searchBarHeight = _searchBar.moFrameHeight; + if(self.moContentSizeHeight > self.moFrameHeight + searchBarHeight) { + if(_showedSearchBar == YES) { + self.searchBarOverlayLastPosition = MAX(_searchBar.moFrameHeight, _scrollBeginPosition.y + _searchBar.moFrameHeight); + } else { + self.searchBarOverlayLastPosition = MAX(0.0f, _scrollBeginPosition.y - _searchBar.moFrameHeight); + } + self.canDraggingSearchBar = ((_searchBar.searching == NO) && (_searchBar.editing == NO)); + } + break; + } + } + } + } + if((_canDraggingTopRefresh == NO) && (_canDraggingBottomRefresh == NO) && (_canDraggingLeftRefresh == NO) && (_canDraggingRightRefresh == NO)) { + if((_topRefreshView != nil) && (_topRefreshIteractionEnabled == YES)) { + switch(_topRefreshView.state) { + case MobilyDataRefreshViewStateIdle: self.canDraggingTopRefresh = YES; break; + default: self.canDraggingTopRefresh = NO; break; + } + } + if((_bottomRefreshView != nil) && (_bottomRefreshIteractionEnabled == YES)) { + switch(_bottomRefreshView.state) { + case MobilyDataRefreshViewStateIdle: self.canDraggingBottomRefresh = YES; break; + default: self.canDraggingBottomRefresh = NO; break; + } + } + if((_leftRefreshView != nil) && (_leftRefreshIteractionEnabled == YES)) { + switch(_leftRefreshView.state) { + case MobilyDataRefreshViewStateIdle: self.canDraggingLeftRefresh = YES; break; + default: self.canDraggingLeftRefresh = NO; break; + } + } + if((_rightRefreshView != nil) && (_rightRefreshIteractionEnabled == YES)) { + switch(_rightRefreshView.state) { + case MobilyDataRefreshViewStateIdle: self.canDraggingRightRefresh = YES; break; + default: self.canDraggingRightRefresh = NO; break; + } + } + } + } + if(_container != nil) { + [_container _willBeginDragging]; + } +} + +- (void)_didScrollDragging:(BOOL)dragging decelerating:(BOOL)decelerating { + if(self.pagingEnabled == NO) { + CGSize frameSize = self.moFrameSize; + CGPoint contentOffset = self.contentOffset; + CGSize contentSize = self.contentSize; + UIEdgeInsets contentInset = self.contentInset; + UIEdgeInsets containerInsets = _containerInsets; + CGFloat searchBarHeight = _searchBar.moFrameHeight; + CGFloat searchBarInset = _searchBarInset; + UIEdgeInsets refreshViewInsets = _refreshViewInsets; + CGSize contentViewSize = self.contentView.moFrameSize; + if(self.bounces == YES) { + if(self.alwaysBounceVertical == YES) { + if(_bouncesTop == NO) { + contentOffset.y = MAX(-contentInset.top, contentOffset.y); + } + if((_bouncesBottom == NO) && (contentSize.height >= frameSize.height)) { + contentOffset.y = MIN(contentSize.height - frameSize.height + contentInset.bottom, contentOffset.y); + } + } + if(self.alwaysBounceHorizontal == YES) { + if(_bouncesLeft == NO) { + contentOffset.x = MAX(-contentInset.left, contentOffset.x); + } + if((_bouncesRight == NO) && (contentSize.width >= frameSize.width)) { + contentOffset.x = MIN(contentSize.width - frameSize.width + contentInset.right, contentOffset.x); + } + } + } + if((self.directionalLockEnabled == YES) && (dragging == YES)) { + switch(_scrollDirection) { + case MobilyDataViewDirectionUnknown: { + CGFloat dx = MOBILY_FABS(contentOffset.x - _scrollBeginPosition.x); + CGFloat dy = MOBILY_FABS(contentOffset.y - _scrollBeginPosition.y); + if(dx > dy) { + self.scrollDirection = MobilyDataViewDirectionHorizontal; + contentOffset.y = _scrollBeginPosition.y; + } else if(dx < dy) { + self.scrollDirection = MobilyDataViewDirectionVertical; + contentOffset.x = _scrollBeginPosition.x; + } + break; + } + case MobilyDataViewDirectionHorizontal: + contentOffset.y = _scrollBeginPosition.y; + break; + case MobilyDataViewDirectionVertical: + contentOffset.x = _scrollBeginPosition.x; + break; + } + } + if(_canDraggingSearchBar == YES) { + switch(_searchBarStyle) { + case MobilyDataViewSearchBarStyleStatic: + break; + case MobilyDataViewSearchBarStyleInside: { + searchBarInset = MAX(0.0f, MIN(searchBarInset - contentOffset.y, searchBarHeight)); + if(_showedSearchBar == YES) { + _constraintSearchBarTop.constant = -(searchBarHeight - searchBarInset); + } else { + _constraintSearchBarTop.constant = searchBarInset; + } + break; + } + case MobilyDataViewSearchBarStyleOverlay: { + CGFloat diff = contentOffset.y - _searchBarOverlayLastPosition; + CGFloat progress = ((_searchBarInset - diff) * 0.5f) / searchBarHeight; + searchBarInset = MAX(0.0f, MIN(searchBarHeight * progress, searchBarHeight)); + if(_showedSearchBar == YES) { + _constraintSearchBarTop.constant = -(searchBarHeight - searchBarInset); + } else { + _constraintSearchBarTop.constant = searchBarInset; + } + break; + } + } + } + if(_topRefreshView != nil) { + CGFloat progress = 0.0f; + if((_topRefreshIteractionEnabled == YES) && ((contentViewSize.height > 0.0f) || (dragging == NO))) { + CGFloat inset = containerInsets.top + searchBarInset; + if(contentOffset.y < -inset) { + progress = -(contentOffset.y + inset); + } + if((_canDraggingTopRefresh == YES) && (dragging == YES)) { + switch(_topRefreshView.state) { + case MobilyDataRefreshViewStateIdle: + if(progress > 0.0f) { + _topRefreshView.state = MobilyDataRefreshViewStatePull; + } + break; + case MobilyDataRefreshViewStatePull: + case MobilyDataRefreshViewStateRelease: + if(progress <= 0.0f) { + _topRefreshView.state = MobilyDataRefreshViewStateIdle; + } else if(progress >= _topRefreshView.threshold) { + if(_topRefreshView.state != MobilyDataRefreshViewStateRelease) { + _topRefreshView.state = MobilyDataRefreshViewStateRelease; + } + } else { + _topRefreshView.state = MobilyDataRefreshViewStatePull; + } + break; + default: + break; + } + refreshViewInsets.top = progress; + } + } + _topRefreshView.constraintOffset.constant = (progress < _topRefreshView.size) ? -(_topRefreshView.size - progress) : 0.0f; + _topRefreshView.constraintSize.constant = (progress < _topRefreshView.size) ? _topRefreshView.size : progress; + } + if(_bottomRefreshView != nil) { + CGFloat progress = 0.0f; + if((_bottomRefreshIteractionEnabled == YES) && ((contentViewSize.height >= frameSize.height) || (dragging == NO))) { + CGFloat limit = (contentViewSize.height - frameSize.height); + if(contentOffset.y > limit) { + progress = contentOffset.y - limit; + } + if((_canDraggingBottomRefresh == YES) && (dragging == YES)) { + switch(_bottomRefreshView.state) { + case MobilyDataRefreshViewStateIdle: + if(progress > 0.0f) { + _bottomRefreshView.state = MobilyDataRefreshViewStatePull; + } + break; + case MobilyDataRefreshViewStatePull: + case MobilyDataRefreshViewStateRelease: + if(progress <= 0.0f) { + _bottomRefreshView.state = MobilyDataRefreshViewStateIdle; + } else if(progress >= _bottomRefreshView.threshold) { + if(_bottomRefreshView.state != MobilyDataRefreshViewStateRelease) { + _bottomRefreshView.state = MobilyDataRefreshViewStateRelease; + } + } else { + _bottomRefreshView.state = MobilyDataRefreshViewStatePull; + } + break; + default: + break; + } + refreshViewInsets.bottom = progress; + } + } + _bottomRefreshView.constraintOffset.constant = (progress < _bottomRefreshView.size) ? (_bottomRefreshView.size - progress) : 0.0f; + _bottomRefreshView.constraintSize.constant = (progress < _bottomRefreshView.size) ? _bottomRefreshView.size : progress; + } + if(_leftRefreshView != nil) { + CGFloat progress = 0.0f; + if((_leftRefreshIteractionEnabled == YES) && ((contentViewSize.width >= 0.0f) || (dragging == NO))) { + CGFloat inset = containerInsets.left; + if(contentOffset.x < -inset) { + progress = -(contentOffset.x + inset); + } + if((_canDraggingLeftRefresh == YES) && (dragging == YES)) { + switch(_leftRefreshView.state) { + case MobilyDataRefreshViewStateIdle: + if(progress > 0.0f) { + _leftRefreshView.state = MobilyDataRefreshViewStatePull; + } + break; + case MobilyDataRefreshViewStatePull: + case MobilyDataRefreshViewStateRelease: + if(progress <= 0.0f) { + _leftRefreshView.state = MobilyDataRefreshViewStateIdle; + } else if(progress >= _leftRefreshView.threshold) { + if(_leftRefreshView.state != MobilyDataRefreshViewStateRelease) { + _leftRefreshView.state = MobilyDataRefreshViewStateRelease; + } + } else { + _leftRefreshView.state = MobilyDataRefreshViewStatePull; + } + break; + default: + break; + } + refreshViewInsets.left = progress; + } + } + _leftRefreshView.constraintOffset.constant = (progress < _leftRefreshView.size) ? -(_leftRefreshView.size - progress) : 0.0f; + _leftRefreshView.constraintSize.constant = (progress < _leftRefreshView.size) ? _leftRefreshView.size : progress; + } + if(_rightRefreshView != nil) { + CGFloat progress = 0.0f; + if((_rightRefreshIteractionEnabled == YES) && ((contentViewSize.width >= frameSize.width) || (dragging == NO))) { + CGFloat limit = (contentViewSize.width - frameSize.width); + if(contentOffset.x > limit) { + progress = contentOffset.x - limit; + } + if((_canDraggingRightRefresh == YES) && (dragging == YES)) { + switch(_rightRefreshView.state) { + case MobilyDataRefreshViewStateIdle: + if(progress > 0.0f) { + _rightRefreshView.state = MobilyDataRefreshViewStatePull; + } + break; + case MobilyDataRefreshViewStatePull: + case MobilyDataRefreshViewStateRelease: + if(progress <= 0.0f) { + _rightRefreshView.state = MobilyDataRefreshViewStateIdle; + } else if(progress >= _rightRefreshView.threshold) { + if(_rightRefreshView.state != MobilyDataRefreshViewStateRelease) { + _rightRefreshView.state = MobilyDataRefreshViewStateRelease; + } + } else { + _rightRefreshView.state = MobilyDataRefreshViewStatePull; + } + break; + default: + break; + } + refreshViewInsets.right = progress; + } + } + _rightRefreshView.constraintOffset.constant = (progress < _rightRefreshView.size) ? (_rightRefreshView.size - progress) : 0.0f; + _rightRefreshView.constraintSize.constant = (progress < _rightRefreshView.size) ? _rightRefreshView.size : progress; + } + self.contentOffset = contentOffset; + if((_searchBarInset != searchBarInset) || (UIEdgeInsetsEqualToEdgeInsets(_refreshViewInsets, refreshViewInsets) == NO)) { + _searchBarInset = searchBarInset; + _refreshViewInsets = refreshViewInsets; + [self _updateInsets]; + } + } + if(_container != nil) { + [_container _didScrollDragging:dragging decelerating:decelerating]; + } +} + +- (void)_willEndDraggingWithVelocity:(CGPoint)velocity contentOffset:(inout CGPoint*)contentOffset contentSize:(CGSize)contentSize visibleSize:(CGSize)visibleSize { + if(self.pagingEnabled == NO) { + if(_canDraggingSearchBar == YES) { + CGFloat searchBarHeight = _searchBar.moFrameHeight; + switch(_searchBarStyle) { + case MobilyDataViewSearchBarStyleStatic: + self.canDraggingSearchBar = NO; + break; + case MobilyDataViewSearchBarStyleInside: { + if(_searchBarInset >= (searchBarHeight * 0.33f)) { + contentOffset->y = MAX(-_searchBarInset, contentOffset->y - _searchBarInset); + [self _showSearchBarAnimated:YES velocity:velocity.y complete:^(BOOL finished) { + self.canDraggingSearchBar = NO; + }]; + } else { + [self _hideSearchBarAnimated:YES velocity:velocity.y complete:^(BOOL finished) { + self.canDraggingSearchBar = NO; + }]; + } + break; + } + case MobilyDataViewSearchBarStyleOverlay: { + if(_searchBarInset >= (searchBarHeight * 0.33f)) { + contentOffset->y = MAX(-_searchBarInset, contentOffset->y - _searchBarInset); + [self _showSearchBarAnimated:YES velocity:velocity.y complete:^(BOOL finished) { + self.canDraggingSearchBar = NO; + }]; + } else { + [self _hideSearchBarAnimated:YES velocity:velocity.y complete:^(BOOL finished) { + self.canDraggingSearchBar = NO; + }]; + } + break; + } + } + } + if(_canDraggingTopRefresh == YES) { + switch(_topRefreshView.state) { + case MobilyDataRefreshViewStateRelease: { + if([self containsEventForKey:MobilyDataViewTopRefreshTriggered] == YES) { + [self _showTopRefreshAnimated:YES velocity:velocity.y complete:^(BOOL finished __unused) { + [self fireEventForKey:MobilyDataViewTopRefreshTriggered byObject:_topRefreshView]; + self.canDraggingTopRefresh = NO; + }]; + } else { + [self _hideTopRefreshAnimated:YES velocity:velocity.y complete:^(BOOL finished) { + self.canDraggingTopRefresh = NO; + }]; + } + break; + } + case MobilyDataRefreshViewStatePull: { + [self _hideTopRefreshAnimated:YES velocity:velocity.y complete:^(BOOL finished) { + self.canDraggingTopRefresh = NO; + }]; + break; + } + default: + self.canDraggingTopRefresh = NO; + break; + } + } + if(_canDraggingBottomRefresh == YES) { + switch(_bottomRefreshView.state) { + case MobilyDataRefreshViewStateRelease: { + if([self containsEventForKey:MobilyDataViewBottomRefreshTriggered] == YES) { + [self _showBottomRefreshAnimated:YES velocity:velocity.y complete:^(BOOL finished __unused) { + [self fireEventForKey:MobilyDataViewBottomRefreshTriggered byObject:_bottomRefreshView]; + self.canDraggingBottomRefresh = NO; + }]; + } else { + [self _hideBottomRefreshAnimated:YES velocity:velocity.y complete:^(BOOL finished) { + self.canDraggingBottomRefresh = NO; + }]; + } + break; + } + case MobilyDataRefreshViewStatePull: { + [self _hideBottomRefreshAnimated:YES velocity:velocity.y complete:^(BOOL finished) { + self.canDraggingBottomRefresh = NO; + }]; + break; + } + default: + self.canDraggingBottomRefresh = NO; + break; + } + } + if(_canDraggingLeftRefresh == YES) { + switch(_leftRefreshView.state) { + case MobilyDataRefreshViewStateRelease: { + if([self containsEventForKey:MobilyDataViewLeftRefreshTriggered] == YES) { + [self _showLeftRefreshAnimated:YES velocity:velocity.x complete:^(BOOL finished __unused) { + [self fireEventForKey:MobilyDataViewLeftRefreshTriggered byObject:_leftRefreshView]; + self.canDraggingLeftRefresh = NO; + }]; + } else { + [self _hideLeftRefreshAnimated:YES velocity:velocity.x complete:^(BOOL finished) { + self.canDraggingLeftRefresh = NO; + }]; + } + break; + } + case MobilyDataRefreshViewStatePull: { + [self _hideLeftRefreshAnimated:YES velocity:velocity.x complete:^(BOOL finished) { + self.canDraggingLeftRefresh = NO; + }]; + break; + } + default: + self.canDraggingLeftRefresh = NO; + break; + } + } + if(_canDraggingRightRefresh == YES) { + switch(_rightRefreshView.state) { + case MobilyDataRefreshViewStateRelease: { + if([self containsEventForKey:MobilyDataViewRightRefreshTriggered] == YES) { + [self _showRightRefreshAnimated:YES velocity:velocity.x complete:^(BOOL finished __unused) { + [self fireEventForKey:MobilyDataViewRightRefreshTriggered byObject:_rightRefreshView]; + self.canDraggingRightRefresh = NO; + }]; + } else { + [self _hideRightRefreshAnimated:YES velocity:velocity.x complete:^(BOOL finished) { + self.canDraggingRightRefresh = NO; + }]; + } + break; + } + case MobilyDataRefreshViewStatePull: { + [self _hideRightRefreshAnimated:YES velocity:velocity.x complete:^(BOOL finished) { + self.canDraggingRightRefresh = NO; + }]; + break; + } + default: + self.canDraggingRightRefresh = NO; + break; + } + } + } + if(_container != nil) { + [_container _willEndDraggingWithVelocity:velocity contentOffset:contentOffset contentSize:contentSize visibleSize:visibleSize]; + } +} + +- (void)_didEndDraggingWillDecelerate:(BOOL)decelerate { + if(decelerate == NO) { + if(_pageControl != nil) { + [_pageControl updatePageNumberForScrollView:self]; + } + } + if(_container != nil) { + [_container _didEndDraggingWillDecelerate:decelerate]; + } +} + +- (void)_willBeginDecelerating { + if(_container != nil) { + [_container _willBeginDecelerating]; + } +} + +- (void)_didEndDecelerating { + if(_pageControl != nil) { + [_pageControl updatePageNumberForScrollView:self]; + } + if(_container != nil) { + [_container _didEndDecelerating]; + } +} + +- (void)_didEndScrollingAnimation { + if(_pageControl != nil) { + [_pageControl updatePageNumberForScrollView:self]; + } + if(_container != nil) { + [_container _didEndScrollingAnimation]; + } +} + +- (void)_showSearchBarAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete { + _showedSearchBar = YES; + + CGFloat from = _searchBarInset; + CGFloat to = _searchBar.moFrameHeight; + self.constraintSearchBarTop = nil; + [self _updateSuperviewConstraints]; + + if(animated == YES) { + [UIView animateWithDuration:MOBILY_FABS(from - to) / MOBILY_FABS(velocity) + delay:0.01f + options:(UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut) + animations:^{ + self.searchBarInset = to; + [self.superview layoutIfNeeded]; + } completion:^(BOOL finished) { + if(complete != nil) { + complete(finished); + } + }]; + } else { + self.searchBarInset = to; + if(complete != nil) { + complete(YES); + } + } +} + +- (void)_hideSearchBarAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete { + _showedSearchBar = NO; + + CGFloat from = _searchBarInset; + CGFloat to = 0.0f; + self.constraintSearchBarTop = nil; + [self _updateSuperviewConstraints]; + + if(animated == YES) { + [UIView animateWithDuration:MOBILY_FABS(from - to) / MOBILY_FABS(velocity) + delay:0.01f + options:(UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut) + animations:^{ + self.searchBarInset = to; + [self.superview layoutIfNeeded]; + } completion:^(BOOL finished) { + if(complete != nil) { + complete(finished); + } + }]; + } else { + self.searchBarInset = to; + if(complete != nil) { + complete(YES); + } + } +} + +- (void)_showTopRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete { + [_topRefreshView _showAnimated:animated velocity:velocity complete:complete]; +} + +- (void)_hideTopRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete { + [_topRefreshView _hideAnimated:animated velocity:velocity complete:complete]; +} + +- (void)_showBottomRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete { + [_bottomRefreshView _showAnimated:animated velocity:velocity complete:complete]; +} + +- (void)_hideBottomRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete { + [_bottomRefreshView _hideAnimated:animated velocity:velocity complete:complete]; +} + +- (void)_showLeftRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete { + [_leftRefreshView _showAnimated:animated velocity:velocity complete:complete]; +} + +- (void)_hideLeftRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete { + [_leftRefreshView _hideAnimated:animated velocity:velocity complete:complete]; +} + +- (void)_showRightRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete { + [_rightRefreshView _showAnimated:animated velocity:velocity complete:complete]; +} + +- (void)_hideRightRefreshAnimated:(BOOL)animated velocity:(CGFloat)velocity complete:(MobilyDataViewCompleteBlock)complete { + [_rightRefreshView _hideAnimated:animated velocity:velocity complete:complete]; +} + +- (void)_batchUpdate:(MobilyDataViewUpdateBlock)update animated:(BOOL)animated { + self.updating = YES; + self.animating = animated; + [_container _didBeginUpdateAnimated:animated]; + if(update != nil) { + update(); + } + [self validateLayoutIfNeed]; + [self _layoutForVisible]; + if(_reloadedBeforeItems.count > 0) { + if([self containsEventForKey:MobilyDataViewAnimateReplaceOut] == YES) { + [self fireEventForKey:MobilyDataViewAnimateReplaceOut byObject:_reloadedBeforeItems]; + } else { + for(MobilyDataItem* item in _reloadedBeforeItems) { + MobilyDataCell* cell = item.cell; + if(cell != nil) { + [UIView performWithoutAnimation:^{ + cell.moZPosition = -1.0f; + cell.alpha = 1.0f; + }]; + cell.alpha = 0.0f; + } + } + } + } + if(_reloadedAfterItems.count > 0) { + if([self containsEventForKey:MobilyDataViewAnimateReplaceIn] == YES) { + [self fireEventForKey:MobilyDataViewAnimateReplaceIn byObject:_reloadedAfterItems]; + } else { + for(MobilyDataItem* item in _reloadedAfterItems) { + MobilyDataCell* cell = item.cell; + if(cell != nil) { + [UIView performWithoutAnimation:^{ + cell.moZPosition = -1.0f; + cell.alpha = 0.0f; + }]; + cell.alpha = 1.0f; + } + } + } + } + if(_insertedItems.count > 0) { + if([self containsEventForKey:MobilyDataViewAnimateInsert] == YES) { + [self fireEventForKey:MobilyDataViewAnimateInsert byObject:_insertedItems]; + } else { + for(MobilyDataItem* item in _insertedItems) { + MobilyDataCell* cell = item.cell; + if(cell != nil) { + [UIView performWithoutAnimation:^{ + cell.moZPosition = -1.0f; + cell.alpha = 0.0f; + }]; + cell.alpha = 1.0f; + } + } + } + } + if(_deletedItems.count > 0) { + if([self containsEventForKey:MobilyDataViewAnimateDelete] == YES) { + [self fireEventForKey:MobilyDataViewAnimateDelete byObject:_deletedItems]; + } else { + for(MobilyDataItem* item in _deletedItems) { + MobilyDataCell* cell = item.cell; + if(cell != nil) { + [UIView performWithoutAnimation:^{ + cell.moZPosition = -1.0f; + cell.alpha = 1.0f; + }]; + cell.alpha = 0.0f; + } + } + } + } +} + +- (void)_batchComplete:(MobilyDataViewUpdateBlock)complete animated:(BOOL)animated { + if(_reloadedBeforeItems.count > 0) { + if([self containsEventForKey:MobilyDataViewAnimateRestore] == YES) { + [self fireEventForKey:MobilyDataViewAnimateRestore byObject:_reloadedBeforeItems]; + for(MobilyDataItem* item in _reloadedBeforeItems) { + [self _disappearItem:item]; + } + } else { + for(MobilyDataItem* item in _reloadedBeforeItems) { + MobilyDataCell* cell = item.cell; + if(cell != nil) { + cell.moZPosition = 0.0f; + cell.alpha = 1.0f; + } + [self _disappearItem:item]; + } + } + [_reloadedBeforeItems removeAllObjects]; + } + if(_reloadedAfterItems.count > 0) { + for(MobilyDataItem* item in _reloadedAfterItems) { + MobilyDataCell* cell = item.cell; + if(cell != nil) { + cell.moZPosition = 0.0f; + cell.alpha = 1.0f; + } + } + [_reloadedAfterItems removeAllObjects]; + } + if(_insertedItems.count > 0) { + for(MobilyDataItem* item in _insertedItems) { + MobilyDataCell* cell = item.cell; + if(cell != nil) { + cell.moZPosition = 0.0f; + cell.alpha = 1.0f; + } + } + [_insertedItems removeAllObjects]; + } + if(_deletedItems.count > 0) { + if([self containsEventForKey:MobilyDataViewAnimateRestore] == YES) { + [self fireEventForKey:MobilyDataViewAnimateRestore byObject:_deletedItems]; + for(MobilyDataItem* item in _deletedItems) { + [self _disappearItem:item]; + } + } else { + for(MobilyDataItem* item in _deletedItems) { + MobilyDataCell* cell = item.cell; + if(cell != nil) { + cell.moZPosition = 0.0f; + cell.alpha = 1.0f; + } + [self _disappearItem:item]; + } + } + [_deletedItems removeAllObjects]; + } + [_container _didEndUpdateAnimated:animated]; + self.animating = NO; + self.updating = NO; + [self _layoutForVisible]; + if(complete != nil) { + complete(); + } + if(_queueBatch.count > 0) { + MobilyDataBatch* batch = _queueBatch.firstObject; + [_queueBatch removeObjectAtIndex:0]; + [self batchDuration:batch.duration update:batch.update complete:batch.complete]; + } +} + +#pragma mark MobilySearchBarDelegate + +- (void)searchBarBeginSearch:(MobilySearchBar*)searchBar { + [self fireEventForKey:MobilyDataViewSearchBegin byObject:nil]; + [_container searchBarBeginSearch:searchBar]; +} + +- (void)searchBarEndSearch:(MobilySearchBar*)searchBar { + [self fireEventForKey:MobilyDataViewSearchEnd byObject:nil]; + [_container searchBarEndSearch:searchBar]; +} + +- (void)searchBarBeginEditing:(MobilySearchBar*)searchBar { + [self fireEventForKey:MobilyDataViewSearchBeginEditing byObject:nil]; + [_container searchBarBeginEditing:searchBar]; +} + +- (void)searchBar:(MobilySearchBar*)searchBar textChanged:(NSString*)textChanged { + [self fireEventForKey:MobilyDataViewSearchTextChanged byObject:textChanged]; + [_container searchBar:searchBar textChanged:textChanged]; +} + +- (void)searchBarEndEditing:(MobilySearchBar*)searchBar { + [self fireEventForKey:MobilyDataViewSearchEndEditing byObject:nil]; + [_container searchBarEndEditing:searchBar]; +} + +- (void)searchBarPressedClear:(MobilySearchBar*)searchBar { + [self fireEventForKey:MobilyDataViewSearchPressedClear byObject:nil]; + [_container searchBarPressedClear:searchBar]; +} + +- (void)searchBarPressedReturn:(MobilySearchBar*)searchBar { + [self fireEventForKey:MobilyDataViewSearchPressedReturn byObject:nil]; + [_container searchBarPressedReturn:searchBar]; +} + +- (void)searchBarPressedCancel:(MobilySearchBar*)searchBar { + [self fireEventForKey:MobilyDataViewSearchPressedCancel byObject:nil]; + [_container searchBarPressedCancel:searchBar]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyDataContentView + +#pragma mark NSKeyValueCoding + +#pragma mark Init / Free + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + self.clipsToBounds = YES; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyDataBatch + +#pragma mark Init / Free + +- (instancetype)initWithDuration:(NSTimeInterval)duration update:(MobilyDataViewUpdateBlock)update complete:(MobilyDataViewCompleteBlock)complete { + self = [super init]; + if(self != nil) { + _duration = duration; + _update = update; + _complete = complete; + [self setup]; + } + return self; +} + +- (void)setup { +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyDataViewDelegateProxy + +#pragma mark Init / Free + +- (instancetype)initWithDataView:(MobilyDataView*)view { + self = [super init]; + if(self != nil) { + self.view = view; + } + return self; +} + +- (void)dealloc { + self.view = nil; + self.delegate = nil; +} + +#pragma mark NSObject + +- (BOOL)respondsToSelector:(SEL)selector { + return (([_delegate respondsToSelector:selector] == YES) || ([super respondsToSelector:selector] == YES)); +} + +- (void)forwardInvocation:(NSInvocation*)invocation { + [invocation invokeWithTarget:_delegate]; +} + +#pragma mark UIScrollViewDelegate + +- (void)scrollViewWillBeginDragging:(UIScrollView*)scrollView { + [_view _willBeginDragging]; + if([_delegate respondsToSelector:_cmd] == YES) { + [_delegate scrollViewDidEndDecelerating:scrollView]; + } +} + +- (void)scrollViewDidScroll:(UIScrollView*)scrollView { + [_view _didScrollDragging:_view.dragging decelerating:_view.decelerating]; + if([_delegate respondsToSelector:_cmd] == YES) { + [_delegate scrollViewDidScroll:scrollView]; + } +} + +- (void)scrollViewWillEndDragging:(UIScrollView*)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint*)targetContentOffset { + CGFloat vx = (MOBILY_FABS(velocity.x) > MOBILY_EPSILON) ? (velocity.x * 1000.0f) : _view.velocity; + CGFloat vy = (MOBILY_FABS(velocity.y) > MOBILY_EPSILON) ? (velocity.y * 1000.0f) : _view.velocity; + CGFloat nvx = MAX(_view.velocityMin, MIN(MOBILY_FABS(vx), _view.velocityMax)); + CGFloat nvy = MAX(_view.velocityMin, MIN(MOBILY_FABS(vy), _view.velocityMax)); + [_view _willEndDraggingWithVelocity:CGPointMake((vx > MOBILY_EPSILON) ? nvx : -nvx, (vy > MOBILY_EPSILON) ? nvy : -nvy) contentOffset:targetContentOffset contentSize:scrollView.contentSize visibleSize:_view.moBoundsSize]; + if([_delegate respondsToSelector:_cmd] == YES) { + [_delegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset]; + } +} + +- (void)scrollViewDidEndDragging:(UIScrollView*)scrollView willDecelerate:(BOOL)decelerate { + [_view _didEndDraggingWillDecelerate:decelerate]; + if([_delegate respondsToSelector:_cmd] == YES) { + [_delegate scrollViewDidEndDragging:scrollView willDecelerate:decelerate]; + } +} + +- (void)scrollViewWillBeginDecelerating:(UIScrollView*)scrollView { + [_view _willBeginDecelerating]; + if([_delegate respondsToSelector:_cmd] == YES) { + [_delegate scrollViewDidScroll:scrollView]; + } +} + +- (void)scrollViewDidEndDecelerating:(UIScrollView*)scrollView { + [_view _didEndDecelerating]; + if([_delegate respondsToSelector:_cmd] == YES) { + [_delegate scrollViewDidEndDecelerating:scrollView]; + } +} + +- (void)scrollViewDidEndScrollingAnimation:(UIScrollView*)scrollView { + [_view _didEndScrollingAnimation]; + if([_delegate respondsToSelector:_cmd] == YES) { + [_delegate scrollViewDidEndScrollingAnimation:scrollView]; + } +} + +- (BOOL)scrollViewShouldScrollToTop:(UIScrollView*)scrollView { + if([_delegate respondsToSelector:_cmd] == YES) { + return [_delegate scrollViewShouldScrollToTop:scrollView]; + } + return YES; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +NSString* MobilyDataViewSelectItem = @"MobilyDataViewSelectItem"; +NSString* MobilyDataViewDeselectItem = @"MobilyDataViewDeselectItem"; + +/*--------------------------------------------------*/ + +NSString* MobilyDataViewSearchBegin = @"MobilyDataViewSearchBegin"; +NSString* MobilyDataViewSearchEnd = @"MobilyDataViewSearchEnd"; +NSString* MobilyDataViewSearchBeginEditing = @"MobilyDataViewSearchBeginEditing"; +NSString* MobilyDataViewSearchTextChanged = @"MobilyDataViewSearchTextChanged"; +NSString* MobilyDataViewSearchEndEditing = @"MobilyDataViewSearchEndEditing"; +NSString* MobilyDataViewSearchPressedClear = @"MobilyDataViewSearchPressedClear"; +NSString* MobilyDataViewSearchPressedReturn = @"MobilyDataViewSearchPressedReturn"; +NSString* MobilyDataViewSearchPressedCancel = @"MobilyDataViewSearchPressedCancel"; + +/*--------------------------------------------------*/ + +NSString* MobilyDataViewTopRefreshTriggered = @"MobilyDataViewTopRefreshTriggered"; +NSString* MobilyDataViewBottomRefreshTriggered = @"MobilyDataViewBottomRefreshTriggered"; +NSString* MobilyDataViewLeftRefreshTriggered = @"MobilyDataViewLeftRefreshTriggered"; +NSString* MobilyDataViewRightRefreshTriggered = @"MobilyDataViewRightRefreshTriggered"; + +/*--------------------------------------------------*/ + +NSString* MobilyDataViewAnimateRestore = @"MobilyDataViewAnimateRestore"; +NSString* MobilyDataViewAnimateInsert = @"MobilyDataViewAnimateInsert"; +NSString* MobilyDataViewAnimateDelete = @"MobilyDataViewAnimateDelete"; +NSString* MobilyDataViewAnimateReplaceOut = @"MobilyDataViewAnimateReplaceOut"; +NSString* MobilyDataViewAnimateReplaceIn = @"MobilyDataViewAnimateReplaceIn"; + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDateField.h b/Sources/MobilyCore/MobilyDateField.h new file mode 100644 index 0000000..4d1bcb6 --- /dev/null +++ b/Sources/MobilyCore/MobilyDateField.h @@ -0,0 +1,58 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyDateField : MobilyTextField< MobilyBuilderObject > + +@property(nonatomic, readwrite, assign) IBInspectable UIDatePickerMode datePickerMode; +@property(nonatomic, readwrite, strong) IBInspectable NSDateFormatter* dateFormatter; +@property(nonatomic, readwrite, strong) IBInspectable NSLocale* locale; +@property(nonatomic, readwrite, copy) IBInspectable NSCalendar* calendar; +@property(nonatomic, readwrite, strong) IBInspectable NSTimeZone* timeZone; +@property(nonatomic, readwrite, strong) IBInspectable NSDate* minimumDate; +@property(nonatomic, readwrite, strong) IBInspectable NSDate* maximumDate; +@property(nonatomic, readwrite, strong) IBInspectable NSDate* date; +@property(nonatomic, readwrite, assign) IBInspectable NSUInteger minuteInterval; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)setDate:(NSDate*)date animated:(BOOL)animated; + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/ViewFieldDate/MobilyViewFieldDate.m b/Sources/MobilyCore/MobilyDateField.m similarity index 68% rename from Classes/UI/ViewFieldDate/MobilyViewFieldDate.m rename to Sources/MobilyCore/MobilyDateField.m index 5e1a58a..2033cff 100644 --- a/Classes/UI/ViewFieldDate/MobilyViewFieldDate.m +++ b/Sources/MobilyCore/MobilyDateField.m @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -32,12 +32,14 @@ /* OTHER DEALINGS IN THE SOFTWARE. */ /* */ /*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ -#import "MobilyViewFieldDate.h" +#import /*--------------------------------------------------*/ -@interface MobilyViewFieldDate () +@interface MobilyDateField () @property(nonatomic, readwrite, strong) UIDatePicker* pickerView; @@ -47,50 +49,50 @@ - (void)setDate:(NSDate*)date animated:(BOOL)animated emitted:(BOOL)emitted; /*--------------------------------------------------*/ -@implementation MobilyViewFieldDate +@implementation MobilyDateField #pragma mark NSKeyValueCoding -#pragma mark Standart +#pragma mark Init / Free -- (void)dealloc { - [self setPickerView:nil]; +- (void)setup { + [super setup]; - [self setDateFormatter:nil]; - [self setDate:nil]; - - MOBILY_SAFE_DEALLOC; + self.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"RU"]; + self.calendar = [NSCalendar currentCalendar]; + self.date = [NSDate date]; } -#pragma mark Public - -- (void)setupView { - [super setupView]; +- (void)dealloc { + self.pickerView = nil; - [self setLocale:[NSLocale currentLocale]]; - [self setCalendar:[NSCalendar currentCalendar]]; - [self setDate:[NSDate date]]; + self.dateFormatter = nil; + self.date = nil; } +#pragma mark Public + - (void)didBeginEditing { [super didBeginEditing]; if(_pickerView == nil) { - [self setPickerView:[[UIDatePicker alloc] init]]; + self.pickerView = [UIDatePicker new]; if(_pickerView != nil) { - [_pickerView setDatePickerMode:_datePickerMode]; - [_pickerView addTarget:self action:@selector(changedDate:) forControlEvents:UIControlEventValueChanged]; + _pickerView.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"RU"]; + _pickerView.datePickerMode = _datePickerMode; + _pickerView.minuteInterval = _minuteInterval; + [_pickerView addTarget:self action:@selector(changedDate) forControlEvents:UIControlEventValueChanged]; } - [self setInputView:_pickerView]; + self.inputView = _pickerView; } if(_pickerView != nil) { - [_pickerView setLocale:_locale]; - [_pickerView setCalendar:_calendar]; - [_pickerView setTimeZone:_timeZone]; - [_pickerView setMinimumDate:_minimumDate]; - [_pickerView setMaximumDate:_maximumDate]; + _pickerView.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"RU"]; + _pickerView.calendar = _calendar; + _pickerView.timeZone = _timeZone; + _pickerView.minimumDate = _minimumDate; + _pickerView.maximumDate = _maximumDate; if(_date != nil) { - [_pickerView setDate:_date]; + _pickerView.date = _date; } } } @@ -98,7 +100,7 @@ - (void)didBeginEditing { - (void)didEndEditing { [super didEndEditing]; - [self setDate:[_pickerView date] animated:YES emitted:YES]; + [self setDate:_pickerView.date animated:YES emitted:YES]; } #pragma mark Property @@ -108,7 +110,7 @@ - (void)setDatePickerMode:(UIDatePickerMode)datePickerMode { _datePickerMode = datePickerMode; if(_pickerView != nil) { - [_pickerView setDatePickerMode:_datePickerMode]; + _pickerView.datePickerMode = _datePickerMode; } } } @@ -119,12 +121,12 @@ - (void)setDateFormatter:(NSDateFormatter*)dateFormatter { if(_date != nil) { if(_dateFormatter != nil) { - [self setText:[_dateFormatter stringFromDate:_date]]; + self.text = [_dateFormatter stringFromDate:_date]; } else { - [self setText:[_date description]]; + self.text = _date.description; } } else { - [self setText:@""]; + self.text = @""; } } } @@ -135,7 +137,7 @@ - (void)setLocale:(NSLocale*)locale { if([self isEditing] == YES) { if(_date != nil) { - [_pickerView setLocale:_locale]; + _pickerView.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"RU"]; } } } @@ -147,7 +149,7 @@ - (void)setCalendar:(NSCalendar*)calendar { if([self isEditing] == YES) { if(_date != nil) { - [_pickerView setCalendar:_calendar]; + _pickerView.calendar = _calendar; } } } @@ -159,7 +161,7 @@ - (void)setTimeZone:(NSTimeZone*)timeZone { if([self isEditing] == YES) { if(_date != nil) { - [_pickerView setTimeZone:_timeZone]; + _pickerView.timeZone = _timeZone; } } } @@ -171,7 +173,7 @@ - (void)setMinimumDate:(NSDate*)minimumDate { if([self isEditing] == YES) { if(_date != nil) { - [_pickerView setMinimumDate:_minimumDate]; + _pickerView.minimumDate = _minimumDate; } } } @@ -183,7 +185,7 @@ - (void)setMaximumDate:(NSDate*)maximumDate { if([self isEditing] == YES) { if(_date != nil) { - [_pickerView setMaximumDate:_maximumDate]; + _pickerView.maximumDate = _maximumDate; } } } @@ -194,7 +196,19 @@ - (void)setDate:(NSDate*)date { } - (void)setDate:(NSDate*)date animated:(BOOL)animated { - [self setDate:date animated:YES emitted:NO]; + [self setDate:date animated:animated emitted:NO]; +} + +- (void)setMinuteInterval:(NSUInteger)minuteInterval { + if(_minuteInterval != minuteInterval) { + _minuteInterval = minuteInterval; + + if([self isEditing] == YES) { + if(_pickerView != nil) { + _pickerView.minuteInterval = _minuteInterval; + } + } + } } #pragma mark Private @@ -205,12 +219,12 @@ - (void)setDate:(NSDate*)date animated:(BOOL)animated emitted:(BOOL)emitted { if(_date != nil) { if(_dateFormatter != nil) { - [self setText:[_dateFormatter stringFromDate:_date]]; + self.text = [_dateFormatter stringFromDate:_date]; } else { - [self setText:[_date description]]; + self.text = _date.description; } } else { - [self setText:@""]; + self.text = @""; } if([self isEditing] == YES) { if(_date != nil) { @@ -223,8 +237,8 @@ - (void)setDate:(NSDate*)date animated:(BOOL)animated emitted:(BOOL)emitted { } } -- (void)changedDate:(id)sender { - [self setDate:[_pickerView date] animated:YES emitted:YES]; +- (void)changedDate { + [self setDate:_pickerView.date animated:YES emitted:YES]; } @end diff --git a/Classes/Core/MobilyCore.h b/Sources/MobilyCore/MobilyDefines.h similarity index 69% rename from Classes/Core/MobilyCore.h rename to Sources/MobilyCore/MobilyDefines.h index 4aeb2c0..007f323 100644 --- a/Classes/Core/MobilyCore.h +++ b/Sources/MobilyCore/MobilyDefines.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -34,6 +34,7 @@ /*--------------------------------------------------*/ #import +#import #import #import @@ -43,12 +44,24 @@ /*--------------------------------------------------*/ +#include + +/*--------------------------------------------------*/ + #ifdef DEBUG # define MOBILY_DEBUG #endif /*--------------------------------------------------*/ +#ifdef MOBILY_SOURCE +# define MOBILY_REQUIRES_PROPERTY_DEFINITIONS NS_REQUIRES_PROPERTY_DEFINITIONS +#else +# define MOBILY_REQUIRES_PROPERTY_DEFINITIONS +#endif + +/*--------------------------------------------------*/ + #define MOBILY_DEBUG_LEVEL_ERROR 0x01 #define MOBILY_DEBUG_LEVEL_WARNING 0x02 #define MOBILY_DEBUG_LEVEL_INFO 0x04 @@ -68,30 +81,22 @@ # define MOBILY_DEVICE #endif -/*--------------------------------------------------*/ -#if __has_feature(objc_arc) -# define MOBILY_SAFE_AUTORELEASE(object) object -# define MOBILY_SAFE_RETAIN(object) object -# define MOBILY_SAFE_RELEASE(object) object = nil -# define MOBILY_SAFE_BRIDGE(class, object) (__bridge class)object -# define MOBILY_SAFE_DEALLOC /**/ -# define MOBILY_WEAK __weak -# define MOBILY_UNSAFE __unsafe_unretained +#ifdef CGFLOAT_IS_DOUBLE +# define MOBILY_EPSILON DBL_EPSILON #else -# define MOBILY_SAFE_AUTORELEASE(object) [object autorelease] -# define MOBILY_SAFE_RETAIN(object) [object retain] -# define MOBILY_SAFE_RELEASE(object) [object release]; object = nil -# define MOBILY_SAFE_BRIDGE(class, object) (class)object -# define MOBILY_SAFE_DEALLOC [super dealloc] -# define MOBILY_WEAK /**/ -# define MOBILY_UNSAFE __unsafe_unretained +# define MOBILY_EPSILON MOBILY_EPSILON #endif -#define MOBILY_SAFE_SETTER(object, value) MOBILY_SAFE_RELEASE(object); object = MOBILY_SAFE_RETAIN(value) /*--------------------------------------------------*/ -#define MOBILY_SWAP(v1, v2) { id t = v1; v1 = v2; v2 = t; } -#define MOBILY_SWAP_SAFE(v1, v2) { id t = MOBILY_SAFE_RETAIN(v1); v1 = v2; v2 = t; MOBILY_SAFE_RELEASE(t); } +#define MOBILY_COS(X) __tg_cos(__tg_promote1((X))(X)) +#define MOBILY_SIN(X) __tg_sin(__tg_promote1((X))(X)) +#define MOBILY_ATAN2(X, Y) __tg_atan2(__tg_promote2((X), (Y))(X), __tg_promote2((X), (Y))(Y)) +#define MOBILY_POW(X, Y) __tg_pow(__tg_promote2((X), (Y))(X), __tg_promote2((X), (Y))(Y)) +#define MOBILY_SQRT(X) __tg_sqrt(__tg_promote1((X))(X)) +#define MOBILY_FABS(X) __tg_fabs(__tg_promote1((X))(X)) +#define MOBILY_CEIL(X) __tg_ceil(__tg_promote1((X))(X)) +#define MOBILY_FLOOR(X) __tg_floor(__tg_promote1((X))(X)) /*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDialogController.h b/Sources/MobilyCore/MobilyDialogController.h new file mode 100644 index 0000000..6ccb48d --- /dev/null +++ b/Sources/MobilyCore/MobilyDialogController.h @@ -0,0 +1,83 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@class MobilyDialogController; + +/*--------------------------------------------------*/ + +typedef void(^MobilyDialogControllerBlock)(MobilyDialogController* dialogController); + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyDialogController : UIViewController < MobilyObject > + +@property(nonatomic, readwrite, assign) CGFloat animationDuration; + +@property(nonatomic, readwrite, assign, getter=isBackgroundBlurred) BOOL backgroundBlurred; +@property(nonatomic, readwrite, assign) CGFloat backgroundBlurRadius; +@property(nonatomic, readwrite, assign) NSUInteger backgroundBlurIterations; +@property(nonatomic, readwrite, strong) UIColor* backgroundColor; +@property(nonatomic, readwrite, strong) UIColor* backgroundTintColor; +@property(nonatomic, readwrite, assign) CGFloat backgroundAlpha; + +@property(nonatomic, readwrite, assign) CGSize contentSize; +@property(nonatomic, readwrite, assign) CGSize contentMinSize; +@property(nonatomic, readwrite, assign) CGSize contentMaxSize; + +@property(nonatomic, readwrite, copy) MobilyDialogControllerBlock touchedOutsideContent; +@property(nonatomic, readwrite, copy) MobilyDialogControllerBlock dismiss; + +- (instancetype)initWithContentController:(UIViewController*)contentController; + +- (void)presentController:(UIViewController*)controller withCompletion:(MobilySimpleBlock)completion; +- (void)presentWithCompletion:(MobilySimpleBlock)completion; +- (void)dismissWithCompletion:(MobilySimpleBlock)completion; + +@end + +/*--------------------------------------------------*/ + +@interface UIViewController (MobilyDialogController) + +@property(nonatomic, readwrite, weak) MobilyDialogController* moDialogController; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDialogController.m b/Sources/MobilyCore/MobilyDialogController.m new file mode 100644 index 0000000..b962c39 --- /dev/null +++ b/Sources/MobilyCore/MobilyDialogController.m @@ -0,0 +1,488 @@ + /*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyDialogController () < UIGestureRecognizerDelegate > + +@property(nonatomic, readwrite, strong) UIWindow* presentedWindow; +@property(nonatomic, readwrite, weak) UIWindow* presentingWindow; +@property(nonatomic, readwrite, strong) UIViewController* presentingController; + +@property(nonatomic, readwrite, strong) MobilyBlurView* backgroundView; +@property(nonatomic, readwrite, strong) UIViewController* contentController; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintContentViewCenterX; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintContentViewCenterY; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintContentViewWidth; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintContentViewHeight; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintContentViewMinWidth; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintContentViewMinHeight; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintContentViewMaxWidth; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintContentViewMaxHeight; +@property(nonatomic, readwrite, strong) UITapGestureRecognizer* tapGesture; + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyDialogController + +#pragma mark Synthesize + +@synthesize presentedWindow = _presentedWindow; +@synthesize presentingWindow = _presentingWindow; +@synthesize presentingController = _presentingController; +@synthesize backgroundView = _backgroundView; +@synthesize contentController = _contentController; +@synthesize constraintContentViewCenterX = _constraintContentViewCenterX; +@synthesize constraintContentViewCenterY = _constraintContentViewCenterY; +@synthesize constraintContentViewWidth = _constraintContentViewWidth; +@synthesize constraintContentViewHeight = _constraintContentViewHeight; +@synthesize constraintContentViewMinWidth = _constraintContentViewMinWidth; +@synthesize constraintContentViewMinHeight = _constraintContentViewMinHeight; +@synthesize constraintContentViewMaxWidth = _constraintContentViewMaxWidth; +@synthesize constraintContentViewMaxHeight = _constraintContentViewMaxHeight; +@synthesize tapGesture = _tapGesture; +@synthesize animationDuration = _animationDuration; +@synthesize backgroundBlurred = _backgroundBlurred; +@synthesize backgroundBlurRadius = _backgroundBlurRadius; +@synthesize backgroundBlurIterations = _backgroundBlurIterations; +@synthesize backgroundColor = _backgroundColor; +@synthesize backgroundTintColor = _backgroundTintColor; +@synthesize backgroundAlpha = _backgroundAlpha; +@synthesize contentSize = _contentSize; +@synthesize contentMinSize = _contentMinSize; +@synthesize contentMaxSize = _contentMaxSize; +@synthesize touchedOutsideContent = _touchedOutsideContent; +@synthesize dismiss = _dismiss; + +#pragma mark Init / Free + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithNibName:(NSString*)nib bundle:(NSBundle*)bundle { + self = [super initWithNibName:nib bundle:bundle]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithContentController:(UIViewController*)contentController { + self = [super initWithNibName:nil bundle:nil]; + if(self != nil) { + _contentController = contentController; + _contentController.moDialogController = self; + [self setup]; + } + return self; +} + +- (void)setup { + _animationDuration = 0.4f; + _backgroundBlurred = YES; + _backgroundBlurRadius = 20.0f; + _backgroundBlurIterations = 4; + _backgroundColor = nil; + _backgroundTintColor = [UIColor colorWithWhite:0.5f alpha:1.0f]; + _backgroundAlpha = 1.0f; +} + +#pragma mark Property + +- (void)setPresentingController:(UIViewController*)presentingController { + if(_presentingController != presentingController) { + _presentingController = presentingController; + if(self.isViewLoaded == YES) { + [self setNeedsStatusBarAppearanceUpdate]; + } + } +} + +- (void)setPresentedWindow:(UIWindow*)presentedWindow { + if(_presentedWindow != presentedWindow) { + if((_presentingWindow != nil) && (_presentedWindow != nil)) { + [_presentingWindow makeKeyAndVisible]; + } + _presentedWindow = presentedWindow; + if(_presentedWindow != nil) { + _presentedWindow.windowLevel = _presentingWindow.windowLevel + 0.01f; + _presentedWindow.backgroundColor = [UIColor clearColor]; + _presentedWindow.rootViewController = self; + [_presentedWindow makeKeyAndVisible]; + [_presentedWindow layoutIfNeeded]; + } + } +} + +- (void)setBackgroundView:(MobilyBlurView*)backgroundView { + if(_backgroundView != backgroundView) { + if(_backgroundView != nil) { + [_backgroundView removeFromSuperview]; + } + _backgroundView = backgroundView; + if(_backgroundView != nil) { + _backgroundView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; + _backgroundView.underlyingView = _presentingWindow.rootViewController.view; + _backgroundView.blurEnabled = _backgroundBlurred; + _backgroundView.blurRadius = _backgroundBlurRadius; + _backgroundView.blurIterations = _backgroundBlurIterations; + _backgroundView.backgroundColor = _backgroundColor; + _backgroundView.tintColor = _backgroundTintColor; + _backgroundView.alpha = _backgroundAlpha; + [self.view addSubview:_backgroundView]; + } + } +} + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintContentViewCenterX, constraintContentViewCenterX, self.view, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintContentViewCenterY, constraintContentViewCenterY, self.view, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintContentViewWidth, constraintContentViewWidth, self.view, { +}, { + _constraintContentViewWidth.constant = _contentSize.width; +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintContentViewHeight, constraintContentViewHeight, self.view, { +}, { + _constraintContentViewHeight.constant = _contentSize.height; +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintContentViewMinWidth, constraintContentViewMinWidth, self.view, { +}, { + _constraintContentViewMinWidth.constant = _contentMinSize.width; +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintContentViewMinHeight, constraintContentViewMinHeight, self.view, { +}, { + _constraintContentViewMinHeight.constant = _contentMinSize.height; +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintContentViewMaxWidth, constraintContentViewMaxWidth, self.view, { +}, { + _constraintContentViewMaxWidth.constant = _contentMaxSize.width; +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintContentViewMaxHeight, constraintContentViewMaxHeight, self.view, { +}, { + _constraintContentViewMaxHeight.constant = _contentMaxSize.height; +}) + +- (void)setTapGesture:(UITapGestureRecognizer*)tapGesture { + if(_tapGesture != tapGesture) { + if(_tapGesture != nil) { + [self.view removeGestureRecognizer:_tapGesture]; + } + _tapGesture = tapGesture; + if(_tapGesture != nil) { + [self.view addGestureRecognizer:_tapGesture]; + _tapGesture.delegate = self; + } + + } +} + +- (void)setBackgroundBlurred:(BOOL)backgroundBlurred { + if(_backgroundBlurred != backgroundBlurred) { + _backgroundBlurred = backgroundBlurred; + if(self.isViewLoaded == YES) { + _backgroundView.blurEnabled = _backgroundBlurred; + } + } +} + +- (void)setBackgroundBlurRadius:(CGFloat)backgroundBlurRadius { + if(_backgroundBlurRadius != backgroundBlurRadius) { + _backgroundBlurRadius = backgroundBlurRadius; + if(self.isViewLoaded == YES) { + _backgroundView.blurRadius = _backgroundBlurRadius; + } + } +} + +- (void)setBackgroundBlurIterations:(NSUInteger)backgroundBlurIterations { + if(_backgroundBlurIterations != backgroundBlurIterations) { + _backgroundBlurIterations = backgroundBlurIterations; + if(self.isViewLoaded == YES) { + _backgroundView.blurIterations = _backgroundBlurIterations; + } + } +} + +- (void)setBackgroundColor:(UIColor*)backgroundColor { + if([_backgroundColor isEqual:backgroundColor] == NO) { + _backgroundColor = backgroundColor; + if(self.isViewLoaded == YES) { + _backgroundView.backgroundColor = _backgroundColor; + } + } +} + +- (void)setBackgroundTintColor:(UIColor*)backgroundTintColor { + if([_backgroundTintColor isEqual:backgroundTintColor] == NO) { + _backgroundTintColor = backgroundTintColor; + if(self.isViewLoaded == YES) { + _backgroundView.tintColor = _backgroundTintColor; + } + } +} + +- (void)setContentSize:(CGSize)contentSize { + if(CGSizeEqualToSize(_contentSize, contentSize) == NO) { + _contentSize = contentSize; + if(self.isViewLoaded == YES) { + [self _updateConstraintContentView]; + } + } +} + +- (void)setContentMinSize:(CGSize)contentMinSize { + if(CGSizeEqualToSize(_contentMinSize, contentMinSize) == NO) { + _contentMinSize = contentMinSize; + if(self.isViewLoaded == YES) { + [self _updateConstraintContentView]; + } + } +} + +- (void)setContentMaxSize:(CGSize)contentMaxSize { + if(CGSizeEqualToSize(_contentMaxSize, contentMaxSize) == NO) { + _contentMaxSize = contentMaxSize; + if(self.isViewLoaded == YES) { + [self _updateConstraintContentView]; + } + } +} + +#pragma mark UIViewController + +- (BOOL)prefersStatusBarHidden { + if(self.presentingController != nil) { + return [self.presentingController prefersStatusBarHidden]; + } + return [self.contentController prefersStatusBarHidden]; +} + +- (UIStatusBarStyle)preferredStatusBarStyle { + if(self.presentingController != nil) { + return [self.presentingController preferredStatusBarStyle]; + } + return [self.contentController preferredStatusBarStyle]; +} + +- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { + if(self.presentingController != nil) { + return [self.presentingController preferredStatusBarUpdateAnimation]; + } + return [self.contentController preferredStatusBarUpdateAnimation]; +} + +- (BOOL)shouldAutorotate { + if(self.presentingController != nil) { + return [self.presentingController shouldAutorotate]; + } + return [self.contentController shouldAutorotate]; +} + +- (NSUInteger)supportedInterfaceOrientations { + if(self.presentingController != nil) { + return [self.presentingController supportedInterfaceOrientations]; + } + return [self.contentController supportedInterfaceOrientations]; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { + if(self.presentingController != nil) { + return [self.presentingController shouldAutorotateToInterfaceOrientation:interfaceOrientation]; + } + return [self.contentController shouldAutorotateToInterfaceOrientation:interfaceOrientation]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(pressedBackground:)]; + self.backgroundView = [[MobilyBlurView alloc] initWithFrame:self.view.bounds]; + + [self addChildViewController:self.contentController]; + self.contentController.view.translatesAutoresizingMaskIntoConstraints = NO; + self.contentController.view.frame = self.view.bounds; + [self.view addSubview:self.contentController.view]; + [self.contentController didMoveToParentViewController:self]; + + [self _updateConstraintContentView]; +} + +#pragma mark Public + +- (void)presentController:(UIViewController*)controller withCompletion:(MobilySimpleBlock)completion { + self.presentingWindow = UIApplication.sharedApplication.keyWindow; + self.presentingController = controller; + self.presentedWindow = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds]; + self.view.userInteractionEnabled = YES; + self.view.alpha = 0.0; + + self.backgroundView.blurRadius = (_backgroundBlurred == YES) ? 0.0f : _backgroundBlurRadius; + [UIView animateWithDuration:self.animationDuration animations:^{ + self.backgroundView.blurRadius = (_backgroundBlurred == YES) ? _backgroundBlurRadius : _backgroundBlurRadius; + self.view.alpha = 1.0; + } completion:^(BOOL finished) { + self.tapGesture.enabled = YES; + if(completion != nil) { + completion(); + } + }]; +} + +- (void)presentWithCompletion:(MobilySimpleBlock)completion { + [self presentController:UIApplication.sharedApplication.keyWindow.rootViewController withCompletion:completion]; +} + +- (void)dismissWithCompletion:(MobilySimpleBlock)completion { + self.tapGesture.enabled = NO; + [UIView animateWithDuration:self.animationDuration animations:^{ + self.backgroundView.blurRadius = (_backgroundBlurred == YES) ? 0.0f : _backgroundBlurRadius; + self.view.alpha = 0.0; + } completion:^(BOOL finished) { + self.presentedWindow = nil; + if(self.dismiss != nil) { + self.dismiss(self); + } + if(completion != nil) { + completion(); + } + }]; +} + +#pragma mark Private + +- (void)_updateConstraintContentView { + self.constraintContentViewCenterX = [NSLayoutConstraint constraintWithItem:self.contentController.view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]; + self.constraintContentViewCenterY = [NSLayoutConstraint constraintWithItem:self.contentController.view attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]; + if(_contentSize.width > MOBILY_EPSILON) { + self.constraintContentViewWidth = [NSLayoutConstraint constraintWithItem:self.contentController.view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:0.0f]; + self.constraintContentViewMinWidth = nil; + self.constraintContentViewMaxWidth = nil; + } else { + if(_contentMinSize.width > MOBILY_EPSILON) { + self.constraintContentViewMinWidth = [NSLayoutConstraint constraintWithItem:self.contentController.view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:0.0f]; + } else { + self.constraintContentViewMinWidth = nil; + } + if(_contentMaxSize.width > MOBILY_EPSILON) { + self.constraintContentViewMaxWidth = [NSLayoutConstraint constraintWithItem:self.contentController.view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:0.0f]; + } else { + self.constraintContentViewMaxWidth = nil; + } + self.constraintContentViewWidth = nil; + } + if(_contentSize.height > MOBILY_EPSILON) { + self.constraintContentViewHeight = [NSLayoutConstraint constraintWithItem:self.contentController.view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:0.0f]; + self.constraintContentViewMinHeight = nil; + self.constraintContentViewMaxHeight = nil; + } else { + if(_contentMinSize.height > MOBILY_EPSILON) { + self.constraintContentViewMinHeight = [NSLayoutConstraint constraintWithItem:self.contentController.view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:0.0f]; + } else { + self.constraintContentViewMinHeight = nil; + } + if(_contentMaxSize.height > MOBILY_EPSILON) { + self.constraintContentViewMaxHeight = [NSLayoutConstraint constraintWithItem:self.contentController.view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationLessThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:0.0f]; + } else { + self.constraintContentViewMaxHeight = nil; + } + self.constraintContentViewHeight = nil; + } +} + +#pragma mark Actions + +- (IBAction)pressedBackground:(id)sender { + if(self.touchedOutsideContent != nil) { + self.touchedOutsideContent(self); + } else { + [self dismissWithCompletion:nil]; + } +} + +#pragma mark UIGestureRecognizerDelegate + +- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldReceiveTouch:(UITouch*)touch { + return (CGRectContainsPoint(self.contentController.view.bounds, [touch locationInView:self.contentController.view]) == NO); +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UIViewController (MobilyDialogController) + +- (void)setMoDialogController:(MobilyDialogController*)moDialogController { + objc_setAssociatedObject(self, @selector(moDialogController), moDialogController, OBJC_ASSOCIATION_ASSIGN); +} + +- (MobilyDialogController*)moDialogController { + MobilyDialogController* controller = objc_getAssociatedObject(self, @selector(moDialogController)); + if(controller == nil) { + controller = self.parentViewController.moDialogController; + } + return controller; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDownloader.h b/Sources/MobilyCore/MobilyDownloader.h new file mode 100644 index 0000000..b679a06 --- /dev/null +++ b/Sources/MobilyCore/MobilyDownloader.h @@ -0,0 +1,88 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +typedef void (^MobilyDownloaderCompleteBlock)(id entry, NSURL* url); +typedef void (^MobilyDownloaderFailureBlock)(NSURL* url); + +/*--------------------------------------------------*/ + +@protocol MobilyDownloaderDelegate; + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyDownloader : NSObject< MobilyObject > + +@property(nonatomic, readwrite, weak) id< MobilyDownloaderDelegate > delegate; +@property(nonatomic, readonly, strong) MobilyTaskManager* taskManager; +@property(nonatomic, readonly, strong) MobilyCache* cache; + ++ (instancetype)shared; + +- (instancetype)initWithDelegate:(id< MobilyDownloaderDelegate >)delegate; + +- (void)setup NS_REQUIRES_SUPER; + +- (BOOL)isExistEntryByUrl:(NSURL*)url; +- (BOOL)setEntry:(id)entry byUrl:(NSURL*)url; +- (void)removeEntryByUrl:(NSURL*)url; +- (id)entryByUrl:(NSURL*)url; + +- (void)cleanup; + +- (void)downloadWithUrl:(NSURL*)url byTarget:(id)target completeSelector:(SEL)completeSelector failureSelector:(SEL)failureSelector; +- (void)downloadWithUrl:(NSURL*)url byTarget:(id)target completeBlock:(MobilyDownloaderCompleteBlock)completeBlock failureBlock:(MobilyDownloaderFailureBlock)failureBlock; +- (void)cancelByUrl:(NSURL*)url; +- (void)cancelByTarget:(id)target; + +@end + +/*--------------------------------------------------*/ + +@protocol MobilyDownloaderDelegate < NSObject > + +@optional +- (NSData*)downloader:(MobilyDownloader*)downloader dataForUrl:(NSURL*)url; +- (id)downloader:(MobilyDownloader*)downloader entryFromData:(NSData*)data; +- (NSData*)downloader:(MobilyDownloader*)downloader entryToData:(id)entry; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyDownloader.m b/Sources/MobilyCore/MobilyDownloader.m new file mode 100644 index 0000000..5450322 --- /dev/null +++ b/Sources/MobilyCore/MobilyDownloader.m @@ -0,0 +1,393 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +typedef void (^MobilyDownloaderBlock)(); + +/*--------------------------------------------------*/ + +@interface MobilyDownloader () { + __weak id< MobilyDownloaderDelegate > _delegate; + MobilyTaskManager* _taskManager; + MobilyCache* _cache; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyDownloaderTask : MobilyTask { + __weak MobilyDownloader* _downloader; + __weak id< MobilyDownloaderDelegate > _downloaderDelegate; + __weak MobilyCache* _downloaderCache; + id _target; + NSURL* _url; + id _entry; + NSUInteger _countErrors; + id< MobilyEvent > _completeEvent; + id< MobilyEvent > _failureEvent; +} + +@property(nonatomic, readonly, strong) id target; +@property(nonatomic, readonly, strong) NSURL* url; + +- (instancetype)initWithDownloader:(MobilyDownloader*)downloader url:(NSURL*)url target:(id)target; +- (instancetype)initWithDownloader:(MobilyDownloader*)downloader url:(NSURL*)url target:(id)target completeSelector:(SEL)completeSelector failureSelector:(SEL)failureSelector; +- (instancetype)initWithDownloader:(MobilyDownloader*)downloader url:(NSURL*)url target:(id)target completeBlock:(MobilyDownloaderCompleteBlock)completeBlock failureBlock:(MobilyDownloaderFailureBlock)failureBlock; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#define MOBILY_LOADER_MAX_CONCURRENT_TASK 5 + +/*--------------------------------------------------*/ + +@implementation MobilyDownloader + +#pragma mark Synthesize + +@synthesize delegate = _delegate; +@synthesize taskManager = _taskManager; +@synthesize cache = _cache; + +#pragma mark Singleton + ++ (instancetype)shared { + static id shared = nil; + if(shared == nil) { + @synchronized(self) { + if(shared == nil) { + shared = [self new]; + } + } + } + return shared; +} + +#pragma mark Init / Free + +- (instancetype)init { + return [self initWithDelegate:nil]; +} + +- (instancetype)initWithDelegate:(id< MobilyDownloaderDelegate >)delegate { + self = [super init]; + if(self != nil) { + _delegate = delegate; + _taskManager = [MobilyTaskManager new]; + if(_taskManager != nil) { + _taskManager.maxConcurrentTask = MOBILY_LOADER_MAX_CONCURRENT_TASK; + } + _cache = [MobilyCache shared]; + + [self setup]; + } + return self; +} + +- (void)setup { +} + +#pragma mark Public + +- (BOOL)isExistEntryByUrl:(NSURL*)url { + return ([_cache cacheDataForKey:url.absoluteString] != nil); +} + +- (BOOL)setEntry:(id)entry byUrl:(NSURL*)url { + NSData* data = nil; + if(entry != nil) { + if([_delegate respondsToSelector:@selector(downloader:entryToData:)] == YES) { + data = [_delegate downloader:self entryToData:entry]; + } else if([entry isKindOfClass:NSData.class] == YES) { + data = entry; + } + if(data != nil) { + [_cache setCacheData:data forKey:url.absoluteString]; + } + } + return (data != nil); +} + +- (void)removeEntryByUrl:(NSURL*)url { + [_cache removeCacheDataForKey:url.absoluteString]; +} + +- (id)entryByUrl:(NSURL*)url { + id entry = nil; + id data = [_cache cacheDataForKey:url.absoluteString]; + if(data != nil) { + if([_delegate respondsToSelector:@selector(downloader:entryFromData:)] == YES) { + entry = [_delegate downloader:self entryFromData:data]; + } else { + entry = data; + } + } + return entry; +} + +- (void)cleanup { + [_taskManager cancelAllTasks]; + [_cache removeAllCachedData]; +} + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +- (void)downloadWithUrl:(NSURL*)url byTarget:(id)target completeSelector:(SEL)completeSelector failureSelector:(SEL)failureSelector { + if([url.absoluteString length] > 0) { + id entry = nil; + NSData* data = [_cache cacheDataForKey:url.absoluteString]; + if(data != nil) { + if([_delegate respondsToSelector:@selector(downloader:entryFromData:)] == YES) { + entry = [_delegate downloader:self entryFromData:data]; + } else { + entry = data; + } + } + if(entry == nil) { + MobilyDownloaderTask* task = [[MobilyDownloaderTask alloc] initWithDownloader:self url:url target:target completeSelector:completeSelector failureSelector:failureSelector]; + if(task != nil) { + [_taskManager updating]; + [_taskManager addTask:task]; + [_taskManager updated]; + } else { + if([target respondsToSelector:failureSelector] == YES) { + [target performSelector:failureSelector withObject:url]; + } + } + } else { + if([target respondsToSelector:completeSelector] == YES) { + [target performSelector:completeSelector withObject:entry withObject:url]; + } + } + } else { + if([target respondsToSelector:failureSelector] == YES) { + [target performSelector:failureSelector withObject:url]; + } + } +} +#pragma clang diagnostic pop + +- (void)downloadWithUrl:(NSURL*)url byTarget:(id)target completeBlock:(MobilyDownloaderCompleteBlock)completeBlock failureBlock:(MobilyDownloaderFailureBlock)failureBlock { + if([url.absoluteString length] > 0) { + id entry = nil; + NSData* data = [_cache cacheDataForKey:url.absoluteString]; + if(data != nil) { + if([_delegate respondsToSelector:@selector(downloader:entryFromData:)] == YES) { + entry = [_delegate downloader:self entryFromData:data]; + } else { + entry = data; + } + } + if(entry == nil) { + MobilyDownloaderTask* task = [[MobilyDownloaderTask alloc] initWithDownloader:self url:url target:target completeBlock:completeBlock failureBlock:failureBlock]; + if(task != nil) { + [_taskManager updating]; + [_taskManager addTask:task]; + [_taskManager updated]; + } else { + if(failureBlock != nil) { + failureBlock(url); + } + } + } else { + if(completeBlock != nil) { + completeBlock(entry, url); + } + } + } else { + if(failureBlock != nil) { + failureBlock(url); + } + } +} + +- (void)cancelByUrl:(NSURL*)url { + [_taskManager enumirateTasksUsingBlock:^(MobilyDownloaderTask* task, BOOL* stop __unused) { + if([task.url isEqual:url] == YES) { + [task cancel]; + } + }]; +} + +- (void)cancelByTarget:(id)target { + [_taskManager enumirateTasksUsingBlock:^(MobilyDownloaderTask* task, BOOL* stop __unused) { + if(task.target == target) { + [task cancel]; + } + }]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#define MOBILY_LOADER_TASK_ERROR_LIMITS 5 +#define MOBILY_LOADER_TASK_IMAGE_DELAY 1.0f + +/*--------------------------------------------------*/ + +@implementation MobilyDownloaderTask + +#pragma mark Synthesize + +@synthesize target = _target; +@synthesize url = _url; + +#pragma mark Init / Free + +- (instancetype)initWithDownloader:(MobilyDownloader*)downloader url:(NSURL*)url target:(id)target { + self = [super init]; + if(self != nil) { + _downloader = downloader; + _downloaderDelegate = _downloader.delegate; + _downloaderCache = _downloader.cache; + _target = target; + _url = url; + } + return self; +} + +- (instancetype)initWithDownloader:(MobilyDownloader*)downloader url:(NSURL*)url target:(id)target completeSelector:(SEL)completeSelector failureSelector:(SEL)failureSelector { + self = [self initWithDownloader:downloader url:url target:target]; + if(self != nil) { + _completeEvent = [MobilyEventSelector eventWithTarget:target action:completeSelector inMainThread:YES]; + _failureEvent = [MobilyEventSelector eventWithTarget:target action:failureSelector inMainThread:YES]; + } + return self; +} + +- (instancetype)initWithDownloader:(MobilyDownloader*)downloader url:(NSURL*)url target:(id)target completeBlock:(MobilyDownloaderCompleteBlock)completeBlock failureBlock:(MobilyDownloaderFailureBlock)failureBlock { + self = [self initWithDownloader:downloader url:url target:target]; + if(self != nil) { + _completeEvent = [MobilyEventBlock eventWithBlock:^id(id entry, NSURL* url) { + if(completeBlock != nil) { + completeBlock(entry, url); + } + return nil; + } inMainQueue:YES]; + _failureEvent = [MobilyEventBlock eventWithBlock:^id(id sender __unused, NSURL* url) { + if(failureBlock != nil) { + failureBlock(url); + } + return nil; + } inMainQueue:YES]; + } + return self; +} + +- (void)setup { + [super setup]; +} + +#pragma mark MobilyTask + +- (void)working { + [super working]; + + id entry = nil; + NSData* data = [_downloaderCache cacheDataForKey:_url.absoluteString]; + if(data != nil) { + if([_downloaderDelegate respondsToSelector:@selector(downloader:entryFromData:)] == YES) { + entry = [_downloaderDelegate downloader:_downloader entryFromData:data]; + } else { + entry = data; + } + } + if(entry == nil) { + if([_downloaderDelegate respondsToSelector:@selector(downloader:dataForUrl:)] == YES) { + data = [_downloaderDelegate downloader:_downloader dataForUrl:_url]; + } else { + UIApplication.sharedApplication.networkActivityIndicatorVisible = YES; + data = [NSData dataWithContentsOfURL:_url]; + UIApplication.sharedApplication.networkActivityIndicatorVisible = NO; + } + if(data != nil) { + if([_downloaderDelegate respondsToSelector:@selector(downloader:entryFromData:)] == YES) { + entry = [_downloaderDelegate downloader:_downloader entryFromData:data]; + } else { + entry = data; + } + if(entry != nil) { + [_downloaderCache setCacheData:data forKey:_url.absoluteString]; + _entry = entry; + } + } else { + if(_countErrors < MOBILY_LOADER_TASK_ERROR_LIMITS) { + _countErrors = _countErrors + 1; + [self setNeedRework]; + } +#if defined(MOBILY_DEBUG) + NSLog(@"Failure load:%@", _url); +#endif + [NSThread sleepForTimeInterval:MOBILY_LOADER_TASK_IMAGE_DELAY]; + } + } else { + _entry = entry; + } +} + +- (void)didComplete { + [super didComplete]; + + if(_entry != nil) { + [_completeEvent fireSender:_entry object:_url]; + } else { + [_failureEvent fireSender:self object:_url]; + } +} + +- (void)cancel { + _completeEvent = nil; + _failureEvent = nil; + [super cancel]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyEvent+Private.h b/Sources/MobilyCore/MobilyEvent+Private.h new file mode 100644 index 0000000..cee4aa5 --- /dev/null +++ b/Sources/MobilyCore/MobilyEvent+Private.h @@ -0,0 +1,71 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyEventSelector () { +@protected + __weak id _target; + SEL _action; + __weak NSThread* _safeThread; +} + +- (void)_safeFireParams:(NSMutableDictionary*)params; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyEventBlock () { +@protected + MobilyEventBlockType _block; + dispatch_queue_t _safeQueue; +} + +@end + +/*--------------------------------------------------*/ + +@interface MobilyEvents () { +@protected + id _defaultGroup; + NSMutableDictionary* _groupsEvents; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyEvent.h b/Sources/MobilyCore/MobilyEvent.h new file mode 100644 index 0000000..6caa44e --- /dev/null +++ b/Sources/MobilyCore/MobilyEvent.h @@ -0,0 +1,136 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef id (^MobilyEventBlockType)(id sender, id object); + +/*--------------------------------------------------*/ + +@protocol MobilyEvent < MobilyObject, NSCoding > + +- (id)fireSender:(id)sender object:(id)object; + +@end + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyEventSelector : NSObject< MobilyEvent > + +@property(nonatomic, readonly, weak) id target; +@property(nonatomic, readonly, assign) SEL action; + ++ (id)eventWithTarget:(id)target action:(SEL)action; ++ (id)eventWithTarget:(id)target action:(SEL)action inMainThread:(BOOL)inMainThread; ++ (id)eventWithTarget:(id)target action:(SEL)action inCurrentThread:(BOOL)inCurrentThread; +- (instancetype)initWithTarget:(id)target action:(SEL)action thread:(NSThread*)thread; + +- (void)setup NS_REQUIRES_SUPER; + +@end + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyEventBlock : NSObject< MobilyEvent > + +@property(nonatomic, readonly, copy) MobilyEventBlockType block; + ++ (id)eventWithBlock:(MobilyEventBlockType)block; ++ (id)eventWithBlock:(MobilyEventBlockType)block inMainQueue:(BOOL)inMainQueue; ++ (id)eventWithBlock:(MobilyEventBlockType)block inCurrentQueue:(BOOL)inCurrentQueue; +- (instancetype)initWithBlock:(MobilyEventBlockType)block queue:(dispatch_queue_t)queue; + +- (void)setup NS_REQUIRES_SUPER; + +@end + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyEvents: NSObject< MobilyObject > + +@property(nonatomic, readwrite, strong) id defaultGroup; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)addEventWithTarget:(id)target action:(SEL)action forKey:(id)key; +- (void)addEventWithTarget:(id)target action:(SEL)action forGroup:(id)group forKey:(id)key; +- (void)addEventWithBlock:(MobilyEventBlockType)block forKey:(id)key; +- (void)addEventWithBlock:(MobilyEventBlockType)block forGroup:(id)group forKey:(id)key; +- (void)addEvent:(id< MobilyEvent >)event forKey:(id)key; +- (void)addEvent:(id< MobilyEvent >)event forGroup:(id)group forKey:(id)key; +- (void)removeEventForKey:(id)key; +- (void)removeEventInGroup:(id)group forKey:(id)key; +- (void)removeEventsForGroup:(id)group; +- (void)removeAllEvents; + +- (BOOL)containsEventForKey:(id)key; +- (BOOL)containsEventInGroup:(id)group forKey:(id)key; + +- (void)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object; +- (void)fireEventInGroup:(id)group forKey:(id)key bySender:(id)sender byObject:(id)object; +- (id)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault; +- (id)fireEventInGroup:(id)group forKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault; + +@end + +/*--------------------------------------------------*/ + +#define MOBILY_DEFINE_VALIDATE_EVENT(name) \ +- (id)validate##name:(id)value { \ + if([value isKindOfClass:NSString.class] == YES) { \ + SEL action = NSSelectorFromString(value); \ + if(action != nil) { \ + id target = [self objectForSelector:action]; \ + if(target != nil) { \ + value = [MobilyEventSelector eventWithTarget:target action:action]; \ + } else { \ + NSLog(@"Failure bind event %@=\"%@\"", @#name, value); \ + } \ + } else { \ + NSLog(@"Unknown selector %@=\"%@\"", @#name, value); \ + } \ + } \ + if([value conformsToProtocol:@protocol(MobilyEvent)] == YES) { \ + return value; \ + } \ + return nil; \ +} + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyEvent.m b/Sources/MobilyCore/MobilyEvent.m new file mode 100644 index 0000000..eba31e2 --- /dev/null +++ b/Sources/MobilyCore/MobilyEvent.m @@ -0,0 +1,332 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyEventSelector + +#pragma mark Synthesize + +@synthesize target = _target; +@synthesize action = _action; + +#pragma mark Init / Free + ++ (id)eventWithTarget:(id)target action:(SEL)action { + return [[self alloc] initWithTarget:target action:action thread:nil]; +} + ++ (id)eventWithTarget:(id)target action:(SEL)action inMainThread:(BOOL)inMainThread { + return [[self alloc] initWithTarget:target action:action thread:(inMainThread == YES) ? [NSThread mainThread] : nil]; +} + ++ (id)eventWithTarget:(id)target action:(SEL)action inCurrentThread:(BOOL)inCurrentThread { + return [[self alloc] initWithTarget:target action:action thread:(inCurrentThread == YES) ? [NSThread currentThread] : nil]; +} + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super init]; + if(self != nil) { + _action = NSSelectorFromString([coder decodeObjectForKey:@"action"]); + [self setup]; + } + return self; +} + +- (instancetype)initWithTarget:(id)target action:(SEL)action thread:(NSThread*)thread { + self = [super init]; + if(self != nil) { + _target = target; + _action = action; + _safeThread = thread; + [self setup]; + } + return self; +} + +- (void)setup { +} + +#pragma mark NSCoding + +- (void)encodeWithCoder:(NSCoder*)coder { + [coder encodeObject:NSStringFromSelector(_action) forKey:@"action"]; +} + +#pragma mark Public + +- (id)fireSender:(id)sender object:(id)object { + id result = nil; + NSMethodSignature* signature = [_target methodSignatureForSelector:_action]; + if(signature != nil) { + NSUInteger numberOfArguments = signature.numberOfArguments; + NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature]; + if(invocation != nil) { + invocation.target = _target; + invocation.selector = _action; + if(numberOfArguments > 2) { + if(sender != nil) { + [invocation setArgument:&sender atIndex:2]; + if(object != nil) { + if(numberOfArguments > 3) { + [invocation setArgument:&object atIndex:3]; + } + } + } else { + if(object != nil) { + [invocation setArgument:&object atIndex:2]; + } + } + [invocation retainArguments]; + } + if(_safeThread != nil) { + [self performSelector:@selector(_safeFireParams:) onThread:_safeThread withObject:invocation waitUntilDone:YES]; + } else { + [invocation invoke]; + } + if(signature.methodReturnLength == sizeof(id)) { + [invocation getReturnValue:&result]; + } + } + } + return result; +} + +#pragma mark Private + +- (void)_safeFireParams:(NSInvocation*)invocation { + [invocation invoke]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyEventBlock + +#pragma mark Synthesize + +@synthesize block = _block; + +#pragma mark Init / Free + ++ (id)eventWithBlock:(MobilyEventBlockType)block { + return [[self alloc] initWithBlock:block queue:nil]; +} + ++ (id)eventWithBlock:(MobilyEventBlockType)block inMainQueue:(BOOL)inMainQueue { + return [[self alloc] initWithBlock:block queue:(inMainQueue == YES) ? dispatch_get_main_queue() : nil]; +} + ++ (id)eventWithBlock:(MobilyEventBlockType)block inCurrentQueue:(BOOL)inCurrentQueue { + return [[self alloc] initWithBlock:block queue:(inCurrentQueue == YES) ? dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) : nil]; +} + +- (instancetype)initWithCoder:(NSCoder* __unused)coder { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithBlock:(MobilyEventBlockType)block queue:(dispatch_queue_t)queue { + self = [super init]; + if(self != nil) { + _block = block; + _safeQueue = queue; + [self setup]; + } + return self; +} + +- (void)setup { +} + +#pragma mark NSCoding + +- (void)encodeWithCoder:(NSCoder* __unused)coder { +} + +#pragma mark Public + +- (id)fireSender:(id)sender object:(id)object { + if(_safeQueue != nil) { + dispatch_queue_t currentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + if(currentQueue != _safeQueue) { + __block id result = nil; + dispatch_async(_safeQueue, ^{ + result = _block(sender, object); + }); + return result; + } + } + return _block(sender, object); +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyEvents + +#pragma mark Synthesize + +@synthesize defaultGroup = _defaultGroup; + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + _defaultGroup = NSNull.null; + _groupsEvents = NSMutableDictionary.dictionary; +} + +- (void)dealloc { +} + +#pragma mark Public + +- (void)addEventWithTarget:(id)target action:(SEL)action forKey:(id)key { + [self addEventWithTarget:target action:action forGroup:_defaultGroup forKey:key]; +} + +- (void)addEventWithTarget:(id)target action:(SEL)action forGroup:(id)group forKey:(id)key { + [self addEvent:[MobilyEventSelector eventWithTarget:target action:action] forGroup:group forKey:key]; +} + +- (void)addEventWithBlock:(MobilyEventBlockType)block forKey:(id)key { + [self addEventWithBlock:block forGroup:_defaultGroup forKey:key]; +} + +- (void)addEventWithBlock:(MobilyEventBlockType)block forGroup:(id)group forKey:(id)key { + [self addEvent:[MobilyEventBlock eventWithBlock:block] forGroup:group forKey:key]; +} + +- (void)addEvent:(id< MobilyEvent >)event forKey:(id)key { + [self addEvent:event forGroup:_defaultGroup forKey:key]; +} + +- (void)addEvent:(id< MobilyEvent >)event forGroup:(id)group forKey:(id)key { + NSMutableDictionary* events = _groupsEvents[group]; + if(events == nil) { + events = [NSMutableDictionary dictionaryWithObject:event forKey:key]; + _groupsEvents[group] = events; + } else { + events[key] = event; + } +} + +- (void)removeEventForKey:(id)key { + [self removeEventInGroup:_defaultGroup forKey:key]; +} + +- (void)removeEventInGroup:(id)group forKey:(id)key { + NSMutableDictionary* events = _groupsEvents[group]; + if(events != nil) { + [events removeObjectForKey:key]; + } +} + +- (void)removeEventsForGroup:(id)group { + [_groupsEvents removeObjectForKey:group]; +} + +- (void)removeAllEvents { + [_groupsEvents removeAllObjects]; +} + +- (BOOL)containsEventForKey:(id)key { + NSMutableDictionary* events = _groupsEvents[_defaultGroup]; + if(events != nil) { + return (events[key] != nil); + } + return NO; +} + +- (BOOL)containsEventInGroup:(id)group forKey:(id)key { + NSMutableDictionary* events = _groupsEvents[group]; + if(events != nil) { + return (events[key] != nil); + } + return NO; +} + +- (void)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object { + [self fireEventForKey:key bySender:sender byObject:object orDefault:nil]; +} + +- (void)fireEventInGroup:(id)group forKey:(id)key bySender:(id)sender byObject:(id)object { + [self fireEventInGroup:group forKey:key bySender:sender byObject:object orDefault:nil]; +} + +- (id)fireEventForKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault { + NSMutableDictionary* events = _groupsEvents[_defaultGroup]; + id< MobilyEvent > event = (events != nil) ? events[key] : nil; + if(event != nil) { + return [event fireSender:sender object:object]; + } + return orDefault; +} + +- (id)fireEventInGroup:(id)group forKey:(id)key bySender:(id)sender byObject:(id)object orDefault:(id)orDefault { + NSMutableDictionary* events = _groupsEvents[group]; + id< MobilyEvent > event = (events != nil) ? events[key] : nil; + if(event != nil) { + return [event fireSender:sender object:object]; + } + return [self fireEventForKey:key bySender:sender byObject:object orDefault:orDefault]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyFieldValidation+Private.h b/Sources/MobilyCore/MobilyFieldValidation+Private.h new file mode 100644 index 0000000..65c808c --- /dev/null +++ b/Sources/MobilyCore/MobilyFieldValidation+Private.h @@ -0,0 +1,52 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyFieldForm () + +@property(nonatomic, readwrite, strong) NSMutableSet* validatedControls; +@property(nonatomic, readwrite, assign) BOOL valid; + +- (void)_validatedSuccess:(id)control andValue:(NSString*)value; +- (void)_validatedFail:(id)control andValue:(NSString*)value; + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/Sources/MobilyCore/MobilyFieldValidation.h b/Sources/MobilyCore/MobilyFieldValidation.h new file mode 100644 index 0000000..9009e4d --- /dev/null +++ b/Sources/MobilyCore/MobilyFieldValidation.h @@ -0,0 +1,162 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@protocol MobilyValidatedObject; +@class MobilyFieldForm; + +/*--------------------------------------------------*/ + +@protocol MobilyFieldValidator < NSObject > + +@property(nonatomic, readwrite, weak) id< MobilyValidatedObject > control; + +@required +- (BOOL)validate:(NSString*)value; +- (NSArray*)messages:(NSString*)value; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyFieldForm : NSObject + +@property(nonatomic, readwrite, strong) IBOutletCollection(NSObject) NSArray* controls; +@property(nonatomic, readwrite, strong) id< MobilyEvent > eventChangeState; +@property(nonatomic, readonly, assign, getter=isValid) BOOL valid; + +- (void)addControl:(id< MobilyValidatedObject >)control; +- (void)removeControl:(id< MobilyValidatedObject >)control; +- (void)removeAllControls; + +- (NSArray*)invalidControls; +- (NSString*)output; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyFieldEmptyValidator : NSObject < MobilyFieldValidator > + +@property(nonatomic, readwrite, strong) IBInspectable NSString* message; +@property(nonatomic, readonly, assign, getter=isRequired) IBInspectable BOOL required; + +- (instancetype)initWithMessage:(NSString*)message; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyFieldEmailValidator : NSObject < MobilyFieldValidator > + +@property(nonatomic, readwrite, strong) IBInspectable NSString* message; +@property(nonatomic, readonly, assign, getter=isRequired) IBInspectable BOOL required; + +- (instancetype)initWithMessage:(NSString*)message; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyFieldRegExpValidator : NSObject < MobilyFieldValidator > + +@property(nonatomic, readwrite, strong) IBInspectable NSString* message; +@property(nonatomic, readwrite, strong) IBInspectable NSString* regExp; +@property(nonatomic, readonly, assign, getter=isRequired) IBInspectable BOOL required; + +- (instancetype)initWithRegExp:(NSString*)regExp andMessage:(NSString*)message; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyFieldMinLengthValidator : NSObject < MobilyFieldValidator > + +@property(nonatomic, readwrite, strong) IBInspectable NSString* message; +@property(nonatomic, readwrite, assign) IBInspectable NSInteger minLength; +@property(nonatomic, readonly, assign, getter=isRequired) IBInspectable BOOL required; + +- (instancetype)initWithMessage:(NSString*)message minLength:(NSInteger)minLength; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyFieldMaxLengthValidator : NSObject < MobilyFieldValidator > + +@property(nonatomic, readwrite, strong) IBInspectable NSString* message; +@property(nonatomic, readwrite, assign) IBInspectable NSInteger maxLength; +@property(nonatomic, readonly, assign, getter=isRequired) IBInspectable BOOL required; + +- (instancetype)initWithMessage:(NSString*)message maxLength:(NSInteger)maxLength; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyFieldDigitValidator : NSObject < MobilyFieldValidator > + +@property(nonatomic, readwrite, strong) IBInspectable NSString* message; +@property(nonatomic, readonly, assign, getter=isRequired) IBInspectable BOOL required; + +- (instancetype)initWithMessage:(NSString*)message; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyFieldANDValidator : NSObject < MobilyFieldValidator > + +@property(nonatomic, readwrite, strong) IBOutletCollection(NSObject) NSArray* validators; + +- (instancetype)initWithValidators:(NSArray*)validators; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyFieldORValidator : NSObject < MobilyFieldValidator > + +@property(nonatomic, readwrite, strong) IBOutletCollection(NSObject) NSArray* validators; + +- (instancetype)initWithValidators:(NSArray*)validators; + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/Sources/MobilyCore/MobilyFieldValidation.m b/Sources/MobilyCore/MobilyFieldValidation.m new file mode 100644 index 0000000..08259d6 --- /dev/null +++ b/Sources/MobilyCore/MobilyFieldValidation.m @@ -0,0 +1,490 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to demal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyFieldForm + +#pragma mark Property + +- (void)setControls:(NSArray*)controls { + NSMutableArray* checkedControls = [NSMutableArray array]; + for(id control in controls) { + if([control conformsToProtocol:@protocol(MobilyValidatedObject)]) { + [checkedControls addObject:control]; + } + } + if([_controls isEqualToArray:checkedControls] == NO) { + for(id< MobilyValidatedObject > control in _controls) { + control.form = nil; + } + _controls = checkedControls; + for(id< MobilyValidatedObject > control in _controls) { + control.form = self; + } + _validatedControls = [NSMutableSet set]; + } +} + +- (void)setValid:(BOOL)valid { + if(_valid != valid) { + _valid = valid; + [_eventChangeState fireSender:self object:@(_valid)]; + } +} + +#pragma mark Public + +- (void)addControl:(id< MobilyValidatedObject >)control { + if(([_controls containsObject:control] == NO) && (control.form == nil)) { + _controls = [NSArray moArrayWithArray:_controls andAddingObject:control]; + [_validatedControls addObject:control]; + control.form = self; + } +} + +- (void)removeControl:(id< MobilyValidatedObject >)control { + if(([_controls containsObject:control] == YES) && (control.form == self)) { + _controls = [NSArray moArrayWithArray:_controls andRemovingObject:control]; + control.form = nil; + } +} + +- (void)removeAllControls { + for(id< MobilyValidatedObject > control in _controls) { + control.form = nil; + } + _controls = @[]; +} + +- (NSArray*)invalidControls { + return [_controls moRelativeComplement:[_validatedControls allObjects]]; +} + +- (NSString*)output { + __block NSString* output = @""; + NSArray* results = @[]; + NSArray* invalidControls = [self invalidControls]; + for(id< MobilyValidatedObject > control in invalidControls) { + results = [results moUnionWithArray:[control messages]]; + } + [results moEachWithIndex:^(NSString* r, NSUInteger index) { + output = [output stringByAppendingString:r]; + if(index != results.count-1) { + output = [output stringByAppendingString:@"\n"]; + } + }]; + return output; +} + +#pragma mark Private + +- (void)_validatedSuccess:(id< MobilyValidatedObject >)control andValue:(NSString* __unused)value { + [_validatedControls addObject:control]; + self.valid = (_controls.count == _validatedControls.count); +} + +- (void)_validatedFail:(id< MobilyValidatedObject >)control andValue:(NSString* __unused)value { + [_validatedControls removeObject:control]; + self.valid = (_controls.count == _validatedControls.count); +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyFieldEmptyValidator + +@synthesize control = _control; + +- (instancetype)init { + if(self = [super init]) { + _required = YES; + } + return self; +} + +- (instancetype)initWithMessage:(NSString*)message { + if(self = [super init]) { + _message = message; + _required = YES; + } + return self; +} + +- (BOOL)validate:(NSString*)value { + NSString* trimmed = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if(trimmed.length > 0) { + return YES; + } else if((_required == NO) && (trimmed.length < 1)) { + return YES; + } + return NO; +} + +- (NSArray*)messages:(NSString*)value { + if([self validate:value] == NO) { + return @[(_message == nil) ? @"Заполните все поля" : _message]; + } + return @[]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyFieldEmailValidator + +@synthesize control = _control; + +- (instancetype)init { + if(self = [super init]) { + _required = YES; + } + return self; +} + +- (instancetype)initWithMessage:(NSString*)message { + if(self = [super init]) { + _message = message; + _required = YES; + } + return self; +} + +- (BOOL)validate:(NSString*)value { + NSString* trimmed = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if(trimmed.length > 0) { + return [trimmed moIsEmail]; + } else if((_required == NO) && (trimmed.length < 1)) { + return YES; + } + return NO; +} + +- (NSArray*)messages:(NSString*)value { + if([self validate:value] == NO) { + return @[(_message == nil) ? @"Заполните все поля" : _message]; + } + return @[]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyFieldRegExpValidator + +@synthesize control = _control; + +- (instancetype)init { + if(self = [super init]) { + _required = YES; + } + return self; +} + +- (instancetype)initWithRegExp:(NSString*)regExp andMessage:(NSString*)message { + if(self = [super init]) { + _regExp = regExp; + _message = message; + _required = YES; + } + return self; +} + +- (void)setRegExp:(NSString*)regExp { + if([_regExp isEqualToString:regExp] == NO) { + _regExp = regExp; + [_control validate]; + } +} + +- (BOOL)validate:(NSString*)value { + NSString* trimmed = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if(trimmed.length > 0) { + return [[NSPredicate predicateWithFormat:@"SELF MATCHES %@", _regExp] evaluateWithObject:trimmed]; + } else if((_required == NO) && (trimmed.length < 1)) { + return YES; + } + return NO; +} + +- (NSArray*)messages:(NSString*)value { + if([self validate:value] == NO) { + return @[(_message == nil) ? @"Заполните все поля" : _message]; + } + return @[]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyFieldMinLengthValidator + +@synthesize control = _control; + +- (instancetype)init { + if(self = [super init]) { + _required = YES; + } + return self; +} + +- (instancetype)initWithMessage:(NSString*)message minLength:(NSInteger)minLength { + if(self = [super init]) { + _message = message; + _minLength = minLength; + _required = YES; + } + return self; +} + +- (void)setMinLength:(NSInteger)minLength { + if(_minLength != minLength) { + _minLength = minLength; + [_control validate]; + } +} + +- (BOOL)validate:(NSString*)value { + NSString* trimmed = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if(trimmed.length > 0) { + return (trimmed.length >= _minLength); + } else if((_required == NO) && (trimmed.length < 1)) { + return YES; + } + return NO; +} + +- (NSArray*)messages:(NSString*)value { + if([self validate:value] == NO) { + return @[(_message == nil) ? @"Заполните все поля" : _message]; + } + return @[]; +} + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyFieldMaxLengthValidator + +@synthesize control = _control; + +- (instancetype)init { + if(self = [super init]) { + _required = YES; + } + return self; +} + +- (instancetype)initWithMessage:(NSString*)message maxLength:(NSInteger)maxLength { + if(self = [super init]) { + _message = message; + _maxLength = maxLength; + _required = YES; + } + return self; +} + +- (void)setMaxLength:(NSInteger)maxLength { + if(_maxLength != maxLength) { + _maxLength = maxLength; + [_control validate]; + } +} + +- (BOOL)validate:(NSString*)value { + NSString* trimmed = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if(trimmed.length > 0) { + return (trimmed.length <= _maxLength); + } else if((_required == NO) && (trimmed.length < 1)) { + return YES; + } + return NO; +} + +- (NSArray*)messages:(NSString*)value { + if([self validate:value] == NO) { + return @[(_message == nil) ? @"Заполните все поля" : _message]; + } + return @[]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyFieldDigitValidator + +@synthesize control = _control; + +- (instancetype)init { + if(self = [super init]) { + _required = YES; + } + return self; +} + +- (instancetype)initWithMessage:(NSString*)message { + if(self = [super init]) { + _message = message; + _required = YES; + } + return self; +} + +- (BOOL)validate:(NSString*)value { + NSString* trimmed = [value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if(trimmed.length > 0) { + static NSPredicate* predicate = nil; + if(predicate == nil) { + predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", @"[0-9]+"]; + } + return [predicate evaluateWithObject:value]; + } else if((_required == NO) && (trimmed.length < 1)) { + return YES; + } + return NO; +} + +- (NSArray*)messages:(NSString*)value { + if([self validate:value] == NO) { + return @[(_message == nil) ? @"Заполните все поля" : _message]; + } + return @[]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyFieldANDValidator + +@synthesize control = _control; + +- (instancetype)init { + if(self = [super init]) { + } + return self; +} + +- (instancetype)initWithValidators:(NSArray*)validators { + if(self = [super init]) { + _validators = validators; + } + return self; +} + +- (BOOL)validate:(NSString*)value { + BOOL result = YES; + for(id val in _validators) { + if([val validate:value] == NO) { + result = NO; + break; + } + } + return result; +} + +- (NSArray*)messages:(NSString*)value { + NSArray* results = @[]; + for(id val in _validators) { + results = [results moUnionWithArray:[val messages:value]]; + } + return results; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyFieldORValidator + +@synthesize control = _control; + +- (instancetype)init { + if(self = [super init]) { + } + return self; +} + +- (instancetype)initWithValidators:(NSArray*)validators { + if(self = [super init]) { + _validators = validators; + } + return self; +} + +- (BOOL)validate:(NSString*)value { + BOOL result = NO; + for(id val in _validators) { + if([val validate:value] == YES) { + result = YES; + break; + } + } + return result; +} + +- (NSArray*)messages:(NSString* __unused)value { + return @[]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/Sources/MobilyCore/MobilyGeoLocationManager.h b/Sources/MobilyCore/MobilyGeoLocationManager.h new file mode 100644 index 0000000..9cc743a --- /dev/null +++ b/Sources/MobilyCore/MobilyGeoLocationManager.h @@ -0,0 +1,111 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@class MobilyGeoLocationRequest; + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSInteger, MobilyGeoLocationServicesState) { + MobilyGeoLocationServicesStateAvailable, + MobilyGeoLocationServicesStateNotDetermined, + MobilyGeoLocationServicesStateDenied, + MobilyGeoLocationServicesStateRestricted, + MobilyGeoLocationServicesStateDisabled +}; + +typedef CGFloat MobilyGeoLocationAccuracy; + +typedef NS_ENUM(NSInteger, MobilyGeoLocationStatus) { + MobilyGeoLocationStatusSuccess = 0, + MobilyGeoLocationStatusTimedOut, + MobilyGeoLocationStatusServicesNotDetermined, + MobilyGeoLocationStatusServicesDenied, + MobilyGeoLocationStatusServicesRestricted, + MobilyGeoLocationStatusServicesDisabled, + MobilyGeoLocationStatusError +}; + +typedef void(^MobilyGeoLocationRequestComplete)(CLLocation* location, MobilyGeoLocationRequest* request); +typedef void(^MobilyGeoLocationRequestFailure)(MobilyGeoLocationRequest* request); +typedef CLGeocodeCompletionHandler MobilyGeoLocationGeocodeBlock; + +/*--------------------------------------------------*/ + +@interface MobilyGeoLocationManager : NSObject < MobilyObject > + +@property(nonatomic, readonly, copy) NSArray* requests; + ++ (MobilyGeoLocationServicesState)servicesState; + ++ (instancetype)shared; + +- (void)setup NS_REQUIRES_SUPER; + +- (MobilyGeoLocationRequest*)requestWithDesiredAccuracy:(MobilyGeoLocationAccuracy)desiredAccuracy complete:(MobilyGeoLocationRequestComplete)complete failure:(MobilyGeoLocationRequestFailure)failure; +- (MobilyGeoLocationRequest*)requestWithDesiredAccuracy:(MobilyGeoLocationAccuracy)desiredAccuracy timeout:(NSTimeInterval)timeout complete:(MobilyGeoLocationRequestComplete)complete failure:(MobilyGeoLocationRequestFailure)failure; +- (MobilyGeoLocationRequest*)requestWithDesiredAccuracy:(MobilyGeoLocationAccuracy)desiredAccuracy timeout:(NSTimeInterval)timeout delayUntilAuthorized:(BOOL)delayUntilAuthorized complete:(MobilyGeoLocationRequestComplete)complete failure:(MobilyGeoLocationRequestFailure)failure; +- (MobilyGeoLocationRequest*)subscribeStaleThreshold:(NSTimeInterval)staleThreshold complete:(MobilyGeoLocationRequestComplete)complete failure:(MobilyGeoLocationRequestFailure)failure; + +- (void)geocodeAddressString:(NSString*)address block:(MobilyGeoLocationGeocodeBlock)block; +- (void)reverseGeocodeLocation:(CLLocation*)location block:(MobilyGeoLocationGeocodeBlock)block; + +- (void)forceCompleteRequest:(MobilyGeoLocationRequest*)request; +- (void)cancelRequest:(MobilyGeoLocationRequest*)request; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyGeoLocationRequest : NSObject + +@property(nonatomic, readonly, assign, getter=isSubscription) BOOL subscription; +@property(nonatomic, readonly, assign) MobilyGeoLocationAccuracy desiredAccuracy; +@property(nonatomic, readonly, assign) NSTimeInterval staleThreshold; +@property(nonatomic, readonly, assign) NSTimeInterval timeout; +@property(nonatomic, readonly, assign) NSTimeInterval timeAlive; +@property(nonatomic, readonly, copy) MobilyGeoLocationRequestComplete complete; +@property(nonatomic, readonly, copy) MobilyGeoLocationRequestFailure failure; + +@property(nonatomic, readonly, assign, getter=isCanceled) BOOL canceled; +@property(nonatomic, readonly, readonly) BOOL hasTimedOut; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyGeoLocationManager.m b/Sources/MobilyCore/MobilyGeoLocationManager.m new file mode 100644 index 0000000..9e4aafe --- /dev/null +++ b/Sources/MobilyCore/MobilyGeoLocationManager.m @@ -0,0 +1,507 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@protocol MobilyGeoLocationRequestDelegate + +- (void)requestDidTimeout:(MobilyGeoLocationRequest*)request; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyGeoLocationManager () < CLLocationManagerDelegate, MobilyGeoLocationRequestDelegate > { + CLLocationManager* _locationManager; + CLLocation* _currentLocation; + BOOL _isUpdatingLocation; + BOOL _updateFailed; + NSMutableArray* _requests; +} + +- (void)_startUpdatingIfNeeded; +- (void)_stopUpdatingIfPossible; + +- (void)_addRequest:(MobilyGeoLocationRequest*)request; +- (void)_removeRequest:(MobilyGeoLocationRequest*)request; + +- (void)_processRequests; +- (void)_forceCompleteRequest:(MobilyGeoLocationRequest*)request; +- (void)_completeRequest:(MobilyGeoLocationRequest*)request; +- (void)_completeAllRequests; +- (void)_cancelRequest:(MobilyGeoLocationRequest*)request; +- (void)_cancelAllRequests; + +- (CLLocation*)_currentLocation; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyGeoLocationRequest () { + id< MobilyGeoLocationRequestDelegate > _delegate; + BOOL _isSubscription; + MobilyGeoLocationAccuracy _desiredAccuracy; + NSTimeInterval _staleThreshold; + NSTimeInterval _timeout; + MobilyGeoLocationRequestComplete _complete; + MobilyGeoLocationRequestFailure _failure; + BOOL _canceled; + BOOL _hasTimedOut; + + NSDate* _requestStartTime; + NSTimer* _timer; +} + +- (instancetype)initWithDelegate:(id< MobilyGeoLocationRequestDelegate >)delegate desiredAccuracy:(MobilyGeoLocationAccuracy)desiredAccuracy timeout:(NSTimeInterval)timeout complete:(MobilyGeoLocationRequestComplete)complete failure:(MobilyGeoLocationRequestFailure)failure; +- (instancetype)initWithDelegate:(id< MobilyGeoLocationRequestDelegate >)delegate staleThreshold:(NSTimeInterval)staleThreshold complete:(MobilyGeoLocationRequestComplete)complete failure:(MobilyGeoLocationRequestFailure)failure; + +- (void)_complete; +- (void)_forceTimeout; +- (void)_cancel; + +- (void)_startTimerIfNeeded; + +- (void)_timeoutTriggered:(NSTimer*)timer; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyGeoLocationManager + +#pragma mark Synthesize + +@synthesize requests = _requests; + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + _locationManager = [CLLocationManager new]; + _locationManager.delegate = self; + _requests = [NSMutableArray array]; +} + +#pragma mark Static + ++ (MobilyGeoLocationServicesState)servicesState { + if([CLLocationManager locationServicesEnabled] == NO) { + return MobilyGeoLocationServicesStateDisabled; + } else if([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) { + return MobilyGeoLocationServicesStateNotDetermined; + } else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) { + return MobilyGeoLocationServicesStateDenied; + } else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusRestricted) { + return MobilyGeoLocationServicesStateRestricted; + } + return MobilyGeoLocationServicesStateAvailable; +} + ++ (instancetype)shared { + static id shared = nil; + if(shared == nil) { + @synchronized(self) { + if(shared == nil) { + shared = [self new]; + } + } + } + return shared; +} + +#pragma mark Public + +- (MobilyGeoLocationRequest*)requestWithDesiredAccuracy:(MobilyGeoLocationAccuracy)desiredAccuracy complete:(MobilyGeoLocationRequestComplete)complete failure:(MobilyGeoLocationRequestFailure)failure { + return [self requestWithDesiredAccuracy:desiredAccuracy timeout:0.0f delayUntilAuthorized:NO complete:complete failure:failure]; +} + +- (MobilyGeoLocationRequest*)requestWithDesiredAccuracy:(MobilyGeoLocationAccuracy)desiredAccuracy timeout:(NSTimeInterval)timeout complete:(MobilyGeoLocationRequestComplete)complete failure:(MobilyGeoLocationRequestFailure)failure { + return [self requestWithDesiredAccuracy:desiredAccuracy timeout:timeout delayUntilAuthorized:NO complete:complete failure:failure]; +} + +- (MobilyGeoLocationRequest*)requestWithDesiredAccuracy:(MobilyGeoLocationAccuracy)desiredAccuracy timeout:(NSTimeInterval)timeout delayUntilAuthorized:(BOOL)delayUntilAuthorized complete:(MobilyGeoLocationRequestComplete)complete failure:(MobilyGeoLocationRequestFailure)failure { + MobilyGeoLocationRequest* request = [[MobilyGeoLocationRequest alloc] initWithDelegate:self desiredAccuracy:desiredAccuracy timeout:timeout complete:complete failure:failure]; + BOOL deferTimeout = delayUntilAuthorized && ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined); + if(deferTimeout == NO) { + [request _startTimerIfNeeded]; + } + [self _addRequest:request]; + return request; +} + +- (MobilyGeoLocationRequest*)subscribeStaleThreshold:(NSTimeInterval)staleThreshold complete:(MobilyGeoLocationRequestComplete)complete failure:(MobilyGeoLocationRequestFailure)failure { + MobilyGeoLocationRequest* request = [[MobilyGeoLocationRequest alloc] initWithDelegate:self staleThreshold:staleThreshold complete:complete failure:failure]; + [self _addRequest:request]; + return request; +} + +- (void)geocodeAddressString:(NSString*)address block:(MobilyGeoLocationGeocodeBlock)block { + if(block != nil) { + CLGeocoder* geocoder = [CLGeocoder new]; + [geocoder geocodeAddressString:address completionHandler:^(NSArray* placemarks, NSError* error) { + dispatch_async(dispatch_get_main_queue(), ^{ + block(placemarks, error); + }); + }]; + } +} + +- (void)reverseGeocodeLocation:(CLLocation*)location block:(MobilyGeoLocationGeocodeBlock)block { + if(block != nil) { + CLGeocoder* geocoder = [CLGeocoder new]; + [geocoder reverseGeocodeLocation:location completionHandler:^(NSArray* placemarks, NSError* error) { + dispatch_async(dispatch_get_main_queue(), ^{ + block(placemarks, error); + }); + }]; + } +} + +- (void)forceCompleteRequest:(MobilyGeoLocationRequest*)request { + if([_requests containsObject:request] == YES) { + [self _forceCompleteRequest:request]; + } +} + +- (void)cancelRequest:(MobilyGeoLocationRequest*)request { + if([_requests containsObject:request] == YES) { + [self _cancelRequest:request]; + } +} + +#pragma mark Private + +- (void)_startUpdatingIfNeeded { +#if (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0) + if(UIDevice.moSystemVersion >= 8.0f) { + CLAuthorizationStatus authorizationStatus = [CLLocationManager authorizationStatus]; + switch(authorizationStatus) { + case kCLAuthorizationStatusNotDetermined: { + BOOL hasAlwaysKey = ([NSBundle.mainBundle objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"] != nil); + BOOL hasWhenInUseKey = ([NSBundle.mainBundle objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"] != nil); + if(hasAlwaysKey == YES) { + [_locationManager requestAlwaysAuthorization]; + } else if(hasWhenInUseKey == YES) { + [_locationManager requestWhenInUseAuthorization]; + } else { + NSAssert((hasAlwaysKey == YES) || (hasWhenInUseKey == YES), @"To use location services in iOS 8+, your Info.plist must provide a value for either NSLocationWhenInUseUsageDescription or NSLocationAlwaysUsageDescription."); + } + break; + } + case kCLAuthorizationStatusDenied: { + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; + break; + } + default: break; + } + } +#endif + if(_requests.count == 0) { + _locationManager.desiredAccuracy = kCLLocationAccuracyBest; + [_locationManager startUpdatingLocation]; + _isUpdatingLocation = YES; + } +} + +- (void)_stopUpdatingIfPossible { + if(_requests.count == 0) { + [_locationManager stopUpdatingLocation]; + _isUpdatingLocation = NO; + } +} + +- (void)_addRequest:(MobilyGeoLocationRequest*)request { + switch([MobilyGeoLocationManager servicesState]) { + case MobilyGeoLocationServicesStateDisabled: + case MobilyGeoLocationServicesStateDenied: + case MobilyGeoLocationServicesStateRestricted: + [self _completeRequest:request]; + return; + default: + break; + } + [self _startUpdatingIfNeeded]; + [_requests addObject:request]; +} + +- (void)_removeRequest:(MobilyGeoLocationRequest*)request { + [_requests removeObject:request]; + [self _stopUpdatingIfPossible]; +} + +- (void)_processRequests { + CLLocation* location = [self _currentLocation]; + NSMutableArray* completingRequests = [NSMutableArray array]; + for(MobilyGeoLocationRequest* request in _requests) { + if(request.hasTimedOut == YES) { + [completingRequests addObject:request]; + continue; + } + if(location != nil) { + if(request.isSubscription == YES) { + dispatch_async(dispatch_get_main_queue(), ^{ + if(request.complete != nil) { + request.complete(location, request); + } + }); + } else { + CLLocationAccuracy desiredAccuracy = MAX(location.horizontalAccuracy, location.verticalAccuracy); + NSTimeInterval timeSinceUpdate = MOBILY_FABS(location.timestamp.timeIntervalSinceNow); + if((desiredAccuracy <= request.desiredAccuracy) || (timeSinceUpdate <= request.staleThreshold)) { + [completingRequests addObject:request]; + } + } + } + } + for(MobilyGeoLocationRequest* request in completingRequests) { + [self _completeRequest:request]; + } +} + +- (void)_forceCompleteRequest:(MobilyGeoLocationRequest*)request { + if(request.isSubscription == YES) { + [self _cancelRequest:request]; + } else { + [request _forceTimeout]; + [self _completeRequest:request]; + } +} + +- (void)_completeRequest:(MobilyGeoLocationRequest*)request { + [request _complete]; + [self _removeRequest:request]; + CLLocation* location = [self _currentLocation]; + dispatch_async(dispatch_get_main_queue(), ^{ + if(request.complete != nil) { + request.complete(location, request); + } + }); +} + +- (void)_completeAllRequests { + [_requests moEach:^(MobilyGeoLocationRequest* request) { + [self _completeRequest:request]; + }]; +} + +- (void)_cancelRequest:(MobilyGeoLocationRequest*)request { + [request _cancel]; + [self _removeRequest:request]; + dispatch_async(dispatch_get_main_queue(), ^{ + if(request.failure != nil) { + request.failure(request); + } + }); +} + +- (void)_cancelAllRequests { + [_requests moEach:^(MobilyGeoLocationRequest* request) { + [self _cancelRequest:request]; + }]; +} + +- (CLLocation*)_currentLocation { + if(_currentLocation != nil) { + if((_currentLocation.coordinate.latitude == 0.0) && (_currentLocation.coordinate.longitude == 0.0)) { + _currentLocation = nil; + } + } + return _currentLocation; +} + +#pragma mark CLLocationManagerDelegate + +- (void)locationManager:(CLLocationManager* __unused)manager didUpdateLocations:(NSArray*)locations { + _updateFailed = NO; + _currentLocation = [locations lastObject]; + [self _processRequests]; +} + +- (void)locationManager:(CLLocationManager* __unused)manager didFailWithError:(NSError* __unused)error { + _updateFailed = YES; + [self _completeAllRequests]; +} + +- (void)locationManager:(CLLocationManager* __unused)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { + switch(status) { + case kCLAuthorizationStatusDenied: + case kCLAuthorizationStatusRestricted: + [self _completeAllRequests]; + break; +#if (__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_8_0) + case kCLAuthorizationStatusAuthorizedAlways: + case kCLAuthorizationStatusAuthorizedWhenInUse: { +#elif (__IPHONE_OS_VERSION_MAX_ALLOWED <= __IPHONE_8_0) + case kCLAuthorizationStatusAuthorized: { +#endif + for(MobilyGeoLocationRequest* request in _requests) { + [request _startTimerIfNeeded]; + } + break; + } + default: + break; + } +} + +#pragma mark MobilyGeoLocationRequestDelegate + +- (void)requestDidTimeout:(MobilyGeoLocationRequest*)request { + [self _completeRequest:request]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyGeoLocationRequest + +#pragma mark Synthesize + +@synthesize subscription = _subscription; +@synthesize desiredAccuracy = _desiredAccuracy; +@synthesize staleThreshold = _staleThreshold; +@synthesize timeout = _timeout; +@synthesize complete = _complete; +@synthesize failure = _failure; +@synthesize canceled = _canceled; +@synthesize hasTimedOut = _hasTimedOut; + +#pragma mark Init / Free + +- (instancetype)initWithDelegate:(id< MobilyGeoLocationRequestDelegate >)delegate desiredAccuracy:(MobilyGeoLocationAccuracy)desiredAccuracy timeout:(NSTimeInterval)timeout complete:(MobilyGeoLocationRequestComplete)complete failure:(MobilyGeoLocationRequestFailure)failure { + self = [super init]; + if(self != nil) { + _delegate = delegate; + _desiredAccuracy = desiredAccuracy; + _timeout = timeout; + _complete = complete; + _failure = failure; + } + return self; +} + +- (instancetype)initWithDelegate:(id< MobilyGeoLocationRequestDelegate >)delegate staleThreshold:(NSTimeInterval)staleThreshold complete:(MobilyGeoLocationRequestComplete)complete failure:(MobilyGeoLocationRequestFailure)failure { + self = [super init]; + if(self != nil) { + _delegate = delegate; + _subscription = YES; + _staleThreshold = staleThreshold; + _complete = complete; + _failure = failure; + } + return self; +} + +- (void)dealloc { + [_timer invalidate]; +} + +#pragma mark Public + +- (NSTimeInterval)timeAlive { + if(_requestStartTime == nil) { + return 0.0f; + } + return MOBILY_FABS(_requestStartTime.timeIntervalSinceNow); +} + +- (BOOL)hasTimedOut { + if((_timeout > 0.0f) && (self.timeAlive > _timeout)) { + _hasTimedOut = YES; + } + return _hasTimedOut; +} + +#pragma mark Private + +- (void)_complete { + if(_timer != nil) { + [_timer invalidate]; + _timer = nil; + } + _requestStartTime = nil; +} + +- (void)_forceTimeout { + if(_desiredAccuracy > MOBILY_EPSILON) { + _hasTimedOut = YES; + } +} + +- (void)_cancel { + if(_timer != nil) { + [_timer invalidate]; + _timer = nil; + } + _requestStartTime = nil; + _canceled = YES; +} + +- (void)_startTimerIfNeeded { + if((_timeout > 0) && (_timer == nil)) { + _requestStartTime = [NSDate date]; + _timer = [NSTimer scheduledTimerWithTimeInterval:_timeout target:self selector:@selector(_timeoutTriggered:) userInfo:nil repeats:NO]; + } +} + +- (void)_timeoutTriggered:(NSTimer*)timer { + _hasTimedOut = YES; + [_delegate requestDidTimeout:self]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyGrid.h b/Sources/MobilyCore/MobilyGrid.h new file mode 100644 index 0000000..4cfcc0b --- /dev/null +++ b/Sources/MobilyCore/MobilyGrid.h @@ -0,0 +1,94 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyGrid : NSObject< NSCopying > + +@property(nonatomic, readonly, assign) NSUInteger numberOfColumns; +@property(nonatomic, readonly, assign) NSUInteger numberOfRows; +@property(nonatomic, readonly, assign) NSUInteger count; + ++ (instancetype)grid; ++ (instancetype)gridWithColumns:(NSUInteger)columns rows:(NSUInteger)rows; ++ (instancetype)gridWithColumns:(NSUInteger)columns rows:(NSUInteger)rows objects:(NSArray*)objects; ++ (instancetype)gridWithGrid:(MobilyGrid*)grid; + +- (instancetype)initWithColumns:(NSUInteger)columns rows:(NSUInteger)rows; +- (instancetype)initWithColumns:(NSUInteger)columns rows:(NSUInteger)rows objects:(NSArray*)objects; +- (instancetype)initWithGrid:(MobilyGrid*)grid; + +- (BOOL)containsObject:(id)object; +- (BOOL)containsColumn:(NSUInteger)column row:(NSUInteger)row; +- (BOOL)isEmptyColumn:(NSInteger)column; +- (BOOL)isEmptyRow:(NSInteger)row; + +- (id)objectAtColumn:(NSUInteger)column atRow:(NSUInteger)row; +- (void)findObject:(id)object inColumn:(NSUInteger*)column inRow:(NSUInteger*)row; +- (void)findObjectUsingBlock:(BOOL(^)(id object))block inColumn:(NSUInteger*)column inRow:(NSUInteger*)row; +- (NSArray*)objects; + +- (void)enumerateColumnsRowsUsingBlock:(void(^)(id object, NSUInteger column, NSUInteger row, BOOL* stopColumn, BOOL* stopRow))block; +- (void)enumerateRowsColumnsUsingBlock:(void(^)(id object, NSUInteger column, NSUInteger row, BOOL* stopColumn, BOOL* stopRow))block; +- (void)enumerateByColumn:(NSInteger)column usingBlock:(void(^)(id object, NSUInteger column, NSUInteger row, BOOL* stop))block; +- (void)enumerateByRow:(NSInteger)row usingBlock:(void(^)(id object, NSUInteger column, NSUInteger row, BOOL* stop))block; + +- (void)eachColumnsRows:(void(^)(id object, NSUInteger column, NSUInteger row))block; +- (void)eachRowsColumns:(void(^)(id object, NSUInteger column, NSUInteger row))block; +- (void)moEach:(void(^)(id object, NSUInteger column, NSUInteger row))block byColumn:(NSInteger)column; +- (void)moEach:(void(^)(id object, NSUInteger column, NSUInteger row))block byRow:(NSInteger)row; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyMutableGrid : MobilyGrid + +- (void)setNumberOfColumns:(NSUInteger)numberOfColumns numberOfRows:(NSUInteger)numberOfRows; + +- (void)setObject:(id)object atColumn:(NSUInteger)column atRow:(NSUInteger)row; +- (void)setObjects:(NSArray*)objects; + +- (void)insertColumn:(NSUInteger)column objects:(NSArray*)objects; +- (void)insertRow:(NSUInteger)row objects:(NSArray*)objects; +- (void)removeColumn:(NSUInteger)column; +- (void)removeRow:(NSUInteger)row; +- (void)removeAllObjects; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyGrid.m b/Sources/MobilyCore/MobilyGrid.m new file mode 100644 index 0000000..d08e3b7 --- /dev/null +++ b/Sources/MobilyCore/MobilyGrid.m @@ -0,0 +1,425 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyGrid () { +@protected + NSUInteger _numberOfColumns; + NSUInteger _numberOfRows; + NSUInteger _count; + NSMutableArray* _objects; +} + +@property(nonatomic, readonly, copy) NSArray* columns; + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyGrid + +#pragma mark Synthesize + +@synthesize numberOfColumns = _numberOfColumns; +@synthesize numberOfRows = _numberOfRows; +@synthesize count = _count; +@synthesize columns = _objects; + +#pragma mark Init / Free + ++ (instancetype)grid { + return [[self alloc] init]; +} + ++ (instancetype)gridWithColumns:(NSUInteger)columns rows:(NSUInteger)rows { + return [[self alloc] initWithColumns:columns rows:rows]; +} + ++ (instancetype)gridWithColumns:(NSUInteger)columns rows:(NSUInteger)rows objects:(NSArray*)objects { + return [[self alloc] initWithColumns:columns rows:rows objects:objects]; +} + ++ (instancetype)gridWithGrid:(MobilyGrid*)grid { + return [[self alloc] gridWithGrid:grid]; +} + +- (instancetype)init { + self = [super init]; + if(self != nil) { + _objects = NSMutableArray.array; + } + return self; +} + +- (instancetype)initWithColumns:(NSUInteger)columns rows:(NSUInteger)rows { + self = [super init]; + if(self != nil) { + _numberOfColumns = columns; + _numberOfRows = rows; + _count = _numberOfColumns * _numberOfRows; + _objects = [NSMutableArray arrayWithCapacity:_numberOfColumns]; + for(NSUInteger ic = 0; ic < _numberOfColumns; ic++) { + NSMutableArray* columnObjects = [NSMutableArray arrayWithCapacity:_numberOfRows]; + for(NSUInteger ir = 0; ir < _numberOfRows; ir++) { + [columnObjects addObject:[NSNull null]]; + } + [_objects addObject:columnObjects]; + } + } + return self; +} + +- (instancetype)initWithColumns:(NSUInteger)columns rows:(NSUInteger)rows objects:(NSArray*)objects { + self = [super init]; + if(self != nil) { + _numberOfColumns = columns; + _numberOfRows = rows; + _count = _numberOfColumns * _numberOfRows; + _objects = [NSMutableArray arrayWithCapacity:_numberOfColumns]; + if(objects.count > 0) { + NSUInteger index = 0; + for(NSUInteger ic = 0; ic < _numberOfColumns; ic++) { + NSMutableArray* columnObjects = [NSMutableArray arrayWithCapacity:_numberOfRows]; + for(NSUInteger ir = 0; ir < _numberOfRows; ir++) { + if(index < objects.count) { + [columnObjects addObject:objects[index]]; + } else { + [columnObjects addObject:[NSNull null]]; + } + index++; + } + [_objects addObject:columnObjects]; + } + } + } + return self; +} + +- (instancetype)initWithGrid:(MobilyGrid*)grid { + self = [super init]; + if(self != nil) { + _numberOfColumns = grid.numberOfColumns; + _numberOfRows = grid.numberOfRows; + _count = grid.count; + _objects = [NSMutableArray arrayWithArray:grid.columns]; + } + return self; +} + +- (void)dealloc { + _objects = nil; +} + +#pragma mark Public + +- (BOOL)containsObject:(id)object { + for(NSMutableArray* columnObjects in _objects) { + if([columnObjects containsObject:object] == YES) { + return YES; + } + } + return NO; +} + +- (BOOL)containsColumn:(NSUInteger)column row:(NSUInteger)row { + return ([_objects[column][row] isKindOfClass:NSNull.class] == NO); +} + +- (BOOL)isEmptyColumn:(NSInteger)column { + for(NSUInteger ir = 0; ir < _numberOfRows; ir++) { + if([_objects[column][ir] isKindOfClass:NSNull.class] == NO) { + return NO; + } + } + return YES; +} + +- (BOOL)isEmptyRow:(NSInteger)row { + for(NSUInteger ic = 0; ic < _numberOfColumns; ic++) { + if([_objects[ic][row] isKindOfClass:NSNull.class] == NO) { + return NO; + } + } + return YES; +} + +- (id)objectAtColumn:(NSUInteger)column atRow:(NSUInteger)row { + id object = _objects[column][row]; + if([object isKindOfClass:NSNull.class] == YES) { + return nil; + } + return object; +} + +- (void)findObject:(id)object inColumn:(NSUInteger*)column inRow:(NSUInteger*)row { + [self findObjectUsingBlock:^BOOL(id exist) { return [exist isEqual:object]; } inColumn:column inRow:row]; +} + +- (void)findObjectUsingBlock:(BOOL(^)(id object))block inColumn:(NSUInteger*)column inRow:(NSUInteger*)row { + for(NSUInteger ic = 0; ic < _numberOfColumns; ic++) { + NSMutableArray* columnObjects = _objects[ic]; + for(NSUInteger ir = 0; ir < _numberOfRows; ir++) { + if(block(columnObjects[ir]) == YES) { + if(column != NULL) { + *column = ic; + } + if(row != NULL) { + *row = ir; + } + return; + } + } + } + if(column != NULL) { + *column = NSNotFound; + } + if(row != NULL) { + *row = NSNotFound; + } +} + +- (NSArray*)objects { + NSMutableArray* result = [NSMutableArray array]; + for(NSUInteger ic = 0; ic < _numberOfColumns; ic++) { + NSMutableArray* columnObjects = _objects[ic]; + for(NSUInteger ir = 0; ir < _numberOfRows; ir++) { + [result addObject:columnObjects[ir]]; + } + } + return result; +} + +- (void)enumerateColumnsRowsUsingBlock:(void(^)(id object, NSUInteger column, NSUInteger row, BOOL* stopColumn, BOOL* stopRow))block { + for(NSUInteger ic = 0; ic < _numberOfColumns; ic++) { + BOOL stopColumn = NO; + NSMutableArray* columnObjects = _objects[ic]; + for(NSUInteger ir = 0; ir < _numberOfRows; ir++) { + BOOL stopRow = NO; + block(columnObjects[ir], ic, ir, &stopColumn, &stopRow); + if(stopRow == YES) { + break; + } + } + if(stopColumn == YES) { + break; + } + } +} + +- (void)enumerateRowsColumnsUsingBlock:(void(^)(id object, NSUInteger column, NSUInteger row, BOOL* stopColumn, BOOL* stopRow))block { + for(NSUInteger ir = 0; ir < _numberOfRows; ir++) { + BOOL stopRow = NO; + for(NSUInteger ic = 0; ic < _numberOfColumns; ic++) { + BOOL stopColumn = NO; + block(_objects[ic][ir], ic, ir, &stopColumn, &stopRow); + if(stopColumn == YES) { + break; + } + } + if(stopRow == YES) { + break; + } + } +} + +- (void)enumerateByColumn:(NSInteger)column usingBlock:(void(^)(id object, NSUInteger column, NSUInteger row, BOOL* stop))block { + NSMutableArray* columnObjects = _objects[column]; + for(NSUInteger ir = 0; ir < _numberOfRows; ir++) { + BOOL stop = NO; + block(columnObjects[ir], column, ir, &stop); + if(stop == YES) { + break; + } + } +} + +- (void)enumerateByRow:(NSInteger)row usingBlock:(void(^)(id object, NSUInteger column, NSUInteger row, BOOL* stop))block { + for(NSUInteger ic = 0; ic < _numberOfColumns; ic++) { + BOOL stop = NO; + block(_objects[ic][row], ic, row, &stop); + if(stop == YES) { + break; + } + } +} + +- (void)eachColumnsRows:(void(^)(id object, NSUInteger column, NSUInteger row))block { + for(NSUInteger ic = 0; ic < _numberOfColumns; ic++) { + NSMutableArray* columnObjects = _objects[ic]; + for(NSUInteger ir = 0; ir < _numberOfRows; ir++) { + block(columnObjects[ir], ic, ir); + } + } +} + +- (void)eachRowsColumns:(void(^)(id object, NSUInteger column, NSUInteger row))block { + for(NSUInteger ir = 0; ir < _numberOfRows; ir++) { + for(NSUInteger ic = 0; ic < _numberOfColumns; ic++) { + block(_objects[ic][ir], ic, ir); + } + } +} + +- (void)moEach:(void(^)(id object, NSUInteger column, NSUInteger row))block byColumn:(NSInteger)column { + NSMutableArray* columnObjects = _objects[column]; + for(NSUInteger ir = 0; ir < _numberOfRows; ir++) { + block(columnObjects[ir], column, ir); + } +} + +- (void)moEach:(void(^)(id object, NSUInteger column, NSUInteger row))block byRow:(NSInteger)row { + for(NSUInteger ic = 0; ic < _numberOfColumns; ic++) { + block(_objects[ic][row], ic, row); + } +} + +#pragma mark NSCopying + +- (id)copy { + return [self copyWithZone:NSDefaultMallocZone()]; +} + +- (id)copyWithZone:(NSZone*)zone { + return [[MobilyGrid allocWithZone:zone] initWithGrid:self]; +} + +- (id)mutableCopy { + return [self mutableCopyWithZone:NSDefaultMallocZone()]; +} + +- (id)mutableCopyWithZone:(NSZone*)zone { + return [[MobilyMutableGrid allocWithZone:zone] initWithGrid:self]; +} + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyMutableGrid + +#pragma mark Public + +- (void)setNumberOfColumns:(NSUInteger)numberOfColumns numberOfRows:(NSUInteger)numberOfRows { + if((_numberOfColumns != numberOfColumns) || (_numberOfRows != numberOfRows)) { + _numberOfColumns = numberOfColumns; + _numberOfRows = numberOfRows; + _count = _numberOfColumns * _numberOfRows; + [_objects removeAllObjects]; + for(NSUInteger ic = 0; ic < _numberOfColumns; ic++) { + NSMutableArray* columnObjects = [NSMutableArray arrayWithCapacity:_numberOfRows]; + for(NSUInteger ir = 0; ir < _numberOfRows; ir++) { + [columnObjects addObject:[NSNull null]]; + } + [_objects addObject:columnObjects]; + } + } +} + +- (void)setObject:(id)object atColumn:(NSUInteger)column atRow:(NSUInteger)row { + _objects[column][row] = (object != nil) ? object : [NSNull null]; +} + +- (void)setObjects:(NSArray*)objects { + [_objects removeAllObjects]; + NSUInteger index = 0; + for(NSUInteger ic = 0; ic < _numberOfColumns; ic++) { + NSMutableArray* columnObjects = [NSMutableArray arrayWithCapacity:_numberOfRows]; + for(NSUInteger ir = 0; ir < _numberOfRows; ir++) { + if(index < objects.count) { + [columnObjects addObject:objects[index]]; + } else { + [columnObjects addObject:[NSNull null]]; + } + index++; + } + [_objects addObject:columnObjects]; + } +} + +- (void)insertColumn:(NSUInteger)column objects:(NSArray*)objects { + NSMutableArray* columnObjects = [NSMutableArray arrayWithCapacity:_numberOfRows]; + for(NSUInteger ir = 0; ir < _numberOfRows; ir++) { + if(ir < objects.count) { + [columnObjects addObject:objects[ir]]; + } else { + [columnObjects addObject:[NSNull null]]; + } + } + [_objects insertObject:columnObjects atIndex:column]; + _numberOfColumns++; + _count = _numberOfColumns * _numberOfRows; +} + +- (void)insertRow:(NSUInteger)row objects:(NSArray*)objects { + for(NSUInteger ic = 0; ic < _numberOfColumns; ic++) { + if(ic < objects.count) { + [_objects[ic] insertObject:objects[ic] atIndex:row]; + } else { + [_objects[ic] insertObject:[NSNull null] atIndex:row]; + } + } + _numberOfRows--; + _count = _numberOfColumns * _numberOfRows; +} + +- (void)removeColumn:(NSUInteger)column { + [_objects removeObjectAtIndex:column]; + _numberOfColumns--; + _count = _numberOfColumns * _numberOfRows; +} + +- (void)removeRow:(NSUInteger)row { + for(NSUInteger ic = 0; ic < _numberOfColumns; ic++) { + [_objects[ic] removeObjectAtIndex:row]; + } + _numberOfRows--; + _count = _numberOfColumns * _numberOfRows; +} + +- (void)removeAllObjects { + [_objects removeAllObjects]; + _numberOfColumns = 0; + _numberOfRows = 0; + _count = 0; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyHttpQuery+Private.h b/Sources/MobilyCore/MobilyHttpQuery+Private.h new file mode 100644 index 0000000..6df37d4 --- /dev/null +++ b/Sources/MobilyCore/MobilyHttpQuery+Private.h @@ -0,0 +1,81 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyHttpQuery () < NSURLConnectionDelegate, NSURLConnectionDataDelegate > { +@protected + NSString* _certificateFilename; + BOOL _allowInvalidCertificates; + NSError* _error; + __weak id< MobilyHttpQueryDelegate > _delegate; + MobilyHttpQueryBlock _startCallback; + MobilyHttpQueryBlock _cancelCallback; + MobilyHttpQueryBlock _finishCallback; + MobilyHttpQueryErrorBlock _errorCallback; + + NSURLConnection* _connection; + NSMutableURLRequest* _request; + NSHTTPURLResponse* _response; + NSMutableData* _mutableResponseData; +} + +@property(nonatomic, readwrite, strong) NSURLConnection* connection; +@property(nonatomic, readwrite, strong) NSMutableURLRequest* request; +@property(nonatomic, readwrite, strong) NSHTTPURLResponse* response; +@property(nonatomic, readwrite, strong) NSMutableData* mutableResponseData; + +- (NSDictionary*)_formDataFromDictionary:(NSDictionary*)dictionary; +- (void)_formDataFromDictionary:(NSMutableDictionary*)dictionary value:(id)value keyPath:(NSString*)keyPath; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyHttpAttachment () { + NSString* _name; + BOOL _encodeName; + NSString* _filename; + BOOL _encodeFilename; + NSString* _mimeType; + BOOL _encodeMimeType; + NSData* _data; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/NS/Core/MobilyHttpQuery.h b/Sources/MobilyCore/MobilyHttpQuery.h similarity index 60% rename from Classes/NS/Core/MobilyHttpQuery.h rename to Sources/MobilyCore/MobilyHttpQuery.h index d50f44b..33f349c 100644 --- a/Classes/NS/Core/MobilyHttpQuery.h +++ b/Sources/MobilyCore/MobilyHttpQuery.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,23 +33,26 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyTaskManager.h" +#import /*--------------------------------------------------*/ -@class MobilyHttpQuery; +@protocol MobilyHttpQueryDelegate; /*--------------------------------------------------*/ -typedef void (^MobilyHttpQueryBlock)(MobilyHttpQuery* query); +typedef void (^MobilyHttpQueryBlock)(); +typedef void (^MobilyHttpQueryErrorBlock)(NSError* error); /*--------------------------------------------------*/ -@interface MobilyHttpQuery : NSObject +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyHttpQuery : NSObject < MobilyObject > @property(nonatomic, readwrite, strong) NSString* certificateFilename; +@property(nonatomic, readwrite, assign) BOOL allowInvalidCertificates; -@property(nonatomic, readwrite, strong) NSString* requestUrl; +@property(nonatomic, readwrite, strong) NSURL* requestUrl; @property(nonatomic, readwrite, strong) NSString* requestMethod; @property(nonatomic, readwrite, strong) NSDictionary* requestHeaders; @property(nonatomic, readwrite, strong) NSData* requestBody; @@ -66,30 +69,25 @@ typedef void (^MobilyHttpQueryBlock)(MobilyHttpQuery* query); @property(nonatomic, readonly, strong) NSArray* responseJsonArray; @property(nonatomic, readonly, assign) id responseJson; -@property(nonatomic, readwrite, strong) NSError* lastError; +@property(nonatomic, readonly, strong) NSError* error; +@property(nonatomic, readwrite, weak) id< MobilyHttpQueryDelegate > delegate; @property(nonatomic, readwrite, copy) MobilyHttpQueryBlock startCallback; @property(nonatomic, readwrite, copy) MobilyHttpQueryBlock cancelCallback; @property(nonatomic, readwrite, copy) MobilyHttpQueryBlock finishCallback; -@property(nonatomic, readwrite, copy) MobilyHttpQueryBlock errorCallback; - -+ (MobilyHttpQuery*)queryWithMethod:(NSString*)method - headers:(NSDictionary*)headers - url:(NSString*)url - body:(id)body; - -+ (MobilyHttpQuery*)queryWithMethod:(NSString*)method - headers:(NSDictionary*)headers - url:(NSString*)url - params:(id)params - attachBoundary:(NSString*)attachBoundary - attachType:(NSString*)attachType - attachKey:(NSString*)attachKey - attachName:(NSString*)attachName - attachData:(NSData*)attachData; +@property(nonatomic, readwrite, copy) MobilyHttpQueryErrorBlock errorCallback; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)setRequestUrl:(NSURL*)url params:(NSDictionary*)params; +- (void)setRequestUrlParams:(NSDictionary*)params; +- (void)setRequestBodyParams:(NSDictionary*)params encodeParamKey:(BOOL)encodeParamKey encodeParamValue:(BOOL)encodeParamValue; +- (void)setRequestBodyParams:(NSDictionary*)params encodeParamKey:(BOOL)encodeParamKey encodeParamValue:(BOOL)encodeParamValue boundary:(NSString*)boundary attachments:(NSArray*)attachments; - (void)addRequestHeader:(NSString*)header value:(NSString*)value; +- (void)addRequestHeaders:(NSDictionary*)headers; - (void)removeRequestHeader:(NSString*)header; +- (void)removeRequestHeaders:(NSArray*)headers; - (void)start; - (void)cancel; @@ -98,9 +96,30 @@ typedef void (^MobilyHttpQueryBlock)(MobilyHttpQuery* query); /*--------------------------------------------------*/ -@interface MobilyTaskHttpQuery : MobilyTask +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyHttpAttachment : NSObject < MobilyObject > + +@property(nonatomic, readonly, strong) NSString* name; +@property(nonatomic, readwrite, assign) BOOL encodeName; +@property(nonatomic, readonly, strong) NSString* filename; +@property(nonatomic, readwrite, assign) BOOL encodeFilename; +@property(nonatomic, readonly, strong) NSString* mimeType; +@property(nonatomic, readwrite, assign) BOOL encodeMimeType; +@property(nonatomic, readonly, strong) NSData* data; + +- (instancetype)initWithName:(NSString*)name filename:(NSString*)filename mimeType:(NSString*)mimeType data:(NSData*)data; + +@end + +/*--------------------------------------------------*/ + +@protocol MobilyHttpQueryDelegate < NSObject > -@property(nonatomic, readwrite, strong) MobilyHttpQuery* httpQuery; +@optional +- (void)didStartHttpQuery:(MobilyHttpQuery*)httpQuery; +- (void)didCancelHttpQuery:(MobilyHttpQuery*)httpQuery; +- (void)didFinishHttpQuery:(MobilyHttpQuery*)httpQuery; +- (void)httpQuery:(MobilyHttpQuery*)httpQuery didError:(NSError*)error; @end diff --git a/Sources/MobilyCore/MobilyHttpQuery.m b/Sources/MobilyCore/MobilyHttpQuery.m new file mode 100644 index 0000000..cec2aa4 --- /dev/null +++ b/Sources/MobilyCore/MobilyHttpQuery.m @@ -0,0 +1,484 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyHttpQuery + +#pragma mark Synthesize + +@synthesize certificateFilename = _certificateFilename; +@synthesize allowInvalidCertificates = _allowInvalidCertificates; +@synthesize error = _error; +@synthesize delegate = _delegate; +@synthesize startCallback = _startCallback; +@synthesize cancelCallback = _cancelCallback; +@synthesize finishCallback = _finishCallback; +@synthesize errorCallback = _errorCallback; + +@synthesize connection = _connection; +@synthesize request = _request; +@synthesize response = _response; +@synthesize mutableResponseData = _mutableResponseData; + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + _request = [NSMutableURLRequest new]; + _request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData; + _request.networkServiceType = NSURLNetworkServiceTypeDefault; + [self setup]; + } + return self; +} + +- (void)setup { +} + +- (void)dealloc { + [self cancel]; +} + +#pragma mark Public + +- (void)setRequestUrl:(NSURL*)url params:(NSDictionary*)params { + NSURLComponents* urlComponents = [NSURLComponents componentsWithString:[url absoluteString]]; + NSMutableDictionary* queryParams = NSMutableDictionary.dictionary; + if([urlComponents.query length] > 0) { + [queryParams addEntriesFromDictionary:urlComponents.query.moDictionaryFromQueryComponents]; + } + [queryParams addEntriesFromDictionary:[self _formDataFromDictionary:params]]; + NSMutableString* queryString = NSMutableString.string; + [queryParams enumerateKeysAndObjectsUsingBlock:^(NSString* key, id< NSObject > value, BOOL* stop __unused) { + if(queryString.length > 0) { + [queryString appendString:@"&"]; + } + [queryString appendFormat:@"%@=%@", key, value.description]; + }]; + urlComponents.query = queryString; + _request.URL = urlComponents.URL; +} + +- (void)setRequestUrlParams:(NSDictionary*)params { + [self setRequestUrl:_request.URL params:params]; +} + +- (void)setRequestBodyParams:(NSDictionary*)params encodeParamKey:(BOOL)encodeParamKey encodeParamValue:(BOOL)encodeParamValue { + NSMutableString* bodyString = NSMutableString.string; + NSDictionary* formData = [self _formDataFromDictionary:params]; + [formData enumerateKeysAndObjectsUsingBlock:^(NSString* key, id< NSObject > value, BOOL* stop __unused) { + if(bodyString.length > 0) { + [bodyString appendString:@"&"]; + } + NSString* tempKey = (encodeParamKey == YES) ? key.moStringByEncodingURLFormat : key; + NSString* tempValue = (encodeParamValue == YES) ? value.description.moStringByEncodingURLFormat : value.description; + [bodyString appendFormat:@"%@=%@", tempKey, tempValue]; + }]; + + NSData* body = [bodyString dataUsingEncoding:NSUTF8StringEncoding]; + [_request addValue:[NSString stringWithFormat:@"%lu", (unsigned long)body.length] forHTTPHeaderField:@"Content-Length"]; + [_request addValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; + _request.HTTPBody = body; +} + +- (void)setRequestBodyParams:(NSDictionary*)params encodeParamKey:(BOOL)encodeParamKey encodeParamValue:(BOOL)encodeParamValue boundary:(NSString*)boundary attachments:(NSArray*)attachments { + NSMutableData* body = NSMutableData.data; + NSDictionary* formData = [self _formDataFromDictionary:params]; + NSString* boundaryEncoded = boundary.moStringByEncodingURLFormat; + [formData enumerateKeysAndObjectsUsingBlock:^(NSString* key, id< NSObject > value, BOOL* stop __unused) { + NSString* tempKey = (encodeParamKey == YES) ? key.moStringByEncodingURLFormat : key; + NSString* tempValue = (encodeParamValue == YES) ? value.description.moStringByEncodingURLFormat : value.description; + [body appendData:[[NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n", boundaryEncoded, tempKey, tempValue] dataUsingEncoding:NSUTF8StringEncoding]]; + }]; + for(MobilyHttpAttachment* attachment in attachments) { + NSString* tempName = (attachment.encodeName == YES) ? attachment.name.moStringByEncodingURLFormat : attachment.name; + NSString* tempFilename = (attachment.encodeFilename == YES) ? attachment.filename.moStringByEncodingURLFormat : attachment.filename; + NSString* tempMimeType = (attachment.encodeMimeType == YES) ? attachment.mimeType.moStringByEncodingURLFormat : attachment.mimeType; + [body appendData:[[NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\nContent-Type: %@\r\n\r\n", boundaryEncoded, tempName, tempFilename, tempMimeType] dataUsingEncoding:NSUTF8StringEncoding]]; + [body appendData:attachment.data]; + [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + } + [body appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundaryEncoded] dataUsingEncoding:NSUTF8StringEncoding]]; + + [_request addValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundaryEncoded] forHTTPHeaderField:@"Content-Type"]; + [_request addValue:[NSString stringWithFormat:@"%lu", (unsigned long)body.length] forHTTPHeaderField:@"Content-Length"]; + _request.HTTPBody = body; +} + +- (void)addRequestHeader:(NSString*)header value:(NSString*)value { + [_request addValue:value forHTTPHeaderField:header]; +} + +- (void)addRequestHeaders:(NSDictionary*)headers { + NSMutableDictionary* mutableHeaders = [NSMutableDictionary dictionaryWithDictionary:[_request allHTTPHeaderFields]]; + if(mutableHeaders != nil) { + mutableHeaders.valuesForKeysWithDictionary = headers; + _request.allHTTPHeaderFields = mutableHeaders; + } +} + +- (void)removeRequestHeader:(NSString*)header { + NSMutableDictionary* headers = [NSMutableDictionary dictionaryWithDictionary:[_request allHTTPHeaderFields]]; + if(headers != nil) { + [headers removeObjectForKey:header]; + _request.allHTTPHeaderFields = headers; + } +} + +- (void)removeRequestHeaders:(NSArray*)headers { + NSMutableDictionary* mutableHeaders = [NSMutableDictionary dictionaryWithDictionary:[_request allHTTPHeaderFields]]; + if(mutableHeaders != nil) { + [mutableHeaders removeObjectsForKeys:headers]; + _request.allHTTPHeaderFields = mutableHeaders; + } +} + +- (void)start { + if(_connection == nil) { + _response = nil; + _mutableResponseData = nil; + _connection = [[NSURLConnection alloc] initWithRequest:_request delegate:self startImmediately:NO]; + UIApplication.sharedApplication.networkActivityIndicatorVisible = YES; + [_connection scheduleInRunLoop:NSRunLoop.currentRunLoop forMode:NSDefaultRunLoopMode]; + [_connection start]; + if([_delegate respondsToSelector:@selector(didStartHttpQuery:)] == YES) { + [_delegate didStartHttpQuery:self]; + } else if(_startCallback != nil) { + _startCallback(self); + } + [NSRunLoop.currentRunLoop run]; + } +} + +- (void)cancel { + if(_connection != nil) { + [_connection cancel]; + _connection = nil; + _response = nil; + _mutableResponseData = nil; + if([_delegate respondsToSelector:@selector(didCancelHttpQuery:)] == YES) { + [_delegate didCancelHttpQuery:self]; + } else if(_cancelCallback != nil) { + _cancelCallback(self); + } + UIApplication.sharedApplication.networkActivityIndicatorVisible = NO; + } +} + +#pragma mark Property + +- (void)setRequestUrl:(NSURL*)requestUrl { + _request.URL = requestUrl; +} + +- (NSURL*)requestUrl { + return _request.URL; +} + +- (void)setRequestTimeout:(NSTimeInterval)requestTimeout { + _request.timeoutInterval = requestTimeout; +} + +- (NSTimeInterval)requestTimeout { + return _request.timeoutInterval; +} + +- (void)setRequestMethod:(NSString*)requestMethod { + _request.HTTPMethod = requestMethod; +} + +- (NSString*)requestMethod { + return _request.HTTPMethod; +} + +- (void)setRequestHeaders:(NSDictionary*)requestHeaders { + _request.allHTTPHeaderFields = requestHeaders; +} + +- (NSDictionary*)requestHeaders { + return [_request allHTTPHeaderFields]; +} + +- (void)setRequestBody:(NSData*)requestBody { + _request.HTTPBody = requestBody; +} + +- (NSData*)requestBody { + return _request.HTTPBody; +} + +- (NSInteger)responseStatusCode { + return _response.statusCode; +} + +- (NSString*)responseMimeType { + return _response.MIMEType; +} + +- (NSString*)responseTextEncoding { + return _response.textEncodingName; +} + +- (NSDictionary*)responseHeaders { + return _response.allHeaderFields; +} + +- (NSData*)responseData { + return _mutableResponseData; +} + +- (NSString*)responseString { + return [NSString moStringWithData:_mutableResponseData encoding:NSASCIIStringEncoding]; +} + +- (NSDictionary*)responseJsonObject { + id json = self.responseJson; + if([json isKindOfClass:NSDictionary.class] == YES) { + return json; + } + return nil; +} + +- (NSArray*)responseJsonArray { + id json = self.responseJson; + if([json isKindOfClass:NSArray.class] == YES) { + return json; + } + return nil; +} + +- (id)responseJson { + if(_mutableResponseData.length < 1) { + return nil; + } + NSError* parseError = nil; + id result = [NSJSONSerialization JSONObjectWithData:_mutableResponseData options:0 error:&parseError]; + if(parseError != nil) { + NSLog(@"MobilyHttpQuery::responseJson:%@", parseError); + } + return result; +} + +#pragma mark Private + +- (NSDictionary*)_formDataFromDictionary:(NSDictionary*)dictionary { + NSMutableDictionary* result = NSMutableDictionary.dictionary; + [dictionary enumerateKeysAndObjectsUsingBlock:^(id keyPath, id value, BOOL* stop __unused) { + [self _formDataFromDictionary:result value:value keyPath:keyPath]; + }]; + return result; +} + +- (void)_formDataFromDictionary:(NSMutableDictionary*)dictionary value:(id)value keyPath:(NSString*)keyPath { + if([value isKindOfClass:NSDictionary.class] == YES) { + [value enumerateKeysAndObjectsUsingBlock:^(id dictKey, id dictValue, BOOL* stop __unused) { + [self _formDataFromDictionary:dictionary value:dictValue keyPath:[NSString stringWithFormat:@"%@[%@]", keyPath, dictKey]]; + }]; + } else if([value isKindOfClass:NSArray.class] == YES) { + [value enumerateObjectsUsingBlock:^(id arrayValue, NSUInteger arrayIndex, BOOL* stop __unused) { + [self _formDataFromDictionary:dictionary value:arrayValue keyPath:[NSString stringWithFormat:@"%@[%lu]", keyPath, (unsigned long)arrayIndex]]; + }]; + } else { + dictionary[keyPath] = value; + } +} + +#pragma mark NSURLConnectionDelegate + +- (void)connection:(NSURLConnection* __unused)connection didFailWithError:(NSError*)error { + _connection = nil; + _response = nil; + _mutableResponseData = nil; + _error = error; + + if([_delegate respondsToSelector:@selector(httpQuery:didError:)] == YES) { + [_delegate httpQuery:self didError:_error]; + } else if(_errorCallback != nil) { + _errorCallback(_error); + } + + UIApplication.sharedApplication.networkActivityIndicatorVisible = NO; +} + +- (void)connection:(NSURLConnection* __unused)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge*)challenge { + id< NSURLAuthenticationChallengeSender > sender = challenge.sender; + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + + if(_certificateFilename != nil) { + SecCertificateRef localCertificate = NULL; + SecTrustResultType serverTrustResult = kSecTrustResultOtherError; + NSString* path = [NSBundle.mainBundle pathForResource:_certificateFilename ofType:@"der"]; + if(path != nil) { + NSData* data = [NSData dataWithContentsOfFile:path]; + if(data != nil) { + CFDataRef cfData = (__bridge_retained CFDataRef)data; + localCertificate = SecCertificateCreateWithData(NULL, cfData); + if(localCertificate != NULL) { + CFArrayRef cfCertArray = CFArrayCreate(NULL, (void*)&localCertificate, 1, NULL); + if(cfCertArray != NULL) { + SecTrustSetAnchorCertificates(serverTrust, cfCertArray); + SecTrustEvaluate(serverTrust, &serverTrustResult); + if(serverTrustResult == kSecTrustResultRecoverableTrustFailure) { + CFDataRef cfErrorData = SecTrustCopyExceptions(serverTrust); + SecTrustSetExceptions(serverTrust, cfErrorData); + SecTrustEvaluate(serverTrust, &serverTrustResult); + CFRelease(cfErrorData); + } + CFRelease(cfCertArray); + } + } + CFRelease(cfData); + } + } + if((serverTrustResult == kSecTrustResultUnspecified) || (serverTrustResult == kSecTrustResultProceed)) { + SecCertificateRef serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0); + if(serverCertificate != NULL) { + NSString* serverHash = nil; + NSData* serverCertificateData = (__bridge_transfer NSData*)SecCertificateCopyData(serverCertificate); + if(serverCertificateData != nil) { + serverHash = serverCertificateData.moToBase64.moStringBySHA256; + } + NSString* localHash = nil; + NSData* localCertificateData = (__bridge_transfer NSData*)SecCertificateCopyData(localCertificate); + if(localCertificateData != nil) { + localHash = localCertificateData.moToBase64.moStringBySHA256; + } + if([serverHash isEqualToString:localHash] == YES) { + NSURLCredential* credential = [NSURLCredential credentialForTrust:serverTrust]; + if(credential != nil) { + [sender useCredential:credential forAuthenticationChallenge:challenge]; + } else { + [sender cancelAuthenticationChallenge:challenge]; + } + } else { + [sender cancelAuthenticationChallenge:challenge]; + } + } else { + [sender cancelAuthenticationChallenge:challenge]; + } + } else { + [sender cancelAuthenticationChallenge:challenge]; + } + if(localCertificate != NULL) { + CFRelease(localCertificate); + } + } else if(_allowInvalidCertificates == NO) { + [sender useCredential:[NSURLCredential credentialForTrust:serverTrust] forAuthenticationChallenge:challenge]; + } else { + [sender continueWithoutCredentialForAuthenticationChallenge:challenge]; + } +} + +#pragma mark NSURLConnectionDataDelegate + +- (NSCachedURLResponse*)connection:(NSURLConnection* __unused)connection willCacheResponse:(NSCachedURLResponse* __unused)cachedResponse { + return nil; +} + +- (void)connection:(NSURLConnection* __unused)connection didReceiveResponse:(NSURLResponse*)response { + if([response isKindOfClass:NSHTTPURLResponse.class] == YES) { + _response = (NSHTTPURLResponse*)response; + } +} + +- (void)connection:(NSURLConnection* __unused)connection didReceiveData:(NSData*)data { + if(_mutableResponseData == nil) { + _mutableResponseData = NSMutableData.data; + } + [_mutableResponseData appendData:data]; +} + +- (void)connectionDidFinishLoading:(NSURLConnection* __unused)connection { + _error = nil; + _connection = nil; + if([_delegate respondsToSelector:@selector(didFinishHttpQuery:)] == YES) { + [_delegate didFinishHttpQuery:self]; + } else if(_finishCallback != nil) { + _finishCallback(self); + } + UIApplication.sharedApplication.networkActivityIndicatorVisible = NO; +} + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyHttpAttachment + +#pragma mark Synthesize + +@synthesize name = _name; +@synthesize encodeName = _encodeName; +@synthesize filename = _filename; +@synthesize encodeFilename = _encodeFilename; +@synthesize mimeType = _mimeType; +@synthesize encodeMimeType = _encodeMimeType; +@synthesize data = _data; + +#pragma mark Init / Free + +- (instancetype)initWithName:(NSString*)name filename:(NSString*)filename mimeType:(NSString*)mimeType data:(NSData*)data { + self = [super init]; + if(self != nil) { + _name = name; + _encodeName = YES; + _filename = filename; + _encodeFilename = YES; + _mimeType = mimeType; + _encodeMimeType = YES; + _data = data; + [self setup]; + } + return self; +} + +- (void)setup { +} + +#pragma mark Debug + +- (NSString*)description { + return [NSString stringWithFormat:@"\tName = \"%@\"; Filename = \"%@\"; MimeType = \"%@\"; (%d bytes);", _name, _filename, _mimeType, (int)_data.length]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyImageCropController.h b/Sources/MobilyCore/MobilyImageCropController.h new file mode 100755 index 0000000..84f8388 --- /dev/null +++ b/Sources/MobilyCore/MobilyImageCropController.h @@ -0,0 +1,82 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, MobilyImageCropMode) { + MobilyImageCropModeCircle, + MobilyImageCropModeSquare +}; + +/*--------------------------------------------------*/ + +@class MobilyImageCropController; + +/*--------------------------------------------------*/ + +typedef void(^MobilyImageCropControllerChoose)(MobilyImageCropController* contoller, UIImage* image, CGRect cropRect); +typedef void(^MobilyImageCropControllerCancel)(MobilyImageCropController* contoller); + +/*--------------------------------------------------*/ + +@interface MobilyImageCropController : MobilyController + +- (instancetype)initWithImage:(UIImage*)originalImage; +- (instancetype)initWithImage:(UIImage*)originalImage cropMode:(MobilyImageCropMode)cropMode; + +@property(nonatomic, readwrite, strong) UIImage* originalImage; +@property(nonatomic, readwrite, strong) UIBezierPath* maskPath; +@property(nonatomic, readwrite, strong) UIColor* maskColor; +@property(nonatomic, readonly, assign) CGRect maskRect; + +@property(nonatomic, readonly, assign) MobilyImageCropMode cropMode; +@property(nonatomic, readonly, assign) CGRect cropRect; +@property(nonatomic, readonly, assign) CGFloat scale; + +@property(nonatomic, readwrite, assign) BOOL avoidEmptySpaceAroundImage; +@property(nonatomic, readwrite, assign) BOOL applyMaskToCroppedImage; + +@property(nonatomic, readwrite, copy) MobilyImageCropControllerChoose didChoose; +@property(nonatomic, readwrite, copy) MobilyImageCropControllerCancel didCancel; + +@property(nonatomic, readonly, strong) UILabel* titleLabel; +@property(nonatomic, readonly, strong) UIButton* chooseButton; +@property(nonatomic, readonly, strong) UIButton* cancelButton; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyImageCropController.m b/Sources/MobilyCore/MobilyImageCropController.m new file mode 100755 index 0000000..57c7766 --- /dev/null +++ b/Sources/MobilyCore/MobilyImageCropController.m @@ -0,0 +1,770 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyImageScrollView : UIScrollView { + CGSize _imageSize; + CGPoint _pointToCenterAfterResize; + CGFloat _scaleToRestoreAfterResize; +} + +@property(nonatomic, readwrite, strong) UIImageView* zoomView; +@property(nonatomic, readwrite, assign) BOOL aspectFill; + +- (void)_displayImage:(UIImage*)image; + +- (void)_centerZoomView; + +@end + +/*--------------------------------------------------*/ + +static const CGFloat MobilyImageCropController_PortraitCircleInsets = 15.0f; +static const CGFloat MobilyImageCropController_PortraitSquareInsets = 20.0f; +static const CGFloat MobilyImageCropController_PortraitTitleLabelVerticalMargin = 64.0f; +static const CGFloat MobilyImageCropController_PortraitButtonsHorizontalMargin = 13.0f; +static const CGFloat MobilyImageCropController_PortraitButtonsVerticalMargin = 21.0f; + +static const CGFloat MobilyImageCropController_LandscapeCircleInsets = 45.0f; +static const CGFloat MobilyImageCropController_LandscapeSquareInsets = 45.0f; +static const CGFloat MobilyImageCropController_LandscapeTitleLabelVerticalMargin = 12.0f; +static const CGFloat MobilyImageCropController_LandscapeButtonsHorizontalMargin = 13.0f; +static const CGFloat MobilyImageCropController_LandscapeButtonsVerticalMargin = 12.0f; + +static const CGFloat MobilyImageCropController_ResetDuration = 0.4f; +static const CGFloat MobilyImageCropController_ScrollDuration = 0.25f; + +/*--------------------------------------------------*/ + +@interface MobilyImageCropController () < UIScrollViewDelegate, UIGestureRecognizerDelegate > + +@property(nonatomic, readwrite, strong) MobilyImageScrollView* scrollView; +@property(nonatomic, readwrite, strong) MobilyTouchView* overlayView; +@property(nonatomic, readwrite, strong) CAShapeLayer* maskLayer; +@property(nonatomic, readwrite, assign) CGRect maskRect; + +@property(nonatomic, readwrite, strong) UILabel* titleLabel; +@property(nonatomic, readwrite, strong) UIButton* chooseButton; +@property(nonatomic, readwrite, strong) UIButton* cancelButton; +@property(nonatomic, readwrite, strong) UITapGestureRecognizer* doubleTapGestureRecognizer; + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyImageCropController + +#pragma mark Init / Free + +- (instancetype)initWithImage:(UIImage*)originalImage { + self = [super init]; + if(self != nil) { + _originalImage = originalImage; + } + return self; +} + +- (instancetype)initWithImage:(UIImage*)originalImage cropMode:(MobilyImageCropMode)cropMode { + self = [self initWithImage:originalImage]; + if(self != nil) { + _cropMode = cropMode; + } + return self; +} + +- (void)setup { + [super setup]; + + _cropMode = MobilyImageCropModeSquare; + _avoidEmptySpaceAroundImage = YES; + _applyMaskToCroppedImage = NO; +} + +#pragma mark Load / Unload + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor blackColor]; + self.view.clipsToBounds = YES; + + [self.view addSubview:self.scrollView]; + [self.view addSubview:self.overlayView]; + [self.view addSubview:self.titleLabel]; + [self.view addSubview:self.cancelButton]; + [self.view addSubview:self.chooseButton]; + + [self.view addGestureRecognizer:self.doubleTapGestureRecognizer]; +} + +#pragma mark Layout subviews + +- (void)viewWillLayoutSubviews { + [super viewWillLayoutSubviews]; + + [self _updateMask]; + [self _layoutImageScrollView]; + [self _layoutOverlayView]; + + CGRect bounds = self.view.bounds; + BOOL isPortrait = UIInterfaceOrientationIsPortrait(self.interfaceOrientation); + CGFloat titleLabelVerticalMargin = (isPortrait == YES) ? MobilyImageCropController_PortraitTitleLabelVerticalMargin : MobilyImageCropController_LandscapeTitleLabelVerticalMargin; + CGFloat buttonsHorizontalMargin = (isPortrait == YES) ? MobilyImageCropController_PortraitButtonsHorizontalMargin : MobilyImageCropController_LandscapeButtonsHorizontalMargin; + CGFloat buttonsVerticalMargin = (isPortrait == YES) ? MobilyImageCropController_PortraitButtonsVerticalMargin : MobilyImageCropController_LandscapeButtonsVerticalMargin; + + self.titleLabel.moFramePosition = CGPointMake((bounds.origin.x + (bounds.size.width * 0.5f)) - (self.titleLabel.moFrameWidth * 0.5f), bounds.origin.y + titleLabelVerticalMargin); + self.cancelButton.moFramePosition = CGPointMake(bounds.origin.x + buttonsHorizontalMargin, (bounds.origin.y + bounds.size.height) - (self.cancelButton.moFrameHeight + buttonsVerticalMargin)); + self.chooseButton.moFramePosition = CGPointMake((bounds.origin.x + bounds.size.width) - (self.chooseButton.moFrameWidth + buttonsHorizontalMargin), (bounds.origin.y + bounds.size.height) - (self.cancelButton.moFrameHeight + buttonsVerticalMargin)); +} + +- (void)viewDidLayoutSubviews { + [super viewDidLayoutSubviews]; + + if(self.scrollView.zoomView == nil) { + [self _displayImage]; + } +} + +#pragma mark Property + +- (CGRect)cropRect { + CGFloat zoom = 1.0f / self.scrollView.zoomScale; + CGPoint offset = self.scrollView.contentOffset; + CGSize boundsSize = self.scrollView.moBoundsSize; + CGFloat x = round(offset.x * zoom); + CGFloat y = round(offset.y * zoom); + CGFloat w = MOBILY_CEIL(boundsSize.width * zoom); + CGFloat h = MOBILY_CEIL(boundsSize.height * zoom); + return CGRectIntegral(CGRectMake(x, y, w, h)); +} + +- (CGFloat)angle { + CGAffineTransform transform = self.scrollView.transform; + return MOBILY_ATAN2(transform.b, transform.a); +} + +- (CGFloat)scale { + return self.scrollView.zoomScale; +} + +- (void)setAvoidEmptySpaceAroundImage:(BOOL)avoidEmptySpaceAroundImage { + if(_avoidEmptySpaceAroundImage != avoidEmptySpaceAroundImage) { + _avoidEmptySpaceAroundImage = avoidEmptySpaceAroundImage; + if(self.isViewLoaded == YES) { + self.scrollView.aspectFill = _avoidEmptySpaceAroundImage; + } + } +} + +- (void)setOriginalImage:(UIImage*)originalImage { + if([_originalImage isEqual:originalImage] == NO) { + _originalImage = originalImage; + if((self.isViewLoaded == YES) && (self.view.window != nil)) { + [self _displayImage]; + } + } +} + +- (void)setMaskPath:(UIBezierPath*)maskPath { + if([_maskPath isEqual:maskPath] == NO) { + _maskPath = maskPath; + + UIBezierPath* clipPath = [UIBezierPath bezierPathWithRect:self.overlayView.frame]; + clipPath.usesEvenOddFillRule = YES; + [clipPath appendPath:maskPath]; + + CABasicAnimation* pathAnimation = [CABasicAnimation animationWithKeyPath:@"path"]; + pathAnimation.timingFunction = [CATransaction animationTimingFunction]; + pathAnimation.duration = [CATransaction animationDuration]; + [self.maskLayer addAnimation:pathAnimation forKey:@"path"]; + + self.maskLayer.path = [clipPath CGPath]; + } +} + +- (MobilyImageScrollView*)scrollView { + if(_scrollView == nil) { + _scrollView = [[MobilyImageScrollView alloc] initWithFrame:self.view.bounds]; + _scrollView.aspectFill = self.avoidEmptySpaceAroundImage; + _scrollView.delegate = self; + } + return _scrollView; +} + +- (MobilyTouchView*)overlayView { + if(_overlayView == nil) { + _overlayView = [[MobilyTouchView alloc] initWithFrame:self.view.bounds]; + _overlayView.receiver = self.scrollView; + [_overlayView.layer addSublayer:self.maskLayer]; + } + return _overlayView; +} + +- (CAShapeLayer*)maskLayer { + if(_maskLayer == nil) { + _maskLayer = [CAShapeLayer layer]; + _maskLayer.fillRule = kCAFillRuleEvenOdd; + _maskLayer.fillColor = self.maskColor.CGColor; + } + return _maskLayer; +} + +- (UIColor*)maskColor { + if(_maskColor == nil) { + _maskColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:0.7f]; + } + return _maskColor; +} + +- (UILabel*)titleLabel { + if(_titleLabel == nil) { + _titleLabel = [[UILabel alloc] init]; + _titleLabel.backgroundColor = [UIColor clearColor]; + _titleLabel.text = NSLocalizedString(@"Move and Scale", @"Move and Scale label"); + _titleLabel.textColor = [UIColor whiteColor]; + _titleLabel.opaque = NO; + [_titleLabel sizeToFit]; + } + return _titleLabel; +} + +- (UIButton*)cancelButton { + if(_cancelButton == nil) { + _cancelButton = [[UIButton alloc] init]; + _cancelButton.moNormalTitle = NSLocalizedString(@"Cancel", @"Cancel button"); + _cancelButton.opaque = NO; + + [_cancelButton addTarget:self action:@selector(onCancelButtonTouch:) forControlEvents:UIControlEventTouchUpInside]; + [_cancelButton sizeToFit]; + } + return _cancelButton; +} + +- (UIButton*)chooseButton { + if(_chooseButton == nil) { + _chooseButton = [[UIButton alloc] init]; + _chooseButton.moNormalTitle = NSLocalizedString(@"Choose", @"Choose button"); + _chooseButton.opaque = NO; + + [_chooseButton addTarget:self action:@selector(onChooseButtonTouch:) forControlEvents:UIControlEventTouchUpInside]; + [_chooseButton sizeToFit]; + } + return _chooseButton; +} + +- (UITapGestureRecognizer*)doubleTapGestureRecognizer { + if(_doubleTapGestureRecognizer == nil) { + _doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)]; + _doubleTapGestureRecognizer.numberOfTapsRequired = 2; + _doubleTapGestureRecognizer.delaysTouchesEnded = NO; + _doubleTapGestureRecognizer.delegate = self; + } + return _doubleTapGestureRecognizer; +} + +#pragma mark Actions + +- (void)onCancelButtonTouch:(UIBarButtonItem*)sender { + [self cancelCrop]; +} + +- (void)onChooseButtonTouch:(UIBarButtonItem*)sender { + [self _cropImage]; +} + +- (void)handleDoubleTap:(UITapGestureRecognizer*)gestureRecognizer { + [self _reset:YES]; +} + +- (void)handleRotation:(UIRotationGestureRecognizer*)gestureRecognizer { + [self _applyAngle:(self.angle + gestureRecognizer.rotation)]; + gestureRecognizer.rotation = 0; + + if(gestureRecognizer.state == UIGestureRecognizerStateEnded) { + [UIView animateWithDuration:MobilyImageCropController_ScrollDuration delay:0.0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{ + [self _layoutImageScrollView]; + } completion:nil]; + } +} + +#pragma mark Private + +- (void)_reset:(BOOL)animated { + if(animated == YES) { + [UIView beginAnimations:@"reset" context:NULL]; + [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; + [UIView setAnimationDuration:MobilyImageCropController_ResetDuration]; + [UIView setAnimationBeginsFromCurrentState:YES]; + } + [self _resetRotation]; + [self _resetFrame]; + [self _resetZoomScale]; + [self _resetContentOffset]; + if(animated == YES) { + [UIView commitAnimations]; + } +} + +- (void)_resetContentOffset { + CGSize boundsSize = self.scrollView.bounds.size; + CGRect zoomFrame = self.scrollView.zoomView.frame; + CGPoint contentOffset; + if(zoomFrame.size.width > boundsSize.width) { + contentOffset.x = (zoomFrame.size.width - boundsSize.width) * 0.5f; + } else { + contentOffset.x = 0.0f; + } + if(zoomFrame.size.height > boundsSize.height) { + contentOffset.y = (zoomFrame.size.height - boundsSize.height) * 0.5f; + } else { + contentOffset.y = 0.0f; + } + self.scrollView.contentOffset = contentOffset; +} + +- (void)_resetFrame { + [self _layoutImageScrollView]; +} + +- (void)_resetRotation { + [self _applyAngle:0.0]; +} + +- (void)_resetZoomScale { + CGSize boundsSize = self.view.bounds.size; + CGSize imageSize = self.originalImage.size; + CGFloat zoomScale; + if(boundsSize.width > boundsSize.height) { + zoomScale = boundsSize.height / imageSize.height; + } else { + zoomScale = boundsSize.width / imageSize.width; + } + self.scrollView.zoomScale = zoomScale; +} + +- (void)_applyAngle:(CGFloat)angle { + self.scrollView.transform = CGAffineTransformRotate(self.scrollView.transform, (angle - self.angle)); +} + +- (NSArray*)_intersectionPointsOfLineSegment:(MobilyLineSegment)lineSegment withRect:(CGRect)rect { + CGPoint tl = MobilyRectGetTopLeftPoint(rect); + CGPoint tr = MobilyRectGetTopRightPoint(rect); + CGPoint bl = MobilyRectGetBottomLeftPoint(rect); + CGPoint br = MobilyRectGetBottomRightPoint(rect); + MobilyLineSegment ts = MobilyLineSegmentMake(tl, tr); + MobilyLineSegment rs = MobilyLineSegmentMake(tr, br); + MobilyLineSegment bs = MobilyLineSegmentMake(br, bl); + MobilyLineSegment ls = MobilyLineSegmentMake(bl, tl); + CGPoint p0 = MobilyLineSegmentIntersection(ts, lineSegment); + CGPoint p1 = MobilyLineSegmentIntersection(rs, lineSegment); + CGPoint p2 = MobilyLineSegmentIntersection(bs, lineSegment); + CGPoint p3 = MobilyLineSegmentIntersection(ls, lineSegment); + NSMutableArray* intersectionPoints = [NSMutableArray array]; + if(MobilyPointIsInfinity(p0) == NO) { + [intersectionPoints addObject:[NSValue valueWithCGPoint:p0]]; + } + if(MobilyPointIsInfinity(p1) == NO) { + [intersectionPoints addObject:[NSValue valueWithCGPoint:p1]]; + } + if(MobilyPointIsInfinity(p2) == NO) { + [intersectionPoints addObject:[NSValue valueWithCGPoint:p2]]; + } + if(MobilyPointIsInfinity(p3) == NO) { + [intersectionPoints addObject:[NSValue valueWithCGPoint:p3]]; + } + return intersectionPoints; +} + +- (void)_displayImage { + if(self.originalImage != nil) { + [self.scrollView _displayImage:self.originalImage]; + [self _reset:NO]; + } +} + +- (void)_layoutImageScrollView { + CGRect frame = CGRectZero; + switch(self.cropMode) { + case MobilyImageCropModeSquare: { + CGFloat angle = self.angle; + if(angle == 0.0f) { + frame = self.maskRect; + } else { + CGFloat rotation = MOBILY_FABS(angle); + CGRect initialRect = self.maskRect; + CGPoint leftTopPoint = CGPointMake(initialRect.origin.x, initialRect.origin.y); + CGPoint leftBottomPoint = CGPointMake(initialRect.origin.x, initialRect.origin.y + initialRect.size.height); + CGPoint pivot = MobilyRectGetCenterPoint(initialRect); + MobilyLineSegment leftLineSegment = MobilyLineSegmentMake(leftTopPoint, leftBottomPoint); + MobilyLineSegment rotatedLeftLineSegment = MobilyLineSegmentRotateAroundPoint(leftLineSegment, pivot, rotation); + NSArray* points = [self _intersectionPointsOfLineSegment:rotatedLeftLineSegment withRect:initialRect]; + if(points.count > 1) { + if((rotation > M_PI_2) && (rotation < M_PI)) { + rotation = rotation - M_PI_2; + } else if((rotation > (M_PI + M_PI_2)) && (rotation < (M_PI + M_PI))) { + rotation = rotation - (M_PI + M_PI_2); + } + CGFloat sinAlpha = MOBILY_SIN(rotation); + CGFloat cosAlpha = MOBILY_COS(rotation); + CGFloat hypotenuse = MobilyPointDistance([points[0] CGPointValue], [points[1] CGPointValue]); + CGFloat altitude = hypotenuse * sinAlpha * cosAlpha; + CGFloat initialWidth = initialRect.size.width; + CGFloat targetWidth = initialWidth + altitude * 2.0f; + CGFloat scale = targetWidth / initialWidth; + CGPoint center = MobilyRectGetCenterPoint(initialRect); + frame = MobilyRectScaleAroundPoint(initialRect, center, scale, scale); + frame.origin.x = round(CGRectGetMinX(frame)); + frame.origin.y = round(CGRectGetMinY(frame)); + frame = CGRectIntegral(frame); + } else { + frame = initialRect; + } + } + break; + } + case MobilyImageCropModeCircle: { + frame = self.maskRect; + break; + } + } + + CGAffineTransform transform = self.scrollView.transform; + self.scrollView.transform = CGAffineTransformIdentity; + self.scrollView.frame = frame; + self.scrollView.transform = transform; +} + +- (void)_layoutOverlayView { + CGSize boundsSize = self.view.bounds.size; + self.overlayView.frame = CGRectMake(0, 0, boundsSize.width * 2.0f, boundsSize.height * 2.0f); +} + +- (void)_updateMask { + CGSize boundsSize = self.view.bounds.size; + switch(self.cropMode) { + case MobilyImageCropModeCircle: { + CGFloat diameter; + if(UIInterfaceOrientationIsPortrait(self.interfaceOrientation) == YES) { + diameter = MIN(boundsSize.width, boundsSize.height) - MobilyImageCropController_PortraitCircleInsets * 2; + } else { + diameter = MIN(boundsSize.width, boundsSize.height) - MobilyImageCropController_LandscapeCircleInsets * 2; + } + self.maskRect = CGRectMake((boundsSize.width - diameter) * 0.5f, (boundsSize.height - diameter) * 0.5f, diameter, diameter); + self.maskPath = [UIBezierPath bezierPathWithOvalInRect:self.maskRect]; + break; + } + case MobilyImageCropModeSquare: { + CGFloat length; + if(UIInterfaceOrientationIsPortrait(self.interfaceOrientation) == YES) { + length = MIN(boundsSize.width, boundsSize.height) - MobilyImageCropController_PortraitSquareInsets * 2; + } else { + length = MIN(boundsSize.width, boundsSize.height) - MobilyImageCropController_LandscapeSquareInsets * 2; + } + self.maskRect = CGRectMake((boundsSize.width - length) * 0.5f, (boundsSize.height - length) * 0.5f, length, length); + self.maskPath = [UIBezierPath bezierPathWithRect:self.maskRect]; + break; + } + } +} + +- (UIImage*)_croppedImage:(UIImage*)image cropMode:(MobilyImageCropMode)cropMode cropRect:(CGRect)cropRect zoom:(CGFloat)zoom maskPath:(UIBezierPath*)maskPath applyMaskToCroppedImage:(BOOL)applyMaskToCroppedImage { + CGSize imageSize = image.size; + CGFloat x = CGRectGetMinX(cropRect); + CGFloat y = CGRectGetMinY(cropRect); + CGFloat width = CGRectGetWidth(cropRect); + CGFloat height = CGRectGetHeight(cropRect); + UIImageOrientation imageOrientation = image.imageOrientation; + if(imageOrientation == UIImageOrientationRight || imageOrientation == UIImageOrientationRightMirrored) { + cropRect.origin.x = y; + cropRect.origin.y = round(imageSize.width - CGRectGetWidth(cropRect) - x); + cropRect.size.width = height; + cropRect.size.height = width; + } else if(imageOrientation == UIImageOrientationLeft || imageOrientation == UIImageOrientationLeftMirrored) { + cropRect.origin.x = round(imageSize.height - CGRectGetHeight(cropRect) - y); + cropRect.origin.y = x; + cropRect.size.width = height; + cropRect.size.height = width; + } else if(imageOrientation == UIImageOrientationDown || imageOrientation == UIImageOrientationDownMirrored) { + cropRect.origin.x = round(imageSize.width - CGRectGetWidth(cropRect) - x); + cropRect.origin.y = round(imageSize.height - CGRectGetHeight(cropRect) - y); + } + CGFloat imageScale = image.scale; + cropRect = CGRectApplyAffineTransform(cropRect, CGAffineTransformMakeScale(imageScale, imageScale)); + CGImageRef croppedCGImage = CGImageCreateWithImageInRect(image.CGImage, cropRect); + UIImage *croppedImage = [UIImage imageWithCGImage:croppedCGImage scale:imageScale orientation:imageOrientation]; + CGImageRelease(croppedCGImage); + croppedImage = [croppedImage moUnrotate]; + imageOrientation = croppedImage.imageOrientation; + if((cropMode == MobilyImageCropModeSquare) || (applyMaskToCroppedImage == NO)) { + return croppedImage; + } else { + CGSize maskSize = CGRectIntegral(maskPath.bounds).size; + CGSize contextSize = CGSizeMake(MOBILY_CEIL(maskSize.width / zoom), MOBILY_CEIL(maskSize.height / zoom)); + UIGraphicsBeginImageContextWithOptions(contextSize, NO, imageScale); + if(applyMaskToCroppedImage == YES) { + UIBezierPath* maskPathCopy = [maskPath copy]; + CGFloat scale = 1.0f / zoom; + [maskPathCopy applyTransform:CGAffineTransformMakeScale(scale, scale)]; + CGPoint translation = CGPointMake(-CGRectGetMinX(maskPathCopy.bounds), -CGRectGetMinY(maskPathCopy.bounds)); + [maskPathCopy applyTransform:CGAffineTransformMakeTranslation(translation.x, translation.y)]; + [maskPathCopy addClip]; + } + CGPoint point = CGPointMake(round((contextSize.width - croppedImage.size.width) * 0.5f), round((contextSize.height - croppedImage.size.height) * 0.5f)); + [croppedImage drawAtPoint:point]; + croppedImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + croppedImage = [UIImage imageWithCGImage:croppedImage.CGImage scale:imageScale orientation:imageOrientation]; + return croppedImage; + } +} + +- (void)_cropImage { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + CGRect cropRect = self.cropRect; + UIImage* croppedImage = [self _croppedImage:self.originalImage cropMode:self.cropMode cropRect:self.cropRect zoom:self.scrollView.zoomScale maskPath:self.maskPath applyMaskToCroppedImage:self.applyMaskToCroppedImage]; + dispatch_async(dispatch_get_main_queue(), ^{ + if(_didChoose != nil) { + _didChoose(self, croppedImage, cropRect); + } + }); + }); +} + +- (void)cancelCrop { + if(_didCancel != nil) { + _didCancel(self); + } +} + +#pragma mark UIScrollViewDelegate + +- (UIView*)viewForZoomingInScrollView:(__unused UIScrollView*)scrollView { + return self.scrollView.zoomView; +} + +- (void)scrollViewDidZoom:(__unused UIScrollView*)scrollView { + [self.scrollView _centerZoomView]; +} + +#pragma mark UIGestureRecognizerDelegate + +- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer { + return YES; +} + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyImageScrollView + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + self.decelerationRate = UIScrollViewDecelerationRateFast; + self.showsHorizontalScrollIndicator = NO; + self.showsVerticalScrollIndicator = NO; + self.alwaysBounceHorizontal = YES; + self.alwaysBounceVertical = YES; + self.bouncesZoom = YES; + self.clipsToBounds = NO; + self.scrollsToTop = NO; + } + return self; +} + +- (void)didAddSubview:(UIView*)subview { + [super didAddSubview:subview]; + [self _centerZoomView]; +} + +- (void)setFrame:(CGRect)frame { + BOOL sizeChanging = CGSizeEqualToSize(self.moFrameSize, frame.size); + if(sizeChanging == NO) { + [self _prepareToResize]; + } + [super setFrame:frame]; + if(sizeChanging == NO) { + [self _recoverFromResizing]; + [self _centerZoomView]; + } +} + +#pragma mark Private + +- (void)_centerZoomView { + CGSize boundsSize = self.bounds.size; + CGSize contentSize = self.contentSize; + if((boundsSize.width > MOBILY_EPSILON) && (boundsSize.height > MOBILY_EPSILON) && (contentSize.width > MOBILY_EPSILON) && (contentSize.height > MOBILY_EPSILON)) { + if(self.aspectFill == YES) { + CGFloat top = 0.0f; + CGFloat left = 0.0f; + if(contentSize.height < boundsSize.height) { + top = (boundsSize.height - contentSize.height) * 0.5f; + } + if(contentSize.width < boundsSize.width) { + left = (boundsSize.width - contentSize.width) * 0.5f; + } + self.contentInset = UIEdgeInsetsMake(top, left, top, left); + } else { + CGRect frameToCenter = self.zoomView.frame; + if(frameToCenter.size.width < boundsSize.width) { + frameToCenter.origin.x = (boundsSize.width - frameToCenter.size.width) * 0.5f; + } else { + frameToCenter.origin.x = 0.0f; + } + if(CGRectGetHeight(frameToCenter) < contentSize.height) { + frameToCenter.origin.y = (contentSize.height - frameToCenter.size.height) * 0.5f; + } else { + frameToCenter.origin.y = 0.0f; + } + self.zoomView.frame = frameToCenter; + } + } +} + +- (void)_displayImage:(UIImage*)image { + [_zoomView removeFromSuperview]; + _zoomView = nil; + self.zoomScale = 1.0; + _zoomView = [[UIImageView alloc] initWithImage:image]; + [self addSubview:_zoomView]; + [self _configureForImageSize:image.size]; +} + +- (void)_configureForImageSize:(CGSize)imageSize { + _imageSize = imageSize; + self.contentSize = imageSize; + [self _setMaxMinZoomScalesForCurrentBounds]; + [self _setInitialZoomScale]; + [self _setInitialContentOffset]; + self.contentInset = UIEdgeInsetsZero; +} + +- (void)_setMaxMinZoomScalesForCurrentBounds { + CGSize boundsSize = self.bounds.size; + if((boundsSize.width > MOBILY_EPSILON) && (boundsSize.height > MOBILY_EPSILON) && (_imageSize.width > MOBILY_EPSILON) && (_imageSize.height > MOBILY_EPSILON)) { + CGFloat xScale = boundsSize.width / _imageSize.width; + CGFloat yScale = boundsSize.height / _imageSize.height; + CGFloat minScale; + if(self.aspectFill == YES) { + minScale = MAX(xScale, yScale); + } else { + minScale = MIN(xScale, yScale); + } + CGFloat maxScale = MAX(xScale, yScale); + CGFloat xImageScale = maxScale * _imageSize.width / boundsSize.width; + CGFloat yImageScale = maxScale * _imageSize.height / boundsSize.width; + CGFloat maxImageScale = MAX(xImageScale, yImageScale); + maxImageScale = MAX(minScale, maxImageScale); + maxScale = MAX(maxScale, maxImageScale); + if(minScale > maxScale) { + minScale = maxScale; + } + self.minimumZoomScale = minScale; + self.maximumZoomScale = maxScale; + } else { + self.minimumZoomScale = 1.0f; + self.maximumZoomScale = 1.0f; + } +} + +- (void)_setInitialZoomScale { + CGSize boundsSize = self.bounds.size; + if((boundsSize.width > MOBILY_EPSILON) && (boundsSize.height > MOBILY_EPSILON) && (_imageSize.width > MOBILY_EPSILON) && (_imageSize.height > MOBILY_EPSILON)) { + CGFloat xScale = boundsSize.width / _imageSize.width; + CGFloat yScale = boundsSize.height / _imageSize.height; + CGFloat scale = MAX(xScale, yScale); + self.zoomScale = scale; + } else { + self.zoomScale = 1.0f; + } +} + +- (void)_setInitialContentOffset { + CGSize boundsSize = self.bounds.size; + CGSize zoomSize = self.zoomView.moFrameSize; + if((boundsSize.width > MOBILY_EPSILON) && (boundsSize.height > MOBILY_EPSILON) && (zoomSize.width > MOBILY_EPSILON) && (zoomSize.height > MOBILY_EPSILON)) { + CGPoint contentOffset = CGPointZero; + if(zoomSize.width > boundsSize.width) { + contentOffset.x = (zoomSize.width - boundsSize.width) * 0.5f; + } + if(zoomSize.height > boundsSize.height) { + contentOffset.y = (zoomSize.height - boundsSize.height) * 0.5f; + } + self.contentOffset = contentOffset; + } +} + +- (void)_prepareToResize { + CGRect bounds = self.bounds; + _pointToCenterAfterResize = [self convertPoint:MobilyRectGetCenterPoint(bounds) toView:self.zoomView]; + _scaleToRestoreAfterResize = self.zoomScale; + if(_scaleToRestoreAfterResize <= self.minimumZoomScale + MOBILY_EPSILON) { + _scaleToRestoreAfterResize = 0; + } +} + +- (void)_recoverFromResizing { + [self _setMaxMinZoomScalesForCurrentBounds]; + self.zoomScale = MIN(self.maximumZoomScale, MAX(_scaleToRestoreAfterResize, self.minimumZoomScale)); + CGPoint boundsCenter = [self convertPoint:_pointToCenterAfterResize fromView:self.zoomView]; + CGPoint offset = CGPointMake(boundsCenter.x - self.bounds.size.width * 0.5f, boundsCenter.y - self.bounds.size.height * 0.5f); + CGPoint maxOffset = [self _maximumContentOffset]; + CGPoint minOffset = [self _minimumContentOffset]; + offset.x = MAX(minOffset.x, MIN(maxOffset.x, offset.x)); + offset.y = MAX(minOffset.y, MIN(maxOffset.y, offset.y)); + self.contentOffset = offset; +} + +- (CGPoint)_maximumContentOffset { + CGSize contentSize = self.contentSize; + CGSize boundsSize = self.moBoundsSize; + return CGPointMake(contentSize.width - boundsSize.width, contentSize.height - boundsSize.height); +} + +- (CGPoint)_minimumContentOffset { + return CGPointZero; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyImageView.h b/Sources/MobilyCore/MobilyImageView.h new file mode 100644 index 0000000..cc34700 --- /dev/null +++ b/Sources/MobilyCore/MobilyImageView.h @@ -0,0 +1,82 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef void (^MobilyImageViewBlock)(); + +/*--------------------------------------------------*/ + +@interface MobilyImageView : UIImageView< MobilyBuilderObject > + +@property(nonatomic, readwrite, assign) IBInspectable BOOL roundCorners; +@property(nonatomic, readwrite, assign) IBInspectable BOOL automaticShadowPath; +@property(nonatomic, readwrite, strong) IBInspectable UIImage* defaultImage; +@property(nonatomic, readwrite, strong) IBInspectable NSURL* imageUrl; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)setImageUrl:(NSURL*)imageUrl complete:(MobilyImageViewBlock)complete failure:(MobilyImageViewBlock)failure; + +@end + +/*--------------------------------------------------*/ + +typedef void (^MobilyImageDownloaderCompleteBlock)(UIImage* image, NSURL* url); +typedef void (^MobilyImageDownloaderFailureBlock)(NSURL* url); + +/*--------------------------------------------------*/ + +@interface MobilyImageDownloader : NSObject + ++ (instancetype)shared; + +- (BOOL)isExistImageWithUrl:(NSURL*)url; +- (void)setImage:(UIImage*)image byUrl:(NSURL*)url; +- (void)removeByUrl:(NSURL*)url; +- (void)cleanup; + +- (UIImage*)imageWithUrl:(NSURL*)url; + +- (void)downloadWithUrl:(NSURL*)url byTarget:(id)target completeSelector:(SEL)completeSelector failureSelector:(SEL)failureSelector; +- (void)downloadWithUrl:(NSURL*)url byTarget:(id)target completeBlock:(MobilyImageDownloaderCompleteBlock)completeBlock failureBlock:(MobilyImageDownloaderFailureBlock)failureBlock; +- (void)cancelByUrl:(NSURL*)url; +- (void)cancelByTarget:(id)target; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyImageView.m b/Sources/MobilyCore/MobilyImageView.m new file mode 100644 index 0000000..9f59f48 --- /dev/null +++ b/Sources/MobilyCore/MobilyImageView.m @@ -0,0 +1,297 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyImageDownloader () < MobilyDownloaderDelegate > + +@property(nonatomic, readwrite, strong) MobilyDownloader* downloader; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyImageView + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; + +#pragma mark NSKeyValueCoding + +#pragma mark Init / Free + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + self.clipsToBounds = YES; +} + +- (void)dealloc { + self.objectName = nil; + self.objectParent = nil; + self.objectChilds = nil; + + self.defaultImage = nil; + self.imageUrl = nil; +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return self.subviews; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + [self addSubview:(UIView*)objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + [self moRemoveSubview:(UIView*)objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark Property override + +- (void)setFrame:(CGRect)frame { + [super setFrame:frame]; + [self _updateCorners]; + [self _updateShadow]; +} + +- (void)setBounds:(CGRect)bounds { + [super setBounds:bounds]; + [self _updateCorners]; + [self _updateShadow]; +} + +#pragma mark Property + +- (void)setRoundCorners:(BOOL)roundCorners { + if(_roundCorners != roundCorners) { + _roundCorners = roundCorners; + [self _updateCorners]; + [self _updateShadow]; + } +} + +- (void)setAutomaticShadowPath:(BOOL)automaticShadowPath { + if(_automaticShadowPath != automaticShadowPath) { + _automaticShadowPath = automaticShadowPath; + self.clipsToBounds = (_automaticShadowPath == NO); + [self _updateShadow]; + } +} + +- (void)setImage:(UIImage*)image { + if(image == nil) { + image = _defaultImage; + } + super.image = image; +} + +- (void)setImageUrl:(NSURL*)imageUrl { + [self setImageUrl:imageUrl complete:nil failure:nil]; +} + +- (void)setImageUrl:(NSURL*)imageUrl complete:(MobilyImageViewBlock)complete failure:(MobilyImageViewBlock)failure { + if([_imageUrl isEqual:imageUrl] == NO) { + if(_imageUrl != nil) { + [[MobilyImageDownloader shared] cancelByTarget:self]; + } + _imageUrl = imageUrl; + super.image = _defaultImage; + [[MobilyImageDownloader shared] downloadWithUrl:_imageUrl byTarget:self completeBlock:^(UIImage* image, NSURL* url __unused) { + super.image = image; + if(complete != nil) { + complete(); + } + } failureBlock:^(NSURL* url __unused) { + if(failure != nil) { + failure(); + } + }]; + } else { + if(complete != nil) { + complete(); + } + } +} + +#pragma mark Private + +- (void)_updateCorners { + if(_roundCorners == YES) { + CGRect bounds = self.bounds; + self.layer.cornerRadius = ceilf(MIN(bounds.size.width - 1.0f, bounds.size.height - 1.0f) * 0.5f); + } +} + +- (void)_updateShadow { + if(_automaticShadowPath == YES) { + CGRect bounds = self.bounds; + if((bounds.size.width > 0.0f) && (bounds.size.height > 0.0f)) { + self.layer.shadowPath = [[UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:self.layer.cornerRadius] CGPath]; + } + } +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyImageDownloader + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + self.downloader = [[MobilyDownloader alloc] initWithDelegate:self]; + } + return self; +} + +- (void)dealloc { + self.downloader = nil; +} + +#pragma mark Public + ++ (instancetype)shared { + static id shared = nil; + if(shared == nil) { + @synchronized(self) { + if(shared == nil) { + shared = [self new]; + } + } + } + return shared; +} + +- (BOOL)isExistImageWithUrl:(NSURL*)url { + return [_downloader isExistEntryByUrl:url]; +} + +- (UIImage*)imageWithUrl:(NSURL*)url { + return [_downloader entryByUrl:url]; +} + +- (void)setImage:(UIImage*)image byUrl:(NSURL*)url { + [_downloader setEntry:image byUrl:url]; +} + +- (void)removeByUrl:(NSURL*)url { + [_downloader removeEntryByUrl:url]; +} + +- (void)cleanup { + [_downloader cleanup]; +} + +- (void)downloadWithUrl:(NSURL*)url byTarget:(id)target completeSelector:(SEL)completeSelector failureSelector:(SEL)failureSelector { + [_downloader downloadWithUrl:url byTarget:target completeSelector:completeSelector failureSelector:failureSelector]; +} + +- (void)downloadWithUrl:(NSURL*)url byTarget:(id)target completeBlock:(MobilyImageDownloaderCompleteBlock)completeBlock failureBlock:(MobilyImageDownloaderFailureBlock)failureBlock { + [_downloader downloadWithUrl:url byTarget:target completeBlock:completeBlock failureBlock:failureBlock]; +} + +- (void)cancelByUrl:(NSURL*)url { + [_downloader cancelByUrl:url]; +} + +- (void)cancelByTarget:(id)target { + [_downloader cancelByTarget:target]; +} + +#pragma mark MobilyDownloaderDelegate + +- (id)downloader:(MobilyDownloader* __unused)mobilyDownloader entryFromData:(NSData*)data { + return [UIImage imageWithData:data]; +} + +- (NSData*)downloader:(MobilyDownloader* __unused)mobilyDownloader entryToData:(id)entry { + return UIImagePNGRepresentation(entry); +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/NS/Core/MobilyKVO.h b/Sources/MobilyCore/MobilyKVO.h similarity index 84% rename from Classes/NS/Core/MobilyKVO.h rename to Sources/MobilyCore/MobilyKVO.h index 019ad29..051cb7e 100644 --- a/Classes/NS/Core/MobilyKVO.h +++ b/Sources/MobilyCore/MobilyKVO.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,7 +33,7 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyNS.h" +#import /*--------------------------------------------------*/ @@ -45,13 +45,16 @@ typedef void (^MobilyKVOBlock)(MobilyKVO* kvo, id oldValue, id newValue); /*--------------------------------------------------*/ -@interface MobilyKVO : NSObject +@interface MobilyKVO : NSObject< MobilyObject > @property(nonatomic, readonly, weak) id subject; @property(nonatomic, readonly, strong) NSString* keyPath; @property(nonatomic, readwrite, copy) MobilyKVOBlock block; -- (id)initWithSubject:(id)subject keyPath:(NSString*)keyPath block:(MobilyKVOBlock)block; +- (instancetype)initWithSubject:(id)subject keyPath:(NSString*)keyPath block:(MobilyKVOBlock)block; + +- (void)setup NS_REQUIRES_SUPER; + - (void)stopObservation; @end @@ -60,8 +63,8 @@ typedef void (^MobilyKVOBlock)(MobilyKVO* kvo, id oldValue, id newValue); @interface NSObject (MobilyKVO) -- (MobilyKVO*)observeKeyPath:(NSString*)keyPath withBlock:(MobilyKVOBlock)block; -- (MobilyKVO*)observeSelector:(SEL)selector withBlock:(MobilyKVOBlock)block; +- (MobilyKVO*)moObserveKeyPath:(NSString*)keyPath withBlock:(MobilyKVOBlock)block; +- (MobilyKVO*)moObserveSelector:(SEL)selector withBlock:(MobilyKVOBlock)block; @end diff --git a/Classes/NS/Core/MobilyKVO.m b/Sources/MobilyCore/MobilyKVO.m similarity index 78% rename from Classes/NS/Core/MobilyKVO.m rename to Sources/MobilyCore/MobilyKVO.m index 8022ba4..412ae1e 100644 --- a/Classes/NS/Core/MobilyKVO.m +++ b/Sources/MobilyCore/MobilyKVO.m @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -32,8 +32,10 @@ /* OTHER DEALINGS IN THE SOFTWARE. */ /* */ /*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ -#import "MobilyKVO.h" +#import /*--------------------------------------------------*/ @@ -52,46 +54,49 @@ @interface MobilyKVO () @implementation MobilyKVO -#pragma mark Standart +#pragma mark Init / Free -- (id)initWithSubject:(id)subject keyPath:(NSString*)keyPath block:(MobilyKVOBlock)block { +- (instancetype)initWithSubject:(id)subject keyPath:(NSString*)keyPath block:(MobilyKVOBlock)block { self = [super init]; if(self != nil) { - [self setSubject:subject]; - [self setKeyPath:keyPath]; - [self setBlock:block]; + self.subject = subject; + self.keyPath = keyPath; + self.block = block; [subject addObserver:self forKeyPath:keyPath options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:MobilyKVOContext]; + + [self setup]; } return self; } +- (void)setup { +} + - (void)dealloc { [self stopObservation]; - [self setKeyPath:nil]; - [self setBlock:nil]; - - MOBILY_SAFE_DEALLOC; + self.keyPath = nil; + self.block = nil; } #pragma mark Public - (void)stopObservation { [_subject removeObserver:self forKeyPath:_keyPath context:MobilyKVOContext]; - [self setSubject:nil]; + self.subject = nil; } #pragma mark Private -- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context { +- (void)observeValueForKeyPath:(NSString* __unused)keyPath ofObject:(id __unused)object change:(NSDictionary*)change context:(void*)context { if(context == MobilyKVOContext) { if(_block != nil) { - id oldValue = [change objectForKey:NSKeyValueChangeOldKey]; + id oldValue = change[NSKeyValueChangeOldKey]; if(oldValue == [NSNull null]) { oldValue = nil; } - id newValue = [change objectForKey:NSKeyValueChangeNewKey]; + id newValue = change[NSKeyValueChangeNewKey]; if(newValue == [NSNull null]) { newValue = nil; } @@ -108,11 +113,11 @@ - (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NS @implementation NSObject (MobilyKVO) -- (MobilyKVO*)observeKeyPath:(NSString*)keyPath withBlock:(MobilyKVOBlock)block { +- (MobilyKVO*)moObserveKeyPath:(NSString*)keyPath withBlock:(MobilyKVOBlock)block { return [[MobilyKVO alloc] initWithSubject:self keyPath:keyPath block:block]; } -- (MobilyKVO*)observeSelector:(SEL)selector withBlock:(MobilyKVOBlock)block { +- (MobilyKVO*)moObserveSelector:(SEL)selector withBlock:(MobilyKVOBlock)block { return [[MobilyKVO alloc] initWithSubject:self keyPath:NSStringFromSelector(selector) block:block]; } diff --git a/Sources/MobilyCore/MobilyLayoutView.h b/Sources/MobilyCore/MobilyLayoutView.h new file mode 100644 index 0000000..d3f8bb1 --- /dev/null +++ b/Sources/MobilyCore/MobilyLayoutView.h @@ -0,0 +1,58 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, MobilyLayoutViewAlignment) { + MobilyLayoutViewAlignmentFill, + MobilyLayoutViewAlignmentCenter, + MobilyLayoutViewAlignmentLeading, + MobilyLayoutViewAlignmentTrailing, +}; + +/*--------------------------------------------------*/ + +@interface MobilyLayoutView : MobilyView + +@property(nonatomic, readwrite, assign) IBInspectable UILayoutConstraintAxis axis; +@property(nonatomic, readwrite, assign) IBInspectable MobilyLayoutViewAlignment alignment; +@property(nonatomic, readwrite, assign) IBInspectable UIEdgeInsets margins; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat spacing; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyLayoutView.m b/Sources/MobilyCore/MobilyLayoutView.m new file mode 100644 index 0000000..ef19c7b --- /dev/null +++ b/Sources/MobilyCore/MobilyLayoutView.m @@ -0,0 +1,237 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyLayoutView () { + NSMutableArray* _hiddenObservers; + NSMutableArray* _topConstraints; + NSMutableArray* _bottomConstraints; + NSMutableArray* _leftConstraints; + NSMutableArray* _rightConstraints; + NSMutableArray* _spacingConstraints; +} + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyLayoutView + +#pragma mark Init / Free + +- (void)setup { + [super setup]; + + _hiddenObservers = [NSMutableArray array]; + _topConstraints = [NSMutableArray array]; + _bottomConstraints = [NSMutableArray array]; + _leftConstraints = [NSMutableArray array]; + _rightConstraints = [NSMutableArray array]; + _spacingConstraints = [NSMutableArray array]; +} + +#pragma mark Property + +- (void)setAxis:(UILayoutConstraintAxis)axis { + if(_axis != axis) { + _axis = axis; + [self setNeedsUpdateConstraints]; + } +} + +- (void)setAlignment:(MobilyLayoutViewAlignment)alignment { + if(_alignment != alignment) { + _alignment = alignment; + [self setNeedsUpdateConstraints]; + } +} + +- (void)setMargins:(UIEdgeInsets)margins{ + if(UIEdgeInsetsEqualToEdgeInsets(_margins, margins) == NO) { + if(_margins.top != margins.top) { + [_topConstraints moEach:^(NSLayoutConstraint* constraint) { + constraint.constant = margins.top; + }]; + } + if(_margins.bottom != margins.bottom) { + [_bottomConstraints moEach:^(NSLayoutConstraint* constraint) { + constraint.constant = margins.bottom; + }]; + } + if(_margins.left != margins.left) { + [_leftConstraints moEach:^(NSLayoutConstraint* constraint) { + constraint.constant = margins.left; + }]; + } + if(_margins.right != margins.right) { + [_rightConstraints moEach:^(NSLayoutConstraint* constraint) { + constraint.constant = margins.right; + }]; + } + _margins = margins; + } +} + +- (void)setSpacing:(CGFloat)spacing { + if(_spacing != spacing) { + _spacing = spacing; + [_spacingConstraints moEach:^(NSLayoutConstraint* constraint) { + constraint.constant = _spacing; + }]; + } +} + +#pragma mark Public override + +- (void)didAddSubview:(UIView*)subview { + subview.translatesAutoresizingMaskIntoConstraints = NO; + [_hiddenObservers addObject:[[MobilyKVO alloc] initWithSubject:subview keyPath:@"hidden" block:^(MobilyKVO* kvo, id oldValue, id newValue) { + [self setNeedsUpdateConstraints]; + }]]; + [super didAddSubview:subview]; + [self setNeedsUpdateConstraints]; +} + +- (void)willRemoveSubview:(UIView*)subview { + [_hiddenObservers moEach:^(MobilyKVO* kvo) { + if(kvo.subject == subview) { + [kvo stopObservation]; + [_hiddenObservers removeObject:kvo]; + } + }]; + [super willRemoveSubview:subview]; + [self setNeedsUpdateConstraints]; +} + +- (void)updateConstraints { + if(_topConstraints.count > 0) { + [self removeConstraints:_topConstraints]; + [_topConstraints removeAllObjects]; + } + if(_bottomConstraints.count > 0) { + [self removeConstraints:_bottomConstraints]; + [_bottomConstraints removeAllObjects]; + } + if(_rightConstraints.count > 0) { + [self removeConstraints:_rightConstraints]; + [_rightConstraints removeAllObjects]; + } + if(_leftConstraints.count > 0) { + [self removeConstraints:_leftConstraints]; + [_leftConstraints removeAllObjects]; + } + + __block UIView* prevSubview = nil; + [self.subviews moEach:^(UIView* subview) { + switch(_axis) { + case UILayoutConstraintAxisHorizontal: + if(prevSubview == nil) { + [_leftConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeLeft relation:NSLayoutRelationEqual attribute:NSLayoutAttributeLeft constant:_margins.left]]; + } else { + [_spacingConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeLeft relation:NSLayoutRelationEqual view:prevSubview attribute:NSLayoutAttributeRight constant:_spacing]]; + } + switch(_alignment) { + case MobilyLayoutViewAlignmentFill: + [_topConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeTop relation:NSLayoutRelationEqual attribute:NSLayoutAttributeTop constant:_margins.top]]; + [_bottomConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeBottom relation:NSLayoutRelationEqual attribute:NSLayoutAttributeBottom constant:_margins.bottom]]; + break; + case MobilyLayoutViewAlignmentLeading: + [_topConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeTop relation:NSLayoutRelationEqual attribute:NSLayoutAttributeTop constant:_margins.top]]; + [_bottomConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeBottom relation:NSLayoutRelationGreaterThanOrEqual attribute:NSLayoutAttributeBottom constant:_margins.bottom]]; + break; + case MobilyLayoutViewAlignmentCenter: + [subview moAddConstraintAttribute:NSLayoutAttributeCenterY relation:NSLayoutRelationEqual attribute:NSLayoutAttributeCenterY constant:0.0f]; + [_topConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeTop relation:NSLayoutRelationGreaterThanOrEqual attribute:NSLayoutAttributeTop constant:_margins.top]]; + [_bottomConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeBottom relation:NSLayoutRelationGreaterThanOrEqual attribute:NSLayoutAttributeBottom constant:_margins.bottom]]; + break; + case MobilyLayoutViewAlignmentTrailing: + [_topConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeTop relation:NSLayoutRelationGreaterThanOrEqual attribute:NSLayoutAttributeTop constant:_margins.top]]; + [_bottomConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeBottom relation:NSLayoutRelationEqual attribute:NSLayoutAttributeBottom constant:_margins.bottom]]; + break; + } + break; + case UILayoutConstraintAxisVertical: + if(prevSubview == nil) { + [_topConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeTop relation:NSLayoutRelationEqual attribute:NSLayoutAttributeTop constant:_margins.top]]; + } else { + [_spacingConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeTop relation:NSLayoutRelationEqual view:prevSubview attribute:NSLayoutAttributeBottom constant:_spacing]]; + } + switch(_alignment) { + case MobilyLayoutViewAlignmentFill: + [_leftConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeLeft relation:NSLayoutRelationEqual attribute:NSLayoutAttributeLeft constant:_margins.left]]; + [_rightConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeRight relation:NSLayoutRelationEqual attribute:NSLayoutAttributeRight constant:_margins.right]]; + break; + case MobilyLayoutViewAlignmentLeading: + [_leftConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeLeft relation:NSLayoutRelationEqual attribute:NSLayoutAttributeLeft constant:_margins.left]]; + [_rightConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeRight relation:NSLayoutRelationGreaterThanOrEqual attribute:NSLayoutAttributeRight constant:_margins.right]]; + break; + case MobilyLayoutViewAlignmentCenter: + [subview moAddConstraintAttribute:NSLayoutAttributeCenterX relation:NSLayoutRelationEqual attribute:NSLayoutAttributeCenterX constant:0.0f]; + [_leftConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeLeft relation:NSLayoutRelationGreaterThanOrEqual attribute:NSLayoutAttributeLeft constant:_margins.left]]; + [_rightConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeRight relation:NSLayoutRelationGreaterThanOrEqual attribute:NSLayoutAttributeRight constant:_margins.right]]; + break; + case MobilyLayoutViewAlignmentTrailing: + [_leftConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeLeft relation:NSLayoutRelationGreaterThanOrEqual attribute:NSLayoutAttributeLeft constant:_margins.left]]; + [_rightConstraints addObject:[subview moAddConstraintAttribute:NSLayoutAttributeRight relation:NSLayoutRelationEqual attribute:NSLayoutAttributeRight constant:_margins.right]]; + break; + } + break; + } + if(subview.isHidden == NO) { + prevSubview = subview; + } + }]; + if(prevSubview != nil) { + switch(_axis) { + case UILayoutConstraintAxisHorizontal: + [_rightConstraints addObject:[prevSubview moAddConstraintAttribute:NSLayoutAttributeRight relation:NSLayoutRelationEqual attribute:NSLayoutAttributeRight constant:_margins.right]]; + break; + case UILayoutConstraintAxisVertical: + [_bottomConstraints addObject:[prevSubview moAddConstraintAttribute:NSLayoutAttributeBottom relation:NSLayoutRelationEqual attribute:NSLayoutAttributeBottom constant:_margins.bottom]]; + break; + } + } + [super updateConstraints]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/ViewFieldList/MobilyViewFieldList.h b/Sources/MobilyCore/MobilyListField.h similarity index 77% rename from Classes/UI/ViewFieldList/MobilyViewFieldList.h rename to Sources/MobilyCore/MobilyListField.h index 17251d7..249bec4 100644 --- a/Classes/UI/ViewFieldList/MobilyViewFieldList.h +++ b/Sources/MobilyCore/MobilyListField.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,35 +33,37 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyViewFieldText.h" +#import /*--------------------------------------------------*/ -@class MobilyViewFieldListItem; +@class MobilyListFieldItem; /*--------------------------------------------------*/ -@interface MobilyViewFieldList : MobilyViewFieldText< MobilyBuilderObject > +@interface MobilyListField : MobilyTextField< MobilyBuilderObject > @property(nonatomic, readwrite, strong) NSArray* items; -@property(nonatomic, readwrite, strong) MobilyViewFieldListItem* selectedItem; +@property(nonatomic, readwrite, strong) MobilyListFieldItem* selectedItem; -- (void)setSelectedItem:(MobilyViewFieldListItem*)selectedItem animated:(BOOL)animated; +- (void)setSelectedItem:(MobilyListFieldItem*)selectedItem animated:(BOOL)animated; @end /*--------------------------------------------------*/ -@interface MobilyViewFieldListItem : NSObject +@interface MobilyListFieldItem : NSObject< MobilyObject > @property(nonatomic, readwrite, strong) NSString* title; @property(nonatomic, readwrite, strong) UIFont* font; @property(nonatomic, readwrite, strong) UIColor* color; @property(nonatomic, readwrite, strong) id value; -- (id)initWithTitle:(NSString*)title value:(id)value; -- (id)initWithTitle:(NSString*)title color:(UIColor*)color value:(id)value; -- (id)initWithTitle:(NSString*)title font:(UIFont*)font color:(UIColor*)color value:(id)value; +- (instancetype)initWithTitle:(NSString*)title value:(id)value; +- (instancetype)initWithTitle:(NSString*)title color:(UIColor*)color value:(id)value; +- (instancetype)initWithTitle:(NSString*)title font:(UIFont*)font color:(UIColor*)color value:(id)value; + +- (void)setup NS_REQUIRES_SUPER; @end diff --git a/Classes/UI/ViewFieldList/MobilyViewFieldList.m b/Sources/MobilyCore/MobilyListField.m similarity index 56% rename from Classes/UI/ViewFieldList/MobilyViewFieldList.m rename to Sources/MobilyCore/MobilyListField.m index b2870a5..7b888b4 100644 --- a/Classes/UI/ViewFieldList/MobilyViewFieldList.m +++ b/Sources/MobilyCore/MobilyListField.m @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -32,12 +32,14 @@ /* OTHER DEALINGS IN THE SOFTWARE. */ /* */ /*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ -#import "MobilyViewFieldList.h" +#import /*--------------------------------------------------*/ -@interface MobilyViewFieldList () < UIPickerViewDataSource, UIPickerViewDelegate > +@interface MobilyListField () < UIPickerViewDataSource, UIPickerViewDelegate > @property(nonatomic, readwrite, strong) UIPickerView* pickerView; @@ -45,45 +47,43 @@ @interface MobilyViewFieldList () < UIPickerViewDataSource, UIPickerViewDelegate /*--------------------------------------------------*/ -@implementation MobilyViewFieldList +@implementation MobilyListField #pragma mark NSKeyValueCoding -#pragma mark Standart - -- (void)dealloc { - [self setPickerView:nil]; - - [self setItems:nil]; - [self setSelectedItem:nil]; - - MOBILY_SAFE_DEALLOC; -} +#pragma mark Init / Free #pragma mark Public - (void)didBeginEditing { [super didBeginEditing]; - if(_pickerView == nil) { - [self setPickerView:[[UIPickerView alloc] init]]; - if(_pickerView != nil) { - [_pickerView setDelegate:self]; + if(_items.count > 0) { + if(_pickerView == nil) { + self.pickerView = [UIPickerView new]; + if(_pickerView != nil) { + _pickerView.delegate = self; + } + self.inputView = _pickerView; } - [self setInputView:_pickerView]; - } - if(_pickerView != nil) { - [_pickerView reloadAllComponents]; - if(_selectedItem != nil) { - [_pickerView selectRow:[_items indexOfObject:_selectedItem] inComponent:0 animated:NO]; + if(_pickerView != nil) { + [_pickerView reloadAllComponents]; + if(_selectedItem != nil) { + [_pickerView selectRow:[_items indexOfObject:_selectedItem] inComponent:0 animated:NO]; + } } + } else { + [self endEditing:YES]; } } - (void)didEndEditing { [super didEndEditing]; - [self setSelectedItem:[_items objectAtIndex:[_pickerView selectedRowInComponent:0]] animated:YES emitted:YES]; + NSUInteger selectedItem = [_pickerView selectedRowInComponent:0]; + if(selectedItem < _items.count) { + [self setSelectedItem:_items[selectedItem] animated:YES emitted:YES]; + } } #pragma mark Property @@ -95,36 +95,36 @@ - (void)setItems:(NSArray*)items { if([self isEditing] == YES) { [_pickerView reloadAllComponents]; } - if((_selectedItem == nil) && ([_items count] > 0)) { - _selectedItem = [_items objectAtIndex:0]; - [self setText:[_selectedItem title]]; + if((_selectedItem == nil) && (_items.count > 0)) { + _selectedItem = _items[0]; + self.text = [_selectedItem title]; if([self isEditing] == YES) { [_pickerView selectRow:[_items indexOfObject:_selectedItem] inComponent:0 animated:NO]; } } else { - [self setText:@""]; + self.text = @""; } } } -- (void)setSelectedItem:(MobilyViewFieldListItem*)selectedItem { +- (void)setSelectedItem:(MobilyListFieldItem*)selectedItem { [self setSelectedItem:selectedItem animated:NO emitted:NO]; } -- (void)setSelectedItem:(MobilyViewFieldListItem*)selectedItem animated:(BOOL)animated { +- (void)setSelectedItem:(MobilyListFieldItem*)selectedItem animated:(BOOL)animated { [self setSelectedItem:selectedItem animated:animated emitted:NO]; } #pragma mark Private -- (void)setSelectedItem:(MobilyViewFieldListItem*)selectedItem animated:(BOOL)animated emitted:(BOOL)emitted { +- (void)setSelectedItem:(MobilyListFieldItem*)selectedItem animated:(BOOL)animated emitted:(BOOL)emitted { if(_selectedItem != selectedItem) { _selectedItem = selectedItem; if(_selectedItem != nil) { - [self setText:[_selectedItem title]]; + self.text = [_selectedItem title]; } else { - [self setText:@""]; + self.text = @""; } if([self isEditing] == YES) { [_pickerView selectRow:[_items indexOfObject:_selectedItem] inComponent:0 animated:animated]; @@ -137,30 +137,30 @@ - (void)setSelectedItem:(MobilyViewFieldListItem*)selectedItem animated:(BOOL)an #pragma mark UIPickerViewDataSource -- (NSInteger)numberOfComponentsInPickerView:(UIPickerView*)pickerView { +- (NSInteger)numberOfComponentsInPickerView:(UIPickerView* __unused)pickerView { return 1; } -- (NSInteger)pickerView:(UIPickerView*)pickerView numberOfRowsInComponent:(NSInteger)component { - return [_items count]; +- (NSInteger)pickerView:(UIPickerView* __unused)pickerView numberOfRowsInComponent:(NSInteger __unused)component { + return _items.count; } #pragma mark UIPickerViewDelegate -- (NSString*)pickerView:(UIPickerView*)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { - return [[_items objectAtIndex:row] title]; +- (NSString*)pickerView:(UIPickerView* __unused)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger __unused)component { + return [_items[row] title]; } -- (NSAttributedString*)pickerView:(UIPickerView*)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger)component { - MobilyViewFieldListItem* listItem = [_items objectAtIndex:row]; +- (NSAttributedString*)pickerView:(UIPickerView* __unused)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger __unused)component { + MobilyListFieldItem* listItem = _items[row]; return [[NSAttributedString alloc] initWithString:[listItem title] attributes:@{ NSFontAttributeName : [listItem font], NSForegroundColorAttributeName: [listItem color] }]; } -- (void)pickerView:(UIPickerView*)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { - [self setSelectedItem:[_items objectAtIndex:row] animated:YES emitted:YES]; +- (void)pickerView:(UIPickerView* __unused)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger __unused)component { + [self setSelectedItem:_items[row] animated:YES emitted:YES]; } @end @@ -169,50 +169,47 @@ - (void)pickerView:(UIPickerView*)pickerView didSelectRow:(NSInteger)row inCompo #pragma mark - /*--------------------------------------------------*/ -@implementation MobilyViewFieldListItem +@implementation MobilyListFieldItem -#pragma mark Standart +#pragma mark Init / Free -- (id)initWithTitle:(NSString*)title value:(id)value { +- (instancetype)initWithTitle:(NSString*)title value:(id)value { self = [super init]; if(self != nil) { - [self setTitle:title]; - [self setFont:[UIFont systemFontOfSize:[UIFont systemFontSize]]]; - [self setColor:[UIColor blackColor]]; - [self setValue:value]; + self.title = title; + self.font = [UIFont systemFontOfSize:UIFont.systemFontSize]; + self.color = UIColor.blackColor; + self.value = value; + [self setup]; } return self; } -- (id)initWithTitle:(NSString*)title color:(UIColor*)color value:(id)value { +- (instancetype)initWithTitle:(NSString*)title color:(UIColor*)color value:(id)value { self = [super init]; if(self != nil) { - [self setTitle:title]; - [self setFont:[UIFont systemFontOfSize:[UIFont systemFontSize]]]; - [self setColor:color]; - [self setValue:value]; + self.title = title; + self.font = [UIFont systemFontOfSize:UIFont.systemFontSize]; + self.color = color; + self.value = value; + [self setup]; } return self; } -- (id)initWithTitle:(NSString*)title font:(UIFont*)font color:(UIColor*)color value:(id)value { +- (instancetype)initWithTitle:(NSString*)title font:(UIFont*)font color:(UIColor*)color value:(id)value { self = [super init]; if(self != nil) { - [self setTitle:title]; - [self setFont:font]; - [self setColor:color]; - [self setValue:value]; + self.title = title; + self.font = font; + self.color = color; + self.value = value; + [self setup]; } return self; } -- (void)dealloc { - [self setTitle:nil]; - [self setFont:nil]; - [self setColor:nil]; - [self setValue:nil]; - - MOBILY_SAFE_DEALLOC; +- (void)setup { } @end diff --git a/Sources/MobilyCore/MobilyLoadedView.h b/Sources/MobilyCore/MobilyLoadedView.h new file mode 100644 index 0000000..75810cd --- /dev/null +++ b/Sources/MobilyCore/MobilyLoadedView.h @@ -0,0 +1,50 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyLoadedView : UIView< MobilyBuilderObject > + +@property(nonatomic, readwrite, strong) IBOutlet UIView* rootView; +@property(nonatomic, readwrite, assign) UIOffset rootOffsetOfCenter; +@property(nonatomic, readwrite, assign) UIOffset rootMarginSize; + +- (void)setup NS_REQUIRES_SUPER; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyLoadedView.m b/Sources/MobilyCore/MobilyLoadedView.m new file mode 100644 index 0000000..949d25e --- /dev/null +++ b/Sources/MobilyCore/MobilyLoadedView.m @@ -0,0 +1,223 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyLoadedView () { +@protected + UIView* _rootView; + UIOffset _rootOffsetOfCenter; + UIOffset _rootMarginSize; + NSLayoutConstraint* _constraintRootViewCenterX; + NSLayoutConstraint* _constraintRootViewCenterY; + NSLayoutConstraint* _constraintRootViewWidth; + NSLayoutConstraint* _constraintRootViewHeight; +} + +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewCenterX; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewCenterY; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewWidth; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewHeight; + + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyLoadedView + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; +@synthesize rootView = _rootView; +@synthesize rootOffsetOfCenter = _rootOffsetOfCenter; +@synthesize rootMarginSize = _rootMarginSize; +@synthesize constraintRootViewCenterX = _constraintRootViewCenterX; +@synthesize constraintRootViewCenterY = _constraintRootViewCenterY; +@synthesize constraintRootViewWidth = _constraintRootViewWidth; +@synthesize constraintRootViewHeight = _constraintRootViewHeight; + +#pragma mark NSKeyValueCoding + +#pragma mark Init / Free + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + UINib* nib = [UINib moNibWithClass:self.class bundle:nil]; + if(nib != nil) { + [nib instantiateWithOwner:self options:nil]; + } + self.clipsToBounds = YES; +} + +#pragma mark UIView + +- (void)updateConstraints { + if(_rootView != nil) { + if(_constraintRootViewCenterX == nil) { + self.constraintRootViewCenterX = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:_rootOffsetOfCenter.horizontal]; + } + if(_constraintRootViewCenterY == nil) { + self.constraintRootViewCenterY = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:_rootOffsetOfCenter.vertical]; + } + if(_constraintRootViewWidth == nil) { + self.constraintRootViewWidth = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0f constant:_rootMarginSize.horizontal]; + } + if(_constraintRootViewHeight == nil) { + self.constraintRootViewHeight = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0f constant:_rootMarginSize.vertical]; + } + } else { + self.constraintRootViewCenterX = nil; + self.constraintRootViewCenterY = nil; + self.constraintRootViewWidth = nil; + self.constraintRootViewHeight = nil; + } + [super updateConstraints]; +} + +#pragma mark Property + +- (void)setRootView:(UIView*)rootView { + if(_rootView != rootView) { + if(_rootView != nil) { + [_rootView removeFromSuperview]; + } + _rootView = rootView; + if(_rootView != nil) { + _rootView.translatesAutoresizingMaskIntoConstraints = NO; + [self addSubview:_rootView]; + } + [self setNeedsUpdateConstraints]; + } +} + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRootViewCenterX, constraintRootViewCenterX, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRootViewCenterY, constraintRootViewCenterY, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRootViewWidth, constraintRootViewWidth, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRootViewHeight, constraintRootViewHeight, self, { +}, { +}) + +- (void)setRootOffsetOfCenter:(UIOffset)rootOffsetOfCenter { + if(UIOffsetEqualToOffset(_rootOffsetOfCenter, rootOffsetOfCenter) == NO) { + _rootOffsetOfCenter = rootOffsetOfCenter; + if(_constraintRootViewCenterX != nil) { + _constraintRootViewCenterX.constant = _rootOffsetOfCenter.horizontal; + } + if(_constraintRootViewCenterY != nil) { + _constraintRootViewCenterY.constant = _rootOffsetOfCenter.vertical; + } + } +} + +- (void)setRootMarginSize:(UIOffset)rootMarginSize { + if(UIOffsetEqualToOffset(_rootMarginSize, rootMarginSize) == NO) { + _rootMarginSize = rootMarginSize; + if(_constraintRootViewWidth != nil) { + _constraintRootViewWidth.constant = _rootMarginSize.horizontal; + } + if(_constraintRootViewHeight != nil) { + _constraintRootViewHeight.constant = _rootMarginSize.vertical; + } + } +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return self.subviews; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + [self addSubview:(UIView*)objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + [self moRemoveSubview:(UIView*)objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/NS/Core/MobilyEvent.h b/Sources/MobilyCore/MobilyLockScreenController.h similarity index 52% rename from Classes/NS/Core/MobilyEvent.h rename to Sources/MobilyCore/MobilyLockScreenController.h index d3aa5a0..78eac28 100644 --- a/Classes/NS/Core/MobilyEvent.h +++ b/Sources/MobilyCore/MobilyLockScreenController.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,65 +33,52 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyNS.h" +#import /*--------------------------------------------------*/ -typedef id (^MobilyEventBlockType)(id sender, id object); +typedef NS_ENUM(NSInteger, MobilyLockScreenMode) { + MobilyLockScreenModeUnlock = 0, + MobilyLockScreenModeAuth, + MobilyLockScreenModeNew, + MobilyLockScreenModeChange, + MobilyLockScreenModeVerification, +}; /*--------------------------------------------------*/ -@protocol MobilyEvent < NSObject, NSCoding > - -- (id)fireSender:(id)sender object:(id)object; - -@end +typedef void (^MobilyLockScreenControllerChangeBlock)(NSString* pincode); +typedef void (^MobilyLockScreenControllerBlock)(); /*--------------------------------------------------*/ -@interface MobilyEventSelector : NSObject< MobilyEvent > - -@property(nonatomic, readonly, weak) id target; -@property(nonatomic, readonly, assign) SEL action; - -+ (id)callbackWithTarget:(id)target action:(SEL)action; -+ (id)callbackWithTarget:(id)target action:(SEL)action inMainThread:(BOOL)inMainThread; -+ (id)callbackWithTarget:(id)target action:(SEL)action inCurrentThread:(BOOL)inCurrentThread; -- (id)initWithTarget:(id)target action:(SEL)action thread:(NSThread*)thread; - -@end +@class MobilyLockScreenPincodeView; /*--------------------------------------------------*/ -@interface MobilyEventBlock : NSObject< MobilyEvent > +@interface MobilyLockScreenController : MobilyViewController -@property(nonatomic, readonly, copy) MobilyEventBlockType block; +@property(nonatomic, readwrite, assign) MobilyLockScreenMode lockScreenMode; +@property(nonatomic, readwrite, strong) NSString* pincode; +@property(nonatomic, readwrite, assign) BOOL allowTouchID; -+ (id)callbackWithBlock:(MobilyEventBlockType)block; -+ (id)callbackWithBlock:(MobilyEventBlockType)block inMainQueue:(BOOL)inMainQueue; -+ (id)callbackWithBlock:(MobilyEventBlockType)block inCurrentQueue:(BOOL)inCurrentQueue; -- (id)initWithBlock:(MobilyEventBlockType)block queue:(dispatch_queue_t)queue; +@property(nonatomic, readwrite, strong) IBInspectable NSString* titleText; +@property(nonatomic, readwrite, strong) IBInspectable NSString* subtitleText; +@property(nonatomic, readwrite, strong) IBInspectable NSString* confirmTitleText; +@property(nonatomic, readwrite, strong) IBInspectable NSString* confirmSubtitleText; +@property(nonatomic, readwrite, strong) IBInspectable NSString* invalidTitleText; +@property(nonatomic, readwrite, strong) IBInspectable NSString* invalidSubtitleText; -@end +@property(nonatomic, readonly, weak) IBOutlet UILabel* titleLabel; +@property(nonatomic, readonly, weak) IBOutlet UILabel* subtitleLabel; +@property(nonatomic, readonly, weak) IBOutlet UIButton* cancelButton; +@property(nonatomic, readonly, weak) IBOutlet MobilyLockScreenPincodeView* pincodeView; -/*--------------------------------------------------*/ +@property(nonatomic, readwrite, copy) MobilyLockScreenControllerBlock didSuccessfulBlock; +@property(nonatomic, readwrite, copy) MobilyLockScreenControllerChangeBlock didChangeBlock; +@property(nonatomic, readwrite, copy) MobilyLockScreenControllerBlock didCancelledBlock; +@property(nonatomic, readwrite, copy) MobilyLockScreenControllerBlock didFailureBlock; -#define MOBILY_DEFINE_VALIDATE_EVENT(name) \ -- (BOOL)validate##name:(inout id*)value error:(out NSError**)error { \ - if([*value isKindOfClass:[NSString class]] == YES) { \ - SEL action = NSSelectorFromString(*value); \ - if(action != nil) { \ - id target = [self objectForSelector:action]; \ - if(target != nil) { \ - *value = [MobilyEventSelector callbackWithTarget:target action:action]; \ - } else { \ - NSLog(@"Failure bind event %@=\"%@\"", @#name, *value); \ - } \ - } else { \ - NSLog(@"Unknown selector %@=\"%@\"", @#name, *value); \ - } \ - } \ - return [*value conformsToProtocol:@protocol(MobilyEvent)]; \ -} +@end /*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyLockScreenController.m b/Sources/MobilyCore/MobilyLockScreenController.m new file mode 100644 index 0000000..540779c --- /dev/null +++ b/Sources/MobilyCore/MobilyLockScreenController.m @@ -0,0 +1,299 @@ +/*--------------------------------------------------*/ + +#import +#import +#import + +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyLockScreenController () < MobilyLockScreenPincodeViewDelegate > { + MobilyLockScreenMode _prevLockScreenMode; + NSString* _confirmPincode; +} + +@property(nonatomic, readwrite, weak) IBOutlet UILabel* titleLabel; +@property(nonatomic, readwrite, weak) IBOutlet UILabel* subtitleLabel; +@property(nonatomic, readwrite, weak) IBOutlet MobilyButton* cancelButton; +@property(nonatomic, readwrite, weak) IBOutlet MobilyLockScreenPincodeView* pincodeView; + +- (BOOL)_isPincodeValid:(NSString*)pincode; +- (void)_policyDeviceOwnerAuthentication; +- (void)_unlockDelayDismissViewController:(NSTimeInterval)delay; +- (void)_unlockScreenSuccessful:(NSString*)pincode; +- (void)_unlockScreenFailure; + +- (CAAnimation*)_makeShakeAnimation; + +- (void)_swipeSubtitleAndPincodeView; +- (NSLayoutConstraint*)_findLayoutConstraint:(UIView*)superview childView:(UIView*)childView attribute:(NSLayoutAttribute)attribute; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +static const NSTimeInterval MobilyLockScreenController_SwipeAnimationDuration = 0.3f; +static const NSTimeInterval MobilyLockScreenController_DismissWaitingDuration = 0.4f; +static const NSTimeInterval MobilyLockScreenController_ShakeAnimationDuration = 0.5f; + +/*--------------------------------------------------*/ + +@implementation MobilyLockScreenController + +- (void)setup { + [super setup]; + + _allowTouchID = YES; + _titleText = NSLocalizedStringFromTable(@"Pincode", @"MobilyLockScreenController", nil); + _subtitleText = NSLocalizedStringFromTable(@"Please enter your pincode", @"MobilyLockScreenController", nil); + _confirmTitleText = NSLocalizedStringFromTable(@"Confirm pincode", @"MobilyLockScreenController", nil); + _confirmSubtitleText = NSLocalizedStringFromTable(@"Please enter previous pincode", @"MobilyLockScreenController", nil); + _invalidTitleText = NSLocalizedStringFromTable(@"Failure", @"MobilyLockScreenController", nil); + _invalidSubtitleText = NSLocalizedStringFromTable(@"Invalid pincode", @"MobilyLockScreenController", nil); +} + +#pragma mark Load / Unload + +- (void)viewDidLoad { + [super viewDidLoad]; + + switch(_lockScreenMode) { + case MobilyLockScreenModeUnlock: + case MobilyLockScreenModeVerification: + _cancelButton.hidden = YES; + break; + case MobilyLockScreenModeAuth: + case MobilyLockScreenModeNew: + case MobilyLockScreenModeChange: + _cancelButton.hidden = NO; + break; + } + _titleLabel.text = _titleText; + _subtitleLabel.text = _subtitleText; +} + +#pragma mark Appear / Disappear + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + if(((_lockScreenMode == MobilyLockScreenModeUnlock) || (_lockScreenMode == MobilyLockScreenModeAuth)) && (_allowTouchID == YES)) { + [self _policyDeviceOwnerAuthentication]; + } +} + +#pragma mark Property + +- (void)setPincodeView:(MobilyLockScreenPincodeView*)pincodeView { + if(_pincodeView != pincodeView) { + if(_pincodeView != nil) { + _pincodeView.delegate = nil; + } + _pincodeView = pincodeView; + if(_pincodeView != nil) { + _pincodeView.delegate = self; + } + } +} + +#pragma mark Private + +- (BOOL)_isPincodeValid:(NSString*)pincode { + if(_lockScreenMode == MobilyLockScreenModeVerification) { + return [_confirmPincode isEqualToString:pincode]; + } + return [_pincode isEqualToString:pincode]; +} + +- (void)_policyDeviceOwnerAuthentication { + if(UIDevice.moSystemVersion >= 8.0f) { + NSError* error = nil; + LAContext* context = [[LAContext alloc] init]; + if([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error] == YES) { + [context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics + localizedReason:NSLocalizedStringFromTable(@"Pincode TouchID", @"MobilyLockScreenController", nil) + reply:^(BOOL success, NSError* authenticationError) { + if(success == YES) { + [self _unlockDelayDismissViewController:MobilyLockScreenController_DismissWaitingDuration]; + } else { + NSLog(@"MobilyLockScreenController::LAContext::Authentication Error : %@", authenticationError); + } + }]; + } else { + NSLog(@"MobilyLockScreenController::LAContext::Policy Error : %@", [error localizedDescription]); + } + } +} + +- (void)_unlockDelayDismissViewController:(NSTimeInterval)delay { + [_pincodeView wasCompleted]; + [MobilyTimeout executeBlock:^{ + if(self.presentingViewController != nil) { + [self dismissViewControllerAnimated:NO completion:_didSuccessfulBlock]; + } else { + if(_didSuccessfulBlock != nil) { + _didSuccessfulBlock(); + } + } + } afterDelay:delay]; +} + +- (void)_unlockScreenSuccessful:(NSString*)pincode { + MobilySimpleBlock completion = ^{ + switch(_lockScreenMode) { + case MobilyLockScreenModeUnlock: + case MobilyLockScreenModeAuth: + if(_didSuccessfulBlock != nil) { + _didSuccessfulBlock(); + } + break; + case MobilyLockScreenModeNew: + case MobilyLockScreenModeChange: { + if(_didChangeBlock != nil) { + _didChangeBlock(pincode); + } + break; + default: + break; + } + } + }; + if(self.presentingViewController != nil) { + [self dismissViewControllerAnimated:NO completion:completion]; + } else { + completion(); + } +} + +- (void)_unlockScreenFailure { + if(_lockScreenMode != MobilyLockScreenModeVerification) { + if(_didFailureBlock != nil) { + _didFailureBlock(); + } + } + + AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); + + _titleLabel.text = _invalidTitleText; + _subtitleLabel.text = _invalidSubtitleText; + [_pincodeView.layer addAnimation:[self _makeShakeAnimation] forKey:@"shake"]; + [_pincodeView setEnabled:NO]; + + [MobilyTimeout executeBlock:^{ + [_pincodeView setEnabled:YES]; + [_pincodeView initPincode]; + switch(_lockScreenMode) { + case MobilyLockScreenModeVerification: + _titleLabel.text = _confirmTitleText; + _subtitleLabel.text = _confirmSubtitleText; + break; + default: + _titleLabel.text = _titleText; + _subtitleLabel.text = _subtitleText; + break; + } + } afterDelay:MobilyLockScreenController_ShakeAnimationDuration]; +} + +- (CAAnimation*)_makeShakeAnimation { + CAKeyframeAnimation* shake = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.x"]; + shake.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; + shake.duration = MobilyLockScreenController_ShakeAnimationDuration; + shake.values = @[ @(-20), @(20), @(-20), @(20), @(-10), @(10), @(-5), @(5), @(0) ]; + return shake; +} + +- (void)_swipeSubtitleAndPincodeView { + __weak UIView* weakView = self.view; + __weak MobilyLockScreenPincodeView* weakCode = _pincodeView; + [_pincodeView setEnabled:NO]; + + NSLayoutConstraint* centerX = [self _findLayoutConstraint:weakView childView:_subtitleLabel attribute:NSLayoutAttributeCenterX]; + centerX.constant = CGRectGetWidth(self.view.bounds); + [UIView animateWithDuration:MobilyLockScreenController_SwipeAnimationDuration animations:^{ + [weakView layoutIfNeeded]; + } completion:^(BOOL finished) { + [weakCode initPincode]; + centerX.constant = -CGRectGetWidth(weakView.bounds); + [weakView layoutIfNeeded]; + centerX.constant = 0; + [UIView animateWithDuration:MobilyLockScreenController_SwipeAnimationDuration animations:^{ + [weakView layoutIfNeeded]; + } completion:^(BOOL finished) { + [weakCode setEnabled:YES]; + }]; + }]; +} + +- (NSLayoutConstraint*)_findLayoutConstraint:(UIView*)superview childView:(UIView*)childView attribute:(NSLayoutAttribute)attribute { + for(NSLayoutConstraint* constraint in superview.constraints) { + if((constraint.firstItem == superview) && (constraint.secondItem == childView) && (constraint.firstAttribute == attribute)) { + return constraint; + } + } + return nil; +} + +#pragma mark Action + +- (IBAction)pressedNumber:(UIButton*)sender { + [_pincodeView appendingPincode:[NSString stringWithFormat:@"%d", (int)sender.tag]]; +} + +- (IBAction)pressedCancel:(id)sender { + if(_didCancelledBlock != nil) { + _didCancelledBlock(); + } + [self dismissViewControllerAnimated:YES completion:nil]; +} + +- (IBAction)pressedDelete:(id)sender { + [_pincodeView removeLastPincode]; +} + +#pragma mark MobilyLockScreenPincodeViewDelegate + +- (void)lockScreenPincodeView:(MobilyLockScreenPincodeView*)lockScreenPincodeView pincode:(NSString*)pincode { + switch(_lockScreenMode) { + case MobilyLockScreenModeUnlock: + case MobilyLockScreenModeAuth: + if([self _isPincodeValid:pincode] == YES) { + [self _unlockScreenSuccessful:pincode]; + } else { + [self _unlockScreenFailure]; + } + break; + case MobilyLockScreenModeVerification: + if([self _isPincodeValid:pincode] == YES) { + self.lockScreenMode = _prevLockScreenMode; + [self _unlockScreenSuccessful:pincode]; + } else { + self.lockScreenMode = _prevLockScreenMode; + [self _unlockScreenFailure]; + } + break; + case MobilyLockScreenModeNew: + case MobilyLockScreenModeChange: + _prevLockScreenMode = _lockScreenMode; + _confirmPincode = pincode; + _titleLabel.text = _confirmTitleText; + _subtitleLabel.text = _confirmSubtitleText; + self.lockScreenMode = MobilyLockScreenModeVerification; + [self _swipeSubtitleAndPincodeView]; + break; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/ControllerSlideMenu/MobilyControllerSlideMenu.h b/Sources/MobilyCore/MobilyLockScreenPincodeView.h similarity index 68% rename from Classes/UI/ControllerSlideMenu/MobilyControllerSlideMenu.h rename to Sources/MobilyCore/MobilyLockScreenPincodeView.h index c873080..522c926 100644 --- a/Classes/UI/ControllerSlideMenu/MobilyControllerSlideMenu.h +++ b/Sources/MobilyCore/MobilyLockScreenPincodeView.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,28 +33,34 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyController.h" +#import /*--------------------------------------------------*/ -#import "SlideNavigationController.h" +@protocol MobilyLockScreenPincodeViewDelegate; /*--------------------------------------------------*/ -@interface MobilyControllerSlideMenu : SlideNavigationController< MobilyBuilderObject > +@interface MobilyLockScreenPincodeView : MobilyView -@property(nonatomic, readonly, assign, getter=isAppeared) BOOL appeared; -@property(nonatomic, readwrite, strong) MobilyTransitionController* transitionModal; -@property(nonatomic, readwrite, strong) MobilyTransitionController* transitionNavigation; +@property(nonatomic, readwrite, weak) IBOutlet id< MobilyLockScreenPincodeViewDelegate > delegate; +@property(nonatomic, readwrite, strong) IBInspectable UIColor* pincodeColor; +@property(nonatomic, readwrite, assign) IBInspectable NSUInteger pincodeLength; +@property(nonatomic, readwrite, assign) IBInspectable BOOL enabled; -@property(nonatomic, readwrite, strong) id< MobilyEvent > eventDidLoad; -@property(nonatomic, readwrite, strong) id< MobilyEvent > eventDidUnload; -@property(nonatomic, readwrite, strong) id< MobilyEvent > eventWillAppear; -@property(nonatomic, readwrite, strong) id< MobilyEvent > eventDidAppear; -@property(nonatomic, readwrite, strong) id< MobilyEvent > eventWillDisappear; -@property(nonatomic, readwrite, strong) id< MobilyEvent > eventDidDisappear; +- (void)initPincode; +- (void)appendingPincode:(NSString*)pincode; +- (void)removeLastPincode; +- (void)wasCompleted; -- (void)setupController; +@end + +/*--------------------------------------------------*/ + +@protocol MobilyLockScreenPincodeViewDelegate < NSObject > + +@required +- (void)lockScreenPincodeView:(MobilyLockScreenPincodeView*)lockScreenPincodeView pincode:(NSString*)pincode; @end diff --git a/Sources/MobilyCore/MobilyLockScreenPincodeView.m b/Sources/MobilyCore/MobilyLockScreenPincodeView.m new file mode 100644 index 0000000..07a3c43 --- /dev/null +++ b/Sources/MobilyCore/MobilyLockScreenPincodeView.m @@ -0,0 +1,109 @@ +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyLockScreenPincodeView() { + NSUInteger _wasCompleted; +} + +@property(nonatomic, readwrite, strong) NSString* pincode; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyLockScreenPincodeView + +#pragma mark Init / Free + +- (void)setup { + [super setup]; + + _enabled = YES; + _pincodeLength = 4; + _pincode = @""; +} + +#pragma mark Property + +- (void)setPincode:(NSString*)pincode { + if([_pincode isEqualToString:pincode] == NO) { + _pincode = pincode; + if(_pincode.length == _pincodeLength) { + if([_delegate respondsToSelector:@selector(lockScreenPincodeView:pincode:)] == YES) { + [_delegate lockScreenPincodeView:self pincode:pincode]; + } + } + [self setNeedsDisplay]; + } +} + +#pragma mark Public + +- (void)initPincode { + _pincode = @""; + [self setNeedsDisplay]; +} + +- (void)appendingPincode:(NSString*)pincode { + if(_enabled == YES) { + if(_pincode.length < _pincodeLength) { + self.pincode = [_pincode stringByAppendingString:pincode]; + } + } +} + +- (void)removeLastPincode { + if(_enabled == YES) { + if(_pincode.length > 0) { + self.pincode = [_pincode substringToIndex:_pincode.length - 1]; + } + } +} + +- (void)wasCompleted { + for(NSUInteger index = 0; index < _pincodeLength; index++) { + [MobilyTimeout executeBlock:^{ + _wasCompleted++; + [self setNeedsDisplay]; + } afterDelay:index * 0.01f]; + } +} + +#pragma mark Public override + +- (void)drawRect:(CGRect)rect { + [super drawRect:rect]; + + [_pincodeColor setFill]; + + CGSize boxSize = CGSizeMake(CGRectGetWidth(rect) / _pincodeLength, CGRectGetHeight(rect)); + CGSize charSize = CGSizeMake(16, 4); + CGFloat y = rect.origin.y; + NSUInteger completed = MAX(_pincode.length, _wasCompleted); + NSInteger str = MIN(completed, _pincodeLength); + for(NSUInteger index = 0; index < str; index++) { + CGFloat x = boxSize.width * index; + CGRect rounded = CGRectMake(x + floorf((boxSize.width - charSize.width) * 0.5f), y + floorf((boxSize.height - charSize.width) * 0.5f), charSize.width, charSize.width); + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSetFillColorWithColor(context, _pincodeColor.CGColor); + CGContextSetLineWidth(context, 2.0); + CGContextFillEllipseInRect(context, rounded); + CGContextFillPath(context); + } + for(NSUInteger index = str; index < _pincodeLength; index++) { + CGFloat x = boxSize.width * index; + CGRect rounded = CGRectMake(x + floorf((boxSize.width - charSize.width) * 0.5f), y + floorf((boxSize.height - charSize.height) * 0.5f), charSize.width, charSize.height); + UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:rounded cornerRadius:5]; + [path fill]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyMap.h b/Sources/MobilyCore/MobilyMap.h new file mode 100644 index 0000000..f0f1508 --- /dev/null +++ b/Sources/MobilyCore/MobilyMap.h @@ -0,0 +1,281 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyMap : NSObject< MobilyObject, NSCopying, NSCoding, NSFastEnumeration > + ++ (instancetype)map; ++ (instancetype)mapWithMap:(MobilyMap*)map; ++ (instancetype)mapWithContentsOfFile:(NSString*)path; ++ (instancetype)mapWithContentsOfURL:(NSURL*)URL; ++ (instancetype)mapWithObject:(id)anObject pairedWithKey:(id< NSCopying >)aKey; ++ (instancetype)mapWithDictionary:(NSDictionary*)entries; + +- (instancetype)init; +- (instancetype)initWithMap:(MobilyMap*)map; +- (instancetype)initWithMap:(MobilyMap*)map copyEntries:(BOOL)flag; +- (instancetype)initWithContentsOfFile:(NSString*)path; +- (instancetype)initWithContentsOfURL:(NSURL*)URL; +- (instancetype)initWithContentsOfDictionary:(NSDictionary*)entries; +- (instancetype)initWithObjects:(NSArray*)orderedObjects pairedWithKeys:(NSArray*)orderedKeys; +- (instancetype)initWithCoder:(NSCoder*)decoder; + +- (void)setup NS_REQUIRES_SUPER; + +- (BOOL)containsObject:(id)object; +- (BOOL)containsObject:(id)object pairedWithKey:(id< NSCopying >)key; +- (BOOL)containsEntry:(NSDictionary*)entry; + +- (NSUInteger)count; + +- (id)firstObject; +- (id< NSCopying >)firstKey; +- (NSDictionary*)firstEntry; + +- (id)lastObject; +- (id< NSCopying >)lastKey; +- (NSDictionary*)lastEntry; + +- (id)objectAtIndex:(NSUInteger)index; +- (id< NSCopying >)keyAtIndex:(NSUInteger)index; +- (NSDictionary*)entryAtIndex:(NSUInteger)index; + +- (NSArray*)objectsAtIndices:(NSIndexSet*)indeces; +- (NSArray*)keysAtIndices:(NSIndexSet*)indices; +- (MobilyMap*)entriesAtIndices:(NSIndexSet*)indices; +- (NSDictionary*)unorderedEntriesAtIndices:(NSIndexSet*)indices; +- (NSDictionary*)unmap; + +- (NSArray*)allKeys; +- (NSArray*)allObjects; +- (NSArray*)allKeysForObject:(id)anObject; + +- (id)objectForKey:(id< NSCopying >)key; +- (NSArray*)objectForKeys:(NSArray*)keys notFoundMarker:(id)anObject; + +- (NSEnumerator*)objectEnumerator; +- (NSEnumerator*)keyEnumerator; +- (NSEnumerator*)entryEnumerator; +- (NSEnumerator*)reverseObjectEnumerator; +- (NSEnumerator*)reverseKeyEnumerator; +- (NSEnumerator*)reverseEntryEnumerator; + +- (NSUInteger)indexOfObject:(id)object; +- (NSUInteger)indexOfKey:(id< NSCopying >)key; +- (NSUInteger)indexOfEntryWithObject:(id)object pairedWithKey:(id< NSCopying >)key; +- (NSUInteger)indexOfEntry:(NSDictionary*)entry; + +- (NSUInteger)indexOfObject:(id)object inRange:(NSRange)range; +- (NSUInteger)indexOfKey:(id< NSCopying >)key inRange:(NSRange)range; +- (NSUInteger)indexOfEntryWithObject:(id)object pairedWithKey:(id< NSCopying >)key inRange:(NSRange)range; +- (NSUInteger)indexOfEntry:(NSDictionary*)entry inRange:(NSRange)range; +- (NSUInteger)indexOfObjectIdenticalTo:(id)object; +- (id< NSCopying >)keyOfObjectIdenticalTo:(id)object; +- (NSUInteger)indexOfObjectIdenticalTo:(id)object inRange:(NSRange)range; +- (id< NSCopying >)keyOfObjectIdenticalTo:(id)object inRange:(NSRange)range; +- (NSUInteger)indexOfObjectPassingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL* stop))predicate; +- (id< NSCopying >)keyOfObjectPassingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL* stop))predicate; +- (NSUInteger)indexOfObjectWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL* stop))predicate; +- (id< NSCopying >)keyOfObjectWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL* stop))predicate; +- (NSUInteger)indexOfObjectAtIndices:(NSIndexSet*)indexSet options:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL* stop))predicate; +- (id< NSCopying >)keyOfObjectAtIndices:(NSIndexSet*)indexSet options:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL* stop))predicate; +- (NSUInteger)indexOfObject:(id)object inSortedRange:(NSRange)r options:(NSBinarySearchingOptions)opts usingComparator:(NSComparator)cmp; +- (id< NSCopying >)keyOfObject:(id)object inSortedRange:(NSRange)r options:(NSBinarySearchingOptions)opts usingComparator:(NSComparator)cmp; +- (NSIndexSet*)indicesOfObjectsPassingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL* stop))predicate; +- (NSArray*)keysOfObjectsPassingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL* stop))predicate; +- (NSIndexSet*)indicesOfObjectsWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL* stop))predicate; +- (NSArray*)keysOfObjectsWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL* stop))predicate; +- (NSIndexSet*)indicesOfObjectsAtIndices:(NSIndexSet*)indexSet options:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL* stop))predicate; +- (NSArray*)keysOfObjectsAtIndices:(NSIndexSet*)indexSet options:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id obj, NSUInteger idx, BOOL* stop))predicate; + +- (void)makeObjectsPerformSelector:(SEL)aSelector; +- (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)anObject; + +- (void)enumerateObjectsUsingBlock:(void(^)(id obj, NSUInteger idx, BOOL* stop))block; +- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void(^)(id obj, NSUInteger idx, BOOL* stop))block; +- (void)enumerateObjectsAtIndices:(NSIndexSet*)indexSet options:(NSEnumerationOptions)opts usingBlock:(void(^)(id obj, NSUInteger idx, BOOL* stop))block; +- (void)moEach:(void(^)(id key, id object))block; +- (void)eachWithIndex:(void(^)(id key, id object, NSUInteger index))block; +- (void)eachKey:(void(^)(id key))block; +- (void)eachKeyWithIndex:(void(^)(id key, NSUInteger index))block; +- (void)eachValue:(void(^)(id object))block; +- (void)eachValueWithIndex:(void(^)(id object, NSUInteger index))block; + +- (id)firstObjectInCommonWithMap:(MobilyMap*)otherMap; +- (id)firstKeyInCommonWithMap:(MobilyMap*)otherMap; +- (id)firstEntryInCommonWithMap:(MobilyMap*)otherMap; + +- (BOOL)isEqualToMap:(MobilyMap*)otherMap; + +- (MobilyMap*)mapByAddingObject:(id)object pairedWithKey:(id< NSCopying >)aKey; +- (MobilyMap*)mapByAddingEntry:(NSDictionary*)entry; +- (MobilyMap*)mapByAddingObjects:(NSArray*)orderedObjects pairedWithKeys:(NSArray*)orderedKeys; + +- (MobilyMap*)filteredOrderDictionarysUsingPredicateForObjects:(NSPredicate*)predicate; +- (MobilyMap*)subMapWithRange:(NSRange)range; + +- (NSData*)sortedObjectsHint; +- (NSData*)sortedKeysHint; + +- (MobilyMap*)sortedByObjectsUsingFunction:(NSInteger(*)(id, id, void*))comparator context:(void*)context; +- (MobilyMap*)sortedByKeysUsingFunction:(NSInteger(*)(id< NSCopying>, id< NSCopying>, void*))comparator context:(void*)context; +- (MobilyMap*)sortedByObjectsUsingFunction:(NSInteger(*)(id, id, void*))comparator context:(void*)context hint:(NSData*)hint; +- (MobilyMap*)sortedByKeysUsingFunction:(NSInteger(*)(id< NSCopying>, id< NSCopying>, void*))comparator context:(void*)context hint:(NSData*)hint; +- (MobilyMap*)sortedByObjectsUsingDescriptors:(NSArray*)descriptors; +- (MobilyMap*)sortedByKeysUsingDescriptors:(NSArray*)descriptors; +- (MobilyMap*)sortedByObjectsUsingSelector:(SEL)comparator; +- (MobilyMap*)sortedByKeysUsingSelector:(SEL)comparator; +- (MobilyMap*)sortedByObjectsUsingComparator:(NSComparator)cmptr; +- (MobilyMap*)sortedByKeysUsingComparator:(NSComparator)cmptr; +- (MobilyMap*)sortedByObjectsWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr; +- (MobilyMap*)sortedByKeysWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr; + +- (NSString*)description; +- (NSString*)descriptionWithLocale:(id)locale; +- (NSString*)descriptionWithLocale:(id)locale indent:(NSUInteger)level; + +- (BOOL)writeToFile:(NSString*)path atomically:(BOOL)flag; +- (BOOL)writeToURL:(NSURL*)aURL atomically:(BOOL)flag; + +- (void)addObserver:(NSObject*)anObserver toObjectsAtIndices:(NSIndexSet*)indices forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context; +- (void)addObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context; +- (void)removeObserver:(NSObject*)anObserver fromObjectsAtIndices:(NSIndexSet*)indices forKeyPath:(NSString*)keyPath; +- (void)removeObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath context:(void*)context; + +- (void)setValue:(id)value forKey:(NSString*)key; +- (void)setValue:(id)value forKeyPath:(NSString*)keyPath; +- (id)valueForKey:(NSString*)key; +- (id)valueForKeyPath:(NSString*)keyPath; + +- (void)encodeWithCoder:(NSCoder*)aCoder; + +- (id)copy; +- (id)copyWithZone:(NSZone*)zone; +- (id)mutableCopy; +- (id)mutableCopyWithZone:(NSZone*)zone; + +- (id)objectAtIndexedSubscript:(NSUInteger)index; +- (id)objectForKeyedSubscript:(id)key; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyMutableMap : MobilyMap + ++ (instancetype)mapWithCapacity:(NSUInteger)numEntries; +- (instancetype)initWithCapacity:(NSUInteger)numEntries; + +- (void)addObject:(id)object pairedWithKey:(id< NSCopying >)key; +- (void)addEntry:(NSDictionary*)entry; +- (void)addEntriesFromMap:(MobilyMap*)map; +- (void)addEntriesFromDictionary:(NSDictionary*)dictionary; + +- (void)insertObject:(id)object pairedWithKey:(id< NSCopying >)key atIndex:(NSUInteger)index; +- (void)insertEntry:(NSDictionary*)entry atIndex:(NSUInteger)index; +- (void)insertEntriesFromMap:(MobilyMap*)map atIndex:(NSUInteger)index; +- (void)insertEntriesFromDictionary:(NSDictionary*)dictionary atIndex:(NSUInteger)index; + +- (void)setObject:(id)object forKey:(id< NSCopying >)aKey; +- (void)setEntry:(NSDictionary*)entry; +- (void)setEntriesFromMap:(MobilyMap*)map; +- (void)setEntriesFromDictionary:(NSDictionary*)dictionary; +- (void)setObject:(id)object forKey:(id< NSCopying >)aKey atIndex:(NSUInteger)index; +- (void)setEntry:(NSDictionary*)entry atIndex:(NSUInteger)index; +- (void)setEntriesFromMap:(MobilyMap*)map atIndex:(NSUInteger)index; +- (void)setEntriesFromDictionary:(NSDictionary*)dictionary atIndex:(NSUInteger)index; + +- (void)removeObjectForKey:(id)key; +- (void)removeObjectsForKeys:(NSArray*)keys; +- (void)removeFirstEntry; +- (void)removeLastEntry; +- (void)removeEntryWithObject:(id)object; +- (void)removeEntryWithKey:(id< NSCopying >)key; +- (void)removeEntryWithObject:(id)object pairedWithKey:(id< NSCopying >)key; +- (void)removeEntry:(NSDictionary*)entry; +- (void)removeEntryWithObject:(id)object inRange:(NSRange)range; +- (void)removeEntryWithKey:(id< NSCopying >)key inRange:(NSRange)range; +- (void)removeEntryWithObject:(id)object pairedWithKey:(id< NSCopying >)key inRange:(NSRange)ramge; +- (void)removeEntry:(NSDictionary*)entry inRange:(NSRange)range; +- (void)removeEntryAtIndex:(NSUInteger)index; +- (void)removeEntriesAtIndices:(NSIndexSet*)indices; +- (void)removeEntryWithObjectIdenticalTo:(id)anObject; +- (void)removeEntryWithObjectIdenticalTo:(id)anObject inRange:(NSRange)range; +- (void)removeEntriesWithObjectsInArray:(NSArray*)array; +- (void)removeEntriesWithKeysInArray:(NSArray*)array; +- (void)removeEntriesInRange:(NSRange)range; +- (void)removeAllObjects; +- (void)removeAllEntries; + +- (void)replaceEntryAtIndex:(NSInteger)index withObject:(id)object pairedWithKey:(id< NSCopying >)key; +- (void)replaceEntryAtIndex:(NSUInteger)index withEntry:(NSDictionary*)entry; +- (void)replaceEntriesAtIndices:(NSIndexSet*)indices withObjects:(NSArray*)objects pairedWithKeys:(NSArray*)keys; +- (void)replaceEntriesAtIndices:(NSIndexSet*)indices withEntries:(NSArray*)orderedEntries; +- (void)replaceEntriesAtIndices:(NSIndexSet*)indices withEntriesFromMap:(MobilyMap*)map; + +- (void)replaceEntriesInRange:(NSRange)range withObjectsFromArray:(NSArray*)objects pairedWithKeysFromArray:(NSArray*)keys inRange:(NSRange)range2; +- (void)replaceEntriesInRange:(NSRange)range withEntriesFrom:(NSArray*)orderedEntries inRange:(NSRange)range2; +- (void)replaceEntriesInRange:(NSRange)range withEntriesFromMap:(MobilyMap*)dictionary inRange:(NSRange)range2; +- (void)replaceEntriesInRange:(NSRange)range withObjectsFromArray:(NSArray*)objects pairedWithKeysFromArray:(NSArray*)keys; +- (void)replaceEntriesInRange:(NSRange)range withEntriesFrom:(NSArray*)orderedEntries; +- (void)replaceEntriesInRange:(NSRange)range withEntriesFromMap:(MobilyMap*)dictionary; + +- (void)setEntriesToObjects:(NSArray*)objects pairedWithKeys:(NSArray*)keys; +- (void)setEntriesToMap:(MobilyMap*)map; + +- (void)filterEntriesUsingPredicateForObjects:(NSPredicate*)predicate; + +- (void)exchangeEntryAtIndex:(NSUInteger)idx1 withEntryAtIndex:(NSUInteger)idx2; + +- (void)sortEntriesByObjectUsingDescriptors:(NSArray*)descriptors; +- (void)sortEntriesByKeysUsingDescriptors:(NSArray*)descriptors; +- (void)sortEntriesByObjectUsingComparator:(NSComparator)cmptr; +- (void)sortEntriesByKeysUsingComparator:(NSComparator)cmptr; +- (void)sortEntriesByObjectWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr; +- (void)sortEntriesByKeysWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr; +- (void)sortEntriesByObjectUsingFunction:(NSInteger(*)(id, id, void*))compare context:(void*)context; +- (void)sortEntriesByKeysUsingFunction:(NSInteger(*)(id, id, void*))compare context:(void*)context; +- (void)sortEntriesByObjectUsingSelector:(SEL)comparator; +- (void)sortEntriesByKeysUsingSelector:(SEL)comparator; + +- (void)setObject:(id)object forKeyedSubscript:(id< NSCopying >)key; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyMap.m b/Sources/MobilyCore/MobilyMap.m new file mode 100644 index 0000000..e4cd355 --- /dev/null +++ b/Sources/MobilyCore/MobilyMap.m @@ -0,0 +1,1293 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyMap () { +@protected + NSMutableArray* _keys; + NSMutableArray* _objects; + NSMutableDictionary* _pairs; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyMap + +#pragma mark Creation + ++ (instancetype)map { + return [[[self class] alloc] init]; +} + ++ (instancetype)mapWithMap:(MobilyMap*)map { + return [[[self class] alloc] initWithMap:map]; +} + ++ (instancetype)mapWithContentsOfFile:(NSString*)path { + return [[[self class] alloc] initWithContentsOfFile:path]; +} + ++ (instancetype)mapWithContentsOfURL:(NSURL*)URL { + return [[[self class] alloc] initWithContentsOfURL:URL]; +} + ++ (instancetype)mapWithObject:(id)anObject pairedWithKey:(id< NSCopying >)aKey { + return [[[self class] alloc] initWithObjects:@[anObject] pairedWithKeys:@[aKey]]; +} + ++ (instancetype)mapWithDictionary:(NSDictionary*)entrys { + return [[[self class] alloc] initWithContentsOfDictionary:entrys]; +} + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + _keys = [[NSMutableArray alloc] init]; + _objects = [[NSMutableArray alloc] init]; + _pairs = [[NSMutableDictionary alloc] init]; + [self setup]; + } + return self; +} + +- (instancetype)initWithMap:(MobilyMap*)map { + return [self initWithMap:map copyEntries:NO]; +} + +- (instancetype)initWithMap:(MobilyMap*)map copyEntries:(BOOL)flag { + self = [super init]; + if(self != nil) { + _keys = [[NSMutableArray alloc] initWithArray:map.allKeys copyItems:flag]; + _objects = [[NSMutableArray alloc] initWithArray:map.allObjects copyItems:flag]; + _pairs = [[NSMutableDictionary alloc] initWithObjects:_objects forKeys:_keys]; + [self setup]; + } + return self; +} + +- (instancetype)initWithContentsOfFile:(NSString*)path { + NSDictionary* rawData = [NSDictionary dictionaryWithContentsOfFile:path]; + return [self initWithObjects:rawData[@"Objects"] pairedWithKeys:rawData[@"Keys"]]; +} + +- (instancetype)initWithContentsOfURL:(NSURL*)URL { + NSDictionary* rawData = [NSDictionary dictionaryWithContentsOfURL:URL]; + return [self initWithObjects:rawData[@"Objects"] pairedWithKeys:rawData[@"Keys"]]; +} + +- (instancetype)initWithContentsOfDictionary:(NSDictionary*)entrys { + self = [super init]; + if(self != nil) { + _keys = [[NSMutableArray alloc] initWithArray:entrys.allKeys]; + _objects = [[NSMutableArray alloc] init]; + for(id key in _keys) { + [_objects addObject:entrys[key]]; + } + _pairs = [[NSMutableDictionary alloc] initWithObjects:_objects forKeys:_keys]; + [self setup]; + } + return self; +} + +- (instancetype)initWithObjects:(NSArray*)orderedObjects pairedWithKeys:(NSArray*)orderedKeys { + NSAssert(orderedObjects.count == orderedKeys.count, @"The amount of _objects does not match the number of _keys"); + NSAssert([[NSSet setWithArray:orderedKeys] count] == orderedKeys.count, @"There are duplicate _keys on initialization"); + self = [super init]; + if(self != nil) { + _keys = [[NSMutableArray alloc] initWithArray:orderedKeys]; + _objects = [[NSMutableArray alloc] initWithArray:orderedObjects]; + _pairs = [[NSMutableDictionary alloc] initWithObjects:_objects forKeys:_keys]; + [self setup]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder*)decoder { + return [self initWithObjects:[decoder decodeObjectForKey:@"NSODObjects"] pairedWithKeys:[decoder decodeObjectForKey:@"NSODKeys"]]; +} + +- (void)setup { +} + +#pragma mark Querying + +- (BOOL)containsObject:(id)object { + return [_objects containsObject:object]; +} + +- (BOOL)containsObject:(id)object pairedWithKey:(id< NSCopying >)key { + if(([_objects containsObject:object] == YES) && ([_keys containsObject:key] == YES)) { + return YES; + } + return NO; +} + +- (BOOL)containsEntry:(NSDictionary*)entry { + return [self containsObject:(entry.allValues)[0] pairedWithKey:(entry.allKeys)[0]]; +} + +- (NSUInteger)count { + return [_keys count]; +} + +- (id)firstObject { + return _objects.firstObject; +} + +- (id< NSCopying >)firstKey { + return _keys.firstObject; +} + +- (NSDictionary*)firstEntry { + return @{ _keys.firstObject: _objects.firstObject }; +} + +- (id)lastObject { + return _objects.lastObject; +} + +- (id< NSCopying >)lastKey { + return _keys.lastObject; +} + +- (NSDictionary*)lastEntry { + return @{ _keys.lastObject: _objects.lastObject }; +} + +- (id)objectAtIndex:(NSUInteger)index { + return _objects[index]; +} + +- (id< NSCopying >)keyAtIndex:(NSUInteger)index { + return _keys[index]; +} + +- (NSDictionary*)entryAtIndex:(NSUInteger)index { + return @{ _keys[index]: self[index] }; +} + +- (NSArray*)objectsAtIndices:(NSIndexSet*)indexes { + return [_objects objectsAtIndexes:indexes]; +} + +- (NSArray*)keysAtIndices:(NSIndexSet*)indexes { + return [_keys objectsAtIndexes:indexes]; +} + +- (MobilyMap*)entriesAtIndices:(NSIndexSet*)indexes { + return [[MobilyMap alloc] initWithObjects:[_objects objectsAtIndexes:indexes] pairedWithKeys:[_keys objectsAtIndexes:indexes]]; +} + +- (NSDictionary*)unorderedEntriesAtIndices:(NSIndexSet*)indexes { + return [NSDictionary dictionaryWithObjects:[_objects objectsAtIndexes:indexes] forKeys:[_keys objectsAtIndexes:indexes]]; +} + +- (NSDictionary*)unmap { + return [NSDictionary dictionaryWithObjects:_objects forKeys:_keys]; +} + +- (NSArray*)allKeys { + return _keys; +} + +- (NSArray*)allObjects { + return _objects; +} + +- (NSArray*)allKeysForObject:(id)anObject { + return [_pairs allKeysForObject:anObject]; +} + +- (id)objectForKey:(id< NSCopying >)key { + return _pairs[key]; +} + +- (NSArray*)objectForKeys:(NSArray*)orderedKeys notFoundMarker:(id)anObject { + return [_pairs objectsForKeys:orderedKeys notFoundMarker:anObject]; +} + +#pragma mark Enumeration + +- (NSEnumerator*)objectEnumerator { + return [_objects objectEnumerator]; +} + +- (NSEnumerator*)keyEnumerator { + return [_keys objectEnumerator]; +} + +- (NSEnumerator*)entryEnumerator { + NSMutableArray* temp = [[NSMutableArray alloc] init]; + for(NSUInteger i = 0; i < _keys.count; i++) { + [temp addObject:[self entryAtIndex:i]]; + } + return [temp objectEnumerator]; +} + +- (NSEnumerator*)reverseObjectEnumerator { + return [_objects reverseObjectEnumerator]; +} + +- (NSEnumerator*)reverseKeyEnumerator { + return [_keys reverseObjectEnumerator]; +} + +- (NSEnumerator*)reverseEntryEnumerator { + NSMutableArray* temp = [[NSMutableArray alloc] init]; + for(NSUInteger i = 1; i <= _keys.count; i--) { + [temp addObject:[self entryAtIndex:(_keys.count - i)]]; + } + return [temp objectEnumerator]; +} + +#pragma mark Searching + +- (NSUInteger)indexOfObject:(id)object { + return [_objects indexOfObject:object]; +} + +- (NSUInteger)indexOfKey:(id< NSCopying >)key { + return [_keys indexOfObject:key]; +} + +- (NSUInteger)indexOfEntryWithObject:(id)object pairedWithKey:(id< NSCopying >)key { + NSIndexSet* idx1 = [_objects indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger index __unused, BOOL* stop __unused) { + return [obj isEqual:object]; + }]; + NSIndexSet* idx2 = [_keys indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger index __unused, BOOL* stop __unused) { + return [obj isEqual:key]; + }]; + NSUInteger index = NSNotFound; + NSUInteger current_index = [idx1 firstIndex]; + while((current_index != NSNotFound) && (index == NSNotFound)) { + if([idx2 containsIndex:current_index] == YES) { + index = current_index; + } + current_index = [idx1 indexGreaterThanIndex:current_index]; + } + return index; +} + +- (NSUInteger)indexOfEntry:(NSDictionary*)entry { + return [self indexOfEntryWithObject:(entry.allValues)[0] pairedWithKey:(entry.allKeys)[0]]; +} + +- (NSUInteger)indexOfObject:(id)object inRange:(NSRange)range { + return [_objects indexOfObject:object inRange:range]; +} + +- (NSUInteger)indexOfKey:(id< NSCopying >)key inRange:(NSRange)range { + return [_keys indexOfObject:key inRange:range]; +} + +- (NSUInteger)indexOfEntryWithObject:(id)object pairedWithKey:(id< NSCopying >)key inRange:(NSRange)range { + NSIndexSet* idx1 = [[_objects objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range]] indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger index __unused, BOOL* stop __unused) { + return [obj isEqual:object]; + }]; + NSIndexSet* idx2 = [[_keys objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range]] indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger index __unused, BOOL* stop __unused) { + return [obj isEqual:key]; + }]; + NSUInteger index = NSNotFound; + NSUInteger current_index = [idx1 firstIndex]; + while((current_index != NSNotFound) && (index == NSNotFound)) { + if([idx2 containsIndex:current_index] == YES) { + index = current_index; + } + current_index = [idx1 indexGreaterThanIndex:current_index]; + } + return index; +} + +- (NSUInteger)indexOfEntry:(NSDictionary*)entry inRange:(NSRange)range { + return [self indexOfEntryWithObject:(entry.allValues)[0] pairedWithKey:(entry.allKeys)[0] inRange:range]; +} + +- (NSUInteger)indexOfObjectIdenticalTo:(id)object { + return [_objects indexOfObjectIdenticalTo:object]; +} + +- (id< NSCopying >)keyOfObjectIdenticalTo:(id)object { + return _keys[[_objects indexOfObjectIdenticalTo:object]]; +} + +- (NSUInteger)indexOfObjectIdenticalTo:(id)object inRange:(NSRange)range { + return [_objects indexOfObjectIdenticalTo:object inRange:range]; +} + +- (id< NSCopying >)keyOfObjectIdenticalTo:(id)object inRange:(NSRange)range { + return _keys[[_objects indexOfObjectIdenticalTo:object inRange:range]]; +} + +- (NSUInteger)indexOfObjectPassingTest:(BOOL(^)(id, NSUInteger, BOOL*))predicate { + return [_objects indexOfObjectPassingTest:predicate]; +} + +- (id< NSCopying >)keyOfObjectPassingTest:(BOOL(^)(id, NSUInteger, BOOL*))predicate { + return _keys[[_objects indexOfObjectPassingTest:predicate]]; +} + +- (NSUInteger)indexOfObjectWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id, NSUInteger, BOOL*))predicate { + return [_objects indexOfObjectWithOptions:opts passingTest:predicate]; +} + +- (id< NSCopying >)keyOfObjectWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id, NSUInteger, BOOL*))predicate { + return _keys[[_objects indexOfObjectWithOptions:opts passingTest:predicate]]; +} + +- (NSUInteger)indexOfObjectAtIndices:(NSIndexSet*)indexSet options:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id, NSUInteger, BOOL*))predicate { + return [_objects indexOfObjectAtIndexes:indexSet options:opts passingTest:predicate]; +} + +- (id< NSCopying >)keyOfObjectAtIndices:(NSIndexSet*)indexSet options:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id, NSUInteger, BOOL*))predicate { + return _keys[[_objects indexOfObjectAtIndexes:indexSet options:opts passingTest:predicate]]; +} + +- (NSUInteger)indexOfObject:(id)object inSortedRange:(NSRange)r options:(NSBinarySearchingOptions)opts usingComparator:(NSComparator)cmp { + return [_objects indexOfObject:object inSortedRange:r options:opts usingComparator:cmp]; +} + +- (id< NSCopying >)keyOfObject:(id)object inSortedRange:(NSRange)r options:(NSBinarySearchingOptions)opts usingComparator:(NSComparator)cmp { + return _keys[[object indexOfObject:object inSortedRange:r options:opts usingComparator:cmp]]; +} + +- (NSIndexSet*)indicesOfObjectsPassingTest:(BOOL(^)(id, NSUInteger, BOOL*))predicate { + return [_objects indexesOfObjectsPassingTest:predicate]; +} + +- (NSArray*)keysOfObjectsPassingTest:(BOOL(^)(id, NSUInteger, BOOL*))predicate { + return [_keys objectsAtIndexes:[_objects indexesOfObjectsPassingTest:predicate]]; +} + +- (NSIndexSet*)indicesOfObjectsWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id, NSUInteger, BOOL*))predicate { + return [_objects indexesOfObjectsWithOptions:opts passingTest:predicate]; +} + +- (NSArray*)keysOfObjectsWithOptions:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id, NSUInteger, BOOL*))predicate { + return [_keys objectsAtIndexes:[_objects indexesOfObjectsWithOptions:opts passingTest:predicate]]; +} + +- (NSIndexSet*)indicesOfObjectsAtIndices:(NSIndexSet*)indexSet options:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id, NSUInteger, BOOL*))predicate { + return [_objects indexesOfObjectsAtIndexes:indexSet options:opts passingTest:predicate]; +} + +- (NSArray*)keysOfObjectsAtIndices:(NSIndexSet*)indexSet options:(NSEnumerationOptions)opts passingTest:(BOOL(^)(id, NSUInteger, BOOL*))predicate { + return [_keys objectsAtIndexes:[_objects indexesOfObjectsAtIndexes:indexSet options:opts passingTest:predicate]]; +} + +#pragma mark Performing Selectors + +- (void)makeObjectsPerformSelector:(SEL)aSelector { + [_objects makeObjectsPerformSelector:aSelector]; +} + +- (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)anObject { + [_objects makeObjectsPerformSelector:aSelector withObject:anObject]; +} + +- (void)enumerateObjectsUsingBlock:(void(^)(id, NSUInteger, BOOL*))block { + [_objects enumerateObjectsUsingBlock:block]; +} + +- (void)enumerateObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void(^)(id, NSUInteger, BOOL*))block { + [_objects enumerateObjectsWithOptions:opts usingBlock:block]; +} + +- (void)enumerateObjectsAtIndices:(NSIndexSet*)indexSet options:(NSEnumerationOptions)opts usingBlock:(void(^)(id, NSUInteger, BOOL*))block { + [_objects enumerateObjectsAtIndexes:indexSet options:opts usingBlock:block]; +} + +- (void)moEach:(void(^)(id key, id object))block { + [_objects enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL* stop __unused) { + block(_keys[index], object); + }]; +} + +- (void)eachWithIndex:(void(^)(id key, id object, NSUInteger index))block { + [_objects enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL* stop __unused) { + block(_keys[index], object, index); + }]; +} + +- (void)eachKey:(void(^)(id key))block { + [_objects enumerateObjectsUsingBlock:^(id object __unused, NSUInteger index, BOOL* stop __unused) { + block(_keys[index]); + }]; +} + +- (void)eachKeyWithIndex:(void(^)(id key, NSUInteger index))block { + [_objects enumerateObjectsUsingBlock:^(id object __unused, NSUInteger index, BOOL* stop __unused) { + block(_keys[index], index); + }]; +} + +- (void)eachValue:(void(^)(id object))block { + [_objects enumerateObjectsUsingBlock:^(id object, NSUInteger index __unused, BOOL* stop __unused) { + block(object); + }]; +} + +- (void)eachValueWithIndex:(void(^)(id object, NSUInteger index))block { + [_objects enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL* stop __unused) { + block(object, index); + }]; +} + +#pragma mark Comparing + +- (id)firstObjectInCommonWithMap:(MobilyMap*)otherMap { + return [_objects firstObjectCommonWithArray:otherMap.allObjects]; +} + +- (id)firstKeyInCommonWithMap:(MobilyMap*)otherMap { + return [_keys firstObjectCommonWithArray:otherMap.allKeys]; +} + +- (id)firstEntryInCommonWithMap:(MobilyMap*)otherMap { + NSArray* temp1 = [_keys firstObjectCommonWithArray:otherMap.allKeys]; + id object = nil; + int i = 0; + while(i < temp1.count && object == nil) { + if([self[temp1[i]] isEqual:otherMap[temp1[i]]] == YES) { + _objects = self[temp1[i]]; + } + } + return object; +} + +- (BOOL)isEqualToMap:(MobilyMap*)otherMap { + if([self count] != otherMap.count) { + return NO; + } else { + BOOL A = [_keys isEqualToArray:otherMap.allKeys]; + BOOL B = [_objects isEqualToArray:otherMap.allObjects]; + if((A == YES) && (B == YES)) { + return YES; + } + } + return NO; +} + +#pragma mark Deriving + +- (MobilyMap*)mapByAddingObject:(id)object pairedWithKey:(id< NSCopying >)aKey { + return [[MobilyMap alloc] initWithObjects:[_objects arrayByAddingObject:object] pairedWithKeys:[_keys arrayByAddingObject:aKey]]; +} + +- (MobilyMap*)mapByAddingEntry:(NSDictionary*)entry { + return [[MobilyMap alloc] initWithObjects:[_objects arrayByAddingObject:(entry.allValues)[0]] pairedWithKeys:[_keys arrayByAddingObject:(entry.allKeys)[0]]]; +} + +- (MobilyMap*)mapByAddingObjects:(NSArray*)orderedObjects pairedWithKeys:(NSArray*)orderedKeys { + return [[MobilyMap alloc] initWithObjects:[_objects arrayByAddingObjectsFromArray:orderedObjects] pairedWithKeys:[_keys arrayByAddingObjectsFromArray:orderedKeys]]; +} + +- (MobilyMap*)filteredOrderDictionarysUsingPredicateForObjects:(NSPredicate*)predicate { + NSArray* tempObj = [_objects filteredArrayUsingPredicate:predicate]; + int i = 0; + int j = 0; + NSMutableArray* tempKey = [[NSMutableArray alloc] init]; + while((i < tempObj.count) && (j < _keys.count)) { + if([tempObj[i] isEqual:_objects[j]] == YES) { + [tempKey addObject:_keys[j]]; + j++; + i++; + } + j++; + } + return [[MobilyMap alloc] initWithObjects:tempObj pairedWithKeys:tempKey]; +} + +- (MobilyMap*)subMapWithRange:(NSRange)range { + return [[MobilyMap alloc] initWithObjects:[_objects subarrayWithRange:range] pairedWithKeys:[_keys subarrayWithRange:range]]; +} + +#pragma mark Sorting + +- (NSArray*)keysForSortedObjects:(NSArray*)tempObj { + NSMutableArray* tempKey = [[NSMutableArray alloc] init]; + NSMutableArray* testObj = [[NSMutableArray alloc] initWithArray:_objects]; + NSMutableArray* testKey = [[NSMutableArray alloc] initWithArray:_keys]; + while(testObj.count > 0) { + NSInteger index = [testObj indexOfObjectIdenticalTo:tempObj[(tempObj.count - testObj.count)]]; + [tempKey addObject:testKey[index]]; + [testKey removeObjectAtIndex:index]; + [testObj removeObjectAtIndex:index]; + } + return tempKey; +} + +- (NSArray*)objectsForSortedKeys:(NSArray*)tempKey { + NSMutableArray* tempObj = [[NSMutableArray alloc] init]; + for(id key in tempKey) { + [tempObj addObject:_pairs[key]]; + } + return tempObj; +} + +- (NSData*)sortedObjectsHint { + return [_objects sortedArrayHint]; +} + +- (NSData*)sortedKeysHint { + return [_keys sortedArrayHint]; +} + +- (MobilyMap*)sortedByObjectsUsingFunction:(NSInteger(*)(__strong id, __strong id, void*))comparator context:(void*)context { + NSArray* tempObj = [_objects sortedArrayUsingFunction:comparator context:context]; + return [[MobilyMap alloc] initWithObjects:tempObj pairedWithKeys:[self keysForSortedObjects:tempObj]]; +} + +- (MobilyMap*)sortedByKeysUsingFunction:(NSInteger(*)(__strong id< NSCopying>, __strong id< NSCopying>, void*))comparator context:(void*)context { + NSArray* tempKey = [_keys sortedArrayUsingFunction:comparator context:context]; + return [[MobilyMap alloc] initWithObjects:[self objectsForSortedKeys:tempKey] pairedWithKeys:tempKey]; +} + +- (MobilyMap*)sortedByObjectsUsingFunction:(NSInteger(*)(__strong id, __strong id, void*))comparator context:(void*)context hint:(NSData*)hint { + NSArray* tempObj = [_objects sortedArrayUsingFunction:comparator context:context hint:hint]; + return [[MobilyMap alloc] initWithObjects:tempObj pairedWithKeys:[self keysForSortedObjects:tempObj]]; +} + +- (MobilyMap*)sortedByKeysUsingFunction:(NSInteger(*)(__strong id< NSCopying>, __strong id< NSCopying>, void*))comparator context:(void*)context hint:(NSData*)hint { + NSArray* tempKey = [_keys sortedArrayUsingFunction:comparator context:context hint:hint]; + return [[MobilyMap alloc] initWithObjects:[self objectsForSortedKeys:tempKey] pairedWithKeys:tempKey]; +} + +- (MobilyMap*)sortedByObjectsUsingDescriptors:(NSArray*)descriptors { + NSArray* tempObj = [_objects sortedArrayUsingDescriptors:descriptors]; + return [[MobilyMap alloc] initWithObjects:tempObj pairedWithKeys:[self keysForSortedObjects:tempObj]]; +} + +- (MobilyMap*)sortedByKeysUsingDescriptors:(NSArray*)descriptors { + NSArray* tempKey = [_keys sortedArrayUsingDescriptors:descriptors]; + return [[MobilyMap alloc] initWithObjects:[self objectsForSortedKeys:tempKey] pairedWithKeys:tempKey]; +} + +- (MobilyMap*)sortedByObjectsUsingSelector:(SEL)comparator { + NSArray* tempObj = [_objects sortedArrayUsingSelector:comparator]; + return [[MobilyMap alloc] initWithObjects:tempObj pairedWithKeys:[self keysForSortedObjects:tempObj]]; +} + +- (MobilyMap*)sortedByKeysUsingSelector:(SEL)comparator { + NSArray* tempKey = [_keys sortedArrayUsingSelector:comparator]; + return [[MobilyMap alloc] initWithObjects:[self objectsForSortedKeys:tempKey] pairedWithKeys:tempKey]; +} + +- (MobilyMap*)sortedByObjectsUsingComparator:(NSComparator)cmptr { + NSArray* tempObj = [_objects sortedArrayUsingComparator:cmptr]; + return [[MobilyMap alloc] initWithObjects:tempObj pairedWithKeys:[self keysForSortedObjects:tempObj]]; +} + +- (MobilyMap*)sortedByKeysUsingComparator:(NSComparator)cmptr { + NSArray* tempKey = [_keys sortedArrayUsingComparator:cmptr]; + return [[MobilyMap alloc] initWithObjects:[self objectsForSortedKeys:tempKey] pairedWithKeys:tempKey]; +} + +- (MobilyMap*)sortedByObjectsWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr { + NSArray* tempObj = [_objects sortedArrayWithOptions:opts usingComparator:cmptr]; + return [[MobilyMap alloc] initWithObjects:tempObj pairedWithKeys:[self keysForSortedObjects:tempObj]]; +} + +- (MobilyMap*)sortedByKeysWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr { + NSArray* tempKey = [_objects sortedArrayWithOptions:opts usingComparator:cmptr]; + return [[MobilyMap alloc] initWithObjects:[self objectsForSortedKeys:tempKey] pairedWithKeys:tempKey]; +} + +#pragma mark Description + +- (NSString*)description { + NSMutableString* string = [[NSMutableString alloc] init]; + [string appendString:@"{"]; + for(int i = 0; i < self.count; i++) { + id key = _keys[i]; + id object = _objects[i]; + NSString* keyDes = @""; + NSString* objDes = @""; + if([key respondsToSelector:@selector(description)] == YES) { + keyDes = [key description]; + } else { + keyDes = nil; + } + if([object respondsToSelector:@selector(description)] == YES) { + objDes = [object description]; + } else { + objDes = nil; + } + [string appendFormat:@"\n\t%@ = %@", keyDes, objDes]; + if(i < self.count - 1) { + [string appendString:@";"]; + } + } + [string appendString:@"\n}"]; + return string; +} + +- (NSString*)descriptionWithLocale:(id)locale { + NSMutableString* string = [[NSMutableString alloc] init]; + [string appendString:@"{"]; + for(int i = 0; i < self.count; i++) { + id key = _keys[i]; + id object = _objects[i]; + NSString* keyDes = @""; + NSString* objDes = @""; + if([key respondsToSelector:@selector(descriptionWithLocale:indent:)] == YES) { + keyDes = [key descriptionWithLocale:locale indent:1]; + } + else if([key respondsToSelector:@selector(descriptionWithLocale:)] == YES) { + keyDes = [key descriptionWithLocale:locale]; + } else if([key respondsToSelector:@selector(description)] == YES) { + keyDes = [key description]; + } else { + keyDes = nil; + } + if([object respondsToSelector:@selector(descriptionWithLocale:indent:)] == YES) { + objDes = [object descriptionWithLocale:locale indent:1]; + } + else if([object respondsToSelector:@selector(descriptionWithLocale:)] == YES) { + objDes = [object descriptionWithLocale:locale]; + } else if([object respondsToSelector:@selector(description)] == YES) { + objDes = [object description]; + } else { + objDes = nil; + } + [string appendFormat:@"\n\t%@ = %@", keyDes, objDes]; + if(i < self.count - 1) { + [string appendString:@";"]; + } + } + [string appendString:@"\n}"]; + return string; +} + +- (NSString*)descriptionWithLocale:(id)locale indent:(NSUInteger)level { + NSMutableString* string = [[NSMutableString alloc] init]; + [string appendString:@" {"]; + for(int i = 0; i < self.count; i++) { + id key = _keys[i]; + id object = _objects[i]; + NSString* keyDes = @""; + NSString* objDes = @""; + if([key respondsToSelector:@selector(descriptionWithLocale:indent:)] == YES) { + keyDes = [key descriptionWithLocale:locale indent:level + 1]; + } else if([key respondsToSelector:@selector(descriptionWithLocale:)] == YES) { + keyDes = [key descriptionWithLocale:locale]; + } else if([key respondsToSelector:@selector(description)] == YES) { + keyDes = [key description]; + } else { + keyDes = nil; + } + if([object respondsToSelector:@selector(descriptionWithLocale:indent:)] == YES) { + objDes = [object descriptionWithLocale:locale indent:level + 1]; + } else if([object respondsToSelector:@selector(descriptionWithLocale:)] == YES) { + objDes = [object descriptionWithLocale:locale]; + } else if([object respondsToSelector:@selector(description)] == YES) { + objDes = [object description]; + } else { + objDes = nil; + } + for(int i = 0; i < level; i++) { + [string appendString:@"\t"]; + } + [string appendFormat:@"\n%@ = %@", keyDes, objDes]; + if(i < self.count - 1) { + [string appendString:@";"]; + } + } + [string appendString:@"\n"]; + for(int i = 0; i < level; i++) { + [string appendString:@"\t"]; + } + [string appendString:@"}"]; + return string; +} + +- (BOOL)writeToFile:(NSString*)path atomically:(BOOL)flag { + NSDictionary* dict = [NSDictionary dictionaryWithObjects:_objects forKeys:_keys]; + return [dict writeToFile:path atomically:flag]; +} + +- (BOOL)writeToURL:(NSURL*)aURL atomically:(BOOL)flag { + NSDictionary* dict = [NSDictionary dictionaryWithObjects:_objects forKeys:_keys]; + return [dict writeToURL:aURL atomically:flag]; +} + +#pragma mark KVO + +- (void)addObserver:(NSObject*)anObserver toObjectsAtIndices:(NSIndexSet*)indexes forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context { + [_objects addObserver:anObserver toObjectsAtIndexes:indexes forKeyPath:keyPath options:options context:context]; +} + +- (void)addObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context { + [_pairs addObserver:observer forKeyPath:keyPath options:options context:context]; +} + +- (void)removeObserver:(NSObject*)anObserver fromObjectsAtIndices:(NSIndexSet*)indexes forKeyPath:(NSString*)keyPath { + [_objects removeObserver:anObserver fromObjectsAtIndexes:indexes forKeyPath:keyPath]; +} + +- (void)removeObserver:(NSObject*)observer forKeyPath:(NSString*)keyPath context:(void*)context { + [_pairs removeObserver:observer forKeyPath:keyPath context:context]; +} + +- (void)setValue:(id)value forKey:(NSString*)key { + [_objects setValue:value forKey:key]; +} + +- (id)valueForKey:(NSString*)key { + return [_objects valueForKey:key]; +} + +- (void)setValue:(id)value forKeyPath:(NSString*)keyPath { + [_pairs setValue:value forKeyPath:keyPath]; +} + +- (id)valueForKeyPath:(NSString*)keyPath { + return [_pairs valueForKeyPath:keyPath]; +} + +#pragma mark NSCoding + +- (void)encodeWithCoder:(NSCoder*)aCoder { + [aCoder encodeObject:_objects forKey:@"NSODObjects"]; + [aCoder encodeObject:_keys forKey:@"NSODKeys"]; +} + +#pragma mark NSCopying + +- (id)copy { + return [self copyWithZone:NSDefaultMallocZone()]; +} + +- (id)copyWithZone:(NSZone*)zone { + return [[MobilyMap alloc] initWithObjects:[_objects copyWithZone:zone] pairedWithKeys:[_keys copyWithZone:zone]]; +} + +- (id)mutableCopy { + return [self mutableCopyWithZone:NSDefaultMallocZone()]; +} + +- (id)mutableCopyWithZone:(NSZone*)zone { + return [[MobilyMutableMap allocWithZone:zone] initWithMap:self]; +} + +#pragma mark NSFastEnumeration + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState*)state objects:(__unsafe_unretained id [])buffer count:(NSUInteger)len { + return [_keys countByEnumeratingWithState:state objects:buffer count:len]; +} + +#pragma mark Indexed Subscripts + +- (id)objectAtIndexedSubscript:(NSUInteger)index { + return _objects[index]; +} + +- (id)objectForKeyedSubscript:(id)key { + return _pairs[key]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyMutableMap + +#pragma mark Creating + ++ (instancetype)mapWithCapacity:(NSUInteger)numEntrys { + return [[[self class] alloc] initWithCapacity:numEntrys]; +} + +#pragma mark Init / Free + +- (instancetype)initWithCapacity:(NSUInteger)numEntrys { + return [[MobilyMutableMap alloc] initWithObjects:[NSMutableArray arrayWithCapacity:numEntrys] pairedWithKeys:[NSMutableArray arrayWithCapacity:numEntrys]]; +} + +#pragma mark Adding Objects + +- (void)addObject:(id)object pairedWithKey:(id< NSCopying >)key { + if(_pairs[key] != nil) { + [self removeEntryWithKey:key]; + } + _pairs[key] = object; + [_keys addObject:key]; + [_objects addObject:object]; +} + +- (void)addEntry:(NSDictionary*)entry { + [self addObject:(entry.allValues)[0] pairedWithKey:(entry.allKeys)[0]]; +} + +- (void)addEntriesFromMap:(MobilyMap*)map { + for(int i = 0; i < map.count; i++) { + [self addObject:map[i] pairedWithKey:[map keyAtIndex:i]]; + } +} + +- (void)addEntriesFromDictionary:(NSDictionary*)dictionary { + for(id key in dictionary.allKeys) { + [self addObject:dictionary[key] pairedWithKey:key]; + } +} + +- (void)insertObject:(id)object pairedWithKey:(id< NSCopying >)key atIndex:(NSUInteger)index { + if(_pairs[key] != nil) { + [self removeEntryWithKey:key]; + } + _pairs[key] = object; + [_keys insertObject:key atIndex:index]; + [_objects insertObject:object atIndex:index]; +} + +- (void)insertEntry:(NSDictionary*)entry atIndex:(NSUInteger)index { + [self insertObject:(entry.allValues)[0] pairedWithKey:(entry.allKeys)[0] atIndex:index]; +} + +- (void)insertEntriesFromMap:(MobilyMap*)map atIndex:(NSUInteger)index { + for(int i = 0; i < map.count; i++) { + [self insertObject:map[i] pairedWithKey:[map keyAtIndex:i] atIndex:(index + i)]; + } +} + +- (void)insertEntriesFromDictionary:(NSDictionary*)dictionary atIndex:(NSUInteger)index { + NSUInteger i = index; + for(id key in dictionary.allKeys) { + [self insertObject:dictionary[key] pairedWithKey:key atIndex:i]; + i++; + } +} + +- (void)setObject:(id)object forKey:(id< NSCopying >)aKey { + if(_pairs[aKey] != nil) { + _pairs[aKey] = object; + _objects[[self indexOfKey:aKey]] = object; + } else { + [self addObject:object pairedWithKey:aKey]; + } +} + +- (void)setEntry:(NSDictionary*)entry { + self[(entry.allKeys)[0]] = (entry.allValues)[0]; +} + +- (void)setEntriesFromMap:(MobilyMap*)map { + for(NSUInteger i = 0; i < map.count; i++) { + self[[map keyAtIndex:i]] = map[i]; + } +} + +- (void)setEntriesFromDictionary:(NSDictionary*)dictionary { + for(id key in dictionary.allKeys) { + self[key] = dictionary[key]; + } +} + +- (void)setObject:(id)object forKey:(id< NSCopying >)aKey atIndex:(NSUInteger)index { + if(_pairs[aKey] != nil) { + _pairs[aKey] = object; + _objects[[self indexOfKey:aKey]] = object; + } else { + [self insertObject:object pairedWithKey:_keys atIndex:index]; + } +} + +- (void)setEntry:(NSDictionary*)entry atIndex:(NSUInteger)index { + [self setObject:(entry.allValues)[0] forKey:(entry.allKeys)[0] atIndex:index]; +} + +- (void)setEntriesFromMap:(MobilyMap*)map atIndex:(NSUInteger)index { + for(NSUInteger i = 0; i < map.count; i++) { + [self setObject:map[i] forKey:[map keyAtIndex:i] atIndex:(index + i)]; + } +} + +- (void)setEntriesFromDictionary:(NSDictionary*)dictionary atIndex:(NSUInteger)index { + NSUInteger i = index; + for(id key in dictionary.allKeys) { + [self setObject:dictionary[key] forKey:key atIndex:i]; + i++; + } +} + +#pragma mark Removing + +- (void)removeObjectForKey:(id)key { + [self removeEntryWithKey:key]; +} + +- (void)removeObjectsForKeys:(NSArray*)arrayKeys { + [self removeEntriesWithKeysInArray:arrayKeys]; +} + +- (void)removeFirstEntry { + if(_keys.count > 0) { + [self removeEntryAtIndex:0]; + } +} + +- (void)removeLastEntry { + if(_keys.count > 0) { + [self removeEntryAtIndex:(_keys.count - 1)]; + } +} + +- (void)removeEntryWithObject:(id)object { + NSUInteger index = [self indexOfObject:object]; + if(index != NSNotFound) { + [self removeEntryAtIndex:index]; + } +} + +- (void)removeEntryWithKey:(id< NSCopying >)key { + NSUInteger index = [self indexOfKey:key]; + if(index != NSNotFound) { + [self removeEntryAtIndex:index]; + } +} + +- (void)removeEntryWithObject:(id)object pairedWithKey:(id< NSCopying >)key { + NSUInteger index = [self indexOfEntryWithObject:object pairedWithKey:key]; + if(index != NSNotFound) { + [self removeEntryAtIndex:index]; + } +} + +- (void)removeEntry:(NSDictionary*)entry { + [self removeEntryWithObject:(entry.allValues)[0] pairedWithKey:(entry.allKeys)[0]]; +} + +- (void)removeEntryWithObject:(id)object inRange:(NSRange)range { + NSUInteger index = [self indexOfObject:object inRange:range]; + if(index != NSNotFound) { + [self removeEntryAtIndex:index]; + } +} + +- (void)removeEntryWithKey:(id< NSCopying >)key inRange:(NSRange)range { + NSUInteger index = [self indexOfKey:key inRange:range]; + if(index != NSNotFound) { + [self removeEntryAtIndex:index]; + } +} + +- (void)removeEntryWithObject:(id)object pairedWithKey:(id< NSCopying >)key inRange:(NSRange)range { + NSUInteger index = [self indexOfEntryWithObject:object pairedWithKey:key inRange:range]; + if(index != NSNotFound) { + [self removeEntryAtIndex:index]; + } +} + +- (void)removeEntry:(NSDictionary*)entry inRange:(NSRange)range { + NSUInteger index = [self indexOfEntry:entry inRange:range]; + if(index != NSNotFound) { + [self removeEntryAtIndex:index]; + } +} + +- (void)removeEntryAtIndex:(NSUInteger)index { + id key = _keys[index]; + [_keys removeObjectAtIndex:index]; + [_objects removeObjectAtIndex:index]; + [_pairs removeObjectForKey:key]; +} + +- (void)removeEntriesAtIndices:(NSIndexSet*)indexes { + NSArray* tempKey = [self keysAtIndices:indexes]; + for(id key in tempKey) { + [self removeEntryWithKey:key]; + } +} + +- (void)removeEntryWithObjectIdenticalTo:(id)anObject { + NSUInteger index = [self indexOfObjectIdenticalTo:anObject]; + if(index != NSNotFound) { + [self removeEntryAtIndex:index]; + } +} + +- (void)removeEntryWithObjectIdenticalTo:(id)anObject inRange:(NSRange)range { + NSUInteger index = [self indexOfObjectIdenticalTo:anObject inRange:range]; + if(index != NSNotFound) { + [self removeEntryAtIndex:index]; + } +} + +- (void)removeEntriesWithObjectsInArray:(NSArray*)array { + for(id object in array) { + [self removeEntryWithObject:object]; + } +} + +- (void)removeEntriesWithKeysInArray:(NSArray*)array { + for(id key in array) { + [self removeEntryWithKey:key]; + } +} + +- (void)removeEntriesInRange:(NSRange)range { + for(NSUInteger i = range.location; i < range.location + range.length; i++) { + [self removeEntryAtIndex:i]; + } +} + +- (void)removeAllObjects { + [self removeAllEntries]; +} + +- (void)removeAllEntries { + [_keys removeAllObjects]; + [_objects removeAllObjects]; + [_pairs removeAllObjects]; +} + +#pragma mark Replacing Objects + +- (void)replaceEntryAtIndex:(NSInteger)index withObject:(id)object pairedWithKey:(id< NSCopying >)key { + id oldKey = _keys[index]; + [_pairs removeObjectForKey:oldKey]; + _pairs[key] = object; + _keys[index] = key; + _objects[index] = object; +} + +- (void)replaceEntryAtIndex:(NSUInteger)index withEntry:(NSDictionary*)entry { + [self replaceEntryAtIndex:index withObject:(entry.allValues)[0] pairedWithKey:(entry.allKeys)[0]]; +} + +- (void)replaceEntriesAtIndices:(NSIndexSet*)indexes withObjects:(NSArray*)aobjects pairedWithKeys:(NSArray*)akeys { + NSUInteger index = [indexes firstIndex]; + int i = 0; + while(index != NSNotFound) { + if((i < aobjects.count) && (i < akeys.count)) { + [self replaceEntryAtIndex:index withObject:aobjects[i] pairedWithKey:akeys[i]]; + } + index = [indexes indexGreaterThanIndex:index]; + i++; + } +} + +- (void)replaceEntriesAtIndices:(NSIndexSet*)indexes withEntries:(NSArray*)orderedEntrys { + NSUInteger index = [indexes firstIndex]; + int i = 0; + while(index != NSNotFound) { + if(i < orderedEntrys.count) { + [self replaceEntryAtIndex:index withObject:orderedEntrys[i][0] pairedWithKey:orderedEntrys[i][0]]; + } + index = [indexes indexGreaterThanIndex:index]; + } +} + +- (void)replaceEntriesAtIndices:(NSIndexSet*)indexes withEntriesFromMap:(MobilyMap*)map { + NSUInteger index = [indexes firstIndex]; + int i = 0; + while(index != NSNotFound) { + if(i < map.count) { + [self replaceEntryAtIndex:index withObject:map[i] pairedWithKey:[map keyAtIndex:i]]; + } + index = [indexes indexGreaterThanIndex:index]; + } +} + +- (void)replaceEntriesInRange:(NSRange)range withObjectsFromArray:(NSArray*)object pairedWithKeysFromArray:(NSArray*)key inRange:(NSRange)range2 { + [self replaceEntriesAtIndices:[NSIndexSet indexSetWithIndexesInRange:range] withObjects:[object objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range2]] pairedWithKeys:[key objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range2]]]; +} + +- (void)replaceEntriesInRange:(NSRange)range withEntriesFrom:(NSArray*)orderedEntries inRange:(NSRange)range2 { + [self replaceEntriesAtIndices:[NSIndexSet indexSetWithIndexesInRange:range] withEntries:[orderedEntries objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range2]]]; +} + +- (void)replaceEntriesInRange:(NSRange)range withEntriesFromMap:(MobilyMap*)dictionary inRange:(NSRange)range2 { + [self replaceEntriesInRange:range withObjectsFromArray:[dictionary.allObjects objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range2]] pairedWithKeysFromArray:[dictionary.allKeys objectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range2]]]; +} + +- (void)replaceEntriesInRange:(NSRange)range withObjectsFromArray:(NSArray*)object pairedWithKeysFromArray:(NSArray*)key { + [self replaceEntriesAtIndices:[NSIndexSet indexSetWithIndexesInRange:range] withObjects:object pairedWithKeys:key]; +} + +- (void)replaceEntriesInRange:(NSRange)range withEntriesFrom:(NSArray*)orderedEntrys { + [self replaceEntriesAtIndices:[NSIndexSet indexSetWithIndexesInRange:range] withEntries:orderedEntrys]; +} + +- (void)replaceEntriesInRange:(NSRange)range withEntriesFromMap:(MobilyMap*)dictionary { + [self replaceEntriesAtIndices:[NSIndexSet indexSetWithIndexesInRange:range] withEntriesFromMap:dictionary]; +} + +- (void)setEntriesToObjects:(NSArray*)object pairedWithKeys:(NSArray*)key { + int i = 0; + while((i < object.count) && (i < key.count)) { + self[key[i]] = object[i]; + i++; + } +} + +- (void)setEntriesToMap:(MobilyMap*)map { + for(id key in map.allKeys) { + self[key] = map[key]; + } +} + +#pragma mark Filtering + +- (NSArray*)keysForSortedObjects:(NSArray*)tempObj { + NSMutableArray* tempKey = [[NSMutableArray alloc] init]; + NSMutableArray* testObj = [[NSMutableArray alloc] initWithArray:_objects]; + NSMutableArray* testKey = [[NSMutableArray alloc] initWithArray:_keys]; + while((testObj.count > 0) && (tempObj.count > 0)) { + NSInteger index = [testObj indexOfObjectIdenticalTo:tempObj[(tempObj.count - testObj.count)]]; + [tempKey addObject:testKey[index]]; + [testKey removeObjectAtIndex:index]; + [testObj removeObjectAtIndex:index]; + } + return tempKey; +} + +- (NSArray*)objectsForSortedKeys:(NSArray*)tempKey { + NSMutableArray* tempObj = [[NSMutableArray alloc] init]; + for(id key in tempKey) { + [tempObj addObject:_pairs[key]]; + } + return tempObj; +} + +- (void)filterEntriesUsingPredicateForObjects:(NSPredicate*)predicate { + NSArray* tempObj = [_objects filteredArrayUsingPredicate:predicate]; + NSArray* tempKey = [self keysForSortedObjects:tempObj]; + [_pairs removeAllObjects]; + _objects = [tempObj mutableCopy]; + _keys = [tempKey mutableCopy]; + for(int i = 0; i < _keys.count; i++) { + _pairs[_keys[i]] = _objects[i]; + } +} + +#pragma mark Sorting + +- (void)exchangeEntryAtIndex:(NSUInteger)idx1 withEntryAtIndex:(NSUInteger)idx2 { + [_keys exchangeObjectAtIndex:idx1 withObjectAtIndex:idx2]; + [_objects exchangeObjectAtIndex:idx1 withObjectAtIndex:idx2]; +} + +- (void)sortEntriesByObjectUsingDescriptors:(NSArray*)descriptors { + NSArray* tempObj = [_objects sortedArrayUsingDescriptors:descriptors]; + NSArray* tempKey = [self keysForSortedObjects:tempObj]; + _keys = [tempKey mutableCopy]; + _objects = [tempObj mutableCopy]; +} + +- (void)sortEntriesByKeysUsingDescriptors:(NSArray*)descriptors { + NSArray* tempKey = [_keys sortedArrayUsingDescriptors:descriptors]; + NSArray* tempObj = [self objectsForSortedKeys:tempKey]; + _keys = [tempKey mutableCopy]; + _objects = [tempObj mutableCopy]; +} + +- (void)sortEntriesByObjectUsingComparator:(NSComparator)cmptr { + NSArray* tempObj = [_objects sortedArrayUsingComparator:cmptr]; + NSArray* tempKey = [self keysForSortedObjects:tempObj]; + _keys = [tempKey mutableCopy]; + _objects = [tempObj mutableCopy]; +} + +- (void)sortEntriesByKeysUsingComparator:(NSComparator)cmptr { + NSArray* tempKey = [_keys sortedArrayUsingComparator:cmptr]; + NSArray* tempObj = [self objectsForSortedKeys:tempKey]; + _keys = [tempKey mutableCopy]; + _objects = [tempObj mutableCopy]; +} + +- (void)sortEntriesByObjectWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr { + NSArray* tempObj = [_objects sortedArrayWithOptions:opts usingComparator:cmptr]; + NSArray* tempKey = [self keysForSortedObjects:tempObj]; + _keys = [tempKey mutableCopy]; + _objects = [tempObj mutableCopy]; +} + +- (void)sortEntriesByKeysWithOptions:(NSSortOptions)opts usingComparator:(NSComparator)cmptr { + NSArray* tempKey = [_keys sortedArrayWithOptions:opts usingComparator:cmptr]; + NSArray* tempObj = [self objectsForSortedKeys:tempKey]; + _keys = [tempKey mutableCopy]; + _objects = [tempObj mutableCopy]; +} + +- (void)sortEntriesByObjectUsingFunction:(NSInteger(*)(__strong id, __strong id, void*))compare context:(void*)context { + NSArray* tempObj = [_objects sortedArrayUsingFunction:compare context:context]; + NSArray* tempKey = [self keysForSortedObjects:tempObj]; + _keys = [tempKey mutableCopy]; + _objects = [tempObj mutableCopy]; +} + +- (void)sortEntriesByKeysUsingFunction:(NSInteger(*)(__strong id, __strong id, void*))compare context:(void*)context { + NSArray* tempKey = [_keys sortedArrayUsingFunction:compare context:context]; + NSArray* tempObj = [self objectsForSortedKeys:tempKey]; + _keys = [tempKey mutableCopy]; + _objects = [tempObj mutableCopy]; +} + +- (void)sortEntriesByObjectUsingSelector:(SEL)comparator { + NSArray* tempObj = [_objects sortedArrayUsingSelector:comparator]; + NSArray* tempKey = [self keysForSortedObjects:tempObj]; + _keys = [tempKey mutableCopy]; + _objects = [tempObj mutableCopy]; +} + +- (void)sortEntriesByKeysUsingSelector:(SEL)comparator { + NSArray* tempKey = [_keys sortedArrayUsingSelector:comparator]; + NSArray* tempObj = [self objectsForSortedKeys:tempKey]; + _keys = [tempKey mutableCopy]; + _objects = [tempObj mutableCopy]; +} + +#pragma mark Indexed Subscripts + +- (void)setObject:(id)obj forKeyedSubscript:(id< NSCopying >)key { + [self setObject:obj forKey:key]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyModel+Private.h b/Sources/MobilyCore/MobilyModel+Private.h new file mode 100644 index 0000000..0e0ad75 --- /dev/null +++ b/Sources/MobilyCore/MobilyModel+Private.h @@ -0,0 +1,103 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyModel () { + NSString* _userDefaultsKey; + NSString* _fileName; + NSString* _filePath; + __weak NSArray* compareMap; + __weak NSArray* serializeMap; + __weak NSArray* copyMap; + __weak NSDictionary* jsonMap; +} + +@property(nonatomic, readonly, weak) NSArray* compareMap; +@property(nonatomic, readonly, weak) NSArray* serializeMap; +@property(nonatomic, readonly, weak) NSArray* copyMap; +@property(nonatomic, readonly, weak) NSDictionary* jsonMap; + ++ (NSArray*)_arrayMap:(NSMutableDictionary*)cache class:(Class)class selector:(SEL)selector; ++ (NSDictionary*)_dictionaryMap:(NSMutableDictionary*)cache class:(Class)class selector:(SEL)selector; ++ (NSArray*)_buildCompareMap; ++ (NSArray*)_buildSerializeMap; ++ (NSArray*)_buildCopyMap; ++ (NSDictionary*)_buildJsonMap; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyModelCollection () { + NSString* _userDefaultsKey; + NSString* _fileName; + NSString* _filePath; + NSMutableArray* _models; + BOOL _needLoad; +} + +- (NSMutableArray*)_mutableModels; +- (void)_loadIsNeed; +- (void)_load; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyModelQuery () { + __weak MobilyModelCollection* _collection; + __weak id< MobilyModelQueryDelegate > _delegate; + MobilyModelQueryReloadBlock _reloadBlock; + MobilyModelQueryResortBlock _resortBlock; + BOOL _resortInvert; + NSMutableArray* _models; + BOOL _needReload; + BOOL _needResort; +} + +- (void)_reload; +- (void)_resort; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyModel.h b/Sources/MobilyCore/MobilyModel.h new file mode 100644 index 0000000..e1af04a --- /dev/null +++ b/Sources/MobilyCore/MobilyModel.h @@ -0,0 +1,177 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef void (^MobilyModelBlock)(); + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyModel : NSObject < MobilyObject, NSCopying > + +@property(nonatomic, readwrite, strong) NSString* userDefaultsKey; +@property(nonatomic, readwrite, strong) NSString* fileName; +@property(nonatomic, readonly, strong) NSString* filePath; + +- (instancetype)initWithUserDefaultsKey:(NSString*)userDefaultsKey; +- (instancetype)initWithFileName:(NSString*)fileName; +- (instancetype)initWithJson:(id)json; + +- (void)setup NS_REQUIRES_SUPER; + ++ (NSArray*)compareMap; ++ (NSArray*)serializeMap; ++ (NSArray*)copyMap; ++ (NSDictionary*)jsonMap; + +- (void)fromJson:(id)json; + +- (void)clear; +- (void)clearComplete:(MobilyModelBlock)complete; + +- (BOOL)save; +- (void)saveSuccess:(MobilyModelBlock)success failure:(MobilyModelBlock)failure; + +- (void)load; +- (void)loadComplete:(MobilyModelBlock)complete; + +- (void)erase; +- (void)eraseComplete:(MobilyModelBlock)complete; + +@end + +/*--------------------------------------------------*/ + +typedef void (^MobilyModelCollectionEnumBlock)(id item, BOOL* stop); + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyModelCollection : NSObject < MobilyObject, NSCopying > + +@property(nonatomic, readwrite, strong) NSString* userDefaultsKey; +@property(nonatomic, readwrite, strong) NSString* fileName; +@property(nonatomic, readonly, strong) NSString* filePath; +@property(nonatomic, readwrite, copy) NSArray* models; + +- (instancetype)initWithUserDefaultsKey:(NSString*)userDefaultsKey; +- (instancetype)initWithFileName:(NSString*)fileName; +- (instancetype)initWithJson:(id)json storageItemClass:(Class)storageItemClass; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)fromJson:(id)json modelClass:(Class)storageItemClass; + +- (NSUInteger)count; + +- (id)modelAtIndex:(NSUInteger)index; + +- (id)firstModel; +- (id)lastModel; + +- (void)prependModel:(MobilyModel*)item; +- (void)prependModelsFromArray:(NSArray*)items; + +- (void)appendModel:(MobilyModel*)item; +- (void)appendModelsFromArray:(NSArray*)items; + +- (void)insertModel:(MobilyModel*)item atIndex:(NSUInteger)index; +- (void)insertModelsFromArray:(NSArray*)items atIndex:(NSUInteger)index; + +- (void)removeModel:(MobilyModel*)item; +- (void)removeModelsInArray:(NSArray*)items; +- (void)removeAllModels; + +- (void)enumirateModelsUsingBlock:(MobilyModelCollectionEnumBlock)block; + +- (BOOL)save; + +@end + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSInteger, MobilyModelQuerySortResult) { + MobilyModelQuerySortResultMore = NSOrderedAscending, + MobilyModelQuerySortResultEqual = NSOrderedSame, + MobilyModelQuerySortResultLess = NSOrderedDescending +}; + +/*--------------------------------------------------*/ + +@protocol MobilyModelQueryDelegate; + +/*--------------------------------------------------*/ + +typedef BOOL (^MobilyModelQueryReloadBlock)(id item); +typedef MobilyModelQuerySortResult (^MobilyModelQueryResortBlock)(id item1, id item2); + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyModelQuery : NSObject < MobilyObject > + +@property(nonatomic, readwrite, weak) id< MobilyModelQueryDelegate > delegate; +@property(nonatomic, readwrite, copy) MobilyModelQueryReloadBlock reloadBlock; +@property(nonatomic, readwrite, copy) MobilyModelQueryResortBlock resortBlock; +@property(nonatomic, readwrite, assign) BOOL resortInvert; +@property(nonatomic, readonly, strong) NSArray* models; + +- (instancetype)initWithCollection:(MobilyModelCollection*)collection; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)setNeedReload; +- (void)setNeedResort; + +- (NSUInteger)count; + +- (id)modelAtIndex:(NSUInteger)index; + +@end + +/*--------------------------------------------------*/ + +@protocol MobilyModelQueryDelegate < NSObject > + +@optional +- (BOOL)modelQuery:(MobilyModelQuery*)modelQuery reloadItem:(id)item; +- (MobilyModelQuerySortResult)modelQuery:(MobilyModelQuery*)modelQuery resortItem1:(id)item1 item2:(id)item2; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyModel.m b/Sources/MobilyCore/MobilyModel.m new file mode 100644 index 0000000..6c6fc94 --- /dev/null +++ b/Sources/MobilyCore/MobilyModel.m @@ -0,0 +1,911 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#define MOBILY_MODEL_EXTENSION @"model" + +/*--------------------------------------------------*/ + +@implementation MobilyModel + +#pragma mark Synthesize + +@synthesize userDefaultsKey = _userDefaultsKey; +@synthesize fileName = _fileName; +@synthesize filePath = _filePath; +@synthesize compareMap = _compareMap; +@synthesize serializeMap = _serializeMap; +@synthesize copyMap = _copyMap; +@synthesize jsonMap = _jsonMap; + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super init]; + if(self != nil) { + for(NSString* field in self.serializeMap) { + id value = [coder decodeObjectForKey:field]; + if(value != nil) { + [self setValue:value forKey:field]; + } + } + [self setup]; + } + return self; +} + +- (instancetype)initWithFileName:(NSString*)fileName { + self = [super init]; + if(self != nil) { + self.fileName = fileName; + [self load]; + [self setup]; + } + return self; +} + +- (instancetype)initWithJson:(id)json { + self = [super init]; + if(self != nil) { + [self fromJson:json]; + [self setup]; + } + return self; +} + +- (instancetype)initWithUserDefaultsKey:(NSString*)userDefaultsKey { + self = [super init]; + if(self != nil) { + _userDefaultsKey = userDefaultsKey; + [self load]; + [self setup]; + } + return self; +} + +- (void)setup { +} + +#pragma mark NSObject + +- (BOOL)isEqual:(id)object { + BOOL result = NO; + if([object isKindOfClass:self.class] == YES) { + NSArray* map = self.compareMap; + if(map.count < 1) { + map = self.serializeMap; + } + if(map.count > 0) { + result = YES; + for(NSString* field in map) { + id value1 = [self valueForKey:field]; + id value2 = [object valueForKey:field]; + if(value1 != value2) { + if([value1 isEqual:value2] == NO) { + result = NO; + break; + } + } + } + } + } else { + result = [super isEqual:object]; + } + return result; +} + +#pragma mark NSCoding + +- (void)encodeWithCoder:(NSCoder*)coder { + for(NSString* field in self.serializeMap) { + id value = [self valueForKey:field]; + if(value != nil) { + [coder encodeObject:value forKey:field]; + } + } +} + +#pragma mark NSCopying + +- (id)copyWithZone:(NSZone*)zone { + MobilyModel* result = [[self.class allocWithZone:zone] init]; + if(result != nil) { + result.userDefaultsKey = _userDefaultsKey; + result.fileName = _fileName; + NSArray* map = self.copyMap; + if(map.count < 1) { + map = self.serializeMap; + } + for(NSString* field in map) { + id value = [self valueForKey:field]; + if([value isKindOfClass:NSArray.class] == YES) { + NSMutableArray* array = [NSMutableArray arrayWithCapacity:[value count]]; + for(id item in value) { + [array addObject:[item copyWithZone:zone]]; + } + [result setValue:array forKey:field]; + } else if([value isKindOfClass:NSDictionary.class] == YES) { + NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:[value count]]; + [value moEach:^(id key, id item) { + dict[key] = [item copyWithZone:zone]; + }]; + [result setValue:dict forKey:field]; + } else { + [result setValue:[value copyWithZone:zone] forKey:field]; + } + } + } + return result; +} + +#pragma mark Debug + +- (NSString*)description { + NSMutableArray* result = NSMutableArray.array; + for(NSString* field in self.serializeMap) { + [result addObject:[NSString stringWithFormat:@"%@ = %@", field, [self valueForKey:field]]]; + } + return [result componentsJoinedByString:@"; "]; +} + +#pragma mark Property + +- (void)setFileName:(NSString*)fileName { + if(_fileName != fileName) { + _fileName = fileName; + if(_fileName != nil) { + _filePath = [MobilyStorage.moFileSystemDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", _fileName, MOBILY_MODEL_EXTENSION]]; + } else { + _filePath = nil; + } + } +} + +- (NSArray*)compareMap { + if(_compareMap == nil) { + _compareMap = [self.class _buildCompareMap]; + } + return _compareMap; +} + +- (NSArray*)serializeMap { + if(_serializeMap == nil) { + _serializeMap = [self.class _buildSerializeMap]; + } + return _serializeMap; +} + +- (NSArray*)copyMap { + if(_copyMap == nil) { + _copyMap = [self.class _buildCopyMap]; + } + return _copyMap; +} + +- (NSDictionary*)jsonMap { + if(_jsonMap == nil) { + _jsonMap = [self.class _buildJsonMap]; + } + return _jsonMap; +} + +#pragma mark Public + ++ (NSArray*)compareMap { + return nil; +} + ++ (NSArray*)serializeMap { + return nil; +} + ++ (NSArray*)copyMap { + return nil; +} + ++ (NSDictionary*)jsonMap { + return nil; +} + +- (void)fromJson:(id)json { + [self.jsonMap enumerateKeysAndObjectsUsingBlock:^(NSString* field, MobilyModelJson* converter, BOOL* stop __unused) { + id value = [converter parseJson:json]; + if(value != nil) { + [self setValue:value forKey:field]; + } + }]; +} + +- (void)clear { + for(NSString* field in self.serializeMap) { + @try { + [self setValue:nil forKey:field]; + } + @catch(NSException *exception) { + } + } +} + +- (void)clearComplete:(MobilyModelBlock)complete { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + [self clear]; + if(complete != nil) { + dispatch_sync(dispatch_get_main_queue(), ^{ + complete(); + }); + } + }); +} + +- (BOOL)save { + @try { + NSMutableDictionary* dict = NSMutableDictionary.dictionary; + if(dict != nil) { + for(NSString* field in self.serializeMap) { + @try { + id value = [self valueForKey:field]; + if(value != nil) { + NSData* archive = [NSKeyedArchiver archivedDataWithRootObject:value]; + if(archive != nil) { + dict[field] = archive; + } + } + } + @catch (NSException* exception) { + NSLog(@"MobilyModel::saveItem:%@ Exception = %@ Field=%@", _userDefaultsKey, exception, field); + } + } + if(_userDefaultsKey.length > 0) { + [NSUserDefaults.standardUserDefaults setObject:dict forKey:_userDefaultsKey]; + return [NSUserDefaults.standardUserDefaults synchronize]; + } else if(_filePath.length > 0) { + return [NSKeyedArchiver archiveRootObject:dict toFile:_filePath]; + } + } + } + @catch(NSException* exception) { + NSLog(@"MobilyModel::saveItem:%@ Exception = %@", _userDefaultsKey, exception); + } + return NO; +} + +- (void)saveSuccess:(MobilyModelBlock)success failure:(MobilyModelBlock)failure { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + if([self save] == YES) { + if(success != nil) { + dispatch_sync(dispatch_get_main_queue(), ^{ + success(); + }); + } + } else { + if(failure != nil) { + dispatch_sync(dispatch_get_main_queue(), ^{ + failure(); + }); + } + } + }); +} + +- (void)load { + @try { + NSDictionary* dict = nil; + if(_userDefaultsKey.length > 0) { + dict = [NSUserDefaults.standardUserDefaults objectForKey:_userDefaultsKey]; + } else if(_filePath.length > 0) { + dict = [NSKeyedUnarchiver unarchiveObjectWithFile:_filePath]; + } + if(dict != nil) { + for(NSString* field in self.serializeMap) { + id value = dict[field]; + if(value != nil) { + if([value isKindOfClass:NSData.class] == YES) { + id unarchive = [NSKeyedUnarchiver unarchiveObjectWithData:value]; + if(unarchive != nil) { + @try { + [self setValue:unarchive forKey:field]; + } + @catch(NSException *exception) { + } + } + } + } + } + } + } + @catch(NSException* exception) { + NSLog(@"MobilyModel::loadItem:%@ Exception = %@", _userDefaultsKey, exception); + } +} + +- (void)loadComplete:(MobilyModelBlock)complete { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + [self load]; + if(complete != nil) { + dispatch_sync(dispatch_get_main_queue(), ^{ + complete(); + }); + } + }); +} + +- (void)erase { + NSDictionary* dict = [NSUserDefaults.standardUserDefaults objectForKey:_userDefaultsKey]; + if(dict != nil) { + [NSUserDefaults.standardUserDefaults removeObjectForKey:_userDefaultsKey]; + [NSUserDefaults.standardUserDefaults synchronize]; + } +} + +- (void)eraseComplete:(MobilyModelBlock)complete { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + [self erase]; + if(complete != nil) { + dispatch_sync(dispatch_get_main_queue(), ^{ + complete(); + }); + } + }); +} + +#pragma mark Private + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + ++ (NSArray*)_arrayMap:(NSMutableDictionary*)cache class:(Class)class selector:(SEL)selector { + NSString* className = NSStringFromClass(class); + NSMutableArray* map = cache[className]; + if(map == nil) { + map = NSMutableArray.array; + while(class != nil) { + if([class respondsToSelector:selector] == YES) { + NSArray* mapPart = [class performSelector:selector]; + if([mapPart isKindOfClass:NSArray.class] == YES) { + [map addObjectsFromArray:mapPart]; + } + } + class = [class superclass]; + } + cache[className] = map; + } + return map; +} + ++ (NSDictionary*)_dictionaryMap:(NSMutableDictionary*)cache class:(Class)class selector:(SEL)selector { + NSString* className = NSStringFromClass(class); + NSMutableDictionary* map = cache[className]; + if(map == nil) { + map = NSMutableDictionary.dictionary; + while(class != nil) { + if([class respondsToSelector:selector] == YES) { + NSDictionary* mapPart = [class performSelector:selector]; + if([mapPart isKindOfClass:NSDictionary.class] == YES) { + [map addEntriesFromDictionary:mapPart]; + } + } + class = [class superclass]; + } + cache[className] = map; + } + return map; +} + +#pragma clang diagnostic pop + ++ (NSArray*)_buildCompareMap { + static NSMutableDictionary* cache = nil; + if(cache == nil) { + cache = NSMutableDictionary.dictionary; + } + return [self _arrayMap:cache class:self.class selector:@selector(compareMap)]; +} + ++ (NSArray*)_buildSerializeMap { + static NSMutableDictionary* cache = nil; + if(cache == nil) { + cache = NSMutableDictionary.dictionary; + } + return [self _arrayMap:cache class:self.class selector:@selector(serializeMap)]; +} + ++ (NSArray*)_buildCopyMap { + static NSMutableDictionary* cache = nil; + if(cache == nil) { + cache = NSMutableDictionary.dictionary; + } + return [self _arrayMap:cache class:self.class selector:@selector(copyMap)]; +} + ++ (NSDictionary*)_buildJsonMap { + static NSMutableDictionary* cache = nil; + if(cache == nil) { + cache = NSMutableDictionary.dictionary; + } + return [self _dictionaryMap:cache class:self.class selector:@selector(jsonMap)]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#define MOBILY_STORAGE_COLLECTION_EXTENSION @"collection" + +/*--------------------------------------------------*/ + +@implementation MobilyModelCollection + +#pragma mark Synthesize + +@synthesize userDefaultsKey = _userDefaultsKey; +@synthesize fileName = _fileName; +@synthesize filePath = _filePath; +@synthesize models = _models; + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + _models = NSMutableArray.array; + _needLoad = NO; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super init]; + if(self != nil) { + id models = [coder decodeObjectForKey:@"models"]; + if(models != nil) { + _models = models; + } else { + _models = NSMutableArray.array; + } + _needLoad = NO; + [self setup]; + } + return self; +} + +- (instancetype)initWithUserDefaultsKey:(NSString*)userDefaultsKey { + self = [super init]; + if(self != nil) { + _userDefaultsKey = userDefaultsKey; + _models = NSMutableArray.array; + _needLoad = YES; + [self setup]; + } + return self; +} + +- (instancetype)initWithFileName:(NSString*)fileName { + self = [super init]; + if(self != nil) { + self.fileName = fileName; + _models = NSMutableArray.array; + _needLoad = YES; + [self setup]; + } + return self; +} + +- (instancetype)initWithJson:(id)json storageItemClass:(Class)storageItemClass { + self = [super init]; + if(self != nil) { + _models = NSMutableArray.array; + _needLoad = NO; + [self fromJson:json modelClass:storageItemClass]; + [self setup]; + } + return self; +} + +- (void)setup { +} + +#pragma mark NSCoding + +- (void)encodeWithCoder:(NSCoder*)coder { + [self _loadIsNeed]; + [coder encodeObject:_models forKey:@"models"]; +} + +#pragma mark NSCopying + +- (id)copyWithZone:(NSZone*)zone { + MobilyModelCollection* result = [[self.class allocWithZone:zone] init]; + if(result != nil) { + result.userDefaultsKey = self.userDefaultsKey; + result.fileName = _fileName; + result.models = [_models copyWithZone:zone]; + } + return result; +} + +#pragma mark Property + +- (void)setFileName:(NSString*)fileName { + if(_fileName != fileName) { + _fileName = fileName; + if(_fileName != nil) { + _filePath = [MobilyStorage.moFileSystemDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.%@", _fileName, MOBILY_STORAGE_COLLECTION_EXTENSION]]; + } else { + _filePath = nil; + } + } +} + +- (void)setUserDefaultsKey:(NSString*)userDefaultsKey { + if(_userDefaultsKey != userDefaultsKey) { + _userDefaultsKey = userDefaultsKey; + } +} + +- (void)setModels:(NSArray*)items { + _needLoad = NO; + _models.array = items; +} + +- (NSArray*)models { + [self _loadIsNeed]; + return [_models copy]; +} + +#pragma mark Public + +- (void)fromJson:(id)json modelClass:(Class)storageItemClass { + [_models removeAllObjects]; + if([storageItemClass isSubclassOfClass:MobilyModel.class] == YES) { + if([json isKindOfClass:NSArray.class] == YES) { + for(id jsonItem in json) { + id item = [[storageItemClass alloc] initWithJson:jsonItem]; + if(item != nil) { + [_models addObject:item]; + } + } + } + } +} + +- (NSUInteger)count { + [self _loadIsNeed]; + return _models.count; +} + +- (id)modelAtIndex:(NSUInteger)index { + [self _loadIsNeed]; + return _models[index]; +} + +- (id)firstModel { + [self _loadIsNeed]; + if(_models.count > 0) { + return _models[0]; + } + return nil; +} + +- (id)lastModel { + return [_models lastObject]; +} + +- (void)prependModel:(MobilyModel*)item { + [self _loadIsNeed]; + [_models insertObject:item atIndex:0]; +} + +- (void)prependModelsFromArray:(NSArray*)items { + [self _loadIsNeed]; + [_models insertObjects:items atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, items.count)]]; +} + +- (void)appendModel:(MobilyModel*)item { + [self _loadIsNeed]; + [_models addObject:item]; +} + +- (void)appendModelsFromArray:(NSArray*)items { + [self _loadIsNeed]; + [_models addObjectsFromArray:items]; +} + +- (void)insertModel:(MobilyModel*)item atIndex:(NSUInteger)index { + [self _loadIsNeed]; + [_models insertObject:item atIndex:index]; +} + +- (void)insertModelsFromArray:(NSArray*)items atIndex:(NSUInteger)index { + [self _loadIsNeed]; + [_models insertObjects:items atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(index, items.count)]]; +} + +- (void)removeModel:(MobilyModel*)item { + [self _loadIsNeed]; + [_models removeObject:item]; +} + +- (void)removeModelsInArray:(NSArray*)items { + [self _loadIsNeed]; + [_models removeObjectsInArray:items]; +} + +- (void)removeAllModels { + [self _loadIsNeed]; + [_models removeAllObjects]; +} + +- (void)enumirateModelsUsingBlock:(MobilyModelCollectionEnumBlock)block { + [self _loadIsNeed]; + [_models enumerateObjectsUsingBlock:^(id item, NSUInteger index __unused, BOOL* stop) { + block(item, stop); + }]; +} + +- (BOOL)save { + @try { + if(_needLoad == NO) { + if(_userDefaultsKey.length > 0) { + @try { + NSData* data = [NSKeyedArchiver archivedDataWithRootObject:_models]; + [NSUserDefaults.standardUserDefaults setObject:data forKey:_userDefaultsKey]; + } + @catch(NSException* exception) { +#if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) + NSLog(@"ERROR: [%@:%@]: Exception = %@", self.class, NSStringFromSelector(_cmd), exception); +#endif + [_models removeAllObjects]; + } + } else if(_filePath.length > 0) { + return [NSKeyedArchiver archiveRootObject:_models toFile:_filePath]; + } + } + } + @catch(NSException* exception) { +#if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) + NSLog(@"ERROR: [%@:%@]: Exception = %@", self.class, NSStringFromSelector(_cmd), exception); +#endif + } + return NO; +} + +#pragma mark Private + +- (NSMutableArray*)_mutableModels { + [self _loadIsNeed]; + return _models; +} + +- (void)_loadIsNeed { + if(_needLoad == YES) { + [self _load]; + _needLoad = NO; + } +} + +- (void)_load { + @try { + if(_userDefaultsKey.length > 0) { + NSData* data = [NSUserDefaults.standardUserDefaults objectForKey:_userDefaultsKey]; + if([data isKindOfClass:NSData.class] == YES) { + id items = [NSKeyedUnarchiver unarchiveObjectWithData:data]; + if([items isKindOfClass:NSArray.class] == YES) { + _models.array = items; + } else { + [_models removeAllObjects]; + } + } + } else if(_filePath.length > 0) { + id items = [NSKeyedUnarchiver unarchiveObjectWithFile:_filePath]; + if([items isKindOfClass:NSArray.class] == YES) { + _models.array = items; + } else { + [_models removeAllObjects]; + } + } + } + @catch(NSException* exception) { +#if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) + NSLog(@"ERROR: [%@:%@]: Exception = %@", self.class, NSStringFromSelector(_cmd), exception); +#endif + [_models removeAllObjects]; + } +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyModelQuery + +#pragma mark Synthesize + +@synthesize delegate = _delegate; +@synthesize reloadBlock = _reloadBlock; +@synthesize resortBlock = _resortBlock; +@synthesize resortInvert = _resortInvert; +@synthesize models = _models; + +#pragma mark Init / Free + +- (instancetype)initWithCollection:(MobilyModelCollection*)collection { + self = [super init]; + if(self != nil) { + _collection = collection; + [self setup]; + } + return self; +} + +- (void)setup { + _models = NSMutableArray.array; + _needReload = YES; + _needResort = YES; +} + +#pragma mark Public + +- (void)setNeedReload { + _needReload = YES; + _needResort = YES; +} + +- (void)setNeedResort { + _needResort = YES; +} + +- (NSUInteger)count { + return self.models.count; +} + +- (id)modelAtIndex:(NSUInteger)index { + return self.models[index]; +} + +- (NSArray*)models { + if(_needReload == YES) { + [self _reload]; + _needReload = NO; + } + if(_needResort == YES) { + [self _resort]; + _needResort = NO; + } + return _models; +} + +#pragma mark Property + +- (void)setReloadBlock:(MobilyModelQueryReloadBlock)reloadBlock { + if(_reloadBlock != reloadBlock) { + _reloadBlock = [reloadBlock copy]; + _needReload = YES; + _needResort = YES; + } +} + +- (void)setResortBlock:(MobilyModelQueryResortBlock)resortBlock { + if(_resortBlock != resortBlock) { + _resortBlock = [resortBlock copy]; + _needResort = YES; + } +} + +- (void)setResortInvert:(BOOL)resortInvert { + if(_resortInvert != resortInvert) { + _resortInvert = resortInvert; + _needResort = YES; + } +} + +#pragma mark Private + +- (void)_reload { + NSArray* collectionModels = [_collection _mutableModels]; + if([_delegate respondsToSelector:@selector(modelQuery:reloadItem:)] == YES) { + [_models removeAllObjects]; + for(id item in collectionModels) { + if([_delegate modelQuery:self reloadItem:item] == YES) { + [_models addObject:item]; + } + } + } else if(_reloadBlock != nil) { + [_models removeAllObjects]; + for(id item in collectionModels) { + if(_reloadBlock(item) == YES) { + [_models addObject:item]; + } + } + } else { + _models.array = collectionModels; + } +} + +- (void)_resort { + if(_resortInvert == YES) { + if([_delegate respondsToSelector:@selector(modelQuery:resortItem1:item2:)] == YES) { + [_models sortUsingComparator:^NSComparisonResult(id item1, id item2) { + switch(_resortBlock(item1, item2)) { + case MobilyModelQuerySortResultMore: return NSOrderedDescending; + case MobilyModelQuerySortResultLess: return NSOrderedAscending; + default: break; + } + return NSOrderedSame; + }]; + } else if(_resortBlock != nil) { + [_models sortUsingComparator:^NSComparisonResult(id item1, id item2) { + switch([_delegate modelQuery:self resortItem1:item1 item2:item2]) { + case MobilyModelQuerySortResultMore: return NSOrderedDescending; + case MobilyModelQuerySortResultLess: return NSOrderedAscending; + default: break; + } + return NSOrderedSame; + }]; + } + } else { + if([_delegate respondsToSelector:@selector(modelQuery:resortItem1:item2:)] == YES) { + [_models sortUsingComparator:^NSComparisonResult(id item1, id item2) { + return (NSComparisonResult)_resortBlock(item1, item2); + }]; + } else if(_resortBlock != nil) { + [_models sortUsingComparator:^NSComparisonResult(id item1, id item2) { + return (NSComparisonResult)[_delegate modelQuery:self resortItem1:item1 item2:item2]; + }]; + } + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyModelJson.h b/Sources/MobilyCore/MobilyModelJson.h new file mode 100644 index 0000000..766981f --- /dev/null +++ b/Sources/MobilyCore/MobilyModelJson.h @@ -0,0 +1,258 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef id (^MobilyModelJsonUndefinedBehaviour)(id modelJson, id value); + +/*--------------------------------------------------*/ + +@interface MobilyModelJson : NSObject < MobilyObject > + +@property(nonatomic, readonly, strong) NSString* path; + +- (instancetype)initWithPath:(NSString*)path; +- (instancetype)initWithUndefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; + +- (void)setup NS_REQUIRES_SUPER; + +- (id)parseJson:(id)json; + +- (id)convertValue:(id)value; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyModelJsonArray : MobilyModelJson + +@property(nonatomic, readonly, strong) MobilyModelJson* jsonConverter; + +- (instancetype)initWithJsonModelClass:(Class)jsonModelClass; +- (instancetype)initWithJsonModelClass:(Class)jsonModelClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithJsonConverter:(MobilyModelJson*)jsonConverter; +- (instancetype)initWithJsonConverter:(MobilyModelJson*)jsonConverter undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path jsonModelClass:(Class)jsonModelClass; +- (instancetype)initWithPath:(NSString*)path jsonModelClass:(Class)jsonModelClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path jsonConverter:(MobilyModelJson*)jsonConverter; +- (instancetype)initWithPath:(NSString*)path jsonConverter:(MobilyModelJson*)jsonConverter undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyModelJsonDictionary : MobilyModelJson + +@property(nonatomic, readonly, strong) MobilyModelJson* keyJsonConverter; +@property(nonatomic, readonly, strong) MobilyModelJson* valueJsonConverter; + +- (instancetype)initWithValueJsonModelClass:(Class)valueJsonModelClass; +- (instancetype)initWithValueJsonModelClass:(Class)valueJsonModelClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithValueJsonConverter:(MobilyModelJson*)valueJsonConverter; +- (instancetype)initWithValueJsonConverter:(MobilyModelJson*)valueJsonConverter undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithKeyJsonModelClass:(Class)keyJsonModelClass valueJsonModelClass:(Class)valueJsonModelClass; +- (instancetype)initWithKeyJsonModelClass:(Class)keyJsonModelClass valueJsonModelClass:(Class)valueJsonModelClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithKeyJsonConverter:(MobilyModelJson*)keyJsonConverter valueJsonConverter:(MobilyModelJson*)valueJsonConverter; +- (instancetype)initWithKeyJsonConverter:(MobilyModelJson*)keyJsonConverter valueJsonConverter:(MobilyModelJson*)valueJsonConverter undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path valueJsonModelClass:(Class)valueJsonModelClass; +- (instancetype)initWithPath:(NSString*)path valueJsonModelClass:(Class)valueJsonModelClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path valueJsonConverter:(MobilyModelJson*)valueJsonConverter; +- (instancetype)initWithPath:(NSString*)path valueJsonConverter:(MobilyModelJson*)valueJsonConverter undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path keyJsonModelClass:(Class)keyJsonModelClass valueJsonModelClass:(Class)valueJsonModelClass; +- (instancetype)initWithPath:(NSString*)path keyJsonModelClass:(Class)keyJsonModelClass valueJsonModelClass:(Class)valueJsonModelClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path keyJsonConverter:(MobilyModelJson*)keyJsonConverter valueJsonConverter:(MobilyModelJson*)valueJsonConverter; +- (instancetype)initWithPath:(NSString*)path keyJsonConverter:(MobilyModelJson*)keyJsonConverter valueJsonConverter:(MobilyModelJson*)valueJsonConverter undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyModelJsonBool : MobilyModelJson + +@property(nonatomic, readonly, assign) BOOL defaultValue; + +- (instancetype)initWithPath:(NSString*)path defaultValue:(BOOL)defaultValue; +- (instancetype)initWithPath:(NSString*)path defaultValue:(BOOL)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyModelJsonString : MobilyModelJson + +@property(nonatomic, readonly, strong) NSString* defaultValue; + +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSString*)defaultValue; +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSString*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyModelJsonUrl : MobilyModelJson + +@property(nonatomic, readonly, strong) NSURL* defaultValue; + +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSURL*)defaultValue; +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSURL*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyModelJsonNumber : MobilyModelJson + +@property(nonatomic, readonly, strong) NSNumber* defaultValue; + +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSNumber*)defaultValue; +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSNumber*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyModelJsonDate : MobilyModelJson + +@property(nonatomic, readonly, strong) NSDate* defaultValue; +@property(nonatomic, readonly, strong) NSArray* formats; +@property(nonatomic, readonly, strong) NSTimeZone* timeZone; + +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSDate*)defaultValue; +- (instancetype)initWithPath:(NSString*)path timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue; +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithFormat:(NSString*)format; +- (instancetype)initWithFormat:(NSString*)format timeZone:(NSTimeZone*)timeZone; +- (instancetype)initWithFormat:(NSString*)format undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithFormat:(NSString*)format timeZone:(NSTimeZone*)timeZone undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithFormat:(NSString*)format defaultValue:(NSDate*)defaultValue; +- (instancetype)initWithFormat:(NSString*)format timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue; +- (instancetype)initWithFormat:(NSString*)format defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithFormat:(NSString*)format timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format; +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format timeZone:(NSTimeZone*)timeZone; +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format timeZone:(NSTimeZone*)timeZone undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format defaultValue:(NSDate*)defaultValue; +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue; +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithFormats:(NSArray*)formats; +- (instancetype)initWithFormats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone; +- (instancetype)initWithFormats:(NSArray*)formats undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithFormats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithFormats:(NSArray*)formats defaultValue:(NSDate*)defaultValue; +- (instancetype)initWithFormats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue; +- (instancetype)initWithFormats:(NSArray*)formats defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithFormats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats; +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone; +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats defaultValue:(NSDate*)defaultValue; +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue; +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyModelJsonEnum : MobilyModelJson + +@property(nonatomic, readonly, strong) NSNumber* defaultValue; +@property(nonatomic, readonly, strong) NSDictionary* enums; + +- (instancetype)initWithEnums:(NSDictionary*)enums; +- (instancetype)initWithEnums:(NSDictionary*)enums undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithEnums:(NSDictionary*)enums defaultValue:(NSNumber*)defaultValue; +- (instancetype)initWithEnums:(NSDictionary*)enums defaultValue:(NSNumber*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path enums:(NSDictionary*)enums; +- (instancetype)initWithPath:(NSString*)path enums:(NSDictionary*)enums undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path enums:(NSDictionary*)enums defaultValue:(NSNumber*)defaultValue; +- (instancetype)initWithPath:(NSString*)path enums:(NSDictionary*)enums defaultValue:(NSNumber*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyModelJsonLocation : MobilyModelJson + +@property(nonatomic, readonly, strong) CLLocation* defaultValue; + +- (instancetype)initWithPath:(NSString*)path defaultValue:(CLLocation*)defaultValue; +- (instancetype)initWithPath:(NSString*)path defaultValue:(CLLocation*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyModelJsonCustomClass : MobilyModelJson + +@property(nonatomic, readonly, assign) Class customClass; +@property(nonatomic, readonly, assign) BOOL hasAnySource; + +- (instancetype)initWithCustomClass:(Class)customClass; +- (instancetype)initWithCustomClass:(Class)customClass hasAnySource:(BOOL)hasAnySource; +- (instancetype)initWithCustomClass:(Class)customClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithCustomClass:(Class)customClass hasAnySource:(BOOL)hasAnySource undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path customClass:(Class)customClass; +- (instancetype)initWithPath:(NSString*)path customClass:(Class)customClass hasAnySource:(BOOL)hasAnySource; +- (instancetype)initWithPath:(NSString*)path customClass:(Class)customClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path customClass:(Class)customClass hasAnySource:(BOOL)hasAnySource undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; + +@end + +/*--------------------------------------------------*/ + +typedef id (^MobilyModelJsonConvertBlock)(id value); + +/*--------------------------------------------------*/ + +@interface MobilyModelJsonBlock : MobilyModelJson + +@property(nonatomic, readonly, copy) MobilyModelJsonConvertBlock block; + +- (instancetype)initWithBlock:(MobilyModelJsonConvertBlock)block; +- (instancetype)initWithBlock:(MobilyModelJsonConvertBlock)block undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; +- (instancetype)initWithPath:(NSString*)path block:(MobilyModelJsonConvertBlock)block; +- (instancetype)initWithPath:(NSString*)path block:(MobilyModelJsonConvertBlock)block undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyModelJson.m b/Sources/MobilyCore/MobilyModelJson.m new file mode 100644 index 0000000..88ec136 --- /dev/null +++ b/Sources/MobilyCore/MobilyModelJson.m @@ -0,0 +1,1097 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyModelJson () + +@property(nonatomic, readwrite, strong) NSString* path; +@property(nonatomic, readwrite, strong) NSArray* subPaths; +@property(nonatomic, readwrite, copy) MobilyModelJsonUndefinedBehaviour undefinedBehaviour; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyModelJson + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithPath:(NSString*)path { + return [self initWithPath:path + undefinedBehaviour:nil]; +} + +- (instancetype)initWithUndefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil + undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + self = [self init]; + if(self != nil) { + if(path.length > 0) { + self.path = path; + NSMutableArray* subPaths = [NSMutableArray arrayWithArray:[path componentsSeparatedByString:@"|"]]; + [subPaths enumerateObjectsUsingBlock:^(NSString* subPath, NSUInteger index, BOOL* stop __unused) { + subPaths[index] = [subPath componentsSeparatedByString:@"."]; + }]; + self.subPaths = subPaths; + } + self.undefinedBehaviour = undefinedBehaviour; + } + return self; +} + +- (void)setup { +} + +#pragma mark Public + +- (id)parseJson:(id)json { + id value = json; + if([value isKindOfClass:NSDictionary.class] == YES) { + for(NSArray* subPath in _subPaths) { + value = json; + for(NSString* path in subPath) { + if([value isKindOfClass:NSDictionary.class] == YES) { + value = value[path]; + if(value == nil) { + break; + } + } else { + if(path != subPath.lastObject) { + value = nil; + } + break; + } + } + } + } + id result = [self convertValue:value]; + if(result == nil) { + if(_undefinedBehaviour != nil) { + result = _undefinedBehaviour(self, value); + } + } + return result; +} + +#pragma mark MobilyModelJson + +- (id)convertValue:(id)value { + return value; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyModelJsonArray () + +@property(nonatomic, readwrite, strong) MobilyModelJson* jsonConverter; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyModelJsonArray + +#pragma mark Init / Free + +- (instancetype)initWithJsonModelClass:(Class)jsonModelClass { + return [self initWithPath:nil + jsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:jsonModelClass] + undefinedBehaviour:nil]; +} + +- (instancetype)initWithJsonModelClass:(Class)jsonModelClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil + jsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:jsonModelClass] + undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithJsonConverter:(MobilyModelJson*)jsonConverter { + return [self initWithPath:nil + jsonConverter:jsonConverter + undefinedBehaviour:nil]; +} + +- (instancetype)initWithJsonConverter:(MobilyModelJson*)jsonConverter undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil + jsonConverter:jsonConverter + undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path jsonModelClass:(Class)jsonModelClass { + return [self initWithPath:path + jsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:jsonModelClass] + undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path jsonModelClass:(Class)jsonModelClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:path + jsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:jsonModelClass] + undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path jsonConverter:(MobilyModelJson*)jsonConverter { + return [self initWithPath:path + jsonConverter:jsonConverter + undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path jsonConverter:(MobilyModelJson*)jsonConverter undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + self = [super initWithPath:path undefinedBehaviour:undefinedBehaviour]; + if(self != nil) { + self.jsonConverter = jsonConverter; + } + return self; +} + +#pragma mark MobilyModelJson + +- (id)convertValue:(id)value { + if([value isKindOfClass:NSArray.class] == YES) { + NSMutableArray* result = NSMutableArray.array; + if(result != nil) { + for(id object in value) { + id convertedValue = [_jsonConverter convertValue:object]; + if(convertedValue != nil) { + [result addObject:convertedValue]; + } + } + return result; + } + } + return nil; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyModelJsonDictionary () + +@property(nonatomic, readwrite, strong) MobilyModelJson* keyJsonConverter; +@property(nonatomic, readwrite, strong) MobilyModelJson* valueJsonConverter; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyModelJsonDictionary + +#pragma mark Init / Free + +- (instancetype)initWithValueJsonModelClass:(Class)valueJsonModelClass { + return [self initWithPath:nil + keyJsonConverter:nil + valueJsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:valueJsonModelClass] + undefinedBehaviour:nil]; +} + +- (instancetype)initWithValueJsonModelClass:(Class)valueJsonModelClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil + keyJsonConverter:nil + valueJsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:valueJsonModelClass] + undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithValueJsonConverter:(MobilyModelJson*)valueJsonConverter { + return [self initWithPath:nil + keyJsonConverter:nil + valueJsonConverter:valueJsonConverter + undefinedBehaviour:nil]; +} + +- (instancetype)initWithValueJsonConverter:(MobilyModelJson*)valueJsonConverter undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil + keyJsonConverter:nil + valueJsonConverter:valueJsonConverter + undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithKeyJsonModelClass:(Class)keyJsonModelClass valueJsonModelClass:(Class)valueJsonModelClass { + return [self initWithPath:nil + keyJsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:keyJsonModelClass] + valueJsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:valueJsonModelClass] + undefinedBehaviour:nil]; +} + +- (instancetype)initWithKeyJsonModelClass:(Class)keyJsonModelClass valueJsonModelClass:(Class)valueJsonModelClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil + keyJsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:keyJsonModelClass] + valueJsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:valueJsonModelClass] + undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithKeyJsonConverter:(MobilyModelJson*)keyJsonConverter valueJsonConverter:(MobilyModelJson*)valueJsonConverter { + return [self initWithPath:nil + keyJsonConverter:keyJsonConverter + valueJsonConverter:valueJsonConverter + undefinedBehaviour:nil]; +} + +- (instancetype)initWithKeyJsonConverter:(MobilyModelJson*)keyJsonConverter valueJsonConverter:(MobilyModelJson*)valueJsonConverter undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil + keyJsonConverter:keyJsonConverter + valueJsonConverter:valueJsonConverter + undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path valueJsonModelClass:(Class)valueJsonModelClass { + return [self initWithPath:path + keyJsonConverter:nil + valueJsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:valueJsonModelClass] + undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path valueJsonModelClass:(Class)valueJsonModelClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:path + keyJsonConverter:nil + valueJsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:valueJsonModelClass] + undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path valueJsonConverter:(MobilyModelJson*)valueJsonConverter { + return [self initWithPath:path + keyJsonConverter:nil + valueJsonConverter:valueJsonConverter + undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path valueJsonConverter:(MobilyModelJson*)valueJsonConverter undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:path + keyJsonConverter:nil + valueJsonConverter:valueJsonConverter + undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path keyJsonModelClass:(Class)keyJsonModelClass valueJsonModelClass:(Class)valueJsonModelClass { + return [self initWithPath:path + keyJsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:keyJsonModelClass] + valueJsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:valueJsonModelClass] + undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path keyJsonModelClass:(Class)keyJsonModelClass valueJsonModelClass:(Class)valueJsonModelClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:path + keyJsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:keyJsonModelClass] + valueJsonConverter:[[MobilyModelJsonCustomClass alloc] initWithCustomClass:valueJsonModelClass] + undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path keyJsonConverter:(MobilyModelJson*)keyJsonConverter valueJsonConverter:(MobilyModelJson*)valueJsonConverter { + return [self initWithPath:path + keyJsonConverter:keyJsonConverter + valueJsonConverter:valueJsonConverter + undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path keyJsonConverter:(MobilyModelJson*)keyJsonConverter valueJsonConverter:(MobilyModelJson*)valueJsonConverter undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + self = [super initWithPath:path undefinedBehaviour:undefinedBehaviour]; + if(self != nil) { + self.keyJsonConverter = keyJsonConverter; + self.valueJsonConverter = valueJsonConverter; + } + return self; +} + +#pragma mark MobilyModelJson + +- (id)convertValue:(id)value { + if([value isKindOfClass:NSDictionary.class] == YES) { + NSMutableDictionary* result = NSMutableDictionary.dictionary; + if(result != nil) { + [value enumerateKeysAndObjectsUsingBlock:^(id jsonKey, id jsonObject, BOOL* stop __unused) { + id key = (_keyJsonConverter != nil) ? [_keyJsonConverter convertValue:jsonKey] : jsonKey; + if(key != nil) { + id value = [_valueJsonConverter convertValue:jsonObject]; + if(value != nil) { + result[key] = value; + } + } + }]; + return result; + } + } + return nil; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyModelJsonBool () + +@property(nonatomic, readwrite, assign) BOOL defaultValue; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyModelJsonBool + +#pragma mark Init / Free + +- (instancetype)initWithPath:(NSString*)path defaultValue:(BOOL)defaultValue { + return [self initWithPath:path defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path defaultValue:(BOOL)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + self = [super initWithPath:path undefinedBehaviour:undefinedBehaviour]; + if(self != nil) { + self.defaultValue = defaultValue; + } + return self; +} + +#pragma mark MobilyModelJson + +- (id)convertValue:(id)value { + if([value isKindOfClass:NSString.class] == YES) { + NSString* lowercaseString = [value lowercaseString]; + if(([lowercaseString isEqualToString:@"true"] == YES) || ([lowercaseString isEqualToString:@"yes"] == YES) || ([lowercaseString isEqualToString:@"on"] == YES) || ([lowercaseString isEqualToString:@"1"] == YES)) { + return @YES; + } + return @NO; + } else if([value isKindOfClass:NSNumber.class] == YES) { + return value; + } + return @(_defaultValue); +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyModelJsonString () + +@property(nonatomic, readwrite, strong) NSString* defaultValue; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyModelJsonString + +#pragma mark Init / Free + +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSString*)defaultValue { + return [self initWithPath:path defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSString*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + self = [super initWithPath:path undefinedBehaviour:undefinedBehaviour]; + if(self != nil) { + self.defaultValue = defaultValue; + } + return self; +} + +#pragma mark MobilyModelJson + +- (id)convertValue:(id)value { + if([value isKindOfClass:NSString.class] == YES) { + return value; + } else if([value isKindOfClass:NSNumber.class] == YES) { + static NSNumberFormatter* numberFormat = nil; + if(numberFormat == nil) { + numberFormat = [NSNumberFormatter new]; + numberFormat.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"RU"]; + numberFormat.formatterBehavior = NSNumberFormatterBehavior10_4; + numberFormat.numberStyle = NSNumberFormatterNoStyle; + } + return [numberFormat stringFromNumber:value]; + } + return _defaultValue; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyModelJsonUrl () + +@property(nonatomic, readwrite, strong) NSURL* defaultValue; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyModelJsonUrl + +#pragma mark Init / Free + +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSURL*)defaultValue { + return [self initWithPath:path defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSURL*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + self = [super initWithPath:path undefinedBehaviour:undefinedBehaviour]; + if(self != nil) { + self.defaultValue = defaultValue; + } + return self; +} + +#pragma mark MobilyModelJson + +- (id)convertValue:(id)value { + if([value isKindOfClass:NSString.class] == YES) { + return [NSURL URLWithString:value]; + } + return _defaultValue; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyModelJsonNumber () + +@property(nonatomic, readwrite, strong) NSNumber* defaultValue; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyModelJsonNumber + +#pragma mark Init / Free + +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSNumber*)defaultValue { + return [self initWithPath:path defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSNumber*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + self = [super initWithPath:path undefinedBehaviour:undefinedBehaviour]; + if(self != nil) { + self.defaultValue = defaultValue; + } + return self; +} + +#pragma mark MobilyModelJson + +- (id)convertValue:(id)value { + if([value isKindOfClass:NSNumber.class] == YES) { + return value; + } else if([value isKindOfClass:NSString.class] == YES) { + static NSNumberFormatter* numberFormat = nil; + if(numberFormat == nil) { + numberFormat = [NSNumberFormatter new]; + } + numberFormat.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"RU"]; + numberFormat.formatterBehavior = NSNumberFormatterBehavior10_4; + numberFormat.numberStyle = NSNumberFormatterNoStyle; + + NSNumber* number = [numberFormat numberFromString:value]; + if(number == nil) { + if([numberFormat.decimalSeparator isEqualToString:@"."] == YES) { + numberFormat.decimalSeparator = @","; + } else { + numberFormat.decimalSeparator = @"."; + } + number = [numberFormat numberFromString:value]; + } + if(number != nil) { + return number; + } + } + return _defaultValue; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyModelJsonDate () + +@property(nonatomic, readwrite, strong) NSDate* defaultValue; +@property(nonatomic, readwrite, strong) NSArray* formats; +@property(nonatomic, readwrite, strong) NSTimeZone* timeZone; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyModelJsonDate + +#pragma mark Init / Free + +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSDate*)defaultValue { + return [self initWithPath:path formats:nil timeZone:nil defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue { + return [self initWithPath:path formats:nil timeZone:timeZone defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:path formats:nil timeZone:nil defaultValue:defaultValue undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:path formats:nil timeZone:timeZone defaultValue:defaultValue undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithFormat:(NSString*)format { + return [self initWithPath:nil formats:@[ format ] timeZone:nil defaultValue:nil undefinedBehaviour:nil]; +} + +- (instancetype)initWithFormat:(NSString*)format timeZone:(NSTimeZone*)timeZone { + return [self initWithPath:nil formats:@[ format ] timeZone:timeZone defaultValue:nil undefinedBehaviour:nil]; +} + +- (instancetype)initWithFormat:(NSString*)format undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil formats:@[ format ] timeZone:nil defaultValue:nil undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithFormat:(NSString*)format timeZone:(NSTimeZone*)timeZone undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil formats:@[ format ] timeZone:timeZone defaultValue:nil undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithFormat:(NSString*)format defaultValue:(NSDate*)defaultValue { + return [self initWithPath:nil formats:@[ format ] timeZone:nil defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithFormat:(NSString*)format timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue { + return [self initWithPath:nil formats:@[ format ] timeZone:timeZone defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithFormat:(NSString*)format defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil formats:@[ format ] timeZone:nil defaultValue:defaultValue undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithFormat:(NSString*)format timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil formats:@[ format ] timeZone:timeZone defaultValue:defaultValue undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format { + return [self initWithPath:path formats:@[ format ] timeZone:nil defaultValue:nil undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format timeZone:(NSTimeZone*)timeZone { + return [self initWithPath:path formats:@[ format ] timeZone:timeZone defaultValue:nil undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:path formats:@[ format ] timeZone:nil defaultValue:nil undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format timeZone:(NSTimeZone*)timeZone undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:path formats:@[ format ] timeZone:timeZone defaultValue:nil undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format defaultValue:(NSDate*)defaultValue { + return [self initWithPath:path formats:@[ format ] timeZone:nil defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue { + return [self initWithPath:path formats:@[ format ] timeZone:timeZone defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:path formats:@[ format ] timeZone:nil defaultValue:defaultValue undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path format:(NSString*)format timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:path formats:@[ format ] timeZone:timeZone defaultValue:defaultValue undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithFormats:(NSArray*)formats { + return [self initWithPath:nil formats:formats timeZone:nil defaultValue:nil undefinedBehaviour:nil]; +} + +- (instancetype)initWithFormats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone { + return [self initWithPath:nil formats:formats timeZone:timeZone defaultValue:nil undefinedBehaviour:nil]; +} + +- (instancetype)initWithFormats:(NSArray*)formats undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil formats:formats timeZone:nil defaultValue:nil undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithFormats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil formats:formats timeZone:timeZone defaultValue:nil undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithFormats:(NSArray*)formats defaultValue:(NSDate*)defaultValue { + return [self initWithPath:nil formats:formats timeZone:nil defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithFormats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue { + return [self initWithPath:nil formats:formats timeZone:timeZone defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithFormats:(NSArray*)formats defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil formats:formats timeZone:nil defaultValue:defaultValue undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithFormats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil formats:formats timeZone:timeZone defaultValue:defaultValue undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats { + return [self initWithPath:path formats:formats timeZone:nil defaultValue:nil undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone { + return [self initWithPath:path formats:formats timeZone:timeZone defaultValue:nil undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:path formats:formats timeZone:nil defaultValue:nil undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:path formats:formats timeZone:timeZone defaultValue:nil undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats defaultValue:(NSDate*)defaultValue { + return [self initWithPath:path formats:formats timeZone:nil defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue { + return [self initWithPath:path formats:formats timeZone:timeZone defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:path formats:formats timeZone:nil defaultValue:defaultValue undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path formats:(NSArray*)formats timeZone:(NSTimeZone*)timeZone defaultValue:(NSDate*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + self = [super initWithPath:path undefinedBehaviour:undefinedBehaviour]; + if(self != nil) { + self.formats = formats; + self.defaultValue = defaultValue; + self.timeZone = timeZone; + } + return self; +} + +#pragma mark MobilyModelJson + +- (id)convertValue:(id)value { + if([value isKindOfClass:NSString.class] == YES) { + static NSDateFormatter* dateFormatter = nil; + if(dateFormatter == nil) { + dateFormatter = [NSDateFormatter new]; + dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"RU"]; + } + if(_timeZone != nil) { + dateFormatter.timeZone = _timeZone; + } else { + dateFormatter.timeZone = NSTimeZone.localTimeZone; + } + NSDate* resultValue = nil; + for(NSString* format in _formats) { + if([format isKindOfClass:NSString.class] == true) { + dateFormatter.dateFormat = format; + } + NSDate* date = [dateFormatter dateFromString:value]; + if(date != nil) { + resultValue = date; + break; + } + } + return resultValue; + } else if([value isKindOfClass:NSNumber.class] == YES) { + return [NSDate dateWithTimeIntervalSince1970:[value longValue]]; + } + return _defaultValue; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyModelJsonEnum () + +@property(nonatomic, readwrite, strong) NSNumber* defaultValue; +@property(nonatomic, readwrite, strong) NSDictionary* enums; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyModelJsonEnum + +#pragma mark Init / Free + +- (instancetype)initWithEnums:(NSDictionary*)enums { + return [self initWithPath:nil enums:enums defaultValue:nil undefinedBehaviour:nil]; +} + +- (instancetype)initWithEnums:(NSDictionary*)enums undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil enums:enums defaultValue:nil undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithEnums:(NSDictionary*)enums defaultValue:(NSNumber*)defaultValue { + return [self initWithPath:nil enums:enums defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithEnums:(NSDictionary*)enums defaultValue:(NSNumber*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil enums:enums defaultValue:defaultValue undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path enums:(NSDictionary*)enums { + return [self initWithPath:path enums:enums defaultValue:nil undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path enums:(NSDictionary*)enums undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:path enums:enums defaultValue:nil undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path enums:(NSDictionary*)enums defaultValue:(NSNumber*)defaultValue { + return [self initWithPath:path enums:enums defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path enums:(NSDictionary*)enums defaultValue:(NSNumber*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + self = [super initWithPath:path undefinedBehaviour:undefinedBehaviour]; + if(self != nil) { + self.enums = enums; + self.defaultValue = defaultValue; + } + return self; +} + +#pragma mark MobilyModelJson + +- (id)convertValue:(id)value { + if([value isKindOfClass:NSString.class] == YES) { + if([_enums.allKeys containsObject:value] == YES) { + return _enums[value]; + } + } else if([value isKindOfClass:NSNumber.class] == YES) { + if([_enums.allKeys containsObject:value] == YES) { + return _enums[value]; + } + } + return _defaultValue; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyModelJsonLocation () + +@property(nonatomic, readwrite, strong) CLLocation* defaultValue; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyModelJsonLocation + +#pragma mark Init / Free + +- (instancetype)initWithPath:(NSString*)path defaultValue:(CLLocation*)defaultValue { + return [self initWithPath:path defaultValue:defaultValue undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path defaultValue:(CLLocation*)defaultValue undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + self = [super initWithPath:path undefinedBehaviour:undefinedBehaviour]; + if(self != nil) { + self.defaultValue = defaultValue; + } + return self; +} + +#pragma mark MobilyModelJson + +- (id)convertValue:(id)value { + static NSNumberFormatter* numberFormat = nil; + if(numberFormat == nil) { + numberFormat = [NSNumberFormatter new]; + numberFormat.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"RU"]; + numberFormat.formatterBehavior = NSNumberFormatterBehavior10_4; + numberFormat.numberStyle = NSNumberFormatterNoStyle; + } + if([value isKindOfClass:NSString.class] == YES) { + NSArray* parts = [value componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"-/_,"]]; + if(parts.count == 2) { + NSNumber* latitude = [numberFormat numberFromString:parts[0]]; + if(latitude == nil) { + if([[numberFormat decimalSeparator] isEqualToString:@"."] == YES) { + numberFormat.decimalSeparator = @","; + } + latitude = [numberFormat numberFromString:parts[0]]; + } + NSNumber* longitude = [numberFormat numberFromString:parts[1]]; + if(longitude == nil) { + if([[numberFormat decimalSeparator] isEqualToString:@"."] == YES) { + numberFormat.decimalSeparator = @","; + } + longitude = [numberFormat numberFromString:parts[1]]; + } + return [[CLLocation alloc] initWithLatitude:[latitude doubleValue] longitude:[longitude doubleValue]]; + } + } else if([value isKindOfClass:NSArray.class] == YES) { + if([value count] == 2) { + id latitude = value[0]; + if([latitude isKindOfClass:NSString.class] == YES) { + latitude = [numberFormat numberFromString:latitude]; + if(latitude == nil) { + if([[numberFormat decimalSeparator] isEqualToString:@"."] == YES) { + numberFormat.decimalSeparator = @","; + } + latitude = [numberFormat numberFromString:latitude]; + } + } else if([latitude isKindOfClass:NSNumber.class] == NO) { + latitude = nil; + } + id longitude = value[1]; + if([longitude isKindOfClass:NSString.class] == YES) { + longitude = [numberFormat numberFromString:longitude]; + if(longitude == nil) { + if([[numberFormat decimalSeparator] isEqualToString:@"."] == YES) { + numberFormat.decimalSeparator = @","; + } + longitude = [numberFormat numberFromString:longitude]; + } + } else if([longitude isKindOfClass:NSNumber.class] == NO) { + longitude = nil; + } + return [[CLLocation alloc] initWithLatitude:[latitude doubleValue] longitude:[longitude doubleValue]]; + } + } else if([value isKindOfClass:NSDictionary.class] == YES) { + id latitude = value[@"latitude"]; + if(latitude == nil) { + latitude = value[@"lat"]; + } + if([latitude isKindOfClass:NSString.class] == YES) { + latitude = [numberFormat numberFromString:latitude]; + if(latitude == nil) { + if([[numberFormat decimalSeparator] isEqualToString:@"."] == YES) { + numberFormat.decimalSeparator = @","; + } + latitude = [numberFormat numberFromString:latitude]; + } + } else if([latitude isKindOfClass:NSNumber.class] == NO) { + latitude = nil; + } + id longitude = value[@"longitude"]; + if(longitude == nil) { + longitude = value[@"lon"]; + } + if([longitude isKindOfClass:NSString.class] == YES) { + longitude = [numberFormat numberFromString:longitude]; + if(longitude == nil) { + if([[numberFormat decimalSeparator] isEqualToString:@"."] == YES) { + numberFormat.decimalSeparator = @","; + } + longitude = [numberFormat numberFromString:longitude]; + } + } else if([longitude isKindOfClass:NSNumber.class] == NO) { + longitude = nil; + } + return [[CLLocation alloc] initWithLatitude:[latitude doubleValue] longitude:[longitude doubleValue]]; + } + return _defaultValue; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyModelJsonCustomClass () + +@property(nonatomic, readwrite, assign) Class customClass; +@property(nonatomic, readwrite, assign) BOOL hasAnySource; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyModelJsonCustomClass + +#pragma mark Init / Free + +- (instancetype)initWithCustomClass:(Class)customClass { + return [self initWithPath:nil customClass:customClass hasAnySource:NO undefinedBehaviour:nil]; +} + +- (instancetype)initWithCustomClass:(Class)customClass hasAnySource:(BOOL)hasAnySource { + return [self initWithPath:nil customClass:customClass hasAnySource:hasAnySource undefinedBehaviour:nil]; +} + +- (instancetype)initWithCustomClass:(Class)customClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil customClass:customClass hasAnySource:NO undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithCustomClass:(Class)customClass hasAnySource:(BOOL)hasAnySource undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil customClass:customClass hasAnySource:hasAnySource undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path customClass:(Class)customClass { + return [self initWithPath:path customClass:customClass hasAnySource:NO undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path customClass:(Class)customClass hasAnySource:(BOOL)hasAnySource { + return [self initWithPath:path customClass:customClass hasAnySource:hasAnySource undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path customClass:(Class)customClass undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:path customClass:customClass hasAnySource:NO undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path customClass:(Class)customClass hasAnySource:(BOOL)hasAnySource undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + self = [super initWithPath:path undefinedBehaviour:undefinedBehaviour]; + if(self != nil) { + self.customClass = customClass; + self.hasAnySource = hasAnySource; + } + return self; +} + +#pragma mark MobilyModelJson + +- (id)convertValue:(id)value { + if((_hasAnySource == YES) || ([value isKindOfClass:NSDictionary.class] == YES)) { + return [[_customClass alloc] initWithJson:value]; + } + return nil; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyModelJsonBlock () + +@property(nonatomic, readwrite, copy) MobilyModelJsonConvertBlock block; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyModelJsonBlock + +#pragma mark Init / Free + +- (instancetype)initWithBlock:(MobilyModelJsonConvertBlock)block { + return [self initWithPath:nil block:block undefinedBehaviour:nil]; +} + +- (instancetype)initWithBlock:(MobilyModelJsonConvertBlock)block undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + return [self initWithPath:nil block:block undefinedBehaviour:undefinedBehaviour]; +} + +- (instancetype)initWithPath:(NSString*)path block:(MobilyModelJsonConvertBlock)block { + return [self initWithPath:path block:block undefinedBehaviour:nil]; +} + +- (instancetype)initWithPath:(NSString*)path block:(MobilyModelJsonConvertBlock)block undefinedBehaviour:(MobilyModelJsonUndefinedBehaviour)undefinedBehaviour { + self = [super initWithPath:path undefinedBehaviour:undefinedBehaviour]; + if(self != nil) { + self.block = block; + } + return self; +} + +#pragma mark MobilyModelJson + +- (id)convertValue:(id)value { + if(_block != nil) { + return _block(value); + } + return nil; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyNS.h b/Sources/MobilyCore/MobilyNS.h new file mode 100644 index 0000000..c42c38d --- /dev/null +++ b/Sources/MobilyCore/MobilyNS.h @@ -0,0 +1,354 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface NSObject (MobilyNS) + ++ (NSString*)moClassName; +- (NSString*)moClassName; + +@end + +/*--------------------------------------------------*/ + +#define MOBILY_MINUTE 60.0f +#define MOBILY_HOUR (60.0f * MOBILY_MINUTE) +#define MOBILY_DAY (24.0f * MOBILY_HOUR) +#define MOBILY_5_DAYS (5.0f * MOBILY_DAY) +#define MOBILY_WEEK (7.0f * MOBILY_DAY) +#define MOBILY_MONTH (30.5f * MOBILY_DAY) +#define MOBILY_YEAR (365.0f * MOBILY_DAY) + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, MobilyDateSeason) { + MobilyDateSeasonWinter, + MobilyDateSeasonSpring, + MobilyDateSeasonSummer, + MobilyDateSeasonAutumn +}; + +typedef NS_ENUM(NSUInteger, MobilyDateWeekday) { + MobilyDateWeekdayMonday = 2, + MobilyDateWeekdayTuesday = 3, + MobilyDateWeekdayWednesday = 4, + MobilyDateWeekdayThursday = 5, + MobilyDateWeekdayFriday = 6, + MobilyDateWeekdaySaturday = 7, + MobilyDateWeekdaySunday = 1, +}; + +/*--------------------------------------------------*/ + +@interface NSDate (MobilyNS) + ++ (NSDate*)moDateByYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day; ++ (NSDate*)moDateByHour:(NSInteger)hour minute:(NSInteger)minute second:(NSInteger)seccond; ++ (NSDate*)moDateByYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour minute:(NSInteger)minute second:(NSInteger)seccond; + +- (NSString*)moFormatTime; +- (NSString*)moFormatDate; +- (NSString*)moFormatShortTime; +- (NSString*)moFormatDateTime; +- (NSString*)moFormatRelativeTime; +- (NSString*)moFormatShortRelativeTime; + ++ (NSDate*)moDateWithUnixTimestamp:(NSUInteger)timestamp; +- (NSUInteger)moUnixTimestamp; + +- (NSDate*)moExtractCalendarUnit:(NSCalendarUnit)calendarUnit; +- (NSDate*)moWithoutDate; +- (NSDate*)moWithoutTime; + +- (NSDate*)moBeginningOfYear; +- (NSDate*)moEndOfYear; +- (NSDate*)moBeginningOfMonth; +- (NSDate*)moEndOfMonth; +- (NSDate*)moBeginningOfWeek; +- (NSDate*)moEndOfWeek; +- (NSDate*)moBeginningOfDay; +- (NSDate*)moEndOfDay; +- (NSDate*)moBeginningOfHour; +- (NSDate*)moEndOfHour; +- (NSDate*)moBeginningOfMinute; +- (NSDate*)moEndOfMinute; + +- (NSDate*)moPreviousYear; +- (NSDate*)moNextYear; +- (NSDate*)moPreviousMonth; +- (NSDate*)moNextMonth; +- (NSDate*)moPreviousWeek; +- (NSDate*)moNextWeek; +- (NSDate*)moPreviousDay; +- (NSDate*)moNextDay; +- (NSDate*)moPreviousHour; +- (NSDate*)moNextHour; +- (NSDate*)moPreviousMinute; +- (NSDate*)moNextMinute; +- (NSDate*)moPreviousSecond; +- (NSDate*)moNextSecond; + +- (NSInteger)moYearsToDate:(NSDate*)date; +- (NSInteger)moMonthsToDate:(NSDate*)date; +- (NSInteger)moDaysToDate:(NSDate*)date; +- (NSInteger)moWeeksToDate:(NSDate*)date; +- (NSInteger)moHoursToDate:(NSDate*)date; +- (NSInteger)moMinutesToDate:(NSDate*)date; +- (NSInteger)moSecondsToDate:(NSDate*)date; + +- (NSDate*)moAddYears:(NSInteger)years; +- (NSDate*)moAddMonths:(NSInteger)months; +- (NSDate*)moAddWeeks:(NSInteger)weeks; +- (NSDate*)moAddDays:(NSInteger)days; +- (NSDate*)moAddHours:(NSInteger)hours; +- (NSDate*)moAddMinutes:(NSInteger)minutes; +- (NSDate*)moAddSeconds:(NSInteger)seconds; + +- (BOOL)moIsYesterday; +- (BOOL)moIsToday; +- (BOOL)moIsTomorrow; +- (BOOL)moInsideFrom:(NSDate*)from to:(NSDate*)to; +- (BOOL)moIsEarlier:(NSDate*)anotherDate; +- (BOOL)moIsEarlierOrSame:(NSDate*)anotherDate; +- (BOOL)moIsSame:(NSDate*)anotherDate; +- (BOOL)moIsAfter:(NSDate*)anotherDate; +- (BOOL)moIsAfterOrSame:(NSDate*)anotherDate; + +- (MobilyDateSeason)moSeason; +- (MobilyDateWeekday)moWeekday; + +@end + +/*--------------------------------------------------*/ + +@interface NSDateFormatter (MobilyNS) + ++ (instancetype)moDateFormatterWithFormat:(NSString*)format; ++ (instancetype)moDateFormatterWithFormat:(NSString*)format locale:(NSLocale*)locale; ++ (instancetype)moDateFormatterWithFormatTemplate:(NSString*)formatTemplate; ++ (instancetype)moDateFormatterWithFormatTemplate:(NSString*)formatTemplate locale:(NSLocale*)locale; + +@end + +/*--------------------------------------------------*/ + +@interface NSData (MobilyNS) + +- (NSString*)moToHex; + +- (NSString*)moToBase64; + +@end + +/*--------------------------------------------------*/ + +@interface NSString (MobilyNS) + ++ (id)moStringWithData:(NSData*)data encoding:(NSStringEncoding)encoding; + +- (NSString*)moStringByUppercaseFirstCharacterString; +- (NSString*)moStringByLowercaseFirstCharacterString; + +- (NSString*)moStringByMD5; +- (NSString*)moStringBySHA256; + +- (NSString*)moStringByDecodingURLFormat; +- (NSString*)moStringByEncodingURLFormat; +- (NSMutableDictionary*)moDictionaryFromQueryComponents; + +- (BOOL)moIsEmail; + +- (NSData*)moHMACSHA1:(NSString*)key; + +- (BOOL)moConvertToBool; +- (NSNumber*)moConvertToNumber; +- (NSDate*)moConvertToDateWithFormat:(NSString*)format; + +- (NSTextAlignment)moConvertToTextAlignment; +- (NSLineBreakMode)moConvertToLineBreakMode; + ++ (NSString*)moRightWordFormByCount:(NSInteger)count andForms:(NSArray*)forms; + +- (NSArray*)moCharactersArray; +- (NSString*)moOnlyDigits; + +@end + +/*--------------------------------------------------*/ + +@interface NSArray (MobilyNS) + ++ (instancetype)moArrayWithArray:(NSArray*)array andAddingObject:(id)object; ++ (instancetype)moArrayWithArray:(NSArray*)array andAddingObjectsFromArray:(NSArray*)addingObjects; ++ (instancetype)moArrayWithArray:(NSArray*)array andRemovingObject:(id)object; ++ (instancetype)moArrayWithArray:(NSArray*)array andRemovingObjectsInArray:(NSArray*)removingObjects; + +- (NSArray*)moArrayByReplaceObject:(id)object atIndex:(NSUInteger)index; + +- (NSArray*)moArrayByRemovedObjectAtIndex:(NSUInteger)index; +- (NSArray*)moArrayByRemovedObject:(id)object; +- (NSArray*)moArrayByRemovedObjectsFromArray:(NSArray*)array; + +- (NSArray*)moArrayByObjectClass:(Class)objectClass; +- (NSArray*)moArrayByObjectProtocol:(Protocol*)objectProtocol; + +- (id)moFirstObjectIsClass:(Class)objectClass; +- (id)moLastObjectIsClass:(Class)objectClass; + +- (id)moFirstObjectIsProtocol:(Protocol*)objectProtocol; +- (id)moLastObjectIsProtocol:(Protocol*)objectProtocol; + +- (BOOL)moContainsObjectsInArray:(NSArray*)objectsArray; + +- (NSUInteger)moNextIndexOfObject:(id)object; +- (NSUInteger)moPrevIndexOfObject:(id)object; + +- (id)moNextObjectOfObject:(id)object; +- (id)moPrevObjectOfObject:(id)object; + +- (void)moEnumerateObjectsAtRange:(NSRange)range options:(NSEnumerationOptions)options usingBlock:(void(^)(id obj, NSUInteger idx, BOOL *stop))block NS_AVAILABLE(10_6, 4_0); + +- (void)moEach:(void(^)(id object))block; +- (void)moEachWithIndex:(void(^)(id object, NSUInteger index))block; +- (void)moEach:(void(^)(id object))block options:(NSEnumerationOptions)options; +- (void)moEachWithIndex:(void(^)(id object, NSUInteger index))block options:(NSEnumerationOptions)options; +- (NSArray*)moMap:(id(^)(id object))block; +- (NSDictionary*)moGroupBy:(id(^)(id object))block; +- (NSArray*)moSelect:(BOOL(^)(id object))block; +- (NSArray*)moReject:(BOOL(^)(id object))block; +- (id)moFind:(BOOL(^)(id object))block; +- (NSArray*)moReverse; +- (NSArray*)moIntersectionWithArray:(NSArray*)array; +- (NSArray*)moIntersectionWithArrays:(NSArray*)firstArray, ... NS_REQUIRES_NIL_TERMINATION; +- (NSArray*)moUnionWithArray:(NSArray*)array; +- (NSArray*)moUnionWithArrays:(NSArray*)firstArray, ... NS_REQUIRES_NIL_TERMINATION; +- (NSArray*)moRelativeComplement:(NSArray*)array; +- (NSArray*)moRelativeComplements:(NSArray*)firstArray, ... NS_REQUIRES_NIL_TERMINATION; +- (NSArray*)moSymmetricDifference:(NSArray*)array; + +@end + +/*--------------------------------------------------*/ + +@interface NSMutableArray (MobilyNS) + +- (void)moRemoveFirstObjectsByCount:(NSUInteger)count; +- (void)moRemoveLastObjectsByCount:(NSUInteger)count; + +@end + +/*--------------------------------------------------*/ + +@interface NSDictionary (MobilyNS) + +- (BOOL)moBoolValueForKey:(NSString*)key orDefault:(BOOL)defaultValue; +- (NSInteger)moIntegerValueForKey:(NSString*)key orDefault:(NSInteger)defaultValue; +- (NSUInteger)moUnsignedIntegerValueForKey:(NSString*)key orDefault:(NSUInteger)defaultValue; +- (float)moFloatValueForKey:(NSString*)key orDefault:(float)defaultValue; +- (double)moDoubleValueForKey:(NSString*)key orDefault:(double)defaultValue; +- (NSNumber*)moNumberValueForKey:(NSString*)key orDefault:(NSNumber*)defaultValue; +- (NSString*)moStringValueForKey:(NSString*)key orDefault:(NSString*)defaultValue; +- (NSArray*)moArrayValueForKey:(NSString*)key orDefault:(NSArray*)defaultValue; +- (NSDictionary*)moDictionaryValueForKey:(NSString*)key orDefault:(NSDictionary*)defaultValue; + +- (NSString*)moStringFromQueryComponents; + +- (void)moEach:(void(^)(id key, id value))block; +- (void)moEachWithIndex:(void(^)(id key, id value, NSUInteger index))block; +- (void)moEachKey:(void(^)(id key))block; +- (void)moEachKeyWithIndex:(void(^)(id key, NSUInteger index))block; +- (void)moEachValue:(void(^)(id value))block; +- (void)moEachValueWithIndex:(void(^)(id value, NSUInteger index))block; +- (NSArray*)moMap:(id(^)(id key, id value))block; +- (id)moFindObjectByKey:(BOOL(^)(id key))block; +- (BOOL)moHasKey:(id)key; + +@end + +/*--------------------------------------------------*/ + +@interface NSURL (MobilyNS) + +- (NSMutableDictionary*)moQueryComponents; +- (NSMutableDictionary*)moFragmentComponents; + +@end + +/*--------------------------------------------------*/ + +@interface NSFileManager (MobilyNS) + ++ (NSString*)moDocumentDirectory; ++ (NSString*)moCachesDirectory; + +@end + +/*--------------------------------------------------*/ + +@interface NSHTTPCookieStorage (MobilyNS) + ++ (void)moClearCookieWithDomain:(NSString*)domain; + +@end + +/*--------------------------------------------------*/ + +@interface NSBundle (MobilyNS) + +- (id)moObjectForInfoDictionaryKey:(NSString*)key defaultValue:(id)defaultValue; + +@end + +/*--------------------------------------------------*/ + +@interface NSError (MobilyNS) + +- (BOOL)moIsNoInternetConnection; +- (BOOL)moIsTimedOut; + +@end + +/*--------------------------------------------------*/ + +@interface MobilyStorage : NSObject + ++ (NSString*)moFileSystemDirectory; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyNS.m b/Sources/MobilyCore/MobilyNS.m new file mode 100644 index 0000000..6b76a6f --- /dev/null +++ b/Sources/MobilyCore/MobilyNS.m @@ -0,0 +1,1447 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@implementation NSObject (MobilyNS) + ++ (NSString*)moClassName { + return NSStringFromClass(self.class); +} + +- (NSString*)moClassName { + return NSStringFromClass(self.class); +} + +@end + +/*--------------------------------------------------*/ + +@implementation NSDate (MobilyNS) + ++ (NSDate*)moDateByYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day { + NSDateComponents* components = [NSDateComponents new]; + components.year = year; + components.month = month; + components.day = day; + return [NSCalendar.currentCalendar dateFromComponents:components]; +} + ++ (NSDate*)moDateByHour:(NSInteger)hour minute:(NSInteger)minute second:(NSInteger)seccond { + NSDateComponents* components = [NSDateComponents new]; + components.hour = hour; + components.minute = minute; + components.second = seccond; + return [NSCalendar.currentCalendar dateFromComponents:components]; +} + ++ (NSDate*)moDateByYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour minute:(NSInteger)minute second:(NSInteger)seccond { + NSDateComponents* components = [NSDateComponents new]; + components.year = year; + components.month = month; + components.day = day; + components.hour = hour; + components.minute = minute; + components.second = seccond; + return [NSCalendar.currentCalendar dateFromComponents:components]; +} + +- (NSString*)moFormatTime { + static NSDateFormatter* formatter = nil; + if(formatter == nil) { + formatter = [NSDateFormatter new]; + formatter.dateFormat = NSLocalizedStringFromTable(@"h:mm a", @"MobilyNS", @"Date format: 1:05 pm"); + formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:NSLocalizedStringFromTable(@"en_EN", @"MobilyNS", @"Current locale")]; + formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; + } + return [formatter stringFromDate:self]; +} + +- (NSString*)moFormatDate { + static NSDateFormatter* formatter = nil; + if(formatter == nil) { + formatter = [NSDateFormatter new]; + formatter.dateFormat = NSLocalizedStringFromTable(@"EEEE, LLLL d, YYYY", @"MobilyNS", @"Date format: Monday, July 27, 2009"); + formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:NSLocalizedStringFromTable(@"en_EN", @"MobilyNS", @"Current locale")]; + formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; + } + return [formatter stringFromDate:self]; +} + +- (NSString*)moFormatShortTime { + NSTimeInterval diff = MOBILY_FABS(self.timeIntervalSinceNow); + if(diff < MOBILY_DAY) { + return [self moFormatTime]; + } else if(diff < MOBILY_5_DAYS) { + static NSDateFormatter* formatter = nil; + if(formatter == nil) { + formatter = [NSDateFormatter new]; + formatter.dateFormat = NSLocalizedStringFromTable(@"EEEE", @"MobilyNS", @"Date format: Monday"); + formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:NSLocalizedStringFromTable(@"en_EN", @"MobilyNS", @"Current locale")]; + formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; + } + return [formatter stringFromDate:self]; + } else { + static NSDateFormatter* formatter = nil; + if(formatter == nil) { + formatter = [NSDateFormatter new]; + formatter.dateFormat = NSLocalizedStringFromTable(@"M/d/yy", @"MobilyNS", @"Date format: 7/27/09"); + formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:NSLocalizedStringFromTable(@"en_EN", @"MobilyNS", @"Current locale")]; + formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; + } + return [formatter stringFromDate:self]; + } +} + +- (NSString*)moFormatDateTime { + NSTimeInterval diff = MOBILY_FABS(self.timeIntervalSinceNow); + if(diff < MOBILY_DAY) { + return [self moFormatTime]; + } else if(diff < MOBILY_5_DAYS) { + static NSDateFormatter* formatter = nil; + if(formatter == nil) { + formatter = [NSDateFormatter new]; + formatter.dateFormat = NSLocalizedStringFromTable(@"EEE h:mm a", @"MobilyNS", @"Date format: Mon 1:05 pm"); + formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:NSLocalizedStringFromTable(@"en_EN", @"MobilyNS", @"Current locale")]; + formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; + } + return [formatter stringFromDate:self]; + } else { + static NSDateFormatter* formatter = nil; + if(formatter == nil) { + formatter = [NSDateFormatter new]; + formatter.dateFormat = NSLocalizedStringFromTable(@"MMM d h:mm a", @"MobilyNS", @"Date format: Jul 27 1:05 pm"); + formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:NSLocalizedStringFromTable(@"en_EN", @"MobilyNS", @"Current locale")]; + formatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0]; + } + return [formatter stringFromDate:self]; + } +} + +- (NSString*)moFormatRelativeTime { + NSTimeInterval elapsed = MOBILY_FABS(self.timeIntervalSinceNow); + if(elapsed <= 1.0f) { + return NSLocalizedStringFromTable(@"just a moment ago", @"MobilyNS", @""); + } else if(elapsed < MOBILY_MINUTE) { + int seconds = (int)(elapsed); + return [NSString stringWithFormat:NSLocalizedStringFromTable(@"%d seconds ago", @"MobilyNS", @""), seconds]; + } else if(elapsed < 2.0f * MOBILY_MINUTE) { + return NSLocalizedStringFromTable(@"about a minute ago", @"MobilyNS", @""); + } else if(elapsed < MOBILY_HOUR) { + int mins = (int)(elapsed / MOBILY_MINUTE); + return [NSString stringWithFormat:NSLocalizedStringFromTable(@"%d minutes ago", @"MobilyNS", @""), mins]; + } else if(elapsed < MOBILY_HOUR * 1.5f) { + return NSLocalizedStringFromTable(@"about an hour ago", @"MobilyNS", @""); + } else if(elapsed < MOBILY_DAY) { + int hours = (int)((elapsed + MOBILY_HOUR * 0.5f) / MOBILY_HOUR); + return [NSString stringWithFormat:NSLocalizedStringFromTable(@"%d hours ago", @"MobilyNS", @""), hours]; + } else { + return [self moFormatDateTime]; + } +} + +- (NSString*)moFormatShortRelativeTime { + NSTimeInterval elapsed = MOBILY_FABS(self.timeIntervalSinceNow); + if(elapsed < MOBILY_MINUTE) { + return NSLocalizedStringFromTable(@"<1m", @"MobilyNS", @"Date format: less than one minute ago"); + } else if(elapsed < MOBILY_HOUR) { + int mins = (int)(elapsed / MOBILY_MINUTE); + return [NSString stringWithFormat:NSLocalizedStringFromTable(@"%dm", @"MobilyNS", @"Date format: 50m"), mins]; + } else if(elapsed < MOBILY_DAY) { + int hours = (int)((elapsed + MOBILY_HOUR / 2) / MOBILY_HOUR); + return [NSString stringWithFormat:NSLocalizedStringFromTable(@"%dh", @"MobilyNS", @"Date format: 3h"), hours]; + } else if(elapsed < MOBILY_WEEK) { + int day = (int)((elapsed + MOBILY_DAY / 2) / MOBILY_DAY); + return [NSString stringWithFormat:NSLocalizedStringFromTable(@"%dd", @"MobilyNS", @"Date format: 3d"), day]; + } else { + return [self moFormatShortTime]; + } +} + ++ (NSDate*)moDateWithUnixTimestamp:(NSUInteger)timestamp { + return [NSDate dateWithTimeIntervalSince1970:timestamp]; +} + +- (NSUInteger)moUnixTimestamp { + return (NSUInteger)self.timeIntervalSince1970; +} + + +- (NSDate*)moExtractCalendarUnit:(NSCalendarUnit)calendarUnit { + return [NSCalendar.currentCalendar dateFromComponents:[NSCalendar.currentCalendar components:calendarUnit fromDate:self]]; +} + +- (NSDate*)moWithoutDate { + return [self moExtractCalendarUnit:(NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond)]; +} + +- (NSDate*)moWithoutTime { + return [self moExtractCalendarUnit:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay)]; +} + +- (NSDate*)moBeginningOfYear { + NSDateComponents* components = [NSCalendar.currentCalendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:self]; + components.month = 1; + components.day = 1; + return [NSCalendar.currentCalendar dateFromComponents:components]; +} + +- (NSDate*)moEndOfYear { + static NSDateComponents* components = nil; + if(components == nil) { + components = NSDateComponents.new; + components.year = 1; + } + return [[NSCalendar.currentCalendar dateByAddingComponents:components toDate:self.moBeginningOfYear options:0] dateByAddingTimeInterval:-1]; +} + +- (NSDate*)moBeginningOfMonth { + NSDateComponents* components = [NSCalendar.currentCalendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:self]; + components.day = 1; + return [NSCalendar.currentCalendar dateFromComponents:components]; +} + +- (NSDate*)moEndOfMonth { + static NSDateComponents* components = nil; + if(components == nil) { + components = NSDateComponents.new; + components.month = 1; + } + return [[NSCalendar.currentCalendar dateByAddingComponents:components toDate:self.moBeginningOfMonth options:0] dateByAddingTimeInterval:-1]; +} + +- (NSDate*)moBeginningOfWeek { + NSDateComponents* components = [NSCalendar.currentCalendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitWeekday | NSCalendarUnitDay) fromDate:self]; + NSInteger offset = components.weekday - (NSInteger)NSCalendar.currentCalendar.firstWeekday; + if(offset < 0) { + offset = offset + 7; + } + components.day = components.day - offset; + return [NSCalendar.currentCalendar dateFromComponents:components]; +} + +- (NSDate*)moEndOfWeek { + static NSDateComponents* components = nil; + if(components == nil) { + components = NSDateComponents.new; + components.weekOfMonth = 1; + } + return [[NSCalendar.currentCalendar dateByAddingComponents:components toDate:self.moBeginningOfWeek options:0] dateByAddingTimeInterval:-1]; +} + +- (NSDate*)moBeginningOfDay { + return [NSCalendar.currentCalendar dateFromComponents:[NSCalendar.currentCalendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:self]]; +} + +- (NSDate*)moEndOfDay { + static NSDateComponents* components = nil; + if(components == nil) { + components = NSDateComponents.new; + components.day = 1; + } + return [[NSCalendar.currentCalendar dateByAddingComponents:components toDate:self.moBeginningOfDay options:0] dateByAddingTimeInterval:-1]; +} + +- (NSDate*)moBeginningOfHour { + return [NSCalendar.currentCalendar dateFromComponents:[NSCalendar.currentCalendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour) fromDate:self]]; +} + +- (NSDate*)moEndOfHour { + static NSDateComponents* components = nil; + if(components == nil) { + components = NSDateComponents.new; + components.hour = 1; + } + return [[NSCalendar.currentCalendar dateByAddingComponents:components toDate:self.moBeginningOfHour options:0] dateByAddingTimeInterval:-1]; +} + +- (NSDate*)moBeginningOfMinute { + return [NSCalendar.currentCalendar dateFromComponents:[NSCalendar.currentCalendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute) fromDate:self]]; +} + +- (NSDate*)moEndOfMinute { + static NSDateComponents* components = nil; + if(components == nil) { + components = NSDateComponents.new; + components.minute = 1; + } + return [[NSCalendar.currentCalendar dateByAddingComponents:components toDate:self.moBeginningOfMinute options:0] dateByAddingTimeInterval:-1]; +} + +- (NSDate*)moPreviousYear { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.year = -1; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSDate*)moNextYear { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.year = 1; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSDate*)moPreviousMonth { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.month = -1; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSDate*)moNextMonth { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.month = 1; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSDate*)moPreviousWeek { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.day = -7; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSDate*)moNextWeek { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.day = 7; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSDate*)moPreviousDay { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.day = -1; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSDate*)moNextDay { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.day = 1; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSDate*)moPreviousHour { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.hour = -1; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSDate*)moNextHour { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.hour = 1; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSDate*)moPreviousMinute { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.minute = -1; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSDate*)moNextMinute { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.minute = 1; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSDate*)moPreviousSecond { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.second = -1; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSDate*)moNextSecond { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.second = 1; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSInteger)moYearsToDate:(NSDate*)date { + return [[NSCalendar.currentCalendar components:NSCalendarUnitYear fromDate:self toDate:date options:0] year]; +} + +- (NSInteger)moMonthsToDate:(NSDate*)date { + return [[NSCalendar.currentCalendar components:NSCalendarUnitMonth fromDate:self toDate:date options:0] month]; +} + +- (NSInteger)moDaysToDate:(NSDate*)date { + return [[NSCalendar.currentCalendar components:NSCalendarUnitDay fromDate:self toDate:date options:0] day]; +} + +- (NSInteger)moWeeksToDate:(NSDate*)date { + return [[NSCalendar.currentCalendar components:NSCalendarUnitWeekOfYear fromDate:self toDate:date options:0] weekOfYear]; +} + +- (NSInteger)moHoursToDate:(NSDate*)date { + return [[NSCalendar.currentCalendar components:NSCalendarUnitHour fromDate:self toDate:date options:0] hour]; +} + +- (NSInteger)moMinutesToDate:(NSDate*)date { + return [[NSCalendar.currentCalendar components:NSCalendarUnitMinute fromDate:self toDate:date options:0] minute]; +} + +- (NSInteger)moSecondsToDate:(NSDate*)date { + return [[NSCalendar.currentCalendar components:NSCalendarUnitSecond fromDate:self toDate:date options:0] second]; +} + +- (NSDate*)moAddYears:(NSInteger)years { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.year = years; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSDate*)moAddMonths:(NSInteger)months { + static NSDateComponents* components = nil; + if(components == nil) { + components = [NSDateComponents new]; + components.month = months; + } + return [NSCalendar.currentCalendar dateByAddingComponents:components toDate:self options:0]; +} + +- (NSDate*)moAddWeeks:(NSInteger)weeks { + return [self dateByAddingTimeInterval:(MOBILY_DAY * 7)*weeks]; +} + +- (NSDate*)moAddDays:(NSInteger)days { + return [self dateByAddingTimeInterval:MOBILY_DAY * days]; +} + +- (NSDate*)moAddHours:(NSInteger)hours { + return [self dateByAddingTimeInterval:MOBILY_HOUR * hours]; +} + +- (NSDate*)moAddMinutes:(NSInteger)minutes { + return [self dateByAddingTimeInterval:MOBILY_MINUTE * minutes]; +} + +- (NSDate*)moAddSeconds:(NSInteger)seconds { + return [self dateByAddingTimeInterval:seconds]; +} + +- (BOOL)moIsYesterday { + NSDate* date = NSDate.date.moPreviousDay; + return [self moInsideFrom:date.moBeginningOfDay to:date.moEndOfDay]; +} + +- (BOOL)moIsToday { + NSDate* date = NSDate.date; + return [self moInsideFrom:date.moBeginningOfDay to:date.moEndOfDay]; +} + +- (BOOL)moIsTomorrow { + NSDate* date = NSDate.date.moNextDay; + return [self moInsideFrom:date.moBeginningOfDay to:date.moEndOfDay]; +} + +- (BOOL)moInsideFrom:(NSDate*)from to:(NSDate*)to { + return ([self moIsAfterOrSame:from] == YES) && ([self moIsEarlierOrSame:to]); +} + +- (BOOL)moIsEarlier:(NSDate*)anotherDate { + return ([self compare:anotherDate] == NSOrderedAscending); +} + +- (BOOL)moIsEarlierOrSame:(NSDate*)anotherDate { + return ([self moIsEarlier:anotherDate] || [self moIsSame:anotherDate]); +} + +- (BOOL)moIsSame:(NSDate*)anotherDate { + return ([self compare:anotherDate] == NSOrderedSame); +} + +- (BOOL)moIsAfter:(NSDate*)anotherDate { + return ([self compare:anotherDate] == NSOrderedDescending); +} + +- (BOOL)moIsAfterOrSame:(NSDate*)anotherDate { + return ([self moIsAfter:anotherDate] || [self moIsSame:anotherDate]); +} + +- (MobilyDateSeason)moSeason { + NSDateComponents* components = [NSCalendar.currentCalendar components:NSCalendarUnitMonth fromDate:self]; + NSInteger month = [components month]; + if((month >= 3) && (month <= 5)) { + return MobilyDateSeasonSpring; + } else if((month >= 6) && (month <= 8)) { + return MobilyDateSeasonSummer; + } else if((month >= 9) && (month <= 11)) { + return MobilyDateSeasonAutumn; + } + return MobilyDateSeasonWinter; +} + +- (MobilyDateWeekday)moWeekday { + NSDateComponents* components = [NSCalendar.currentCalendar components:NSCalendarUnitWeekday fromDate:self]; + return [components weekday]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation NSDateFormatter (MobilyNS) + ++ (instancetype)moDateFormatterWithFormat:(NSString*)format { + return [self moDateFormatterWithFormat:format locale:[[NSLocale alloc] initWithLocaleIdentifier:@"RU"]]; +} + ++ (instancetype)moDateFormatterWithFormat:(NSString*)format locale:(NSLocale*)locale { + NSDateFormatter* dateFormatter = [NSDateFormatter new]; + dateFormatter.dateFormat = format; + dateFormatter.locale = locale; + return dateFormatter; +} + ++ (instancetype)moDateFormatterWithFormatTemplate:(NSString*)formatTemplate { + return [self moDateFormatterWithFormatTemplate:formatTemplate locale:[[NSLocale alloc] initWithLocaleIdentifier:@"RU"]]; +} + ++ (instancetype)moDateFormatterWithFormatTemplate:(NSString*)formatTemplate locale:(NSLocale*)locale { + NSDateFormatter* dateFormatter = [NSDateFormatter new]; + dateFormatter.dateFormat = [NSDateFormatter dateFormatFromTemplate:formatTemplate options:0 locale:locale]; + dateFormatter.locale = locale; + return dateFormatter; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +static char Mobily_Base64Table[] = "ABCDEMHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + +/*--------------------------------------------------*/ + +@implementation NSData (MobilyNS) + +- (NSString*)moToHex { + NSUInteger length = self.length; + unsigned char* bytes = (unsigned char*)self.bytes; + NSMutableString* hex = [NSMutableString stringWithCapacity:self.length]; + for(NSUInteger i = 0; i < length; i++) { + [hex appendFormat:@"%02X", bytes[i]]; + } + return hex; +} + +- (NSString*)moToBase64 { + NSData* data = [NSData dataWithBytes:self.bytes length:self.length]; + const uint8_t* input = (const uint8_t*)data.bytes; + NSInteger length = data.length; + NSMutableData* result = [NSMutableData dataWithLength:((length + 2) / 3) * 4]; + uint8_t* output = (uint8_t*)[result mutableBytes]; + for(NSInteger i = 0; i < length; i += 3) { + NSInteger value = 0; + for(NSInteger j = i; j < (i + 3); j++) { + value <<= 8; + if(j < length) { + value |= (0xFF & input[j]); + } + } + NSInteger index = (i / 3) * 4; + output[index + 0] = Mobily_Base64Table[(value >> 18) & 0x3F]; + output[index + 1] = Mobily_Base64Table[(value >> 12) & 0x3F]; + output[index + 2] = (i + 1) < length ? Mobily_Base64Table[(value >> 6) & 0x3F] : '='; + output[index + 3] = (i + 2) < length ? Mobily_Base64Table[(value >> 0) & 0x3F] : '='; + } + return [NSString moStringWithData:result encoding:NSASCIIStringEncoding]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation NSString (MobilyNS) + ++ (instancetype)moStringWithData:(NSData*)data encoding:(NSStringEncoding)encoding { + return [[self alloc] initWithData:data encoding:encoding]; +} + +- (NSString*)moStringByUppercaseFirstCharacterString { + if(self.length > 0) { + return [[[self substringToIndex:1] uppercaseString] stringByAppendingString:[self substringFromIndex:1]]; + } + return NSString.string; +} + +- (NSString*)moStringByLowercaseFirstCharacterString { + if(self.length > 0) { + return [[[self substringToIndex:1] lowercaseString] stringByAppendingString:[self substringFromIndex:1]]; + } + return NSString.string; +} + +- (NSString*)moStringByMD5 { + unsigned char result[16]; + const char* string = self.UTF8String; + CC_MD5(string, (CC_LONG)strlen(string), result); + return [[NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7], result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15]] lowercaseString]; +} + +- (NSString*)moStringBySHA256 { + unsigned char result[CC_SHA256_DIGEST_LENGTH]; + const char* string = self.UTF8String; + CC_SHA256(string, (CC_LONG)strlen(string), result); + return [[NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7], result[8], result[9], result[10], result[11], result[12], result[13], result[14], result[15], result[16], result[17], result[18], result[19], result[20], result[21], result[22], result[23], result[24], result[25], result[26], result[27], result[28], result[29], result[30], result[31]] lowercaseString]; +} + +- (NSString*)moStringByDecodingURLFormat { + NSString* result = nil; + CFStringRef string = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(NULL, (__bridge CFStringRef)self, CFSTR(""), kCFStringEncodingUTF8); + if(string != nil) { + result = [NSString stringWithString:(__bridge NSString*)string]; + CFRelease(string); + } + return result; +} + +- (NSString*)moStringByEncodingURLFormat { + NSString* result = nil; + CFStringRef string = CFURLCreateStringByAddingPercentEscapes(NULL, (__bridge CFStringRef)self, NULL, CFSTR("!*'();:@&=+$,/?%#[]"), kCFStringEncodingUTF8); + if(string != nil) { + result = [NSString stringWithString:(__bridge NSString*)string]; + CFRelease(string); + } + return result; +} + +- (NSMutableDictionary*)moDictionaryFromQueryComponents { + NSMutableDictionary* queryComponents = NSMutableDictionary.dictionary; + for(NSString* keyValuePairString in [self componentsSeparatedByString:@"&"]) { + NSArray* keyValuePairArray = [keyValuePairString componentsSeparatedByString:@"="]; + if(keyValuePairArray.count < 2) { + continue; + } + NSString* key = [keyValuePairArray[0] moStringByDecodingURLFormat]; + NSString* value = [keyValuePairArray[1] moStringByDecodingURLFormat]; + NSMutableArray* results = queryComponents[key]; + if(results == nil) { + results = [NSMutableArray arrayWithCapacity:1]; + queryComponents[key] = results; + } + [results addObject:value]; + } + return queryComponents; +} + +- (BOOL)moIsEmail { + static NSPredicate* predicate = nil; + if(predicate == nil) { + predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES[c] %@", @".+@.+\\..+"]; + } + return [predicate evaluateWithObject:self]; +} + +- (NSData*)moHMACSHA1:(NSString*)key { + const char* cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; + const char* cData = [self cStringUsingEncoding:NSASCIIStringEncoding]; + unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH]; + CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC); + return [NSData dataWithBytes:cHMAC length:sizeof(cHMAC)]; +} + +- (BOOL)moConvertToBool { + if(([self isEqualToString:@"yes"] == YES) || ([self isEqualToString:@"true"] == YES)) { + return YES; + } + return NO; +} + +- (NSNumber*)moConvertToNumber { + static NSNumberFormatter* formatter = nil; + if(formatter == nil) { + formatter = [NSNumberFormatter new]; + formatter.numberStyle = NSNumberFormatterDecimalStyle; + } + return [formatter numberFromString:self]; +} + +- (NSDate*)moConvertToDateWithFormat:(NSString*)format { + static NSDateFormatter* formatter = nil; + if(formatter == nil) { + formatter = [NSDateFormatter new]; + } + formatter.dateFormat = format; + return [formatter dateFromString:self]; +} + +- (NSTextAlignment)moConvertToTextAlignment { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"left"] == YES) { + return NSTextAlignmentLeft; + } else if([temp isEqualToString:@"center"] == YES) { + return NSTextAlignmentCenter; + } else if([temp isEqualToString:@"right"] == YES) { + return NSTextAlignmentRight; + } else if([temp isEqualToString:@"justified"] == YES) { + return NSTextAlignmentJustified; + } else if([temp isEqualToString:@"natural"] == YES) { + return NSTextAlignmentNatural; + } + return NSTextAlignmentLeft; +} + +- (NSLineBreakMode)moConvertToLineBreakMode { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"word-wrap"] == YES) { + return NSLineBreakByWordWrapping; + } else if([temp isEqualToString:@"char-wrap"] == YES) { + return NSLineBreakByCharWrapping; + } else if([temp isEqualToString:@"clip"] == YES) { + return NSLineBreakByClipping; + } else if([temp isEqualToString:@"truncate-head"] == YES) { + return NSLineBreakByTruncatingHead; + } else if([temp isEqualToString:@"truncate-middle"] == YES) { + return NSLineBreakByTruncatingMiddle; + } else if([temp isEqualToString:@"truncate-tail"] == YES) { + return NSLineBreakByTruncatingTail; + } + return NSLineBreakByWordWrapping; +} + ++ (NSString*)moRightWordFormByCount:(NSInteger)count andForms:(NSArray*)forms { + NSInteger count100 = (ABS(count) % 100); + NSInteger count10 = count100 % 10; + + if(count100 > 10 && count100 < 20) return forms[2]; + if(count10 > 1 && count10 < 5) return forms[1]; + if(count10 == 1) return forms[0]; + return forms[2]; +} + +- (NSArray*)moCharactersArray { + NSMutableArray* chars = NSMutableArray.array; + for(int i=0; i < self.length; i++) { + [chars addObject:[NSString stringWithFormat:@"%c", [self characterAtIndex:i]]]; + } + return chars; +} + +- (NSString*)moOnlyDigits { + return [[self componentsSeparatedByCharactersInSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]] componentsJoinedByString:@""]; +} + + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation NSArray (MobilyNS) + ++ (instancetype)moArrayWithArray:(NSArray*)array andAddingObject:(id)object { + NSMutableArray* result = [NSMutableArray arrayWithArray:array]; + [result addObject:object]; + return [NSArray arrayWithArray:result]; +} + ++ (instancetype)moArrayWithArray:(NSArray*)array andAddingObjectsFromArray:(NSArray*)addingObjects { + NSMutableArray* result = [NSMutableArray arrayWithArray:array]; + [result addObjectsFromArray:addingObjects]; + return [NSArray arrayWithArray:result]; +} + ++ (instancetype)moArrayWithArray:(NSArray*)array andRemovingObject:(id)object { + NSMutableArray* result = [NSMutableArray arrayWithArray:array]; + [result removeObject:object]; + return [NSArray arrayWithArray:result]; +} + ++ (instancetype)moArrayWithArray:(NSArray*)array andRemovingObjectsInArray:(NSArray*)removingObjects { + NSMutableArray* result = [NSMutableArray arrayWithArray:array]; + [result removeObjectsInArray:removingObjects]; + return [NSArray arrayWithArray:result]; +} + +- (NSArray*)moArrayByReplaceObject:(id)object atIndex:(NSUInteger)index { + NSMutableArray* result = [NSMutableArray arrayWithArray:self]; + result[index] = object; + return [NSArray arrayWithArray:result]; +} + +- (NSArray*)moArrayByRemovedObjectAtIndex:(NSUInteger)index { + NSMutableArray* result = [NSMutableArray arrayWithArray:self]; + [result removeObjectAtIndex:index]; + return [NSArray arrayWithArray:result]; +} + +- (NSArray*)moArrayByRemovedObject:(id)object { + NSMutableArray* result = [NSMutableArray arrayWithArray:self]; + [result removeObject:object]; + return [NSArray arrayWithArray:result]; +} + +- (NSArray*)moArrayByRemovedObjectsFromArray:(NSArray*)array { + NSMutableArray* result = [NSMutableArray arrayWithArray:self]; + [result removeObjectsInArray:array]; + return [NSArray arrayWithArray:result]; +} + +- (NSArray*)moArrayByObjectClass:(Class)objectClass { + NSMutableArray* result = NSMutableArray.array; + for(id object in self) { + if([object isKindOfClass:objectClass] == YES) { + [result addObject:object]; + } + } + return [NSArray arrayWithArray:result]; +} + +- (NSArray*)moArrayByObjectProtocol:(Protocol*)objectProtocol { + NSMutableArray* result = NSMutableArray.array; + for(id object in self) { + if([object conformsToProtocol:objectProtocol] == YES) { + [result addObject:object]; + } + } + return [NSArray arrayWithArray:result]; +} + +- (id)moFirstObjectIsClass:(Class)objectClass { + id result = nil; + for(id object in self) { + if([object isKindOfClass:objectClass] == YES) { + result = object; + break; + } + } + return result; +} + +- (id)moLastObjectIsClass:(Class)objectClass { + __block id result = nil; + [self enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id object, NSUInteger index __unused, BOOL *stop __unused) { + if([object isKindOfClass:objectClass] == YES) { + result = object; + *stop = YES; + } + }]; + return result; +} + +- (id)moFirstObjectIsProtocol:(Protocol*)objectProtocol { + id result = nil; + for(id object in self) { + if([object conformsToProtocol:objectProtocol] == YES) { + result = object; + break; + } + } + return result; +} + +- (id)moLastObjectIsProtocol:(Protocol*)objectProtocol { + __block id result = nil; + [self enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(id object, NSUInteger index __unused, BOOL *stop __unused) { + if([object conformsToProtocol:objectProtocol] == YES) { + result = object; + *stop = YES; + } + }]; + return result; +} + +- (BOOL)moContainsObjectsInArray:(NSArray*)objectsArray { + for(id object in objectsArray) { + if([self containsObject:object] == NO) { + return NO; + } + } + return (self.count > 0); +} + +- (NSUInteger)moNextIndexOfObject:(id)object { + NSUInteger index = [self indexOfObject:object]; + if(index != NSNotFound) { + if(index == self.count - 1) { + index = NSNotFound; + } else { + index++; + } + } + return index; +} + +- (NSUInteger)moPrevIndexOfObject:(id)object { + NSUInteger index = [self indexOfObject:object]; + if(index != NSNotFound) { + if(index == 0) { + index = NSNotFound; + } else { + index--; + } + } + return index; +} + +- (id)moNextObjectOfObject:(id)object { + NSUInteger index = [self indexOfObject:object]; + if(index != NSNotFound) { + if(index < self.count - 1) { + return self[index + 1]; + } + } + return nil; +} + +- (id)moPrevObjectOfObject:(id)object { + NSUInteger index = [self indexOfObject:object]; + if(index != NSNotFound) { + if(index != 0) { + return self[index - 1]; + } + } + return nil; +} + +- (void)moEnumerateObjectsAtRange:(NSRange)range options:(NSEnumerationOptions)options usingBlock:(void(^)(id obj, NSUInteger idx, BOOL *stop))block { + [self enumerateObjectsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:range] options:options usingBlock:block]; +} + +- (void)moEach:(void(^)(id object))block { + [self enumerateObjectsUsingBlock:^(id object, NSUInteger index __unused, BOOL* stop __unused) { + block(object); + }]; +} + +- (void)moEachWithIndex:(void(^)(id object, NSUInteger index))block { + [self enumerateObjectsUsingBlock:^(id object, NSUInteger index, BOOL* stop __unused) { + block(object, index); + }]; +} + +- (void)moEach:(void(^)(id object))block options:(NSEnumerationOptions)options { + [self enumerateObjectsWithOptions:options usingBlock:^(id object, NSUInteger index __unused, BOOL* stop __unused) { + block(object); + }]; +} + +- (void)moEachWithIndex:(void(^)(id object, NSUInteger index))block options:(NSEnumerationOptions)options { + [self enumerateObjectsWithOptions:options usingBlock:^(id object, NSUInteger index, BOOL* stop __unused) { + block(object, index); + }]; +} + +- (NSArray*)moMap:(id(^)(id object))block { + NSMutableArray* array = [NSMutableArray arrayWithCapacity:self.count]; + for(id object in self) { + id temp = block(object); + if(temp != nil) { + [array addObject:temp]; + } + } + return array; +} + +- (NSDictionary*)moGroupBy:(id(^)(id object))block { + NSMutableDictionary* dictionary = NSMutableDictionary.dictionary; + for(id object in self) { + id temp = block(object); + if([dictionary moHasKey:temp] == YES) { + [dictionary[temp] addObject:object]; + } else { + dictionary[temp] = [NSMutableArray arrayWithObject:object]; + } + } + return dictionary; +} + +- (NSArray*)moSelect:(BOOL(^)(id object))block { + return [self filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary* bindings __unused) { + return (block(evaluatedObject) == YES); + }]]; +} + +- (NSArray*)moReject:(BOOL(^)(id object))block { + return [self filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary* bindings __unused) { + return (block(evaluatedObject) == NO); + }]]; +} + +- (id)moFind:(BOOL(^)(id object))block { + for(id object in self) { + if(block(object) == YES) { + return object; + } + } + return nil; +} + +- (NSArray*)moReverse { + return self.reverseObjectEnumerator.allObjects; +} + +- (NSArray*)moIntersectionWithArray:(NSArray*)array { + return [self filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF IN %@", array]]; +} + +- (NSArray*)moIntersectionWithArrays:(NSArray*)firstArray, ... { + NSArray* resultArray = nil; + if(firstArray != nil) { + NSArray* eachArray = nil; + resultArray = [self moIntersectionWithArray:firstArray]; + va_list argumentList; + va_start(argumentList, firstArray); + while((eachArray = va_arg(argumentList, id)) != nil) { + resultArray = [resultArray moIntersectionWithArray:eachArray]; + } + va_end(argumentList); + } else { + resultArray = @[]; + } + return resultArray; +} + +- (NSArray*)moUnionWithArray:(NSArray*)array { + return [[self moRelativeComplement:array] arrayByAddingObjectsFromArray:array]; +} + +- (NSArray*)moUnionWithArrays:(NSArray*)firstArray, ... { + NSArray* resultArray = nil; + if(firstArray != nil) { + NSArray* eachArray = nil; + resultArray = [self moUnionWithArray:firstArray]; + va_list argumentList; + va_start(argumentList, firstArray); + while((eachArray = va_arg(argumentList, id)) != nil) { + resultArray = [resultArray moUnionWithArray:eachArray]; + } + va_end(argumentList); + } else { + resultArray = @[]; + } + return resultArray; +} + +- (NSArray*)moRelativeComplement:(NSArray*)array { + return [self filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"NOT SELF IN %@", array]]; +} + +- (NSArray*)moRelativeComplements:(NSArray*)firstArray, ... { + NSArray* resultArray = nil; + if(firstArray != nil) { + NSArray* eachArray = nil; + resultArray = [self moRelativeComplement:firstArray]; + va_list argumentList; + va_start(argumentList, firstArray); + while((eachArray = va_arg(argumentList, id)) != nil) { + resultArray = [resultArray moRelativeComplement:eachArray]; + } + va_end(argumentList); + } else { + resultArray = @[]; + } + return resultArray; +} + +- (NSArray*)moSymmetricDifference:(NSArray*)array { + NSArray* subA = [array moRelativeComplement:self]; + NSArray* subB = [self moRelativeComplement:array]; + return [subB moUnionWithArray:subA]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation NSMutableArray (MobilyNS) + +- (void)moRemoveFirstObjectsByCount:(NSUInteger)count { + [self removeObjectsInRange:NSMakeRange(0, count)]; +} + +- (void)moRemoveLastObjectsByCount:(NSUInteger)count { + [self removeObjectsInRange:NSMakeRange((self.count - 1) - count, count)]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation NSDictionary (MobilyNS) + +- (BOOL)moBoolValueForKey:(NSString*)key orDefault:(BOOL)defaultValue { + NSNumber* number = [self moNumberValueForKey:key orDefault:nil]; + if(number != nil) { + return number.boolValue; + } + return defaultValue; +} + +- (NSInteger)moIntegerValueForKey:(NSString*)key orDefault:(NSInteger)defaultValue { + NSNumber* number = [self moNumberValueForKey:key orDefault:nil]; + if(number != nil) { + return number.integerValue; + } + return defaultValue; +} + +- (NSUInteger)moUnsignedIntegerValueForKey:(NSString*)key orDefault:(NSUInteger)defaultValue { + NSNumber* number = [self moNumberValueForKey:key orDefault:nil]; + if(number != nil) { + return number.unsignedIntegerValue; + } + return defaultValue; +} + +- (float)moFloatValueForKey:(NSString*)key orDefault:(float)defaultValue { + NSNumber* number = [self moNumberValueForKey:key orDefault:nil]; + if(number != nil) { + return number.floatValue; + } + return defaultValue; +} + +- (double)moDoubleValueForKey:(NSString*)key orDefault:(double)defaultValue { + NSNumber* number = [self moNumberValueForKey:key orDefault:nil]; + if(number != nil) { + return number.doubleValue; + } + return defaultValue; +} + +- (NSNumber*)moNumberValueForKey:(NSString*)key orDefault:(NSNumber*)defaultValue { + id value = self[key]; + if([value isKindOfClass:NSNumber.class] == YES) { + return value; + } + return defaultValue; +} + +- (NSString*)moStringValueForKey:(NSString*)key orDefault:(NSString*)defaultValue { + id value = self[key]; + if([value isKindOfClass:NSString.class] == YES) { + return value; + } + return defaultValue; +} + +- (NSArray*)moArrayValueForKey:(NSString*)key orDefault:(NSArray*)defaultValue { + id value = self[key]; + if([value isKindOfClass:NSArray.class] == YES) { + return value; + } + return defaultValue; +} + +- (NSDictionary*)moDictionaryValueForKey:(NSString*)key orDefault:(NSDictionary*)defaultValue { + id value = self[key]; + if([value isKindOfClass:NSDictionary.class] == YES) { + return value; + } + return defaultValue; +} + +- (NSString*)moStringFromQueryComponents { + NSString* result = nil; + for(NSString* dictKey in self.allKeys) { + NSString* key = [dictKey moStringByEncodingURLFormat]; + NSArray* allValues = self[key]; + if([allValues isKindOfClass:NSArray.class]) { + for(NSString* dictValue in allValues) { + NSString* value = [dictValue.description moStringByEncodingURLFormat]; + if(result == nil) { + result = [NSString stringWithFormat:@"%@=%@", key, value]; + } else { + result = [result stringByAppendingFormat:@"&%@=%@", key, value]; + } + } + } else { + NSString* value = [allValues.description moStringByEncodingURLFormat]; + if(result == nil) { + result = [NSString stringWithFormat:@"%@=%@", key, value]; + } else { + result = [result stringByAppendingFormat:@"&%@=%@", key, value]; + } + } + } + return result; +} + +- (void)moEach:(void(^)(id key, id value))block { + [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL* stop __unused) { + block(key, obj); + }]; +} + +- (void)moEachWithIndex:(void(^)(id key, id value, NSUInteger index))block { + __block NSInteger index = 0; + [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL* stop __unused) { + block(key, obj, index); + index++; + }]; +} + +- (void)moEachKey:(void(^)(id key))block { + [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj __unused, BOOL* stop __unused) { + block(key); + }]; +} + +- (void)moEachKeyWithIndex:(void(^)(id key, NSUInteger index))block { + __block NSInteger index = 0; + [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj __unused, BOOL* stop __unused) { + block(key, index); + index++; + }]; +} + +- (void)moEachValue:(void(^)(id value))block { + [self enumerateKeysAndObjectsUsingBlock:^(id key __unused, id obj, BOOL* stop __unused) { + block(obj); + }]; +} + +- (void)moEachValueWithIndex:(void(^)(id value, NSUInteger index))block { + __block NSInteger index = 0; + [self enumerateKeysAndObjectsUsingBlock:^(id key __unused, id obj, BOOL* stop __unused) { + block(obj, index); + index++; + }]; +} + +- (NSArray*)moMap:(id(^)(id key, id value))block { + NSMutableArray* array = [NSMutableArray array]; + [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL* stop __unused) { + id object = block(key, obj); + if(object != nil) { + [array addObject:object]; + } + }]; + return array; +} + +- (id)moFindObjectByKey:(BOOL(^)(id key))block { + __block id result = nil; + [self enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + if(block(key) == YES) { + result = obj; + *stop = YES; + } + }]; + return result; +} + +- (BOOL)moHasKey:(id)key { + return (self[key] != nil); +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation NSURL (MobilyNS) + +- (NSMutableDictionary*)moQueryComponents { + return self.query.moDictionaryFromQueryComponents; +} + +- (NSMutableDictionary*)moFragmentComponents { + return self.fragment.moDictionaryFromQueryComponents; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation NSFileManager (MobilyNS) + ++ (NSString*)moDocumentDirectory { + static NSString* result = nil; + if(result == nil) { + NSArray* directories = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + if(directories.count > 0) { + result = directories.firstObject; + } + } + return result; +} + ++ (NSString*)moCachesDirectory { + static NSString* result = nil; + if(result == nil) { + NSArray* directories = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + if(directories.count > 0) { + result = directories.firstObject; + } + } + return result; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation NSHTTPCookieStorage (MobilyNS) + ++ (void)moClearCookieWithDomain:(NSString*)domain { + NSHTTPCookieStorage* storage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; + if(storage != nil) { + for(NSHTTPCookie* cookie in storage.cookies) { + NSRange range = [cookie.domain rangeOfString:domain]; + if(range.length > 0) { + [storage deleteCookie:cookie]; + } + } + [NSUserDefaults.standardUserDefaults synchronize]; + } +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation NSBundle (MobilyNS) + +- (id)moObjectForInfoDictionaryKey:(NSString*)key defaultValue:(id)defaultValue { + id value = [self objectForInfoDictionaryKey:key]; + if(value == nil) { + return defaultValue; + } + return value; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation NSError (MobilyNS) + +- (BOOL)moIsNoInternetConnection { + return ([self.domain isEqualToString:NSURLErrorDomain] || (self.code == NSURLErrorNotConnectedToInternet)); +} + +- (BOOL)moIsTimedOut { + return ([self.domain isEqualToString:NSURLErrorDomain] && (self.code == NSURLErrorTimedOut)); +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyStorage + ++ (NSString*)moFileSystemDirectory { + static NSString* fileSystemDirectory = nil; + if(fileSystemDirectory == nil) { + NSFileManager* fileManager = NSFileManager.defaultManager; + NSString* path = [NSFileManager.moCachesDirectory stringByAppendingPathComponent:NSBundle.mainBundle.bundleIdentifier]; + if([fileManager fileExistsAtPath:path] == NO) { + if([fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil] == YES) { + fileSystemDirectory = path; + } + } else { + fileSystemDirectory = path; + } + } + return fileSystemDirectory; +} + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/Classes/UI/Core/MobilyControllerNavigation.h b/Sources/MobilyCore/MobilyNavigationController.h similarity index 86% rename from Classes/UI/Core/MobilyControllerNavigation.h rename to Sources/MobilyCore/MobilyNavigationController.h index ac87c97..c1cd1b3 100644 --- a/Classes/UI/Core/MobilyControllerNavigation.h +++ b/Sources/MobilyCore/MobilyNavigationController.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,16 +33,17 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyBuilder.h" -#import "MobilyTransitionController.h" +#import +#import /*--------------------------------------------------*/ -@interface MobilyControllerNavigation : UINavigationController< MobilyBuilderObject > +@interface MobilyNavigationController : UINavigationController< MobilyBuilderObject > @property(nonatomic, readonly, assign, getter=isAppeared) BOOL appeared; @property(nonatomic, readwrite, strong) MobilyTransitionController* transitionModal; @property(nonatomic, readwrite, strong) MobilyTransitionController* transitionNavigation; +@property(nonatomic, readwrite, strong) MobilyTransitionController* transitionInteractive; @property(nonatomic, readwrite, strong) id< MobilyEvent > eventDidLoad; @property(nonatomic, readwrite, strong) id< MobilyEvent > eventDidUnload; @@ -51,7 +52,11 @@ @property(nonatomic, readwrite, strong) id< MobilyEvent > eventWillDisappear; @property(nonatomic, readwrite, strong) id< MobilyEvent > eventDidDisappear; -- (void)setupController; +- (void)setup NS_REQUIRES_SUPER; + +- (void)setNeedUpdate; +- (void)update NS_REQUIRES_SUPER; +- (void)clear NS_REQUIRES_SUPER; @end diff --git a/Sources/MobilyCore/MobilyNavigationController.m b/Sources/MobilyCore/MobilyNavigationController.m new file mode 100644 index 0000000..c5bc15e --- /dev/null +++ b/Sources/MobilyCore/MobilyNavigationController.m @@ -0,0 +1,644 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import +#import +#import +#import + +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyNavigationController () < UIViewControllerTransitioningDelegate, UINavigationControllerDelegate, UIGestureRecognizerDelegate, MobilySlideControllerDelegate > + +@property(nonatomic, readwrite, assign, getter=isAppeared) BOOL appeared; +@property(nonatomic, readwrite, assign, getter=isNeedUpdate) BOOL needUpdate; +@property(nonatomic, readwrite, assign) BOOL updating; + +@property(nonatomic, readwrite, strong) UIScreenEdgePanGestureRecognizer* interactiveGesture; + +- (void)interactiveGestureHandle:(UIPanGestureRecognizer* __unused)interactiveGesture; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyNavigationController + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; +@synthesize interactiveGesture = _interactiveGesture; + +#pragma mark NSKeyValueCoding + +MOBILY_DEFINE_VALIDATE_TRANSITION_CONTROLLER(TransitionModal); +MOBILY_DEFINE_VALIDATE_TRANSITION_CONTROLLER(TransitionNavigation); +MOBILY_DEFINE_VALIDATE_TRANSITION_CONTROLLER(TransitionInteractive); +MOBILY_DEFINE_VALIDATE_EVENT(EventDidLoad) +MOBILY_DEFINE_VALIDATE_EVENT(EventDidUnload) +MOBILY_DEFINE_VALIDATE_EVENT(EventWillAppear) +MOBILY_DEFINE_VALIDATE_EVENT(EventDidAppear) +MOBILY_DEFINE_VALIDATE_EVENT(EventWillDisappear) +MOBILY_DEFINE_VALIDATE_EVENT(EventDidDisappear) + +#pragma mark Init / Free + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithNibName:(NSString*)nib bundle:(NSBundle*)bundle { + self = [super initWithNibName:nib bundle:bundle]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithNavigationBarClass:(Class)navigationBarClass toolbarClass:(Class)toolbarClass { + self = [super initWithNavigationBarClass:navigationBarClass toolbarClass:toolbarClass]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithRootViewController:(UIViewController*)rootViewController { + self = [super initWithRootViewController:rootViewController]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + self.delegate = self; + self.navigationController.interactivePopGestureRecognizer.delegate = self; + + self.interactiveGesture = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(interactiveGestureHandle:)]; + self.transitionInteractive = [[MobilyTransitionControllerSlide alloc] initWithRatio:0.2f]; + self.needUpdate = YES; +} + +- (void)dealloc { + [NSNotificationCenter.defaultCenter removeObserver:self]; +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return self.viewControllers; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIViewController.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIViewController.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { + if(self.moRootController == nil) { + UIViewController* viewController = [_objectChilds moFirstObjectIsClass:UIViewController.class]; + if(viewController != nil) { + self.viewControllers = @[ viewController ]; + } + } +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark Property + +- (void)setView:(UIView*)view { + super.view = view; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if((UIDevice.moSystemVersion >= 6.0f) && (view == nil)) { + [self viewDidUnload]; + } +#pragma clang diagnostic pop +} + +- (void)setInteractiveGesture:(UIScreenEdgePanGestureRecognizer*)interactiveGesture { + if(_interactiveGesture != interactiveGesture) { + if(_interactiveGesture != nil) { + [self.view removeGestureRecognizer:_interactiveGesture]; + } + _interactiveGesture = interactiveGesture; + if(_interactiveGesture != nil) { + _interactiveGesture.delegate = self; + _interactiveGesture.edges = UIRectEdgeLeft; + [self.view addGestureRecognizer:_interactiveGesture]; + + } + } +} + +#pragma mark Public + +- (void)setNeedUpdate { + if(_updating == NO) { + self.updating = YES; + [self clear]; + if(self.isAppeared == YES) { + [self update]; + } else { + self.needUpdate = YES; + } + [self.relatedObjects moEach:^(id object) { + if([object respondsToSelector:@selector(setNeedUpdate)] == YES) { + [object setNeedUpdate]; + } + }]; + self.updating = NO; + } +} + +- (void)update { +} + +- (void)clear { +} + +#pragma mark UIViewController + +- (BOOL)shouldAutorotate { + return self.topViewController.shouldAutorotate; +} + +- (NSUInteger)supportedInterfaceOrientations { + return self.topViewController.supportedInterfaceOrientations; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation { + return [self.topViewController shouldAutorotateToInterfaceOrientation:orientation]; +} + +- (BOOL)prefersStatusBarHidden { + return self.topViewController.prefersStatusBarHidden; +} + +- (UIStatusBarStyle)preferredStatusBarStyle { + return self.topViewController.preferredStatusBarStyle; +} + +- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { + return self.topViewController.preferredStatusBarUpdateAnimation; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + if(self.moRootController == nil) { + UIViewController* viewController = [_objectChilds moFirstObjectIsClass:UIViewController.class]; + if(viewController != nil) { + self.viewControllers = @[ viewController ]; + } + } + [_eventDidLoad fireSender:self object:nil]; +} + +- (void)viewDidUnload { + [_eventDidUnload fireSender:self object:nil]; + [self setNeedUpdate]; + + [super viewDidUnload]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [self.view layoutIfNeeded]; + + if(_appeared == NO) { + [_eventWillAppear fireSender:self object:nil]; + self.appeared = YES; + if(self.isNeedUpdate == YES) { + self.needUpdate = NO; + [self clear]; + [self update]; + } + } +} + +- (void)viewDidAppear:(BOOL)animated { + [_eventDidAppear fireSender:self object:nil]; + + [super viewDidAppear:animated]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [_eventWillDisappear fireSender:self object:nil]; + + [super viewWillDisappear:animated]; +} + +- (void)viewDidDisappear:(BOOL)animated { + if(_appeared == YES) { + self.appeared = NO; + [_eventDidDisappear fireSender:self object:nil]; + } + [super viewDidDisappear:animated]; +} + +#pragma mark UIViewControllerTransitioningDelegate + +- (id< UIViewControllerAnimatedTransitioning >)animationControllerForPresentedController:(UIViewController* __unused)presented presentingController:(UIViewController* __unused)presenting sourceController:(UIViewController* __unused)source { + if(_transitionModal != nil) { + _transitionModal.operation = MobilyTransitionOperationPresent; + } + return _transitionModal; +} + +- (id< UIViewControllerAnimatedTransitioning >)animationControllerForDismissedController:(UIViewController* __unused)dismissed { + if(_transitionModal != nil) { + _transitionModal.operation = MobilyTransitionOperationDismiss; + } + return _transitionModal; +} + +- (id< UIViewControllerInteractiveTransitioning >)interactionControllerForPresentation:(id< UIViewControllerAnimatedTransitioning > __unused)animator { + if(_transitionModal != nil) { + _transitionModal.operation = MobilyTransitionOperationPresent; + } + return _transitionModal; +} + +- (id< UIViewControllerInteractiveTransitioning >)interactionControllerForDismissal:(id< UIViewControllerAnimatedTransitioning > __unused)animator { + if(_transitionModal != nil) { + _transitionModal.operation = MobilyTransitionOperationDismiss; + } + return _transitionModal; +} + +#pragma mark UINavigationControllerDelegate + +- (void)navigationController:(UINavigationController*)navigationController willShowViewController:(UIViewController*)viewController animated:(BOOL)animated { + if([viewController isKindOfClass:MobilyController.class] == YES) { + MobilyController* mobilyController = (MobilyController*)viewController; + [navigationController setNavigationBarHidden:mobilyController.isNavigationBarHidden animated:animated]; + } +} + +- (NSUInteger)navigationControllerSupportedInterfaceOrientations:(UINavigationController* __unused)navigationController { + return self.topViewController.supportedInterfaceOrientations; +} + +- (UIInterfaceOrientation)navigationControllerPreferredInterfaceOrientationForPresentation:(UINavigationController* __unused)navigationController { + return [self.topViewController preferredInterfaceOrientationForPresentation]; +} + +- (id< UIViewControllerInteractiveTransitioning >)navigationController:(UINavigationController* __unused)navigationController interactionControllerForAnimationController:(id< UIViewControllerAnimatedTransitioning > __unused)animationController { + if(animationController == _transitionInteractive) { + return _transitionInteractive; + } + return nil; +} + +- (id< UIViewControllerAnimatedTransitioning >)navigationController:(UINavigationController* __unused)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController* __unused)fromViewController toViewController:(UIViewController* __unused)toViewController { + if((_transitionInteractive != nil) && (_transitionInteractive.isInteractive == YES)) { + switch(operation) { + case UINavigationControllerOperationPush: _transitionInteractive.operation = MobilyTransitionOperationPush; break; + case UINavigationControllerOperationPop: _transitionInteractive.operation = MobilyTransitionOperationPop; break; + default: break; + } + return _transitionInteractive; + } else if(_transitionNavigation != nil) { + switch(operation) { + case UINavigationControllerOperationPush: _transitionNavigation.operation = MobilyTransitionOperationPush; break; + case UINavigationControllerOperationPop: _transitionNavigation.operation = MobilyTransitionOperationPop; break; + default: break; + } + return _transitionNavigation; + } + return nil; +} + +#pragma mark Private + +- (void)interactiveGestureHandle:(UIPanGestureRecognizer* __unused)interactiveGesture { + CGPoint translation = [_interactiveGesture translationInView:self.view]; + CGFloat progress = translation.x / self.view.frame.size.width; + switch(_interactiveGesture.state) { + case UIGestureRecognizerStateBegan: { + [_transitionInteractive beginInteractive]; + [self popViewControllerAnimated:YES]; + break; + } + case UIGestureRecognizerStateChanged: { + [_transitionInteractive updateInteractive:MAX(0.0f, MIN(progress, 1.0f))]; + break; + } + case UIGestureRecognizerStateEnded: + case UIGestureRecognizerStateCancelled: { + if((_transitionInteractive.isCancelled == NO) && (progress >= 0.3f)) { + [_transitionInteractive finishInteractive]; + } else { + [_transitionInteractive cancelInteractive]; + } + [_transitionInteractive endInteractive]; + break; + } + default: { + break; + } + } +} + +#pragma mark UIGestureRecognizerDelegate + +- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer { + if(_transitionInteractive != nil) { + if(_transitionInteractive.isAnimated == NO) { + if(self.viewControllers.count > 1) { + if(gestureRecognizer == _interactiveGesture) { + return YES; + } else if(gestureRecognizer == self.interactivePopGestureRecognizer) { + return YES; + } + } + } + } + return NO; +} + +#pragma mark MobilySlideControllerDelegate + +- (BOOL)canShowLeftControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(canShowLeftControllerInSlideController:)] == YES) { + return [controller canShowLeftControllerInSlideController:slideController]; + } + return (self.viewControllers.count == 1); +} + +- (void)willShowLeftControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(willShowLeftControllerInSlideController:duration:)] == YES) { + [controller willShowLeftControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didShowLeftControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(didShowLeftControllerInSlideController:)] == YES) { + [controller didShowLeftControllerInSlideController:slideController]; + } +} + +- (void)willHideLeftControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(willHideLeftControllerInSlideController:duration:)] == YES) { + [controller willHideLeftControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didHideLeftControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(didHideLeftControllerInSlideController:)] == YES) { + [controller didHideLeftControllerInSlideController:slideController]; + } +} + +- (BOOL)canShowRightControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(canShowRightControllerInSlideController:)] == YES) { + return [controller canShowRightControllerInSlideController:slideController]; + } + return (self.viewControllers.count == 1); +} + +- (void)willShowRightControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(willShowRightControllerInSlideController:duration:)] == YES) { + [controller willShowRightControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didShowRightControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(didShowRightControllerInSlideController:)] == YES) { + [controller didShowRightControllerInSlideController:slideController]; + } +} + +- (void)willHideRightControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(willHideRightControllerInSlideController:duration:)] == YES) { + [controller willHideRightControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didHideRightControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(didHideRightControllerInSlideController:)] == YES) { + [controller didHideRightControllerInSlideController:slideController]; + } +} + +- (BOOL)canShowControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(canShowControllerInSlideController:)] == YES) { + return [controller canShowControllerInSlideController:slideController]; + } + return (self.viewControllers.count == 1); +} + +- (void)willShowControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(willShowControllerInSlideController:duration:)] == YES) { + [controller willShowControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didShowControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(didShowControllerInSlideController:)] == YES) { + [controller didShowControllerInSlideController:slideController]; + } +} + +- (void)willHideControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(willHideControllerInSlideController:duration:)] == YES) { + [controller willHideControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didHideControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(didHideControllerInSlideController:)] == YES) { + [controller didHideControllerInSlideController:slideController]; + } +} + +- (void)willBeganLeftSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(willBeganLeftSwipeInSlideController:)] == YES) { + [controller willBeganLeftSwipeInSlideController:slideController]; + } +} + +- (void)didBeganLeftSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(didBeganLeftSwipeInSlideController:)] == YES) { + [controller didBeganLeftSwipeInSlideController:slideController]; + } +} + +- (void)movingLeftSwipeInSlideController:(MobilySlideController*)slideController progress:(CGFloat)progress { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(movingLeftSwipeInSlideController:progress:)] == YES) { + [controller movingLeftSwipeInSlideController:slideController progress:progress]; + } +} + +- (void)willEndedLeftSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(willEndedLeftSwipeInSlideController:)] == YES) { + [controller willEndedLeftSwipeInSlideController:slideController]; + } +} + +- (void)didEndedLeftSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(didEndedLeftSwipeInSlideController:)] == YES) { + [controller didEndedLeftSwipeInSlideController:slideController]; + } +} + +- (void)willBeganRightSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(willBeganRightSwipeInSlideController:)] == YES) { + [controller willBeganRightSwipeInSlideController:slideController]; + } +} + +- (void)didBeganRightSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(didBeganRightSwipeInSlideController:)] == YES) { + [controller didBeganRightSwipeInSlideController:slideController]; + } +} + +- (void)movingRightSwipeInSlideController:(MobilySlideController*)slideController progress:(CGFloat)progress { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(movingRightSwipeInSlideController:progress:)] == YES) { + [controller movingRightSwipeInSlideController:slideController progress:progress]; + } +} + +- (void)willEndedRightSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(willEndedRightSwipeInSlideController:)] == YES) { + [controller willEndedRightSwipeInSlideController:slideController]; + } +} + +- (void)didEndedRightSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(didEndedRightSwipeInSlideController:)] == YES) { + [controller didEndedRightSwipeInSlideController:slideController]; + } +} + +- (void)willBeganSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(willBeganSwipeInSlideController:)] == YES) { + [controller willBeganSwipeInSlideController:slideController]; + } +} + +- (void)didBeganSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(didBeganSwipeInSlideController:)] == YES) { + [controller didBeganSwipeInSlideController:slideController]; + } +} + +- (void)movingSwipeInSlideController:(MobilySlideController*)slideController progress:(CGFloat)progress { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(movingSwipeInSlideController:progress:)] == YES) { + [controller movingSwipeInSlideController:slideController progress:progress]; + } +} + +- (void)willEndedSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(willEndedSwipeInSlideController:)] == YES) { + [controller willEndedSwipeInSlideController:slideController]; + } +} + +- (void)didEndedSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.topViewController; + if([controller respondsToSelector:@selector(didEndedSwipeInSlideController:)] == YES) { + [controller didEndedSwipeInSlideController:slideController]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyNotificationManager.h b/Sources/MobilyCore/MobilyNotificationManager.h new file mode 100755 index 0000000..df3511b --- /dev/null +++ b/Sources/MobilyCore/MobilyNotificationManager.h @@ -0,0 +1,96 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@class MobilyNotificationView; + +/*--------------------------------------------------*/ + +typedef void(^MobilyNotificationPressed)(MobilyNotificationView* notificationView); + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyNotificationManager : NSObject + ++ (void)setParentWindow:(UIWindow*)parentWindow; ++ (UIWindow*)parentWindow; + ++ (void)setStatusBarStyle:(UIStatusBarStyle)statusBarStyle; ++ (UIStatusBarStyle)statusBarStyle; + ++ (void)setStatusBarHidden:(BOOL)statusBarHidden; ++ (BOOL)statusBarHidden; + ++ (MobilyNotificationView*)showView:(UIView*)view; ++ (MobilyNotificationView*)showView:(UIView*)view pressed:(MobilyNotificationPressed)pressed; ++ (MobilyNotificationView*)showView:(UIView*)view duration:(NSTimeInterval)duration; ++ (MobilyNotificationView*)showView:(UIView*)view duration:(NSTimeInterval)duration pressed:(MobilyNotificationPressed)pressed; + ++ (void)hideNotificationView:(MobilyNotificationView*)notificationView animated:(BOOL)animated; ++ (void)hideAllAnimated:(BOOL)animated; + +@end + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyNotificationView : UIView + +@property(nonatomic, readonly, strong) UIView* view; +@property(nonatomic, readonly, assign) NSTimeInterval duration; +@property(nonatomic, readonly, copy) MobilyNotificationPressed pressed; + +- (void)hideAnimated:(BOOL)animated; + +- (void)willShow; +- (void)didShow; +- (void)willHide; +- (void)didHide; + +@end + +/*--------------------------------------------------*/ + +@interface UIView (MobilyNotification) + +@property(nonatomic, readwrite, weak) MobilyNotificationView* moNotificationView; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyNotificationManager.m b/Sources/MobilyCore/MobilyNotificationManager.m new file mode 100755 index 0000000..7bbeae4 --- /dev/null +++ b/Sources/MobilyCore/MobilyNotificationManager.m @@ -0,0 +1,679 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyNotificationWindow : UIWindow { +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyNotificationController : UIViewController { +@protected + __weak UIWindow* _parentWindow; + UIStatusBarStyle _statusBarStyle; + NSMutableArray* _queue; +} + +@property(nonatomic, readwrite, weak) UIWindow* parentWindow; +@property(nonatomic, readwrite, assign) UIStatusBarStyle statusBarStyle; + +- (MobilyNotificationView*)pushView:(UIView*)view duration:(NSTimeInterval)duration pressed:(MobilySimpleBlock)pressed; +- (void)popNotificationView:(MobilyNotificationView*)notificationView animated:(BOOL)animated; +- (void)popAllAnimated:(BOOL)animated; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyNotificationView () { +@protected + __weak MobilyNotificationController* _controller; + UITapGestureRecognizer* _tapGesture; + NSTimer* _timer; +@protected + UIView* _view; + NSLayoutConstraint* _constraintViewCenterX; + NSLayoutConstraint* _constraintViewCenterY; + NSLayoutConstraint* _constraintViewWidth; + NSLayoutConstraint* _constraintViewHeight; + NSTimeInterval _duration; + UIStatusBarStyle _statusBarStyle; + BOOL _statusBarHidden; + MobilyNotificationPressed _pressed; +} + +@property(nonatomic, readwrite, weak) MobilyNotificationController* controller; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintControllerTop; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintControllerLeft; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintControllerRight; +@property(nonatomic, readwrite, strong) UITapGestureRecognizer* tapGesture; +@property(nonatomic, readwrite, strong) NSTimer* timer; + +@property(nonatomic, readwrite, strong) UIView* view; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintViewCenterX; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintViewCenterY; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintViewWidth; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintViewHeight; +@property(nonatomic, readwrite, assign) NSTimeInterval duration; +@property(nonatomic, readwrite, copy) MobilyNotificationPressed pressed; + +- (instancetype)initWithController:(MobilyNotificationController*)controller view:(UIView*)view duration:(NSTimeInterval)duration pressed:(MobilyNotificationPressed)pressed; + +- (IBAction)pressed:(id)sender; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyNotificationManager () { +@protected + MobilyNotificationWindow* _window; + MobilyNotificationController* _controller; +} + +@property(nonatomic, readonly, strong) MobilyNotificationWindow* window; +@property(nonatomic, readonly, strong) MobilyNotificationController* controller; + ++ (instancetype)shared; + +- (MobilyNotificationView*)_showView:(UIView*)view duration:(NSTimeInterval)duration pressed:(MobilySimpleBlock)pressed; +- (void)_hideNotificationView:(MobilyNotificationView*)notificationView animated:(BOOL)animated; +- (void)_hideAllAnimated:(BOOL)animated; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyNotificationWindow + +#pragma mark Init / Free + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + self.backgroundColor = [UIColor clearColor]; + } + return self; +} + +#pragma mark Public override + +- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event { + UIView* view = [super hitTest:point withEvent:event]; + if(view == self.rootViewController.view) { + view = nil; + } + return view; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +static NSTimeInterval MobilyNotificationController_ShowDutation = 0.1f; +static NSTimeInterval MobilyNotificationController_HideDutation = 0.2f; + +/*--------------------------------------------------*/ + +@implementation MobilyNotificationController + +#pragma mark Synthesize + +@synthesize parentWindow = _parentWindow; +@synthesize statusBarStyle = _statusBarStyle; + +#pragma mark Init / Free + +- (instancetype)initWithNibName:(NSString*)nibName bundle:(NSBundle*)bundle { + self = [super initWithNibName:nibName bundle:bundle]; + if(self != nil) { + _statusBarStyle = UIStatusBarStyleDefault; + _queue = [NSMutableArray array]; + } + return self; +} + +#pragma mark Property + +- (void)setParentWindow:(UIWindow*)parentWindow { + if(_parentWindow != parentWindow) { + _parentWindow = parentWindow; + if(UIDevice.moSystemVersion >= 7.0f) { + [self setNeedsStatusBarAppearanceUpdate]; + } + } +} + +- (void)setStatusBarStyle:(UIStatusBarStyle)statusBarStyle { + if(_statusBarStyle != statusBarStyle) { + _statusBarStyle = statusBarStyle; + if(UIDevice.moSystemVersion >= 7.0f) { + [self setNeedsStatusBarAppearanceUpdate]; + } + } +} + +#pragma mark Public override + +- (UIStatusBarStyle)preferredStatusBarStyle { + if(_queue.count > 0) { + return _statusBarStyle; + } + return [_parentWindow.rootViewController preferredStatusBarStyle]; +} + +- (BOOL)prefersStatusBarHidden { + return [_parentWindow.rootViewController prefersStatusBarHidden]; +} + +- (BOOL)shouldAutorotate { + return [_parentWindow.rootViewController shouldAutorotate]; +} + +- (NSUInteger)supportedInterfaceOrientations { + return [_parentWindow.rootViewController supportedInterfaceOrientations]; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation { + return [_parentWindow.rootViewController shouldAutorotateToInterfaceOrientation:orientation]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor clearColor]; +} + +#pragma mark Public + +- (MobilyNotificationView*)pushView:(UIView*)view duration:(NSTimeInterval)duration pressed:(MobilySimpleBlock)pressed { + MobilyNotificationView* notificationView = [[MobilyNotificationView alloc] initWithController:self view:view duration:duration pressed:pressed]; + if(notificationView != nil) { + [_queue insertObject:notificationView atIndex:0]; + if(UIDevice.moSystemVersion >= 7.0f) { + [self setNeedsStatusBarAppearanceUpdate]; + } + [self _showNotificationView:notificationView animated:YES]; + } + return notificationView; +} + +- (void)popNotificationView:(MobilyNotificationView*)notificationView animated:(BOOL)animated { + if([_queue containsObject:notificationView] == YES) { + [self _hideNotificationView:notificationView animated:animated]; + [_queue removeObject:notificationView]; + if(UIDevice.moSystemVersion >= 7.0f) { + [self setNeedsStatusBarAppearanceUpdate]; + } + } +} + +- (void)popAllAnimated:(BOOL)animated { + if(_queue.count > 0) { + [_queue moEach:^(MobilyNotificationView* notificationView) { + [self _hideNotificationView:notificationView animated:animated]; + [_queue removeObject:notificationView]; + if(UIDevice.moSystemVersion >= 7.0f) { + [self setNeedsStatusBarAppearanceUpdate]; + } + } options:NSEnumerationReverse]; + if(UIDevice.moSystemVersion >= 7.0f) { + [self setNeedsStatusBarAppearanceUpdate]; + } + } +} + +#pragma mark Private + +- (void)_showNotificationView:(MobilyNotificationView*)notificationView animated:(BOOL)animated { + MobilyNotificationView* prevNotificationView = [_queue moPrevObjectOfObject:notificationView]; + MobilyNotificationView* nextNotificationView = [_queue moNextObjectOfObject:notificationView]; + notificationView.translatesAutoresizingMaskIntoConstraints = NO; + [self.view addSubview:notificationView]; + if(animated == YES) { + if(prevNotificationView != nil) { + notificationView.constraintControllerTop = [NSLayoutConstraint constraintWithItem:notificationView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:prevNotificationView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; + } else { + notificationView.constraintControllerTop = [NSLayoutConstraint constraintWithItem:notificationView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]; + } + } + notificationView.constraintControllerLeft = [NSLayoutConstraint constraintWithItem:notificationView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]; + notificationView.constraintControllerRight = [NSLayoutConstraint constraintWithItem:notificationView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]; + if(nextNotificationView != nil) { + nextNotificationView.constraintControllerTop = [NSLayoutConstraint constraintWithItem:nextNotificationView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:notificationView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; + } + if(animated == YES) { + [self.view layoutIfNeeded]; + } + if(prevNotificationView != nil) { + notificationView.constraintControllerTop = [NSLayoutConstraint constraintWithItem:notificationView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:prevNotificationView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; + } else { + notificationView.constraintControllerTop = [NSLayoutConstraint constraintWithItem:notificationView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]; + } + [notificationView willShow]; + if(animated == YES) { + [UIView animateWithDuration:MobilyNotificationController_ShowDutation delay:0.0f options:(UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut) animations:^{ + [self.view layoutIfNeeded]; + } completion:^(BOOL finished) { + [notificationView didShow]; + }]; + } else { + [notificationView didShow]; + } +} + +- (void)_hideNotificationView:(MobilyNotificationView*)notificationView animated:(BOOL)animated { + MobilyNotificationView* prevNotificationView = [_queue moPrevObjectOfObject:notificationView]; + MobilyNotificationView* nextNotificationView = [_queue moNextObjectOfObject:notificationView]; + if(prevNotificationView != nil) { + notificationView.constraintControllerTop = [NSLayoutConstraint constraintWithItem:notificationView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:prevNotificationView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; + } else { + notificationView.constraintControllerTop = [NSLayoutConstraint constraintWithItem:notificationView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]; + } + if(nextNotificationView != nil) { + if(prevNotificationView != nil) { + nextNotificationView.constraintControllerTop = [NSLayoutConstraint constraintWithItem:nextNotificationView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:prevNotificationView attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; + } else { + nextNotificationView.constraintControllerTop = [NSLayoutConstraint constraintWithItem:nextNotificationView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]; + } + } + [notificationView willHide]; + if(animated == YES) { + [UIView animateWithDuration:MobilyNotificationController_HideDutation delay:0.0f options:(UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionCurveEaseInOut) animations:^{ + [self.view layoutIfNeeded]; + } completion:^(BOOL finished) { + notificationView.constraintControllerTop = nil; + notificationView.constraintControllerLeft = nil; + notificationView.constraintControllerRight = nil; + [notificationView removeFromSuperview]; + [notificationView didHide]; + }]; + } else { + notificationView.constraintControllerTop = nil; + notificationView.constraintControllerLeft = nil; + notificationView.constraintControllerRight = nil; + [notificationView removeFromSuperview]; + [notificationView didHide]; + } +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyNotificationView + +#pragma mark Synthesize + +@synthesize controller = _controller; +@synthesize constraintControllerTop = _constraintControllerTop; +@synthesize constraintControllerLeft = _constraintControllerLeft; +@synthesize constraintControllerRight = _constraintControllerRight; +@synthesize tapGesture = _tapGesture; +@synthesize timer = _timer; +@synthesize view = _view; +@synthesize constraintViewCenterX = _constraintViewCenterX; +@synthesize constraintViewCenterY = _constraintViewCenterY; +@synthesize constraintViewWidth = _constraintViewWidth; +@synthesize constraintViewHeight = _constraintViewHeight; +@synthesize duration = _duration; +@synthesize pressed = _pressed; + +#pragma mark Init / Free + +- (instancetype)initWithController:(MobilyNotificationController*)controller view:(UIView*)view duration:(NSTimeInterval)duration pressed:(MobilyNotificationPressed)pressed { + self = [super initWithFrame:view.bounds]; + if(self != nil) { + self.controller = controller; + self.view = view; + self.duration = duration; + self.pressed = [pressed copy]; + } + return self; +} + +#pragma mark Public override + +- (void)updateConstraints { + if(_view != nil) { + if(_constraintViewCenterX == nil) { + self.constraintViewCenterX = [NSLayoutConstraint constraintWithItem:_view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]; + } + if(_constraintViewCenterY == nil) { + self.constraintViewCenterY = [NSLayoutConstraint constraintWithItem:_view attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]; + } + if(_constraintViewWidth == nil) { + self.constraintViewWidth = [NSLayoutConstraint constraintWithItem:_view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f]; + } + if(_constraintViewHeight == nil) { + self.constraintViewHeight = [NSLayoutConstraint constraintWithItem:_view attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]; + } + } else { + self.constraintViewCenterX = nil; + self.constraintViewCenterY = nil; + self.constraintViewWidth = nil; + self.constraintViewHeight = nil; + } + [super updateConstraints]; +} + +#pragma mark Property + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintControllerTop, constraintControllerTop, _controller.view, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintControllerLeft, constraintControllerLeft, _controller.view, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintControllerRight, constraintControllerRight, _controller.view, { +}, { +}) + +- (void)setView:(UIView*)view { + if(_view != view) { + if(_view != nil) { + _view.moNotificationView = nil; + [_view removeFromSuperview]; + } + _view = view; + if(_view != nil) { + _view.moNotificationView = self; + _view.translatesAutoresizingMaskIntoConstraints = NO; + [self addSubview:_view]; + } + [self setNeedsUpdateConstraints]; + } +} + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintViewCenterX, constraintViewCenterX, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintViewCenterY, constraintViewCenterY, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintViewWidth, constraintViewWidth, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintViewHeight, constraintViewHeight, self, { +}, { +}) + +- (void)setTimer:(NSTimer*)timer { + if(_timer != timer) { + if(_timer != nil) { + [_timer invalidate]; + } + _timer = timer; + if(_timer != nil) { + [NSRunLoop.mainRunLoop addTimer:_timer forMode:NSRunLoopCommonModes]; + } + } +} + +- (void)setTapGesture:(UITapGestureRecognizer*)tapGesture { + if(_tapGesture != tapGesture) { + if(_tapGesture != nil) { + [self removeGestureRecognizer:_tapGesture]; + } + _tapGesture = tapGesture; + if(_tapGesture != nil) { + [self addGestureRecognizer:_tapGesture]; + } + } +} + +#pragma mark Public + +- (void)hideAnimated:(BOOL)animated { + [_controller popNotificationView:self animated:animated]; +} + +- (void)willShow { +} + +- (void)didShow { + if(_duration > MOBILY_EPSILON) { + self.timer = [NSTimer scheduledTimerWithTimeInterval:_duration target:self selector:@selector(hideTimer:) userInfo:nil repeats:NO]; + } + self.tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(pressed:)]; +} + +- (void)willHide { + self.tapGesture = nil; + self.timer = nil; +} + +- (void)didHide { + self.view = nil; +} + +#pragma mark Actions + +- (IBAction)hideTimer:(id)sender { + [self hideAnimated:YES]; +} + +- (IBAction)pressed:(id)sender { + self.timer = nil; + if(_pressed != nil) { + _pressed(self); + } else { + [self hideAnimated:YES]; + } +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +static NSTimeInterval MobilyNotificationManager_Dutation = 3.0f; + +/*--------------------------------------------------*/ + +@implementation MobilyNotificationManager + +#pragma mark Synthesize + +@synthesize window = _window; +@synthesize controller = _controller; + +#pragma mark Singleton + ++ (instancetype)shared { + static id shared = nil; + if(shared == nil) { + @synchronized(self) { + if(shared == nil) { + shared = [self new]; + } + } + } + return shared; +} + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + self.window.hidden = NO; + } + return self; +} + +#pragma mark Public + ++ (void)setParentWindow:(UIWindow*)parentWindow { + [[self.shared controller] setParentWindow:parentWindow]; +} + ++ (UIWindow*)parentWindow { + return [[self.shared controller] parentWindow]; +} + ++ (void)setStatusBarStyle:(UIStatusBarStyle)statusBarStyle { + [[self.shared controller] setStatusBarStyle:statusBarStyle]; +} + ++ (UIStatusBarStyle)statusBarStyle { + return [[self.shared controller] statusBarStyle]; +} + ++ (void)setStatusBarHidden:(BOOL)statusBarHidden { + if(statusBarHidden == YES) { + [[self.shared window] setWindowLevel:UIWindowLevelStatusBar + 1]; + } else { + [[self.shared window] setWindowLevel:UIWindowLevelStatusBar - 1]; + } +} + ++ (BOOL)statusBarHidden { + return [[self.shared window] windowLevel] > UIWindowLevelStatusBar; +} + ++ (MobilyNotificationView*)showView:(UIView*)view { + return [self.shared _showView:view duration:MobilyNotificationManager_Dutation pressed:nil]; +} + ++ (MobilyNotificationView*)showView:(UIView*)view pressed:(MobilyNotificationPressed)pressed { + return [self.shared _showView:view duration:MobilyNotificationManager_Dutation pressed:pressed]; +} + ++ (MobilyNotificationView*)showView:(UIView*)view duration:(NSTimeInterval)duration { + return [self.shared _showView:view duration:duration pressed:nil]; +} + ++ (MobilyNotificationView*)showView:(UIView*)view duration:(NSTimeInterval)duration pressed:(MobilyNotificationPressed)pressed { + return [self.shared _showView:view duration:duration pressed:pressed]; +} + ++ (void)hideNotificationView:(MobilyNotificationView*)notificationView animated:(BOOL)animated { + [self.shared _hideNotificationView:notificationView animated:animated]; +} + ++ (void)hideAllAnimated:(BOOL)animated { + [self.shared _hideAllAnimated:animated]; +} + +#pragma mark Property + +- (MobilyNotificationWindow*)window { + if(_window == nil) { + _window = [[MobilyNotificationWindow alloc] initWithFrame:UIScreen.mainScreen.bounds]; + _window.windowLevel = UIWindowLevelStatusBar - 1.0f; + _window.rootViewController = self.controller; + } + return _window; +} + +- (MobilyNotificationController*)controller { + if(_controller == nil) { + _controller = [MobilyNotificationController new]; + _controller.parentWindow = UIApplication.sharedApplication.keyWindow; + } + return _controller; +} + +#pragma mark Private + +- (MobilyNotificationView*)_showView:(UIView*)view duration:(NSTimeInterval)duration pressed:(MobilySimpleBlock)pressed { + return [self.controller pushView:view duration:duration pressed:pressed]; +} + +- (void)_hideNotificationView:(MobilyNotificationView*)notificationView animated:(BOOL)animated { + [self.controller popNotificationView:notificationView animated:animated]; +} + +- (void)_hideAllAnimated:(BOOL)animated { + [self.controller popAllAnimated:animated]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UIView (MobilyNotification) + +- (void)setMoNotificationView:(MobilyNotificationView*)moNotificationView { + objc_setAssociatedObject(self, @selector(moNotificationView), moNotificationView, OBJC_ASSOCIATION_ASSIGN); +} + +- (MobilyNotificationView*)moNotificationView { + MobilyNotificationView* view = objc_getAssociatedObject(self, @selector(moNotificationView)); + if(view == nil) { + view = self.superview.moNotificationView; + } + return view; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyObject.h b/Sources/MobilyCore/MobilyObject.h new file mode 100644 index 0000000..384f9a7 --- /dev/null +++ b/Sources/MobilyCore/MobilyObject.h @@ -0,0 +1,51 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef void(^MobilySimpleBlock)(); + +/*--------------------------------------------------*/ + +NS_PROTOCOL_REQUIRES_EXPLICIT_IMPLEMENTATION +@protocol MobilyObject < NSObject > + +- (void)setup; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyPageControl.h b/Sources/MobilyCore/MobilyPageControl.h new file mode 100755 index 0000000..13d5c0b --- /dev/null +++ b/Sources/MobilyCore/MobilyPageControl.h @@ -0,0 +1,101 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, MobilyPageControlAlignment) { + MobilyPageControlAlignmentLeft = 1, + MobilyPageControlAlignmentCenter, + MobilyPageControlAlignmentRight +}; + +typedef NS_ENUM(NSUInteger, MobilyPageControlVerticalAlignment) { + MobilyPageControlVerticalAlignmentTop = 1, + MobilyPageControlVerticalAlignmentMiddle, + MobilyPageControlVerticalAlignmentBottom +}; + +typedef NS_ENUM(NSUInteger, MobilyPageControlTapBehavior) { + MobilyPageControlTapBehaviorStep = 1, + MobilyPageControlTapBehaviorJump +}; + +/*--------------------------------------------------*/ + +@interface MobilyPageControl : UIControl < MobilyBuilderObject > + +@property(nonatomic, readwrite, assign) IBInspectable NSInteger numberOfPages; +@property(nonatomic, readwrite, assign) IBInspectable NSInteger currentPage; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat indicatorMargin; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat indicatorDiameter; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat minHeight; +@property(nonatomic, readwrite, assign) IBInspectable MobilyPageControlAlignment alignment; +@property(nonatomic, readwrite, assign) IBInspectable MobilyPageControlVerticalAlignment verticalAlignment; +@property(nonatomic, readwrite, strong) IBInspectable UIImage* pageIndicatorImage; +@property(nonatomic, readwrite, strong) IBInspectable UIImage* pageIndicatorMaskImage; +@property(nonatomic, readwrite, strong) IBInspectable UIColor* pageIndicatorTintColor; +@property(nonatomic, readwrite, strong) IBInspectable UIImage* currentPageIndicatorImage; +@property(nonatomic, readwrite, strong) IBInspectable UIColor* currentPageIndicatorTintColor; +@property(nonatomic, readwrite, assign) IBInspectable BOOL hidesForSinglePage; +@property(nonatomic, readwrite, assign) IBInspectable BOOL defersCurrentPageDisplay; +@property(nonatomic, readwrite, assign) IBInspectable MobilyPageControlTapBehavior tapBehavior; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)updateCurrentPageDisplay; + +- (CGRect)rectForPageIndicator:(NSInteger)pageIndex; +- (CGSize)sizeForNumberOfPages:(NSInteger)pageCount; + +- (void)setImage:(UIImage*)image forPage:(NSInteger)pageIndex; +- (UIImage*)imageForPage:(NSInteger)pageIndex; + +- (void)setCurrentImage:(UIImage*)image forPage:(NSInteger)pageIndex; +- (UIImage*)currentImageForPage:(NSInteger)pageIndex; + +- (void)setImageMask:(UIImage*)image forPage:(NSInteger)pageIndex; +- (UIImage*)imageMaskForPage:(NSInteger)pageIndex; + +- (void)setScrollViewContentOffsetForCurrentPage:(UIScrollView*)scrollView animated:(BOOL)animated; +- (void)updatePageNumberForScrollView:(UIScrollView*)scrollView; + +- (void)setName:(NSString*)name forPage:(NSInteger)pageIndex; +- (NSString*)nameForPage:(NSInteger)pageIndex; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyPageControl.m b/Sources/MobilyCore/MobilyPageControl.m new file mode 100755 index 0000000..b734e31 --- /dev/null +++ b/Sources/MobilyCore/MobilyPageControl.m @@ -0,0 +1,613 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +#define DEFAULT_INDICATOR_WIDTH 6.0f +#define DEFAULT_INDICATOR_MARGIN 10.0f +#define DEFAULT_MIN_HEIGHT 36.0f + +#define DEFAULT_INDICATOR_WIDTH_LARGE 7.0f +#define DEFAULT_INDICATOR_MARGIN_LARGE 9.0f +#define DEFAULT_MIN_HEIGHT_LARGE 36.0f + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, MobilyPageControlImageType) { + MobilyPageControlImageTypeNormal = 1, + MobilyPageControlImageTypeCurrent, + MobilyPageControlImageTypeMask +}; + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyPageControl () { +@private + NSInteger _displayedPage; + CGFloat _measuredIndicatorWidth; + CGFloat _measuredIndicatorHeight; + CGImageRef _pageImageMask; +} + +@property(nonatomic, readonly, strong) NSMutableDictionary* pageNames; +@property(nonatomic, readonly, strong) NSMutableDictionary* pageImages; +@property(nonatomic, readonly, strong) NSMutableDictionary* currentPageImages; +@property(nonatomic, readonly, strong) NSMutableDictionary* pageImageMasks; +@property(nonatomic, readonly, strong) NSMutableDictionary* cgImageMasks; +@property(nonatomic, readwrite, strong) NSArray* pageRects; +@property(nonatomic, readwrite, strong) UIPageControl* accessibilityPageControl; + +- (void)_setCurrentPage:(NSInteger)currentPage sendEvent:(BOOL)sendEvent canDefer:(BOOL)defer; + +- (CGFloat)_leftOffset; +- (CGFloat)_topOffsetForHeight:(CGFloat)height rect:(CGRect)rect; +- (void)_setImage:(UIImage*)image forPage:(NSInteger)pageIndex type:(MobilyPageControlImageType)type; +- (id)_imageForPage:(NSInteger)pageIndex type:(MobilyPageControlImageType)type; +- (CGImageRef)_createMaskForImage:(UIImage*)image CF_RETURNS_RETAINED; +- (void)_updateMeasuredIndicatorSizeWithSize:(CGSize)size; +- (void)_updateMeasuredIndicatorSizes; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyPageControl + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; +@synthesize pageNames = _pageNames; +@synthesize pageImages = _pageImages; +@synthesize currentPageImages = _currentPageImages; +@synthesize pageImageMasks = _pageImageMasks; +@synthesize cgImageMasks = _cgImageMasks; + +#pragma mark NSKeyValueCoding + +#pragma mark Init / Free + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (id)initWithCoder:(NSCoder*)aDecoder { + self = [super initWithCoder:aDecoder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + _numberOfPages = 0; + _indicatorDiameter = 7.0f; + _indicatorMargin = 14.0f; + _minHeight = 36.0f; + _alignment = MobilyPageControlAlignmentCenter; + _verticalAlignment = MobilyPageControlVerticalAlignmentMiddle; + _pageIndicatorTintColor = [UIColor colorWithWhite:0.8f alpha:0.5f]; + _currentPageIndicatorTintColor = [UIColor colorWithWhite:0.5f alpha:0.5f]; + _tapBehavior = MobilyPageControlTapBehaviorStep; + + self.backgroundColor = [UIColor clearColor]; + self.contentMode = UIViewContentModeRedraw; + self.isAccessibilityElement = YES; + self.accessibilityTraits = UIAccessibilityTraitUpdatesFrequently; + self.accessibilityPageControl = [[UIPageControl alloc] init]; +} + +- (void)dealloc { + if(_pageImageMask != nil) { + CGImageRelease(_pageImageMask); + } +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return self.subviews; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + [self addSubview:(UIView*)objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + [self moRemoveSubview:(UIView*)objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark Property + +- (void)setIndicatorDiameter:(CGFloat)indicatorDiameter { + if(_indicatorDiameter != indicatorDiameter) { + _indicatorDiameter = indicatorDiameter; + if(_minHeight < indicatorDiameter) { + self.minHeight = indicatorDiameter; + } + [self _updateMeasuredIndicatorSizes]; + [self setNeedsDisplay]; + } +} + +- (void)setIndicatorMargin:(CGFloat)indicatorMargin { + if(_indicatorMargin != indicatorMargin) { + _indicatorMargin = indicatorMargin; + [self setNeedsDisplay]; + } +} + +- (void)setMinHeight:(CGFloat)minHeight { + if(minHeight < _indicatorDiameter) { + minHeight = _indicatorDiameter; + } + if(_minHeight != minHeight) { + _minHeight = minHeight; + if([self respondsToSelector:@selector(invalidateIntrinsicContentSize)] == YES) { + [self invalidateIntrinsicContentSize]; + } + [self setNeedsLayout]; + } +} + +- (void)setNumberOfPages:(NSInteger)numberOfPages { + if(_numberOfPages != numberOfPages) { + _numberOfPages = MAX(0, numberOfPages); + self.accessibilityPageControl.numberOfPages = _numberOfPages; + if([self respondsToSelector:@selector(invalidateIntrinsicContentSize)] == YES) { + [self invalidateIntrinsicContentSize]; + } + [self updateAccessibilityValue]; + [self setNeedsDisplay]; + } +} + +- (void)setCurrentPage:(NSInteger)currentPage { + [self _setCurrentPage:currentPage sendEvent:NO canDefer:NO]; +} + +- (void)setCurrentPageIndicatorImage:(UIImage*)currentPageIndicatorImage { + if([currentPageIndicatorImage isEqual:_currentPageIndicatorImage] == NO) { + _currentPageIndicatorImage = currentPageIndicatorImage; + [self _updateMeasuredIndicatorSizes]; + [self setNeedsDisplay]; + } +} + +- (void)setPageIndicatorImage:(UIImage*)pageIndicatorImage { + if([pageIndicatorImage isEqual:_pageIndicatorImage] == NO) { + _pageIndicatorImage = pageIndicatorImage; + [self _updateMeasuredIndicatorSizes]; + [self setNeedsDisplay]; + } +} + +- (void)setPageIndicatorMaskImage:(UIImage*)pageIndicatorMaskImage { + if([pageIndicatorMaskImage isEqual:_pageIndicatorMaskImage] == NO) { + _pageIndicatorMaskImage = pageIndicatorMaskImage; + if(_pageImageMask != NULL) { + CGImageRelease(_pageImageMask); + } + _pageImageMask = [self _createMaskForImage:_pageIndicatorMaskImage]; + [self _updateMeasuredIndicatorSizes]; + [self setNeedsDisplay]; + } +} + +- (NSMutableDictionary*)pageNames { + if(_pageNames == nil) { + _pageNames = [[NSMutableDictionary alloc] init]; + } + return _pageNames; +} + +- (NSMutableDictionary*)pageImages { + if(_pageImages == nil) { + _pageImages = [[NSMutableDictionary alloc] init]; + } + return _pageImages; +} + +- (NSMutableDictionary*)currentPageImages { + if(_currentPageImages == nil) { + _currentPageImages = [[NSMutableDictionary alloc] init]; + } + return _currentPageImages; +} + +- (NSMutableDictionary*)pageImageMasks { + if(_pageImageMasks == nil) { + _pageImageMasks = [[NSMutableDictionary alloc] init]; + } + return _pageImageMasks; +} + +- (NSMutableDictionary*)cgImageMasks { + if(_cgImageMasks == nil) { + _cgImageMasks = [[NSMutableDictionary alloc] init]; + } + return _cgImageMasks; +} + +#pragma mark Public override + +- (void)setFrame:(CGRect)frame { + [super setFrame:frame]; + [self setNeedsDisplay]; +} + +- (CGSize)sizeThatFits:(CGSize)size { + CGSize sizeThatFits = [self sizeForNumberOfPages:_numberOfPages]; + sizeThatFits.height = MAX(sizeThatFits.height, _minHeight); + return sizeThatFits; +} + +- (CGSize)intrinsicContentSize { + if((_numberOfPages < 1) || ((_numberOfPages < 2) && (_hidesForSinglePage == YES))) { + return CGSizeMake(UIViewNoIntrinsicMetric, 0.0f); + } + return CGSizeMake(UIViewNoIntrinsicMetric, MAX(_measuredIndicatorHeight, _minHeight)); +} + +- (void)drawRect:(CGRect)rect { + CGContextRef context = UIGraphicsGetCurrentContext(); + NSMutableArray* pageRects = [NSMutableArray arrayWithCapacity:self.numberOfPages]; + if((_hidesForSinglePage == NO) && (_numberOfPages >= 2)) { + CGFloat left = [self _leftOffset]; + CGFloat xOffset = left; + CGFloat yOffset = 0.0f; + UIColor *fillColor = nil; + UIImage *image = nil; + CGImageRef maskingImage = nil; + CGSize maskSize = CGSizeZero; + for(NSInteger i = 0; i < _numberOfPages; i++) { + NSNumber* indexNumber = @(i); + if(i == _displayedPage) { + fillColor = _currentPageIndicatorTintColor ? _currentPageIndicatorTintColor : [UIColor whiteColor]; + image = _currentPageImages[indexNumber]; + if(image == nil) { + image = _currentPageIndicatorImage; + } + } else { + fillColor = _pageIndicatorTintColor ? _pageIndicatorTintColor : [[UIColor whiteColor] colorWithAlphaComponent:0.3f]; + image = _pageImages[indexNumber]; + if(image == nil) { + image = _pageIndicatorImage; + } + } + if(image == nil) { + maskingImage = (__bridge CGImageRef)_cgImageMasks[indexNumber]; + UIImage* originalImage = _pageImageMasks[indexNumber]; + maskSize = originalImage.size; + if(maskingImage == nil) { + maskingImage = _pageImageMask; + maskSize = _pageIndicatorMaskImage.size; + } + } + [fillColor set]; + CGRect indicatorRect; + if(image != nil) { + yOffset = [self _topOffsetForHeight:image.size.height rect:rect]; + CGFloat centeredXOffset = xOffset + floorf((_measuredIndicatorWidth - image.size.width) / 2.0f); + [image drawAtPoint:CGPointMake(centeredXOffset, yOffset)]; + indicatorRect = CGRectMake(centeredXOffset, yOffset, image.size.width, image.size.height); + } else if(maskingImage != nil) { + yOffset = [self _topOffsetForHeight:maskSize.height rect:rect]; + CGFloat centeredXOffset = xOffset + floorf((_measuredIndicatorWidth - maskSize.width) / 2.0f); + indicatorRect = CGRectMake(centeredXOffset, yOffset, maskSize.width, maskSize.height); + CGContextDrawImage(context, indicatorRect, maskingImage); + } else { + yOffset = [self _topOffsetForHeight:_indicatorDiameter rect:rect]; + CGFloat centeredXOffset = xOffset + floorf((_measuredIndicatorWidth - _indicatorDiameter) / 2.0f); + indicatorRect = CGRectMake(centeredXOffset, yOffset, _indicatorDiameter, _indicatorDiameter); + CGContextFillEllipseInRect(context, indicatorRect); + } + [pageRects addObject:[NSValue valueWithCGRect:indicatorRect]]; + maskingImage = NULL; + xOffset += _measuredIndicatorWidth + _indicatorMargin; + } + self.pageRects = pageRects; + } +} + +- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { + UITouch* touch = [touches anyObject]; + CGPoint point = [touch locationInView:self]; + if(MobilyPageControlTapBehaviorJump == self.tapBehavior) { + __block NSInteger tappedIndicatorIndex = NSNotFound; + [self.pageRects enumerateObjectsUsingBlock:^(NSValue *value, NSUInteger index, BOOL *stop) { + CGRect indicatorRect = [value CGRectValue]; + if(CGRectContainsPoint(indicatorRect, point)) { + tappedIndicatorIndex = index; + *stop = YES; + } + }]; + if(tappedIndicatorIndex != NSNotFound) { + [self _setCurrentPage:tappedIndicatorIndex sendEvent:YES canDefer:YES]; + return; + } + } + CGSize size = [self sizeForNumberOfPages:self.numberOfPages]; + CGFloat left = [self _leftOffset]; + CGFloat middle = left + (size.width / 2.0f); + if(point.x < middle) { + [self _setCurrentPage:self.currentPage - 1 sendEvent:YES canDefer:YES]; + } else { + [self _setCurrentPage:self.currentPage + 1 sendEvent:YES canDefer:YES]; + } +} + +#pragma mark Private + +- (void)_setCurrentPage:(NSInteger)currentPage sendEvent:(BOOL)sendEvent canDefer:(BOOL)defer { + currentPage = MIN(MAX(0, currentPage), _numberOfPages - 1); + if(_currentPage != currentPage) { + _currentPage = currentPage; + self.accessibilityPageControl.currentPage = _currentPage; + [self updateAccessibilityValue]; + if((self.defersCurrentPageDisplay == NO) || (defer == NO)) { + _displayedPage = _currentPage; + [self setNeedsDisplay]; + } + if(sendEvent == YES) { + [self sendActionsForControlEvents:UIControlEventValueChanged]; + } + } +} + +- (CGFloat)_leftOffset { + CGRect rect = self.bounds; + CGSize size = [self sizeForNumberOfPages:self.numberOfPages]; + CGFloat left = 0.0f; + switch(_alignment) { + case MobilyPageControlAlignmentCenter: left = ceilf(CGRectGetMidX(rect) - (size.width / 2.0f)); break; + case MobilyPageControlAlignmentRight: left = CGRectGetMaxX(rect) - size.width; break; + default: break; + } + return left; +} + +- (CGFloat)_topOffsetForHeight:(CGFloat)height rect:(CGRect)rect { + CGFloat top = 0.0f; + switch(_verticalAlignment) { + case MobilyPageControlVerticalAlignmentMiddle: top = CGRectGetMidY(rect) - (height / 2.0f); break; + case MobilyPageControlVerticalAlignmentBottom: top = CGRectGetMaxY(rect) - height; break; + default: break; + } + return top; +} + +- (void)_setImage:(UIImage*)image forPage:(NSInteger)pageIndex type:(MobilyPageControlImageType)type { + if((pageIndex >= 0) && (pageIndex < _numberOfPages)) { + NSMutableDictionary* dictionary = nil; + switch(type) { + case MobilyPageControlImageTypeCurrent: dictionary = self.currentPageImages; break; + case MobilyPageControlImageTypeNormal: dictionary = self.pageImages; break; + case MobilyPageControlImageTypeMask: dictionary = self.pageImageMasks; break; + default: break; + } + if(image != nil) { + dictionary[@(pageIndex)] = image; + } else { + [dictionary removeObjectForKey:@(pageIndex)]; + } + } +} + +- (id)_imageForPage:(NSInteger)pageIndex type:(MobilyPageControlImageType)type { + if((pageIndex >= 0) && (pageIndex < _numberOfPages)) { + NSDictionary* dictionary = nil; + switch(type) { + case MobilyPageControlImageTypeCurrent: dictionary = self.currentPageImages; break; + case MobilyPageControlImageTypeNormal: dictionary = self.pageImages; break; + case MobilyPageControlImageTypeMask: dictionary = self.pageImageMasks; break; + default: break; + } + return dictionary[@(pageIndex)]; + } + return nil; +} + +- (CGImageRef)_createMaskForImage:(UIImage*)image CF_RETURNS_RETAINED { + CGImageRef maskImage = NULL; + size_t pixelsWide = image.size.width * image.scale; + size_t pixelsHigh = image.size.height * image.scale; + size_t bitmapBytesPerRow = (pixelsWide * 1); + CGContextRef context = CGBitmapContextCreate(NULL, pixelsWide, pixelsHigh, CGImageGetBitsPerComponent(image.CGImage), bitmapBytesPerRow, NULL, (CGBitmapInfo)kCGImageAlphaOnly); + if(context != nil) { + CGContextTranslateCTM(context, 0.f, pixelsHigh); + CGContextScaleCTM(context, 1.0f, -1.0f); + CGContextDrawImage(context, CGRectMake(0, 0, pixelsWide, pixelsHigh), image.CGImage); + maskImage = CGBitmapContextCreateImage(context); + CGContextRelease(context); + } + return maskImage; +} + +- (void)_updateMeasuredIndicatorSizeWithSize:(CGSize)size { + _measuredIndicatorWidth = MAX(_measuredIndicatorWidth, size.width); + _measuredIndicatorHeight = MAX(_measuredIndicatorHeight, size.height); +} + +- (void)_updateMeasuredIndicatorSizes { + _measuredIndicatorWidth = _indicatorDiameter; + _measuredIndicatorHeight = _indicatorDiameter; + if(((self.pageIndicatorImage != nil) || (self.pageIndicatorMaskImage != nil)) && (self.currentPageIndicatorImage != nil)) { + _measuredIndicatorWidth = 0; + _measuredIndicatorHeight = 0; + } + if(self.pageIndicatorImage != nil) { + [self _updateMeasuredIndicatorSizeWithSize:self.pageIndicatorImage.size]; + } + if(self.currentPageIndicatorImage != nil) { + [self _updateMeasuredIndicatorSizeWithSize:self.currentPageIndicatorImage.size]; + } + if(self.pageIndicatorMaskImage != nil) { + [self _updateMeasuredIndicatorSizeWithSize:self.pageIndicatorMaskImage.size]; + } + if([self respondsToSelector:@selector(invalidateIntrinsicContentSize)] == YES) { + [self invalidateIntrinsicContentSize]; + } +} + +#pragma mark Public + +- (void)updateCurrentPageDisplay { + _displayedPage = _currentPage; + [self setNeedsDisplay]; +} + +- (CGRect)rectForPageIndicator:(NSInteger)pageIndex { + if((pageIndex >= 0) && (pageIndex < _numberOfPages)) { + CGFloat left = [self _leftOffset]; + CGSize size = [self sizeForNumberOfPages:pageIndex + 1]; + return CGRectMake(left + size.width - _measuredIndicatorWidth, 0, _measuredIndicatorWidth, _measuredIndicatorWidth); + } + return CGRectZero; +} + +- (CGSize)sizeForNumberOfPages:(NSInteger)pageCount { + CGFloat marginSpace = MAX(0, pageCount - 1) * _indicatorMargin; + CGFloat indicatorSpace = pageCount * _measuredIndicatorWidth; + CGSize size = CGSizeMake(marginSpace + indicatorSpace, _measuredIndicatorHeight); + return size; +} + +- (void)setImage:(UIImage*)image forPage:(NSInteger)pageIndex { + [self _setImage:image forPage:pageIndex type:MobilyPageControlImageTypeNormal]; + [self _updateMeasuredIndicatorSizes]; +} + +- (UIImage*)imageForPage:(NSInteger)pageIndex { + return [self _imageForPage:pageIndex type:MobilyPageControlImageTypeNormal]; +} + +- (void)setCurrentImage:(UIImage*)image forPage:(NSInteger)pageIndex { + [self _setImage:image forPage:pageIndex type:MobilyPageControlImageTypeCurrent];; + [self _updateMeasuredIndicatorSizes]; +} + +- (UIImage*)currentImageForPage:(NSInteger)pageIndex { + return [self _imageForPage:pageIndex type:MobilyPageControlImageTypeCurrent]; +} + +- (void)setImageMask:(UIImage*)image forPage:(NSInteger)pageIndex { + [self _setImage:image forPage:pageIndex type:MobilyPageControlImageTypeMask]; + if(image != nil) { + CGImageRef maskImage = [self _createMaskForImage:image]; + if(maskImage != nil) { + self.cgImageMasks[@(pageIndex)] = (__bridge id)maskImage; + CGImageRelease(maskImage); + [self _updateMeasuredIndicatorSizeWithSize:image.size]; + [self setNeedsDisplay]; + } + } else { + [self.cgImageMasks removeObjectForKey:@(pageIndex)]; + } +} + +- (UIImage*)imageMaskForPage:(NSInteger)pageIndex { + return [self _imageForPage:pageIndex type:MobilyPageControlImageTypeMask]; +} + +- (void)setScrollViewContentOffsetForCurrentPage:(UIScrollView*)scrollView animated:(BOOL)animated { + CGPoint offset = scrollView.contentOffset; + offset.x = scrollView.bounds.size.width * _currentPage; + [scrollView setContentOffset:offset animated:animated]; +} + +- (void)updatePageNumberForScrollView:(UIScrollView*)scrollView { + self.currentPage = (int)floorf(scrollView.contentOffset.x / scrollView.bounds.size.width); +} + +#pragma mark - UIAccessibility + +- (void)setName:(NSString*)name forPage:(NSInteger)pageIndex { + if((pageIndex >= 0) && (pageIndex < _numberOfPages)) { + self.pageNames[@(pageIndex)] = name; + } +} + +- (NSString*)nameForPage:(NSInteger)pageIndex { + if((pageIndex >= 0) && (pageIndex < _numberOfPages)) { + return _pageNames[@(pageIndex)]; + } + return nil; +} + +- (void)updateAccessibilityValue { + NSString* pageName = [self nameForPage:self.currentPage]; + NSString* accessibilityValue = self.accessibilityPageControl.accessibilityValue; + if(pageName != nil) { + self.accessibilityValue = [NSString stringWithFormat:@"%@ - %@", pageName, accessibilityValue]; + } else { + self.accessibilityValue = accessibilityValue; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyPageController.h b/Sources/MobilyCore/MobilyPageController.h new file mode 100644 index 0000000..6475ad4 --- /dev/null +++ b/Sources/MobilyCore/MobilyPageController.h @@ -0,0 +1,120 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@protocol MobilyPageControllerDelegate; +@protocol MobilyPageDecorDelegate; + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, MobilyPageControllerOrientation) { + MobilyPageControllerOrientationHorizontal, + MobilyPageControllerOrientationVertical +}; + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSInteger, MobilyPageControllerDirection) { + MobilyPageControllerDirectionForward, + MobilyPageControllerDirectionReverse +}; + +/*--------------------------------------------------*/ + +@interface MobilyPageController : MobilyController + +@property(nonatomic, readwrite, assign) IBInspectable MobilyPageControllerOrientation orientation; +@property(nonatomic, readwrite, strong) UIViewController< MobilyPageControllerDelegate >* controller; +@property(nonatomic, readonly, assign, getter = isAnimating) BOOL animating; +@property(nonatomic, readwrite, assign) IBInspectable BOOL userInteractionEnabled; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat draggingRate; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat bounceRate; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat thresholdHorizontal; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat thresholdVertical; + +- (void)setController:(UIViewController< MobilyPageControllerDelegate >*)controller direction:(MobilyPageControllerDirection)direction animated:(BOOL)animated; +- (void)setController:(UIViewController< MobilyPageControllerDelegate >*)controller direction:(MobilyPageControllerDirection)direction duration:(NSTimeInterval)duration animated:(BOOL)animated; + +@end + +/*--------------------------------------------------*/ + +@protocol MobilyPageControllerDelegate < NSObject > + +@required +- (BOOL)allowBeforeControllerInPageController:(MobilyPageController*)pageController; +- (BOOL)allowAfterControllerInPageController:(MobilyPageController*)pageController; + +@optional +- (void)willAppearInPageController:(MobilyPageController*)pageController; +- (void)didAppearInPageController:(MobilyPageController*)pageController; +- (void)willDisappearInPageController:(MobilyPageController*)pageController; +- (void)didDisappearInPageController:(MobilyPageController*)pageController; + +@optional +- (UIViewController< MobilyPageControllerDelegate >*)beforeControllerInPageController:(MobilyPageController*)pageController; +- (UIEdgeInsets)beforeDecorInsetsInPageController:(MobilyPageController*)pageController; +- (CGSize)beforeDecorSizeInPageController:(MobilyPageController*)pageController; +- (UIView< MobilyPageDecorDelegate >*)beforeDecorViewInPageController:(MobilyPageController*)pageController; + +@optional +- (UIViewController< MobilyPageControllerDelegate >*)afterControllerInPageController:(MobilyPageController*)pageController; +- (UIEdgeInsets)afterDecorInsetsInPageController:(MobilyPageController*)pageController; +- (CGSize)afterDecorSizeInPageController:(MobilyPageController*)pageController; +- (UIView< MobilyPageDecorDelegate >*)afterDecorViewInPageController:(MobilyPageController*)pageController; + +@end + +/*--------------------------------------------------*/ + +@protocol MobilyPageDecorDelegate < NSObject > + +@optional +- (void)pageController:(MobilyPageController*)pageController applyFromProgress:(CGFloat)progress; + +@end + +/*--------------------------------------------------*/ + +@interface UIViewController (MobilyPageController) + +@property(nonatomic, readwrite, weak) MobilyPageController* moPageController; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyPageController.m b/Sources/MobilyCore/MobilyPageController.m new file mode 100644 index 0000000..6d7651f --- /dev/null +++ b/Sources/MobilyCore/MobilyPageController.m @@ -0,0 +1,1041 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +#define ANIMATION_DURATION 0.2f + +/*--------------------------------------------------*/ + +@interface MobilyPageController () < UIGestureRecognizerDelegate, MobilySlideControllerDelegate > { + struct { + unsigned int applyFromProgress:1; + } _canBeforeDecor; + struct { + unsigned int applyFromProgress:1; + } _canAfterDecor; +} + +@property(nonatomic, readwrite, assign, getter = isAnimating) BOOL animating; +@property(nonatomic, readwrite, assign, getter = isAllowBeforeController) BOOL allowBeforeController; +@property(nonatomic, readwrite, assign, getter = isAllowAfterController) BOOL allowAfterController; +@property(nonatomic, readwrite, strong) UIViewController< MobilyPageControllerDelegate >* animateController; +@property(nonatomic, readwrite, strong) UIView* rootView; +@property(nonatomic, readwrite, assign) UIEdgeInsets beforeDecorInsets; +@property(nonatomic, readwrite, assign) UIEdgeInsets afterDecorInsets; +@property(nonatomic, readwrite, assign) CGSize beforeDecorSize; +@property(nonatomic, readwrite, assign) CGSize afterDecorSize; +@property(nonatomic, readwrite, strong) UIView< MobilyPageDecorDelegate >* beforeDecorView; +@property(nonatomic, readwrite, strong) UIView< MobilyPageDecorDelegate >* afterDecorView; +@property(nonatomic, readwrite, strong) UIPanGestureRecognizer* panGesture; +@property(nonatomic, readwrite, strong) NSMutableArray* friendlyGestures; +@property(nonatomic, readwrite, assign) CGPoint panBeganPosition; + +- (void)loadBeforeAfterData; + +- (CGRect)beforeFrame; +- (CGRect)currentFrame; +- (CGRect)afterFrame; + +- (CGRect)beforeDecorFrame; +- (CGRect)beforeDecorFrameFromFrame:(CGRect)currentFrame; +- (CGFloat)beforeDecorProgressFromFrame:(CGRect)currentFrame; + +- (CGRect)afterDecorFrame; +- (CGRect)afterDecorFrameFromFrame:(CGRect)currentFrame; +- (CGFloat)afterDecorProgressFromFrame:(CGRect)currentFrame; + +- (void)panGestureHandle:(UIPanGestureRecognizer*)panGesture; + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyPageController + +- (void)setup { + [super setup]; + + self.userInteractionEnabled = YES; + self.draggingRate = 0.5f; + self.bounceRate = 0.5f; + self.thresholdHorizontal = 100.0f; + self.thresholdVertical = 120.0f; + + self.friendlyGestures = [NSMutableArray array]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor clearColor]; + self.view.clipsToBounds = YES; + + self.rootView = [[UIView alloc] initWithFrame:self.view.bounds]; + _rootView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _rootView.backgroundColor = [UIColor clearColor]; + [self.view addSubview:_rootView]; + + self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureHandle:)]; + [_panGesture setDelegate:self]; + [_rootView addGestureRecognizer:_panGesture]; + + if(_controller != nil) { + _controller.moPageController = self; + if(_controller.parentViewController != self) { + if(_controller.parentViewController != nil) { + [_controller willMoveToParentViewController:nil]; + [_controller.view removeFromSuperview]; + [_controller removeFromParentViewController]; + } + [self addChildViewController:_controller]; + _controller.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + _controller.view.frame = self.currentFrame; + [_rootView addSubview:_controller.view]; + [_controller didMoveToParentViewController:self]; + } + [self loadBeforeAfterData]; + } +} + +- (void)viewWillLayoutSubviews { + [super viewWillLayoutSubviews]; + + _rootView.frame = self.view.bounds; + if(_animating == NO) { + _rootView.frame = self.view.bounds; + if(_controller != nil) { + _controller.view.frame = self.currentFrame; + } + if(_beforeDecorView != nil) { + _beforeDecorView.frame = [self beforeDecorFrameFromFrame:self.currentFrame]; + if(_canBeforeDecor.applyFromProgress == YES) { + [_beforeDecorView pageController:self applyFromProgress:[self beforeDecorProgressFromFrame:self.currentFrame]]; + } + } + if(_afterDecorView != nil) { + _afterDecorView.frame = [self afterDecorFrameFromFrame:self.currentFrame]; + if(_canAfterDecor.applyFromProgress == YES) { + [_afterDecorView pageController:self applyFromProgress:[self afterDecorProgressFromFrame:self.currentFrame]]; + } + } + } +} + +- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { + [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; + + [self.view setNeedsLayout]; +} + +- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { + [super didRotateFromInterfaceOrientation:fromInterfaceOrientation]; + + [self.view setNeedsLayout]; +} + +#pragma mark Property + +- (void)setController:(UIViewController< MobilyPageControllerDelegate >*)controller { + if(_controller != controller) { + if(self.isViewLoaded == YES) { + if(_controller != nil) { + [_controller willMoveToParentViewController:nil]; + [_controller.view removeFromSuperview]; + [_controller removeFromParentViewController]; + } + _controller = controller; + if(_controller != nil) { + _controller.moPageController = self; + if(_controller.parentViewController != self) { + if(_controller.parentViewController != nil) { + [_controller willMoveToParentViewController:nil]; + [_controller.view removeFromSuperview]; + [_controller removeFromParentViewController]; + } + [self addChildViewController:_controller]; + _controller.view.autoresizingMask = (UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin); + _controller.view.frame = self.currentFrame; + [_rootView addSubview:_controller.view]; + [_controller didMoveToParentViewController:self]; + } + } + [self loadBeforeAfterData]; + } else { + _controller = controller; + } + } +} + +- (void)setController:(UIViewController< MobilyPageControllerDelegate >*)controller direction:(MobilyPageControllerDirection)direction animated:(BOOL)animated { + [self setController:controller direction:direction duration:ANIMATION_DURATION animated:animated]; +} + +- (void)setController:(UIViewController< MobilyPageControllerDelegate >*)controller direction:(MobilyPageControllerDirection)direction duration:(NSTimeInterval)duration animated:(BOOL)animated { + [self setController:controller direction:direction duration:duration animated:animated notification:NO]; +} + +- (void)setController:(UIViewController< MobilyPageControllerDelegate >*)controller direction:(MobilyPageControllerDirection)direction duration:(NSTimeInterval)duration animated:(BOOL)animated notification:(BOOL)notification { + UIViewController< MobilyPageControllerDelegate >* currentController = _controller; + if(notification == YES) { + if([currentController respondsToSelector:@selector(willDisappearInPageController:)] == YES) { + [currentController willDisappearInPageController:self]; + } + if([controller respondsToSelector:@selector(willAppearInPageController:)] == YES) { + [controller willAppearInPageController:self]; + } + } + if((self.isViewLoaded == YES) && (animated == YES)) { + self.animating = YES; + _rootView.userInteractionEnabled = NO; + self.animateController = controller; + switch(direction) { + case MobilyPageControllerDirectionReverse: + _animateController.view.frame = self.beforeFrame; + break; + case MobilyPageControllerDirectionForward: + _animateController.view.frame = self.afterFrame; + break; + } + [UIView animateWithDuration:duration + animations:^{ + CGRect currentFrame = self.currentFrame; + switch(direction) { + case MobilyPageControllerDirectionReverse: + _controller.view.frame = self.afterFrame; + _animateController.view.frame = currentFrame; + if(_beforeDecorView != nil) { + _beforeDecorView.frame = [self beforeDecorFrameFromFrame:currentFrame]; + if(_canBeforeDecor.applyFromProgress == YES) { + [_beforeDecorView pageController:self applyFromProgress:[self beforeDecorProgressFromFrame:currentFrame]]; + } + } + break; + case MobilyPageControllerDirectionForward: + _controller.view.frame = self.beforeFrame; + _animateController.view.frame = self.currentFrame; + if(_afterDecorView != nil) { + _afterDecorView.frame = [self afterDecorFrameFromFrame:currentFrame]; + if(_canAfterDecor.applyFromProgress == YES) { + [_afterDecorView pageController:self applyFromProgress:[self afterDecorProgressFromFrame:currentFrame]]; + } + } + break; + } + } completion:^(BOOL finished) { + switch(direction) { + case MobilyPageControllerDirectionReverse: + _controller.view.frame = self.afterFrame; + _animateController.view.frame = self.currentFrame; + break; + case MobilyPageControllerDirectionForward: + _controller.view.frame = self.beforeFrame; + _animateController.view.frame = self.currentFrame; + break; + } + self.animateController = nil; + self.controller = controller; + _rootView.userInteractionEnabled = YES; + self.animating = NO; + if(notification == YES) { + if([controller respondsToSelector:@selector(didAppearInPageController:)] == YES) { + [controller didAppearInPageController:self]; + } + if([currentController respondsToSelector:@selector(didDisappearInPageController:)] == YES) { + [currentController didDisappearInPageController:self]; + } + } + }]; + } else { + self.controller = controller; + if(notification == YES) { + if([controller respondsToSelector:@selector(didAppearInPageController:)] == YES) { + [controller didAppearInPageController:self]; + } + if([currentController respondsToSelector:@selector(didDisappearInPageController:)] == YES) { + [currentController didDisappearInPageController:self]; + } + } + } +} + +- (void)setAnimateController:(UIViewController< MobilyPageControllerDelegate >*)animateController { + if(_animateController != animateController) { + _animateController = animateController; + if(_animateController != nil) { + if(_animateController.parentViewController != self) { + if(_animateController.parentViewController != nil) { + [_animateController willMoveToParentViewController:nil]; + [_animateController.view removeFromSuperview]; + [_animateController removeFromParentViewController]; + } + [self addChildViewController:_animateController]; + _animateController.view.autoresizingMask = (UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin); + _animateController.view.frame = self.beforeFrame; + [_rootView addSubview:_animateController.view]; + [_animateController didMoveToParentViewController:self]; + } + } + } +} + +- (void)setBeforeDecorView:(UIView< MobilyPageDecorDelegate >*)beforeDecorView { + if(_beforeDecorView != beforeDecorView) { + if(_beforeDecorView != nil) { + [_beforeDecorView removeFromSuperview]; + } + _beforeDecorView = beforeDecorView; + _canBeforeDecor.applyFromProgress = [_beforeDecorView respondsToSelector:@selector(pageController:applyFromProgress:)]; + if(_beforeDecorView != nil) { + CGRect currentFrame = self.currentFrame; + _beforeDecorView.frame = [self beforeDecorFrameFromFrame:currentFrame]; + if(_canBeforeDecor.applyFromProgress == YES) { + [_beforeDecorView pageController:self applyFromProgress:[self beforeDecorProgressFromFrame:currentFrame]]; + } + [_rootView addSubview:_beforeDecorView]; + [_rootView sendSubviewToBack:_beforeDecorView]; + } + } +} + +- (void)setAfterDecorView:(UIView< MobilyPageDecorDelegate >*)afterDecorView { + if(_afterDecorView != afterDecorView) { + if(_afterDecorView != nil) { + [_afterDecorView removeFromSuperview]; + } + _afterDecorView = afterDecorView; + _canAfterDecor.applyFromProgress = [_afterDecorView respondsToSelector:@selector(pageController:applyFromProgress:)]; + if(_afterDecorView != nil) { + CGRect currentFrame = self.currentFrame; + _afterDecorView.frame = [self afterDecorFrameFromFrame:currentFrame]; + if(_canAfterDecor.applyFromProgress == YES) { + [_afterDecorView pageController:self applyFromProgress:[self afterDecorProgressFromFrame:currentFrame]]; + } + [_rootView addSubview:_afterDecorView]; + [_rootView sendSubviewToBack:_afterDecorView]; + } + } +} + +- (void)loadBeforeAfterData { + self.allowBeforeController = [_controller allowBeforeControllerInPageController:self]; + self.allowAfterController = [_controller allowAfterControllerInPageController:self]; + if(([_controller respondsToSelector:@selector(beforeDecorSizeInPageController:)] == YES) && ([_controller respondsToSelector:@selector(beforeDecorViewInPageController:)] == YES)) { + if([_controller respondsToSelector:@selector(beforeDecorInsetsInPageController:)] == YES) { + self.beforeDecorInsets = [_controller beforeDecorInsetsInPageController:self]; + } + self.beforeDecorSize = [_controller beforeDecorSizeInPageController:self]; + self.beforeDecorView = [_controller beforeDecorViewInPageController:self]; + } + if(([_controller respondsToSelector:@selector(afterDecorSizeInPageController:)] == YES) && ([_controller respondsToSelector:@selector(afterDecorViewInPageController:)] == YES)) { + if([_controller respondsToSelector:@selector(afterDecorInsetsInPageController:)] == YES) { + self.afterDecorInsets = [_controller afterDecorInsetsInPageController:self]; + } + self.afterDecorSize = [_controller afterDecorSizeInPageController:self]; + self.afterDecorView = [_controller afterDecorViewInPageController:self]; + } +} + +- (CGRect)beforeFrame { + CGRect currentFrame = self.currentFrame; + switch(_orientation) { + case MobilyPageControllerOrientationVertical: + return CGRectMake(currentFrame.origin.x, currentFrame.origin.y - currentFrame.size.height, currentFrame.size.width, currentFrame.size.height); + case MobilyPageControllerOrientationHorizontal: + return CGRectMake(currentFrame.origin.x - currentFrame.size.width, currentFrame.origin.y, currentFrame.size.width, currentFrame.size.height); + } +} + +- (CGRect)currentFrame { + return _rootView.bounds; +} + +- (CGRect)afterFrame { + CGRect currentFrame = self.currentFrame; + switch(_orientation) { + case MobilyPageControllerOrientationVertical: + return CGRectMake(currentFrame.origin.x, currentFrame.origin.y + currentFrame.size.height, currentFrame.size.width, currentFrame.size.height); + case MobilyPageControllerOrientationHorizontal: + return CGRectMake(currentFrame.origin.x + currentFrame.size.width, currentFrame.origin.y, currentFrame.size.width, currentFrame.size.height); + } +} + +- (CGRect)beforeDecorFrame { + CGRect result = CGRectZero; + CGRect beforeFrame = self.beforeFrame; + switch(_orientation) { + case MobilyPageControllerOrientationVertical: + result.origin.x = CGRectGetMidX(beforeFrame) - (_beforeDecorSize.width * 0.5f); + result.origin.y = CGRectGetMaxY(beforeFrame) - _beforeDecorSize.height; + result.size.width = _beforeDecorSize.width; + result.size.height = _beforeDecorSize.height; + break; + case MobilyPageControllerOrientationHorizontal: + result.origin.x = CGRectGetMaxX(beforeFrame) - _beforeDecorSize.width; + result.origin.y = CGRectGetMidY(beforeFrame) - (_beforeDecorSize.height * 0.5f); + result.size.width = _beforeDecorSize.width; + result.size.height = _beforeDecorSize.height; + break; + } + result = UIEdgeInsetsInsetRect(result, _beforeDecorInsets); + result.size.width = MAX(0.0f, result.size.width); + result.size.height = MAX(0.0f, result.size.height); + return result; +} + +- (CGRect)beforeDecorFrameFromFrame:(CGRect)currentFrame { + CGRect result = CGRectZero; + CGRect beforeFrame = self.beforeFrame; + switch(_orientation) { + case MobilyPageControllerOrientationVertical: { + CGFloat delta = CGRectGetMinY(currentFrame) - CGRectGetMaxY(beforeFrame); + result.origin.x = CGRectGetMidX(beforeFrame) - (_beforeDecorSize.width * 0.5f); + result.origin.y = (CGRectGetMaxY(beforeFrame) + (delta * 0.5f)) - (_beforeDecorSize.height * 0.5f); + result.size.width = _beforeDecorSize.width; + result.size.height = _beforeDecorSize.height; + break; + } + case MobilyPageControllerOrientationHorizontal: { + CGFloat delta = CGRectGetMinX(currentFrame) - CGRectGetMaxX(beforeFrame); + result.origin.x = (CGRectGetMaxX(beforeFrame) + (delta * 0.5f)) - (_beforeDecorSize.width * 0.5f); + result.origin.y = CGRectGetMidY(beforeFrame) - (_beforeDecorSize.height * 0.5f); + result.size.width = _beforeDecorSize.width; + result.size.height = _beforeDecorSize.height; + break; + } + } + result = UIEdgeInsetsInsetRect(result, _beforeDecorInsets); + result.size.width = MAX(0.0f, result.size.width); + result.size.height = MAX(0.0f, result.size.height); + return result; +} + +- (CGFloat)beforeDecorProgressFromFrame:(CGRect)currentFrame { + CGFloat result = 0.0f; + CGRect beforeFrame = self.beforeFrame; + switch(_orientation) { + case MobilyPageControllerOrientationVertical: { + CGFloat delta = CGRectGetMinY(currentFrame) - CGRectGetMaxY(beforeFrame); + result = MAX(0.0f, MOBILY_FABS(delta) / _beforeDecorSize.height); + break; + } + case MobilyPageControllerOrientationHorizontal: { + CGFloat delta = CGRectGetMinX(currentFrame) - CGRectGetMaxX(beforeFrame); + result = MAX(0.0f, MOBILY_FABS(delta) / _beforeDecorSize.width); + break; + } + } + return result; +} + +- (CGRect)afterDecorFrame { + CGRect result = CGRectZero; + CGRect afterFrame = self.afterFrame; + switch(_orientation) { + case MobilyPageControllerOrientationVertical: + result.origin.x = CGRectGetMidX(afterFrame) - (_afterDecorSize.width * 0.5f); + result.origin.y = CGRectGetMinY(afterFrame); + result.size.width = _beforeDecorSize.width; + result.size.height = _beforeDecorSize.height; + break; + case MobilyPageControllerOrientationHorizontal: + result.origin.x = CGRectGetMinX(afterFrame); + result.origin.y = CGRectGetMidY(afterFrame) - (_afterDecorSize.height * 0.5f); + result.size.width = _afterDecorSize.width; + result.size.height = _afterDecorSize.height; + break; + } + result = UIEdgeInsetsInsetRect(result, _afterDecorInsets); + result.size.width = MAX(0.0f, result.size.width); + result.size.height = MAX(0.0f, result.size.height); + return result; +} + +- (CGRect)afterDecorFrameFromFrame:(CGRect)currentFrame { + CGRect result = CGRectZero; + CGRect afterFrame = self.afterFrame; + switch(_orientation) { + case MobilyPageControllerOrientationVertical: { + CGFloat delta = CGRectGetMinY(afterFrame) - CGRectGetMaxY(currentFrame); + result.origin.x = CGRectGetMidX(afterFrame) - (_afterDecorSize.width * 0.5f); + result.origin.y = (CGRectGetMinY(afterFrame) - (delta * 0.5f)) - (_afterDecorSize.height * 0.5f); + result.size.width = _afterDecorSize.width; + result.size.height = _afterDecorSize.height; + break; + } + case MobilyPageControllerOrientationHorizontal: { + CGFloat delta = CGRectGetMinX(afterFrame) - CGRectGetMaxX(currentFrame); + result.origin.x = CGRectGetMinX(afterFrame) - (delta * 0.5f) - (_afterDecorSize.width * 0.5f); + result.origin.y = CGRectGetMidY(afterFrame) - (_afterDecorSize.height * 0.5f); + result.size.width = _afterDecorSize.width; + result.size.height = _afterDecorSize.height; + break; + } + } + result = UIEdgeInsetsInsetRect(result, _afterDecorInsets); + result.size.width = MAX(0.0f, result.size.width); + result.size.height = MAX(0.0f, result.size.height); + return result; +} + +- (CGFloat)afterDecorProgressFromFrame:(CGRect)currentFrame { + CGFloat result = 0.0f; + CGRect afterFrame = self.afterFrame; + switch(_orientation) { + case MobilyPageControllerOrientationVertical: { + CGFloat delta = CGRectGetMinY(afterFrame) - CGRectGetMaxY(currentFrame); + result = MAX(0.0f, MOBILY_FABS(delta) / _afterDecorSize.height); + break; + } + case MobilyPageControllerOrientationHorizontal: { + CGFloat delta = CGRectGetMinX(afterFrame) - CGRectGetMaxX(currentFrame); + result = MAX(0.0f, MOBILY_FABS(delta) / _afterDecorSize.width); + break; + } + } + return result; +} + +- (void)panGestureHandle:(UIPanGestureRecognizer*)panGesture { + CGPoint currentPosition = [panGesture locationInView:_rootView]; + switch(panGesture.state) { + case UIGestureRecognizerStateBegan: { + _panBeganPosition = currentPosition; + break; + } + case UIGestureRecognizerStateChanged: { + CGPoint offset = CGPointZero; + if(_userInteractionEnabled == YES) { + switch(_orientation) { + case MobilyPageControllerOrientationVertical: + offset.y = currentPosition.y - _panBeganPosition.y; + break; + case MobilyPageControllerOrientationHorizontal: + offset.x = currentPosition.x - _panBeganPosition.x; + break; + } + if(_friendlyGestures.count > 0) { + for(UIGestureRecognizer* gesture in _friendlyGestures) { + if([gesture.view isKindOfClass:UIScrollView.class] == YES) { + UIScrollView* scrollView = (UIScrollView*)gesture.view; + if(scrollView.scrollEnabled == YES) { + UIEdgeInsets contentInsets = scrollView.contentInset; + CGPoint contentOffset = scrollView.contentOffset; + CGSize contentSize = scrollView.contentSize; + CGRect frame = scrollView.frame; + switch(_orientation) { + case MobilyPageControllerOrientationVertical: { + if(((contentOffset.y + contentInsets.top) <= offset.y) && (offset.y > 0.0f)) { + scrollView.moContentOffsetY = -contentInsets.top; + scrollView.scrollEnabled = NO; + } else if(((contentOffset.y + frame.size.height) >= contentSize.height + offset.y) && (offset.y < 0.0f)) { + scrollView.moContentOffsetY = (contentSize.height - frame.size.height) + contentInsets.bottom; + scrollView.scrollEnabled = NO; + } else { + _panBeganPosition.y = currentPosition.y; + } + break; + } + case MobilyPageControllerOrientationHorizontal: { + if(((contentOffset.x + contentInsets.left) <= offset.x) && (offset.x > 0.0f)) { + scrollView.moContentOffsetX = -contentInsets.left; + scrollView.scrollEnabled = NO; + } else if(((contentOffset.x + frame.size.width) >= contentSize.width + offset.x) && (offset.x < 0.0f)) { + scrollView.moContentOffsetX = (contentSize.width - frame.size.width) + contentInsets.right; + scrollView.scrollEnabled = NO; + } else { + _panBeganPosition.x = currentPosition.x; + } + break; + } + } + } + } + } + } + CGRect currentFrame = self.currentFrame; + switch(_orientation) { + case MobilyPageControllerOrientationVertical: + offset.y = (currentPosition.y - _panBeganPosition.y) * _draggingRate; + if(_allowBeforeController == YES) { + if((currentFrame.origin.y + offset.y) > 0.0f) { + offset.y = (_bounceRate > 0.0f) ? offset.y * _bounceRate : 0.0f; + } + } + if(_allowAfterController == YES) { + if((currentFrame.origin.y + offset.y) < 0.0f) { + offset.y = (_bounceRate > 0.0f) ? offset.y * _bounceRate : 0.0f; + } + } + break; + case MobilyPageControllerOrientationHorizontal: + offset.x = (currentPosition.x - _panBeganPosition.x) * _draggingRate; + if(_allowBeforeController == YES) { + if((currentFrame.origin.x + offset.x) > 0.0f) { + offset.x = (_bounceRate > 0.0f) ? offset.x * _bounceRate : 0.0f; + } + } + if(_allowAfterController == YES) { + if((currentFrame.origin.x + offset.x) < 0.0f) { + offset.x = (_bounceRate > 0.0f) ? offset.x * _bounceRate : 0.0f; + } + } + break; + } + currentFrame = CGRectOffset(currentFrame, floorf(offset.x), floorf(offset.y)); + _controller.view.frame = currentFrame; + if(_beforeDecorView != nil) { + _beforeDecorView.frame = [self beforeDecorFrameFromFrame:currentFrame]; + if(_canBeforeDecor.applyFromProgress == YES) { + [_beforeDecorView pageController:self applyFromProgress:[self beforeDecorProgressFromFrame:currentFrame]]; + } + } + if(_afterDecorView != nil) { + _afterDecorView.frame = [self afterDecorFrameFromFrame:currentFrame]; + if(_canAfterDecor.applyFromProgress == YES) { + [_afterDecorView pageController:self applyFromProgress:[self afterDecorProgressFromFrame:currentFrame]]; + } + } + } else { + _panBeganPosition = currentPosition; + } + break; + } + case UIGestureRecognizerStateEnded: + case UIGestureRecognizerStateCancelled: { + BOOL needRestore = NO; + switch(_orientation) { + case MobilyPageControllerOrientationVertical: { + CGFloat delta = ((currentPosition.y - _panBeganPosition.y) * _draggingRate) * _bounceRate; + if(delta > _thresholdVertical) { + if(_allowBeforeController == YES) { + UIViewController< MobilyPageControllerDelegate >* controller = nil; + if([_controller respondsToSelector:@selector(beforeControllerInPageController:)] == YES) { + controller = [_controller beforeControllerInPageController:self]; + } + if(controller != nil) { + [self setController:controller direction:MobilyPageControllerDirectionReverse duration:ANIMATION_DURATION animated:YES notification:YES]; + } else { + needRestore = YES; + } + } else { + needRestore = YES; + } + } else if(delta < -_thresholdVertical) { + if(_allowBeforeController == YES) { + UIViewController< MobilyPageControllerDelegate >* controller = nil; + if([_controller respondsToSelector:@selector(afterControllerInPageController:)] == YES) { + controller = [_controller afterControllerInPageController:self]; + } + if(controller != nil) { + [self setController:controller direction:MobilyPageControllerDirectionForward duration:ANIMATION_DURATION animated:YES notification:YES]; + } else { + needRestore = YES; + } + } else { + needRestore = YES; + } + } else { + needRestore = YES; + } + break; + } + case MobilyPageControllerOrientationHorizontal: { + CGFloat delta = ((currentPosition.x - _panBeganPosition.x) * _draggingRate) * _bounceRate; + if(delta > _thresholdHorizontal) { + if(_allowBeforeController == YES) { + UIViewController< MobilyPageControllerDelegate >* controller = nil; + if([_controller respondsToSelector:@selector(beforeControllerInPageController:)] == YES) { + controller = [_controller beforeControllerInPageController:self]; + } + if(controller != nil) { + [self setController:controller direction:MobilyPageControllerDirectionReverse duration:ANIMATION_DURATION animated:YES notification:YES]; + } else { + needRestore = YES; + } + } else { + needRestore = YES; + } + } else if(delta < -_thresholdHorizontal) { + if(_allowBeforeController == YES) { + UIViewController< MobilyPageControllerDelegate >* controller = nil; + if([_controller respondsToSelector:@selector(afterControllerInPageController:)] == YES) { + controller = [_controller afterControllerInPageController:self]; + } + if(controller != nil) { + [self setController:controller direction:MobilyPageControllerDirectionForward duration:ANIMATION_DURATION animated:YES notification:YES]; + } else { + needRestore = YES; + } + } else { + needRestore = YES; + } + } else { + needRestore = YES; + } + break; + } + } + if(needRestore == YES) { + _rootView.userInteractionEnabled = NO; + [UIView animateWithDuration:ANIMATION_DURATION + animations:^{ + CGRect currentFrame = self.currentFrame; + _controller.view.frame = currentFrame; + if(_beforeDecorView != nil) { + _beforeDecorView.frame = [self beforeDecorFrameFromFrame:currentFrame]; + if(_canBeforeDecor.applyFromProgress == YES) { + [_beforeDecorView pageController:self applyFromProgress:[self beforeDecorProgressFromFrame:currentFrame]]; + } + } + if(_afterDecorView != nil) { + _afterDecorView.frame = [self afterDecorFrameFromFrame:currentFrame]; + if(_canAfterDecor.applyFromProgress == YES) { + [_afterDecorView pageController:self applyFromProgress:[self afterDecorProgressFromFrame:currentFrame]]; + } + } + } completion:^(BOOL finished) { + _rootView.userInteractionEnabled = YES; + }]; + } + for(UIGestureRecognizer* gesture in _friendlyGestures) { + if([gesture.view isKindOfClass:UIScrollView.class] == YES) { + UIScrollView* scrollView = (UIScrollView*)gesture.view; + scrollView.scrollEnabled = YES; + } + } + [_friendlyGestures removeAllObjects]; + break; + } + default: + break; + } +} + +#pragma mark UIGestureRecognizerDelegate + +- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gesture { + BOOL result = NO; + if(gesture == _panGesture) { + if(_userInteractionEnabled == YES) { + CGPoint translation = [_panGesture translationInView:_rootView]; + switch(_orientation) { + case MobilyPageControllerOrientationVertical: + if(MOBILY_FABS(translation.y) >= MOBILY_FABS(translation.x)) { + if(translation.y > 0.0f) { + result = (_allowBeforeController == YES) || (_bounceRate > 0.0f); + } else if(translation.y < 0.0f) { + result = (_allowAfterController == YES) || (_bounceRate > 0.0f); + } else { + result = (_allowAfterController == YES) || (_allowBeforeController == YES); + } + } + break; + case MobilyPageControllerOrientationHorizontal: + if(MOBILY_FABS(translation.x) >= MOBILY_FABS(translation.y)) { + if(translation.x > 0.0f) { + result = (_allowBeforeController == YES) || (_bounceRate > 0.0f); + } else if(translation.x < 0.0f) { + result = (_allowAfterController == YES) || (_bounceRate > 0.0f); + } else { + result = (_allowAfterController == YES) || (_allowBeforeController == YES); + } + } + break; + } + } + } + return result; +} + +- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gesture shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGesture { + if([otherGesture isKindOfClass:UIPanGestureRecognizer.class] == YES) { + if([otherGesture.view isKindOfClass:UIScrollView.class] == YES) { + if([_friendlyGestures containsObject:otherGesture] == NO) { + [_friendlyGestures addObject:otherGesture]; + } + return YES; + } + } + return NO; +} + +#pragma mark MobilySlideControllerDelegate + +- (BOOL)canShowLeftControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(canShowLeftControllerInSlideController:)] == YES) { + return [controller canShowLeftControllerInSlideController:slideController]; + } + return YES; +} + +- (void)willShowLeftControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(willShowLeftControllerInSlideController:duration:)] == YES) { + [controller willShowLeftControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didShowLeftControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(didShowLeftControllerInSlideController:)] == YES) { + [controller didShowLeftControllerInSlideController:slideController]; + } +} + +- (void)willHideLeftControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(willHideLeftControllerInSlideController:duration:)] == YES) { + [controller willHideLeftControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didHideLeftControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(didHideLeftControllerInSlideController:)] == YES) { + [controller didHideLeftControllerInSlideController:slideController]; + } +} + +- (BOOL)canShowRightControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(canShowRightControllerInSlideController:)] == YES) { + return [controller canShowRightControllerInSlideController:slideController]; + } + return YES; +} + +- (void)willShowRightControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(willShowRightControllerInSlideController:duration:)] == YES) { + [controller willShowRightControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didShowRightControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(didShowRightControllerInSlideController:)] == YES) { + [controller didShowRightControllerInSlideController:slideController]; + } +} + +- (void)willHideRightControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(willHideRightControllerInSlideController:duration:)] == YES) { + [controller willHideRightControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didHideRightControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(didHideRightControllerInSlideController:)] == YES) { + [controller didHideRightControllerInSlideController:slideController]; + } +} + +- (BOOL)canShowControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(canShowControllerInSlideController:)] == YES) { + return [controller canShowControllerInSlideController:slideController]; + } + return YES; +} + +- (void)willShowControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(willShowControllerInSlideController:duration:)] == YES) { + [controller willShowControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didShowControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(didShowControllerInSlideController:)] == YES) { + [controller didShowControllerInSlideController:slideController]; + } +} + +- (void)willHideControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(willHideControllerInSlideController:duration:)] == YES) { + [controller willHideControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didHideControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(didHideControllerInSlideController:)] == YES) { + [controller didHideControllerInSlideController:slideController]; + } +} + +- (void)willBeganLeftSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(willBeganLeftSwipeInSlideController:)] == YES) { + [controller willBeganLeftSwipeInSlideController:slideController]; + } +} + +- (void)didBeganLeftSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(didBeganLeftSwipeInSlideController:)] == YES) { + [controller didBeganLeftSwipeInSlideController:slideController]; + } +} + +- (void)movingLeftSwipeInSlideController:(MobilySlideController*)slideController progress:(CGFloat)progress { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(movingLeftSwipeInSlideController:progress:)] == YES) { + [controller movingLeftSwipeInSlideController:slideController progress:progress]; + } +} + +- (void)willEndedLeftSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(willEndedLeftSwipeInSlideController:)] == YES) { + [controller willEndedLeftSwipeInSlideController:slideController]; + } +} + +- (void)didEndedLeftSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(didEndedLeftSwipeInSlideController:)] == YES) { + [controller didEndedLeftSwipeInSlideController:slideController]; + } +} + +- (void)willBeganRightSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(willBeganRightSwipeInSlideController:)] == YES) { + [controller willBeganRightSwipeInSlideController:slideController]; + } +} + +- (void)didBeganRightSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(didBeganRightSwipeInSlideController:)] == YES) { + [controller didBeganRightSwipeInSlideController:slideController]; + } +} + +- (void)movingRightSwipeInSlideController:(MobilySlideController*)slideController progress:(CGFloat)progress { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(movingRightSwipeInSlideController:progress:)] == YES) { + [controller movingRightSwipeInSlideController:slideController progress:progress]; + } +} + +- (void)willEndedRightSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(willEndedRightSwipeInSlideController:)] == YES) { + [controller willEndedRightSwipeInSlideController:slideController]; + } +} + +- (void)didEndedRightSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(didEndedRightSwipeInSlideController:)] == YES) { + [controller didEndedRightSwipeInSlideController:slideController]; + } +} + +- (void)willBeganSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(willBeganSwipeInSlideController:)] == YES) { + [controller willBeganSwipeInSlideController:slideController]; + } +} + +- (void)didBeganSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(didBeganSwipeInSlideController:)] == YES) { + [controller didBeganSwipeInSlideController:slideController]; + } +} + +- (void)movingSwipeInSlideController:(MobilySlideController*)slideController progress:(CGFloat)progress { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(movingSwipeInSlideController:progress:)] == YES) { + [controller movingSwipeInSlideController:slideController progress:progress]; + } +} + +- (void)willEndedSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(willEndedSwipeInSlideController:)] == YES) { + [controller willEndedSwipeInSlideController:slideController]; + } +} + +- (void)didEndedSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)_controller; + if([controller respondsToSelector:@selector(didEndedSwipeInSlideController:)] == YES) { + [controller didEndedSwipeInSlideController:slideController]; + } +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UIViewController (MobilyPageController) + +- (void)setMoPageController:(MobilyPageController*)moPageController { + objc_setAssociatedObject(self, @selector(moPageController), moPageController, OBJC_ASSOCIATION_ASSIGN); +} + +- (MobilyPageController*)moPageController { + MobilyPageController* controller = objc_getAssociatedObject(self, @selector(moPageController)); + if(controller == nil) { + controller = self.parentViewController.moPageController; + } + return controller; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyPopoverController.h b/Sources/MobilyCore/MobilyPopoverController.h new file mode 100644 index 0000000..18055bb --- /dev/null +++ b/Sources/MobilyCore/MobilyPopoverController.h @@ -0,0 +1,61 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyPopoverController : NSObject + +@property(nonatomic, readonly, weak) UIViewController* controller; + ++ (instancetype)presentController:(UIViewController*)controller fromView:(UIView*)view arrowTargetView:(UIView*)arrowTargetView arrowDirection:(UIPopoverArrowDirection)arrowDirection animated:(BOOL)animated; + +- (instancetype)initWithController:(UIViewController*)controller fromView:(UIView*)view arrowTargetView:(UIView*)arrowTargetView arrowDirection:(UIPopoverArrowDirection)arrowDirection; + +- (void)presentAnimated:(BOOL)animated; +- (void)dismissAnimated:(BOOL)animated; + +@end + +/*--------------------------------------------------*/ + +@interface UIViewController (MobilyPopoverController) + +@property(nonatomic, readwrite, strong) MobilyPopoverController* moPopoverController; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyPopoverController.m b/Sources/MobilyCore/MobilyPopoverController.m new file mode 100644 index 0000000..c76e1a8 --- /dev/null +++ b/Sources/MobilyCore/MobilyPopoverController.m @@ -0,0 +1,157 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyPopoverController () < UIPopoverControllerDelegate > + +@property(nonatomic, readwrite, weak) UIViewController* controller; +@property(nonatomic, readwrite, strong) UIPopoverController* popover; +@property(nonatomic, readwrite, strong) UIView* view; +@property(nonatomic, readwrite, strong) UIView* arrowTargetView; +@property(nonatomic, readwrite, assign) UIPopoverArrowDirection arrowDirection; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyPopoverController + +#pragma mark Init / Free + +- (instancetype)initWithController:(UIViewController*)controller fromView:(UIView*)view arrowTargetView:(UIView*)arrowTargetView arrowDirection:(UIPopoverArrowDirection)arrowDirection { + self = [super init]; + if(self != nil) { + self.controller = controller; + self.popover = [[UIPopoverController alloc] initWithContentViewController:controller]; + self.popover.delegate = self; + self.view = view; + self.arrowTargetView = arrowTargetView; + self.arrowDirection = arrowDirection; + [self setup]; + } + return self; +} + +- (void)setup { +} + +#pragma mark Property + +- (void)setController:(UIViewController*)controller { + if(_controller != controller) { + if(_controller != nil) { + _controller.moPopoverController = nil; + } + _controller = controller; + if(_controller != nil) { + _controller.moPopoverController = self; + } + } +} + +- (void)setPopover:(UIPopoverController*)popover { + if(_popover != popover) { + _popover = popover; + if(_popover != nil) { + _popover.delegate = self; + } + } +} + +#pragma mark Public static + ++ (instancetype)presentController:(UIViewController*)controller fromView:(UIView*)view arrowTargetView:(UIView*)arrowTargetView arrowDirection:(UIPopoverArrowDirection)arrowDirection animated:(BOOL)animated { + MobilyPopoverController* popoverController = [[MobilyPopoverController alloc] initWithController:controller fromView:view arrowTargetView:arrowTargetView arrowDirection:arrowDirection]; + [popoverController presentAnimated:animated]; + return popoverController; +} + +#pragma mark Public + +- (void)presentAnimated:(BOOL)animated { + [self.popover presentPopoverFromRect:[_arrowTargetView convertRect:[_arrowTargetView bounds] toView:_view] inView:_view permittedArrowDirections:_arrowDirection animated:animated]; +} + +- (void)dismissAnimated:(BOOL)animated { + [_popover dismissPopoverAnimated:animated]; + self.controller = nil; +} + +#pragma mark UIPopoverControllerDelegate + +- (void)popoverController:(UIPopoverController*)popoverController willRepositionPopoverToRect:(inout CGRect*)rect inView:(inout UIView**)view { + *rect = [_arrowTargetView convertRect:[_arrowTargetView bounds] toView:*view]; +} + +- (void)popoverControllerDidDismissPopover:(UIPopoverController*)popoverController { + self.controller = nil; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UIViewController (MobilyPopoverController) + +- (void)setMoPopoverController:(MobilyPopoverController*)moPopoverController { + objc_setAssociatedObject(self, @selector(moPopoverController), moPopoverController, OBJC_ASSOCIATION_RETAIN); +} + +- (MobilyPopoverController*)moPopoverController { + MobilyPopoverController* controller = objc_getAssociatedObject(self, @selector(moPopoverController)); + if(controller == nil) { + controller = self.parentViewController.moPopoverController; + } + return controller; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyPressAndHoldGestureRecognizer.h b/Sources/MobilyCore/MobilyPressAndHoldGestureRecognizer.h new file mode 100755 index 0000000..6c42bd5 --- /dev/null +++ b/Sources/MobilyCore/MobilyPressAndHoldGestureRecognizer.h @@ -0,0 +1,47 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyPressAndHoldGestureRecognizer : UILongPressGestureRecognizer + +@property(nonatomic, readwrite, assign) NSTimeInterval reportInterval; +@property(nonatomic, readwrite, assign) CGFloat allowableMovementWhenRecognized; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyPressAndHoldGestureRecognizer.m b/Sources/MobilyCore/MobilyPressAndHoldGestureRecognizer.m new file mode 100755 index 0000000..183bc1b --- /dev/null +++ b/Sources/MobilyCore/MobilyPressAndHoldGestureRecognizer.m @@ -0,0 +1,137 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyPressAndHoldGestureRecognizer () { +@protected + NSMutableArray* _actions; + NSTimer* _repeatedlyReportTimer; + CGPoint _beginLocation; +} + +- (void)_invokeMethods; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyPressAndHoldGestureRecognizer + +#pragma mark Init / Free + +- (id)initWithTarget:(id)target action:(SEL)action { + self = [super initWithTarget:nil action:NULL]; + if(self) { + _actions = [NSMutableArray new]; + if((target != nil) && (action != NULL)) { + [_actions addObject:[MobilyEventSelector eventWithTarget:target action:action]]; + } + _reportInterval = 0.5f; + _allowableMovementWhenRecognized = 3.0f; + } + return self; +} + +#pragma mark Public override + +- (void)setState:(UIGestureRecognizerState)state { + if (state == UIGestureRecognizerStateBegan) { + _repeatedlyReportTimer = [NSTimer scheduledTimerWithTimeInterval:_reportInterval target:self selector:@selector(_invokeMethods) userInfo:nil repeats:YES]; + } + [super setState:state]; +} + +- (void)reset { + if(_repeatedlyReportTimer != nil) { + [_repeatedlyReportTimer invalidate]; + _repeatedlyReportTimer = nil; + } + [super reset]; + if((self.state == UIGestureRecognizerStateCancelled) || (self.state == UIGestureRecognizerStateEnded)) { + [self _invokeMethods]; + } +} + +- (void)addTarget:(id)target action:(SEL)action { + if((target != nil) && (action != NULL)) { + [_actions addObject:[MobilyEventSelector eventWithTarget:target action:action]]; + } +} + +- (void)removeTarget:(id)target action:(SEL)action { + [_actions moEach:^(MobilyEventSelector* event) { + if((event.target == target) && (event.action == action)) { + [_actions removeObject:event]; + } + }]; + [super removeTarget:target action:action]; +} + +#pragma mark Public override + +- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { + _beginLocation = [touches.anyObject locationInView:self.view]; + [super touchesBegan:touches withEvent:event]; +} + +- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { + if((self.state == UIGestureRecognizerStateBegan) || (self.state == UIGestureRecognizerStateChanged)) { + CGPoint newLocation = [touches.anyObject locationInView:self.view]; + CGFloat dx = newLocation.x - _beginLocation.x; + CGFloat dy = newLocation.y - _beginLocation.y; + if(MOBILY_SQRT(dx * dx + dy * dy) > _allowableMovementWhenRecognized) { + self.state = UIGestureRecognizerStateEnded; + } + } + [super touchesMoved:touches withEvent:event]; +} + +- (void)_invokeMethods { + [_actions moEach:^(MobilyEventSelector* event) { + [event fireSender:self object:nil]; + }]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/NS/RegExpParser/MobilyRegExpParser.h b/Sources/MobilyCore/MobilyRegExpParser.h similarity index 83% rename from Classes/NS/RegExpParser/MobilyRegExpParser.h rename to Sources/MobilyCore/MobilyRegExpParser.h index 90251ba..455eefd 100644 --- a/Classes/NS/RegExpParser/MobilyRegExpParser.h +++ b/Sources/MobilyCore/MobilyRegExpParser.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,7 +33,7 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyNS.h" +#import /*--------------------------------------------------*/ @@ -41,7 +41,8 @@ /*--------------------------------------------------*/ -@interface MobilyRegExpParser : NSObject +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyRegExpParser : NSObject < MobilyObject > @property(nonatomic, readwrite, strong) NSString* string; @property(nonatomic, readwrite, strong) NSString* expression; @@ -49,14 +50,17 @@ @property(nonatomic, readonly, strong) NSArray* matches; @property(nonatomic, readonly, strong) NSString* result; -- (id)initWithExpression:(NSString*)expression pattern:(NSString*)pattern; -- (id)initWithSting:(NSString*)string expression:(NSString*)expression pattern:(NSString*)pattern; +- (instancetype)initWithExpression:(NSString*)expression pattern:(NSString*)pattern; +- (instancetype)initWithSting:(NSString*)string expression:(NSString*)expression pattern:(NSString*)pattern; + +- (void)setup NS_REQUIRES_SUPER; @end /*--------------------------------------------------*/ -@interface MobilyRegExpMatch : NSObject +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyRegExpMatch : NSObject < MobilyObject > @property(nonatomic, readonly, strong) NSString* originalString; @property(nonatomic, readonly, strong) NSArray* originalSubStrings; @@ -65,6 +69,8 @@ @property(nonatomic, readonly, strong) NSString* resultString; @property(nonatomic, readonly, assign) NSRange resultRange; +- (void)setup NS_REQUIRES_SUPER; + @end /*--------------------------------------------------*/ diff --git a/Classes/NS/RegExpParser/MobilyRegExpParser.m b/Sources/MobilyCore/MobilyRegExpParser.m similarity index 64% rename from Classes/NS/RegExpParser/MobilyRegExpParser.m rename to Sources/MobilyCore/MobilyRegExpParser.m index 2e54c0b..13b6a56 100644 --- a/Classes/NS/RegExpParser/MobilyRegExpParser.m +++ b/Sources/MobilyCore/MobilyRegExpParser.m @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -32,16 +32,22 @@ /* OTHER DEALINGS IN THE SOFTWARE. */ /* */ /*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ -#import "MobilyRegExpParser.h" +#import /*--------------------------------------------------*/ -@interface MobilyRegExpParser () - -@property(nonatomic, readwrite, strong) NSArray* matches; -@property(nonatomic, readwrite, strong) NSString* result; -@property(nonatomic, readwrite, assign, getter=isNeedApplyParser) BOOL needApplyParser; +@interface MobilyRegExpParser () { +@protected + NSString* _string; + NSString* _expression; + NSString* _pattern; + NSArray* _matches; + NSString* _result; + BOOL _needApplyParser; +} - (void)applyParserIfNeed; - (void)applyParser; @@ -52,7 +58,14 @@ - (void)applyParser; #pragma mark - /*--------------------------------------------------*/ -@interface MobilyRegExpMatch () +@interface MobilyRegExpMatch () { +@protected + NSString* _originalString; + NSArray* _originalSubStrings; + NSRange _originalRange; + NSString* _resultString; + NSRange _resultRange; +} @property(nonatomic, readwrite, strong) NSString* originalString; @property(nonatomic, readwrite, strong) NSArray* originalSubStrings; @@ -68,67 +81,71 @@ @interface MobilyRegExpMatch () @implementation MobilyRegExpParser -#pragma mark Standart +#pragma mark Synthesize -- (id)init { +@synthesize string = _string; +@synthesize expression = _expression; +@synthesize pattern = _pattern; +@synthesize matches = _matches; +@synthesize result = _result; + +#pragma mark Init / Free + +- (instancetype)init { self = [super init]; if(self != nil) { - [self setNeedApplyParser:NO]; + _needApplyParser = NO; + [self setup]; } return self; } -- (id)initWithExpression:(NSString*)expression pattern:(NSString*)pattern { +- (instancetype)initWithExpression:(NSString*)expression pattern:(NSString*)pattern { self = [super init]; if(self != nil) { - MOBILY_SAFE_SETTER(_expression, expression); - MOBILY_SAFE_SETTER(_pattern, pattern); - [self setNeedApplyParser:NO]; + _expression = expression; + _pattern = pattern; + _needApplyParser = NO; + [self setup]; } return self; } -- (id)initWithSting:(NSString*)string expression:(NSString*)expression pattern:(NSString*)pattern { +- (instancetype)initWithSting:(NSString*)string expression:(NSString*)expression pattern:(NSString*)pattern { self = [super init]; if(self != nil) { - MOBILY_SAFE_SETTER(_string, string); - MOBILY_SAFE_SETTER(_expression, expression); - MOBILY_SAFE_SETTER(_pattern, pattern); - [self setNeedApplyParser:YES]; + _string = string; + _expression = expression; + _pattern = pattern; + _needApplyParser = YES; + [self setup]; } return self; } -- (void)dealloc { - [self setString:nil]; - [self setExpression:nil]; - [self setPattern:nil]; - [self setMatches:nil]; - [self setResult:nil]; - - MOBILY_SAFE_DEALLOC; +- (void)setup { } #pragma mark Property - (void)setString:(NSString*)string { if([_string isEqualToString:string] == NO) { - MOBILY_SAFE_SETTER(_string, string); - [self setNeedApplyParser:YES]; + _string = string; + _needApplyParser = YES; } } - (void)setExpression:(NSString*)expression { if([_expression isEqualToString:expression] == NO) { - MOBILY_SAFE_SETTER(_expression, expression); - [self setNeedApplyParser:YES]; + _expression = expression; + _needApplyParser = YES; } } - (void)setPattern:(NSString*)pattern { if([_pattern isEqualToString:pattern] == NO) { - MOBILY_SAFE_SETTER(_pattern, pattern); - [self setNeedApplyParser:YES]; + _pattern = pattern; + _needApplyParser = YES; } } @@ -146,22 +163,22 @@ - (NSString*)result { - (void)applyParserIfNeed { if(_needApplyParser == YES) { - [self setNeedApplyParser:NO]; + _needApplyParser = NO; [self applyParser]; } } - (void)applyParser { - if([_string length] > 0) { - NSMutableArray* resultMatches = [NSMutableArray array]; + if(_string.length > 0) { + NSMutableArray* resultMatches = NSMutableArray.array; NSMutableString* resultString = [NSMutableString stringWithString:_string]; NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:_expression options:0 error:nil]; if(regex != nil) { __block NSInteger offset = 0; - [regex enumerateMatchesInString:_string options:0 range:NSMakeRange(0, [_string length]) usingBlock:^(NSTextCheckingResult* checkingResult, NSMatchingFlags flags, BOOL* stop) { - NSUInteger numberOfRanges = [checkingResult numberOfRanges]; + [regex enumerateMatchesInString:_string options:0 range:NSMakeRange(0, _string.length) usingBlock:^(NSTextCheckingResult* checkingResult, NSMatchingFlags flags __unused, BOOL* stop __unused) { + NSUInteger numberOfRanges = checkingResult.numberOfRanges; - NSString* matchOriginalString = [_string substringWithRange:[checkingResult range]]; + NSString* matchOriginalString = [_string substringWithRange:checkingResult.range]; NSMutableArray* matchOriginalSubStrings = [NSMutableArray arrayWithCapacity:numberOfRanges]; for(NSUInteger rangeIndex = 1; rangeIndex < numberOfRanges; rangeIndex++) { NSRange range = [checkingResult rangeAtIndex:rangeIndex]; @@ -169,20 +186,20 @@ - (void)applyParser { [matchOriginalSubStrings addObject:substring]; } - NSRange matchOriginalRange = [checkingResult range]; + NSRange matchOriginalRange = checkingResult.range; NSString* matchResultString = [regex replacementStringForResult:checkingResult inString:_string offset:0 template:(_pattern != nil) ? _pattern : @""]; - NSRange matchResultRange = NSMakeRange(matchOriginalRange.location + offset, [matchResultString length]); + NSRange matchResultRange = NSMakeRange(matchOriginalRange.location + offset, matchResultString.length); [resultString replaceCharactersInRange:NSMakeRange(matchOriginalRange.location + offset, matchOriginalRange.length) withString:matchResultString]; - MobilyRegExpMatch* match = [[MobilyRegExpMatch alloc] init]; + MobilyRegExpMatch* match = [MobilyRegExpMatch new]; if(match != nil) { - [match setOriginalString:matchOriginalString]; - [match setOriginalSubStrings:matchOriginalSubStrings]; - [match setOriginalRange:matchOriginalRange]; - [match setResultString:matchResultString]; - [match setResultRange:matchResultRange]; + match.originalString = matchOriginalString; + match.originalSubStrings = matchOriginalSubStrings; + match.originalRange = matchOriginalRange; + match.resultString = matchResultString; + match.resultRange = matchResultRange; [resultMatches addObject:match]; } @@ -190,11 +207,11 @@ - (void)applyParser { offset += (matchResultRange.length - matchOriginalRange.length); }]; } - [self setMatches:[resultMatches copy]]; - [self setResult:[resultString copy]]; + _matches = [resultMatches copy]; + _result = [resultString copy]; } else { - [self setMatches:nil]; - [self setResult:nil]; + _matches = nil; + _result = nil; } } @@ -206,14 +223,25 @@ - (void)applyParser { @implementation MobilyRegExpMatch -#pragma mark Standart +#pragma mark Synthesize + +@synthesize originalString = _originalString; +@synthesize originalSubStrings = _originalSubStrings; +@synthesize originalRange = _originalRange; +@synthesize resultString = _resultString; +@synthesize resultRange = _resultRange; + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} -- (void)dealloc { - [self setOriginalString:nil]; - [self setOriginalSubStrings:nil]; - [self setResultString:nil]; - - MOBILY_SAFE_DEALLOC; +- (void)setup { } @end diff --git a/Classes/UI/ViewScroll/MobilyViewScroll.h b/Sources/MobilyCore/MobilyScrollView.h similarity index 82% rename from Classes/UI/ViewScroll/MobilyViewScroll.h rename to Sources/MobilyCore/MobilyScrollView.h index 5b7f3bf..71383fb 100644 --- a/Classes/UI/ViewScroll/MobilyViewScroll.h +++ b/Sources/MobilyCore/MobilyScrollView.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,24 +33,24 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyBuilder.h" +#import /*--------------------------------------------------*/ -typedef NS_ENUM(NSInteger, MobilyViewScrollDirection) { - MobilyViewScrollDirectionStretch, - MobilyViewScrollDirectionHorizontal, - MobilyViewScrollDirectionVertical +typedef NS_ENUM(NSInteger, MobilyScrollViewDirection) { + MobilyScrollViewDirectionStretch, + MobilyScrollViewDirectionHorizontal, + MobilyScrollViewDirectionVertical }; /*--------------------------------------------------*/ -@interface MobilyViewScroll : UIScrollView< MobilyBuilderObject > +@interface MobilyScrollView : UIScrollView< MobilyBuilderObject > -@property(nonatomic, readwrite, assign) MobilyViewScrollDirection direction; +@property(nonatomic, readwrite, assign) IBInspectable MobilyScrollViewDirection direction; @property(nonatomic, readwrite, strong) IBOutlet UIView* rootView; -- (void)setupView; +- (void)setup NS_REQUIRES_SUPER; @end diff --git a/Sources/MobilyCore/MobilyScrollView.m b/Sources/MobilyCore/MobilyScrollView.m new file mode 100644 index 0000000..4aa7187 --- /dev/null +++ b/Sources/MobilyCore/MobilyScrollView.m @@ -0,0 +1,229 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyScrollView () + +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewL; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewT; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewR; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewB; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewW; +@property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintRootViewH; + +- (void)linkConstraint; +- (void)unlinkConstraint; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyScrollView + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; + +#pragma mark NSKeyValueCoding + +#pragma mark Init / Free + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + self.direction = MobilyScrollViewDirectionVertical; + + [self moRegisterAdjustmentResponder]; +} + +- (void)dealloc { + [self moUnregisterAdjustmentResponder]; +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return self.subviews; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + [self addSubview:(UIView*)objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + [self moRemoveSubview:(UIView*)objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark Public + +#pragma mark Property + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRootViewL, constraintRootViewL, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRootViewT, constraintRootViewT, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRootViewR, constraintRootViewR, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRootViewB, constraintRootViewB, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRootViewW, constraintRootViewW, self, { +}, { +}) + +MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(ConstraintRootViewH, constraintRootViewH, self, { +}, { +}) + +- (void)setDirection:(MobilyScrollViewDirection)direction { + if(_direction != direction) { + if(_rootView != nil) { + [self unlinkConstraint]; + } + _direction = direction; + if(_rootView != nil) { + [self linkConstraint]; + } + [self setNeedsLayout]; + } +} + +- (void)setRootView:(UIView*)rootView { + if(_rootView != rootView) { + if(_rootView != nil) { + [self unlinkConstraint]; + [_rootView removeFromSuperview]; + } + _rootView = rootView; + if(_rootView != nil) { + _rootView.translatesAutoresizingMaskIntoConstraints = NO; + [self addSubview:_rootView]; + [self linkConstraint]; + } + [self setNeedsLayout]; + } +} + +#pragma mark Private + +- (void)linkConstraint { + switch(_direction) { + case MobilyScrollViewDirectionStretch: + self.constraintRootViewL = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]; + self.constraintRootViewT = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; + self.constraintRootViewR = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]; + self.constraintRootViewB = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]; + self.constraintRootViewW = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f]; + self.constraintRootViewH = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]; + break; + case MobilyScrollViewDirectionVertical: + self.constraintRootViewT = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]; + self.constraintRootViewB = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; + self.constraintRootViewL = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]; + self.constraintRootViewR = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]; + self.constraintRootViewW = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1.0f constant:0.0f]; + break; + case MobilyScrollViewDirectionHorizontal: + self.constraintRootViewT = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]; + self.constraintRootViewB = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]; + self.constraintRootViewL = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1.0f constant:0.0f]; + self.constraintRootViewR = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1.0f constant:0.0f]; + self.constraintRootViewH = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]; + break; + } +} + +- (void)unlinkConstraint { + self.constraintRootViewL = nil; + self.constraintRootViewT = nil; + self.constraintRootViewR = nil; + self.constraintRootViewB = nil; + self.constraintRootViewW = nil; + self.constraintRootViewH = nil; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySearchBar.h b/Sources/MobilyCore/MobilySearchBar.h new file mode 100644 index 0000000..d9a6b5f --- /dev/null +++ b/Sources/MobilyCore/MobilySearchBar.h @@ -0,0 +1,83 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import +#import + +/*--------------------------------------------------*/ + +@protocol MobilySearchBarDelegate; + +/*--------------------------------------------------*/ + +@interface MobilySearchBar : MobilyBlurView + +@property(nonatomic, readwrite, weak) IBOutlet id< MobilySearchBarDelegate > delegate; +@property(nonatomic, readwrite, assign, getter=isSearching) IBInspectable BOOL searching; +@property(nonatomic, readonly, assign, getter=isEditing) BOOL editing; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat minimalHeight; +@property(nonatomic, readwrite, assign) IBInspectable UIEdgeInsets margin; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat spacing; +@property(nonatomic, readonly, strong) IBInspectable UIColor* separatorColor; +@property(nonatomic, readonly, weak) UIView* separatorView; +@property(nonatomic, readonly, weak) IBOutlet MobilyTextField* searchField; +@property(nonatomic, readwrite, assign) BOOL showCancelButton; +@property(nonatomic, readonly, weak) IBOutlet MobilyButton* cancelButton; + +- (void)setSearching:(BOOL)searching animated:(BOOL)animated complete:(MobilySimpleBlock)complete; +- (void)setEditing:(BOOL)editing animated:(BOOL)animated complete:(MobilySimpleBlock)complete; + +@end + +/*--------------------------------------------------*/ + +@protocol MobilySearchBarDelegate < NSObject > + +@optional +- (void)searchBarBeginSearch:(MobilySearchBar*)searchBar; +- (void)searchBarEndSearch:(MobilySearchBar*)searchBar; + +- (void)searchBarBeginEditing:(MobilySearchBar*)searchBar; +- (void)searchBar:(MobilySearchBar*)searchBar textChanged:(NSString*)textChanged; +- (void)searchBarEndEditing:(MobilySearchBar*)searchBar; + +- (void)searchBarPressedClear:(MobilySearchBar*)searchBar; +- (void)searchBarPressedReturn:(MobilySearchBar*)searchBar; +- (void)searchBarPressedCancel:(MobilySearchBar*)searchBar; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySearchBar.m b/Sources/MobilyCore/MobilySearchBar.m new file mode 100644 index 0000000..8cd9988 --- /dev/null +++ b/Sources/MobilyCore/MobilySearchBar.m @@ -0,0 +1,396 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilySearchBar () < UITextFieldDelegate > { +@protected + __weak id< MobilySearchBarDelegate > _delegate; + BOOL _searching; + BOOL _editing; + CGFloat _minimalHeight; + UIEdgeInsets _margin; + CGFloat _spacing; + __weak UIView* _separatorView; + __weak MobilyTextField* _searchField; + BOOL _showCancelButton; + __weak MobilyButton* _cancelButton; + NSMutableArray* _contentConstraints; +} + +@property(nonatomic, readwrite, weak) UIView* separatorView; +@property(nonatomic, readwrite, weak) MobilyTextField* searchField; +@property(nonatomic, readwrite, weak) MobilyButton* cancelButton; + +- (void)updateAnimated:(BOOL)animated complete:(MobilySimpleBlock)complete; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +static CGFloat MobilySearchBarSeparatorHeight = 0.5f; + +/*--------------------------------------------------*/ + +@implementation MobilySearchBar + +#pragma mark Synthesize + +@synthesize delegate = _delegate; +@synthesize searching = _searching; +@synthesize editing = _editing; +@synthesize minimalHeight = _minimalHeight; +@synthesize margin = _margin; +@synthesize spacing = _spacing; +@synthesize separatorView = _separatorView; +@synthesize searchField = _searchField; +@synthesize showCancelButton = _showCancelButton; +@synthesize cancelButton = _cancelButton; + +#pragma mark Init / Free + +- (void)setup { + [super setup]; + + self.blurEnabled = NO; + self.backgroundColor = MOBILY_COLOR_RGB(201, 201, 206); + + _minimalHeight = 28.0f; + _margin = UIEdgeInsetsMake(8.0f, 8.0f, 8.0f, 8.0f); + _spacing = 6.0f; + _showCancelButton = YES; + _contentConstraints = NSMutableArray.array; +} + +- (void)dealloc { +} + +#pragma mark InterfaceBuilder + +#if TARGET_INTERFACE_BUILDER +- (void)prepareForInterfaceBuilder { + [super prepareForInterfaceBuilder]; + if(self.searchField != nil) { + } + if(self.cancelButton != nil) { + } + if(self.separatorView != nil) { + } +} +#endif + +#pragma mark Property + +- (void)setSearching:(BOOL)searching { + [self setSearching:searching animated:NO complete:nil]; +} + +- (void)setSearching:(BOOL)searching animated:(BOOL)animated complete:(MobilySimpleBlock)complete { + if(_searching != searching) { + _searching = searching; + if(_searching == NO) { + _editing = NO; + self.searchField.clearButtonMode = UITextFieldViewModeNever; + self.searchField.text = @""; + [self.searchField endEditing:NO]; + } + [self updateAnimated:animated complete:complete]; + } +} + +- (void)setEditing:(BOOL)editing { + [self setEditing:editing animated:NO complete:nil]; +} + +- (void)setEditing:(BOOL)editing animated:(BOOL)animated complete:(MobilySimpleBlock)complete { + if(_editing != editing) { + _editing = editing; + if(_editing == YES) { + [self.searchField becomeFirstResponder]; + } else { + [self.searchField endEditing:NO]; + } + [self updateAnimated:animated complete:complete]; + } +} + +- (void)setSeparatorColor:(UIColor*)separatorColor { + self.separatorView.backgroundColor = separatorColor; +} + +- (UIColor*)separatorColor { + return self.separatorView.backgroundColor; +} + +- (void)setSeparatorView:(UIView*)separatorView { + if(_separatorView != separatorView) { + if(_separatorView != nil) { + [_separatorView removeFromSuperview]; + } + _separatorView = separatorView; + if(_separatorView != nil) { + _separatorView.translatesAutoresizingMaskIntoConstraints = NO; + if(_separatorView.superview == nil) { + [self addSubview:_separatorView]; + } + [self setNeedsUpdateConstraints]; + } + } +} + +- (UIView*)separatorView { + if(_separatorView == nil) { + UIView* separatorView = [[UIView alloc] initWithFrame:CGRectZero]; + separatorView.backgroundColor = MOBILY_COLOR_RGB(199, 199, 199); + self.separatorView = separatorView; + } + return _separatorView; +} + +- (void)setSearchField:(MobilyTextField*)searchField { + if(_searchField != searchField) { + if(_searchField != nil) { + [_searchField removeFromSuperview]; + } + _searchField = searchField; + if(_searchField != nil) { + [_searchField addTarget:self action:@selector(changeTextField) forControlEvents:UIControlEventEditingChanged]; + _searchField.translatesAutoresizingMaskIntoConstraints = NO; + _searchField.delegate = self; + if(_searchField.superview == nil) { + [self addSubview:_searchField]; + } + [self setNeedsUpdateConstraints]; + } + } +} + +- (MobilyTextField*)searchField { + if(_searchField == nil) { + MobilyTextField* textField = [[MobilyTextField alloc] initWithFrame:CGRectZero]; + textField.placeholder = NSLocalizedStringFromTable(@"Search", @"MobilySearchBar", @"SearchBar placeholder"); + textField.borderStyle = UITextBorderStyleNone; + textField.backgroundColor = [UIColor whiteColor]; + textField.textColor = [UIColor darkGrayColor]; + textField.tintColor = [UIColor blackColor]; + textField.moCornerRadius = 4.0f; + textField.hiddenToolbar = YES; + textField.font = [UIFont fontWithName:@"HelveticaNeue" size:13.0f]; + UIImage* image = [UIImage imageNamed:@"icon_searchbar.png"]; + if(image != nil) { + textField.leftView = [[UIImageView alloc] initWithImage:image]; + textField.leftViewMode = UITextFieldViewModeAlways; + } + self.searchField = textField; + } + return _searchField; +} + +- (void)setCancelButton:(MobilyButton*)cancelButton { + if(_cancelButton != cancelButton) { + if(_cancelButton != nil) { + [_cancelButton removeFromSuperview]; + } + _cancelButton = cancelButton; + if(_cancelButton != nil) { + [_cancelButton addTarget:self action:@selector(pressedCancel) forControlEvents:UIControlEventTouchUpInside]; + _cancelButton.translatesAutoresizingMaskIntoConstraints = NO; + if(((_searching == YES) || (_editing == YES)) && (_showCancelButton == YES)) { + _cancelButton.hidden = NO; + } else { + _cancelButton.hidden = YES; + } + if(_cancelButton.superview == nil) { + [self addSubview:_cancelButton]; + } + [self setNeedsUpdateConstraints]; + } + } +} + +- (MobilyButton*)cancelButton { + if(_cancelButton == nil) { + MobilyButton* button = [[MobilyButton alloc] initWithFrame:CGRectZero]; + button.moNormalTitle = NSLocalizedStringFromTable(@"Cancel", @"MobilySearchBar", @"Cancel title"); + button.moNormalTitleColor = [UIColor darkGrayColor]; + button.titleLabel.font = [UIFont fontWithName:@"HelveticaNeue" size:15.0f]; + self.cancelButton = button; + } + return _cancelButton; +} + +#pragma mark Public override + +- (void)updateConstraints { + NSDictionary* metrics = @{ + @"separatorHeight": @(MobilySearchBarSeparatorHeight), + @"contentHeight": @(_minimalHeight), + @"marginTop": @(_margin.top), + @"marginBottom": @(_margin.bottom), + @"marginLeft": @(_margin.left), + @"marginRight": @(_margin.right), + @"spacing": @(_spacing), + }; + NSDictionary* views = @{ + @"separatorView": self.separatorView, + @"searchField": self.searchField, + @"cancelButton": self.cancelButton, + }; + [self removeConstraints:_contentConstraints]; + [_contentConstraints removeAllObjects]; + if(((_searching == YES) || (_editing == YES)) && (_showCancelButton == YES)) { + [_contentConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(marginLeft)-[searchField]-(spacing)-[cancelButton]-(marginRight)-|" options:0 metrics:metrics views:views]]; + [_contentConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=marginTop)-[searchField(>=contentHeight)]-(marginBottom)-|" options:0 metrics:metrics views:views]]; + [_contentConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=marginTop)-[cancelButton(>=contentHeight)]-(marginBottom)-|" options:0 metrics:metrics views:views]]; + } else { + [_contentConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(marginLeft)-[searchField]-(marginRight)-|" options:0 metrics:metrics views:views]]; + [_contentConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[searchField]-(marginRight)-[cancelButton]" options:0 metrics:metrics views:views]]; + [_contentConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=marginTop)-[searchField(>=contentHeight)]-(marginBottom)-|" options:0 metrics:metrics views:views]]; + [_contentConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(>=marginTop)-[cancelButton(>=contentHeight)]-(marginBottom)-|" options:0 metrics:metrics views:views]]; + } + [_contentConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[separatorView]-0-|" options:0 metrics:metrics views:views]]; + [_contentConstraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[separatorView(==separatorHeight)]-0-|" options:0 metrics:metrics views:views]]; + [self addConstraints:_contentConstraints]; + [super updateConstraints]; +} + +#pragma mark Public + +#pragma mark Private + +- (void)updateAnimated:(BOOL)animated complete:(MobilySimpleBlock)complete { + if(_searching == _editing) { + [self setNeedsUpdateConstraints]; + [self updateConstraintsIfNeeded]; + } + if(animated == YES) { + if(((_searching == YES) || (_editing == YES)) && (_showCancelButton == YES)) { + self.cancelButton.hidden = NO; + } + [UIView animateWithDuration:0.2f animations:^{ + [self layoutIfNeeded]; + } completion:^(BOOL finished) { + if((_searching == NO) && (_editing == NO)) { + self.cancelButton.hidden = YES; + } + if(complete != nil) { + complete(); + } + }]; + } else { + if(((_searching == YES) || (_editing == YES)) && (_showCancelButton == YES)) { + self.cancelButton.hidden = NO; + } else { + self.cancelButton.hidden = YES; + } + if(complete != nil) { + complete(); + } + } +} + +#pragma mark Action + +- (void)changeTextField { + if((_searching == NO) && (self.searchField.text.length > 0)) { + if([_delegate respondsToSelector:@selector(searchBarBeginSearch:)]) { + [_delegate searchBarBeginSearch:self]; + } + [self setSearching:YES animated:YES complete:nil]; + } + if(self.searchField.text.length > 0) { + _searchField.clearButtonMode = UITextFieldViewModeAlways; + } else { + _searchField.clearButtonMode = UITextFieldViewModeNever; + } + if([_delegate respondsToSelector:@selector(searchBar:textChanged:)]) { + [_delegate searchBar:self textChanged:self.searchField.text]; + } +} + +- (void)pressedCancel { + __weak typeof(self) wealSelf = self; + [self setSearching:NO animated:YES complete:^{ + if([wealSelf.delegate respondsToSelector:@selector(searchBarEndEditing:)]) { + [wealSelf.delegate searchBarPressedCancel:wealSelf]; + } + }]; +} + +#pragma mark UITextFieldDelegate + +- (void)textFieldDidBeginEditing:(UITextField*)textField { + if([_delegate respondsToSelector:@selector(searchBarBeginEditing:)]) { + [_delegate searchBarBeginEditing:self]; + } + [self setEditing:YES animated:YES complete:nil]; +} + +- (void)textFieldDidEndEditing:(UITextField*)textField { + if([_delegate respondsToSelector:@selector(searchBarEndEditing:)]) { + [_delegate searchBarEndEditing:self]; + } + if(self.searchField.text.length < 1) { + if([_delegate respondsToSelector:@selector(searchBarEndSearch:)]) { + [_delegate searchBarEndSearch:self]; + } + [self setSearching:NO animated:YES complete:nil]; + } + [self setEditing:NO animated:YES complete:nil]; +} + +- (BOOL)textFieldShouldClear:(UITextField*)textField { + if([_delegate respondsToSelector:@selector(searchBarPressedClear:)]) { + [_delegate searchBarPressedClear:self]; + } + return YES; +} + +- (BOOL)textFieldShouldReturn:(UITextField*)textField { + if([_delegate respondsToSelector:@selector(searchBarPressedReturn:)]) { + [_delegate searchBarPressedReturn:self]; + } + return YES; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySharedManager.h b/Sources/MobilyCore/MobilySharedManager.h new file mode 100644 index 0000000..f5146c0 --- /dev/null +++ b/Sources/MobilyCore/MobilySharedManager.h @@ -0,0 +1,64 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef void (^MobilySharedManagerListenerBlock)(id messageObject); + +/*--------------------------------------------------*/ + +@interface MobilySharedManager : NSObject< MobilyObject > + ++ (BOOL)isSupported; + +- (instancetype)initWithApplicationGroupIdentifier:(NSString*)identifier optionalDirectory:(NSString*)directory; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)passMessageObject:(id< NSCoding >)messageObject identifier:(NSString*)identifier; + +- (id)messageWithIdentifier:(NSString*)identifier; + +- (void)clearMessageContentsForIdentifier:(NSString*)identifier; +- (void)clearAllMessageContents; + +- (void)listenForMessageWithIdentifier:(NSString*)identifier listener:(MobilySharedManagerListenerBlock)listener; +- (void)stopListeningForMessageWithIdentifier:(NSString*)identifier; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySharedManager.m b/Sources/MobilyCore/MobilySharedManager.m new file mode 100644 index 0000000..3f10841 --- /dev/null +++ b/Sources/MobilyCore/MobilySharedManager.m @@ -0,0 +1,216 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +static NSString* const MobilySharedManagerNotification = @"MobilySharedManagerNotification"; + +/*--------------------------------------------------*/ + +@interface MobilySharedManager () + +@property(nonatomic, readwrite, copy) NSString* applicationGroupIdentifier; +@property(nonatomic, readwrite, copy) NSString* directory; +@property(nonatomic, readwrite, strong) NSFileManager* fileManager; +@property(nonatomic, readwrite, strong) NSMutableDictionary* listenerBlocks; + +- (NSString*)_messagePassingDirectoryPath; +- (NSString*)_filePathForIdentifier:(NSString*)identifier; +- (void)_writeMessageObject:(id)messageObject toFileWithIdentifier:(NSString*)identifier; +- (id)_messageObjectFromFileWithIdentifier:(NSString*)identifier; +- (void)_deleteFileForIdentifier:(NSString*)identifier; + +- (void)_sendNotificationForMessageWithIdentifier:(NSString*)identifier; +- (void)_registerForNotificationsWithIdentifier:(NSString*)identifier; +- (void)_unregisterForNotificationsWithIdentifier:(NSString*)identifier; +- (void)_didReceiveMessageNotification:(NSNotification*)notification; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +void MobilySharedManagerNotificationCallback(CFNotificationCenterRef center, void* observer, CFStringRef name, void const* object, CFDictionaryRef userInfo) { + [[NSNotificationCenter defaultCenter] postNotificationName:MobilySharedManagerNotification object:nil userInfo:@{ @"identifier" : (__bridge NSString*)name }]; +} + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilySharedManager + +#pragma mark Init / Free + +- (instancetype)initWithApplicationGroupIdentifier:(NSString*)identifier optionalDirectory:(NSString*)directory { + self = [super init]; + if(self != nil) { + _applicationGroupIdentifier = [identifier copy]; + _directory = [directory copy]; + } + return self; +} + +- (void)setup { + _fileManager = [[NSFileManager alloc] init]; + _listenerBlocks = [NSMutableDictionary dictionary]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_didReceiveMessageNotification:) name:MobilySharedManagerNotification object:nil]; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + CFNotificationCenterRemoveEveryObserver(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge const void*)self); +} + +#pragma mark Public static + ++ (BOOL)isSupported { + return [[NSFileManager defaultManager] respondsToSelector:@selector(containerURLForSecurityApplicationGroupIdentifier:)]; +} + +#pragma mark Public + +- (void)passMessageObject:(id< NSCoding >)messageObject identifier:(NSString*)identifier { + if((messageObject != nil) && (identifier.length > 0)) { + [self _writeMessageObject:messageObject toFileWithIdentifier:identifier]; + } +} + +- (id)messageWithIdentifier:(NSString*)identifier { + if(identifier.length > 0) { + return [self _messageObjectFromFileWithIdentifier:identifier]; + } + return nil; +} + +- (void)clearMessageContentsForIdentifier:(NSString*)identifier { + if(identifier.length > 0) { + [self _deleteFileForIdentifier:identifier]; + } +} + +- (void)clearAllMessageContents { + if(_directory != nil) { + NSString* directoryPath = [self _messagePassingDirectoryPath]; + NSArray* messageFiles = [_fileManager contentsOfDirectoryAtPath:directoryPath error:NULL]; + for(NSString* path in messageFiles) { + [self.fileManager removeItemAtPath:[directoryPath stringByAppendingPathComponent:path] error:NULL]; + } + } +} + +- (void)listenForMessageWithIdentifier:(NSString*)identifier listener:(MobilySharedManagerListenerBlock)listener { + if(identifier.length > 0) { + [_listenerBlocks setValue:listener forKey:identifier]; + [self _registerForNotificationsWithIdentifier:identifier]; + } +} + +- (void)stopListeningForMessageWithIdentifier:(NSString*)identifier { + if(identifier.length > 0) { + [_listenerBlocks setValue:nil forKey:identifier]; + [self _unregisterForNotificationsWithIdentifier:identifier]; + } +} + +#pragma mark Private + +- (NSString*)_messagePassingDirectoryPath { + NSURL* appGroupContainer = [_fileManager containerURLForSecurityApplicationGroupIdentifier:_applicationGroupIdentifier]; + NSString* directoryPath = appGroupContainer.path; + if(_directory != nil) { + directoryPath = [directoryPath stringByAppendingPathComponent:_directory]; + } + if([_fileManager fileExistsAtPath:directoryPath] == NO) { + [_fileManager createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:NULL]; + } + return directoryPath; +} + +- (NSString*)_filePathForIdentifier:(NSString*)identifier { + return [[self _messagePassingDirectoryPath] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.archive", identifier]]; +} + +- (void)_writeMessageObject:(id)messageObject toFileWithIdentifier:(NSString*)identifier { + NSData* data = [NSKeyedArchiver archivedDataWithRootObject:messageObject]; + if([data writeToFile:[self _filePathForIdentifier:identifier] atomically:YES] == YES) { + [self _sendNotificationForMessageWithIdentifier:identifier]; + } +} + +- (id)_messageObjectFromFileWithIdentifier:(NSString*)identifier { + NSData* data = [NSData dataWithContentsOfFile:[self _filePathForIdentifier:identifier]]; + if(data != nil) { + return [NSKeyedUnarchiver unarchiveObjectWithData:data]; + } + return nil; +} + +- (void)_deleteFileForIdentifier:(NSString*)identifier { + [_fileManager removeItemAtPath:[self _filePathForIdentifier:identifier] error:NULL]; +} + +- (void)_sendNotificationForMessageWithIdentifier:(NSString*)identifier { + CFNotificationCenterPostNotification(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge CFStringRef)identifier, NULL, NULL, YES); +} + +- (void)_registerForNotificationsWithIdentifier:(NSString*)identifier { + CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge const void*)self, MobilySharedManagerNotificationCallback, (__bridge CFStringRef)identifier, NULL, CFNotificationSuspensionBehaviorDeliverImmediately); +} + +- (void)_unregisterForNotificationsWithIdentifier:(NSString*)identifier { + CFNotificationCenterRemoveObserver(CFNotificationCenterGetDarwinNotifyCenter(), (__bridge const void*)self, (__bridge CFStringRef)identifier, NULL); +} + +- (void)_didReceiveMessageNotification:(NSNotification*)notification { + NSDictionary* userInfo = notification.userInfo; + NSString* identifier = [userInfo valueForKey:@"identifier"]; + if(identifier != nil) { + MobilySharedManagerListenerBlock listenerBlock = [_listenerBlocks valueForKey:identifier]; + if(listenerBlock != nil) { + listenerBlock([self _messageObjectFromFileWithIdentifier:identifier]); + } + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySlideController.h b/Sources/MobilyCore/MobilySlideController.h new file mode 100644 index 0000000..6d47f99 --- /dev/null +++ b/Sources/MobilyCore/MobilySlideController.h @@ -0,0 +1,128 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef void(^MobilySlideControllerBlock)(); + +/*--------------------------------------------------*/ + +@interface MobilySlideController : MobilyController + +@property(nonatomic, readwrite, assign) IBInspectable CGFloat swipeThreshold; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat swipeVelocity; +@property(nonatomic, readwrite, strong) IBOutlet UIViewController* backgroundController; +@property(nonatomic, readwrite, assign, getter=isShowedLeftController) IBInspectable BOOL showedLeftController; +@property(nonatomic, readwrite, strong) IBOutlet UIViewController* leftController; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat leftControllerWidth; +@property(nonatomic, readwrite, strong) IBOutlet UIViewController* centerController; +@property(nonatomic, readwrite, assign, getter=isShowedRightController) IBInspectable BOOL showedRightController; +@property(nonatomic, readwrite, strong) IBOutlet UIViewController* rightController; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat rightControllerWidth; +@property(nonatomic, readonly, getter=isSwipeDragging) BOOL swipeDragging; +@property(nonatomic, readonly, getter=isSwipeDecelerating) BOOL swipeDecelerating; + +- (void)setBackgroundController:(UIViewController*)backgroundController animated:(BOOL)animated complete:(MobilySlideControllerBlock)complete; +- (void)setLeftController:(UIViewController*)leftController animated:(BOOL)animated complete:(MobilySlideControllerBlock)complete; +- (void)setCenterController:(UIViewController*)centerController animated:(BOOL)animated complete:(MobilySlideControllerBlock)complete; +- (void)setRightController:(UIViewController*)rightController animated:(BOOL)animated complete:(MobilySlideControllerBlock)complete; + +- (void)showLeftControllerAnimated:(BOOL)animated complete:(MobilySlideControllerBlock)complete; +- (void)hideLeftControllerAnimated:(BOOL)animated complete:(MobilySlideControllerBlock)complete; + +- (void)showRightControllerAnimated:(BOOL)animated complete:(MobilySlideControllerBlock)complete; +- (void)hideRightControllerAnimated:(BOOL)animated complete:(MobilySlideControllerBlock)complete; + +@end + +/*--------------------------------------------------*/ + +@protocol MobilySlideControllerDelegate < NSObject > + +@optional +- (BOOL)canShowLeftControllerInSlideController:(MobilySlideController*)slideController; +- (void)willShowLeftControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration; +- (void)didShowLeftControllerInSlideController:(MobilySlideController*)slideController; +- (void)willHideLeftControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration; +- (void)didHideLeftControllerInSlideController:(MobilySlideController*)slideController; + +@optional +- (BOOL)canShowRightControllerInSlideController:(MobilySlideController*)slideController; +- (void)willShowRightControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration; +- (void)didShowRightControllerInSlideController:(MobilySlideController*)slideController; +- (void)willHideRightControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration; +- (void)didHideRightControllerInSlideController:(MobilySlideController*)slideController; + +@optional +- (BOOL)canShowControllerInSlideController:(MobilySlideController*)slideController; +- (void)willShowControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration; +- (void)didShowControllerInSlideController:(MobilySlideController*)slideController; +- (void)willHideControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration; +- (void)didHideControllerInSlideController:(MobilySlideController*)slideController; + +@optional +- (void)willBeganLeftSwipeInSlideController:(MobilySlideController*)slideController; +- (void)didBeganLeftSwipeInSlideController:(MobilySlideController*)slideController; +- (void)movingLeftSwipeInSlideController:(MobilySlideController*)slideController progress:(CGFloat)progress; +- (void)willEndedLeftSwipeInSlideController:(MobilySlideController*)slideController; +- (void)didEndedLeftSwipeInSlideController:(MobilySlideController*)slideController; + +@optional +- (void)willBeganRightSwipeInSlideController:(MobilySlideController*)slideController; +- (void)didBeganRightSwipeInSlideController:(MobilySlideController*)slideController; +- (void)movingRightSwipeInSlideController:(MobilySlideController*)slideController progress:(CGFloat)progress; +- (void)willEndedRightSwipeInSlideController:(MobilySlideController*)slideController; +- (void)didEndedRightSwipeInSlideController:(MobilySlideController*)slideController; + +@optional +- (void)willBeganSwipeInSlideController:(MobilySlideController*)slideController; +- (void)didBeganSwipeInSlideController:(MobilySlideController*)slideController; +- (void)movingSwipeInSlideController:(MobilySlideController*)slideController progress:(CGFloat)progress; +- (void)willEndedSwipeInSlideController:(MobilySlideController*)slideController; +- (void)didEndedSwipeInSlideController:(MobilySlideController*)slideController; + +@end + +/*--------------------------------------------------*/ + +@interface UIViewController (MobilySlideController) + +@property(nonatomic, readwrite, weak) MobilySlideController* moSlideController; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySlideController.m b/Sources/MobilyCore/MobilySlideController.m new file mode 100644 index 0000000..ac8512f --- /dev/null +++ b/Sources/MobilyCore/MobilySlideController.m @@ -0,0 +1,1067 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSUInteger, MobilySlideControllerSwipeCellDirection) { + MobilySlideControllerSwipeCellDirectionUnknown, + MobilySlideControllerSwipeCellDirectionLeft, + MobilySlideControllerSwipeCellDirectionRight +}; + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilySlideController () < UIGestureRecognizerDelegate > + +@property(nonatomic, readwrite, getter=isSwipeDragging) BOOL swipeDragging; +@property(nonatomic, readwrite, getter=isSwipeDecelerating) BOOL swipeDecelerating; + +@property(nonatomic, readwrite, strong) UIView* backgroundView; +@property(nonatomic, readwrite, strong) UIView* leftView; +@property(nonatomic, readwrite, strong) UIView* centerView; +@property(nonatomic, readwrite, strong) UIView* rightView; +@property(nonatomic, readwrite, strong) UIPanGestureRecognizer* panGesture; +@property(nonatomic, readwrite, strong) UITapGestureRecognizer* tapGesture; + +@property(nonatomic, readwrite, assign) CGFloat swipeLastOffset; +@property(nonatomic, readwrite, assign) CGFloat swipeLastVelocity; +@property(nonatomic, readwrite, assign) CGFloat swipeProgress; +@property(nonatomic, readwrite, assign) CGFloat swipeLeftWidth; +@property(nonatomic, readwrite, assign) CGFloat swipeRightWidth; +@property(nonatomic, readwrite, assign) MobilySlideControllerSwipeCellDirection swipeDirection; + +- (CGRect)leftViewFrameByPercent:(CGFloat)percent; +- (CGRect)leftViewFrameFromBounds:(CGRect)bounds byPercent:(CGFloat)percent; +- (CGRect)centerViewFrameByPercent:(CGFloat)percent; +- (CGRect)centerViewFrameFromBounds:(CGRect)bounds byPercent:(CGFloat)percent; +- (CGRect)rightViewFrameByPercent:(CGFloat)percent; +- (CGRect)rightViewFrameFromBounds:(CGRect)bounds byPercent:(CGFloat)percent; + +- (void)appearBackgroundController; +- (void)disappearBackgroundController; +- (void)appearLeftController; +- (void)disappearLeftController; +- (void)appearCenterController; +- (void)disappearCenterController; +- (void)appearRightController; +- (void)disappearRightController; + +- (void)setSwipeProgress:(CGFloat)swipeProgress speed:(CGFloat)speed endedSwipe:(BOOL)endedSwipe; + +- (void)willBeganSwipe; +- (void)didBeganSwipe; +- (void)movingSwipe:(CGFloat)progress; +- (void)willEndedSwipe; +- (void)didEndedSwipe; + +- (void)tapGestureHandle:(UITapGestureRecognizer*)tapGesture; +- (void)panGestureHandle:(UIPanGestureRecognizer*)panGesture; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilySlideController + +#pragma mark Init / Free + +- (void)setup { + [super setup]; + + if(UIDevice.moIsIPhone == YES) { + _swipeThreshold = 2.0f; + _swipeVelocity = 1050.0f; + _leftControllerWidth = 280.0f; + _rightControllerWidth = 280.0f; + } else if(UIDevice.moIsIPad == YES) { + _swipeThreshold = 2.0f; + _swipeVelocity = 3000.0f; + _leftControllerWidth = 320.0f; + _rightControllerWidth = 320.0f; + } + +} + +- (void)dealloc { + self.backgroundController = nil; + self.leftController = nil; + self.centerController = nil; + self.rightController = nil; + self.backgroundView = nil; + self.leftView = nil; + self.centerView = nil; + self.rightView = nil; + self.panGesture = nil; + self.tapGesture = nil; +} + +#pragma mark UIViewController + +- (BOOL)shouldAutorotate { + return _centerController.shouldAutorotate; +} + +- (NSUInteger)supportedInterfaceOrientations { + return _centerController.supportedInterfaceOrientations; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation { + return [_centerController shouldAutorotateToInterfaceOrientation:orientation]; +} + +- (BOOL)prefersStatusBarHidden { + return _centerController.prefersStatusBarHidden; +} + +- (UIStatusBarStyle)preferredStatusBarStyle { + return _centerController.preferredStatusBarStyle; +} + +- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { + return _centerController.preferredStatusBarUpdateAnimation; +} + +- (void)loadView { + [super loadView]; + + self.view.clipsToBounds = YES; + + self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureHandle:)]; + self.tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureHandle:)]; + self.backgroundView = [[UIView alloc] initWithFrame:self.view.bounds]; + self.leftView = [[UIView alloc] initWithFrame:[self leftViewFrameByPercent:0.0f]]; + self.centerView = [[UIView alloc] initWithFrame:[self centerViewFrameByPercent:0.0f]]; + self.rightView = [[UIView alloc] initWithFrame:[self rightViewFrameByPercent:0.0f]]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + if(_backgroundController != nil) { + [self appearBackgroundController]; + } + if(_leftController != nil) { + [self appearLeftController]; + } + if(_centerController != nil) { + [self appearCenterController]; + } + if(_rightController != nil) { + [self appearRightController]; + } +} + +- (void)viewDidLayoutSubviews { + [super viewDidLayoutSubviews]; + + CGRect bounds = self.view.bounds; + _backgroundView.frame = bounds; + _leftView.frame = [self leftViewFrameFromBounds:bounds byPercent:_swipeProgress]; + _centerView.frame = [self centerViewFrameFromBounds:bounds byPercent:_swipeProgress]; + _rightView.frame = [self rightViewFrameFromBounds:bounds byPercent:_swipeProgress]; +} + +#pragma mark Property + +- (void)setTapGesture:(UITapGestureRecognizer*)tapGesture { + if(_tapGesture != tapGesture) { + if(_tapGesture != nil) { + [self.view removeGestureRecognizer:_tapGesture]; + } + _tapGesture = tapGesture; + if(_tapGesture != nil) { + _tapGesture.delegate = self; + [self.view addGestureRecognizer:_tapGesture]; + } + } +} + +- (void)setPanGesture:(UIPanGestureRecognizer*)panGesture { + if(_panGesture != panGesture) { + if(_panGesture != nil) { + [self.view removeGestureRecognizer:_panGesture]; + } + _panGesture = panGesture; + if(_panGesture != nil) { + _panGesture.delegate = self; + [self.view addGestureRecognizer:_panGesture]; + } + } +} + +- (void)setBackgroundView:(UIView*)backgroundView { + if(_backgroundView != backgroundView) { + if(_backgroundView != nil) { + [_backgroundView removeFromSuperview]; + } + _backgroundView = backgroundView; + if(_backgroundView != nil) { + [self.view addSubview:_backgroundView]; + } + } +} + +- (void)setLeftView:(UIView*)leftView { + if(_leftView != leftView) { + if(_leftView != nil) { + [_leftView removeFromSuperview]; + } + _leftView = leftView; + if(_leftView != nil) { + [self.view addSubview:_leftView]; + } + } +} + +- (void)setCenterView:(UIView*)centerView { + if(_centerView != centerView) { + if(_centerView != nil) { + [_centerView removeFromSuperview]; + } + _centerView = centerView; + if(_centerView != nil) { + [self.view addSubview:_centerView]; + } + } +} + +- (void)setRightView:(UIView*)rightView { + if(_rightView != rightView) { + if(_rightView != nil) { + [_rightView removeFromSuperview]; + } + _rightView = rightView; + if(_rightView != nil) { + [self.view addSubview:_rightView]; + } + } +} + +- (void)setBackgroundController:(UIViewController*)backgroundController { + [self setBackgroundController:backgroundController animated:NO complete:nil]; +} + +- (void)setLeftController:(UIViewController*)leftController { + [self setLeftController:leftController animated:NO complete:nil]; +} + +- (void)setCenterController:(UIViewController*)centerController { + [self setCenterController:centerController animated:NO complete:nil]; +} + +- (void)setRightController:(UIViewController*)rightController { + [self setRightController:rightController animated:NO complete:nil]; +} + +#pragma mark Public + +- (void)setBackgroundController:(UIViewController*)backgroundController animated:(BOOL)animated complete:(MobilySlideControllerBlock)complete { + if(_backgroundController != backgroundController) { + if(self.isViewLoaded == NO) { + animated = NO; + } + if(animated == YES) { + } else { + if((_backgroundController != nil) && (self.isViewLoaded == YES)) { + [self disappearBackgroundController]; + } + _backgroundController = backgroundController; + if((_backgroundController != nil) && (self.isViewLoaded == YES)) { + [self appearBackgroundController]; + } + if(complete != nil) { + complete(); + } + } + } +} + +- (void)setLeftController:(UIViewController*)leftController animated:(BOOL)animated complete:(MobilySlideControllerBlock)complete { + if(_leftController != leftController) { + if(self.isViewLoaded == NO) { + animated = NO; + } + if(animated == YES) { + } else { + if((_leftController != nil) && (self.isViewLoaded == YES)) { + [self disappearLeftController]; + } + _leftController = leftController; + if((_leftController != nil) && (self.isViewLoaded == YES)) { + [self appearLeftController]; + } + if(complete != nil) { + complete(); + } + } + } +} + +- (void)setCenterController:(UIViewController*)centerController animated:(BOOL)animated complete:(MobilySlideControllerBlock)complete { + if(_centerController != centerController) { + if(self.isViewLoaded == NO) { + animated = NO; + } + if(animated == YES) { + } else { + if((_centerController != nil) && (self.isViewLoaded == YES)) { + [self disappearCenterController]; + } + _centerController = centerController; + if((_centerController != nil) && (self.isViewLoaded == YES)) { + [self appearCenterController]; + } + if(complete != nil) { + complete(); + } + } + } +} + +- (void)setRightController:(UIViewController*)rightController animated:(BOOL)animated complete:(MobilySlideControllerBlock)complete { + if(_rightController != rightController) { + if(self.isViewLoaded == NO) { + animated = NO; + } + if(animated == YES) { + } else { + if((_rightController != nil) && (self.isViewLoaded == YES)) { + [self disappearRightController]; + } + _rightController = rightController; + if((_rightController != nil) && (self.isViewLoaded == YES)) { + [self appearRightController]; + } + if(complete != nil) { + complete(); + } + } + } +} + +- (void)showLeftControllerAnimated:(BOOL)animated complete:(MobilySlideControllerBlock)complete { + if(_showedLeftController == NO) { + BOOL allow = YES; + id< MobilySlideControllerDelegate > centerController = ([_centerController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_centerController : nil; + id< MobilySlideControllerDelegate > leftController = ([_leftController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_leftController : nil; + if([centerController respondsToSelector:@selector(canShowLeftControllerInSlideController:)] == YES) { + if([centerController canShowLeftControllerInSlideController:self] == YES) { + if([leftController respondsToSelector:@selector(canShowControllerInSlideController:)] == YES) { + allow = [leftController canShowControllerInSlideController:self]; + } + } else { + allow = NO; + } + } + if(allow == YES) { + if(self.isViewLoaded == NO) { + animated = NO; + } + _swipeProgress = -1.0f; + CGRect leftFrame = [self leftViewFrameByPercent:_swipeProgress]; + CGRect centerFrame = [self centerViewFrameByPercent:_swipeProgress]; + CGFloat diffX = MOBILY_FABS(leftFrame.origin.x - centerFrame.origin.x); + CGFloat diffY = MOBILY_FABS(leftFrame.origin.y - centerFrame.origin.y); + CGFloat diffW = MOBILY_FABS(leftFrame.size.width - centerFrame.size.width); + CGFloat diffH = MOBILY_FABS(leftFrame.size.height - centerFrame.size.height); + CGFloat speed = MAX(MAX(diffX, diffY), MAX(diffW, diffH)); + if(animated == YES) { + NSTimeInterval duration = speed / _swipeVelocity; + if([centerController respondsToSelector:@selector(willShowLeftControllerInSlideController:duration:)] == YES) { + [centerController willShowLeftControllerInSlideController:self duration:duration]; + } + if([leftController respondsToSelector:@selector(willShowControllerInSlideController:duration:)] == YES) { + [leftController willShowControllerInSlideController:self duration:duration]; + } + [UIView animateWithDuration:duration animations:^{ + _leftView.frame = leftFrame; + _centerView.frame = centerFrame; + } completion:^(BOOL finished __unused) { + _leftView.userInteractionEnabled = YES; + _centerView.userInteractionEnabled = NO; + _showedLeftController = YES; + if([centerController respondsToSelector:@selector(didShowLeftControllerInSlideController:)] == YES) { + [centerController didShowLeftControllerInSlideController:self]; + } + if([leftController respondsToSelector:@selector(didShowControllerInSlideController:)] == YES) { + [leftController didShowControllerInSlideController:self]; + } + if(complete != nil) { + complete(); + } + }]; + } else { + if([centerController respondsToSelector:@selector(willShowLeftControllerInSlideController:duration:)] == YES) { + [centerController willShowLeftControllerInSlideController:self duration:0.0f]; + } + if([leftController respondsToSelector:@selector(willShowControllerInSlideController:duration:)] == YES) { + [leftController willShowControllerInSlideController:self duration:0.0f]; + } + _leftView.userInteractionEnabled = YES; + _leftView.frame = leftFrame; + _centerView.userInteractionEnabled = NO; + _centerView.frame = centerFrame; + _showedLeftController = YES; + if([centerController respondsToSelector:@selector(didShowLeftControllerInSlideController:)] == YES) { + [centerController didShowLeftControllerInSlideController:self]; + } + if([leftController respondsToSelector:@selector(didShowControllerInSlideController:)] == YES) { + [leftController didShowControllerInSlideController:self]; + } + if(complete != nil) { + complete(); + } + } + } + } +} + +- (void)hideLeftControllerAnimated:(BOOL)animated complete:(MobilySlideControllerBlock)complete { + if(_showedLeftController == YES) { + id< MobilySlideControllerDelegate > centerController = ([_centerController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_centerController : nil; + id< MobilySlideControllerDelegate > leftController = ([_leftController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_leftController : nil; + if(self.isViewLoaded == NO) { + animated = NO; + } + _swipeProgress = 0.0f; + CGRect leftFrame = [self leftViewFrameByPercent:_swipeProgress]; + CGRect centerFrame = [self centerViewFrameByPercent:_swipeProgress]; + CGFloat diffX = MOBILY_FABS(leftFrame.origin.x - centerFrame.origin.x); + CGFloat diffY = MOBILY_FABS(leftFrame.origin.y - centerFrame.origin.y); + CGFloat diffW = MOBILY_FABS(leftFrame.size.width - centerFrame.size.width); + CGFloat diffH = MOBILY_FABS(leftFrame.size.height - centerFrame.size.height); + CGFloat speed = MAX(MAX(diffX, diffY), MAX(diffW, diffH)); + if(animated == YES) { + NSTimeInterval duration = speed / _swipeVelocity; + if([centerController respondsToSelector:@selector(willHideLeftControllerInSlideController:duration:)] == YES) { + [centerController willHideLeftControllerInSlideController:self duration:duration]; + } + if([leftController respondsToSelector:@selector(willHideControllerInSlideController:duration:)] == YES) { + [leftController willHideControllerInSlideController:self duration:duration]; + } + [UIView animateWithDuration:duration animations:^{ + _leftView.frame = leftFrame; + _centerView.frame = centerFrame; + } completion:^(BOOL finished __unused) { + _leftView.userInteractionEnabled = NO; + _centerView.userInteractionEnabled = YES; + _showedLeftController = NO; + if([centerController respondsToSelector:@selector(didHideLeftControllerInSlideController:)] == YES) { + [centerController didHideLeftControllerInSlideController:self]; + } + if([leftController respondsToSelector:@selector(didHideControllerInSlideController:)] == YES) { + [leftController didHideControllerInSlideController:self]; + } + if(complete != nil) { + complete(); + } + }]; + } else { + if([centerController respondsToSelector:@selector(willHideLeftControllerInSlideController:duration:)] == YES) { + [centerController willHideLeftControllerInSlideController:self duration:0.0f]; + } + if([leftController respondsToSelector:@selector(willHideControllerInSlideController:duration:)] == YES) { + [leftController willHideControllerInSlideController:self duration:0.0f]; + } + _leftView.userInteractionEnabled = NO; + _leftView.frame = leftFrame; + _centerView.userInteractionEnabled = YES; + _centerView.frame = centerFrame; + _showedLeftController = NO; + if([centerController respondsToSelector:@selector(didHideLeftControllerInSlideController:)] == YES) { + [centerController didHideLeftControllerInSlideController:self]; + } + if([leftController respondsToSelector:@selector(didHideControllerInSlideController:)] == YES) { + [leftController didHideControllerInSlideController:self]; + } + if(complete != nil) { + complete(); + } + } + } +} + +- (void)showRightControllerAnimated:(BOOL)animated complete:(MobilySlideControllerBlock)complete { + if(_showedRightController == NO) { + BOOL allow = YES; + id< MobilySlideControllerDelegate > centerController = ([_centerController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_centerController : nil; + id< MobilySlideControllerDelegate > rightController = ([_rightController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_rightController : nil; + if([centerController respondsToSelector:@selector(canShowRightControllerInSlideController:)] == YES) { + if([centerController canShowRightControllerInSlideController:self] == YES) { + if([rightController respondsToSelector:@selector(canShowControllerInSlideController:)] == YES) { + allow = [rightController canShowControllerInSlideController:self]; + } + } else { + allow = NO; + } + } + if(allow == YES) { + if(self.isViewLoaded == NO) { + animated = NO; + } + _swipeProgress = 1.0f; + CGRect rightFrame = [self rightViewFrameByPercent:_swipeProgress]; + CGRect centerFrame = [self centerViewFrameByPercent:_swipeProgress]; + CGFloat diffX = MOBILY_FABS(rightFrame.origin.x - centerFrame.origin.x); + CGFloat diffY = MOBILY_FABS(rightFrame.origin.y - centerFrame.origin.y); + CGFloat diffW = MOBILY_FABS(rightFrame.size.width - centerFrame.size.width); + CGFloat diffH = MOBILY_FABS(rightFrame.size.height - centerFrame.size.height); + CGFloat speed = MAX(MAX(diffX, diffY), MAX(diffW, diffH)); + if(animated == YES) { + NSTimeInterval duration = speed / _swipeVelocity; + if([centerController respondsToSelector:@selector(willShowRightControllerInSlideController:duration:)] == YES) { + [centerController willShowRightControllerInSlideController:self duration:duration]; + } + if([rightController respondsToSelector:@selector(willShowControllerInSlideController:duration:)] == YES) { + [rightController willShowControllerInSlideController:self duration:duration]; + } + [UIView animateWithDuration:duration animations:^{ + _rightView.frame = rightFrame; + _centerView.frame = centerFrame; + } completion:^(BOOL finished __unused) { + _rightView.userInteractionEnabled = YES; + _centerView.userInteractionEnabled = NO; + _showedRightController = YES; + if([centerController respondsToSelector:@selector(didShowRightControllerInSlideController:)] == YES) { + [centerController didShowRightControllerInSlideController:self]; + } + if([rightController respondsToSelector:@selector(didShowControllerInSlideController:)] == YES) { + [rightController didShowControllerInSlideController:self]; + } + if(complete != nil) { + complete(); + } + }]; + } else { + if([centerController respondsToSelector:@selector(willShowRightControllerInSlideController:duration:)] == YES) { + [centerController willShowRightControllerInSlideController:self duration:0.0f]; + } + if([rightController respondsToSelector:@selector(willShowControllerInSlideController:duration:)] == YES) { + [rightController willShowControllerInSlideController:self duration:0.0f]; + } + _rightView.userInteractionEnabled = YES; + _rightView.frame = rightFrame; + _centerView.userInteractionEnabled = NO; + _centerView.frame = centerFrame; + _showedRightController = YES; + if([centerController respondsToSelector:@selector(didShowRightControllerInSlideController:)] == YES) { + [centerController didShowRightControllerInSlideController:self]; + } + if([rightController respondsToSelector:@selector(didShowControllerInSlideController:)] == YES) { + [rightController didShowControllerInSlideController:self]; + } + if(complete != nil) { + complete(); + } + } + } + } +} + +- (void)hideRightControllerAnimated:(BOOL)animated complete:(MobilySlideControllerBlock)complete { + if(_showedRightController == YES) { + id< MobilySlideControllerDelegate > centerController = ([_centerController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_centerController : nil; + id< MobilySlideControllerDelegate > rightController = ([_rightController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_rightController : nil; + if(self.isViewLoaded == NO) { + animated = NO; + } + _swipeProgress = 0.0f; + CGRect rightFrame = [self rightViewFrameByPercent:_swipeProgress]; + CGRect centerFrame = [self centerViewFrameByPercent:_swipeProgress]; + CGFloat diffX = MOBILY_FABS(rightFrame.origin.x - centerFrame.origin.x); + CGFloat diffY = MOBILY_FABS(rightFrame.origin.y - centerFrame.origin.y); + CGFloat diffW = MOBILY_FABS(rightFrame.size.width - centerFrame.size.width); + CGFloat diffH = MOBILY_FABS(rightFrame.size.height - centerFrame.size.height); + CGFloat speed = MAX(MAX(diffX, diffY), MAX(diffW, diffH)); + if(animated == YES) { + NSTimeInterval duration = speed / _swipeVelocity; + if([centerController respondsToSelector:@selector(willHideRightControllerInSlideController:duration:)] == YES) { + [centerController willHideRightControllerInSlideController:self duration:duration]; + } + if([rightController respondsToSelector:@selector(willHideRightControllerInSlideController:duration:)] == YES) { + [rightController willHideControllerInSlideController:self duration:duration]; + } + [UIView animateWithDuration:duration animations:^{ + _rightView.frame = rightFrame; + _centerView.frame = centerFrame; + } completion:^(BOOL finished __unused) { + _rightView.userInteractionEnabled = NO; + _centerView.userInteractionEnabled = YES; + _showedRightController = NO; + if([centerController respondsToSelector:@selector(didHideRightControllerInSlideController:)] == YES) { + [centerController didHideRightControllerInSlideController:self]; + } + if([rightController respondsToSelector:@selector(didHideRightControllerInSlideController:)] == YES) { + [rightController didHideControllerInSlideController:self]; + } + if(complete != nil) { + complete(); + } + }]; + } else { + if([centerController respondsToSelector:@selector(willHideRightControllerInSlideController:duration:)] == YES) { + [centerController willHideRightControllerInSlideController:self duration:0.0f]; + } + if([rightController respondsToSelector:@selector(willHideRightControllerInSlideController:duration:)] == YES) { + [rightController willHideControllerInSlideController:self duration:0.0f]; + } + _rightView.userInteractionEnabled = NO; + _rightView.frame = rightFrame; + _centerView.userInteractionEnabled = YES; + _centerView.frame = centerFrame; + _showedRightController = NO; + if([centerController respondsToSelector:@selector(didHideRightControllerInSlideController:)] == YES) { + [centerController didHideRightControllerInSlideController:self]; + } + if([rightController respondsToSelector:@selector(didHideRightControllerInSlideController:)] == YES) { + [rightController didHideControllerInSlideController:self]; + } + if(complete != nil) { + complete(); + } + } + } +} + +#pragma mark Private + +- (CGRect)leftViewFrameByPercent:(CGFloat)percent { + return [self leftViewFrameFromBounds:self.view.bounds byPercent:percent]; +} + +- (CGRect)leftViewFrameFromBounds:(CGRect)bounds byPercent:(CGFloat)percent { + return CGRectMake((bounds.origin.x - _leftControllerWidth) + (_leftControllerWidth * -percent), bounds.origin.y, _leftControllerWidth, bounds.size.height); +} + +- (CGRect)centerViewFrameByPercent:(CGFloat)percent { + return [self centerViewFrameFromBounds:self.view.bounds byPercent:percent]; +} + +- (CGRect)centerViewFrameFromBounds:(CGRect)bounds byPercent:(CGFloat)percent { + if(percent < -MOBILY_EPSILON) { + return CGRectMake(bounds.origin.x + (_leftControllerWidth * -percent), bounds.origin.y, bounds.size.width, bounds.size.height); + } else if(percent > MOBILY_EPSILON) { + return CGRectMake(bounds.origin.x - (_rightControllerWidth * percent), bounds.origin.y, bounds.size.width, bounds.size.height); + } + return bounds; +} + +- (CGRect)rightViewFrameByPercent:(CGFloat)percent { + return [self rightViewFrameFromBounds:self.view.bounds byPercent:percent]; +} + +- (CGRect)rightViewFrameFromBounds:(CGRect)bounds byPercent:(CGFloat)percent { + return CGRectMake((bounds.origin.x + bounds.size.width) - (_rightControllerWidth * percent), bounds.origin.y, _rightControllerWidth, bounds.size.height); +} + +- (void)appearBackgroundController { + _backgroundController.moSlideController = self; + + [self addChildViewController:_backgroundController]; + _backgroundController.view.frame = _backgroundView.bounds; + [_backgroundView addSubview:_backgroundController.view]; + [_backgroundController didMoveToParentViewController:self]; +} + +- (void)disappearBackgroundController { + _backgroundController.moSlideController = nil; + + [_backgroundController viewWillDisappear:NO]; + [_backgroundController.view removeFromSuperview]; + [_backgroundController viewDidDisappear:NO]; +} + +- (void)appearLeftController { + _leftController.moSlideController = self; + + [self addChildViewController:_leftController]; + _leftController.view.frame = _leftView.bounds; + [_leftView addSubview:_leftController.view]; + [_leftController didMoveToParentViewController:self]; +} + +- (void)disappearLeftController { + _leftController.moSlideController = nil; + + [_leftController willMoveToParentViewController:nil]; + [_leftController.view removeFromSuperview]; + [_leftController removeFromParentViewController]; +} + +- (void)appearCenterController { + _centerController.moSlideController = self; + + [self addChildViewController:_centerController]; + _centerController.view.frame = _centerView.bounds; + [_centerView addSubview:_centerController.view]; + [_centerController didMoveToParentViewController:self]; +} + +- (void)disappearCenterController { + _centerController.moSlideController = nil; + + [_centerController willMoveToParentViewController:nil]; + [_centerController.view removeFromSuperview]; + [_centerController removeFromParentViewController]; +} + +- (void)appearRightController { + _rightController.moSlideController = self; + + [self addChildViewController:_rightController]; + _rightController.view.frame = _rightView.bounds; + [_rightView addSubview:_rightController.view]; + [_rightController didMoveToParentViewController:self]; +} + +- (void)disappearRightController { + _rightController.moSlideController = nil; + + [_rightController willMoveToParentViewController:nil]; + [_rightController.view removeFromSuperview]; + [_rightController removeFromParentViewController]; +} + +- (void)setSwipeProgress:(CGFloat)swipeProgress speed:(CGFloat)speed endedSwipe:(BOOL)endedSwipe { + CGFloat minSwipeProgress = (_swipeDirection == MobilySlideControllerSwipeCellDirectionLeft) ? -1.0f : 0.0f; + CGFloat maxSwipeProgress = (_swipeDirection == MobilySlideControllerSwipeCellDirectionRight) ? 1.0f :0.0f; + CGFloat normalizedSwipeProgress = MIN(MAX(minSwipeProgress, swipeProgress), maxSwipeProgress); + if(_swipeProgress != normalizedSwipeProgress) { + _swipeProgress = normalizedSwipeProgress; + + CGRect bounds = self.view.bounds; + [UIView animateWithDuration:MOBILY_FABS(speed) / _swipeVelocity + animations:^{ + _leftView.frame = [self leftViewFrameFromBounds:bounds byPercent:_swipeProgress]; + _centerView.frame = [self centerViewFrameFromBounds:bounds byPercent:_swipeProgress]; + _rightView.frame = [self rightViewFrameFromBounds:bounds byPercent:_swipeProgress]; + } completion:^(BOOL finished __unused) { + if(endedSwipe == YES) { + [self didEndedSwipe]; + } + }]; + } else { + if(endedSwipe == YES) { + [self didEndedSwipe]; + } + } +} + +- (void)willBeganSwipe { + id< MobilySlideControllerDelegate > centerController = ([_centerController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_centerController : nil; + if([centerController respondsToSelector:@selector(willBeganSwipeInSlideController:)] == YES) { + [centerController willBeganSwipeInSlideController:self]; + } +} + +- (void)didBeganSwipe { + self.swipeDragging = YES; + + id< MobilySlideControllerDelegate > centerController = ([_centerController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_centerController : nil; + if([centerController respondsToSelector:@selector(didBeganSwipeInSlideController:)] == YES) { + [centerController didBeganSwipeInSlideController:self]; + } + if(_swipeDirection == MobilySlideControllerSwipeCellDirectionLeft) { + id< MobilySlideControllerDelegate > leftController = ([_leftController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_leftController : nil; + if([leftController respondsToSelector:@selector(didBeganLeftSwipeInSlideController:)] == YES) { + [leftController willBeganLeftSwipeInSlideController:self]; + [leftController didBeganLeftSwipeInSlideController:self]; + } + } else if(_swipeDirection == MobilySlideControllerSwipeCellDirectionRight) { + id< MobilySlideControllerDelegate > rightController = ([_rightController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_rightController : nil; + if([rightController respondsToSelector:@selector(didBeganRightSwipeInSlideController:)] == YES) { + [rightController willBeganRightSwipeInSlideController:self]; + [rightController didBeganRightSwipeInSlideController:self]; + } + } +} + +- (void)movingSwipe:(CGFloat)progress { + id< MobilySlideControllerDelegate > centerController = ([_centerController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_centerController : nil; + if([centerController respondsToSelector:@selector(movingSwipeInSlideController:progress:)] == YES) { + [centerController movingSwipeInSlideController:self progress:progress]; + } + if(_swipeDirection == MobilySlideControllerSwipeCellDirectionLeft) { + id< MobilySlideControllerDelegate > leftController = ([_leftController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_leftController : nil; + if([leftController respondsToSelector:@selector(movingLeftSwipeInSlideController:progress:)] == YES) { + [leftController movingLeftSwipeInSlideController:self progress:progress]; + } + } else if(_swipeDirection == MobilySlideControllerSwipeCellDirectionRight) { + id< MobilySlideControllerDelegate > rightController = ([_rightController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_rightController : nil; + if([rightController respondsToSelector:@selector(movingRightSwipeInSlideController:progress:)] == YES) { + [rightController movingRightSwipeInSlideController:self progress:progress]; + } + } +} + +- (void)willEndedSwipe { + self.swipeDragging = NO; + self.swipeDecelerating = YES; + + id< MobilySlideControllerDelegate > centerController = ([_centerController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_centerController : nil; + if([centerController respondsToSelector:@selector(willEndedSwipeInSlideController:)] == YES) { + [centerController willEndedSwipeInSlideController:self]; + } + if(_swipeDirection == MobilySlideControllerSwipeCellDirectionLeft) { + id< MobilySlideControllerDelegate > leftController = ([_leftController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_leftController : nil; + if([leftController respondsToSelector:@selector(willEndedLeftSwipeInSlideController:)] == YES) { + [leftController willEndedLeftSwipeInSlideController:self]; + } + } else if(_swipeDirection == MobilySlideControllerSwipeCellDirectionRight) { + id< MobilySlideControllerDelegate > rightController = ([_rightController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_rightController : nil; + if([rightController respondsToSelector:@selector(willEndedRightSwipeInSlideController:)] == YES) { + [rightController willEndedRightSwipeInSlideController:self]; + } + } +} + +- (void)didEndedSwipe { + _showedLeftController = (_swipeProgress < 0.0f) ? YES : NO; + _showedRightController = (_swipeProgress > 0.0f) ? YES : NO; + _leftView.userInteractionEnabled = (_showedLeftController == YES) ? YES : NO; + _centerView.userInteractionEnabled = ((_showedLeftController == YES) || (_showedRightController == YES)) ? NO : YES; + _rightView.userInteractionEnabled = (_showedRightController == YES) ? YES : NO; + self.swipeDecelerating = NO; + + id< MobilySlideControllerDelegate > centerController = ([_centerController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_centerController : nil; + if([centerController respondsToSelector:@selector(didEndedSwipeInSlideController:)] == YES) { + [centerController didEndedSwipeInSlideController:self]; + } + if(_swipeDirection == MobilySlideControllerSwipeCellDirectionLeft) { + id< MobilySlideControllerDelegate > leftController = ([_leftController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_leftController : nil; + if([leftController respondsToSelector:@selector(didEndedLeftSwipeInSlideController:)] == YES) { + [leftController didEndedLeftSwipeInSlideController:self]; + } + } else if(_swipeDirection == MobilySlideControllerSwipeCellDirectionRight) { + id< MobilySlideControllerDelegate > rightController = ([_rightController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_rightController : nil; + if([rightController respondsToSelector:@selector(didEndedRightSwipeInSlideController:)] == YES) { + [rightController didEndedRightSwipeInSlideController:self]; + } + } +} + +- (void)tapGestureHandle:(UITapGestureRecognizer* __unused)tapGesture { + if(_showedLeftController == YES) { + [self hideLeftControllerAnimated:YES complete:nil]; + } else if(_showedRightController == YES) { + [self hideRightControllerAnimated:YES complete:nil]; + } +} + +- (void)panGestureHandle:(UIPanGestureRecognizer* __unused)panGesture { + if(_swipeDecelerating == NO) { + CGPoint translation = [_panGesture translationInView:self.view]; + CGPoint velocity = [_panGesture velocityInView:self.view]; + switch([_panGesture state]) { + case UIGestureRecognizerStateBegan: { + [self willBeganSwipe]; + self.swipeLastOffset = translation.x; + self.swipeLastVelocity = velocity.x; + self.swipeLeftWidth = -_leftControllerWidth; + self.swipeRightWidth = _rightControllerWidth; + self.swipeDirection = MobilySlideControllerSwipeCellDirectionUnknown; + break; + } + case UIGestureRecognizerStateChanged: { + CGFloat delta = _swipeLastOffset - translation.x; + if(_swipeDirection == MobilySlideControllerSwipeCellDirectionUnknown) { + if((_showedLeftController == YES) && (_leftController != nil) && (delta > _swipeThreshold)) { + self.swipeDirection = MobilySlideControllerSwipeCellDirectionLeft; + [self didBeganSwipe]; + } else if((_showedRightController == YES) && (_rightController != nil) && (delta < -_swipeThreshold)) { + self.swipeDirection = MobilySlideControllerSwipeCellDirectionRight; + [self didBeganSwipe]; + } else if((_showedLeftController == NO) && (_leftController != nil) && (delta < -_swipeThreshold)) { + self.swipeDirection = MobilySlideControllerSwipeCellDirectionLeft; + [self didBeganSwipe]; + } else if((_showedRightController == NO) && (_rightController != nil) && (delta > _swipeThreshold)) { + self.swipeDirection = MobilySlideControllerSwipeCellDirectionRight; + [self didBeganSwipe]; + } + } + if(_swipeDirection != MobilySlideControllerSwipeCellDirectionUnknown) { + switch(_swipeDirection) { + case MobilySlideControllerSwipeCellDirectionUnknown: { + break; + } + case MobilySlideControllerSwipeCellDirectionLeft: { + CGFloat localDelta = MIN(MAX(_swipeLeftWidth, delta), -_swipeLeftWidth); + [self setSwipeProgress:_swipeProgress - (localDelta / _swipeLeftWidth) speed:localDelta endedSwipe:NO]; + [self movingSwipe:_swipeProgress]; + break; + } + case MobilySlideControllerSwipeCellDirectionRight: { + CGFloat localDelta = MIN(MAX(-_swipeRightWidth, delta), _swipeRightWidth); + [self setSwipeProgress:_swipeProgress + (localDelta / _swipeRightWidth) speed:localDelta endedSwipe:NO]; + [self movingSwipe:_swipeProgress]; + break; + } + } + self.swipeLastOffset = translation.x; + self.swipeLastVelocity = velocity.x; + } + break; + } + case UIGestureRecognizerStateEnded: + case UIGestureRecognizerStateCancelled: { + [self willEndedSwipe]; + CGFloat swipeProgress = roundf(_swipeProgress - (_swipeLastVelocity / _swipeVelocity)); + CGFloat minSwipeProgress = (_swipeDirection == MobilySlideControllerSwipeCellDirectionLeft) ? -1.0f : 0.0f; + CGFloat maxSwipeProgress = (_swipeDirection == MobilySlideControllerSwipeCellDirectionRight) ? 1.0f :0.0f; + CGFloat needSwipeProgress = MIN(MAX(minSwipeProgress, swipeProgress), maxSwipeProgress); + switch(_swipeDirection) { + case MobilySlideControllerSwipeCellDirectionLeft: { + [self setSwipeProgress:needSwipeProgress speed:_swipeLeftWidth * MOBILY_FABS(needSwipeProgress - _swipeProgress) endedSwipe:YES]; + break; + } + case MobilySlideControllerSwipeCellDirectionRight: { + [self setSwipeProgress:needSwipeProgress speed:_swipeRightWidth * MOBILY_FABS(needSwipeProgress - _swipeProgress) endedSwipe:YES]; + break; + } + default: { + [self didEndedSwipe]; + break; + } + } + break; + } + default: { + break; + } + } + } +} + +#pragma mark UIGestureRecognizerDelegate + +- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer { + if(gestureRecognizer == _tapGesture) { + CGPoint location = [_tapGesture locationInView:self.view]; + if((_showedLeftController == YES) || (_showedRightController == YES)) { + if(CGRectContainsPoint(_centerView.frame, location) == YES) { + return YES; + } + } + } else if(gestureRecognizer == _panGesture) { + if((_swipeDragging == NO) && (_swipeDecelerating == NO)) { + BOOL allowPan = NO; + CGPoint location = [_panGesture locationInView:self.view]; + CGPoint translation = [_panGesture translationInView:self.view]; + if((_showedLeftController == YES) && (_leftController != nil)) { + if(CGRectContainsPoint(_centerView.frame, location) == YES) { + allowPan = YES; + } + } else if((_showedRightController == YES) && (_rightController != nil)) { + if(CGRectContainsPoint(_centerView.frame, location) == YES) { + allowPan = YES; + } + } else if((_showedLeftController == NO) && (_leftController != nil) && (translation.x > 0.0f)) { + if(MOBILY_FABS(translation.x) >= MOBILY_FABS(translation.y)) { + allowPan = CGRectContainsPoint(_centerView.frame, location); + if(allowPan == YES) { + id< MobilySlideControllerDelegate > centerController = ([_centerController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_centerController : nil; + if([centerController respondsToSelector:@selector(canShowLeftControllerInSlideController:)] == YES) { + if([centerController canShowLeftControllerInSlideController:self] == YES) { + id< MobilySlideControllerDelegate > leftController = ([_leftController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_leftController : nil; + if([leftController respondsToSelector:@selector(canShowControllerInSlideController:)] == YES) { + allowPan = [leftController canShowControllerInSlideController:self]; + } + } else { + allowPan = NO; + } + } + } + } + } else if((_showedRightController == NO) && (_rightController != nil) && (translation.x < 0.0f)) { + if(MOBILY_FABS(translation.x) >= MOBILY_FABS(translation.y)) { + allowPan = CGRectContainsPoint(_centerView.frame, location); + if(allowPan == YES) { + id< MobilySlideControllerDelegate > centerController = ([_centerController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_centerController : nil; + if([centerController respondsToSelector:@selector(canShowRightControllerInSlideController:)] == YES) { + if([centerController canShowRightControllerInSlideController:self] == YES) { + id< MobilySlideControllerDelegate > rightController = ([_rightController conformsToProtocol:@protocol(MobilySlideControllerDelegate)] == YES) ? (id< MobilySlideControllerDelegate >)_rightController : nil; + if([rightController respondsToSelector:@selector(canShowControllerInSlideController:)] == YES) { + allowPan = [rightController canShowControllerInSlideController:self]; + } + } else { + allowPan = NO; + } + } + } + } + } + return allowPan; + } + } + return NO; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UIViewController (MobilySlideController) + +- (void)setMoSlideController:(MobilySlideController*)moSlideController { + objc_setAssociatedObject(self, @selector(moSlideController), moSlideController, OBJC_ASSOCIATION_ASSIGN); +} + +- (MobilySlideController*)moSlideController { + MobilySlideController* controller = objc_getAssociatedObject(self, @selector(moSlideController)); + if(controller == nil) { + controller = self.parentViewController.moSlideController; + } + return controller; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySpinnerView.h b/Sources/MobilyCore/MobilySpinnerView.h new file mode 100644 index 0000000..d51d107 --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerView.h @@ -0,0 +1,138 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilySpinnerView : UIView < MobilyObject > + +@property(nonatomic, readwrite, strong) IBInspectable UIColor* color; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat size; +@property(nonatomic, readwrite, assign) IBInspectable BOOL hidesWhenStopped; +@property(nonatomic, readonly, assign, getter=isAnimating) BOOL animating; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)startAnimating; +- (void)stopAnimating; + +- (void)prepareAnimation NS_REQUIRES_SUPER; + +@end + +/*--------------------------------------------------*/ + +@interface MobilySpinnerViewPlane : MobilySpinnerView +@end + +/*--------------------------------------------------*/ + +@interface MobilySpinnerViewCircleFlip : MobilySpinnerView +@end + +/*--------------------------------------------------*/ + +@interface MobilySpinnerViewBounce : MobilySpinnerView +@end + +/*--------------------------------------------------*/ + +@interface MobilySpinnerViewWave : MobilySpinnerView +@end + +/*--------------------------------------------------*/ + +@interface MobilySpinnerViewWanderingCubes : MobilySpinnerView +@end + +/*--------------------------------------------------*/ + +@interface MobilySpinnerViewPulse : MobilySpinnerView +@end + +/*--------------------------------------------------*/ + +@interface MobilySpinnerViewChasingDots : MobilySpinnerView +@end + +/*--------------------------------------------------*/ + +@interface MobilySpinnerViewThreeBounce : MobilySpinnerView +@end + +/*--------------------------------------------------*/ + +@interface MobilySpinnerViewCircle : MobilySpinnerView +@end + +/*--------------------------------------------------*/ + +@interface MobilySpinnerView9CubeGrid : MobilySpinnerView +@end + +/*--------------------------------------------------*/ + +@interface MobilySpinnerViewWordPress : MobilySpinnerView +@end + +/*--------------------------------------------------*/ + +@interface MobilySpinnerViewFadingCircle : MobilySpinnerView +@end + +/*--------------------------------------------------*/ + +@interface MobilySpinnerViewFadingCircleAlt : MobilySpinnerView + +@property(nonatomic, readwrite, assign) IBInspectable NSUInteger numberOfCircle; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat factorCircle; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat factorRadius; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat minScale; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat minOpacity; + +@end + +/*--------------------------------------------------*/ + +@interface MobilySpinnerViewArc : MobilySpinnerView +@end + +/*--------------------------------------------------*/ + +@interface MobilySpinnerViewArcAlt : MobilySpinnerView +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySpinnerView.m b/Sources/MobilyCore/MobilySpinnerView.m new file mode 100644 index 0000000..5bdd967 --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerView.m @@ -0,0 +1,192 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilySpinnerView () + +@property(nonatomic, readwrite, assign, getter=isStopped) BOOL stopped; +@property(nonatomic, readwrite, assign, getter=isAnimating) BOOL animating; + +- (void)applicationDidEnterBackground; +- (void)applicationWillEnterForeground; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#define MobilySpinnerViewSize 42.0f +#define MobilySpinnerViewColor [UIColor colorWithWhite:1.0f alpha:0.8f] + +/*--------------------------------------------------*/ + +@implementation MobilySpinnerView + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + _size = MobilySpinnerViewSize; + _color = MobilySpinnerViewColor; + _hidesWhenStopped = NO; + + self.backgroundColor = UIColor.clearColor; + self.hidden = NO; + self.layer.timeOffset = [self.layer convertTime:CACurrentMediaTime() fromLayer:nil]; + self.layer.speed = 0.0f; + + [self prepareAnimation]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidEnterBackground) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillEnterForeground) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma Property + +-(void)setSize:(CGFloat)size { + if(_size != size) { + _size = size; + [self invalidateIntrinsicContentSize]; + [self prepareAnimation]; + } +} + +- (void)setColor:(UIColor*)color { + if([_color isEqual:color] == NO) { + _color = color; + [self prepareAnimation]; + } +} + +- (void)setHidesWhenStopped:(BOOL)hidesWhenStopped { + if(_hidesWhenStopped != hidesWhenStopped) { + _hidesWhenStopped = hidesWhenStopped; + if(_hidesWhenStopped == YES) { + if(_animating == NO) { + self.layer.sublayers = nil; + self.hidden = YES; + } + } else { + self.hidden = NO; + [self prepareAnimation]; + } + } +} + +#pragma mark Public override + +- (CGSize)sizeThatFits:(CGSize __unused)size { + return CGSizeMake(_size, _size); +} + +- (CGSize)intrinsicContentSize { + return CGSizeMake(_size, _size); +} + +#pragma mark Public + +- (void)startAnimating { + if(_animating == NO) { + _animating = YES; + self.hidden = NO; + if(self.layer.sublayers.count < 1) { + [self prepareAnimation]; + } + CFTimeInterval currentTime = CACurrentMediaTime(); + CFTimeInterval pausedTime = self.layer.timeOffset; + self.layer.beginTime = [self.layer convertTime:currentTime fromLayer:nil] - pausedTime;; + self.layer.timeOffset = 0.0f; + self.layer.speed = 1.0; + } +} + +- (void)stopAnimating { + if(_animating == YES) { + _animating = NO; + if(_hidesWhenStopped == YES) { + self.layer.sublayers = nil; + self.hidden = YES; + } + self.layer.timeOffset = [self.layer convertTime:CACurrentMediaTime() fromLayer:nil]; + self.layer.speed = 0.0f; + } +} + +- (void)prepareAnimation { + self.layer.sublayers = nil; +} + +#pragma mark Private + +- (void)applicationDidEnterBackground { + if(_animating == YES) { + self.layer.sublayers = nil; + } +} + +- (void)applicationWillEnterForeground { + if(_animating == YES) { + [self prepareAnimation]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySpinnerView9CubeGrid.m b/Sources/MobilyCore/MobilySpinnerView9CubeGrid.m new file mode 100644 index 0000000..570836f --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerView9CubeGrid.m @@ -0,0 +1,86 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilySpinnerView9CubeGrid + +- (void)prepareAnimation { + [super prepareAnimation]; + + NSTimeInterval beginTime = CACurrentMediaTime(); + CGFloat squareSize = self.size / 3; + for(NSInteger sum = 0; sum < 5; sum++) { + for(NSInteger x = 0; x < 3; x++) { + for(NSInteger y = 0; y < 3; y++) { + if(x + y == sum) { + CALayer* square = [CALayer layer]; + square.frame = CGRectMake(x * squareSize, y * squareSize, squareSize, squareSize); + square.backgroundColor = self.color.CGColor; + square.transform = CATransform3DMakeScale(0.0f, 0.0f, 0.0f); + + CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; + animation.removedOnCompletion = NO; + animation.repeatCount = HUGE_VALF; + animation.duration = 1.5f; + animation.beginTime = beginTime + (0.1f * sum); + animation.keyTimes = @[@(0.0f), @(0.4f), @(0.6f), @(1.0f)]; + animation.timingFunctions = @[ + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] + ]; + animation.values = @[ + [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0f, 0.0f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0f, 1.0f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0f, 1.0f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0f, 0.0f, 0.0f)] + ]; + [self.layer addSublayer:square]; + [square addAnimation:animation forKey:@"square"]; + } + } + } + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySpinnerViewArc.m b/Sources/MobilyCore/MobilySpinnerViewArc.m new file mode 100644 index 0000000..7408405 --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerViewArc.m @@ -0,0 +1,86 @@ +//*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilySpinnerViewArc + +- (void)prepareAnimation { + [super prepareAnimation]; + + NSTimeInterval beginTime = CACurrentMediaTime(); + CGRect frame = CGRectInset(CGRectMake(0.0f, 0.0f, self.size, self.size), 2.0f, 2.0f); + CGFloat radius = CGRectGetWidth(frame) / 2.0f; + CGPoint center = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame)); + + CALayer* circle = [CALayer layer]; + circle.frame = CGRectMake(0.0f, 0.0f, self.size, self.size); + circle.backgroundColor = self.color.CGColor; + circle.anchorPoint = CGPointMake(0.5f, 0.5f); + circle.cornerRadius = self.size * 0.5f; + [self.layer addSublayer:circle]; + + CAShapeLayer* mask = [CAShapeLayer layer]; + mask.frame = CGRectMake(0.0f, 0.0f, self.size, self.size); + mask.path = [[UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0.0f endAngle:((M_PI * 2.0f) / 360.0f) * 300.0f clockwise:YES] CGPath]; + mask.strokeColor = UIColor.blackColor.CGColor; + mask.fillColor = UIColor.clearColor.CGColor; + mask.lineWidth = 2.0f; + mask.cornerRadius = self.size * 0.5f; + mask.anchorPoint = CGPointMake(0.5f, 0.5f); + circle.mask = mask; + + CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"]; + animation.removedOnCompletion = NO; + animation.repeatCount = HUGE_VALF; + animation.duration = 0.8f; + animation.beginTime = beginTime; + animation.keyTimes = @[@(0.0f), @(0.5f), @(1.0f)]; + animation.values = @[ + [NSNumber numberWithDouble:0.0f], + [NSNumber numberWithDouble:M_PI], + [NSNumber numberWithDouble:M_PI * 2.0f] + ]; + + [circle addAnimation:animation forKey:@"circle"]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySpinnerViewArcAlt.m b/Sources/MobilyCore/MobilySpinnerViewArcAlt.m new file mode 100644 index 0000000..887b225 --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerViewArcAlt.m @@ -0,0 +1,101 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilySpinnerViewArcAlt + +- (void)prepareAnimation { + [super prepareAnimation]; + + NSTimeInterval beginTime = CACurrentMediaTime(); + CGRect frame = CGRectInset(CGRectMake(0.0f, 0.0f, self.size, self.size), 2.0f, 2.0f); + CGFloat radius = CGRectGetWidth(frame) / 2.0f; + CGPoint center = CGPointMake(CGRectGetMidX(frame), CGRectGetMidY(frame)); + + CALayer* arc = [CALayer layer]; + arc.frame = CGRectMake(0.0f, 0.0f, self.size, self.size); + arc.backgroundColor = self.color.CGColor; + arc.anchorPoint = CGPointMake(0.5f, 0.5f); + arc.cornerRadius = self.size * 0.5f; + [self.layer addSublayer:arc]; + + CAShapeLayer* mask = [CAShapeLayer layer]; + mask.frame = CGRectMake(0.0f, 0.0f, self.size, self.size); + mask.path = [[UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0.0f endAngle:M_PI * 2.0f clockwise:YES] CGPath]; + mask.strokeColor = UIColor.blackColor.CGColor; + mask.fillColor = UIColor.clearColor.CGColor; + mask.lineWidth = 2.0f; + mask.cornerRadius = self.size * 0.5f; + mask.anchorPoint = CGPointMake(0.5f, 0.5f); + arc.mask = mask; + + CAKeyframeAnimation* strokeStartAnimation = [CAKeyframeAnimation animationWithKeyPath:@"strokeStart"]; + strokeStartAnimation.removedOnCompletion = NO; + strokeStartAnimation.repeatCount = HUGE_VALF; + strokeStartAnimation.duration = 1.2f; + strokeStartAnimation.beginTime = beginTime; + strokeStartAnimation.keyTimes = @[@(0.0f), @(0.6f), @(1.0f)]; + strokeStartAnimation.values = @[@(0.0f), @(0.0f), @(1.0f)]; + strokeStartAnimation.timingFunctions = @[ + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + ]; + [mask addAnimation:strokeStartAnimation forKey:@"circle-start"]; + + CAKeyframeAnimation* strokeEndAnimation = [CAKeyframeAnimation animationWithKeyPath:@"strokeEnd"]; + strokeEndAnimation.removedOnCompletion = NO; + strokeEndAnimation.repeatCount = HUGE_VALF; + strokeEndAnimation.duration = 1.2f; + strokeEndAnimation.beginTime = beginTime; + strokeEndAnimation.keyTimes = @[@(0.0f), @(0.4f), @(1.0f)]; + strokeEndAnimation.values = @[@(0.0f), @(1.0f), @(1.0f)]; + strokeEndAnimation.timingFunctions = @[ + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut], + ]; + [mask addAnimation:strokeEndAnimation forKey:@"circle-end"]; +} + +@end + +/*--------------------------------------------------*/ + diff --git a/Sources/MobilyCore/MobilySpinnerViewBounce.m b/Sources/MobilyCore/MobilySpinnerViewBounce.m new file mode 100644 index 0000000..eca9d32 --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerViewBounce.m @@ -0,0 +1,80 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilySpinnerViewBounce + +- (void)prepareAnimation { + [super prepareAnimation]; + + NSTimeInterval beginTime = CACurrentMediaTime(); + for(NSInteger i = 0; i < 2; i++) { + CALayer* circle = [CALayer layer]; + circle.frame = CGRectInset(CGRectMake(0.0f, 0.0f, self.size, self.size), 2.0f, 2.0f); + circle.backgroundColor = self.color.CGColor; + circle.anchorPoint = CGPointMake(0.5f, 0.5f); + circle.opacity = 0.6; + circle.cornerRadius = CGRectGetHeight(circle.bounds) * 0.5f; + circle.transform = CATransform3DMakeScale(0.0f, 0.0f, 0.0f); + [self.layer addSublayer:circle]; + + CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; + animation.removedOnCompletion = NO; + animation.repeatCount = HUGE_VALF; + animation.duration = 2.0f; + animation.beginTime = beginTime - (1.0f * i); + animation.keyTimes = @[@(0.0f), @(0.5f), @(1.0f)]; + animation.timingFunctions = @[ + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] + ]; + animation.values = @[ + [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0f, 0.0f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0f, 1.0f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0f, 0.0f, 0.0f)] + ]; + [circle addAnimation:animation forKey:@"spinner"]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySpinnerViewChasingDots.m b/Sources/MobilyCore/MobilySpinnerViewChasingDots.m new file mode 100644 index 0000000..cc2e503 --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerViewChasingDots.m @@ -0,0 +1,113 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilySpinnerViewChasingDots + +- (void)prepareAnimation { + [super prepareAnimation]; + + NSTimeInterval beginTime = CACurrentMediaTime(); + + CALayer* spinner = [CALayer layer]; + spinner.frame = CGRectMake(0.0f, 0.0f, self.size, self.size); + spinner.anchorPoint = CGPointMake(0.5f, 0.5f); + spinner.transform = CATransform3DIdentity; + spinner.shouldRasterize = YES; + spinner.rasterizationScale = UIScreen.mainScreen.scale; + [self.layer addSublayer:spinner]; + + CAKeyframeAnimation* spinnerAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; + spinnerAnimation.removedOnCompletion = NO; + spinnerAnimation.repeatCount = HUGE_VALF; + spinnerAnimation.duration = 2.0f; + spinnerAnimation.beginTime = beginTime; + spinnerAnimation.keyTimes = @[@(0.0f), @(0.25), @(0.5f), @(0.75), @(1.0f)]; + spinnerAnimation.timingFunctions = @[ + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear] + ]; + spinnerAnimation.values = @[ + [NSValue valueWithCATransform3D:CATransform3DMakeRotation(0.0f, 0.0f, 0.0f, 1.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_2, 0.0f, 0.0f, 1.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 0.0f, 0.0f, 1.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeRotation(3.0f * M_PI_2, 0.0f, 0.0f, 1.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeRotation(2.0f * M_PI, 0.0f, 0.0f, 1.0f)] + ]; + [spinner addAnimation:spinnerAnimation forKey:@"spinner"]; + + for(NSInteger i = 0; i < 2; i++) { + CGFloat offset = self.size * 0.3f * i; + + CALayer* circle = [CALayer layer]; + circle.frame = CGRectOffset(CGRectApplyAffineTransform(CGRectMake(0.0f, 0.0f, self.size, self.size), CGAffineTransformMakeScale(0.6f, 0.6f)), offset, offset); + circle.backgroundColor = self.color.CGColor; + circle.anchorPoint = CGPointMake(0.5f, 0.5f); + circle.cornerRadius = CGRectGetHeight(circle.bounds) * 0.5f; + circle.transform = CATransform3DMakeScale(0.0f, 0.0f, 0.0f); + [spinner addSublayer:circle]; + + CAKeyframeAnimation* circleAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; + circleAnimation.removedOnCompletion = NO; + circleAnimation.repeatCount = HUGE_VALF; + circleAnimation.duration = 2.0f; + circleAnimation.beginTime = beginTime - (1.0f * i); + circleAnimation.keyTimes = @[@(0.0f), @(0.5f), @(1.0f)]; + circleAnimation.timingFunctions = @[ + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] + ]; + circleAnimation.values = @[ + [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0f, 0.0f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0f, 1.0f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0f, 0.0f, 0.0f)] + ]; + [circle addAnimation:circleAnimation forKey:@"circle"]; + } +} + +@end + +/*--------------------------------------------------*/ + diff --git a/Sources/MobilyCore/MobilySpinnerViewCircle.m b/Sources/MobilyCore/MobilySpinnerViewCircle.m new file mode 100644 index 0000000..8fde419 --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerViewCircle.m @@ -0,0 +1,87 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilySpinnerViewCircle + +- (void)prepareAnimation { + [super prepareAnimation]; + + NSTimeInterval beginTime = CACurrentMediaTime(); + CGFloat circleSize = self.size * 0.25f; + CGFloat circleSize2 = circleSize * 0.5f; + CGFloat radius = self.size * 0.5f; + CGFloat radius2 = radius - circleSize2; + for(NSInteger i = 0; i < 8; i++) { + CGFloat angle = i * M_PI_4; + CGFloat x = (radius + (sinf(angle) * radius2)) - circleSize2; + CGFloat y = (radius - (cosf(angle) * radius2)) - circleSize2; + + CALayer* circle = [CALayer layer]; + circle.frame = CGRectMake(x, y, circleSize, circleSize); + circle.backgroundColor = self.color.CGColor; + circle.anchorPoint = CGPointMake(0.5f, 0.5f); + circle.cornerRadius = circleSize * 0.5f; + circle.transform = CATransform3DMakeScale(0.0f, 0.0f, 0.0f); + [self.layer addSublayer:circle]; + + CAKeyframeAnimation* circleAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; + circleAnimation.removedOnCompletion = NO; + circleAnimation.repeatCount = HUGE_VALF; + circleAnimation.duration = 1.0f; + circleAnimation.beginTime = beginTime + (0.125f * i); + circleAnimation.keyTimes = @[@(0.0f), @(0.5f), @(1.0f)]; + circleAnimation.timingFunctions = @[ + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] + ]; + circleAnimation.values = @[ + [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0f, 0.0f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0f, 1.0f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0f, 0.0f, 0.0f)] + ]; + [circle addAnimation:circleAnimation forKey:@"circle"]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySpinnerViewCircleFlip.m b/Sources/MobilyCore/MobilySpinnerViewCircleFlip.m new file mode 100644 index 0000000..5aebbc8 --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerViewCircleFlip.m @@ -0,0 +1,77 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilySpinnerViewCircleFlip + +- (void)prepareAnimation { + [super prepareAnimation]; + + CALayer* circle = [CALayer layer]; + circle.frame = CGRectInset(CGRectMake(0.0f, 0.0f, self.size, self.size), 2.0f, 2.0f); + circle.backgroundColor = self.color.CGColor; + circle.cornerRadius = self.size * 0.5f; + circle.anchorPoint = CGPointMake(0.5f, 0.5f); + circle.anchorPointZ = 0.5; + circle.shouldRasterize = YES; + circle.rasterizationScale = UIScreen.mainScreen.scale; + [self.layer addSublayer:circle]; + + CAKeyframeAnimation* circleAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; + circleAnimation.removedOnCompletion = NO; + circleAnimation.repeatCount = HUGE_VALF; + circleAnimation.duration = 1.2; + circleAnimation.keyTimes = @[@(0.0), @(0.5), @(1.0)]; + circleAnimation.timingFunctions = @[ + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] + ]; + circleAnimation.values = @[ + [NSValue valueWithCATransform3D:MobilyTransform3DRotationWithPerspective(1.0f / 120.0f, 0.0f, 0.0f, 0.0f, 0.0f)], + [NSValue valueWithCATransform3D:MobilyTransform3DRotationWithPerspective(1.0f / 120.0f, M_PI, 0.0f, 1.0f, 0.0f)], + [NSValue valueWithCATransform3D:MobilyTransform3DRotationWithPerspective(1.0f / 120.0f, M_PI, 0.0f, 0.0f, 1.0f)] + ]; + [circle addAnimation:circleAnimation forKey:@"circle"]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySpinnerViewFadingCircle.m b/Sources/MobilyCore/MobilySpinnerViewFadingCircle.m new file mode 100644 index 0000000..8e46d51 --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerViewFadingCircle.m @@ -0,0 +1,82 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilySpinnerViewFadingCircle + +- (void)prepareAnimation { + [super prepareAnimation]; + + NSTimeInterval beginTime = CACurrentMediaTime(); + CGFloat squareSize = self.size / 6.0f; + CGFloat squareSize2 = squareSize * 0.5f; + CGFloat radius = self.size * 0.5f; + CGFloat radius2 = radius - squareSize2; + for(NSInteger i = 0; i < 12; i++) { + CGFloat angle = i * (M_PI_2 / 3.0f); + CGFloat x = (radius + (sinf(angle) * radius2)) - squareSize2; + CGFloat y = (radius - (cosf(angle) * radius2)) - squareSize2; + + CALayer* square = [CALayer layer]; + square.frame = CGRectMake(x, y, squareSize, squareSize); + square.transform = CATransform3DRotate(CATransform3DIdentity, angle, 0.0f, 0.0f, 1.0f); + square.anchorPoint = CGPointMake(0.5f, 0.5f); + square.backgroundColor = self.color.CGColor; + square.opacity = 0.0f; + [self.layer addSublayer:square]; + + CAKeyframeAnimation* squareAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; + squareAnimation.removedOnCompletion = NO; + squareAnimation.repeatCount = HUGE_VALF; + squareAnimation.duration = 1.0; + squareAnimation.beginTime = beginTime + (0.084 * i); + squareAnimation.keyTimes = @[@(0.0), @(0.5), @(1.0)]; + squareAnimation.timingFunctions = @[ + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] + ]; + squareAnimation.values = @[@(1.0), @(0.0), @(0.0)]; + [square addAnimation:squareAnimation forKey:@"square"]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySpinnerViewFadingCircleAlt.m b/Sources/MobilyCore/MobilySpinnerViewFadingCircleAlt.m new file mode 100644 index 0000000..44373a3 --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerViewFadingCircleAlt.m @@ -0,0 +1,96 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilySpinnerViewFadingCircleAlt + +- (void)setup { + [super setup]; + + _numberOfCircle = 12; + _factorCircle = 0.25f; + _factorRadius = 0.5f; + _minScale = 0.1f; + _minOpacity = 0.0f; +} + +- (void)prepareAnimation { + [super prepareAnimation]; + + NSTimeInterval beginTime = CACurrentMediaTime(); + CGFloat squareSize = self.size * _factorCircle; + CGFloat squareSize2 = squareSize * 0.5f; + CGFloat radius = self.size * _factorRadius; + CGFloat radius2 = radius - squareSize2; + for(NSInteger i = 0; i < _numberOfCircle; i++) { + CGFloat angle = MOBILY_DEG_TO_RAD * ((360.0f / _numberOfCircle) * i); + CGFloat x = (radius + (cosf(angle) * radius2)) - squareSize2; + CGFloat y = (radius - (sinf(angle) * radius2)) - squareSize2; + + CALayer* circle = [CALayer layer]; + circle.backgroundColor = self.color.CGColor; + circle.frame = CGRectMake(x, y, squareSize, squareSize); + circle.anchorPoint = CGPointMake(0.5f, 0.5f); + circle.cornerRadius = radius * 0.25f; + circle.rasterizationScale = UIScreen.mainScreen.scale; + circle.shouldRasterize = YES; + [self.layer addSublayer:circle]; + + CAKeyframeAnimation* transformAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; + transformAnimation.values = @[ + [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0f, 1.0f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(_minScale, _minScale, 0.0f)] + ]; + CAKeyframeAnimation* opacityAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; + opacityAnimation.values = @[ @(1.0f), @(_minOpacity) ]; + + CAAnimationGroup* groupAnimation = [[CAAnimationGroup alloc] init]; + groupAnimation.removedOnCompletion = NO; + groupAnimation.repeatCount = HUGE_VALF; + groupAnimation.duration = 0.1f * _numberOfCircle; + groupAnimation.beginTime = beginTime - (groupAnimation.duration - (0.1f * i)); + groupAnimation.animations = @[ transformAnimation, opacityAnimation ]; + [circle addAnimation:groupAnimation forKey:@"group"]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/ControllerDynamicsDrawer/MobilyControllerDynamicsDrawer.h b/Sources/MobilyCore/MobilySpinnerViewPlane.m similarity index 54% rename from Classes/UI/ControllerDynamicsDrawer/MobilyControllerDynamicsDrawer.h rename to Sources/MobilyCore/MobilySpinnerViewPlane.m index 74ee246..049cabd 100644 --- a/Classes/UI/ControllerDynamicsDrawer/MobilyControllerDynamicsDrawer.h +++ b/Sources/MobilyCore/MobilySpinnerViewPlane.m @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -32,42 +32,46 @@ /* OTHER DEALINGS IN THE SOFTWARE. */ /* */ /*--------------------------------------------------*/ - -#import "MobilyController.h" - +#define MOBILY_SOURCE /*--------------------------------------------------*/ -#import +#import /*--------------------------------------------------*/ -@interface MobilyControllerDynamicsDrawer : MSDynamicsDrawerViewController< MobilyBuilderObject > - -@property(nonatomic, readwrite, assign) BOOL navigationBarHidden; - -@property(nonatomic, readonly, assign, getter=isAppeared) BOOL appeared; -@property(nonatomic, readwrite, strong) MobilyTransitionController* transitionModal; +@implementation MobilySpinnerViewPlane -@property(nonatomic, readwrite, strong) id< MobilyEvent > eventDidLoad; -@property(nonatomic, readwrite, strong) id< MobilyEvent > eventDidUnload; -@property(nonatomic, readwrite, strong) id< MobilyEvent > eventWillAppear; -@property(nonatomic, readwrite, strong) id< MobilyEvent > eventDidAppear; -@property(nonatomic, readwrite, strong) id< MobilyEvent > eventWillDisappear; -@property(nonatomic, readwrite, strong) id< MobilyEvent > eventDidDisappear; +- (void)prepareAnimation { + [super prepareAnimation]; + + CALayer* plane = [CALayer layer]; + plane.frame = CGRectInset(CGRectMake(0.0f, 0.0f, self.size, self.size), 2.0f, 2.0f); + plane.backgroundColor = self.color.CGColor; + plane.anchorPoint = CGPointMake(0.5f, 0.5f); + plane.anchorPointZ = 0.5f; + plane.shouldRasterize = YES; + plane.rasterizationScale = [[UIScreen mainScreen] scale]; + [self.layer addSublayer:plane]; -@property(nonatomic, readwrite, strong) UIViewController* leftDrawerViewController; -@property(nonatomic, readwrite, strong) UIViewController* rightDrawerViewController; - -- (void)showWideLeftDrawerAnimated:(BOOL)animated completion:(void (^)(void))completion; -- (void)showLeftDrawerAnimated:(BOOL)animated completion:(void (^)(void))completion; -- (void)hideLeftDrawerAnimated:(BOOL)animated completion:(void (^)(void))completion; - -- (void)showWideRightDrawerAnimated:(BOOL)animated completion:(void (^)(void))completion; -- (void)showRightDrawerAnimated:(BOOL)animated completion:(void (^)(void))completion; -- (void)hideRightDrawerAnimated:(BOOL)animated completion:(void (^)(void))completion; - -- (void)setupController; + CAKeyframeAnimation* planeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; + planeAnimation.removedOnCompletion = NO; + planeAnimation.repeatCount = HUGE_VALF; + planeAnimation.duration = 1.2; + planeAnimation.keyTimes = @[@(0.0), @(0.5), @(1.0)]; + planeAnimation.timingFunctions = @[ + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] + ]; + planeAnimation.values = @[ + [NSValue valueWithCATransform3D:MobilyTransform3DRotationWithPerspective(1.0f / 120.0f, 0.0f, 0.0f, 0.0f, 0.0f)], + [NSValue valueWithCATransform3D:MobilyTransform3DRotationWithPerspective(1.0f / 120.0f, M_PI, 0.0f, 1.0f, 0.0f)], + [NSValue valueWithCATransform3D:MobilyTransform3DRotationWithPerspective(1.0f / 120.0f, M_PI, 0.0f, 0.0f, 1.0f)] + ]; + [plane addAnimation:planeAnimation forKey:@"plane"]; +} @end /*--------------------------------------------------*/ + diff --git a/Sources/MobilyCore/MobilySpinnerViewPulse.m b/Sources/MobilyCore/MobilySpinnerViewPulse.m new file mode 100644 index 0000000..f2604dd --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerViewPulse.m @@ -0,0 +1,81 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilySpinnerViewPulse + +- (void)prepareAnimation { + [super prepareAnimation]; + + NSTimeInterval beginTime = CACurrentMediaTime(); + + CALayer* circle = [CALayer layer]; + circle.frame = CGRectInset(CGRectMake(0.0f, 0.0f, self.size, self.size), 2.0f, 2.0f); + circle.backgroundColor = self.color.CGColor; + circle.anchorPoint = CGPointMake(0.5f, 0.5f); + circle.opacity = 1.0f; + circle.cornerRadius = CGRectGetHeight(circle.bounds) * 0.5f; + circle.transform = CATransform3DMakeScale(0.0f, 0.0f, 0.0f); + [self.layer addSublayer:circle]; + + CAKeyframeAnimation* scaleAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; + scaleAnimation.values = @[ + [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0f, 0.0f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0f, 1.0f, 0.0f)] + ]; + CAKeyframeAnimation* opacityAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; + opacityAnimation.values = @[ + @(1.0f), + @(0.0f) + ]; + + CAAnimationGroup* groupAnimation = [CAAnimationGroup animation]; + groupAnimation.removedOnCompletion = NO; + groupAnimation.beginTime = beginTime; + groupAnimation.repeatCount = HUGE_VALF; + groupAnimation.duration = 1.0f; + groupAnimation.animations = @[ scaleAnimation, opacityAnimation ]; + groupAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; + [circle addAnimation:groupAnimation forKey:@"circle"]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySpinnerViewThreeBounce.m b/Sources/MobilyCore/MobilySpinnerViewThreeBounce.m new file mode 100644 index 0000000..89e8244 --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerViewThreeBounce.m @@ -0,0 +1,82 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilySpinnerViewThreeBounce + +- (void)prepareAnimation { + [super prepareAnimation]; + + NSTimeInterval beginTime = CACurrentMediaTime(); + CGFloat offset = self.size / 8.0f; + CGFloat circleSize = offset * 2.0f; + CGFloat circleSize2 = circleSize * 0.5f; + for (NSInteger i=0; i < 3; i+=1) { + CALayer* circle = [CALayer layer]; + circle.frame = CGRectMake(i * 3.0f * offset, (self.size * 0.5f) - circleSize2, circleSize, circleSize); + circle.backgroundColor = self.color.CGColor; + circle.anchorPoint = CGPointMake(0.5f, 0.5f); + circle.cornerRadius = circleSize * 0.5f; + circle.transform = CATransform3DMakeScale(0.0f, 0.0f, 0.0f); + [self.layer addSublayer:circle]; + + CAKeyframeAnimation* circleAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; + circleAnimation.removedOnCompletion = NO; + circleAnimation.repeatCount = HUGE_VALF; + circleAnimation.duration = 1.5f; + circleAnimation.beginTime = beginTime + (0.25f * i); + circleAnimation.keyTimes = @[ @(0.0f), @(0.5f), @(1.0f) ]; + circleAnimation.timingFunctions = @[ + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] + ]; + circleAnimation.values = @[ + [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0f, 0.0f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0f, 1.0f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(0.0f, 0.0f, 0.0f)] + ]; + [circle addAnimation:circleAnimation forKey:@"circle"]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySpinnerViewWanderingCubes.m b/Sources/MobilyCore/MobilySpinnerViewWanderingCubes.m new file mode 100644 index 0000000..8beef4c --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerViewWanderingCubes.m @@ -0,0 +1,100 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilySpinnerViewWanderingCubes + +- (void)prepareAnimation { + [super prepareAnimation]; + + NSTimeInterval beginTime = CACurrentMediaTime(); + CGFloat cubeSize = MOBILY_FLOOR(self.size / 3.0f); + CGFloat widthMinusCubeSize = self.size - cubeSize; + for(NSInteger i = 0; i < 2; i++) { + CALayer* cube = [CALayer layer]; + cube.backgroundColor = self.color.CGColor; + cube.frame = CGRectMake(0.0f, 0.0f, cubeSize, cubeSize); + cube.anchorPoint = CGPointMake(0.5f, 0.5f); + cube.rasterizationScale = UIScreen.mainScreen.scale; + cube.shouldRasterize = YES; + [self.layer addSublayer:cube]; + + CAKeyframeAnimation* cubeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; + cubeAnimation.removedOnCompletion = NO; + cubeAnimation.beginTime = beginTime - (i * 0.9f); + cubeAnimation.duration = 1.8f; + cubeAnimation.repeatCount = HUGE_VALF; + cubeAnimation.timingFunctions = @[ + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] + ]; + cubeAnimation.keyTimes = @[ @(0.0f), @(0.25f), @(0.50f), @(0.75f), @(1.0f)]; + + CATransform3D t0 = CATransform3DIdentity; + CATransform3D t1 = CATransform3DMakeTranslation(widthMinusCubeSize, 0.0f, 0.0f); + t1 = CATransform3DRotate(t1, -90.0f * MOBILY_DEG_TO_RAD, 0.0f, 0.0f, 1.0f); + t1 = CATransform3DScale(t1, 0.5f, 0.5f, 1.0f); + CATransform3D t2 = CATransform3DMakeTranslation(widthMinusCubeSize, widthMinusCubeSize, 0.0f); + t2 = CATransform3DRotate(t2, -180.0f * MOBILY_DEG_TO_RAD, 0.0f, 0.0f, 1.0f); + t2 = CATransform3DScale(t2, 1.0f, 1.0f, 1.0f); + CATransform3D t3 = CATransform3DMakeTranslation(0.0f, widthMinusCubeSize, 0.0f); + t3 = CATransform3DRotate(t3, -270.0f * MOBILY_DEG_TO_RAD, 0.0f, 0.0f, 1.0f); + t3 = CATransform3DScale(t3, 0.5f, 0.5f, 1.0f); + CATransform3D t4 = CATransform3DMakeTranslation(0.0f, 0.0f, 0.0f); + t4 = CATransform3DRotate(t4, -360.0f * MOBILY_DEG_TO_RAD, 0.0f, 0.0f, 1.0f); + t4 = CATransform3DScale(t4, 1.0f, 1.0f, 1.0f); + + cubeAnimation.values = @[ + [NSValue valueWithCATransform3D:t0], + [NSValue valueWithCATransform3D:t1], + [NSValue valueWithCATransform3D:t2], + [NSValue valueWithCATransform3D:t3], + [NSValue valueWithCATransform3D:t4] + ]; + [cube addAnimation:cubeAnimation forKey:@"cube"]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySpinnerViewWave.m b/Sources/MobilyCore/MobilySpinnerViewWave.m new file mode 100644 index 0000000..324f14b --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerViewWave.m @@ -0,0 +1,81 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilySpinnerViewWave + +- (void)prepareAnimation { + [super prepareAnimation]; + + NSTimeInterval beginTime = CACurrentMediaTime() + 1.2f; + CGFloat barWidth = self.size / 5.0f; + for(NSInteger i = 0; i < 5; i++) { + CALayer* bar = [CALayer layer]; + bar.backgroundColor = self.color.CGColor; + bar.frame = CGRectMake(barWidth * i, 0.0f, barWidth - 3.0f, self.size); + bar.transform = CATransform3DMakeScale(1.0f, 0.3f, 0.0f); + [self.layer addSublayer:bar]; + + CAKeyframeAnimation* barAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; + barAnimation.removedOnCompletion = NO; + barAnimation.beginTime = beginTime - (1.2f - (0.1f * i)); + barAnimation.duration = 1.2f; + barAnimation.repeatCount = HUGE_VALF; + barAnimation.keyTimes = @[ @(0.0f), @(0.2f), @(0.4f), @(1.0f) ]; + barAnimation.timingFunctions = @[ + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut] + ]; + barAnimation.values = @[ + [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0f, 0.4f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0f, 1.0f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0f, 0.4f, 0.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0f, 0.4f, 0.0f)] + ]; + + [bar addAnimation:barAnimation forKey:@"bar"]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilySpinnerViewWordPress.m b/Sources/MobilyCore/MobilySpinnerViewWordPress.m new file mode 100644 index 0000000..aa07fe3 --- /dev/null +++ b/Sources/MobilyCore/MobilySpinnerViewWordPress.m @@ -0,0 +1,100 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilySpinnerViewWordPress + +- (void)prepareAnimation { + [super prepareAnimation]; + + NSTimeInterval beginTime = CACurrentMediaTime(); + + CALayer* spinner = [CALayer layer]; + spinner.frame = CGRectMake(0.0f, 0.0f, self.size, self.size); + spinner.anchorPoint = CGPointMake(0.5f, 0.5f); + spinner.transform = CATransform3DIdentity; + spinner.backgroundColor = self.color.CGColor; + spinner.rasterizationScale = UIScreen.mainScreen.scale; + spinner.shouldRasterize = YES; + [self.layer addSublayer:spinner]; + + CAKeyframeAnimation* spinnerAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; + spinnerAnimation.removedOnCompletion = NO; + spinnerAnimation.repeatCount = HUGE_VALF; + spinnerAnimation.duration = 1.0f; + spinnerAnimation.beginTime = beginTime; + spinnerAnimation.keyTimes = @[ @(0.0f), @(0.25f), @(0.5f), @(0.75f), @(1.0f) ]; + spinnerAnimation.timingFunctions = @[ + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear], + [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear] + ]; + spinnerAnimation.values = @[ + [NSValue valueWithCATransform3D:CATransform3DMakeRotation(0.0f, 0.0f, 0.0f, 1.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_2, 0.0f, 0.0f, 1.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI, 0.0f, 0.0f, 1.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeRotation(3.0f * M_PI_2, 0.0f, 0.0f, 1.0f)], + [NSValue valueWithCATransform3D:CATransform3DMakeRotation(2.0f * M_PI, 0.0f, 0.0f, 1.0f)] + ]; + [spinner addAnimation:spinnerAnimation forKey:@"spinner-animation"]; + + CAShapeLayer* circleMask = [CAShapeLayer layer]; + circleMask.frame = spinner.bounds; + circleMask.fillColor = UIColor.blackColor.CGColor; + circleMask.anchorPoint = CGPointMake(0.5f, 0.5f); + + CGMutablePathRef path = CGPathCreateMutable(); + CGPathAddEllipseInRect(path, nil, spinner.frame); + + CGFloat circleSize = self.size * 0.25f; + CGPathAddEllipseInRect(path, nil, CGRectMake(CGRectGetMidX(spinner.frame) - circleSize * 0.5f, 3.0f, circleSize, circleSize)); + CGPathCloseSubpath(path); + circleMask.path = path; + circleMask.fillRule = kCAFillRuleEvenOdd; + CGPathRelease(path); + + spinner.mask = circleMask; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyStyle.h b/Sources/MobilyCore/MobilyStyle.h new file mode 100644 index 0000000..f9327bf --- /dev/null +++ b/Sources/MobilyCore/MobilyStyle.h @@ -0,0 +1,72 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef void(^MobilyStyleBlock)(id target); + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyStyle : NSObject< MobilyObject > + +@property(nonatomic, readonly, strong) NSString* name; +@property(nonatomic, readonly, strong) MobilyStyle* parent; + ++ (instancetype)styleWithName:(NSString*)name; ++ (instancetype)styleWithName:(NSString*)name block:(MobilyStyleBlock)block; ++ (instancetype)styleWithName:(NSString*)name parent:(MobilyStyle*)parent block:(MobilyStyleBlock)block; + +- (instancetype)initWithName:(NSString*)name block:(MobilyStyleBlock)block; +- (instancetype)initWithName:(NSString*)name parent:(MobilyStyle*)parent block:(MobilyStyleBlock)block; + +- (void)setup NS_REQUIRES_SUPER; + ++ (void)unregisterStyleWithName:(NSString*)name; + +@end + +/*--------------------------------------------------*/ + +@interface UIResponder (MobilyStyle) + +@property(nonatomic, readwrite, strong) IBInspectable MobilyStyle* moStyle; +@property(nonatomic, readwrite, strong) IBInspectable NSString* moStyleName; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyStyle.m b/Sources/MobilyCore/MobilyStyle.m new file mode 100644 index 0000000..f5bb1ae --- /dev/null +++ b/Sources/MobilyCore/MobilyStyle.m @@ -0,0 +1,162 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyStyle () + +@property(nonatomic, readonly, copy) MobilyStyleBlock block; + ++ (NSMutableDictionary*)_registeredStyles; + +- (void)_applyWithTarget:(id)target; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyStyle + +#pragma mark Synthesize + +@synthesize name = _name; +@synthesize parent = _parent; +@synthesize block = _block; + +#pragma mark Init / Free + ++ (instancetype)styleWithName:(NSString*)name { + return [self.class _registeredStyles][name]; +} + ++ (instancetype)styleWithName:(NSString*)name block:(MobilyStyleBlock)block { + return [[self alloc] initWithName:name block:block]; +} + ++ (instancetype)styleWithName:(NSString*)name parent:(MobilyStyle*)parent block:(MobilyStyleBlock)block { + return [[self alloc] initWithName:name parent:parent block:block]; +} + +- (instancetype)initWithName:(NSString*)name block:(MobilyStyleBlock)block { + return [self initWithName:name parent:nil block:block]; +} + +- (instancetype)initWithName:(NSString*)name parent:(MobilyStyle*)parent block:(MobilyStyleBlock)block { + self = [super init]; + if(self != nil) { + _name = name; + _parent = parent; + _block = block; + [self setup]; + } + return self; +} + +- (void)setup { + if(_name.length > 0) { + [self.class _registeredStyles][_name] = self; + } +} + +#pragma mark Public + ++ (void)unregisterStyleWithName:(NSString*)name { + [[self.class _registeredStyles] removeObjectForKey:name]; +} + +#pragma mark Private + ++ (NSMutableDictionary*)_registeredStyles { + static NSMutableDictionary* styles = nil; + if(styles == nil) { + styles = [NSMutableDictionary dictionary]; + } + return styles; +} + +- (void)_applyWithTarget:(id)target { + if(_parent != nil) { + [_parent _applyWithTarget:target]; + } + if(_block != nil) { + _block(target); + } +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UIResponder (MobilyStyle) + +- (void)setMoStyle:(MobilyStyle*)moStyle { + MobilyStyle* currentStyle = objc_getAssociatedObject(self, @selector(moStyle)); + if(currentStyle != moStyle) { + objc_setAssociatedObject(self, @selector(moStyle), moStyle, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + if(moStyle != nil) { + [moStyle _applyWithTarget:self]; + } + } +} + +- (MobilyStyle*)moStyle { + return objc_getAssociatedObject(self, @selector(moStyle)); +} + +- (void)setMoStyleName:(NSString*)moStyleName { + self.moStyle = [MobilyStyle styleWithName:moStyleName]; +} + +- (NSString*)moStyleName { + return self.moStyle.name; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyControllerTabBar.h b/Sources/MobilyCore/MobilyTabBarController.h similarity index 89% rename from Classes/UI/Core/MobilyControllerTabBar.h rename to Sources/MobilyCore/MobilyTabBarController.h index bf07e67..4fab157 100644 --- a/Classes/UI/Core/MobilyControllerTabBar.h +++ b/Sources/MobilyCore/MobilyTabBarController.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,12 +33,12 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyBuilder.h" -#import "MobilyTransitionController.h" +#import +#import /*--------------------------------------------------*/ -@interface MobilyControllerTabBar : UITabBarController< MobilyBuilderObject > +@interface MobilyTabBarController : UITabBarController< MobilyBuilderObject > @property(nonatomic, readonly, assign, getter=isAppeared) BOOL appeared; @property(nonatomic, readwrite, assign, getter=isNavigationBarHidden) BOOL navigationBarHidden; @@ -52,7 +52,11 @@ @property(nonatomic, readwrite, strong) id< MobilyEvent > eventWillDisappear; @property(nonatomic, readwrite, strong) id< MobilyEvent > eventDidDisappear; -- (void)setupController; +- (void)setup NS_REQUIRES_SUPER; + +- (void)setNeedUpdate; +- (void)update NS_REQUIRES_SUPER; +- (void)clear NS_REQUIRES_SUPER; @end diff --git a/Sources/MobilyCore/MobilyTabBarController.m b/Sources/MobilyCore/MobilyTabBarController.m new file mode 100644 index 0000000..039bd4e --- /dev/null +++ b/Sources/MobilyCore/MobilyTabBarController.m @@ -0,0 +1,557 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import +#import +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyTabBarController () < UIViewControllerTransitioningDelegate, UITabBarControllerDelegate, MobilySlideControllerDelegate > + +@property(nonatomic, readwrite, assign, getter=isAppeared) BOOL appeared; +@property(nonatomic, readwrite, assign, getter=isNeedUpdate) BOOL needUpdate; +@property(nonatomic, readwrite, assign) BOOL updating; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyTabBarController + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; + +#pragma mark NSKeyValueCoding + +MOBILY_DEFINE_VALIDATE_BOOL(NavigationBarHidden) +MOBILY_DEFINE_VALIDATE_TRANSITION_CONTROLLER(TransitionModal); +MOBILY_DEFINE_VALIDATE_TRANSITION_CONTROLLER(TransitionNavigation); +MOBILY_DEFINE_VALIDATE_EVENT(EventDidLoad) +MOBILY_DEFINE_VALIDATE_EVENT(EventDidUnload) +MOBILY_DEFINE_VALIDATE_EVENT(EventWillAppear) +MOBILY_DEFINE_VALIDATE_EVENT(EventDidAppear) +MOBILY_DEFINE_VALIDATE_EVENT(EventWillDisappear) +MOBILY_DEFINE_VALIDATE_EVENT(EventDidDisappear) + +#pragma mark Init / Free + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithNibName:(NSString*)nib bundle:(NSBundle*)bundle { + self = [super initWithNibName:nib bundle:bundle]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + self.delegate = self; + self.needUpdate = YES; +} + +- (void)dealloc { + [NSNotificationCenter.defaultCenter removeObserver:self]; +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return self.viewControllers; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIViewController.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIViewController.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { + if(UIDevice.moSystemVersion >= 7.0f) { + if(self.viewControllers.count < 1) { + self.viewControllers = [_objectChilds moArrayByObjectClass:UIViewController.class]; + } + [_eventDidLoad fireSender:self object:nil]; + } +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark Property + +- (void)setView:(UIView*)view { + super.view = view; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if((UIDevice.moSystemVersion >= 6.0f) && (view == nil)) { + [self viewDidUnload]; + } +#pragma clang diagnostic pop +} + +#pragma mark Public + +- (void)setNeedUpdate { + if(_updating == NO) { + self.updating = YES; + [self clear]; + if(self.isAppeared == YES) { + [self update]; + } else { + self.needUpdate = YES; + } + [self.relatedObjects moEach:^(id object) { + if([object respondsToSelector:@selector(setNeedUpdate)] == YES) { + [object setNeedUpdate]; + } + }]; + self.updating = NO; + } +} + +- (void)update { +} + +- (void)clear { +} + +#pragma mark UIViewController + +- (BOOL)shouldAutorotate { + return self.selectedViewController.shouldAutorotate; +} + +- (NSUInteger)supportedInterfaceOrientations { + return self.selectedViewController.supportedInterfaceOrientations; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation { + return [self.selectedViewController shouldAutorotateToInterfaceOrientation:orientation]; +} + +- (BOOL)prefersStatusBarHidden { + return self.selectedViewController.prefersStatusBarHidden; +} + +- (UIStatusBarStyle)preferredStatusBarStyle { + return self.selectedViewController.preferredStatusBarStyle; +} + +- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation { + return self.selectedViewController.preferredStatusBarUpdateAnimation; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + if(UIDevice.moSystemVersion < 7.0f) { + if(self.viewControllers.count < 1) { + self.viewControllers = [_objectChilds moArrayByObjectClass:UIViewController.class]; + } + [_eventDidLoad fireSender:self object:nil]; + } +} + +- (void)viewDidUnload { + [_eventDidUnload fireSender:self object:nil]; + [self setNeedUpdate]; + + [super viewDidUnload]; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + [self.view layoutIfNeeded]; + + if(_navigationBarHidden == YES) { + [self.navigationController setNavigationBarHidden:YES animated:animated]; + } + if(_appeared == NO) { + [_eventWillAppear fireSender:self object:nil]; + self.appeared = YES; + if(self.isNeedUpdate == YES) { + self.needUpdate = NO; + [self clear]; + [self update]; + } + } +} + +- (void)viewDidAppear:(BOOL)animated { + [_eventDidAppear fireSender:self object:nil]; + + [super viewDidAppear:animated]; +} + +- (void)viewWillDisappear:(BOOL)animated { + if(_navigationBarHidden == YES) { + [self.navigationController setNavigationBarHidden:NO animated:animated]; + } + [_eventWillDisappear fireSender:self object:nil]; + + [super viewWillDisappear:animated]; +} + +- (void)viewDidDisappear:(BOOL)animated { + if(_appeared == YES) { + self.appeared = NO; + [_eventDidDisappear fireSender:self object:nil]; + } + [super viewDidDisappear:animated]; +} + +#pragma mark UIViewControllerTransitioningDelegate + +- (id< UIViewControllerAnimatedTransitioning >)animationControllerForPresentedController:(UIViewController* __unused)presented presentingController:(UIViewController* __unused)presenting sourceController:(UIViewController* __unused)source { + if(_transitionModal != nil) { + _transitionModal.operation = MobilyTransitionOperationPresent; + } + return _transitionModal; +} + +- (id< UIViewControllerAnimatedTransitioning >)animationControllerForDismissedController:(UIViewController* __unused)dismissed { + if(_transitionModal != nil) { + _transitionModal.operation = MobilyTransitionOperationDismiss; + } + return _transitionModal; +} + +- (id< UIViewControllerInteractiveTransitioning >)interactionControllerForPresentation:(id< UIViewControllerAnimatedTransitioning > __unused)animator { + if(_transitionModal != nil) { + _transitionModal.operation = MobilyTransitionOperationPresent; + } + return _transitionModal; +} + +- (id< UIViewControllerInteractiveTransitioning >)interactionControllerForDismissal:(id< UIViewControllerAnimatedTransitioning > __unused)animator { + if(_transitionModal != nil) { + _transitionModal.operation = MobilyTransitionOperationDismiss; + } + return _transitionModal; +} + +#pragma mark UITabBarControllerDelegate +/* +- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController*)viewController { + return YES; +} + +- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController*)viewController { +} + +- (void)tabBarController:(UITabBarController *)tabBarController willBeginCustomizingViewControllers:(NSArray*)viewControllers { +} + +- (void)tabBarController:(UITabBarController *)tabBarController willEndCustomizingViewControllers:(NSArray*)viewControllers changed:(BOOL)changed { +} + +- (void)tabBarController:(UITabBarController *)tabBarController didEndCustomizingViewControllers:(NSArray*)viewControllers changed:(BOOL)changed { +} +*/ +- (NSUInteger)tabBarControllerSupportedInterfaceOrientations:(UITabBarController* __unused)tabBarController { + return self.selectedViewController.supportedInterfaceOrientations; +} + +- (UIInterfaceOrientation)tabBarControllerPreferredInterfaceOrientationForPresentation:(UITabBarController* __unused)tabBarController { + return [self.selectedViewController preferredInterfaceOrientationForPresentation]; +} + +- (id< UIViewControllerInteractiveTransitioning >)tabBarController:(UITabBarController* __unused)tabBarController interactionControllerForAnimationController:(id< UIViewControllerAnimatedTransitioning > __unused)animationController { + return _transitionNavigation; +} + +- (id< UIViewControllerAnimatedTransitioning >)tabBarController:(UITabBarController* __unused)tabBarController animationControllerForTransitionFromViewController:(UIViewController*)fromViewController toViewController:(UIViewController*)toViewController { + if(_transitionNavigation != nil) { + NSArray* viewControllers = tabBarController.viewControllers; + if([viewControllers indexOfObject:fromViewController] > [viewControllers indexOfObject:toViewController]) { + _transitionModal.operation = MobilyTransitionOperationPush; + } else { + _transitionModal.operation = MobilyTransitionOperationPop; + } + return _transitionNavigation; + } + return nil; +} + +#pragma mark MobilySlideControllerDelegate + +- (BOOL)canShowLeftControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(canShowLeftControllerInSlideController:)] == YES) { + return [controller canShowLeftControllerInSlideController:slideController]; + } + return (self.viewControllers.count == 1); +} + +- (void)willShowLeftControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(willShowLeftControllerInSlideController:duration:)] == YES) { + [controller willShowLeftControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didShowLeftControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(didShowLeftControllerInSlideController:)] == YES) { + [controller didShowLeftControllerInSlideController:slideController]; + } +} + +- (void)willHideLeftControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(willHideLeftControllerInSlideController:duration:)] == YES) { + [controller willHideLeftControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didHideLeftControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(didHideLeftControllerInSlideController:)] == YES) { + [controller didHideLeftControllerInSlideController:slideController]; + } +} + +- (BOOL)canShowRightControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(canShowRightControllerInSlideController:)] == YES) { + return [controller canShowRightControllerInSlideController:slideController]; + } + return (self.viewControllers.count == 1); +} + +- (void)willShowRightControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(willShowRightControllerInSlideController:duration:)] == YES) { + [controller willShowRightControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didShowRightControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(didShowRightControllerInSlideController:)] == YES) { + [controller didShowRightControllerInSlideController:slideController]; + } +} + +- (void)willHideRightControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(willHideRightControllerInSlideController:duration:)] == YES) { + [controller willHideRightControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didHideRightControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(didHideRightControllerInSlideController:)] == YES) { + [controller didHideRightControllerInSlideController:slideController]; + } +} + +- (BOOL)canShowControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(canShowControllerInSlideController:)] == YES) { + return [controller canShowControllerInSlideController:slideController]; + } + return (self.viewControllers.count == 1); +} + +- (void)willShowControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(willShowControllerInSlideController:duration:)] == YES) { + [controller willShowControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didShowControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(didShowControllerInSlideController:)] == YES) { + [controller didShowControllerInSlideController:slideController]; + } +} + +- (void)willHideControllerInSlideController:(MobilySlideController*)slideController duration:(CGFloat)duration { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(willHideControllerInSlideController:duration:)] == YES) { + [controller willHideControllerInSlideController:slideController duration:duration]; + } +} + +- (void)didHideControllerInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(didHideControllerInSlideController:)] == YES) { + [controller didHideControllerInSlideController:slideController]; + } +} + +- (void)willBeganLeftSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(willBeganLeftSwipeInSlideController:)] == YES) { + [controller willBeganLeftSwipeInSlideController:slideController]; + } +} + +- (void)didBeganLeftSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(didBeganLeftSwipeInSlideController:)] == YES) { + [controller didBeganLeftSwipeInSlideController:slideController]; + } +} + +- (void)movingLeftSwipeInSlideController:(MobilySlideController*)slideController progress:(CGFloat)progress { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(movingLeftSwipeInSlideController:progress:)] == YES) { + [controller movingLeftSwipeInSlideController:slideController progress:progress]; + } +} + +- (void)willEndedLeftSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(willEndedLeftSwipeInSlideController:)] == YES) { + [controller willEndedLeftSwipeInSlideController:slideController]; + } +} + +- (void)didEndedLeftSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(didEndedLeftSwipeInSlideController:)] == YES) { + [controller didEndedLeftSwipeInSlideController:slideController]; + } +} + +- (void)willBeganRightSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(willBeganRightSwipeInSlideController:)] == YES) { + [controller willBeganRightSwipeInSlideController:slideController]; + } +} + +- (void)didBeganRightSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(didBeganRightSwipeInSlideController:)] == YES) { + [controller didBeganRightSwipeInSlideController:slideController]; + } +} + +- (void)movingRightSwipeInSlideController:(MobilySlideController*)slideController progress:(CGFloat)progress { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(movingRightSwipeInSlideController:progress:)] == YES) { + [controller movingRightSwipeInSlideController:slideController progress:progress]; + } +} + +- (void)willEndedRightSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(willEndedRightSwipeInSlideController:)] == YES) { + [controller willEndedRightSwipeInSlideController:slideController]; + } +} + +- (void)didEndedRightSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(didEndedRightSwipeInSlideController:)] == YES) { + [controller didEndedRightSwipeInSlideController:slideController]; + } +} + +- (void)willBeganSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(willBeganSwipeInSlideController:)] == YES) { + [controller willBeganSwipeInSlideController:slideController]; + } +} + +- (void)didBeganSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(didBeganSwipeInSlideController:)] == YES) { + [controller didBeganSwipeInSlideController:slideController]; + } +} + +- (void)movingSwipeInSlideController:(MobilySlideController*)slideController progress:(CGFloat)progress { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(movingSwipeInSlideController:progress:)] == YES) { + [controller movingSwipeInSlideController:slideController progress:progress]; + } +} + +- (void)willEndedSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(willEndedSwipeInSlideController:)] == YES) { + [controller willEndedSwipeInSlideController:slideController]; + } +} + +- (void)didEndedSwipeInSlideController:(MobilySlideController*)slideController { + UIViewController< MobilySlideControllerDelegate >* controller = (id)self.selectedViewController; + if([controller respondsToSelector:@selector(didEndedSwipeInSlideController:)] == YES) { + [controller didEndedSwipeInSlideController:slideController]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/ViewTable/MobilyViewTable.h b/Sources/MobilyCore/MobilyTableView.h similarity index 72% rename from Classes/UI/ViewTable/MobilyViewTable.h rename to Sources/MobilyCore/MobilyTableView.h index 3526287..bd3d2db 100644 --- a/Classes/UI/ViewTable/MobilyViewTable.h +++ b/Sources/MobilyCore/MobilyTableView.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,21 +33,21 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyBuilder.h" +#import /*--------------------------------------------------*/ -@class MobilyViewTableCellSwipe; +@class MobilyTableSwipeCell; /*--------------------------------------------------*/ -@interface MobilyViewTable : UITableView< MobilyBuilderObject > +@interface MobilyTableView : UITableView< MobilyBuilderObject > -@property(nonatomic, readwrite, weak) MobilyViewTableCellSwipe* currentSwipeCell; +@property(nonatomic, readwrite, weak) MobilyTableSwipeCell* currentSwipeCell; -- (void)setupView; +- (void)setup NS_REQUIRES_SUPER; -- (void)setCurrentSwipeCell:(MobilyViewTableCellSwipe*)currentSwipeCell animated:(BOOL)animated; +- (void)setCurrentSwipeCell:(MobilyTableSwipeCell*)currentSwipeCell animated:(BOOL)animated; - (void)registerCellClass:(Class)cellClass; - (void)registerHeaderFooterClass:(Class)headerFooterClass; @@ -60,13 +60,13 @@ /*--------------------------------------------------*/ -@interface MobilyViewTableCell : UITableViewCell +@interface MobilyTableCell : UITableViewCell< MobilyObject > -@property(nonatomic, readwrite, weak) MobilyViewTable* tableView; +@property(nonatomic, readwrite, weak) MobilyTableView* tableView; @property(nonatomic, readwrite, strong) IBOutlet UIView* rootView; @property(nonatomic, readwrite, weak) id model; -- (void)setupView; +- (void)setup NS_REQUIRES_SUPER; - (void)didLoadFromNib; @@ -76,26 +76,26 @@ /*--------------------------------------------------*/ -typedef NS_ENUM(NSUInteger, MobilyViewTableCellSwipeStyle) { - MobilyViewTableCellSwipeStyleStands, - MobilyViewTableCellSwipeStyleLeaves, - MobilyViewTableCellSwipeStylePushes +typedef NS_ENUM(NSUInteger, MobilyTableSwipeCellStyle) { + MobilyTableSwipeCellStyleStands, + MobilyTableSwipeCellStyleLeaves, + MobilyTableSwipeCellStylePushes }; /*--------------------------------------------------*/ -@interface MobilyViewTableCellSwipe : MobilyViewTableCell +@interface MobilyTableSwipeCell : MobilyTableCell -@property(nonatomic, readwrite, assign) MobilyViewTableCellSwipeStyle swipeStyle; -@property(nonatomic, readwrite, assign) CGFloat swipeThreshold; -@property(nonatomic, readwrite, assign) CGFloat swipeVelocity; -@property(nonatomic, readwrite, assign) CGFloat swipeSpeed; -@property(nonatomic, readwrite, assign, getter=isShowedLeftSwipeView) BOOL showedLeftSwipeView; -@property(nonatomic, readwrite, assign, getter=isShowedRightSwipeView) BOOL showedRightSwipeView; +@property(nonatomic, readwrite, assign) IBInspectable MobilyTableSwipeCellStyle swipeStyle; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat swipeThreshold; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat swipeVelocity; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat swipeSpeed; +@property(nonatomic, readwrite, assign, getter=isShowedLeftSwipeView) IBInspectable BOOL showedLeftSwipeView; +@property(nonatomic, readwrite, assign, getter=isShowedRightSwipeView) IBInspectable BOOL showedRightSwipeView; @property(nonatomic, readwrite, strong) IBOutlet UIView* leftSwipeView; -@property(nonatomic, readwrite, assign) CGFloat leftSwipeViewWidth; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat leftSwipeViewWidth; @property(nonatomic, readwrite, strong) IBOutlet UIView* rightSwipeView; -@property(nonatomic, readwrite, assign) CGFloat rightSwipeViewWidth; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat rightSwipeViewWidth; @property(nonatomic, readonly, getter=isSwipeDragging) BOOL swipeDragging; @property(nonatomic, readonly, getter=isSwipeDecelerating) BOOL swipeDecelerating; diff --git a/Classes/UI/ViewTable/MobilyViewTable.m b/Sources/MobilyCore/MobilyTableView.m similarity index 54% rename from Classes/UI/ViewTable/MobilyViewTable.m rename to Sources/MobilyCore/MobilyTableView.m index 907b13f..7bef191 100644 --- a/Classes/UI/ViewTable/MobilyViewTable.m +++ b/Sources/MobilyCore/MobilyTableView.m @@ -1,10 +1,45 @@ /*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ -#import "MobilyViewTable.h" +#import /*--------------------------------------------------*/ -@interface MobilyViewTable () +@interface MobilyTableView () @property(nonatomic, readwrite, strong) NSMutableDictionary* registeredCellNibs; @property(nonatomic, readwrite, strong) NSMutableDictionary* registeredHeaderFooterNibs; @@ -15,7 +50,7 @@ @interface MobilyViewTable () #pragma mark - /*--------------------------------------------------*/ -@interface MobilyViewTableCell () +@interface MobilyTableCell () @property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintCenterXRootView; @property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintCenterYRootView; @@ -37,20 +72,20 @@ - (CGFloat)rootConstantHeight; #pragma mark - /*--------------------------------------------------*/ -typedef NS_ENUM(NSUInteger, MobilyViewTableCellSwipeDirection) { - MobilyViewTableCellSwipeDirectionUnknown, - MobilyViewTableCellSwipeDirectionLeft, - MobilyViewTableCellSwipeDirectionRight +typedef NS_ENUM(NSUInteger, MobilyDataCellSwipeDirection) { + MobilyDataCellSwipeDirectionUnknown, + MobilyDataCellSwipeDirectionLeft, + MobilyDataCellSwipeDirectionRight }; /*--------------------------------------------------*/ -@interface MobilyViewTableCellSwipe () < UIGestureRecognizerDelegate > +@interface MobilyTableSwipeCell () < UIGestureRecognizerDelegate > @property(nonatomic, readwrite, getter=isSwipeDragging) BOOL swipeDragging; @property(nonatomic, readwrite, getter=isSwipeDecelerating) BOOL swipeDecelerating; -@property(nonatomic, readwrite, strong) UIPanGestureRecognizer* panGestupe; +@property(nonatomic, readwrite, strong) UIPanGestureRecognizer* panGesture; @property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintOffsetLeftSwipeView; @property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintCenterYLeftSwipeView; @property(nonatomic, readwrite, strong) NSLayoutConstraint* constraintWidthLeftSwipeView; @@ -65,14 +100,14 @@ @interface MobilyViewTableCellSwipe () < UIGestureRecognizerDelegate > @property(nonatomic, readwrite, assign) CGFloat swipeProgress; @property(nonatomic, readwrite, assign) CGFloat swipeLeftWidth; @property(nonatomic, readwrite, assign) CGFloat swipeRightWidth; -@property(nonatomic, readwrite, assign) MobilyViewTableCellSwipeDirection swipeDirection; +@property(nonatomic, readwrite, assign) MobilyDataCellSwipeDirection swipeDirection; - (CGFloat)leftConstant; - (CGFloat)rightConstant; - (void)setSwipeProgress:(CGFloat)swipeProgress speed:(CGFloat)speed endedSwipe:(BOOL)endedSwipe; -- (void)handlerPanGestupe; +- (void)handlerPanGesture; @end @@ -80,7 +115,9 @@ - (void)handlerPanGestupe; #pragma mark - /*--------------------------------------------------*/ -@implementation MobilyViewTable +@implementation MobilyTableView + +#pragma mark Synthesize @synthesize objectName = _objectName; @synthesize objectParent = _objectParent; @@ -88,50 +125,59 @@ @implementation MobilyViewTable #pragma mark NSKeyValueCoding -#pragma mark Standart +#pragma mark Init / Free -- (id)initWithCoder:(NSCoder*)coder { +- (instancetype)initWithCoder:(NSCoder*)coder { self = [super initWithCoder:coder]; if(self != nil) { - [self setupView]; + [self setup]; } return self; } -- (id)initWithFrame:(CGRect)frame { +- (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if(self != nil) { - [self setupView]; + [self setup]; } return self; } -- (void)dealloc { - [self unregisterAdjustmentResponder]; +- (void)setup { + self.registeredCellNibs = NSMutableDictionary.dictionary; + self.registeredHeaderFooterNibs = NSMutableDictionary.dictionary; - [self setObjectName:nil]; - [self setObjectParent:nil]; - [self setObjectChilds:nil]; + [self moRegisterAdjustmentResponder]; +} + +- (void)dealloc { + [self moUnregisterAdjustmentResponder]; - [self setRegisteredCellNibs:nil]; - [self setRegisteredHeaderFooterNibs:nil]; + self.objectName = nil; + self.objectParent = nil; + self.objectChilds = nil; - MOBILY_SAFE_DEALLOC; + self.registeredCellNibs = nil; + self.registeredHeaderFooterNibs = nil; } #pragma mark MobilyBuilderObject +- (NSArray*)relatedObjects { + return self.subviews; +} + - (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIView class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andAddingObject:objectChild]]; + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; [self addSubview:(UIView*)objectChild]; } } - (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIView class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andRemovingObject:objectChild]]; - [self removeSubview:(UIView*)objectChild]; + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + [self moRemoveSubview:(UIView*)objectChild]; } } @@ -151,52 +197,45 @@ - (void)didLoadObjectChilds { #pragma mark Property -- (void)setCurrentSwipeCell:(MobilyViewTableCellSwipe*)currentSwipeCell { +- (void)setCurrentSwipeCell:(MobilyTableSwipeCell*)currentSwipeCell { [self setCurrentSwipeCell:currentSwipeCell animated:NO]; } #pragma mark Public -- (void)setupView { - [self setRegisteredCellNibs:[NSMutableDictionary dictionary]]; - [self setRegisteredHeaderFooterNibs:[NSMutableDictionary dictionary]]; - - [self registerAdjustmentResponder]; -} - -- (void)setCurrentSwipeCell:(MobilyViewTableCellSwipe*)currentSwipeCell animated:(BOOL)animated { +- (void)setCurrentSwipeCell:(MobilyTableSwipeCell*)currentSwipeCell animated:(BOOL)animated { if(_currentSwipeCell != currentSwipeCell) { if(_currentSwipeCell != nil) { - [_currentSwipeCell setHiddenAnySwipeViewAnimated:animated]; + _currentSwipeCell.hiddenAnySwipeViewAnimated = animated; } - MOBILY_SAFE_SETTER(_currentSwipeCell, currentSwipeCell); + _currentSwipeCell = currentSwipeCell; } } - (void)registerCellClass:(Class)cellClass { - UINib* nib = [UINib nibWithClass:cellClass bundle:nil]; + UINib* nib = [UINib moNibWithClass:cellClass bundle:nil]; if(nib != nil) { - [_registeredCellNibs setObject:nib forKey:NSStringFromClass(cellClass)]; + _registeredCellNibs[NSStringFromClass(cellClass)] = nib; [self registerClass:cellClass forCellReuseIdentifier:NSStringFromClass(cellClass)]; } } - (void)registerHeaderFooterClass:(Class)headerFooterClass { - UINib* nib = [UINib nibWithClass:headerFooterClass bundle:nil]; + UINib* nib = [UINib moNibWithClass:headerFooterClass bundle:nil]; if(nib != nil) { - [_registeredHeaderFooterNibs setObject:nib forKey:NSStringFromClass(headerFooterClass)]; + _registeredHeaderFooterNibs[NSStringFromClass(headerFooterClass)] = nib; [self registerClass:headerFooterClass forHeaderFooterViewReuseIdentifier:NSStringFromClass(headerFooterClass)]; } } - (id)dequeueReusableCellWithClass:(Class)cellClass { - id cell = [self dequeueReusableCellWithIdentifier:NSStringFromClass(cellClass)]; - [cell setTableView:self]; + MobilyTableCell* cell = [self dequeueReusableCellWithIdentifier:NSStringFromClass(cellClass)]; + cell.tableView = self; if([cell rootView] == nil) { - UINib* nib = [_registeredCellNibs objectForKey:NSStringFromClass(cellClass)]; + UINib* nib = _registeredCellNibs[NSStringFromClass(cellClass)]; if(nib != nil) { [nib instantiateWithOwner:cell options:nil]; - if([cell isKindOfClass:[MobilyViewTableCell class]] == YES) { + if([cell isKindOfClass:MobilyTableCell.class] == YES) { [cell didLoadFromNib]; } } @@ -205,13 +244,13 @@ - (id)dequeueReusableCellWithClass:(Class)cellClass { } - (id)dequeueReusableCellWithClass:(Class)cellClass forIndexPath:(NSIndexPath*)indexPath { - id cell = [self dequeueReusableCellWithIdentifier:NSStringFromClass(cellClass) forIndexPath:indexPath]; - [cell setTableView:self]; + MobilyTableCell* cell = [self dequeueReusableCellWithIdentifier:NSStringFromClass(cellClass) forIndexPath:indexPath]; + cell.tableView = self; if([cell rootView] == nil) { - UINib* nib = [_registeredCellNibs objectForKey:NSStringFromClass(cellClass)]; + UINib* nib = _registeredCellNibs[NSStringFromClass(cellClass)]; if(nib != nil) { [nib instantiateWithOwner:cell options:nil]; - if([cell isKindOfClass:[MobilyViewTableCell class]] == YES) { + if([cell isKindOfClass:MobilyTableCell.class] == YES) { [cell didLoadFromNib]; } } @@ -220,13 +259,13 @@ - (id)dequeueReusableCellWithClass:(Class)cellClass forIndexPath:(NSIndexPath*)i } - (id)dequeueReusableHeaderFooterViewWithClass:(Class)headerFooterClass { - id headerFooter = [self dequeueReusableHeaderFooterViewWithIdentifier:NSStringFromClass(headerFooterClass)]; - [headerFooter setTableView:self]; + MobilyTableCell* headerFooter = [self dequeueReusableHeaderFooterViewWithIdentifier:NSStringFromClass(headerFooterClass)]; + headerFooter.tableView = self; if([headerFooter rootView] == nil) { - UINib* nib = [_registeredHeaderFooterNibs objectForKey:NSStringFromClass(headerFooterClass)]; + UINib* nib = _registeredHeaderFooterNibs[NSStringFromClass(headerFooterClass)]; if(nib != nil) { [nib instantiateWithOwner:headerFooter options:nil]; - if([headerFooter isKindOfClass:[MobilyViewTableCell class]] == YES) { + if([headerFooter isKindOfClass:MobilyTableCell.class] == YES) { [headerFooter didLoadFromNib]; } } @@ -240,22 +279,22 @@ - (id)dequeueReusableHeaderFooterViewWithClass:(Class)headerFooterClass { #pragma mark - /*--------------------------------------------------*/ -@implementation MobilyViewTableCell +@implementation MobilyTableCell -#pragma mark Standart +#pragma mark Init / Free -- (id)initWithCoder:(NSCoder*)coder { +- (instancetype)initWithCoder:(NSCoder*)coder { self = [super initWithCoder:coder]; if(self != nil) { - [self setupView]; + [self setup]; } return self; } -- (id)initWithFrame:(CGRect)frame { +- (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if(self != nil) { - [self setupView]; + [self setup]; } return self; } @@ -263,27 +302,30 @@ - (id)initWithFrame:(CGRect)frame { - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString*)reuseIdentifier { self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if(self != nil) { - [self setupView]; + [self setup]; } return self; } -- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString*)reuseIdentifier { +- (instancetype)initWithFrame:(CGRect)frame reuseIdentifier:(NSString*)reuseIdentifier { self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier]; if(self != nil) { - [self setupView]; + [self setup]; } return self; } +- (void)setup { + self.selectionStyle = UITableViewCellSelectionStyleNone; + self.clipsToBounds = YES; +} + - (void)dealloc { - [self setConstraintCenterXRootView:nil]; - [self setConstraintCenterYRootView:nil]; - [self setConstraintWidthRootView:nil]; - [self setConstraintHeightRootView:nil]; - [self setRootView:nil]; - - MOBILY_SAFE_DEALLOC; + self.constraintCenterXRootView = nil; + self.constraintCenterYRootView = nil; + self.constraintWidthRootView = nil; + self.constraintHeightRootView = nil; + self.rootView = nil; } #pragma mark Property @@ -294,10 +336,10 @@ - (void)setRootView:(UIView*)rootView { [self cleanupConstraint]; [_rootView removeFromSuperview]; } - MOBILY_SAFE_SETTER(_rootView, rootView); + _rootView = rootView; if(_rootView != nil) { - [_rootView setTranslatesAutoresizingMaskIntoConstraints:NO]; - [[self contentView] setSubviews:[self orderedSubviews]]; + _rootView.translatesAutoresizingMaskIntoConstraints = NO; + [self.contentView moSetSubviews:[self orderedSubviews]]; [self setNeedsUpdateConstraints]; } } @@ -306,11 +348,11 @@ - (void)setRootView:(UIView*)rootView { - (void)setConstraintCenterXRootView:(NSLayoutConstraint*)constraintCenterXRootView { if(_constraintCenterXRootView != constraintCenterXRootView) { if(_constraintCenterXRootView != nil) { - [[self contentView] removeConstraint:_constraintCenterXRootView]; + [self.contentView removeConstraint:_constraintCenterXRootView]; } - MOBILY_SAFE_SETTER(_constraintCenterXRootView, constraintCenterXRootView); + _constraintCenterXRootView = constraintCenterXRootView; if(_constraintCenterXRootView != nil) { - [[self contentView] addConstraint:_constraintCenterXRootView]; + [self.contentView addConstraint:_constraintCenterXRootView]; } } } @@ -318,11 +360,11 @@ - (void)setConstraintCenterXRootView:(NSLayoutConstraint*)constraintCenterXRootV - (void)setConstraintCenterYRootView:(NSLayoutConstraint*)constraintCenterYRootView { if(_constraintCenterYRootView != constraintCenterYRootView) { if(_constraintCenterYRootView != nil) { - [[self contentView] removeConstraint:_constraintCenterYRootView]; + [self.contentView removeConstraint:_constraintCenterYRootView]; } - MOBILY_SAFE_SETTER(_constraintCenterYRootView, constraintCenterYRootView); + _constraintCenterYRootView = constraintCenterYRootView; if(_constraintCenterYRootView != nil) { - [[self contentView] addConstraint:_constraintCenterYRootView]; + [self.contentView addConstraint:_constraintCenterYRootView]; } } } @@ -330,11 +372,11 @@ - (void)setConstraintCenterYRootView:(NSLayoutConstraint*)constraintCenterYRootV - (void)setConstraintWidthRootView:(NSLayoutConstraint*)constraintWidthRootView { if(_constraintWidthRootView != constraintWidthRootView) { if(_constraintWidthRootView != nil) { - [[self contentView] removeConstraint:_constraintWidthRootView]; + [self.contentView removeConstraint:_constraintWidthRootView]; } - MOBILY_SAFE_SETTER(_constraintWidthRootView, constraintWidthRootView); + _constraintWidthRootView = constraintWidthRootView; if(_constraintWidthRootView != nil) { - [[self contentView] addConstraint:_constraintWidthRootView]; + [self.contentView addConstraint:_constraintWidthRootView]; } } } @@ -342,27 +384,21 @@ - (void)setConstraintWidthRootView:(NSLayoutConstraint*)constraintWidthRootView - (void)setConstraintHeightRootView:(NSLayoutConstraint*)constraintHeightRootView { if(_constraintHeightRootView != constraintHeightRootView) { if(_constraintHeightRootView != nil) { - [[self contentView] removeConstraint:_constraintHeightRootView]; + [self.contentView removeConstraint:_constraintHeightRootView]; } - MOBILY_SAFE_SETTER(_constraintHeightRootView, constraintHeightRootView); + _constraintHeightRootView = constraintHeightRootView; if(_constraintHeightRootView != nil) { - [[self contentView] addConstraint:_constraintHeightRootView]; + [self.contentView addConstraint:_constraintHeightRootView]; } } } #pragma mark Public -- (void)setupView { - [self setSelectionStyle:UITableViewCellSelectionStyleNone]; - [self setTranslatesAutoresizingMaskIntoConstraints:NO]; - [self setClipsToBounds:YES]; -} - - (void)didLoadFromNib { } -+ (CGFloat)heightForModel:(id)model tableView:(UITableView*)tableView { ++ (CGFloat)heightForModel:(id __unused)model tableView:(UITableView* __unused)tableView { return 240.0f; } @@ -372,31 +408,31 @@ - (void)updateConstraints { [super updateConstraints]; if(_constraintCenterXRootView == nil) { - [self setConstraintCenterXRootView:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:[self contentView] attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:[self rootConstantX]]]; + self.constraintCenterXRootView = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:[self rootConstantX]]; } else { - [_constraintCenterXRootView setConstant:[self rootConstantX]]; + _constraintCenterXRootView.constant = [self rootConstantX]; } if(_constraintCenterYRootView == nil) { - [self setConstraintCenterYRootView:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:[self contentView] attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:[self rootConstantY]]]; + self.constraintCenterYRootView = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:[self rootConstantY]]; } else { - [_constraintCenterYRootView setConstant:[self rootConstantY]]; + _constraintCenterYRootView.constant = [self rootConstantY]; } if(_constraintWidthRootView == nil) { - [self setConstraintWidthRootView:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:[self contentView] attribute:NSLayoutAttributeWidth multiplier:1.0f constant:[self rootConstantWidth]]]; + self.constraintWidthRootView = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeWidth multiplier:1.0f constant:[self rootConstantWidth]]; } else { - [_constraintWidthRootView setConstant:[self rootConstantWidth]]; + _constraintWidthRootView.constant = [self rootConstantWidth]; } if(_constraintHeightRootView == nil) { - [self setConstraintHeightRootView:[NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:[self contentView] attribute:NSLayoutAttributeHeight multiplier:1.0f constant:[self rootConstantHeight]]]; + self.constraintHeightRootView = [NSLayoutConstraint constraintWithItem:_rootView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeHeight multiplier:1.0f constant:[self rootConstantHeight]]; } else { - [_constraintHeightRootView setConstant:[self rootConstantHeight]]; + _constraintHeightRootView.constant = [self rootConstantHeight]; } } #pragma mark Private - (NSArray*)orderedSubviews { - NSMutableArray* result = [NSMutableArray array]; + NSMutableArray* result = NSMutableArray.array; if(_rootView != nil) { [result addObject:_rootView]; } @@ -404,10 +440,10 @@ - (NSArray*)orderedSubviews { } - (void)cleanupConstraint { - [self setConstraintCenterXRootView:nil]; - [self setConstraintCenterYRootView:nil]; - [self setConstraintWidthRootView:nil]; - [self setConstraintHeightRootView:nil]; + self.constraintCenterXRootView = nil; + self.constraintCenterYRootView = nil; + self.constraintWidthRootView = nil; + self.constraintHeightRootView = nil; } - (CGFloat)rootConstantX { @@ -430,40 +466,51 @@ - (CGFloat)rootConstantHeight { /*--------------------------------------------------*/ -@implementation MobilyViewTableCellSwipe +@implementation MobilyTableSwipeCell -#pragma mark Standart +#pragma mark Init / Free -- (void)dealloc { - [self setPanGestupe:nil]; - [self setConstraintOffsetLeftSwipeView:nil]; - [self setLeftSwipeView:nil]; - [self setConstraintOffsetRightSwipeView:nil]; - [self setRightSwipeView:nil]; +- (void)setup { + [super setup]; + + self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlerPanGesture)]; + + self.swipeStyle = MobilyTableSwipeCellStyleLeaves; + self.swipeThreshold = 2.0f; + self.swipeSpeed = 1050.0f; + self.swipeVelocity = 570.0f; + self.leftSwipeViewWidth = -1.0f; + self.rightSwipeViewWidth = -1.0f; +} - MOBILY_SAFE_DEALLOC; +- (void)dealloc { + self.panGesture = nil; + self.constraintOffsetLeftSwipeView = nil; + self.leftSwipeView = nil; + self.constraintOffsetRightSwipeView = nil; + self.rightSwipeView = nil; } #pragma mark Property -- (void)setPanGestupe:(UIPanGestureRecognizer*)gestupePanSwipeRight { - if(_panGestupe != gestupePanSwipeRight) { - if(_panGestupe != nil) { - [self removeGestureRecognizer:_panGestupe]; +- (void)setPanGesture:(UIPanGestureRecognizer*)gesturePanSwipeRight { + if(_panGesture != gesturePanSwipeRight) { + if(_panGesture != nil) { + [self removeGestureRecognizer:_panGesture]; } - MOBILY_SAFE_SETTER(_panGestupe, gestupePanSwipeRight); - if(_panGestupe != nil) { - [_panGestupe setDelegate:self]; - [self addGestureRecognizer:_panGestupe]; + _panGesture = gesturePanSwipeRight; + if(_panGesture != nil) { + _panGesture.delegate = self; + [self addGestureRecognizer:_panGesture]; } } } -- (void)setSwipeStyle:(MobilyViewTableCellSwipeStyle)swipeStyle { +- (void)setSwipeStyle:(MobilyTableSwipeCellStyle)swipeStyle { if(_swipeStyle != swipeStyle) { [self cleanupConstraint]; _swipeStyle = swipeStyle; - [[self contentView] setSubviews:[self orderedSubviews]]; + [self.contentView moSetSubviews:[self orderedSubviews]]; [self setNeedsUpdateConstraints]; } } @@ -482,10 +529,10 @@ - (void)setLeftSwipeView:(UIView*)leftSwipeView { [self cleanupConstraint]; [_leftSwipeView removeFromSuperview]; } - MOBILY_SAFE_SETTER(_leftSwipeView, leftSwipeView); + _leftSwipeView = leftSwipeView; if(_leftSwipeView != nil) { - [_leftSwipeView setTranslatesAutoresizingMaskIntoConstraints:NO]; - [[self contentView] setSubviews:[self orderedSubviews]]; + _leftSwipeView.translatesAutoresizingMaskIntoConstraints = NO; + [self.contentView moSetSubviews:[self orderedSubviews]]; [self setNeedsUpdateConstraints]; } } @@ -503,11 +550,11 @@ - (void)setLeftSwipeViewWidth:(CGFloat)leftSwipeViewWidth { - (void)setConstraintOffsetLeftSwipeView:(NSLayoutConstraint*)constraintOffsetLeftSwipeView { if(_constraintOffsetLeftSwipeView != constraintOffsetLeftSwipeView) { if(_constraintOffsetLeftSwipeView != nil) { - [[self contentView] removeConstraint:_constraintOffsetLeftSwipeView]; + [self.contentView removeConstraint:_constraintOffsetLeftSwipeView]; } - MOBILY_SAFE_SETTER(_constraintOffsetLeftSwipeView, constraintOffsetLeftSwipeView); + _constraintOffsetLeftSwipeView = constraintOffsetLeftSwipeView; if(_constraintOffsetLeftSwipeView != nil) { - [[self contentView] addConstraint:_constraintOffsetLeftSwipeView]; + [self.contentView addConstraint:_constraintOffsetLeftSwipeView]; } } } @@ -515,11 +562,11 @@ - (void)setConstraintOffsetLeftSwipeView:(NSLayoutConstraint*)constraintOffsetLe - (void)setConstraintCenterYLeftSwipeView:(NSLayoutConstraint*)constraintCenterYLeftSwipeView { if(_constraintCenterYLeftSwipeView != constraintCenterYLeftSwipeView) { if(_constraintCenterYLeftSwipeView != nil) { - [[self contentView] removeConstraint:_constraintCenterYLeftSwipeView]; + [self.contentView removeConstraint:_constraintCenterYLeftSwipeView]; } - MOBILY_SAFE_SETTER(_constraintCenterYLeftSwipeView, constraintCenterYLeftSwipeView); + _constraintCenterYLeftSwipeView = constraintCenterYLeftSwipeView; if(_constraintCenterYLeftSwipeView != nil) { - [[self contentView] addConstraint:_constraintCenterYLeftSwipeView]; + [self.contentView addConstraint:_constraintCenterYLeftSwipeView]; } } } @@ -529,7 +576,7 @@ - (void)setConstraintWidthLeftSwipeView:(NSLayoutConstraint*)constraintWidthLeft if(_constraintWidthLeftSwipeView != nil) { [_leftSwipeView removeConstraint:_constraintWidthLeftSwipeView]; } - MOBILY_SAFE_SETTER(_constraintWidthLeftSwipeView, constraintWidthLeftSwipeView); + _constraintWidthLeftSwipeView = constraintWidthLeftSwipeView; if(_constraintWidthLeftSwipeView != nil) { [_leftSwipeView addConstraint:_constraintWidthLeftSwipeView]; } @@ -539,11 +586,11 @@ - (void)setConstraintWidthLeftSwipeView:(NSLayoutConstraint*)constraintWidthLeft - (void)setConstraintHeightLeftSwipeView:(NSLayoutConstraint*)constraintHeightLeftSwipeView { if(_constraintHeightLeftSwipeView != constraintHeightLeftSwipeView) { if(_constraintHeightLeftSwipeView != nil) { - [[self contentView] removeConstraint:_constraintHeightLeftSwipeView]; + [self.contentView removeConstraint:_constraintHeightLeftSwipeView]; } - MOBILY_SAFE_SETTER(_constraintHeightLeftSwipeView, constraintHeightLeftSwipeView); + _constraintHeightLeftSwipeView = constraintHeightLeftSwipeView; if(_constraintHeightLeftSwipeView != nil) { - [[self contentView] addConstraint:_constraintHeightLeftSwipeView]; + [self.contentView addConstraint:_constraintHeightLeftSwipeView]; } } } @@ -554,10 +601,10 @@ - (void)setRightSwipeView:(UIView*)rightSwipeView { [self cleanupConstraint]; [_rightSwipeView removeFromSuperview]; } - MOBILY_SAFE_SETTER(_rightSwipeView, rightSwipeView); + _rightSwipeView = rightSwipeView; if(_rightSwipeView != nil) { - [_rightSwipeView setTranslatesAutoresizingMaskIntoConstraints:NO]; - [[self contentView] setSubviews:[self orderedSubviews]]; + _rightSwipeView.translatesAutoresizingMaskIntoConstraints = NO; + [self.contentView moSetSubviews:[self orderedSubviews]]; [self setNeedsUpdateConstraints]; } } @@ -575,11 +622,11 @@ - (void)setRightSwipeViewWidth:(CGFloat)rightSwipeViewWidth { - (void)setConstraintOffsetRightSwipeView:(NSLayoutConstraint*)constraintOffsetRightSwipeView { if(_constraintOffsetRightSwipeView != constraintOffsetRightSwipeView) { if(_constraintOffsetRightSwipeView != nil) { - [[self contentView] removeConstraint:_constraintOffsetRightSwipeView]; + [self.contentView removeConstraint:_constraintOffsetRightSwipeView]; } - MOBILY_SAFE_SETTER(_constraintOffsetRightSwipeView, constraintOffsetRightSwipeView); + _constraintOffsetRightSwipeView = constraintOffsetRightSwipeView; if(_constraintOffsetRightSwipeView != nil) { - [[self contentView] addConstraint:_constraintOffsetRightSwipeView]; + [self.contentView addConstraint:_constraintOffsetRightSwipeView]; } } } @@ -587,11 +634,11 @@ - (void)setConstraintOffsetRightSwipeView:(NSLayoutConstraint*)constraintOffsetR - (void)setConstraintCenterYRightSwipeView:(NSLayoutConstraint*)constraintCenterYRightSwipeView { if(_constraintCenterYRightSwipeView != constraintCenterYRightSwipeView) { if(_constraintCenterYRightSwipeView != nil) { - [[self contentView] removeConstraint:_constraintCenterYRightSwipeView]; + [self.contentView removeConstraint:_constraintCenterYRightSwipeView]; } - MOBILY_SAFE_SETTER(_constraintCenterYRightSwipeView, constraintCenterYRightSwipeView); + _constraintCenterYRightSwipeView = constraintCenterYRightSwipeView; if(_constraintCenterYRightSwipeView != nil) { - [[self contentView] addConstraint:_constraintCenterYRightSwipeView]; + [self.contentView addConstraint:_constraintCenterYRightSwipeView]; } } } @@ -601,7 +648,7 @@ - (void)setConstraintWidthRightSwipeView:(NSLayoutConstraint*)constraintWidthRig if(_constraintWidthRightSwipeView != nil) { [_rightSwipeView removeConstraint:_constraintWidthRightSwipeView]; } - MOBILY_SAFE_SETTER(_constraintWidthRightSwipeView, constraintWidthRightSwipeView); + _constraintWidthRightSwipeView = constraintWidthRightSwipeView; if(_constraintWidthRightSwipeView != nil) { [_rightSwipeView addConstraint:_constraintWidthRightSwipeView]; } @@ -611,34 +658,21 @@ - (void)setConstraintWidthRightSwipeView:(NSLayoutConstraint*)constraintWidthRig - (void)setConstraintHeightRightSwipeView:(NSLayoutConstraint*)constraintHeightRightSwipeView { if(_constraintHeightRightSwipeView != constraintHeightRightSwipeView) { if(_constraintHeightRightSwipeView != nil) { - [[self contentView] removeConstraint:_constraintHeightRightSwipeView]; + [self.contentView removeConstraint:_constraintHeightRightSwipeView]; } - MOBILY_SAFE_SETTER(_constraintHeightRightSwipeView, constraintHeightRightSwipeView); + _constraintHeightRightSwipeView = constraintHeightRightSwipeView; if(_constraintHeightRightSwipeView != nil) { - [[self contentView] addConstraint:_constraintHeightRightSwipeView]; + [self.contentView addConstraint:_constraintHeightRightSwipeView]; } } } - (void)setSwipeProgress:(CGFloat)swipeProgress { - [self setSwipeProgress:swipeProgress speed:FLT_EPSILON endedSwipe:NO]; + [self setSwipeProgress:swipeProgress speed:MOBILY_EPSILON endedSwipe:NO]; } #pragma mark Public -- (void)setupView { - [super setupView]; - - [self setPanGestupe:[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlerPanGestupe)]]; - - [self setSwipeStyle:MobilyViewTableCellSwipeStyleLeaves]; - [self setSwipeThreshold:2.0f]; - [self setSwipeSpeed:420.0f]; - [self setSwipeVelocity:320.0f]; - [self setLeftSwipeViewWidth:-1.0f]; - [self setRightSwipeViewWidth:-1.0f]; -} - - (void)setShowedLeftSwipeView:(BOOL)showedLeftSwipeView animated:(BOOL)animated { if(_showedLeftSwipeView != showedLeftSwipeView) { _showedLeftSwipeView = showedLeftSwipeView; @@ -646,7 +680,7 @@ - (void)setShowedLeftSwipeView:(BOOL)showedLeftSwipeView animated:(BOOL)animated CGFloat needSwipeProgress = (showedLeftSwipeView == YES) ? -1.0f : 0.0f; [self setSwipeProgress:needSwipeProgress - speed:(animated == YES) ? [_leftSwipeView frameWidth] * ABS(needSwipeProgress - _swipeProgress) : FLT_EPSILON + speed:(animated == YES) ? _leftSwipeView.moFrameWidth * MOBILY_FABS(needSwipeProgress - _swipeProgress) : MOBILY_EPSILON endedSwipe:NO]; } } @@ -658,7 +692,7 @@ - (void)setShowedRightSwipeView:(BOOL)showedRightSwipeView animated:(BOOL)animat CGFloat needSwipeProgress = (_showedRightSwipeView == YES) ? 1.0f : 0.0f; [self setSwipeProgress:needSwipeProgress - speed:(animated == YES) ? [_rightSwipeView frameWidth] * ABS(needSwipeProgress - _swipeProgress) : FLT_EPSILON + speed:(animated == YES) ? _rightSwipeView.moFrameWidth * MOBILY_FABS(needSwipeProgress - _swipeProgress) : MOBILY_EPSILON endedSwipe:NO]; } } @@ -672,21 +706,21 @@ - (void)willBeganSwipe { } - (void)didBeganSwipe { - [self setSwipeDragging:YES]; + self.swipeDragging = YES; } -- (void)movingSwipe:(CGFloat)progress { +- (void)movingSwipe:(CGFloat __unused)progress { } - (void)willEndedSwipe { - [self setSwipeDragging:NO]; - [self setSwipeDecelerating:YES]; + self.swipeDragging = NO; + self.swipeDecelerating = YES; } - (void)didEndedSwipe { _showedLeftSwipeView = (_swipeProgress < 0.0f) ? YES : NO; _showedRightSwipeView = (_swipeProgress > 0.0f) ? YES : NO; - [self setSwipeDecelerating:NO]; + self.swipeDecelerating = NO; if((_showedLeftSwipeView == YES) || (_showedRightSwipeView == YES)) { [[self tableView] setCurrentSwipeCell:self animated:YES]; } else { @@ -703,7 +737,7 @@ - (void)prepareForReuse { [super prepareForReuse]; if((_showedLeftSwipeView == YES) || (_showedRightSwipeView == YES)) { [self willEndedSwipe]; - [self setSwipeProgress:0.0f speed:FLT_EPSILON endedSwipe:YES]; + [self setSwipeProgress:0.0f speed:MOBILY_EPSILON endedSwipe:YES]; } } @@ -713,45 +747,45 @@ - (void)updateConstraints { if(_leftSwipeView != nil) { if(_leftSwipeViewWidth >= 0.0f) { if(_constraintWidthLeftSwipeView == nil) { - [self setConstraintWidthLeftSwipeView:[NSLayoutConstraint constraintWithItem:_leftSwipeView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:_leftSwipeViewWidth]]; + self.constraintWidthLeftSwipeView = [NSLayoutConstraint constraintWithItem:_leftSwipeView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:_leftSwipeViewWidth]; } else { - [_constraintOffsetLeftSwipeView setConstant:_leftSwipeViewWidth]; + _constraintOffsetLeftSwipeView.constant = _leftSwipeViewWidth; } } else { - [self setConstraintWidthLeftSwipeView:nil]; + self.constraintWidthLeftSwipeView = nil; } if(_constraintOffsetLeftSwipeView == nil) { - [self setConstraintOffsetLeftSwipeView:[NSLayoutConstraint constraintWithItem:_leftSwipeView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:[self contentView] attribute:NSLayoutAttributeLeft multiplier:1.0f constant:[self leftConstant]]]; + self.constraintOffsetLeftSwipeView = [NSLayoutConstraint constraintWithItem:_leftSwipeView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeft multiplier:1.0f constant:[self leftConstant]]; } else { - [_constraintOffsetLeftSwipeView setConstant:[self leftConstant]]; + _constraintOffsetLeftSwipeView.constant = [self leftConstant]; } if(_constraintCenterYLeftSwipeView == nil) { - [self setConstraintCenterYLeftSwipeView:[NSLayoutConstraint constraintWithItem:_leftSwipeView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:[self contentView] attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]]; + self.constraintCenterYLeftSwipeView = [NSLayoutConstraint constraintWithItem:_leftSwipeView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]; } if(_constraintHeightLeftSwipeView == nil) { - [self setConstraintHeightLeftSwipeView:[NSLayoutConstraint constraintWithItem:_leftSwipeView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:[self contentView] attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]]; + self.constraintHeightLeftSwipeView = [NSLayoutConstraint constraintWithItem:_leftSwipeView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]; } } if(_rightSwipeView != nil) { if(_rightSwipeViewWidth >= 0.0f) { if(_constraintWidthRightSwipeView == nil) { - [self setConstraintWidthRightSwipeView:[NSLayoutConstraint constraintWithItem:_rightSwipeView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:_rightSwipeViewWidth]]; + self.constraintWidthRightSwipeView = [NSLayoutConstraint constraintWithItem:_rightSwipeView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:_rightSwipeViewWidth]; } else { - [_constraintOffsetRightSwipeView setConstant:_rightSwipeViewWidth]; + _constraintOffsetRightSwipeView.constant = _rightSwipeViewWidth; } } else { - [self setConstraintWidthRightSwipeView:nil]; + self.constraintWidthRightSwipeView = nil; } if(_constraintOffsetRightSwipeView == nil) { - [self setConstraintOffsetRightSwipeView:[NSLayoutConstraint constraintWithItem:_rightSwipeView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:[self contentView] attribute:NSLayoutAttributeRight multiplier:1.0f constant:[self rightConstant]]]; + self.constraintOffsetRightSwipeView = [NSLayoutConstraint constraintWithItem:_rightSwipeView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeRight multiplier:1.0f constant:[self rightConstant]]; } else { - [_constraintOffsetRightSwipeView setConstant:[self rightConstant]]; + _constraintOffsetRightSwipeView.constant = [self rightConstant]; } if(_constraintCenterYRightSwipeView == nil) { - [self setConstraintCenterYRightSwipeView:[NSLayoutConstraint constraintWithItem:_rightSwipeView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:[self contentView] attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]]; + [self setConstraintCenterYRightSwipeView:[NSLayoutConstraint constraintWithItem:_rightSwipeView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]]; } if(_constraintHeightRightSwipeView == nil) { - [self setConstraintHeightRightSwipeView:[NSLayoutConstraint constraintWithItem:_rightSwipeView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:[self contentView] attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]]; + [self setConstraintHeightRightSwipeView:[NSLayoutConstraint constraintWithItem:_rightSwipeView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeHeight multiplier:1.0f constant:0.0f]]; } } } @@ -759,9 +793,9 @@ - (void)updateConstraints { #pragma mark Private - (NSArray*)orderedSubviews { - NSMutableArray* result = [NSMutableArray array]; + NSMutableArray* result = NSMutableArray.array; switch(_swipeStyle) { - case MobilyViewTableCellSwipeStyleStands: { + case MobilyTableSwipeCellStyleStands: { if(_leftSwipeView != nil) { [result addObject:_leftSwipeView]; } @@ -773,8 +807,8 @@ - (NSArray*)orderedSubviews { } break; } - case MobilyViewTableCellSwipeStyleLeaves: - case MobilyViewTableCellSwipeStylePushes: { + case MobilyTableSwipeCellStyleLeaves: + case MobilyTableSwipeCellStylePushes: { if([self rootView] != nil) { [result addObject:[self rootView]]; } @@ -793,41 +827,41 @@ - (NSArray*)orderedSubviews { - (void)cleanupConstraint { [super cleanupConstraint]; - [self setConstraintOffsetLeftSwipeView:nil]; - [self setConstraintCenterYLeftSwipeView:nil]; - [self setConstraintWidthLeftSwipeView:nil]; - [self setConstraintHeightLeftSwipeView:nil]; + self.constraintOffsetLeftSwipeView = nil; + self.constraintCenterYLeftSwipeView = nil; + self.constraintWidthLeftSwipeView = nil; + self.constraintHeightLeftSwipeView = nil; - [self setConstraintOffsetRightSwipeView:nil]; - [self setConstraintCenterYRightSwipeView:nil]; - [self setConstraintWidthRightSwipeView:nil]; - [self setConstraintHeightRightSwipeView:nil]; + self.constraintOffsetRightSwipeView = nil; + self.constraintCenterYRightSwipeView = nil; + self.constraintWidthRightSwipeView = nil; + self.constraintHeightRightSwipeView = nil; } - (CGFloat)rootConstantX { switch(_swipeStyle) { - case MobilyViewTableCellSwipeStyleStands: - case MobilyViewTableCellSwipeStyleLeaves: { + case MobilyTableSwipeCellStyleStands: + case MobilyTableSwipeCellStyleLeaves: { if(_swipeProgress < 0.0f) { - return [_leftSwipeView frameWidth] * (-_swipeProgress); + return _leftSwipeView.moFrameWidth * (-_swipeProgress); } else if(_swipeProgress > 0.0f) { - return (-[_rightSwipeView frameWidth]) * _swipeProgress; + return (-_rightSwipeView.moFrameWidth) * _swipeProgress; } break; } - case MobilyViewTableCellSwipeStylePushes: + case MobilyTableSwipeCellStylePushes: break; } return 0.0f; } - (CGFloat)leftConstant { - CGFloat leftWidth = [_leftSwipeView frameWidth]; + CGFloat leftWidth = _leftSwipeView.moFrameWidth; switch(_swipeStyle) { - case MobilyViewTableCellSwipeStyleStands: + case MobilyTableSwipeCellStyleStands: return 0.0f; - case MobilyViewTableCellSwipeStyleLeaves: - case MobilyViewTableCellSwipeStylePushes: + case MobilyTableSwipeCellStyleLeaves: + case MobilyTableSwipeCellStylePushes: if(_swipeProgress < 0.0f) { return -leftWidth + (leftWidth * (-_swipeProgress)); } @@ -837,12 +871,12 @@ - (CGFloat)leftConstant { } - (CGFloat)rightConstant { - CGFloat rightWidth = [_rightSwipeView frameWidth]; + CGFloat rightWidth = _rightSwipeView.moFrameWidth; switch(_swipeStyle) { - case MobilyViewTableCellSwipeStyleStands: + case MobilyTableSwipeCellStyleStands: return 0.0f; - case MobilyViewTableCellSwipeStyleLeaves: - case MobilyViewTableCellSwipeStylePushes: + case MobilyTableSwipeCellStyleLeaves: + case MobilyTableSwipeCellStylePushes: if(_swipeProgress > 0.0f) { return rightWidth * (1.0f - _swipeProgress); } @@ -852,18 +886,18 @@ - (CGFloat)rightConstant { } - (void)setSwipeProgress:(CGFloat)swipeProgress speed:(CGFloat)speed endedSwipe:(BOOL)endedSwipe { - CGFloat minSwipeProgress = (_swipeDirection == MobilyViewTableCellSwipeDirectionLeft) ? -1.0f : 0.0f; - CGFloat maxSwipeProgress = (_swipeDirection == MobilyViewTableCellSwipeDirectionRight) ? 1.0f :0.0f; + CGFloat minSwipeProgress = (_swipeDirection == MobilyDataCellSwipeDirectionLeft) ? -1.0f : 0.0f; + CGFloat maxSwipeProgress = (_swipeDirection == MobilyDataCellSwipeDirectionRight) ? 1.0f :0.0f; CGFloat normalizedSwipeProgress = MIN(MAX(minSwipeProgress, swipeProgress), maxSwipeProgress); if(_swipeProgress != normalizedSwipeProgress) { _swipeProgress = normalizedSwipeProgress; [self setNeedsUpdateConstraints]; - [UIView animateWithDuration:ABS(speed) / _swipeSpeed + [UIView animateWithDuration:MOBILY_FABS(speed) / _swipeSpeed animations:^{ [self updateConstraintsIfNeeded]; [self layoutIfNeeded]; - } completion:^(BOOL finished) { + } completion:^(BOOL finished __unused) { if(endedSwipe == YES) { [self didEndedSwipe]; } @@ -875,57 +909,57 @@ - (void)setSwipeProgress:(CGFloat)swipeProgress speed:(CGFloat)speed endedSwipe: } } -- (void)handlerPanGestupe { +- (void)handlerPanGesture { if(_swipeDecelerating == NO) { - CGPoint translation = [_panGestupe translationInView:self]; - CGPoint velocity = [_panGestupe velocityInView:self]; - switch([_panGestupe state]) { + CGPoint translation = [_panGesture translationInView:self]; + CGPoint velocity = [_panGesture velocityInView:self]; + switch([_panGesture state]) { case UIGestureRecognizerStateBegan: { [self willBeganSwipe]; - [self setSwipeLastOffset:translation.x]; - [self setSwipeLastVelocity:velocity.x]; - [self setSwipeLeftWidth:-[_leftSwipeView frameWidth]]; - [self setSwipeRightWidth:[_rightSwipeView frameWidth]]; - [self setSwipeDirection:MobilyViewTableCellSwipeDirectionUnknown]; + self.swipeLastOffset = translation.x; + self.swipeLastVelocity = velocity.x; + self.swipeLeftWidth = -_leftSwipeView.moFrameWidth; + self.swipeRightWidth = _rightSwipeView.moFrameWidth; + self.swipeDirection = MobilyDataCellSwipeDirectionUnknown; break; } case UIGestureRecognizerStateChanged: { CGFloat delta = _swipeLastOffset - translation.x; - if(_swipeDirection == MobilyViewTableCellSwipeDirectionUnknown) { + if(_swipeDirection == MobilyDataCellSwipeDirectionUnknown) { if((_showedLeftSwipeView == YES) && (_leftSwipeView != nil) && (delta > _swipeThreshold)) { - [self setSwipeDirection:MobilyViewTableCellSwipeDirectionLeft]; + self.swipeDirection = MobilyDataCellSwipeDirectionLeft; [self didBeganSwipe]; } else if((_showedRightSwipeView == YES) && (_rightSwipeView != nil) && (delta < -_swipeThreshold)) { - [self setSwipeDirection:MobilyViewTableCellSwipeDirectionRight]; + self.swipeDirection = MobilyDataCellSwipeDirectionRight; [self didBeganSwipe]; } else if((_showedLeftSwipeView == NO) && (_leftSwipeView != nil) && (delta < -_swipeThreshold)) { - [self setSwipeDirection:MobilyViewTableCellSwipeDirectionLeft]; + self.swipeDirection = MobilyDataCellSwipeDirectionLeft; [self didBeganSwipe]; } else if((_showedRightSwipeView == NO) && (_rightSwipeView != nil) && (delta > _swipeThreshold)) { - [self setSwipeDirection:MobilyViewTableCellSwipeDirectionRight]; + self.swipeDirection = MobilyDataCellSwipeDirectionRight; [self didBeganSwipe]; } } - if(_swipeDirection != MobilyViewTableCellSwipeDirectionUnknown) { + if(_swipeDirection != MobilyDataCellSwipeDirectionUnknown) { switch(_swipeDirection) { - case MobilyViewTableCellSwipeDirectionUnknown: { + case MobilyDataCellSwipeDirectionUnknown: { break; } - case MobilyViewTableCellSwipeDirectionLeft: { + case MobilyDataCellSwipeDirectionLeft: { CGFloat localDelta = MIN(MAX(_swipeLeftWidth, delta), -_swipeLeftWidth); [self setSwipeProgress:_swipeProgress - (localDelta / _swipeLeftWidth) speed:localDelta endedSwipe:NO]; [self movingSwipe:_swipeProgress]; break; } - case MobilyViewTableCellSwipeDirectionRight: { + case MobilyDataCellSwipeDirectionRight: { CGFloat localDelta = MIN(MAX(-_swipeRightWidth, delta), _swipeRightWidth); [self setSwipeProgress:_swipeProgress + (localDelta / _swipeRightWidth) speed:localDelta endedSwipe:NO]; [self movingSwipe:_swipeProgress]; break; } } - [self setSwipeLastOffset:translation.x]; - [self setSwipeLastVelocity:velocity.x]; + self.swipeLastOffset = translation.x; + self.swipeLastVelocity = velocity.x; } break; } @@ -933,16 +967,16 @@ - (void)handlerPanGestupe { case UIGestureRecognizerStateCancelled: { [self willEndedSwipe]; CGFloat swipeProgress = roundf(_swipeProgress - (_swipeLastVelocity / _swipeVelocity)); - CGFloat minSwipeProgress = (_swipeDirection == MobilyViewTableCellSwipeDirectionLeft) ? -1.0f : 0.0f; - CGFloat maxSwipeProgress = (_swipeDirection == MobilyViewTableCellSwipeDirectionRight) ? 1.0f :0.0f; + CGFloat minSwipeProgress = (_swipeDirection == MobilyDataCellSwipeDirectionLeft) ? -1.0f : 0.0f; + CGFloat maxSwipeProgress = (_swipeDirection == MobilyDataCellSwipeDirectionRight) ? 1.0f : 0.0f; CGFloat needSwipeProgress = MIN(MAX(minSwipeProgress, swipeProgress), maxSwipeProgress); switch(_swipeDirection) { - case MobilyViewTableCellSwipeDirectionLeft: { - [self setSwipeProgress:needSwipeProgress speed:_swipeLeftWidth * ABS(needSwipeProgress - _swipeProgress) endedSwipe:YES]; + case MobilyDataCellSwipeDirectionLeft: { + [self setSwipeProgress:needSwipeProgress speed:_swipeLeftWidth * MOBILY_FABS(needSwipeProgress - _swipeProgress) endedSwipe:YES]; break; } - case MobilyViewTableCellSwipeDirectionRight: { - [self setSwipeProgress:needSwipeProgress speed:_swipeRightWidth * ABS(needSwipeProgress - _swipeProgress) endedSwipe:YES]; + case MobilyDataCellSwipeDirectionRight: { + [self setSwipeProgress:needSwipeProgress speed:_swipeRightWidth * MOBILY_FABS(needSwipeProgress - _swipeProgress) endedSwipe:YES]; break; } default: { @@ -962,19 +996,21 @@ - (void)handlerPanGestupe { #pragma mark UIGestureRecognizerDelegate - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer { - if((_swipeDragging == NO) && (_swipeDecelerating == NO)) { - CGPoint translation = [_panGestupe translationInView:self]; - if(fabs(translation.x) >= fabs(translation.y)) { - if((_showedLeftSwipeView == YES) && (_leftSwipeView != nil) && (translation.x < 0.0f)) { - return YES; - } else if((_showedRightSwipeView == YES) && (_rightSwipeView != nil) && (translation.x > 0.0f)) { - return YES; - } else if((_showedLeftSwipeView == NO) && (_leftSwipeView != nil) && (translation.x > 0.0f)) { - return YES; - } else if((_showedRightSwipeView == NO) && (_rightSwipeView != nil) && (translation.x < 0.0f)) { - return YES; + if(gestureRecognizer == _panGesture) { + if((_swipeDragging == NO) && (_swipeDecelerating == NO)) { + CGPoint translation = [_panGesture translationInView:self]; + if(MOBILY_FABS(translation.x) >= MOBILY_FABS(translation.y)) { + if((_showedLeftSwipeView == YES) && (_leftSwipeView != nil) && (translation.x < 0.0f)) { + return YES; + } else if((_showedRightSwipeView == YES) && (_rightSwipeView != nil) && (translation.x > 0.0f)) { + return YES; + } else if((_showedLeftSwipeView == NO) && (_leftSwipeView != nil) && (translation.x > 0.0f)) { + return YES; + } else if((_showedRightSwipeView == NO) && (_rightSwipeView != nil) && (translation.x < 0.0f)) { + return YES; + } + return NO; } - return NO; } } return NO; diff --git a/Classes/NS/Core/MobilyTaskManager.h b/Sources/MobilyCore/MobilyTaskManager.h similarity index 76% rename from Classes/NS/Core/MobilyTaskManager.h rename to Sources/MobilyCore/MobilyTaskManager.h index ec14a70..c4ef9d5 100644 --- a/Classes/NS/Core/MobilyTaskManager.h +++ b/Sources/MobilyCore/MobilyTaskManager.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,7 +33,7 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyNS.h" +#import /*--------------------------------------------------*/ @@ -53,10 +53,13 @@ typedef void (^MobilyTaskManagerEnumBlock)(id task, BOOL* stop); /*--------------------------------------------------*/ -@interface MobilyTaskManager : NSObject +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyTaskManager : NSObject < MobilyObject > @property(nonatomic, readwrite, assign) NSUInteger maxConcurrentTask; +- (void)setup NS_REQUIRES_SUPER; + - (void)addTask:(MobilyTask*)task; - (void)addTask:(MobilyTask*)task priority:(MobilyTaskPriority)priority; - (void)cancelTask:(MobilyTask*)task; @@ -78,18 +81,35 @@ typedef void (^MobilyTaskManagerEnumBlock)(id task, BOOL* stop); /*--------------------------------------------------*/ -@interface MobilyTask : NSObject +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyTask : NSObject < MobilyObject > -@property(nonatomic, readwrite, assign, getter=isNeedRework) BOOL needRework; +@property(nonatomic, readonly, assign, getter=isNeedRework) BOOL needRework; @property(nonatomic, readonly, assign, getter=isCanceled) BOOL cancel; -- (BOOL)willStart; -- (void)working; -- (void)didComplete; -- (void)didCancel; +- (void)setup NS_REQUIRES_SUPER; + +- (void)setNeedRework; + +- (BOOL)willStart NS_REQUIRES_SUPER; +- (void)working NS_REQUIRES_SUPER; +- (void)didComplete NS_REQUIRES_SUPER; +- (void)didCancel NS_REQUIRES_SUPER; - (void)cancel; @end /*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyTaskHttpQuery : MobilyTask < MobilyHttpQueryDelegate > { +@protected + MobilyHttpQuery* _httpQuery; +} + +@property(nonatomic, readwrite, strong) MobilyHttpQuery* httpQuery; + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/NS/Core/MobilyTaskManager.m b/Sources/MobilyCore/MobilyTaskManager.m similarity index 65% rename from Classes/NS/Core/MobilyTaskManager.m rename to Sources/MobilyCore/MobilyTaskManager.m index a556462..8b0dad0 100644 --- a/Classes/NS/Core/MobilyTaskManager.m +++ b/Sources/MobilyCore/MobilyTaskManager.m @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -32,16 +32,18 @@ /* OTHER DEALINGS IN THE SOFTWARE. */ /* */ /*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ -#import "MobilyTaskManager.h" +#import /*--------------------------------------------------*/ -@interface MobilyTaskManager () - -@property(nonatomic, readwrite, strong) NSOperationQueue* queueManager; -@property(nonatomic, readwrite, assign) UIBackgroundTaskIdentifier backgroundTaskId; -@property(nonatomic, readwrite, assign) NSUInteger updateCount; +@interface MobilyTaskManager () { + NSOperationQueue* _queueManager; + UIBackgroundTaskIdentifier _backgroundTaskId; + NSUInteger _updateCount; +} @end @@ -53,9 +55,12 @@ @interface MobilyTaskManager () /*--------------------------------------------------*/ -@interface MobilyTask () +@interface MobilyTask () { + __weak MobilyTaskManager* _taskManager; + __weak MobilyTaskOperation* _taskOperation; + BOOL _needRework; +} -@property(nonatomic, readwrite, weak) MobilyTaskManager* taskManager; @property(nonatomic, readwrite, weak) MobilyTaskOperation* taskOperation; @end @@ -64,12 +69,14 @@ @interface MobilyTask () #pragma mark - /*--------------------------------------------------*/ -@interface MobilyTaskOperation : NSOperation +@interface MobilyTaskOperation : NSOperation { + __weak MobilyTaskManager* _taskManager; + MobilyTask* _task; +} -@property(nonatomic, readwrite, weak) MobilyTaskManager* taskManager; -@property(nonatomic, readwrite, strong) MobilyTask* task; +@property(nonatomic, readonly, strong) MobilyTask* task; -- (id)initWithMTaskManager:(MobilyTaskManager*)taskManager task:(MobilyTask*)task; +- (instancetype)initWithTaskManager:(MobilyTaskManager*)taskManager task:(MobilyTask*)task; @end @@ -79,24 +86,26 @@ - (id)initWithMTaskManager:(MobilyTaskManager*)taskManager task:(MobilyTask*)tas @implementation MobilyTaskManager -- (id)init { +#pragma mark Init / Free + +- (instancetype)init { self = [super init]; if(self != nil) { - [self setQueueManager:[NSOperationQueue new]]; - [self setBackgroundTaskId:UIBackgroundTaskInvalid]; + _queueManager = [NSOperationQueue new]; + _backgroundTaskId = UIBackgroundTaskInvalid; + [self setup]; } return self; } -- (void)dealloc { - [self setQueueManager:nil]; - - MOBILY_SAFE_DEALLOC; +- (void)setup { } +#pragma mark Public + - (void)setMaxConcurrentTask:(NSUInteger)maxConcurrentTask { [self updating]; - [_queueManager setMaxConcurrentOperationCount:maxConcurrentTask]; + _queueManager.maxConcurrentOperationCount = maxConcurrentTask; [self updated]; } @@ -110,9 +119,9 @@ - (void)addTask:(MobilyTask*)task { - (void)addTask:(MobilyTask*)task priority:(MobilyTaskPriority)priority { [self updating]; - MobilyTaskOperation* operation = MOBILY_SAFE_AUTORELEASE([[MobilyTaskOperation alloc] initWithMTaskManager:self task:task]); + MobilyTaskOperation* operation = [[MobilyTaskOperation alloc] initWithTaskManager:self task:task]; if(operation != nil) { - [operation setQueuePriority:(NSOperationQueuePriority)priority]; + operation.queuePriority = (NSOperationQueuePriority)priority; [_queueManager addOperation:operation]; } [self updated]; @@ -120,8 +129,8 @@ - (void)addTask:(MobilyTask*)task priority:(MobilyTaskPriority)priority { - (void)cancelTask:(MobilyTask*)task { [self updating]; - [[_queueManager operations] enumerateObjectsUsingBlock:^(MobilyTaskOperation* operation, NSUInteger idx, BOOL* stop) { - if([task isEqual:[operation task]] == YES) { + [[_queueManager operations] enumerateObjectsUsingBlock:^(MobilyTaskOperation* operation, NSUInteger index __unused, BOOL* stop) { + if([task isEqual:operation.task] == YES) { [operation cancel]; *stop = YES; } @@ -131,7 +140,7 @@ - (void)cancelTask:(MobilyTask*)task { - (void)cancelAllTasks { [self updating]; - [[_queueManager operations] enumerateObjectsUsingBlock:^(MobilyTaskOperation* operation, NSUInteger idx, BOOL* stop) { + [[_queueManager operations] enumerateObjectsUsingBlock:^(MobilyTaskOperation* operation, NSUInteger index __unused, BOOL* stop __unused) { [operation cancel]; }]; [self updated]; @@ -139,41 +148,41 @@ - (void)cancelAllTasks { - (void)enumirateTasksUsingBlock:(MobilyTaskManagerEnumBlock)block { [self updating]; - [[_queueManager operations] enumerateObjectsUsingBlock:^(MobilyTaskOperation* operation, NSUInteger idx, BOOL* stop) { - block([operation task], stop); + [[_queueManager operations] enumerateObjectsUsingBlock:^(MobilyTaskOperation* operation, NSUInteger index __unused, BOOL* stop) { + block(operation.task, stop); }]; [self updated]; } - (NSArray*)tasks { - NSMutableArray* result = [NSMutableArray array]; + NSMutableArray* result = NSMutableArray.array; if(result != nil) { [self updating]; - [[_queueManager operations] enumerateObjectsUsingBlock:^(MobilyTaskOperation* operation, NSUInteger idx, BOOL* stop) { - [result addObject:[operation task]]; + [[_queueManager operations] enumerateObjectsUsingBlock:^(MobilyTaskOperation* operation, NSUInteger index __unused, BOOL* stop __unused) { + [result addObject:operation.task]; }]; [self updated]; } - return MOBILY_SAFE_AUTORELEASE([result copy]); + return [result copy]; } - (NSUInteger)countTasks { [self updating]; - NSUInteger result = [_queueManager operationCount]; + NSUInteger result = _queueManager.operationCount; [self updated]; return result; } - (void)updating { if(_updateCount == 0) { - [_queueManager setSuspended:YES]; + _queueManager.suspended = YES; } _updateCount++; } - (void)updated { if(_updateCount == 1) { - [_queueManager setSuspended:NO]; + _queueManager.suspended = NO; } _updateCount--; } @@ -184,7 +193,7 @@ - (void)wait { - (void)startBackgroundSession { if(_backgroundTaskId == UIBackgroundTaskInvalid) { - _backgroundTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ + _backgroundTaskId = [UIApplication.sharedApplication beginBackgroundTaskWithExpirationHandler:^{ [self cancelAllTasks]; [self stopBackgroundSession]; }]; @@ -193,7 +202,7 @@ - (void)startBackgroundSession { - (void)stopBackgroundSession { if(_backgroundTaskId != UIBackgroundTaskInvalid) { - [[UIApplication sharedApplication] endBackgroundTask:_backgroundTaskId]; + [UIApplication.sharedApplication endBackgroundTask:_backgroundTaskId]; _backgroundTaskId = UIBackgroundTaskInvalid; } } @@ -206,29 +215,40 @@ - (void)stopBackgroundSession { @implementation MobilyTask -- (id)init { +#pragma mark Synthesize + +@synthesize taskOperation = _taskOperation; +@synthesize needRework = _needRework; + +#pragma mark Init / Free + +- (instancetype)init { self = [super init]; if(self != nil) { + [self setup]; } return self; } -- (void)dealloc { - [self setTaskManager:nil]; - [self setTaskOperation:nil]; - - MOBILY_SAFE_DEALLOC; +- (void)setup { } +#pragma mark Public + - (BOOL)isCanceled { return [_taskOperation isCancelled]; } +- (void)setNeedRework { + _needRework = YES; +} + - (BOOL)willStart { return YES; } - (void)working { + _needRework = NO; } - (void)didComplete { @@ -251,15 +271,21 @@ - (void)cancel { @implementation MobilyTaskOperation -- (id)initWithMTaskManager:(MobilyTaskManager*)taskManager task:(MobilyTask*)task { +#pragma mark Synthesize + +@synthesize task = _task; + +#pragma mark Init / Free + +- (instancetype)initWithTaskManager:(MobilyTaskManager*)taskManager task:(MobilyTask*)task { self = [super init]; if(self != nil) { - [self setTaskManager:taskManager]; - [self setTask:task]; + _taskManager = taskManager; + _task = task; - [_task setTaskOperation:self]; + _task.taskOperation = self; - [self setCompletionBlock:^{ + self.completionBlock = ^{ if([task isCanceled] == YES) { @autoreleasepool { [task didCancel]; @@ -269,18 +295,13 @@ - (id)initWithMTaskManager:(MobilyTaskManager*)taskManager task:(MobilyTask*)tas [task didComplete]; } } - [task setTaskOperation:nil]; - }]; + task.taskOperation = nil; + }; } return self; } -- (void)dealloc { - [self setTaskManager:nil]; - [self setTask:nil]; - - MOBILY_SAFE_DEALLOC; -} +#pragma mark NSOperation - (void)main { if(_task != nil) { @@ -304,7 +325,38 @@ - (void)main { - (void)cancel { [super cancel]; - [_task setTaskOperation:nil]; + _task.taskOperation = nil; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyTaskHttpQuery + +#pragma mark MobilyTask + +@synthesize httpQuery = _httpQuery; + +#pragma mark MobilyTask + +- (BOOL)willStart { + if([super willStart] == YES) { + return (_httpQuery != nil); + } + return NO; +} + +- (void)working { + [super working]; + [_httpQuery start]; +} + +- (void)cancel { + [_httpQuery cancel]; + [super cancel]; } @end diff --git a/Classes/UI/ViewFieldText/MobilyViewFieldText.h b/Sources/MobilyCore/MobilyTextField.h similarity index 75% rename from Classes/UI/ViewFieldText/MobilyViewFieldText.h rename to Sources/MobilyCore/MobilyTextField.h index 22ba363..a65f728 100644 --- a/Classes/UI/ViewFieldText/MobilyViewFieldText.h +++ b/Sources/MobilyCore/MobilyTextField.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,25 +33,39 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyBuilder.h" +#import +#import /*--------------------------------------------------*/ -@interface MobilyViewFieldText : UITextField< MobilyBuilderObject > +@interface MobilyTextField : UITextField< MobilyBuilderObject, MobilyValidatedObject > -@property(nonatomic, readwrite, assign) BOOL hiddenToolbar; +@property(nonatomic, readwrite, strong) IBOutlet id validator; + +@property(nonatomic, readwrite, assign) IBInspectable BOOL hiddenToolbar; +@property(nonatomic, readwrite, assign) IBInspectable BOOL hiddenToolbarArrows; @property(nonatomic, readwrite, strong) UIToolbar* toolbar; @property(nonatomic, readwrite, strong) UIBarButtonItem* prevButton; @property(nonatomic, readwrite, strong) UIBarButtonItem* nextButton; @property(nonatomic, readwrite, strong) UIBarButtonItem* flexButton; @property(nonatomic, readwrite, strong) UIBarButtonItem* doneButton; -- (void)setupView; +@property(nonatomic, readwrite, strong) NSString* phonePrefix; +@property(nonatomic, readwrite, strong) NSString* phoneFormat; + +- (void)setup NS_REQUIRES_SUPER; - (void)setHiddenToolbar:(BOOL)hiddenToolbar animated:(BOOL)animated; +- (void)setPhoneFormat:(NSString *)phoneFormat withPrefix:(NSString*)phonePrefix; - (void)didBeginEditing; - (void)didEndEditing; +- (void)didValueChanged; + +- (void)validate; + +- (BOOL)isEmptyText; +- (BOOL)isPhoneComplete; @end diff --git a/Sources/MobilyCore/MobilyTextField.m b/Sources/MobilyCore/MobilyTextField.m new file mode 100644 index 0000000..f83b8e7 --- /dev/null +++ b/Sources/MobilyCore/MobilyTextField.m @@ -0,0 +1,402 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +#define MOBILY_DURATION 0.2f +#define MOBILY_TOOLBAR_HEIGHT 44.0f + +/*--------------------------------------------------*/ + +const NSString* kPhoneEmptySymbol = @"_"; + +/*--------------------------------------------------*/ + +@interface MobilyTextField () + +@property(nonatomic, readwrite, weak) UIResponder* prevInputResponder; +@property(nonatomic, readwrite, weak) UIResponder* nextInputResponder; + +@property(nonatomic, readwrite, assign) NSInteger prevPhoneDigitsCount; +@property(nonatomic, readwrite, assign) NSInteger formatDigitsCount; +@property(nonatomic, readwrite, strong) NSString* phonePrefixWithoutSpaces; + +- (void)pressedPrev; +- (void)pressedNext; +- (void)pressedDone; + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyTextField + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; +@synthesize validator = _validator; +@synthesize form = _form; + +#pragma mark NSKeyValueCoding + +#pragma mark Init / Free + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(didBeginEditing) name:UITextFieldTextDidBeginEditingNotification object:self]; + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(didEndEditing) name:UITextFieldTextDidEndEditingNotification object:self]; + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(didValueChanged) name:UITextFieldTextDidChangeNotification object:self]; +} + +- (void)dealloc { + [NSNotificationCenter.defaultCenter removeObserver:self]; + + self.objectName = nil; + self.objectParent = nil; + self.objectChilds = nil; + + self.toolbar = nil; + self.prevButton = nil; + self.nextButton = nil; + self.flexButton = nil; + self.doneButton = nil; + + self.prevInputResponder = nil; + self.nextInputResponder = nil; +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return self.subviews; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + [self addSubview:(UIView*)objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + [self moRemoveSubview:(UIView*)objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark Property + +- (void)setText:(NSString*)string { + [super setText:string]; + if(self.isEditing == NO) { + [self validate]; + } +} + +- (void)setForm:(MobilyFieldForm*)form { + if([_form isEqual:form] == NO) { + _form = form; + [self validate]; + } +} + +- (void)setValidator:(id< MobilyFieldValidator >)validator { + if([_validator isEqual:validator] == NO) { + if(_validator != nil) { + _validator.control = nil; + } + _validator = validator; + if(_validator != nil) { + _validator.control = self; + } + [self validate]; + } +} + +- (void)setHiddenToolbar:(BOOL)hiddenToolbar { + [self setHiddenToolbar:hiddenToolbar animated:NO]; +} + +- (void)setHiddenToolbarArrows:(BOOL)hiddenToolbarArrows { + if(_hiddenToolbarArrows != hiddenToolbarArrows) { + _hiddenToolbarArrows = hiddenToolbarArrows; + if([self isEditing] == YES) { + if(_hiddenToolbarArrows == YES) { + _toolbar.items = @[ _flexButton, _doneButton ]; + } else { + _toolbar.items = @[ _prevButton, _nextButton, _flexButton, _doneButton ]; + } + } + } +} + +- (void)setPhonePrefix:(NSString *)phonePrefix { + if([_phonePrefix isEqualToString:phonePrefix] == NO) { + _phonePrefix = phonePrefix; + self.phonePrefixWithoutSpaces = [[_phonePrefix componentsSeparatedByCharactersInSet:NSCharacterSet.whitespaceCharacterSet] componentsJoinedByString:@""]; + } +} + +- (void)setPhoneFormat:(NSString *)phoneFormat { + if([phoneFormat isEqualToString:_phoneFormat] == NO) { + _phoneFormat = phoneFormat; + + NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:(NSString*)kPhoneEmptySymbol options:NSRegularExpressionCaseInsensitive error:nil]; + self.formatDigitsCount = [regex numberOfMatchesInString:_phoneFormat options:0 range:NSMakeRange(0, _phoneFormat.length)]; + } +} + +#pragma mark Public + +- (void)setHiddenToolbar:(BOOL)hiddenToolbar animated:(BOOL)animated { + if(_hiddenToolbar != hiddenToolbar) { + _hiddenToolbar = hiddenToolbar; + + if([self isEditing] == YES) { + CGFloat toolbarHeight = (_hiddenToolbar == NO) ? MOBILY_TOOLBAR_HEIGHT : 0.0f; + if(animated == YES) { + [UIView animateWithDuration:MOBILY_DURATION + animations:^{ + _toolbar.moFrameHeight = toolbarHeight; + }]; + } else { + _toolbar.moFrameHeight = toolbarHeight; + } + } + } +} + +- (void)setPhoneFormat:(NSString *)phoneFormat withPrefix:(NSString*)phonePrefix { + self.phonePrefix = phonePrefix; + self.phoneFormat = phoneFormat; +} + +- (void)didBeginEditing { + if(_phoneFormat != nil) { + [self updateTextWithPhoneFormat]; + } + if(_toolbar == nil) { + CGRect windowBounds = self.window.bounds; + self.toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(windowBounds.origin.x, windowBounds.origin.y, windowBounds.size.width, MOBILY_TOOLBAR_HEIGHT)]; + self.prevButton = [[UIBarButtonItem alloc] initWithTitle:@"<" style:UIBarButtonItemStylePlain target:self action:@selector(pressedPrev)]; + self.nextButton = [[UIBarButtonItem alloc] initWithTitle:@">" style:UIBarButtonItemStylePlain target:self action:@selector(pressedNext)]; + self.flexButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; + self.doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(pressedDone)]; + + _toolbar.barStyle = UIBarStyleDefault; + _toolbar.clipsToBounds = YES; + } + if(_toolbar != nil) { + _prevInputResponder = [UIResponder moPrevResponderFromView:self]; + _nextInputResponder = [UIResponder moNextResponderFromView:self]; + if(_hiddenToolbarArrows == YES) { + _toolbar.items = @[ _flexButton, _doneButton ]; + } else { + _toolbar.items = @[ _prevButton, _nextButton, _flexButton, _doneButton ]; + } + _prevButton.enabled = (_prevInputResponder != nil); + _nextButton.enabled = (_nextInputResponder != nil); + _toolbar.moFrameHeight = (_hiddenToolbar == NO) ? MOBILY_TOOLBAR_HEIGHT : 0.0f; + self.inputAccessoryView = _toolbar; + [self reloadInputViews]; + } +} + +- (void)didValueChanged { + if(_phoneFormat != nil) { + [self updateTextWithPhoneFormat]; + } + [self validate]; +} + +- (void)didEndEditing { + if(_phoneFormat != nil) { + NSArray* digits = [self getDigits]; + if(digits.count == 0) { + self.text = @""; + } + } + + _prevInputResponder = nil; + _nextInputResponder = nil; +} + +- (BOOL)isEmptyText { + NSCharacterSet* whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet]; + NSString* trimmed = [[self text] stringByTrimmingCharactersInSet:whitespace]; + if([trimmed length] == 0) { + return YES; + } + return NO; +} + +- (BOOL)isPhoneComplete { + return (_formatDigitsCount <= [[self getDigits] count]); +} + +#pragma mark MobilyValidatedObject + +- (void)validate { + if((_form != nil) && (_validator != nil)) { + if([_validator validate:self.text] == YES) { + [_form _validatedSuccess:self andValue:self.text]; + } else { + [_form _validatedFail:self andValue:self.text]; + } + } +} + +- (NSArray*)messages { + if((_form != nil) && (_validator != nil)) { + return [_validator messages:self.text]; + } + return @[]; +} + +#pragma mark Private + +- (void)updateTextWithPhoneFormat { + __block NSString* newValue = [NSString stringWithFormat:@"%@%@",(_phonePrefix != nil) ? _phonePrefix : @"", _phoneFormat]; + NSMutableArray* digits = [self getDigits]; + if(digits.count > 0) { + if(self.text.length < newValue.length) { + if(_prevPhoneDigitsCount == digits.count) { + [digits removeLastObject]; + } + } + [digits moEach:^(NSString* digit) { + NSRange range = [newValue rangeOfString:(NSString*)kPhoneEmptySymbol]; + if(range.location != NSNotFound) { + newValue = [newValue stringByReplacingCharactersInRange:range withString:digit]; + } + }]; + } + + self.text = newValue; + self.prevPhoneDigitsCount = digits.count; + + NSRange range = [self.text rangeOfString:(NSString*)kPhoneEmptySymbol]; + if(range.location != NSNotFound) { + [self selectTextAtIndex:range.location]; + } +} + +- (NSMutableArray*)getDigits { + NSString* text = self.text; + + if(_phonePrefix != nil) { + NSRange range = [text rangeOfString:_phonePrefix]; + if(range.location != NSNotFound) { + text = [text stringByReplacingCharactersInRange:range withString:@""]; + } + + range = [text rangeOfString:_phonePrefixWithoutSpaces]; + if(range.location != NSNotFound) { + text = [text stringByReplacingCharactersInRange:range withString:@""]; + } + } + + NSArray* digits = [[[text componentsSeparatedByCharactersInSet:NSCharacterSet.decimalDigitCharacterSet.invertedSet] componentsJoinedByString:@""] moCharactersArray]; + if(_prevPhoneDigitsCount < 1) { + if(digits.count > _formatDigitsCount) { + digits = [digits subarrayWithRange:NSMakeRange((digits.count - _formatDigitsCount), _formatDigitsCount)]; + } + } + return [digits mutableCopy]; +} + +- (void)selectTextAtIndex:(NSInteger)index { + NSRange range = NSMakeRange(index, 0); + UITextPosition *start = [self positionFromPosition:[self beginningOfDocument] offset:range.location]; + UITextPosition *end = [self positionFromPosition:start offset:range.length]; + [self setSelectedTextRange:[self textRangeFromPosition:start toPosition:end]]; +} + +- (void)pressedPrev { + if(_prevInputResponder != nil) { + [_prevInputResponder becomeFirstResponder]; + } +} + +- (void)pressedNext { + if(_nextInputResponder != nil) { + [_nextInputResponder becomeFirstResponder]; + } +} + +- (void)pressedDone { + [self endEditing:NO]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyTextView.h b/Sources/MobilyCore/MobilyTextView.h new file mode 100644 index 0000000..4e0cd08 --- /dev/null +++ b/Sources/MobilyCore/MobilyTextView.h @@ -0,0 +1,72 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyTextView : UITextView< MobilyBuilderObject, MobilyValidatedObject > + +@property(nonatomic, readonly, assign, getter=isEditing) BOOL editing; + +@property(nonatomic, readwrite, copy) IBInspectable NSString* placeholder; +@property(nonatomic, readwrite, copy) IBInspectable NSAttributedString* attributedPlaceholder; +@property(nonatomic, readwrite, strong) IBInspectable UIFont* placeholderFont; +@property(nonatomic, readwrite, strong) IBInspectable UIColor* placeholderColor; + +@property(nonatomic, readwrite, assign) IBInspectable BOOL hiddenToolbar; +@property(nonatomic, readwrite, assign) IBInspectable BOOL hiddenToolbarArrows; +@property(nonatomic, readwrite, strong) UIToolbar* toolbar; +@property(nonatomic, readwrite, strong) UIBarButtonItem* prevButton; +@property(nonatomic, readwrite, strong) UIBarButtonItem* nextButton; +@property(nonatomic, readwrite, strong) UIBarButtonItem* flexButton; +@property(nonatomic, readwrite, strong) UIBarButtonItem* doneButton; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)setHiddenToolbar:(BOOL)hiddenToolbar animated:(BOOL)animated; + +- (void)didBeginEditing; +- (void)didEndEditing; +- (void)didValueChanged; + +- (void)validate; + +- (CGRect)placeholderRectForBounds:(CGRect)bounds; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyTextView.m b/Sources/MobilyCore/MobilyTextView.m new file mode 100644 index 0000000..4efdfec --- /dev/null +++ b/Sources/MobilyCore/MobilyTextView.m @@ -0,0 +1,369 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +#define MOBILY_DURATION 0.2f +#define MOBILY_TOOLBAR_HEIGHT 44.0f + +/*--------------------------------------------------*/ + +@interface MobilyTextView () + +@property(nonatomic, readwrite, weak) UIResponder* prevInputResponder; +@property(nonatomic, readwrite, weak) UIResponder* nextInputResponder; + +- (void)pressedPrev; +- (void)pressedNext; +- (void)pressedDone; + +@end + +/*--------------------------------------------------*/ + +@implementation MobilyTextView + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; +@synthesize validator = _validator; +@synthesize form = _form; + +#pragma mark NSKeyValueCoding + +#pragma mark Init / Free + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(didBeginEditing) name:UITextViewTextDidBeginEditingNotification object:self]; + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(didEndEditing) name:UITextViewTextDidEndEditingNotification object:self]; + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(didValueChanged) name:UITextViewTextDidChangeNotification object:self]; +} + +- (void)dealloc { + [NSNotificationCenter.defaultCenter removeObserver:self]; +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return self.subviews; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + [self addSubview:(UIView*)objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + [self moRemoveSubview:(UIView*)objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark Public override + +- (void)insertText:(NSString*)string { + [super insertText:string]; + [self setNeedsDisplay]; +} + +#pragma mark Property + +- (void)setContentInset:(UIEdgeInsets)contentInset { + [super setContentInset:contentInset]; + [self setNeedsDisplay]; +} + +- (void)setText:(NSString*)string { + [super setText:string]; + if(self.isEditing == NO) { + [self validate]; + } + [self setNeedsDisplay]; +} + +- (void)setAttributedText:(NSAttributedString*)attributedText { + [super setAttributedText:attributedText]; + [self setNeedsDisplay]; +} + +- (void)setFont:(UIFont *)font { + [super setFont:font]; + [self setNeedsDisplay]; +} + +- (void)setTextAlignment:(NSTextAlignment)textAlignment { + [super setTextAlignment:textAlignment]; + [self setNeedsDisplay]; +} + +- (void)setPlaceholder:(NSString*)string { + if([string isEqualToString:_attributedPlaceholder.string] == NO) { + NSMutableDictionary* attributes = [[NSMutableDictionary alloc] init]; + if(([self isFirstResponder] == YES) && (self.typingAttributes != nil)) { + [attributes addEntriesFromDictionary:self.typingAttributes]; + } else { + attributes[NSFontAttributeName] = (_placeholderFont != nil) ? _placeholderFont : self.font; + attributes[NSForegroundColorAttributeName] = (_placeholderColor != nil) ? _placeholderColor : [UIColor colorWithRed:170.0f/255 green:170.0f/255 blue:170.0f/255 alpha:1.0f]; + if(self.textAlignment != NSTextAlignmentLeft) { + NSMutableParagraphStyle* paragraph = [[NSMutableParagraphStyle alloc] init]; + paragraph.alignment = self.textAlignment; + attributes[NSParagraphStyleAttributeName] = paragraph; + } + } + _attributedPlaceholder = [[NSAttributedString alloc] initWithString:string attributes:attributes]; + [self setNeedsDisplay]; + } +} + +- (NSString*)placeholder { + return _attributedPlaceholder.string; +} + +- (void)setAttributedPlaceholder:(NSAttributedString *)attributedPlaceholder { + if([_attributedPlaceholder isEqualToAttributedString:attributedPlaceholder] == NO) { + _attributedPlaceholder = attributedPlaceholder; + [self setNeedsDisplay]; + } +} + +- (void)setForm:(MobilyFieldForm*)form { + if([_form isEqual:form] == NO) { + _form = form; + [self validate]; + } +} + +- (void)setValidator:(id< MobilyFieldValidator >)validator { + if([_validator isEqual:validator] == NO) { + if(_validator != nil) { + _validator.control = nil; + } + _validator = validator; + if(_validator != nil) { + _validator.control = self; + } + [self validate]; + } +} + +- (void)setHiddenToolbar:(BOOL)hiddenToolbar { + [self setHiddenToolbar:hiddenToolbar animated:NO]; +} + +- (void)setHiddenToolbarArrows:(BOOL)hiddenToolbarArrows { + if(_hiddenToolbarArrows != hiddenToolbarArrows) { + _hiddenToolbarArrows = hiddenToolbarArrows; + if([self isEditing] == YES) { + if(_hiddenToolbarArrows == YES) { + _toolbar.items = @[ _flexButton, _doneButton ]; + } else { + _toolbar.items = @[ _prevButton, _nextButton, _flexButton, _doneButton ]; + } + } + } +} + +#pragma mark Public override + +- (void)drawRect:(CGRect)rect { + [super drawRect:rect]; + if((_attributedPlaceholder != nil) && (self.text.length < 1)) { + [_attributedPlaceholder drawInRect:[self placeholderRectForBounds:self.bounds]]; + } +} + + +- (void)layoutSubviews { + [super layoutSubviews]; + if((_attributedPlaceholder != nil) && (self.text.length < 1)) { + [self setNeedsDisplay]; + } +} + +#pragma mark Public + +- (void)setHiddenToolbar:(BOOL)hiddenToolbar animated:(BOOL)animated { + if(_hiddenToolbar != hiddenToolbar) { + _hiddenToolbar = hiddenToolbar; + + if([self isEditing] == YES) { + CGFloat toolbarHeight = (_hiddenToolbar == NO) ? MOBILY_TOOLBAR_HEIGHT : 0.0f; + if(animated == YES) { + [UIView animateWithDuration:MOBILY_DURATION + animations:^{ + _toolbar.moFrameHeight = toolbarHeight; + }]; + } else { + _toolbar.moFrameHeight = toolbarHeight; + } + } + } +} + +- (void)didBeginEditing { + if(_toolbar == nil) { + CGRect windowBounds = self.window.bounds; + self.toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(windowBounds.origin.x, windowBounds.origin.y, windowBounds.size.width, MOBILY_TOOLBAR_HEIGHT)]; + self.prevButton = [[UIBarButtonItem alloc] initWithTitle:@"<" style:UIBarButtonItemStylePlain target:self action:@selector(pressedPrev)]; + self.nextButton = [[UIBarButtonItem alloc] initWithTitle:@">" style:UIBarButtonItemStylePlain target:self action:@selector(pressedNext)]; + self.flexButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; + self.doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(pressedDone)]; + + _toolbar.barStyle = UIBarStyleDefault; + _toolbar.clipsToBounds = YES; + } + if(_toolbar != nil) { + _prevInputResponder = [UIResponder moPrevResponderFromView:self]; + _nextInputResponder = [UIResponder moNextResponderFromView:self]; + if(_hiddenToolbarArrows == YES) { + _toolbar.items = @[ _flexButton, _doneButton ]; + } else { + _toolbar.items = @[ _prevButton, _nextButton, _flexButton, _doneButton ]; + } + _prevButton.enabled = (_prevInputResponder != nil); + _nextButton.enabled = (_nextInputResponder != nil); + _toolbar.moFrameHeight = (_hiddenToolbar == NO) ? MOBILY_TOOLBAR_HEIGHT : 0.0f; + self.inputAccessoryView = _toolbar; + [self reloadInputViews]; + } +} + +- (void)didValueChanged { + [self setNeedsDisplay]; + [self validate]; +} + +- (void)didEndEditing { + _prevInputResponder = nil; + _nextInputResponder = nil; +} + +- (CGRect)placeholderRectForBounds:(CGRect)bounds { + CGRect rect = UIEdgeInsetsInsetRect(bounds, self.contentInset); + if([self respondsToSelector:@selector(textContainer)] == YES) { + rect = UIEdgeInsetsInsetRect(rect, self.textContainerInset); + CGFloat padding = self.textContainer.lineFragmentPadding; + rect.origin.x += padding; + rect.size.width -= padding * 2.0f; + } else { + if(self.contentInset.left == 0.0f) { + rect.origin.x += 8.0f; + } + rect.origin.y += 8.0f; + } + return rect; +} + +#pragma mark MobilyValidatedObject + +- (void)validate { + if((_form != nil) && (_validator != nil)) { + if([_validator validate:self.text] == YES) { + [_form _validatedSuccess:self andValue:self.text]; + } else { + [_form _validatedFail:self andValue:self.text]; + } + } +} + +- (NSArray*)messages { + if((_form != nil) && (_validator != nil)) { + return [_validator messages:self.text]; + } + return @[]; +} + +#pragma mark Private + +- (void)pressedPrev { + if(_prevInputResponder != nil) { + [_prevInputResponder becomeFirstResponder]; + } +} + +- (void)pressedNext { + if(_nextInputResponder != nil) { + [_nextInputResponder becomeFirstResponder]; + } +} + +- (void)pressedDone { + [self endEditing:NO]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyTimeout.h b/Sources/MobilyCore/MobilyTimeout.h new file mode 100644 index 0000000..b04707c --- /dev/null +++ b/Sources/MobilyCore/MobilyTimeout.h @@ -0,0 +1,46 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyTimeout : NSObject + ++ (void)executeBlock:(void (^)())block afterDelay:(NSTimeInterval)delay; + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/Sources/MobilyCore/MobilyTimeout.m b/Sources/MobilyCore/MobilyTimeout.m new file mode 100644 index 0000000..22fde1c --- /dev/null +++ b/Sources/MobilyCore/MobilyTimeout.m @@ -0,0 +1,59 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyTimeout () + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyTimeout + ++ (void)executeBlock:(void (^)())block afterDelay:(NSTimeInterval)delay { + dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC); + dispatch_after(popTime, dispatch_get_main_queue(), block); +} + +@end + +/*--------------------------------------------------*/ \ No newline at end of file diff --git a/Sources/MobilyCore/MobilyTimer.h b/Sources/MobilyCore/MobilyTimer.h new file mode 100644 index 0000000..0b9d7ec --- /dev/null +++ b/Sources/MobilyCore/MobilyTimer.h @@ -0,0 +1,100 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef void(^MobilyTimerBlock)(); + +/*--------------------------------------------------*/ + +@protocol MobilyTimerDelegate; + +/*--------------------------------------------------*/ + +@interface MobilyTimer : NSObject < MobilyObject > + +@property(nonatomic, readonly, assign, getter=isDelaying) BOOL delaying; +@property(nonatomic, readonly, assign, getter=isStarted) BOOL started; +@property(nonatomic, readonly, assign, getter=isPaused) BOOL paused; +@property(nonatomic, readwrite, assign) NSTimeInterval delay; +@property(nonatomic, readwrite, assign) NSTimeInterval interval; +@property(nonatomic, readwrite, assign) NSUInteger repeat; +@property(nonatomic, readonly, assign) NSTimeInterval duration; +@property(nonatomic, readonly, assign) NSTimeInterval elapsed; +@property(nonatomic, readonly, assign) NSUInteger repeated; + +@property(nonatomic, readwrite, weak) id< MobilyTimerDelegate > delegate; +@property(nonatomic, readwrite, copy) MobilyTimerBlock startedBlock; +@property(nonatomic, readwrite, copy) MobilyTimerBlock repeatBlock; +@property(nonatomic, readwrite, copy) MobilyTimerBlock stopedBlock; +@property(nonatomic, readwrite, copy) MobilyTimerBlock pausedBlock; +@property(nonatomic, readwrite, copy) MobilyTimerBlock resumedBlock; + ++ (instancetype)timerWithInterval:(NSTimeInterval)interval; ++ (instancetype)timerWithDelay:(NSTimeInterval)delay interval:(NSTimeInterval)interval; ++ (instancetype)timerWithInterval:(NSTimeInterval)interval repeat:(NSUInteger)repeat; ++ (instancetype)timerWithDelay:(NSTimeInterval)delay interval:(NSTimeInterval)interval repeat:(NSUInteger)repeat; + +- (instancetype)initWithInterval:(NSTimeInterval)interval; +- (instancetype)initWithDelay:(NSTimeInterval)delay interval:(NSTimeInterval)interval; +- (instancetype)initWithInterval:(NSTimeInterval)interval repeat:(NSUInteger)repeat; +- (instancetype)initWithDelay:(NSTimeInterval)delay interval:(NSTimeInterval)interval repeat:(NSUInteger)repeat; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)start; +- (void)stop; + +- (void)pause; +- (void)resume; + +@end + +/*--------------------------------------------------*/ + +@protocol MobilyTimerDelegate < NSObject > + +@optional +-(void)timerDidStarted:(MobilyTimer*)timer; +-(void)timerDidRepeat:(MobilyTimer*)timer; +-(void)timerDidStoped:(MobilyTimer*)timer; +-(void)timerDidResumed:(MobilyTimer*)timer; +-(void)timerDidPaused:(MobilyTimer*)timer; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyTimer.m b/Sources/MobilyCore/MobilyTimer.m new file mode 100644 index 0000000..2b57af2 --- /dev/null +++ b/Sources/MobilyCore/MobilyTimer.m @@ -0,0 +1,275 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyTimer () + +@property(nonatomic, readwrite, assign, getter=isDelaying) BOOL delaying; +@property(nonatomic, readwrite, assign, getter=isStarted) BOOL started; +@property(nonatomic, readwrite, assign, getter=isPaused) BOOL paused; +@property(nonatomic, readwrite, assign) NSTimeInterval startTime; +@property(nonatomic, readwrite, assign) NSTimeInterval pauseTime; +@property(nonatomic, readwrite, assign) NSTimeInterval elapsed; +@property(nonatomic, readwrite, assign) NSUInteger repeated; +@property(nonatomic, readwrite, strong) NSTimer* timer; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyTimer + +#pragma mark Init / Free + ++ (instancetype)timerWithInterval:(NSTimeInterval)interval { + return [[self alloc] initWithInterval:interval]; +} + ++ (instancetype)timerWithDelay:(NSTimeInterval)delay interval:(NSTimeInterval)interval { + return [[self alloc] initWithDelay:delay interval:interval]; +} + ++ (instancetype)timerWithInterval:(NSTimeInterval)interval repeat:(NSUInteger)repeat { + return [[self alloc] initWithInterval:interval repeat:repeat]; +} + ++ (instancetype)timerWithDelay:(NSTimeInterval)delay interval:(NSTimeInterval)interval repeat:(NSUInteger)repeat { + return [[self alloc] initWithDelay:delay interval:interval repeat:repeat]; +} + +- (instancetype)initWithInterval:(NSTimeInterval)interval { + self = [super init]; + if(self != nil) { + self.interval = interval; + [self setup]; + } + return self; +} + +- (instancetype)initWithDelay:(NSTimeInterval)delay interval:(NSTimeInterval)interval { + self = [super init]; + if(self != nil) { + self.delay = delay; + self.interval = interval; + [self setup]; + } + return self; +} + +- (instancetype)initWithInterval:(NSTimeInterval)interval repeat:(NSUInteger)repeat { + self = [super init]; + if(self != nil) { + self.interval = interval; + self.repeat = repeat; + [self setup]; + } + return self; +} + +- (instancetype)initWithDelay:(NSTimeInterval)delay interval:(NSTimeInterval)interval repeat:(NSUInteger)repeat { + self = [super init]; + if(self != nil) { + self.delay = delay; + self.interval = interval; + self.repeat = repeat; + [self setup]; + } + return self; +} + +- (void)setup { +} + +- (void)dealloc { + [self stop]; +} + +#pragma mark Public + +- (void)start { + if(_started == NO) { + self.started = YES; + self.paused = NO; + self.elapsed = 0.0f; + self.repeated = 0; + if(_delay > 0.0f) { + self.delaying = YES; + self.timer = [NSTimer timerWithTimeInterval:_delay target:self selector:@selector(delayStartHandler) userInfo:nil repeats:NO]; + } + if(_timer == nil) { + self.startTime = NSDate.timeIntervalSinceReferenceDate; + self.delaying = NO; + self.timer = [NSTimer timerWithTimeInterval:_interval target:self selector:@selector(timerHandler) userInfo:nil repeats:(_repeat != 0)]; + if([_delegate respondsToSelector:@selector(timerDidStarted:)] == YES) { + [_delegate timerDidStarted:self]; + } else if(_startedBlock != nil) { + _startedBlock(); + } + } + } +} + +- (void)stop { + if(_started == YES) { + self.started = NO; + self.timer = nil; + self.paused = NO; + if([_delegate respondsToSelector:@selector(timerDidStoped:)] == YES) { + [_delegate timerDidStoped:self]; + } else if(_stopedBlock != nil) { + _stopedBlock(); + } + } +} + +- (void)pause { + if((_started == YES) && (_paused == NO)) { + self.pauseTime = NSDate.timeIntervalSinceReferenceDate; + self.paused = YES; + self.timer = nil; + if([_delegate respondsToSelector:@selector(timerDidPaused:)] == YES) { + [_delegate timerDidPaused:self]; + } else if(_pausedBlock != nil) { + _pausedBlock(); + } + } +} + +- (void)resume { + if((_started == YES) && (_paused == YES)) { + self.paused = NO; + if(_delaying == YES) { + self.timer = [NSTimer timerWithTimeInterval:NSDate.timeIntervalSinceReferenceDate - _delay target:self selector:@selector(delayStartHandler) userInfo:nil repeats:NO]; + } + if(_timer == nil) { + self.startTime = NSDate.timeIntervalSinceReferenceDate - (_pauseTime - _startTime); + self.timer = [NSTimer timerWithTimeInterval:_interval target:self selector:@selector(timerHandler) userInfo:nil repeats:(_repeat != 0)]; + if([_delegate respondsToSelector:@selector(timerDidResumed:)] == YES) { + [_delegate timerDidResumed:self]; + } else if(_resumedBlock != nil) { + _resumedBlock(); + } + } + } +} + +#pragma mark Property + +- (void)setDelay:(NSTimeInterval)delay { + if((_started == NO) && (_delay != delay)) { + _delay = delay; + } +} + +- (void)setInterval:(NSTimeInterval)interval { + if((_started == NO) && (_interval != interval)) { + _interval = interval; + } +} + +- (void)setRepeat:(NSUInteger)repeat { + if((_started == NO) && (_repeat != repeat)) { + _repeat = repeat; + } +} + +- (void)setTimer:(NSTimer*)timer { + if(_timer != timer) { + if(_timer != nil) { + [_timer invalidate]; + } + _timer = timer; + if(_timer != nil) { + [NSRunLoop.mainRunLoop addTimer:_timer forMode:NSRunLoopCommonModes]; + } + } +} + +- (NSTimeInterval)duration { + return _interval * _repeat; +} + +- (NSTimeInterval)elapsed { + if((_started == YES) && (_delaying == NO)) { + self.elapsed = NSDate.timeIntervalSinceReferenceDate - _startTime; + } + return _elapsed; +} + +#pragma mark Private + +- (void)delayStartHandler { + self.startTime = NSDate.timeIntervalSinceReferenceDate; + self.delaying = NO; + self.timer = [NSTimer scheduledTimerWithTimeInterval:_interval target:self selector:@selector(timerHandler) userInfo:nil repeats:(_repeat != 0)]; + if([_delegate respondsToSelector:@selector(timerDidStarted:)] == YES) { + [_delegate timerDidStarted:self]; + } else if(_startedBlock != nil) { + _startedBlock(); + } +} + +- (void)timerHandler { + _repeated++; + if(_repeat == NSNotFound) { + if([_delegate respondsToSelector:@selector(timerDidRepeat:)] == YES) { + [_delegate timerDidRepeat:self]; + } else if(_repeatBlock != nil) { + _repeatBlock(); + } + } else if(_repeat != 0) { + if([_delegate respondsToSelector:@selector(timerDidRepeat:)] == YES) { + [_delegate timerDidRepeat:self]; + } else if(_repeatBlock != nil) { + _repeatBlock(); + } + if(_repeated >= _repeat) { + [self stop]; + } + } else { + [self stop]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyTouchView.h b/Sources/MobilyCore/MobilyTouchView.h new file mode 100755 index 0000000..1aca627 --- /dev/null +++ b/Sources/MobilyCore/MobilyTouchView.h @@ -0,0 +1,46 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyTouchView : MobilyView + +@property(nonatomic, readwrite, weak) UIView* receiver; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyTouchView.m b/Sources/MobilyCore/MobilyTouchView.m new file mode 100755 index 0000000..274612d --- /dev/null +++ b/Sources/MobilyCore/MobilyTouchView.m @@ -0,0 +1,53 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyTouchView + +- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event { + if([self pointInside:point withEvent:event] == YES) { + return self.receiver; + } + return nil; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyTransitionControllerCrossFade.m b/Sources/MobilyCore/MobilyTransitionController+Private.h similarity index 65% rename from Classes/UI/Core/MobilyTransitionControllerCrossFade.m rename to Sources/MobilyCore/MobilyTransitionController+Private.h index 050bd62..6d69bb2 100644 --- a/Classes/UI/Core/MobilyTransitionControllerCrossFade.m +++ b/Sources/MobilyCore/MobilyTransitionController+Private.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,30 +33,42 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyTransitionController.h" +#import /*--------------------------------------------------*/ -@implementation MobilyTransitionControllerCrossFade - -- (void)animateTransition:(id< UIViewControllerContextTransitioning >)transitionContext fromVC:(UIViewController*)fromVC toVC:(UIViewController*)toVC fromView:(UIView*)fromView toView:(UIView*)toView { - UIView* containerView = [transitionContext containerView]; - [containerView addSubview:toView]; - [containerView sendSubviewToBack:toView]; +@interface MobilyTransitionController () { +@protected + __weak id< UIViewControllerContextTransitioning > _transitionContext; + MobilyTransitionOperation _operation; + NSTimeInterval _duration; + CGFloat _percentComplete; + CGFloat _completionSpeed; + UIViewAnimationCurve _completionCurve; + BOOL _interactive; - [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{ - [fromView setAlpha:0.0f]; - } completion:^(BOOL finished) { - if ([transitionContext transitionWasCancelled]) { - [fromView setAlpha:1.0f]; - } else { - [fromView removeFromSuperview]; - [fromView setAlpha:1.0f]; - } - [transitionContext completeTransition:([transitionContext transitionWasCancelled] == NO)]; - }]; + __weak UIViewController* _fromViewController; + CGRect _initialFrameFromViewController; + CGRect _finalFrameFromViewController; + __weak UIViewController* _toViewController; + CGRect _initialFrameToViewController; + CGRect _finalFrameToViewController; + UIView* _containerView; + UIView* _fromView; + UIView* _toView; } +- (void)_prepareTransitionContext; + +- (void)_startTransition; +- (void)_completeTransition; + +- (void)_startInteractive; +- (void)_updateInteractive:(CGFloat)percentComplete; +- (void)_finishInteractive; +- (void)_cancelInteractive; +- (void)_completeInteractive; + @end /*--------------------------------------------------*/ diff --git a/Classes/CG/Core/MobilyCG.h b/Sources/MobilyCore/MobilyTransitionController.h similarity index 53% rename from Classes/CG/Core/MobilyCG.h rename to Sources/MobilyCore/MobilyTransitionController.h index dd89de2..e74ffef 100644 --- a/Classes/CG/Core/MobilyCG.h +++ b/Sources/MobilyCore/MobilyTransitionController.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -32,62 +32,88 @@ /* OTHER DEALINGS IN THE SOFTWARE. */ /* */ /*--------------------------------------------------*/ -#ifndef MOBILY_CG -#define MOBILY_CG + +#import + /*--------------------------------------------------*/ -#import + +@class MobilyTransitionController; + /*--------------------------------------------------*/ -@interface NSString (MobilyCG) +@interface NSString (MobilyTransitionController) -- (CGPoint)convertToPoint; -- (CGPoint)convertToPointSeparated:(NSString*)separated; -- (CGSize)convertToSize; -- (CGSize)convertToSizeSeparated:(NSString*)separated; -- (CGRect)convertToRect; -- (CGRect)convertToRectSeparated:(NSString*)separated; +- (MobilyTransitionController*)moConvertToTransitionController; @end /*--------------------------------------------------*/ -#define MOBILY_DEG_TO_RAD 0.0174532925f +typedef NS_ENUM(NSUInteger, MobilyTransitionOperation) { + MobilyTransitionOperationPresent, + MobilyTransitionOperationDismiss, + MobilyTransitionOperationPush, + MobilyTransitionOperationPop +}; /*--------------------------------------------------*/ -CGFloat CGFloatNearestMore(CGFloat value, CGFloat step); +@interface MobilyTransitionController : NSObject < MobilyObject, UIViewControllerAnimatedTransitioning, UIViewControllerInteractiveTransitioning > + +@property(nonatomic, readwrite, weak) id< UIViewControllerContextTransitioning > transitionContext; +@property(nonatomic, readwrite, assign) MobilyTransitionOperation operation; +@property(nonatomic, readwrite, assign) NSTimeInterval duration; +@property(nonatomic, readonly, assign) CGFloat percentComplete; +@property(nonatomic, readwrite, assign) CGFloat completionSpeed; +@property(nonatomic, readwrite, assign) UIViewAnimationCurve completionCurve; +@property(nonatomic, readonly, assign, getter=isInteractive) BOOL interactive; + +- (void)setup NS_REQUIRES_SUPER; + +- (BOOL)isAnimated; +- (BOOL)isCancelled; + +- (void)beginInteractive; +- (void)updateInteractive:(CGFloat)percentComplete; +- (void)finishInteractive; +- (void)cancelInteractive; +- (void)endInteractive; + +@end /*--------------------------------------------------*/ -CGPoint CGPointAdd(CGPoint point, CGFloat value); -CGPoint CGPointSub(CGPoint point, CGFloat value); -CGPoint CGPointMul(CGPoint point, CGFloat value); -CGPoint CGPointDiv(CGPoint point, CGFloat value); -CGPoint CGPointAddPoint(CGPoint point1, CGPoint point2); -CGPoint CGPointSubPoint(CGPoint point1, CGPoint point2); -CGPoint CGPointMulPoint(CGPoint point1, CGPoint point2); -CGPoint CGPointDivPoint(CGPoint point1, CGPoint point2); +@interface MobilyTransitionControllerCrossFade : MobilyTransitionController + +@end /*--------------------------------------------------*/ -CGSize CGSizeNearestMore(CGSize size, CGFloat step); -CGSize CGSizeAdd(CGSize size, CGFloat value); -CGSize CGSizeSub(CGSize size, CGFloat value); -CGSize CGSizeMul(CGSize size, CGFloat value); -CGSize CGSizeDiv(CGSize size, CGFloat value); +@interface MobilyTransitionControllerCards : MobilyTransitionController + +@end /*--------------------------------------------------*/ -CGRect CGRectAdd(CGRect rect, CGFloat value); -CGRect CGRectSub(CGRect rect, CGFloat value); -CGRect CGRectMul(CGRect rect, CGFloat value); -CGRect CGRectDiv(CGRect rect, CGFloat value); -CGRect CGRectIntersectionExt(CGRect r1, CGRect r2, CGRect* smallRemainder, CGRect* largeRemainder); -CGRect CGRectAspectFillFromBoundsAndSize(CGRect bounds, CGSize size); -CGRect CGRectAspectFitFromBoundsAndSize(CGRect bounds, CGSize size); +@interface MobilyTransitionControllerSlide : MobilyTransitionController + +@property(nonatomic, readwrite, assign) CGFloat ratio; -CGPoint CGRectGetCenterPoint(CGRect rect); +- (instancetype)initWithRatio:(CGFloat)ratio; + +@end /*--------------------------------------------------*/ -#endif + +#define MOBILY_DEFINE_VALIDATE_TRANSITION_CONTROLLER(name) \ +- (id)validate##name:(id)value { \ + if([value isKindOfClass:NSString.class] == YES) { \ + value = [value moConvertToTransitionController]; \ + } \ + if([value isKindOfClass:MobilyTransitionController.class] == YES) { \ + return value; \ + } \ + return nil; \ +} + /*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyTransitionController.m b/Sources/MobilyCore/MobilyTransitionController.m new file mode 100644 index 0000000..5b6d422 --- /dev/null +++ b/Sources/MobilyCore/MobilyTransitionController.m @@ -0,0 +1,242 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +#define MOBILY_TRANSITION_CONTROLLER_CLASS @"MobilyTransitionController%@" + +/*--------------------------------------------------*/ + +@implementation NSString (MobilyTransitionController) + +- (MobilyTransitionController*)moConvertToTransitionController { + static NSCharacterSet* characterSet = nil; + if(characterSet == nil) { + characterSet = [NSCharacterSet characterSetWithCharactersInString:@":-"]; + } + NSString* validKey = NSString.string;; + NSArray* components = [self componentsSeparatedByCharactersInSet:characterSet]; + if(components.count > 1) { + for(NSString* component in components) { + validKey = [validKey stringByAppendingString:[component moStringByUppercaseFirstCharacterString]]; + } + } else { + validKey = [self moStringByUppercaseFirstCharacterString]; + } + Class resultClass = nil; + if(validKey.length > 0) { + Class defaultClass = NSClassFromString([NSString stringWithFormat:MOBILY_TRANSITION_CONTROLLER_CLASS, validKey]); + if([defaultClass isSubclassOfClass:MobilyTransitionController.class] == YES) { + resultClass = defaultClass; + } else { + Class customClass = NSClassFromString(self); + if([customClass isSubclassOfClass:MobilyTransitionController.class] == YES) { + resultClass = customClass; + } + } + } + MobilyTransitionController* result = nil; + if(resultClass != nil) { + result = [resultClass new]; + } + return result; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyTransitionController + +@synthesize transitionContext = _transitionContext; +@synthesize operation = _operation; +@synthesize duration = _duration; +@synthesize percentComplete = _percentComplete; +@synthesize completionSpeed = _completionSpeed; +@synthesize completionCurve = _completionCurve; +@synthesize interactive = _interactive; + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + _operation = MobilyTransitionOperationPresent; + _duration = 0.3f; + _completionSpeed = 720.0f; + _completionSpeed = UIViewAnimationCurveEaseOut; + _initialFrameFromViewController = CGRectNull; + _finalFrameFromViewController = CGRectNull; + _initialFrameToViewController = CGRectNull; + _finalFrameToViewController = CGRectNull; +} + +- (void)dealloc { +} + +#pragma mark Property + +- (void)setTransitionContext:(id< UIViewControllerContextTransitioning >)transitionContext { + if(_transitionContext != transitionContext) { + _transitionContext = transitionContext; + [self _prepareTransitionContext]; + } +} + +#pragma mark Public + +- (BOOL)isAnimated { + return [_transitionContext isAnimated]; +} + +- (BOOL)isCancelled { + return [_transitionContext transitionWasCancelled]; +} + +- (void)beginInteractive { + _interactive = YES; +} + +- (void)updateInteractive:(CGFloat)percentComplete { + if((_interactive == YES) && (_percentComplete != percentComplete)) { + _percentComplete = percentComplete; + [self _updateInteractive:percentComplete]; + } +} + +- (void)finishInteractive { + if(_interactive == YES) { + [self _finishInteractive]; + } +} + +- (void)cancelInteractive { + if(_interactive == YES) { + [self _cancelInteractive]; + } +} + +- (void)endInteractive { + _interactive = NO; +} + +#pragma mark Private + +- (void)_prepareTransitionContext { + _fromViewController = [_transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; + _initialFrameFromViewController = [_transitionContext initialFrameForViewController:_fromViewController]; + _finalFrameFromViewController = [_transitionContext finalFrameForViewController:_fromViewController]; + _toViewController = [_transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; + _initialFrameToViewController = [_transitionContext initialFrameForViewController:_toViewController]; + _finalFrameToViewController = [_transitionContext finalFrameForViewController:_toViewController]; + _containerView = _transitionContext.containerView; + _fromView = (UIDevice.moSystemVersion >= 8.0f) ? [_transitionContext viewForKey:UITransitionContextFromViewKey] : _fromViewController.view; + _toView = (UIDevice.moSystemVersion >= 8.0f) ? [_transitionContext viewForKey:UITransitionContextToViewKey] : _toViewController.view; +} + +- (void)_startTransition { +} + +- (void)_completeTransition { + [_transitionContext completeTransition:([_transitionContext transitionWasCancelled] == NO)]; +} + +- (void)_startInteractive { +} + +- (void)_updateInteractive:(CGFloat __unused)percentComplete { + [_transitionContext updateInteractiveTransition:percentComplete]; +} + +- (void)_finishInteractive { + [_transitionContext finishInteractiveTransition]; +} + +- (void)_cancelInteractive { + [_transitionContext cancelInteractiveTransition]; +} + +- (void)_completeInteractive { + [_transitionContext completeTransition:([_transitionContext transitionWasCancelled] == NO)]; +} + +#pragma mark UIViewControllerAnimatedTransitioning + +- (NSTimeInterval)transitionDuration:(id< UIViewControllerContextTransitioning > __unused)transitionContext { + return _duration; +} + +- (void)animateTransition:(id< UIViewControllerContextTransitioning >)transitionContext { + self.transitionContext = transitionContext; + [self _startTransition]; +} + +- (void)animationEnded:(BOOL __unused)transitionComplete { +} + +#pragma mark UIViewControllerInteractiveTransitioning + +- (void)startInteractiveTransition:(id< UIViewControllerContextTransitioning >)transitionContext { + if((_interactive == YES) && ([transitionContext isInteractive] == YES)) { + self.transitionContext = transitionContext; + [self _startInteractive]; + } else { + [self animateTransition:transitionContext]; + } +} + +- (CGFloat)completionSpeed { + return _completionSpeed; +} + +- (UIViewAnimationCurve)completionCurve { + return _completionSpeed; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyTransitionControllerCards.m b/Sources/MobilyCore/MobilyTransitionControllerCards.m similarity index 55% rename from Classes/UI/Core/MobilyTransitionControllerCards.m rename to Sources/MobilyCore/MobilyTransitionControllerCards.m index aab3eba..b763b5d 100644 --- a/Classes/UI/Core/MobilyTransitionControllerCards.m +++ b/Sources/MobilyCore/MobilyTransitionControllerCards.m @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -32,87 +32,106 @@ /* OTHER DEALINGS IN THE SOFTWARE. */ /* */ /*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ -#import "MobilyTransitionController.h" +#import + +/*--------------------------------------------------*/ + +@interface MobilyTransitionControllerCards () + +- (void)_startTransitionForward; +- (void)_startTransitionReverse; +- (CATransform3D)_firstTransform; +- (CATransform3D)_secondTransformWithView:(UIView*)view; + +@end /*--------------------------------------------------*/ @implementation MobilyTransitionControllerCards -- (void)animateTransition:(id< UIViewControllerContextTransitioning >)transitionContext fromVC:(UIViewController*)fromVC toVC:(UIViewController*)toVC fromView:(UIView*)fromView toView:(UIView*)toView { - if([self isReverse] == YES){ - [self executeReverseAnimation:transitionContext fromVC:fromVC toVC:toVC fromView:fromView toView:toView]; - } else { - [self executeForwardsAnimation:transitionContext fromVC:fromVC toVC:toVC fromView:fromView toView:toView]; +#pragma mark Transition + +- (void)_startTransition { + switch(_operation) { + case MobilyTransitionOperationPresent: + case MobilyTransitionOperationPush: + [self _startTransitionForward]; + break; + case MobilyTransitionOperationDismiss: + case MobilyTransitionOperationPop: + [self _startTransitionReverse]; + break; } - } -- (void)executeForwardsAnimation:(id< UIViewControllerContextTransitioning >)transitionContext fromVC:(UIViewController*)fromVC toVC:(UIViewController*)toVC fromView:(UIView*)fromView toView:(UIView*)toView { - UIView* containerView = [transitionContext containerView]; - CGRect frame = [transitionContext initialFrameForViewController:fromVC]; +#pragma mark Private + +- (void)_startTransitionForward { + CGRect frame = _initialFrameFromViewController; CGRect offScreenFrame = frame; offScreenFrame.origin.y = offScreenFrame.size.height; - [toView setFrame:offScreenFrame]; - [containerView insertSubview:toView aboveSubview:fromView]; - CATransform3D t1 = [self firstTransform]; - CATransform3D t2 = [self secondTransformWithView:fromView]; - [UIView animateKeyframesWithDuration:[self transitionDuration:transitionContext] + _toView.frame = offScreenFrame; + [_containerView insertSubview:_toView aboveSubview:_fromView]; + CATransform3D t1 = [self _firstTransform]; + CATransform3D t2 = [self _secondTransformWithView:_fromView]; + [UIView animateKeyframesWithDuration:_duration delay:0.0f options:UIViewKeyframeAnimationOptionCalculationModeCubic animations:^{ [UIView addKeyframeWithRelativeStartTime:0.0f relativeDuration:0.4f animations:^{ - [[fromView layer] setTransform:t1]; - [fromView setAlpha:0.6f]; + _fromView.layer.transform = t1; + _fromView.alpha = 0.6f; }]; [UIView addKeyframeWithRelativeStartTime:0.2f relativeDuration:0.4f animations:^{ - [[fromView layer] setTransform:t2]; + _fromView.layer.transform = t2; }]; [UIView addKeyframeWithRelativeStartTime:0.6f relativeDuration:0.2f animations:^{ - [toView setFrame:CGRectOffset([toView frame], 0.0f, -30.0f)]; + _toView.frame = CGRectOffset(_toView.frame, 0.0f, -30.0f); }]; [UIView addKeyframeWithRelativeStartTime:0.8f relativeDuration:0.2f animations:^{ - [toView setFrame:frame]; + _toView.frame = frame; }]; - } completion:^(BOOL finished) { - [transitionContext completeTransition:([transitionContext transitionWasCancelled] == NO)]; + } completion:^(BOOL finished __unused) { + [self _completeTransition]; }]; } -- (void)executeReverseAnimation:(id< UIViewControllerContextTransitioning >)transitionContext fromVC:(UIViewController*)fromVC toVC:(UIViewController*)toVC fromView:(UIView*)fromView toView:(UIView*)toView { - UIView* containerView = [transitionContext containerView]; - CGRect frame = [transitionContext initialFrameForViewController:fromVC]; - [toView setFrame:frame]; - [[toView layer] setTransform:CATransform3DScale(CATransform3DIdentity, 0.6f, 0.6f, 1.0f)]; - [toView setAlpha:0.6f]; - [containerView insertSubview:toView belowSubview:fromView]; +- (void)_startTransitionReverse { + CGRect frame = _initialFrameFromViewController; + _toView.frame = frame; + _toView.layer.transform = CATransform3DScale(CATransform3DIdentity, 0.6f, 0.6f, 1.0f); + _toView.alpha = 0.6f; + [_containerView insertSubview:_toView belowSubview:_fromView]; CGRect frameOffScreen = frame; frameOffScreen.origin.y = frame.size.height; - CATransform3D t1 = [self firstTransform]; - [UIView animateKeyframesWithDuration:[self transitionDuration:transitionContext] + CATransform3D t1 = [self _firstTransform]; + [UIView animateKeyframesWithDuration:_duration delay:0.0f options:UIViewKeyframeAnimationOptionCalculationModeCubic animations:^{ [UIView addKeyframeWithRelativeStartTime:0.0f relativeDuration:0.5f animations:^{ - [fromView setFrame:frameOffScreen]; + _fromView.frame = frameOffScreen; }]; [UIView addKeyframeWithRelativeStartTime:0.35f relativeDuration:0.35f animations:^{ - [[toView layer] setTransform:t1]; - [toView setAlpha:1.0f]; + _toView.layer.transform = t1; + _toView.alpha = 1.0f; }]; [UIView addKeyframeWithRelativeStartTime:0.75f relativeDuration:0.25f animations:^{ - [[toView layer] setTransform:CATransform3DIdentity]; + _toView.layer.transform = CATransform3DIdentity; }]; - } completion:^(BOOL finished) { - if([transitionContext transitionWasCancelled] == YES) { - [[toView layer] setTransform:CATransform3DIdentity]; - [toView setAlpha:1.0f]; + } completion:^(BOOL finished __unused) { + if([self isCancelled] == YES) { + _toView.layer.transform = CATransform3DIdentity; + _toView.alpha = 1.0f; } - [transitionContext completeTransition:([transitionContext transitionWasCancelled] == NO)]; + [self _completeTransition]; }]; } -- (CATransform3D)firstTransform { +- (CATransform3D)_firstTransform { CATransform3D t1 = CATransform3DIdentity; t1.m34 = 1.0f / -900.0f; t1 = CATransform3DScale(t1, 0.95f, 0.95f, 1.0f); @@ -120,8 +139,8 @@ - (CATransform3D)firstTransform { return t1; } -- (CATransform3D)secondTransformWithView:(UIView*)view { - CATransform3D t1 = [self firstTransform]; +- (CATransform3D)_secondTransformWithView:(UIView*)view { + CATransform3D t1 = [self _firstTransform]; CATransform3D t2 = CATransform3DIdentity; t2.m34 = t1.m34; t2 = CATransform3DTranslate(t2, 0.0f, view.frame.size.height * -0.08f, 0.0f); diff --git a/Sources/MobilyCore/MobilyTransitionControllerCrossFade.m b/Sources/MobilyCore/MobilyTransitionControllerCrossFade.m new file mode 100644 index 0000000..c62139b --- /dev/null +++ b/Sources/MobilyCore/MobilyTransitionControllerCrossFade.m @@ -0,0 +1,118 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyTransitionControllerCrossFade + +#pragma mark Transition + +- (void)_startTransition { + [_containerView addSubview:_toView]; + [_containerView sendSubviewToBack:_toView]; + + [UIView animateWithDuration:_duration + delay:0.0f + options:UIViewAnimationOptionBeginFromCurrentState + animations:^{ + _fromView.alpha = 0.0f; + } completion:^(BOOL finished __unused) { + if([self isCancelled] == YES) { + _fromView.alpha = 1.0; + } else { + [_fromView removeFromSuperview]; + _fromView.alpha = 1.0f; + } + [self _completeTransition]; + }]; +} + +#pragma mark Interactive + +- (void)_startInteractive { + [super _startInteractive]; + + [_containerView addSubview:_toView]; + [_containerView sendSubviewToBack:_toView]; +} + +- (void)_updateInteractive:(CGFloat)percentComplete { + [super _updateInteractive:percentComplete]; + + _fromView.alpha = 1.0f - percentComplete; + _toView.alpha = percentComplete; +} + +- (void)_finishInteractive { + [super _finishInteractive]; + + [UIView animateWithDuration:_duration * _percentComplete + delay:0.0f + options:UIViewAnimationOptionBeginFromCurrentState + animations:^{ + _fromView.alpha = 0.0f; + _toView.alpha = 1.0f; + } completion:^(BOOL finished __unused) { + _fromView.alpha = 1.0f; + _toView.alpha = 1.0f; + [_fromView removeFromSuperview]; + [self _completeInteractive]; + }]; +} + +- (void)_cancelInteractive { + [super _cancelInteractive]; + + [UIView animateWithDuration:_duration * (1.0f - _percentComplete) + delay:0.0f + options:UIViewAnimationOptionBeginFromCurrentState + animations:^{ + _fromView.alpha = 1.0f; + _toView.alpha = 0.0f; + } completion:^(BOOL finished __unused) { + _fromView.alpha = 1.0f; + _toView.alpha = 1.0f; + [_toView removeFromSuperview]; + [self _completeInteractive]; + }]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyTransitionControllerSlide.m b/Sources/MobilyCore/MobilyTransitionControllerSlide.m new file mode 100644 index 0000000..7465a36 --- /dev/null +++ b/Sources/MobilyCore/MobilyTransitionControllerSlide.m @@ -0,0 +1,201 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@implementation MobilyTransitionControllerSlide + +#pragma mark Init / Free + +- (instancetype)initWithRatio:(CGFloat)ratio { + self = [super init]; + if(self != nil) { + _ratio = MAX(0.0f, MIN(ratio, 1.0f)); + } + return self; +} + +- (void)setup { + [super setup]; + + _ratio = 1.0f; +} + +#pragma mark Private override + +- (void)_prepareTransitionContext { + [super _prepareTransitionContext]; + + CGRect containerFrame = _containerView.frame; + switch(_operation) { + case MobilyTransitionOperationPresent: + case MobilyTransitionOperationPush: { + if(CGRectIsEmpty(_initialFrameFromViewController) == YES) { + _initialFrameFromViewController = containerFrame; + } + if(CGRectIsEmpty(_finalFrameFromViewController) == YES) { + if(CGRectIsEmpty(_finalFrameToViewController) == NO) { + _finalFrameFromViewController = CGRectMake(_initialFrameFromViewController.origin.x - _initialFrameFromViewController.size.width, _initialFrameFromViewController.origin.y, _initialFrameFromViewController.size.width, _initialFrameFromViewController.size.height); + } else { + _finalFrameFromViewController = CGRectMake(containerFrame.origin.x - containerFrame.size.width, containerFrame.origin.y, containerFrame.size.width, containerFrame.size.height); + } + } + if(CGRectIsEmpty(_initialFrameToViewController) == YES) { + if(CGRectIsEmpty(_finalFrameToViewController) == NO) { + _initialFrameToViewController = CGRectMake(_finalFrameToViewController.origin.x + (_finalFrameToViewController.size.width * _ratio), _finalFrameToViewController.origin.y, _finalFrameToViewController.size.width, _finalFrameToViewController.size.height); + } else { + _initialFrameToViewController = CGRectMake(containerFrame.origin.x + (containerFrame.size.width * _ratio), containerFrame.origin.y, containerFrame.size.width, containerFrame.size.height); + } + } + if(CGRectIsEmpty(_finalFrameToViewController) == YES) { + _finalFrameToViewController = containerFrame; + } + break; + } + case MobilyTransitionOperationDismiss: + case MobilyTransitionOperationPop: { + if(CGRectIsEmpty(_initialFrameFromViewController) == YES) { + _initialFrameFromViewController = containerFrame; + } + if(CGRectIsEmpty(_finalFrameFromViewController) == YES) { + if(CGRectIsEmpty(_finalFrameToViewController) == NO) { + _finalFrameFromViewController = CGRectMake(_initialFrameFromViewController.origin.x + _initialFrameFromViewController.size.width, _initialFrameFromViewController.origin.y, _initialFrameFromViewController.size.width, _initialFrameFromViewController.size.height); + } else { + _finalFrameFromViewController = CGRectMake(containerFrame.origin.x + containerFrame.size.width, containerFrame.origin.y, containerFrame.size.width, containerFrame.size.height); + } + } + if(CGRectIsEmpty(_initialFrameToViewController) == YES) { + if(CGRectIsEmpty(_finalFrameToViewController) == NO) { + _initialFrameToViewController = CGRectMake(_finalFrameToViewController.origin.x - (_finalFrameToViewController.size.width * _ratio), _finalFrameToViewController.origin.y, _finalFrameToViewController.size.width, _finalFrameToViewController.size.height); + } else { + _initialFrameToViewController = CGRectMake(containerFrame.origin.x - (containerFrame.size.width * _ratio), containerFrame.origin.y, containerFrame.size.width, containerFrame.size.height); + } + } + if(CGRectIsEmpty(_finalFrameToViewController) == YES) { + _finalFrameToViewController = containerFrame; + } + break; + } + } +} + +#pragma mark Transition + +- (void)_startTransition { + _fromView.frame = _initialFrameFromViewController; + _toView.frame = _initialFrameToViewController; + + [_containerView addSubview:_toView]; + [_containerView sendSubviewToBack:_toView]; + + [UIView animateWithDuration:_duration + delay:0.0f + options:UIViewAnimationOptionBeginFromCurrentState + animations:^{ + _fromView.frame = _finalFrameFromViewController; + _toView.frame = _finalFrameToViewController; + } completion:^(BOOL finished __unused) { + if([self isCancelled] == YES) { + _fromView.frame = _initialFrameFromViewController; + _toView.frame = _initialFrameToViewController; + } else { + _fromView.frame = _finalFrameFromViewController; + _toView.frame = _finalFrameToViewController; + [_fromView removeFromSuperview]; + } + [self _completeTransition]; + }]; +} + +#pragma mark Interactive + +- (void)_startInteractive { + [super _startInteractive]; + + _fromView.frame = _initialFrameFromViewController; + _toView.frame = _initialFrameToViewController; + + [_containerView addSubview:_toView]; + [_containerView sendSubviewToBack:_toView]; +} + +- (void)_updateInteractive:(CGFloat)percentComplete { + [super _updateInteractive:percentComplete]; + + _fromView.frame = MobilyRectLerp(_initialFrameFromViewController, _finalFrameFromViewController, percentComplete); + _toView.frame = MobilyRectLerp(_initialFrameToViewController, _finalFrameToViewController, percentComplete); +} + +- (void)_finishInteractive { + [super _finishInteractive]; + + [UIView animateWithDuration:_duration * _percentComplete + delay:0.0f + options:UIViewAnimationOptionBeginFromCurrentState + animations:^{ + _fromView.frame = _finalFrameFromViewController; + _toView.frame = _finalFrameToViewController; + } completion:^(BOOL finished __unused) { + _fromView.frame = _finalFrameFromViewController; + _toView.frame = _finalFrameToViewController; + [_fromView removeFromSuperview]; + [self _completeInteractive]; + }]; +} + +- (void)_cancelInteractive { + [super _cancelInteractive]; + + [UIView animateWithDuration:_duration * (1.0f - _percentComplete) + delay:0.0f + options:UIViewAnimationOptionBeginFromCurrentState + animations:^{ + _fromView.frame = _initialFrameFromViewController; + _toView.frame = _initialFrameToViewController; + } completion:^(BOOL finished __unused) { + _fromView.frame = _initialFrameFromViewController; + _toView.frame = _initialFrameToViewController; + [_toView removeFromSuperview]; + [self _completeInteractive]; + }]; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyUI.h b/Sources/MobilyCore/MobilyUI.h new file mode 100644 index 0000000..706ffbe --- /dev/null +++ b/Sources/MobilyCore/MobilyUI.h @@ -0,0 +1,652 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import +#import + +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +typedef NS_OPTIONS(NSUInteger, MobilyVerticalAlignment) { + MobilyVerticalAlignmentTop, + MobilyVerticalAlignmentCenter, + MobilyVerticalAlignmentBottom +}; + +typedef NS_OPTIONS(NSUInteger, MobilyHorizontalAlignment) { + MobilyHorizontalAlignmentLeft, + MobilyHorizontalAlignmentCenter, + MobilyHorizontalAlignmentRight +}; + +/*--------------------------------------------------*/ + +@interface NSString (MobilyUI) + +- (CGSize)moImplicitSizeWithFont:(UIFont*)font lineBreakMode:(NSLineBreakMode)lineBreakMode; +- (CGSize)moImplicitSizeWithFont:(UIFont*)font forWidth:(CGFloat)width lineBreakMode:(NSLineBreakMode)lineBreakMode; +- (CGSize)moImplicitSizeWithFont:(UIFont*)font forSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode; + +- (UIEdgeInsets)moConvertToEdgeInsets; +- (UIEdgeInsets)moConvertToEdgeInsetsSeparated:(NSString*)separated; + +- (UIBezierPath*)moConvertToBezierPath; +- (UIBezierPath*)moConvertToBezierPathSeparated:(NSString*)separated; + +- (UIFont*)moConvertToFont; +- (UIFont*)moConvertToFontSeparated:(NSString*)separated; +- (UIImage*)moConvertToImage; +- (UIImage*)moConvertToImageSeparated:(NSString*)separated edgeInsetsSeparated:(NSString*)edgeInsetsSeparated; +- (NSArray*)moConvertToImages; +- (NSArray*)moConvertToImagesSeparated:(NSString*)separated edgeInsetsSeparated:(NSString*)edgeInsetsSeparated frameSeparated:(NSString*)frameSeparated; + +- (UIRemoteNotificationType)moConvertToRemoteNotificationType; +- (UIRemoteNotificationType)moConvertToRemoteNotificationTypeSeparated:(NSString*)separated; +- (UIInterfaceOrientationMask)moConvertToInterfaceOrientationMask; +- (UIInterfaceOrientationMask)moConvertToInterfaceOrientationMaskSeparated:(NSString*)separated; + +- (UIStatusBarStyle)moConvertToStatusBarStyle; +- (UIStatusBarAnimation)moConvertToStatusBarAnimation; + +- (UIViewAutoresizing)moConvertToViewAutoresizing; +- (UIViewAutoresizing)moConvertToViewAutoresizingSeparated:(NSString*)separated; +- (UIViewContentMode)moConvertToViewContentMode; +- (UIControlContentHorizontalAlignment)moConvertToControlContentHorizontalAlignment; +- (UIControlContentVerticalAlignment)moConvertToControlContentVerticalAlignment; +- (UITextAutocapitalizationType)moConvertToTextAutocapitalizationType; +- (UITextAutocorrectionType)moConvertToTextAutocorrectionType; +- (UITextSpellCheckingType)moConvertToTestSpellCheckingType; +- (UIKeyboardType)moConvertToKeyboardType; +- (UIReturnKeyType)moConvertToReturnKeyType; +- (UIBaselineAdjustment)moConvertToBaselineAdjustment; + +- (UIScrollViewIndicatorStyle)moConvertToScrollViewIndicatorStyle; +- (UIScrollViewKeyboardDismissMode)moConvertToScrollViewKeyboardDismissMode; +- (UIBarStyle)moConvertToBarStyle; +- (UITabBarItemPositioning)moConvertToTabBarItemPositioning; +- (UISearchBarStyle)moConvertToSearchBarStyle; +- (UIProgressViewStyle)moConvertToProgressViewStyle; +- (UITextBorderStyle)moConvertToTextBorderStyle; + +- (void)moDrawAtPoint:(CGPoint)point font:(UIFont*)font color:(UIColor*)color vAlignment:(MobilyVerticalAlignment)vAlignment hAlignment:(MobilyHorizontalAlignment)hAlignment lineBreakMode:(NSLineBreakMode)lineBreakMode; +- (void)moDrawInRect:(CGRect)rect font:(UIFont*)font color:(UIColor*)color vAlignment:(MobilyVerticalAlignment)vAlignment hAlignment:(MobilyHorizontalAlignment)hAlignment lineBreakMode:(NSLineBreakMode)lineBreakMode; + +@end + +/*--------------------------------------------------*/ +/* BASE */ +/*--------------------------------------------------*/ + +#define MOBILY_COLOR_RGB(R, G, B) [UIColor colorWithRed:(R) / 255.0f green:(G) / 255.0f blue:(B) / 255.0f alpha:1.0f] +#define MOBILY_COLOR_RGBA(R, G, B, A) [UIColor colorWithRed:(R) / 255.0f green:(G) / 255.0f blue:(B) / 255.0f alpha:(A) / 255.0f] + +/*--------------------------------------------------*/ + +typedef struct { + CGFloat hue; + CGFloat saturation; + CGFloat brightness; +} MobilyColorHSB; + +/*--------------------------------------------------*/ + +BOOL MobilyColorHSBEqualToColorHSB(MobilyColorHSB color1, MobilyColorHSB color2); + +/*--------------------------------------------------*/ + +@interface UIColor (MobilyUI) + ++ (UIColor*)moColorWithString:(NSString*)string; ++ (CGFloat)moColorComponentFromString:(NSString*)string start:(NSUInteger)start length:(NSUInteger)length; + +- (UIColor*)moMultiplyColor:(UIColor*)color percent:(CGFloat)percent; +- (UIColor*)moMultiplyBrightness:(CGFloat)brightness; + +-(MobilyColorHSB)moHsb; + +@end + +/*--------------------------------------------------*/ + +typedef NS_OPTIONS(NSUInteger, MobilyImageAlignment) { + MobilyImageAlignmentStretch, + MobilyImageAlignmentAspectFill, + MobilyImageAlignmentAspectFit +}; + +/*--------------------------------------------------*/ + +@interface UIImage (MobilyUI) + ++ (UIImage*)moImageNamed:(NSString*)name capInsets:(UIEdgeInsets)capInsets; ++ (UIImage*)moImageWithColor:(UIColor*)color size:(CGSize)size; + +- (UIImage*)moUnrotate; +- (UIImage*)moScaleToSize:(CGSize)size; +- (UIImage*)moRotateToAngleInRadians:(CGFloat)angleInRadians; + +- (UIImage*)moGrayscale; +- (UIImage*)moBlackAndWhite; +- (UIImage*)moInvertColors; + +- (UIImage*)moBlurredImageWithRadius:(CGFloat)radius iterations:(NSUInteger)iterations tintColor:(UIColor*)tintColor; + +- (void)moDrawInRect:(CGRect)rect alignment:(MobilyImageAlignment)alignment; +- (void)moDrawInRect:(CGRect)rect alignment:(MobilyImageAlignment)alignment blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha; +- (void)moDrawInRect:(CGRect)rect alignment:(MobilyImageAlignment)alignment radius:(CGFloat)radius; +- (void)moDrawInRect:(CGRect)rect alignment:(MobilyImageAlignment)alignment radius:(CGFloat)radius blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha; +- (void)moDrawInRect:(CGRect)rect alignment:(MobilyImageAlignment)alignment corners:(UIRectCorner)corners radius:(CGFloat)radius; +- (void)moDrawInRect:(CGRect)rect alignment:(MobilyImageAlignment)alignment corners:(UIRectCorner)corners radius:(CGFloat)radius blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha; + +@end + +/*--------------------------------------------------*/ + +typedef NS_OPTIONS(NSUInteger, MobilyBezierPathSeparatorEdges) { + MobilyBezierPathSeparatorEdgeTop = 1 << 0, + MobilyBezierPathSeparatorEdgeRight = 1 << 1, + MobilyBezierPathSeparatorEdgeBottom = 1 << 2, + MobilyBezierPathSeparatorEdgeLeft = 1 << 3, + MobilyBezierPathSeparatorEdgeAll = (MobilyBezierPathSeparatorEdgeTop | MobilyBezierPathSeparatorEdgeLeft | MobilyBezierPathSeparatorEdgeBottom | MobilyBezierPathSeparatorEdgeRight) +}; + +/*--------------------------------------------------*/ + +@interface UIBezierPath (MobilyUI) + ++ (void)moDrawRect:(CGRect)rect fillColor:(UIColor*)fillColor; ++ (void)moDrawRect:(CGRect)rect fillColor:(UIColor*)fillColor strokeColor:(UIColor*)strokeColor strokeWidth:(CGFloat)strokeWidth; + ++ (void)moDrawOvalInRect:(CGRect)rect fillColor:(UIColor*)fillColor; ++ (void)moDrawOvalInRect:(CGRect)rect fillColor:(UIColor*)fillColor strokeColor:(UIColor*)strokeColor strokeWidth:(CGFloat)strokeWidth; + ++ (void)moDrawRoundedRect:(CGRect)rect radius:(CGFloat)radius fillColor:(UIColor*)fillColor; ++ (void)moDrawRoundedRect:(CGRect)rect radius:(CGFloat)radius fillColor:(UIColor*)fillColor strokeColor:(UIColor*)strokeColor strokeWidth:(CGFloat)strokeWidth; + ++ (void)moDrawRoundedRect:(CGRect)rect corners:(UIRectCorner)corners radius:(CGSize)radius fillColor:(UIColor*)fillColor; ++ (void)moDrawRoundedRect:(CGRect)rect corners:(UIRectCorner)corners radius:(CGSize)radius fillColor:(UIColor*)fillColor strokeColor:(UIColor*)strokeColor strokeWidth:(CGFloat)strokeWidth; + ++ (void)moDrawSeparatorRect:(CGRect)rect edges:(MobilyBezierPathSeparatorEdges)edges width:(CGFloat)width fillColor:(UIColor*)fillColor; ++ (void)moDrawSeparatorRect:(CGRect)rect edges:(MobilyBezierPathSeparatorEdges)edges width:(CGFloat)width edgeInsets:(UIEdgeInsets)edgeInsets fillColor:(UIColor*)fillColor; ++ (void)moDrawSeparatorRect:(CGRect)rect edges:(MobilyBezierPathSeparatorEdges)edges widthEdges:(UIEdgeInsets)widthEdges edgeInsets:(UIEdgeInsets)edgeInsets fillColor:(UIColor*)fillColor; + +@end + +/*--------------------------------------------------*/ + +@interface UINib (MobilyUI) + ++ (id)moViewWithNibName:(NSString*)nibName withClass:(Class)aClass; ++ (id)moViewWithNibName:(NSString*)nibName withClass:(Class)aClass withOwner:(id)owner; + ++ (UINib*)moNibWithBaseName:(NSString*)baseName bundle:(NSBundle*)bundle; ++ (UINib*)moNibWithClass:(Class)aClass bundle:(NSBundle*)bundle; + +- (id)moInstantiateWithClass:(Class)aClass owner:(id)owner options:(NSDictionary*)options; + +@end + +/*--------------------------------------------------*/ + +@interface UIResponder (MobilyUI) + ++ (id)moCurrentFirstResponderInView:(UIView*)view; ++ (id)moCurrentFirstResponder; + ++ (UIResponder*)moPrevResponderFromView:(UIView*)view; ++ (UIResponder*)moNextResponderFromView:(UIView*)view; + +@end + +/*--------------------------------------------------*/ +/* VIEWS */ +/*--------------------------------------------------*/ + +@interface UIWindow (MobilyUI) + +@property(nonatomic, readonly, strong) UIViewController* moCurrentController; + +#ifdef __IPHONE_7_0 + +@property(nonatomic, readonly, strong) UIViewController* moControllerForStatusBarStyle; +@property(nonatomic, readonly, strong) UIViewController* moControllerForStatusBarHidden; + +#endif + +@end + +/*--------------------------------------------------*/ + +@interface UIView (MobilyUI) + +@property(nonatomic, readwrite, assign) CGPoint moFramePosition; +@property(nonatomic, readwrite, assign) CGPoint moFrameCenter; +@property(nonatomic, readwrite, assign) CGSize moFrameSize; +@property(nonatomic, readwrite, assign) CGFloat moFrameSX; +@property(nonatomic, readwrite, assign) CGFloat moFrameCX; +@property(nonatomic, readwrite, assign) CGFloat moFrameEX; +@property(nonatomic, readwrite, assign) CGFloat moFrameSY; +@property(nonatomic, readwrite, assign) CGFloat moFrameCY; +@property(nonatomic, readwrite, assign) CGFloat moFrameEY; +@property(nonatomic, readwrite, assign) CGFloat moFrameWidth; +@property(nonatomic, readwrite, assign) CGFloat moFrameHeight; +@property(nonatomic, readwrite, assign) CGFloat moFrameLeft; +@property(nonatomic, readwrite, assign) CGFloat moFrameRight; +@property(nonatomic, readwrite, assign) CGFloat moFrameTop; +@property(nonatomic, readwrite, assign) CGFloat moFrameBottom; + +@property(nonatomic, readonly, assign) CGPoint moBoundsPosition; +@property(nonatomic, readonly, assign) CGPoint moBoundsCenter; +@property(nonatomic, readonly, assign) CGSize moBoundsSize; +@property(nonatomic, readonly, assign) CGFloat moBoundsCX; +@property(nonatomic, readonly, assign) CGFloat moBoundsCY; +@property(nonatomic, readonly, assign) CGFloat moBoundsWidth; +@property(nonatomic, readonly, assign) CGFloat moBoundsHeight; + +@property(nonatomic, readwrite, assign) IBInspectable CGFloat moZPosition; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat moCornerRadius; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat moBorderWidth; +@property(nonatomic, readwrite, strong) IBInspectable UIColor* moBorderColor; +@property(nonatomic, readwrite, strong) IBInspectable UIColor* moShadowColor; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat moShadowOpacity; +@property(nonatomic, readwrite, assign) IBInspectable CGSize moShadowOffset; +@property(nonatomic, readwrite, assign) IBInspectable CGFloat moShadowRadius; +@property(nonatomic, readwrite, strong) UIBezierPath* moShadowPath; + +- (NSArray*)moResponders; + +- (BOOL)moIsContainsSubview:(UIView*)subview; + +- (void)moRemoveSubview:(UIView*)subview; + +- (void)moSetSubviews:(NSArray*)subviews; +- (void)moRemoveAllSubviews; + +- (void)moBlinkBackgroundColor:(UIColor*)color duration:(NSTimeInterval)duration timeout:(NSTimeInterval)timeout; + +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation constant:(CGFloat)constant; +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation constant:(CGFloat)constant priority:(UILayoutPriority)priority; +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation constant:(CGFloat)constant priority:(UILayoutPriority)priority multiplier:(CGFloat)multiplier; + +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation attribute:(NSLayoutAttribute)attribute constant:(CGFloat)constant; +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation attribute:(NSLayoutAttribute)attribute constant:(CGFloat)constant priority:(UILayoutPriority)priority; +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation attribute:(NSLayoutAttribute)attribute constant:(CGFloat)constant priority:(UILayoutPriority)priority multiplier:(CGFloat)multiplier; + +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation view:(UIView*)view attribute:(NSLayoutAttribute)attribute constant:(CGFloat)constant; +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation view:(UIView*)view attribute:(NSLayoutAttribute)attribute constant:(CGFloat)constant priority:(UILayoutPriority)priority; +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation view:(UIView*)view attribute:(NSLayoutAttribute)attribute constant:(CGFloat)constant priority:(UILayoutPriority)priority multiplier:(CGFloat)multiplier; + +- (void)moRemoveAllConstraints; + +@end + +/*--------------------------------------------------*/ + +@interface UIScrollView (MobilyUI) + +@property(nonatomic, readwrite, assign) IBInspectable UIEdgeInsets moKeyboardInset; + +@property(nonatomic, readwrite, assign) CGFloat moContentOffsetX; +@property(nonatomic, readwrite, assign) CGFloat moContentOffsetY; +@property(nonatomic, readwrite, assign) CGFloat moContentSizeWidth; +@property(nonatomic, readwrite, assign) CGFloat moContentSizeHeight; +@property(nonatomic, readwrite, assign) CGFloat moContentInsetTop; +@property(nonatomic, readwrite, assign) CGFloat moContentInsetRight; +@property(nonatomic, readwrite, assign) CGFloat moContentInsetBottom; +@property(nonatomic, readwrite, assign) CGFloat moContentInsetLeft; +@property(nonatomic, readwrite, assign) CGFloat moScrollIndicatorInsetTop; +@property(nonatomic, readwrite, assign) CGFloat moScrollIndicatorInsetRight; +@property(nonatomic, readwrite, assign) CGFloat moScrollIndicatorInsetBottom; +@property(nonatomic, readwrite, assign) CGFloat moScrollIndicatorInsetLeft; +@property(nonatomic, readonly, assign) CGRect moVisibleBounds; + +- (void)setMoContentOffsetX:(CGFloat)moContentOffsetX animated:(BOOL)animated; +- (void)setMoContentOffsetY:(CGFloat)moContentOffsetY animated:(BOOL)animated; + +- (void)moRegisterAdjustmentResponder; +- (void)moUnregisterAdjustmentResponder; + +@end + +/*--------------------------------------------------*/ + +@interface UITabBar (MobilyUI) + +@property(nonatomic, readwrite, assign) NSUInteger moSelectedItemIndex; + +@end + +/*--------------------------------------------------*/ + +@interface UINavigationBar (MobilyUI) + + + +@end + +/*--------------------------------------------------*/ + +@interface UILabel (MobilyUI) + +- (CGSize)moImplicitSize; +- (CGSize)moImplicitSizeForWidth:(CGFloat)width; +- (CGSize)moImplicitSizeForSize:(CGSize)size; + +@end + +/*--------------------------------------------------*/ + +@interface UIButton (MobilyUI) + +@property(nonatomic, readwrite, strong) NSString* moNormalTitle; +@property(nonatomic, readwrite, strong) UIColor* moNormalTitleColor; +@property(nonatomic, readwrite, strong) UIColor* moNormalTitleShadowColor; +@property(nonatomic, readwrite, strong) UIImage* moNormalImage; +@property(nonatomic, readwrite, strong) UIImage* moNormalBackgroundImage; + +@property(nonatomic, readwrite, strong) NSString* moHighlightedTitle; +@property(nonatomic, readwrite, strong) UIColor* moHighlightedTitleColor; +@property(nonatomic, readwrite, strong) UIColor* moHighlightedTitleShadowColor; +@property(nonatomic, readwrite, strong) UIImage* moHighlightedImage; +@property(nonatomic, readwrite, strong) UIImage* moHighlightedBackgroundImage; + +@property(nonatomic, readwrite, strong) NSString* moSelectedTitle; +@property(nonatomic, readwrite, strong) UIColor* moSelectedTitleColor; +@property(nonatomic, readwrite, strong) UIColor* moSelectedTitleShadowColor; +@property(nonatomic, readwrite, strong) UIImage* moSelectedImage; +@property(nonatomic, readwrite, strong) UIImage* moSelectedBackgroundImage; + +@property(nonatomic, readwrite, strong) NSString* moDisabledTitle; +@property(nonatomic, readwrite, strong) UIColor* moDisabledTitleColor; +@property(nonatomic, readwrite, strong) UIColor* moDisabledTitleShadowColor; +@property(nonatomic, readwrite, strong) UIImage* moDisabledImage; +@property(nonatomic, readwrite, strong) UIImage* moDisabledBackgroundImage; + +@end + +/*--------------------------------------------------*/ +/* CONTROLLERS */ +/*--------------------------------------------------*/ + +@interface UIViewController (MobilyUI) + +- (void)moLoadViewIfNeed; +- (void)moUnloadViewIfPossible; +- (void)moUnloadView; + +- (UIViewController*)moCurrentController; + +@end + +/*--------------------------------------------------*/ + +@interface UINavigationController (MobilyUI) + +@property(nonatomic, readwrite, assign) BOOL moTranslucent NS_AVAILABLE_IOS(3_0); +@property(nonatomic, readwrite, retain) UIColor* moTintColor; +@property(nonatomic, readwrite, retain) UIColor* moBarTintColor NS_AVAILABLE_IOS(7_0); +@property(nonatomic, readwrite, retain) UIImage* moShadowImage NS_AVAILABLE_IOS(6_0); +@property(nonatomic, readwrite, copy) NSDictionary* moTitleTextAttributes NS_AVAILABLE_IOS(5_0); +@property(nonatomic, readwrite, retain) UIImage* moBackIndicatorImage NS_AVAILABLE_IOS(7_0); +@property(nonatomic, readwrite, retain) UIImage* moBackIndicatorTransitionMaskImage NS_AVAILABLE_IOS(7_0); + +- (UIViewController*)moRootController; + +@end + +/*--------------------------------------------------*/ + +@class MobilyImageView; + +/*--------------------------------------------------*/ + +@interface UINavigationItem (MobilyUI) + +- (UIBarButtonItem*)moAddLeftBarFixedSpace:(CGFloat)fixedSpaceWidth animated:(BOOL)animated; +- (UIBarButtonItem*)moAddRightBarFixedSpace:(CGFloat)fixedSpaceWidth animated:(BOOL)animated; + +- (MobilyImageView*)moAddLeftBarImageUrl:(NSURL*)imageUrl defaultImage:(UIImage*)defaultImage target:(id)target action:(SEL)action animated:(BOOL)animated; +- (MobilyImageView*)moAddRightBarImageUrl:(NSURL*)imageUrl defaultImage:(UIImage*)defaultImage target:(id)target action:(SEL)action animated:(BOOL)animated; + +- (UIButton*)moAddLeftBarButtonNormalImage:(UIImage*)normalImage target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddLeftBarButtonNormalImage:(UIImage*)normalImage highlightedImage:(UIImage*)highlightedImage target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddLeftBarButtonNormalImage:(UIImage*)normalImage highlightedImage:(UIImage*)highlightedImage disabledImage:(UIImage*)disabledImage target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddLeftBarButtonNormalImage:(UIImage*)normalImage highlightedImage:(UIImage*)highlightedImage selectedImage:(UIImage*)selectedImage disabledImage:(UIImage*)disabledImage target:(id)target action:(SEL)action animated:(BOOL)animated; + +- (UIButton*)moAddRightBarButtonNormalImage:(UIImage*)normalImage target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddRightBarButtonNormalImage:(UIImage*)normalImage highlightedImage:(UIImage*)highlightedImage target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddRightBarButtonNormalImage:(UIImage*)normalImage highlightedImage:(UIImage*)highlightedImage disabledImage:(UIImage*)disabledImage target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddRightBarButtonNormalImage:(UIImage*)normalImage highlightedImage:(UIImage*)highlightedImage selectedImage:(UIImage*)selectedImage disabledImage:(UIImage*)disabledImage target:(id)target action:(SEL)action animated:(BOOL)animated; + +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle normalTitleColor:(UIColor*)normatTitleColor target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle normalTitleColor:(UIColor*)normatTitleColor font:(UIFont*)font target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle normalTitleColor:(UIColor*)normatTitleColor font:(UIFont*)font frame:(CGRect)frame target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle highlightedTitle:(NSString*)highlightedTitle target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle highlightedTitle:(NSString*)highlightedTitle disabledTitle:(NSString*)disabledTitle target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle highlightedTitle:(NSString*)highlightedTitle selectedTitle:(NSString*)selectedTitle disabledTitle:(NSString*)disabledTitle target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle + highlightedTitle:(NSString*)highlightedTitle + selectedTitle:(NSString*)selectedTitle + disabledTitle:(NSString*)disabledTitle + normalTitleColor:(UIColor*)normatTitleColor + highlightedTitleColor:(UIColor*)highlightedTitleColor + selectedTitleColor:(UIColor*)selectedTitleColor + disabledTitleColor:(UIColor*)disabledTitleColor + font:(UIFont*)font + frame:(CGRect)frame + target:(id)target + action:(SEL)action + animated:(BOOL)animated; + +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle normalTitleColor:(UIColor*)normatTitleColor target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle normalTitleColor:(UIColor*)normatTitleColor font:(UIFont*)font target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle normalTitleColor:(UIColor*)normatTitleColor font:(UIFont*)font frame:(CGRect)frame target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle highlightedTitle:(NSString*)highlightedTitle target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle highlightedTitle:(NSString*)highlightedTitle disabledTitle:(NSString*)disabledTitle target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle highlightedTitle:(NSString*)highlightedTitle selectedTitle:(NSString*)selectedTitle disabledTitle:(NSString*)disabledTitle target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle + highlightedTitle:(NSString*)highlightedTitle + selectedTitle:(NSString*)selectedTitle + disabledTitle:(NSString*)disabledTitle + normalTitleColor:(UIColor*)normatTitleColor + highlightedTitleColor:(UIColor*)highlightedTitleColor + selectedTitleColor:(UIColor*)selectedTitleColor + disabledTitleColor:(UIColor*)disabledTitleColor + font:(UIFont*)font + frame:(CGRect)frame + target:(id)target + action:(SEL)action + animated:(BOOL)animated; + +- (UIBarButtonItem*)moAddLeftBarView:(UIView*)view animated:(BOOL)animated; +- (UIBarButtonItem*)moAddRightBarView:(UIView*)view animated:(BOOL)animated; +- (UIBarButtonItem*)moAddLeftBarView:(UIView*)view target:(id)target action:(SEL)action animated:(BOOL)animated; +- (UIBarButtonItem*)moAddRightBarView:(UIView*)view target:(id)target action:(SEL)action animated:(BOOL)animated; +- (void)moAddLeftBarButtonItem:(UIBarButtonItem*)barButtonItem animated:(BOOL)animated; +- (void)moAddRightBarButtonItem:(UIBarButtonItem*)barButtonItem animated:(BOOL)animated; +- (void)moRemoveLeftBarButtonItem:(UIBarButtonItem*)barButtonItem animated:(BOOL)animated; +- (void)moRemoveRightBarButtonItem:(UIBarButtonItem*)barButtonItem animated:(BOOL)animated; +- (void)moRemoveAllLeftBarButtonItemsAnimated:(BOOL)animated; +- (void)moRemoveAllRightBarButtonItemsAnimated:(BOOL)animated; + +- (void)moSetLeftBarAutomaticAlignmentAnimated:(BOOL)animated; +- (void)moSetRightBarAutomaticAlignmentAnimated:(BOOL)animated; + +@end + +/*--------------------------------------------------*/ +/* OTHER */ +/*--------------------------------------------------*/ + +typedef NS_ENUM(NSInteger, MobilyDeviceFamily) { + MobilyDeviceFamilyUnknown = 0, + MobilyDeviceFamilyPhone, + MobilyDeviceFamilyPad, + MobilyDeviceFamilyPod, + MobilyDeviceFamilySimulator, +}; + +typedef NS_ENUM(NSInteger, MobilyDeviceModel) { + MobilyDeviceModelUnknown = 0, + MobilyDeviceModelSimulatorPhone, + MobilyDeviceModelSimulatorPad, + MobilyDeviceModelPhone1, + MobilyDeviceModelPhone3G, + MobilyDeviceModelPhone3GS, + MobilyDeviceModelPhone4, + MobilyDeviceModelPhone4S, + MobilyDeviceModelPhone5, + MobilyDeviceModelPhone5C, + MobilyDeviceModelPhone5S, + MobilyDeviceModelPhone6, + MobilyDeviceModelPhone6Plus, + MobilyDeviceModelPad1, + MobilyDeviceModelPad2, + MobilyDeviceModelPad3, + MobilyDeviceModelPad4, + MobilyDeviceModelPadMini1, + MobilyDeviceModelPadMini2, + MobilyDeviceModelPadMini3, + MobilyDeviceModelPadAir1, + MobilyDeviceModelPadAir2, + MobilyDeviceModelPod1, + MobilyDeviceModelPod2, + MobilyDeviceModelPod3, + MobilyDeviceModelPod4, + MobilyDeviceModelPod5, +}; + +typedef NS_ENUM(NSInteger, MobilyDeviceDisplay) { + MobilyDeviceDisplayUnknown = 0, + MobilyDeviceDisplayPad, + MobilyDeviceDisplayPhone35Inch, + MobilyDeviceDisplayPhone4Inch, + MobilyDeviceDisplayPhone47Inch, + MobilyDeviceDisplayPhone55Inch, +}; + +/*--------------------------------------------------*/ + +@interface UIDevice (MobilyUI) + ++ (CGFloat)moSystemVersion; + ++ (BOOL)moIsSimulator; ++ (BOOL)moIsIPhone; ++ (BOOL)moIsIPad; + ++ (NSString*)moDeviceTypeString; ++ (NSString*)moDeviceVersionString; + ++ (MobilyDeviceFamily)moFamily; ++ (MobilyDeviceModel)moModel; ++ (MobilyDeviceDisplay)moDisplay; + +@end + +/*--------------------------------------------------*/ + +#define MOBILY_DEFINE_VALIDATE_STRING(name) \ +- (id)validate##name:(id)value { \ + if([value isKindOfClass:NSString.class] == YES) { \ + return value; \ + } \ + return nil; \ +} + +/*--------------------------------------------------*/ + +#define MOBILY_DEFINE_VALIDATE_STRING_BASED(name, resultClass, convertValue) \ +- (id)validate##name:(id)value { \ + if([value isKindOfClass:NSString.class] == YES) { \ + value = convertValue; \ + } \ + if([value isKindOfClass:resultClass.class] == YES) { \ + return value; \ + } \ + return nil; \ +} + +#define MOBILY_DEFINE_VALIDATE_BOOL(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithBool:[value moConvertToBool]]) +#define MOBILY_DEFINE_VALIDATE_NUMBER(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [value moConvertToNumber]) +#define MOBILY_DEFINE_VALIDATE_RECT(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSValue, [NSValue valueWithCGRect:[value moConvertToRect]]) +#define MOBILY_DEFINE_VALIDATE_POINT(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSValue, [NSValue valueWithCGPoint:[value moConvertToPoint]]) +#define MOBILY_DEFINE_VALIDATE_SIZE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSValue, [NSValue valueWithCGSize:[value moConvertToSize]]) +#define MOBILY_DEFINE_VALIDATE_EDGE_INSETS(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSValue, [NSValue valueWithUIEdgeInsets:[value moConvertToEdgeInsets]]) +#define MOBILY_DEFINE_VALIDATE_COLOR(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, UIColor, [UIColor moColorWithString:value]) +#define MOBILY_DEFINE_VALIDATE_BEZIER_PATH(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, UIBezierPath, [value moConvertToBezierPath]) +#define MOBILY_DEFINE_VALIDATE_IMAGE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, UIImage, [value moConvertToImage]) +#define MOBILY_DEFINE_VALIDATE_FONT(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, UIFont, [value moConvertToFont]) +#define MOBILY_DEFINE_VALIDATE_REMOTE_NOTIFICATION_TYPE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToRemoteNotificationType]]) +#define MOBILY_DEFINE_VALIDATE_INTERFACE_ORIENTATION_MASK(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToInterfaceOrientationMask]]) +#define MOBILY_DEFINE_VALIDATE_STATUS_BAR_STYLE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToStatusBarStyle]]) +#define MOBILY_DEFINE_VALIDATE_STATUS_BAR_ANIMATION(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToStatusBarAnimation]]) +#define MOBILY_DEFINE_VALIDATE_AUTORESIZING(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToViewAutoresizing]]) +#define MOBILY_DEFINE_VALIDATE_CONTENT_MODE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToViewContentMode]]) +#define MOBILY_DEFINE_VALIDATE_TEXT_ALIGNMENT(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToTextAlignment]]) +#define MOBILY_DEFINE_VALIDATE_LINE_BREAKMODE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToLineBreakMode]]) +#define MOBILY_DEFINE_VALIDATE_BASELINE_ADJUSTMENT(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToBaselineAdjustment]]) +#define MOBILY_DEFINE_VALIDATE_SCROLL_VIEW_INDICATOR_STYLE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToScrollViewIndicatorStyle]]) +#define MOBILY_DEFINE_VALIDATE_SCROLL_VIEW_KEYBOARD_DISMISS_MODE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToScrollViewKeyboardDismissMode]]) +#define MOBILY_DEFINE_VALIDATE_BAR_STYLE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToBarStyle]]) +#define MOBILY_DEFINE_VALIDATE_TAB_BAR_ITEM_POSITIONING(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToTabBarItemPositioning]]) +#define MOBILY_DEFINE_VALIDATE_SEARCH_BAR_STYLE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToSearchBarStyle]]) +#define MOBILY_DEFINE_VALIDATE_PROGRESS_VIEW_STYLE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToProgressViewStyle]]) +#define MOBILY_DEFINE_VALIDATE_TEXT_BORDER_STYLE(name) MOBILY_DEFINE_VALIDATE_STRING_BASED(name, NSNumber, [NSNumber numberWithUnsignedInt:[value moConvertToTextBorderStyle]]) + +/*--------------------------------------------------*/ + +#define MOBILY_DEFINE_SETTER_LAYOUT_CONSTRAINT(property, field, view, unuseBlock, useBlock) \ +- (void)set##property:(NSLayoutConstraint*)field { \ + if(_##field != field) { \ + if(_##field != nil) { \ + unuseBlock \ + [view removeConstraint:_##field]; \ + } \ + _##field = field; \ + if(_##field != nil) { \ + useBlock \ + [view addConstraint:_##field]; \ + } \ + } \ +} + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyUI.m b/Sources/MobilyCore/MobilyUI.m new file mode 100644 index 0000000..7e2f626 --- /dev/null +++ b/Sources/MobilyCore/MobilyUI.m @@ -0,0 +1,3011 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import +#import + +/*--------------------------------------------------*/ + +#import +#import +#import + +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation NSString (MobilyUI) + +- (CGSize)moImplicitSizeWithFont:(UIFont*)font lineBreakMode:(NSLineBreakMode)lineBreakMode { + return [self moImplicitSizeWithFont:font forSize:CGSizeMake(NSIntegerMax, NSIntegerMax) lineBreakMode:lineBreakMode]; +} + +- (CGSize)moImplicitSizeWithFont:(UIFont*)font forWidth:(CGFloat)width lineBreakMode:(NSLineBreakMode)lineBreakMode { + return [self moImplicitSizeWithFont:font forSize:CGSizeMake(width, NSIntegerMax) lineBreakMode:lineBreakMode]; +} + +- (CGSize)moImplicitSizeWithFont:(UIFont*)font forSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode { +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_0 + if(UIDevice.moSystemVersion >= 7.0) { + NSMutableParagraphStyle* paragraphStyle = [NSMutableParagraphStyle new]; + paragraphStyle.lineBreakMode = lineBreakMode; + NSDictionary* attributes = @{ NSFontAttributeName : font, NSParagraphStyleAttributeName : paragraphStyle }; + CGRect textRect = [self boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil]; + if(textRect.size.height < font.lineHeight) { + textRect.size.height = font.lineHeight; + } + return CGSizeMake(ceilf(textRect.size.width), ceilf(textRect.size.height)); + } +#endif +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + size = [self sizeWithFont:font constrainedToSize:size lineBreakMode:lineBreakMode]; + if(size.height < font.lineHeight) { + size.height = font.lineHeight; + } +#pragma clang diagnostic pop + return CGSizeMake(ceilf(size.width), ceilf(size.height)); +} + +- (UIEdgeInsets)moConvertToEdgeInsets { + return [self moConvertToEdgeInsetsSeparated:@";"]; +} + +- (UIEdgeInsets)moConvertToEdgeInsetsSeparated:(NSString*)separated { + UIEdgeInsets result = UIEdgeInsetsZero; + static NSNumberFormatter* formatter = nil; + if(formatter == nil) { + formatter = [NSNumberFormatter new]; + formatter.numberStyle = NSNumberFormatterDecimalStyle; + } + NSArray* array = [self componentsSeparatedByString:separated]; + switch(array.count) { + case 1: { + result.top = [[formatter numberFromString:array[0]] floatValue]; + result.left = result.bottom = result.right = result.top; + break; + } + case 2: { + result.top = [[formatter numberFromString:array[0]] floatValue]; + result.left = [[formatter numberFromString:array[1]] floatValue]; + result.bottom = result.top; + result.right = result.left; + break; + } + case 4: { + result.top = [[formatter numberFromString:array[0]] floatValue]; + result.left = [[formatter numberFromString:array[1]] floatValue]; + result.bottom = [[formatter numberFromString:array[2]] floatValue]; + result.right = [[formatter numberFromString:array[3]] floatValue]; + break; + } + default: + break; + } + return result; +} + +- (UIBezierPath*)moConvertToBezierPath { + return [self moConvertToBezierPathSeparated:@";"]; +} + +- (UIBezierPath*)moConvertToBezierPathSeparated:(NSString*)separated { + return nil; +} + +- (UIFont*)moConvertToFont { + return [self moConvertToFontSeparated:@";"]; +} + +- (UIFont*)moConvertToFontSeparated:(NSString*)separated { + UIFont* result = nil; + NSArray* array = [self componentsSeparatedByString:separated]; + if(array.count > 0) { + static NSNumberFormatter* formatter = nil; + if(formatter == nil) { + formatter = [NSNumberFormatter new]; + formatter.numberStyle = NSNumberFormatterDecimalStyle; + } + switch(array.count) { + case 1: { + result = [UIFont fontWithName:array[0] size:UIFont.systemFontSize]; + break; + } + case 2: { + result = [UIFont fontWithName:array[0] size:[[formatter numberFromString:array[1]] floatValue]]; + break; + } + default: + break; + } + } + return result; +} + +- (UIImage*)moConvertToImage { + return [self moConvertToImageSeparated:@";" edgeInsetsSeparated:@";"]; +} + +- (UIImage*)moConvertToImageSeparated:(NSString*)separated edgeInsetsSeparated:(NSString*)edgeInsetsSeparated { + UIImage* result = nil; + NSArray* array = [self componentsSeparatedByString:separated]; + switch(array.count) { + case 1: { + result = [UIImage imageNamed:self]; + break; + } + default:{ + NSString* pattern = [NSString stringWithFormat:@"([A-Za-z0-9-_]+)[%@]+\\[([0-9%@ ]*)\\]", separated, edgeInsetsSeparated]; + NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:NULL]; + NSArray* matches = [regex matchesInString:self options:0 range:NSMakeRange(0, self.length)]; + if(matches.count > 0) { + NSTextCheckingResult* match = matches[0]; + if(match.numberOfRanges == 3) { + NSString* imageName = [self substringWithRange:[match rangeAtIndex:1]]; + result = [UIImage imageNamed:imageName]; + if(result != nil) { + UIEdgeInsets edgeInsets = UIEdgeInsetsZero; + NSString* imageInsets = [self substringWithRange:[match rangeAtIndex:2]]; + if(imageInsets != nil) { + [imageInsets moConvertToEdgeInsetsSeparated:edgeInsetsSeparated]; + } + result = [result resizableImageWithCapInsets:edgeInsets]; + } + } + } + break; + } + } + return result; +} + +- (NSArray*)moConvertToImages { + return [self moConvertToImagesSeparated:@";" edgeInsetsSeparated:@";" frameSeparated:@"|"]; +} + +- (NSArray*)moConvertToImagesSeparated:(NSString*)separated edgeInsetsSeparated:(NSString*)edgeInsetsSeparated frameSeparated:(NSString*)frameSeparated { + NSMutableArray* result = NSMutableArray.array; + NSArray* array = [self componentsSeparatedByString:frameSeparated]; + if(array.count > 0) { + for(NSString* frame in array) { + UIImage* image = [frame moConvertToImageSeparated:separated edgeInsetsSeparated:edgeInsetsSeparated]; + if(image != nil) { + [result addObject:image]; + } + } + } + return result; +} + +- (UIRemoteNotificationType)moConvertToRemoteNotificationType { + return [self moConvertToRemoteNotificationTypeSeparated:@"|"]; +} + +- (UIRemoteNotificationType)moConvertToRemoteNotificationTypeSeparated:(NSString*)separated { + UIRemoteNotificationType result = UIRemoteNotificationTypeNone; + NSString* value = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([value isEqualToString:@"all"] == YES) { + result = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeNewsstandContentAvailability; + } else { + NSArray* keys = [value componentsSeparatedByString:separated]; + for(NSString* key in keys) { + NSString* temp = [key stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if([temp isEqualToString:@"badge"] == YES) { + result |= UIRemoteNotificationTypeBadge; + } else if([temp isEqualToString:@"sound"] == YES) { + result |= UIRemoteNotificationTypeSound; + } else if([temp isEqualToString:@"alert"] == YES) { + result |= UIRemoteNotificationTypeAlert; + } else if([temp isEqualToString:@"news-stand"] == YES) { + result |= UIRemoteNotificationTypeNewsstandContentAvailability; + } + } + } + return result; +} + +- (UIInterfaceOrientationMask)moConvertToInterfaceOrientationMask { + return [self moConvertToInterfaceOrientationMaskSeparated:@"|"]; +} + +- (UIInterfaceOrientationMask)moConvertToInterfaceOrientationMaskSeparated:(NSString*)separated { + UIInterfaceOrientationMask result = 0; + NSString* value = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([value isEqualToString:@"all"] == YES) { + result = UIInterfaceOrientationMaskAll; + } else { + NSArray* keys = [value componentsSeparatedByString:separated]; + for(NSString* key in keys) { + NSString* temp = [key stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if([temp isEqualToString:@"portrait"] == YES) { + result |= UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; + } else if([temp isEqualToString:@"landscape"] == YES) { + result |= UIInterfaceOrientationMaskLandscape; + } else if([temp isEqualToString:@"portrait-down"] == YES) { + result |= UIInterfaceOrientationMaskPortrait; + } else if([temp isEqualToString:@"portrait-up"] == YES) { + result |= UIInterfaceOrientationMaskPortraitUpsideDown; + } else if([temp isEqualToString:@"landscape-left"] == YES) { + result |= UIInterfaceOrientationMaskLandscapeLeft; + } else if([temp isEqualToString:@"landscape-right"] == YES) { + result |= UIInterfaceOrientationMaskLandscapeRight; + } + } + } + return result; +} + +- (UIStatusBarStyle)moConvertToStatusBarStyle { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"default"] == YES) { + return UIStatusBarStyleDefault; + } else if([temp isEqualToString:@"light-content"] == YES) { + return UIStatusBarStyleLightContent; + } else if([temp isEqualToString:@"black-translucent"] == YES) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return UIStatusBarStyleBlackTranslucent; +#pragma clang diagnostic pop + } else if([temp isEqualToString:@"black-opaque"] == YES) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return UIStatusBarStyleBlackOpaque; +#pragma clang diagnostic pop + } + return UIStatusBarStyleDefault; +} + +- (UIStatusBarAnimation)moConvertToStatusBarAnimation { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"fade"] == YES) { + return UIStatusBarAnimationFade; + } else if([temp isEqualToString:@"slide"] == YES) { + return UIStatusBarAnimationSlide; + } + return UIStatusBarAnimationNone; +} + +- (UIViewAutoresizing)moConvertToViewAutoresizing { + return [self moConvertToViewAutoresizingSeparated:@"|"]; +} + +- (UIViewAutoresizing)moConvertToViewAutoresizingSeparated:(NSString*)separated { + UIViewAutoresizing result = UIViewAutoresizingNone; + NSString* value = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([value isEqualToString:@"all"] == YES) { + result = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + } else { + NSArray* keys = [value componentsSeparatedByString:separated]; + for(NSString* key in keys) { + NSString* temp = [key stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + if([temp isEqualToString:@"size"] == YES) { + result |= UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + } else if([temp isEqualToString:@"width"] == YES) { + result |= UIViewAutoresizingFlexibleWidth; + } else if([temp isEqualToString:@"height"] == YES) { + result |= UIViewAutoresizingFlexibleHeight; + } else if([temp isEqualToString:@"top"] == YES) { + result |= UIViewAutoresizingFlexibleBottomMargin; + } else if([temp isEqualToString:@"bottom"] == YES) { + result |= UIViewAutoresizingFlexibleTopMargin; + } else if([temp isEqualToString:@"left"] == YES) { + result |= UIViewAutoresizingFlexibleRightMargin; + } else if([temp isEqualToString:@"right"] == YES) { + result |= UIViewAutoresizingFlexibleLeftMargin; + } + } + } + return result; +} + +- (UIViewContentMode)moConvertToViewContentMode { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"stretch"] == YES) { + return UIViewContentModeScaleToFill; + } else if([temp isEqualToString:@"aspect-fill"] == YES) { + return UIViewContentModeScaleAspectFill; + } else if([temp isEqualToString:@"aspect-fit"] == YES) { + return UIViewContentModeScaleAspectFit; + } else if([temp isEqualToString:@"center"] == YES) { + return UIViewContentModeCenter; + } else if([temp isEqualToString:@"center"] == YES) { + return UIViewContentModeCenter; + } else if([temp isEqualToString:@"left"] == YES) { + return UIViewContentModeLeft; + } else if([temp isEqualToString:@"right"] == YES) { + return UIViewContentModeRight; + } else if([temp isEqualToString:@"top"] == YES) { + return UIViewContentModeTop; + } else if([temp isEqualToString:@"top-left"] == YES) { + return UIViewContentModeTopLeft; + } else if([temp isEqualToString:@"top-right"] == YES) { + return UIViewContentModeTopRight; + } else if([temp isEqualToString:@"bottom"] == YES) { + return UIViewContentModeBottom; + } else if([temp isEqualToString:@"bottom-left"] == YES) { + return UIViewContentModeBottomLeft; + } else if([temp isEqualToString:@"bottom-right"] == YES) { + return UIViewContentModeBottomRight; + } + return UIViewContentModeScaleToFill; +} + +- (UIControlContentHorizontalAlignment)moConvertToControlContentHorizontalAlignment { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"center"] == YES) { + return UIControlContentHorizontalAlignmentCenter; + } else if([temp isEqualToString:@"left"] == YES) { + return UIControlContentHorizontalAlignmentLeft; + } else if([temp isEqualToString:@"right"] == YES) { + return UIControlContentHorizontalAlignmentRight; + } else if([temp isEqualToString:@"fill"] == YES) { + return UIControlContentHorizontalAlignmentFill; + } + return UIControlContentHorizontalAlignmentCenter; +} + +- (UIControlContentVerticalAlignment)moConvertToControlContentVerticalAlignment { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"center"] == YES) { + return UIControlContentVerticalAlignmentCenter; + } else if([temp isEqualToString:@"top"] == YES) { + return UIControlContentVerticalAlignmentTop; + } else if([temp isEqualToString:@"bottom"] == YES) { + return UIControlContentVerticalAlignmentBottom; + } else if([temp isEqualToString:@"fill"] == YES) { + return UIControlContentVerticalAlignmentFill; + } + return UIControlContentVerticalAlignmentCenter; +} + +- (UITextAutocapitalizationType)moConvertToTextAutocapitalizationType { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"none"] == YES) { + return UITextAutocapitalizationTypeNone; + } else if([temp isEqualToString:@"words"] == YES) { + return UITextAutocapitalizationTypeWords; + } else if([temp isEqualToString:@"sentences"] == YES) { + return UITextAutocapitalizationTypeSentences; + } else if([temp isEqualToString:@"all"] == YES) { + return UITextAutocapitalizationTypeAllCharacters; + } + return UITextAutocapitalizationTypeNone; +} + +- (UITextAutocorrectionType)moConvertToTextAutocorrectionType { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"default"] == YES) { + return UITextAutocorrectionTypeDefault; + } else if([temp isEqualToString:@"yes"] == YES) { + return UITextAutocorrectionTypeYes; + } else if([temp isEqualToString:@"no"] == YES) { + return UITextAutocorrectionTypeNo; + } + return UITextAutocorrectionTypeDefault; +} + +- (UITextSpellCheckingType)moConvertToTestSpellCheckingType { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"default"] == YES) { + return UITextSpellCheckingTypeDefault; + } else if([temp isEqualToString:@"yes"] == YES) { + return UITextSpellCheckingTypeYes; + } else if([temp isEqualToString:@"no"] == YES) { + return UITextSpellCheckingTypeNo; + } + return UITextSpellCheckingTypeDefault; +} + +- (UIKeyboardType)moConvertToKeyboardType { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"default"] == YES) { + return UIKeyboardTypeDefault; + } else if([temp isEqualToString:@"ascii"] == YES) { + return UIKeyboardTypeASCIICapable; + } else if([temp isEqualToString:@"url"] == YES) { + return UIKeyboardTypeURL; + } else if([temp isEqualToString:@"number"] == YES) { + return UIKeyboardTypeNumberPad; + } else if([temp isEqualToString:@"number-punctuation"] == YES) { + return UIKeyboardTypeNumbersAndPunctuation; + } else if([temp isEqualToString:@"phone"] == YES) { + return UIKeyboardTypePhonePad; + } else if([temp isEqualToString:@"name-phone"] == YES) { + return UIKeyboardTypeNamePhonePad; + } else if([temp isEqualToString:@"email-address"] == YES) { + return UIKeyboardTypeEmailAddress; + } else if([temp isEqualToString:@"decimal"] == YES) { + return UIKeyboardTypeDecimalPad; + } else if([temp isEqualToString:@"twitter"] == YES) { + return UIKeyboardTypeTwitter; + } else if([temp isEqualToString:@"web-search"] == YES) { + return UIKeyboardTypeWebSearch; + } + return UIKeyboardTypeDefault; +} + +- (UIReturnKeyType)moConvertToReturnKeyType { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"default"] == YES) { + return UIReturnKeyDefault; + } else if([temp isEqualToString:@"go"] == YES) { + return UIReturnKeyGo; + } else if([temp isEqualToString:@"google"] == YES) { + return UIReturnKeyGoogle; + } else if([temp isEqualToString:@"join"] == YES) { + return UIReturnKeyJoin; + } else if([temp isEqualToString:@"next"] == YES) { + return UIReturnKeyNext; + } else if([temp isEqualToString:@"route"] == YES) { + return UIReturnKeyRoute; + } else if([temp isEqualToString:@"search"] == YES) { + return UIReturnKeySearch; + } else if([temp isEqualToString:@"send"] == YES) { + return UIReturnKeySend; + } else if([temp isEqualToString:@"yahoo"] == YES) { + return UIReturnKeyYahoo; + } else if([temp isEqualToString:@"done"] == YES) { + return UIReturnKeyDone; + } else if([temp isEqualToString:@"emergency-call"] == YES) { + return UIReturnKeyEmergencyCall; + } + return UIReturnKeyDefault; +} + +- (UIBaselineAdjustment)moConvertToBaselineAdjustment { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"baselines"] == YES) { + return UIBaselineAdjustmentAlignBaselines; + } else if([temp isEqualToString:@"centers"] == YES) { + return UIBaselineAdjustmentAlignCenters; + } else if([temp isEqualToString:@"none"] == YES) { + return UIBaselineAdjustmentNone; + } + return UIBaselineAdjustmentAlignBaselines; +} + +- (UIScrollViewIndicatorStyle)moConvertToScrollViewIndicatorStyle { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"default"] == YES) { + return UIScrollViewIndicatorStyleDefault; + } else if([temp isEqualToString:@"black"] == YES) { + return UIScrollViewIndicatorStyleBlack; + } else if([temp isEqualToString:@"white"] == YES) { + return UIScrollViewIndicatorStyleWhite; + } + return UIScrollViewIndicatorStyleDefault; +} + +- (UIScrollViewKeyboardDismissMode)moConvertToScrollViewKeyboardDismissMode { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"none"] == YES) { + return UIScrollViewKeyboardDismissModeNone; + } else if([temp isEqualToString:@"drag"] == YES) { + return UIScrollViewKeyboardDismissModeOnDrag; + } else if([temp isEqualToString:@"interactive"] == YES) { + return UIScrollViewKeyboardDismissModeInteractive; + } + return UIScrollViewKeyboardDismissModeNone; +} + +- (UIBarStyle)moConvertToBarStyle { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"default"] == YES) { + return UIBarStyleDefault; + } else if([temp isEqualToString:@"black"] == YES) { + return UIBarStyleBlack; + } else if([temp isEqualToString:@"black-opaque"] == YES) { + return UIBarStyleBlackOpaque; + } else if([temp isEqualToString:@"black-translucent"] == YES) { + return UIBarStyleBlackTranslucent; + } + return UIBarStyleDefault; +} + +- (UITabBarItemPositioning)moConvertToTabBarItemPositioning { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"automatic"] == YES) { + return UITabBarItemPositioningAutomatic; + } else if([temp isEqualToString:@"fill"] == YES) { + return UITabBarItemPositioningFill; + } else if([temp isEqualToString:@"centered"] == YES) { + return UITabBarItemPositioningCentered; + } + return UITabBarItemPositioningAutomatic; +} + +- (UISearchBarStyle)moConvertToSearchBarStyle { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"default"] == YES) { + return UISearchBarStyleDefault; + } else if([temp isEqualToString:@"minimal"] == YES) { + return UISearchBarStyleMinimal; + } else if([temp isEqualToString:@"prominent"] == YES) { + return UISearchBarStyleProminent; + } + return UISearchBarStyleDefault; +} + +- (UIProgressViewStyle)moConvertToProgressViewStyle { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"default"] == YES) { + return UIProgressViewStyleDefault; + } else if([temp isEqualToString:@"bar"] == YES) { + return UIProgressViewStyleBar; + } + return UIProgressViewStyleDefault; +} + +- (UITextBorderStyle)moConvertToTextBorderStyle { + NSString* temp = [[self stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] lowercaseString]; + if([temp isEqualToString:@"none"] == YES) { + return UITextBorderStyleNone; + } else if([temp isEqualToString:@"line"] == YES) { + return UITextBorderStyleLine; + } else if([temp isEqualToString:@"bezer"] == YES) { + return UITextBorderStyleBezel; + } else if([temp isEqualToString:@"rounded"] == YES) { + return UITextBorderStyleRoundedRect; + } + return UITextBorderStyleNone; +} + +- (void)moDrawAtPoint:(CGPoint)point font:(UIFont*)font color:(UIColor*)color vAlignment:(MobilyVerticalAlignment)vAlignment hAlignment:(MobilyHorizontalAlignment)hAlignment lineBreakMode:(NSLineBreakMode)lineBreakMode { + NSStringDrawingOptions options = NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine; + NSMutableParagraphStyle* paragraphStyle = [NSMutableParagraphStyle new]; + paragraphStyle.lineBreakMode = lineBreakMode; + NSDictionary* attributes = @{ NSFontAttributeName: font, NSForegroundColorAttributeName: color, NSParagraphStyleAttributeName: paragraphStyle }; + CGRect boundingRect = [self boundingRectWithSize:CGSizeMake(NSIntegerMax, NSIntegerMax) options:options attributes:attributes context:nil]; + CGRect rect = CGRectMake(point.x, point.y, boundingRect.size.width, boundingRect.size.height); + switch(hAlignment) { + case MobilyHorizontalAlignmentCenter: rect.origin.x -= rect.size.width * 0.5f; break; + case MobilyHorizontalAlignmentRight: rect.origin.x -= rect.size.width; break; + default: break; + } + switch(vAlignment) { + case MobilyVerticalAlignmentCenter: rect.origin.y -= rect.size.height * 0.5f; break; + case MobilyVerticalAlignmentBottom: rect.origin.y -= rect.size.height; break; + default: break; + } + [self drawWithRect:CGRectMake(floorf(rect.origin.x), floorf(rect.origin.y), ceilf(rect.size.width), ceilf(rect.size.height)) options:options attributes:attributes context:nil]; +} + +- (void)moDrawInRect:(CGRect)rect font:(UIFont*)font color:(UIColor*)color vAlignment:(MobilyVerticalAlignment)vAlignment hAlignment:(MobilyHorizontalAlignment)hAlignment lineBreakMode:(NSLineBreakMode)lineBreakMode { + NSStringDrawingOptions options = NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine; + NSMutableParagraphStyle* paragraphStyle = [NSMutableParagraphStyle new]; + paragraphStyle.lineBreakMode = lineBreakMode; + NSDictionary* attributes = @{ NSFontAttributeName: font, NSForegroundColorAttributeName: color, NSParagraphStyleAttributeName: paragraphStyle }; + CGRect boundingRect = [self boundingRectWithSize:rect.size options:options attributes:attributes context:nil]; + switch(hAlignment) { + case MobilyHorizontalAlignmentCenter: rect.origin.x -= (boundingRect.size.width * 0.5f) - (rect.size.width * 0.5f); break; + case MobilyHorizontalAlignmentRight: rect.origin.x -= boundingRect.size.width - rect.size.width; break; + default: break; + } + switch(vAlignment) { + case MobilyVerticalAlignmentCenter: rect.origin.y -= (boundingRect.size.height * 0.5f) - (rect.size.height * 0.5f); break; + case MobilyVerticalAlignmentBottom: rect.origin.y -= boundingRect.size.height - rect.size.height; break; + default: break; + } + [self drawWithRect:CGRectMake(floorf(rect.origin.x), floorf(rect.origin.y), ceilf(rect.size.width), ceilf(rect.size.height)) options:options attributes:attributes context:nil]; +} + +@end + +/*--------------------------------------------------*/ + +BOOL MobilyColorHSBEqualToColorHSB(MobilyColorHSB color1, MobilyColorHSB color2) { + if((color1.hue == color2.hue) && (color1.saturation == color2.saturation) && (color1.brightness == color2.brightness)) { + return YES; + } + return NO; +} + +/*--------------------------------------------------*/ + +@implementation UIColor (MobilyUI) + ++ (UIColor*)moColorWithString:(NSString*)string { + UIColor* result = nil; + NSRange range = [string rangeOfString:@"#"]; + if((range.location != NSNotFound) && (range.length > 0)) { + CGFloat red = 1.0f, blue = 1.0f, green = 1.0f, alpha = 1.0f; + NSString* colorString = [[string stringByReplacingOccurrencesOfString:@"#" withString:@""] uppercaseString]; + switch (colorString.length) { + case 6: // #RRGGBB + red = [self moColorComponentFromString:colorString start:0 length:2]; + green = [self moColorComponentFromString:colorString start:2 length:2]; + blue = [self moColorComponentFromString:colorString start:4 length:2]; + break; + case 8: // #RRGGBBAA + red = [self moColorComponentFromString:colorString start:0 length:2]; + green = [self moColorComponentFromString:colorString start:2 length:2]; + blue = [self moColorComponentFromString:colorString start:4 length:2]; + alpha = [self moColorComponentFromString:colorString start:6 length:2]; + break; + } + result = [UIColor colorWithRed:red green:green blue:blue alpha:alpha]; + } + return result; +} + ++ (CGFloat)moColorComponentFromString:(NSString*)string start:(NSUInteger)start length:(NSUInteger)length { + unsigned result = 0; + NSString* part = [string substringWithRange:NSMakeRange(start, length)]; + if(part != nil) { + NSScanner* scaner = [NSScanner scannerWithString:part]; + if(scaner != nil) { + [scaner scanHexInt:&result]; + } + } + return ((CGFloat)result / 255.0f); +} + +- (UIColor*)moMultiplyColor:(UIColor*)color percent:(CGFloat)percent { + CGFloat r1, g1, b1, a1; + CGFloat r2, g2, b2, a2; + [self getRed:&r1 green:&g1 blue:&b1 alpha:&a1]; + [color getRed:&r2 green:&g2 blue:&b2 alpha:&a2]; + return [UIColor colorWithRed:(r2 * percent) + (r1 * (1.0 - percent)) + green:(g2 * percent) + (g1 * (1.0 - percent)) + blue:(b2 * percent) + (b1 * (1.0 - percent)) + alpha:(a2 * percent) + (a1 * (1.0 - percent))]; +} + +- (UIColor*)moMultiplyBrightness:(CGFloat)brightness { + CGFloat h, s, b, a; + [self getHue:&h saturation:&s brightness:&b alpha:&a]; + return [UIColor colorWithHue:h saturation:s brightness:b * brightness alpha:a]; +} + +- (MobilyColorHSB)moHsb { + MobilyColorHSB hsb; + hsb.hue = 0.0f; + hsb.saturation = 0.0f; + hsb.brightness = 0.0f; + CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace([self CGColor])); + if((model == kCGColorSpaceModelMonochrome) || (model == kCGColorSpaceModelRGB)) { + const CGFloat* c = CGColorGetComponents([self CGColor]); + CGFloat x = fminf(fminf(c[0], c[1]), c[2]); + CGFloat b = fmaxf(fmaxf(c[0], c[1]), c[2]); + if(b == x) { + hsb.hue = 0.0f; + hsb.saturation = 0.0f; + hsb.brightness = b; + } else { + CGFloat f = (c[0] == x) ? c[1] - c[2] : ((c[1] == x) ? c[2] - c[0] : c[0] - c[1]); + NSInteger i = (c[0] == x) ? 3 : ((c[1] == x) ? 5 : 1); + hsb.hue = ((i - f /(b - x)) / 6.0f); + hsb.saturation = (b - x)/b; + hsb.brightness = b; + } + } + return hsb; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UIImage (MobilyUI) + ++ (UIImage*)moImageNamed:(NSString*)name capInsets:(UIEdgeInsets)capInsets { + UIImage* result = [self imageNamed:name]; + if(result != nil) { + result = [result resizableImageWithCapInsets:capInsets]; + } + return result; +} + ++ (UIImage*)moImageWithColor:(UIColor*)color size:(CGSize)size { + UIImage* image = nil; + UIGraphicsBeginImageContext(size); + CGContextRef context = UIGraphicsGetCurrentContext(); + if(context != NULL) { + CGContextSetFillColorWithColor(context, [color CGColor]); + CGContextFillRect(context, CGRectMake(0.0f, 0.0f, size.width, size.height)); + image = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + } + return image; +} + +- (UIImage*)moUnrotate { + UIImage* result = nil; + CGImageRef imageRef = self.CGImage; + if(imageRef != NULL) { + CGSize originalSize = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef)); + CGSize finalSize = CGSizeZero; + CGAffineTransform transform = CGAffineTransformIdentity; + switch(self.imageOrientation) { + case UIImageOrientationUp: { + transform = CGAffineTransformIdentity; + finalSize = originalSize; + break; + } + case UIImageOrientationUpMirrored: { + transform = CGAffineTransformMakeTranslation(originalSize.width, 0.0); + transform = CGAffineTransformScale(transform, -1.0, 1.0); + finalSize = originalSize; + break; + } + case UIImageOrientationDown: { + transform = CGAffineTransformMakeTranslation(originalSize.width, originalSize.height); + transform = CGAffineTransformRotate(transform, M_PI); + finalSize = originalSize; + break; + } + case UIImageOrientationDownMirrored: { + transform = CGAffineTransformMakeTranslation(0.0, originalSize.height); + transform = CGAffineTransformScale(transform, 1.0, -1.0); + finalSize = originalSize; + break; + } + case UIImageOrientationLeftMirrored: { + transform = CGAffineTransformMakeTranslation(originalSize.height, originalSize.width); + transform = CGAffineTransformScale(transform, -1.0, 1.0); + transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0); + finalSize = CGSizeMake(originalSize.height, originalSize.width); + break; + } + case UIImageOrientationLeft: { + transform = CGAffineTransformMakeTranslation(0.0, originalSize.width); + transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0); + finalSize = CGSizeMake(originalSize.height, originalSize.width); + break; + } + case UIImageOrientationRightMirrored: { + transform = CGAffineTransformMakeScale(-1.0, 1.0); + transform = CGAffineTransformRotate(transform, M_PI / 2.0); + finalSize = CGSizeMake(originalSize.height, originalSize.width); + break; + } + case UIImageOrientationRight: { + transform = CGAffineTransformMakeTranslation(originalSize.height, 0.0); + transform = CGAffineTransformRotate(transform, M_PI / 2.0); + finalSize = CGSizeMake(originalSize.height, originalSize.width); + break; + } + default: + break; + } + if((finalSize.width > MOBILY_EPSILON) && (finalSize.height > MOBILY_EPSILON)) { + UIGraphicsBeginImageContext(finalSize); + CGContextRef context = UIGraphicsGetCurrentContext(); + if(context != NULL) { + switch(self.imageOrientation) { + case UIImageOrientationRight: + case UIImageOrientationLeft: + CGContextScaleCTM(context, -1.0f, 1.0f); + CGContextTranslateCTM(context, -originalSize.height, 0.0f); + break; + default: + CGContextScaleCTM(context, 1.0f, -1.0f); + CGContextTranslateCTM(context, 0.0f, -originalSize.height); + break; + } + CGContextConcatCTM(context, transform); + CGContextDrawImage(UIGraphicsGetCurrentContext(), CGRectMake(0.0f, 0.0f, originalSize.width, originalSize.height), imageRef); + result = UIGraphicsGetImageFromCurrentImageContext(); + } + UIGraphicsEndImageContext(); + } + } + return result; +} + +- (UIImage*)moScaleToSize:(CGSize)size { + UIImage* result = nil; + CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); + if(colourSpace != NULL) { + CGRect drawRect = MobilyRectAspectFitFromBoundsAndSize(CGRectMake(0.0f, 0.0f, size.width, size.height), self.size); + drawRect.size.width = floorf(drawRect.size.width); + drawRect.size.height = floorf(drawRect.size.height); + + CGContextRef context = CGBitmapContextCreate(NULL, drawRect.size.width, drawRect.size.height, 8, drawRect.size.width * 4, colourSpace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast); + if(context != NULL) { + CGContextClearRect(context, CGRectMake(0.0f, 0.0f, drawRect.size.width, drawRect.size.height)); + CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, drawRect.size.width, drawRect.size.height), self.CGImage); + + CGImageRef image = CGBitmapContextCreateImage(context); + if(image != NULL) { + result = [UIImage imageWithCGImage:image scale:self.scale orientation:self.imageOrientation]; + CGImageRelease(image); + } + CGContextRelease(context); + } + CGColorSpaceRelease(colourSpace); + } + return result; +} + +- (UIImage*)moRotateToAngleInRadians:(CGFloat)angleInRadians { + UIImage* result = nil; + CGSize size = self.size; + if((size.width > 0.0f) && (size.height > 0.0f)) { + UIGraphicsBeginImageContextWithOptions(size, NO, self.scale); + CGContextRef context = UIGraphicsGetCurrentContext(); + if(context != NULL) { + CGContextTranslateCTM(context, 0.5f * size.width, 0.5f * size.height); + CGContextRotateCTM(context, angleInRadians); + CGContextTranslateCTM(context, -0.5f * size.width, -0.5f * size.height); + [self drawAtPoint:CGPointZero]; + result = UIGraphicsGetImageFromCurrentImageContext(); + } + UIGraphicsEndImageContext(); + } + return result; +} + +- (UIImage*)moGrayscale { + UIImage* result = nil; + CGSize size = self.size; + CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height); + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); + if(colorSpace != NULL) { + CGContextRef context = CGBitmapContextCreate(nil, size.width, size.height, 8, 0, colorSpace, (CGBitmapInfo)kCGImageAlphaNone); + if(context != NULL) { + CGContextDrawImage(context, rect, [self CGImage]); + CGImageRef grayscale = CGBitmapContextCreateImage(context); + if(context != NULL) { + result = [UIImage imageWithCGImage:grayscale]; + CGImageRelease(grayscale); + } + CGContextRelease(context); + } + CGColorSpaceRelease(colorSpace); + } + return result; +} + +- (UIImage*)moBlackAndWhite { + UIImage* result = nil; + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); + if(colorSpace != NULL) { + CGContextRef context = CGBitmapContextCreate(nil, self.size.width, self.size.height, 8, self.size.width, colorSpace, (CGBitmapInfo)kCGImageAlphaNone); + if(colorSpace != NULL) { + CGContextSetInterpolationQuality(context, kCGInterpolationHigh); + CGContextSetShouldAntialias(context, NO); + CGContextDrawImage(context, CGRectMake(0, 0, self.size.width, self.size.height), self.CGImage); + CGImageRef bwImage = CGBitmapContextCreateImage(context); + if(bwImage != NULL) { + result = [UIImage imageWithCGImage:bwImage]; + CGImageRelease(bwImage); + } + CGContextRelease(context); + } + CGColorSpaceRelease(colorSpace); + } + return result; +} + +- (UIImage*)moInvertColors { + UIImage* result = nil; + UIGraphicsBeginImageContext(self.size); + CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeCopy); + [self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)]; + CGContextSetBlendMode(UIGraphicsGetCurrentContext(), kCGBlendModeDifference); + CGContextSetFillColorWithColor(UIGraphicsGetCurrentContext(), UIColor.whiteColor.CGColor); + CGContextFillRect(UIGraphicsGetCurrentContext(), CGRectMake(0, 0, self.size.width, self.size.height)); + result = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return result; +} + +- (UIImage*)moBlurredImageWithRadius:(CGFloat)radius iterations:(NSUInteger)iterations tintColor:(UIColor*)tintColor { + UIImage* image = nil; + CGSize size = self.size; + CGFloat scale = self.scale; + if(floorf(size.width) * floorf(size.height) > MOBILY_EPSILON) { + CGImageRef imageRef = self.CGImage; + uint32_t boxSize = (uint32_t)(radius * scale); + if(boxSize % 2 == 0) { + boxSize++; + } + vImage_Buffer buffer1; + buffer1.width = CGImageGetWidth(imageRef); + buffer1.height = CGImageGetHeight(imageRef); + buffer1.rowBytes = CGImageGetBytesPerRow(imageRef); + size_t bytes = buffer1.rowBytes * buffer1.height; + buffer1.data = malloc(bytes); + if(buffer1.data != NULL) { + vImage_Buffer buffer2; + buffer2.width = buffer1.width; + buffer2.height = buffer1.height; + buffer2.rowBytes = buffer1.rowBytes; + buffer2.data = malloc(bytes); + if(buffer2.data != nil) { + size_t tempBufferSize = (size_t)vImageBoxConvolve_ARGB8888(&buffer1, &buffer2, NULL, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend + kvImageGetTempBufferSize); + if(tempBufferSize > 0) { + void* tempBuffer = malloc(tempBufferSize); + if(tempBuffer != nil) { + CFDataRef dataSource = CGDataProviderCopyData(CGImageGetDataProvider(imageRef)); + if(dataSource != NULL) { + memcpy(buffer1.data, CFDataGetBytePtr(dataSource), bytes); + CFRelease(dataSource); + } + for(NSUInteger i = 0; i < iterations; i++) { + if(vImageBoxConvolve_ARGB8888(&buffer1, &buffer2, tempBuffer, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend) == kvImageNoError) { + void* temp = buffer1.data; + buffer1.data = buffer2.data; + buffer2.data = temp; + } + } + free(tempBuffer); + CGContextRef context = CGBitmapContextCreate(buffer1.data, buffer1.width, buffer1.height, 8, buffer1.rowBytes, CGImageGetColorSpace(imageRef), CGImageGetBitmapInfo(imageRef)); + if(context != NULL) { + if(tintColor != nil) { + if(CGColorGetAlpha(tintColor.CGColor) > 0.0f) { + CGContextSetFillColorWithColor(context, [[tintColor colorWithAlphaComponent:0.25] CGColor]); + CGContextSetBlendMode(context, kCGBlendModePlusDarker); + CGContextFillRect(context, CGRectMake(0, 0, buffer1.width, buffer1.height)); + } + } + imageRef = CGBitmapContextCreateImage(context); + if(imageRef != nil) { + image = [UIImage imageWithCGImage:imageRef scale:scale orientation:self.imageOrientation]; + CGImageRelease(imageRef); + } + CGContextRelease(context); + } + } + } + free(buffer2.data); + } + free(buffer1.data); + } + } + return image; +} + +- (void)moDrawInRect:(CGRect)rect alignment:(MobilyImageAlignment)alignment { + return [self moDrawInRect:rect alignment:alignment corners:UIRectCornerAllCorners radius:0.0f blendMode:kCGBlendModeNormal alpha:1.0f]; +} + +- (void)moDrawInRect:(CGRect)rect alignment:(MobilyImageAlignment)alignment blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha { + return [self moDrawInRect:rect alignment:alignment corners:UIRectCornerAllCorners radius:0.0f blendMode:blendMode alpha:alpha]; +} + +- (void)moDrawInRect:(CGRect)rect alignment:(MobilyImageAlignment)alignment radius:(CGFloat)radius { + return [self moDrawInRect:rect alignment:alignment corners:UIRectCornerAllCorners radius:radius blendMode:kCGBlendModeNormal alpha:1.0f]; +} + +- (void)moDrawInRect:(CGRect)rect alignment:(MobilyImageAlignment)alignment radius:(CGFloat)radius blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha { + return [self moDrawInRect:rect alignment:alignment corners:UIRectCornerAllCorners radius:radius blendMode:blendMode alpha:alpha]; +} + +- (void)moDrawInRect:(CGRect)rect alignment:(MobilyImageAlignment)alignment corners:(UIRectCorner)corners radius:(CGFloat)radius { + return [self moDrawInRect:rect alignment:alignment corners:corners radius:radius blendMode:kCGBlendModeNormal alpha:1.0f]; +} + +- (void)moDrawInRect:(CGRect)rect alignment:(MobilyImageAlignment)alignment corners:(UIRectCorner)corners radius:(CGFloat)radius blendMode:(CGBlendMode)blendMode alpha:(CGFloat)alpha { + CGContextRef contextRef = UIGraphicsGetCurrentContext(); + CGContextSaveGState(contextRef); + UIBezierPath* path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:corners cornerRadii:CGSizeMake(radius, radius)]; + [path addClip]; + switch(alignment) { + case MobilyImageAlignmentStretch: break; + case MobilyImageAlignmentAspectFill: rect = MobilyRectAspectFillFromBoundsAndSize(rect, self.size); break; + case MobilyImageAlignmentAspectFit: rect = MobilyRectAspectFitFromBoundsAndSize(rect, self.size); break; + } + [self drawInRect:rect blendMode:blendMode alpha:alpha]; + CGContextRestoreGState(contextRef); +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UIBezierPath (MobilyUI) + ++ (void)moDrawRect:(CGRect)rect fillColor:(UIColor*)fillColor { + [self moDrawRect:rect fillColor:fillColor strokeColor:nil strokeWidth:0.0f]; +} + ++ (void)moDrawRect:(CGRect)rect fillColor:(UIColor*)fillColor strokeColor:(UIColor*)strokeColor strokeWidth:(CGFloat)strokeWidth { + UIBezierPath* path = [UIBezierPath bezierPathWithRect:rect]; + if(fillColor != nil) { + [fillColor setFill]; + [path fill]; + } + if(strokeColor != nil) { + [strokeColor setStroke]; + [path setLineWidth:strokeWidth]; + [path stroke]; + } +} + ++ (void)moDrawOvalInRect:(CGRect)rect fillColor:(UIColor*)fillColor { + [self moDrawOvalInRect:rect fillColor:fillColor strokeColor:nil strokeWidth:0.0f]; +} + ++ (void)moDrawOvalInRect:(CGRect)rect fillColor:(UIColor*)fillColor strokeColor:(UIColor*)strokeColor strokeWidth:(CGFloat)strokeWidth { + UIBezierPath* path = [UIBezierPath bezierPathWithOvalInRect:rect]; + if(fillColor != nil) { + [fillColor setFill]; + [path fill]; + } + if(strokeColor != nil) { + [strokeColor setStroke]; + [path setLineWidth:strokeWidth]; + [path stroke]; + } +} + ++ (void)moDrawRoundedRect:(CGRect)rect radius:(CGFloat)radius fillColor:(UIColor*)fillColor { + [self moDrawRoundedRect:rect radius:radius fillColor:fillColor strokeColor:nil strokeWidth:0.0f]; +} + ++ (void)moDrawRoundedRect:(CGRect)rect radius:(CGFloat)radius fillColor:(UIColor*)fillColor strokeColor:(UIColor*)strokeColor strokeWidth:(CGFloat)strokeWidth { + UIBezierPath* path = [UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:radius]; + if(fillColor != nil) { + [fillColor setFill]; + [path fill]; + } + if(strokeColor != nil) { + [strokeColor setStroke]; + [path setLineWidth:strokeWidth]; + [path stroke]; + } +} + ++ (void)moDrawRoundedRect:(CGRect)rect corners:(UIRectCorner)corners radius:(CGSize)radius fillColor:(UIColor*)fillColor { + [self moDrawRoundedRect:rect corners:corners radius:radius fillColor:fillColor strokeColor:nil strokeWidth:0.0f]; +} + ++ (void)moDrawRoundedRect:(CGRect)rect corners:(UIRectCorner)corners radius:(CGSize)radius fillColor:(UIColor*)fillColor strokeColor:(UIColor*)strokeColor strokeWidth:(CGFloat)strokeWidth { + UIBezierPath* path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:corners cornerRadii:radius]; + if(fillColor != nil) { + [fillColor setFill]; + [path fill]; + } + if(strokeColor != nil) { + [strokeColor setStroke]; + [path setLineWidth:strokeWidth]; + [path stroke]; + } +} + ++ (void)moDrawSeparatorRect:(CGRect)rect edges:(MobilyBezierPathSeparatorEdges)edges width:(CGFloat)width fillColor:(UIColor*)fillColor { + [self moDrawSeparatorRect:rect edges:edges widthEdges:UIEdgeInsetsMake(width, width, width, width) edgeInsets:UIEdgeInsetsZero fillColor:fillColor]; +} + ++ (void)moDrawSeparatorRect:(CGRect)rect edges:(MobilyBezierPathSeparatorEdges)edges width:(CGFloat)width edgeInsets:(UIEdgeInsets)edgeInsets fillColor:(UIColor*)fillColor { + [self moDrawSeparatorRect:rect edges:edges widthEdges:UIEdgeInsetsMake(width, width, width, width) edgeInsets:edgeInsets fillColor:fillColor]; +} + ++ (void)moDrawSeparatorRect:(CGRect)rect edges:(MobilyBezierPathSeparatorEdges)edges widthEdges:(UIEdgeInsets)widthEdges edgeInsets:(UIEdgeInsets)edgeInsets fillColor:(UIColor*)fillColor { + UIBezierPath* path = [UIBezierPath bezierPath]; + if((edges & MobilyBezierPathSeparatorEdgeTop) != 0) { + CGRect lineRect = CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, widthEdges.top); + UIEdgeInsets lineInsets = UIEdgeInsetsZero; + if((edges & MobilyBezierPathSeparatorEdgeLeft) == 0) { lineInsets.left = edgeInsets.left; } + if((edges & MobilyBezierPathSeparatorEdgeRight) != 0) { lineInsets.right = widthEdges.right; } + [path appendPath:[UIBezierPath bezierPathWithRect:UIEdgeInsetsInsetRect(lineRect, lineInsets)]]; + } + if((edges & MobilyBezierPathSeparatorEdgeRight) != 0) { + CGRect lineRect = CGRectMake((rect.origin.x + rect.size.width) - widthEdges.right, rect.origin.y, widthEdges.right, rect.size.height); + UIEdgeInsets lineInsets = UIEdgeInsetsZero; + if((edges & MobilyBezierPathSeparatorEdgeTop) == 0) { lineInsets.top = edgeInsets.top; } + if((edges & MobilyBezierPathSeparatorEdgeBottom) != 0) { lineInsets.bottom = widthEdges.bottom; } + [path appendPath:[UIBezierPath bezierPathWithRect:UIEdgeInsetsInsetRect(lineRect, lineInsets)]]; + } + if((edges & MobilyBezierPathSeparatorEdgeBottom) != 0) { + CGRect lineRect = CGRectMake(rect.origin.x, (rect.origin.y + rect.size.height) - widthEdges.bottom, rect.size.width, widthEdges.bottom); + UIEdgeInsets lineInsets = UIEdgeInsetsZero; + if((edges & MobilyBezierPathSeparatorEdgeLeft) != 0) { lineInsets.left = widthEdges.left; } + if((edges & MobilyBezierPathSeparatorEdgeRight) == 0) { lineInsets.right = edgeInsets.right; } + [path appendPath:[UIBezierPath bezierPathWithRect:UIEdgeInsetsInsetRect(lineRect, lineInsets)]]; + } + if((edges & MobilyBezierPathSeparatorEdgeLeft) != 0) { + CGRect lineRect = CGRectMake(rect.origin.x, rect.origin.y, widthEdges.left, rect.size.height); + UIEdgeInsets lineInsets = UIEdgeInsetsZero; + if((edges & MobilyBezierPathSeparatorEdgeTop) != 0) { lineInsets.top = widthEdges.top; } + if((edges & MobilyBezierPathSeparatorEdgeBottom) == 0) { lineInsets.bottom = edgeInsets.bottom; } + [path appendPath:[UIBezierPath bezierPathWithRect:UIEdgeInsetsInsetRect(lineRect, lineInsets)]]; + } + if(fillColor != nil) { + [fillColor setFill]; + [path fill]; + } +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UINib (MobilyUI) + ++ (id)moViewWithNibName:(NSString*)nibName withClass:(Class)class { + return [self moViewWithNibName:nibName withClass:class withOwner:nil]; +} + ++ (id)moViewWithNibName:(NSString*)nibName withClass:(Class)class withOwner:(id)owner { + UINib* nib = [UINib nibWithNibName:nibName bundle:nil]; + if(nib != nil) { + return [nib moInstantiateWithClass:class owner:owner options:nil]; + } + return nil; +} + ++ (UINib*)moNibWithBaseName:(NSString*)baseName bundle:(NSBundle*)bundle { + if(bundle == nil) { + bundle = NSBundle.mainBundle; + } + NSMutableArray* nibNames = [NSMutableArray array]; + NSFileManager* fileManager = NSFileManager.defaultManager; + if(UIDevice.moIsIPhone == YES) { + NSString* modelBaseName = [NSString stringWithFormat:@"%@%@", baseName, @"-iPhone"]; + switch(UIDevice.moModel) { + case MobilyDeviceModelPhone6Plus: + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-6Plus"]]; + case MobilyDeviceModelPhone6: + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-6"]]; + case MobilyDeviceModelPhone5S: + case MobilyDeviceModelPhone5C: + case MobilyDeviceModelPhone5: + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-5"]]; + case MobilyDeviceModelPhone4S: + case MobilyDeviceModelPhone4: + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-4"]]; + case MobilyDeviceModelPhone3GS: + case MobilyDeviceModelPhone3G: + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-3"]]; + default: + [nibNames addObject:modelBaseName]; + break; + } + } else if(UIDevice.moIsIPad == YES) { + NSString* modelBaseName = [NSString stringWithFormat:@"%@%@", baseName, @"-iPad"]; + switch(UIDevice.moModel) { + case MobilyDeviceModelPadAir2: + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-Air2"]]; + case MobilyDeviceModelPadAir1: + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-Air1"]]; + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-Air"]]; + break; + case MobilyDeviceModelPadMini3: + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-Mini3"]]; + case MobilyDeviceModelPadMini2: + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-Mini2"]]; + case MobilyDeviceModelPadMini1: + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-Mini1"]]; + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-Mini"]]; + break; + case MobilyDeviceModelPad4: + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-4"]]; + case MobilyDeviceModelPad3: + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-3"]]; + case MobilyDeviceModelPad2: + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-2"]]; + case MobilyDeviceModelPad1: + [nibNames addObject:[NSString stringWithFormat:@"%@%@", modelBaseName, @"-1"]]; + break; + default: + [nibNames addObject:modelBaseName]; + break; + } + } + [nibNames addObject:baseName]; + + NSString* existNibName = nil; + for(NSString* nibName in nibNames) { + if([fileManager fileExistsAtPath:[bundle pathForResource:nibName ofType:@"nib"]] == YES) { + existNibName = nibName; + break; + } + } + if(existNibName != nil) { + return [self nibWithNibName:existNibName bundle:bundle]; + } + return nil; +} + ++ (UINib*)moNibWithClass:(Class)class bundle:(NSBundle*)bundle { + UINib* nib = [self moNibWithBaseName:NSStringFromClass(class) bundle:bundle]; + if((nib == nil) && ([class superclass] != nil)) { + nib = [self moNibWithClass:[class superclass] bundle:bundle]; + } + return nib; +} + +- (id)moInstantiateWithClass:(Class)class owner:(id)owner options:(NSDictionary*)options { + NSArray* content = [self instantiateWithOwner:owner options:options]; + for(id item in content) { + if([item isKindOfClass:class] == YES) { + return item; + } + } + return nil; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +static UIResponder* MOBILY_CURRENT_FIRST_RESPONDER = nil; + +/*--------------------------------------------------*/ + +@implementation UIResponder (MobilyUI) + ++ (id)moCurrentFirstResponderInView:(UIView*)view { + id responder = self.moCurrentFirstResponder; + if([responder isKindOfClass:UIView.class] == YES) { + if([view moIsContainsSubview:responder] == YES) { + return responder; + } + } + return nil; +} + ++ (id)moCurrentFirstResponder { + MOBILY_CURRENT_FIRST_RESPONDER = nil; + [UIApplication.sharedApplication sendAction:@selector(moFindFirstResponder) to:nil from:nil forEvent:nil]; + return MOBILY_CURRENT_FIRST_RESPONDER; +} + +- (void)moFindFirstResponder { + MOBILY_CURRENT_FIRST_RESPONDER = self; +} + ++ (UIResponder*)moPrevResponderFromView:(UIView*)view { + NSArray* responders = view.window.moResponders; + if(responders.count > 1) { + NSInteger index = [responders indexOfObject:view]; + if(index != NSNotFound) { + if(index > 0) { + return responders[index - 1]; + } + } + } + return nil; +} + ++ (UIResponder*)moNextResponderFromView:(UIView*)view { + NSArray* responders = view.window.moResponders; + if(responders.count > 1) { + NSInteger index = [responders indexOfObject:view]; + if(index != NSNotFound) { + if(index < responders.count - 1) { + return responders[index + 1]; + } + } + } + return nil; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UIWindow (MobilyUI) + +#pragma mark NSKeyValueCoding + +#pragma mark Property + +- (UIViewController*)moCurrentController { + return self.rootViewController.moCurrentController; +} + +#ifdef __IPHONE_7_0 + +- (UIViewController*)moControllerForStatusBarStyle { + UIViewController* controller = self.moCurrentController; + while(controller.childViewControllerForStatusBarStyle != nil) { + controller = controller.childViewControllerForStatusBarStyle; + } + return controller; +} + +- (UIViewController*)moControllerForStatusBarHidden { + UIViewController* controller = self.moCurrentController; + while(controller.childViewControllerForStatusBarHidden != nil) { + controller = controller.childViewControllerForStatusBarHidden; + } + return controller; +} + +#endif + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UIView (MobilyUI) + +#pragma mark NSKeyValueCoding + +MOBILY_DEFINE_VALIDATE_BOOL(UserInteractionEnabled) +MOBILY_DEFINE_VALIDATE_RECT(Frame) +MOBILY_DEFINE_VALIDATE_POINT(MoFramePosition) +MOBILY_DEFINE_VALIDATE_POINT(MoFrameCenter) +MOBILY_DEFINE_VALIDATE_SIZE(MoFrameSize) +MOBILY_DEFINE_VALIDATE_NUMBER(MoFrameSX) +MOBILY_DEFINE_VALIDATE_NUMBER(MoFrameSY) +MOBILY_DEFINE_VALIDATE_NUMBER(MoFrameCX) +MOBILY_DEFINE_VALIDATE_NUMBER(MoFrameCY) +MOBILY_DEFINE_VALIDATE_NUMBER(MoFrameEX) +MOBILY_DEFINE_VALIDATE_NUMBER(MoFrameEY) +MOBILY_DEFINE_VALIDATE_NUMBER(MoFrameWidth) +MOBILY_DEFINE_VALIDATE_NUMBER(MoFrameHeight) +MOBILY_DEFINE_VALIDATE_NUMBER(MoFrameLeft) +MOBILY_DEFINE_VALIDATE_NUMBER(MoFrameRight) +MOBILY_DEFINE_VALIDATE_NUMBER(MoFrameTop) +MOBILY_DEFINE_VALIDATE_NUMBER(MoFrameBottom) +MOBILY_DEFINE_VALIDATE_NUMBER(MoCornerRadius) +MOBILY_DEFINE_VALIDATE_NUMBER(MoBorderWidth) +MOBILY_DEFINE_VALIDATE_COLOR(MoBorderColor) +MOBILY_DEFINE_VALIDATE_COLOR(MoShadowColor) +MOBILY_DEFINE_VALIDATE_NUMBER(MoShadowOpacity); +MOBILY_DEFINE_VALIDATE_SIZE(MoShadowOffset); +MOBILY_DEFINE_VALIDATE_NUMBER(MoShadowRadius); +MOBILY_DEFINE_VALIDATE_BEZIER_PATH(MoShadowPath); +MOBILY_DEFINE_VALIDATE_RECT(Bounds) +MOBILY_DEFINE_VALIDATE_POINT(Center) +MOBILY_DEFINE_VALIDATE_NUMBER(ContentScaleFactor) +MOBILY_DEFINE_VALIDATE_BOOL(MultipleTouchEnabled) +MOBILY_DEFINE_VALIDATE_BOOL(AutoresizesSubviews) +MOBILY_DEFINE_VALIDATE_AUTORESIZING(AutoresizingMask) +MOBILY_DEFINE_VALIDATE_BOOL(ClipsToBounds) +MOBILY_DEFINE_VALIDATE_COLOR(BackgroundColor) +MOBILY_DEFINE_VALIDATE_NUMBER(Alpha) +MOBILY_DEFINE_VALIDATE_BOOL(Opaque) +MOBILY_DEFINE_VALIDATE_BOOL(ClearsContextBeforeDrawing) +MOBILY_DEFINE_VALIDATE_BOOL(Hidden) +MOBILY_DEFINE_VALIDATE_CONTENT_MODE(ContentMode) +MOBILY_DEFINE_VALIDATE_RECT(ContentStretch) +MOBILY_DEFINE_VALIDATE_COLOR(TintColor); + +#pragma mark Property + +- (void)setMoFramePosition:(CGPoint)moFramePosition { + CGRect frame = self.frame; + self.frame = CGRectMake(moFramePosition.x, moFramePosition.y, frame.size.width, frame.size.height); +} + +- (CGPoint)moFramePosition { + return self.frame.origin; +} + +- (void)setMoFrameCenter:(CGPoint)moFrameCenter { + CGRect frame = self.frame; + self.frame = CGRectMake(moFrameCenter.x - (frame.size.width * 0.5f), moFrameCenter.y - (frame.size.height * 0.5f), frame.size.width, frame.size.height); +} + +- (CGPoint)moFrameCenter { + CGRect frame = self.frame; + return CGPointMake(frame.origin.x + (frame.size.width * 0.5f), frame.origin.y + (frame.size.height * 0.5f)); +} + +- (void)setMoFrameSize:(CGSize)moFrameSize { + CGRect frame = self.frame; + self.frame = CGRectMake(frame.origin.x, frame.origin.y, moFrameSize.width, moFrameSize.height); +} + +- (CGSize)moFrameSize { + return self.frame.size; +} + +- (void)setMoFrameSX:(CGFloat)moFrameSX { + CGRect frame = self.frame; + self.frame = CGRectMake(moFrameSX, frame.origin.y, frame.size.width, frame.size.height); +} + +- (CGFloat)moFrameSX { + return CGRectGetMinX(self.frame); +} + +- (void)setMoFrameCX:(CGFloat)moFrameCX { + CGRect frame = self.frame; + self.frame = CGRectMake(moFrameCX - (frame.size.width * 0.5f), frame.origin.y, frame.size.width, frame.size.height); +} + +- (CGFloat)moFrameCX { + return CGRectGetMidX(self.frame); +} + +- (void)setMoFrameEX:(CGFloat)moFrameEX { + CGRect frame = self.frame; + self.frame = CGRectMake(frame.origin.x, frame.origin.y, moFrameEX - frame.origin.x, frame.size.height); +} + +- (CGFloat)moFrameEX { + return CGRectGetMaxX(self.frame); +} + +- (void)setMoFrameSY:(CGFloat)moFrameSY { + CGRect frame = self.frame; + self.frame = CGRectMake(frame.origin.x, moFrameSY, frame.size.width, frame.size.height); +} + +- (CGFloat)moFrameSY { + return CGRectGetMinY(self.frame); +} + +- (void)setMoFrameCY:(CGFloat)moFrameCY { + CGRect frame = self.frame; + self.frame = CGRectMake(frame.origin.x, moFrameCY - (frame.size.height * 0.5f), frame.size.width, frame.size.height); +} + +- (CGFloat)moFrameCY { + return CGRectGetMidY(self.frame); +} + +- (void)setMoFrameEY:(CGFloat)moFrameEY { + CGRect frame = self.frame; + self.frame = CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, moFrameEY - frame.origin.y); +} + +- (CGFloat)moFrameEY { + return CGRectGetMaxY(self.frame); +} + +- (void)setMoFrameWidth:(CGFloat)moFrameWidth { + CGRect frame = self.frame; + self.frame = CGRectMake(frame.origin.x, frame.origin.y, moFrameWidth, frame.size.height); +} + +- (CGFloat)moFrameWidth { + return CGRectGetWidth(self.frame); +} + +- (void)setMoFrameHeight:(CGFloat)moFrameHeight { + CGRect frame = self.frame; + self.frame = CGRectMake(frame.origin.x, frame.origin.y, frame.size.width, moFrameHeight); +} + +- (CGFloat)moFrameHeight { + return CGRectGetHeight(self.frame); +} + +- (void)setMoFrameLeft:(CGFloat)moFrameLeft { + CGRect frame = self.frame; + CGFloat offset = moFrameLeft; + CGFloat size = frame.size.width - (moFrameLeft - frame.origin.x); + self.frame = CGRectMake(offset, frame.origin.y, size, frame.size.height); +} + +- (CGFloat)moFrameLeft { + return self.frame.origin.x; +} + +- (void)setMoFrameRight:(CGFloat)moFrameRight { + CGRect frame = self.frame; + CGRect bounds = self.superview.bounds; + CGFloat offset = frame.origin.x; + CGFloat size = bounds.size.width - (frame.origin.x + moFrameRight); + self.frame = CGRectMake(offset, frame.origin.y, size, frame.size.height); +} + +- (CGFloat)moFrameRight { + CGRect frame = self.frame; + CGRect bounds = self.superview.bounds; + return bounds.size.width - (frame.origin.x + frame.size.width); +} + +- (void)setMoFrameTop:(CGFloat)moFrameTop { + CGRect frame = self.frame; + CGFloat offset = moFrameTop; + CGFloat size = frame.size.height - (moFrameTop - frame.origin.y); + self.frame = CGRectMake(frame.origin.x, offset, frame.size.width, size); +} + +- (CGFloat)moFrameTop { + CGRect frame = self.frame; + return frame.origin.y; +} + +- (void)setMoFrameBottom:(CGFloat)moFrameBottom { + CGRect frame = self.frame; + CGRect bounds = self.superview.bounds; + CGFloat offset = frame.origin.y; + CGFloat size = bounds.size.height - (frame.origin.y + moFrameBottom); + self.frame = CGRectMake(frame.origin.x, offset, frame.size.width, size); +} + +- (CGFloat)moFrameBottom { + CGRect frame = self.frame; + CGRect bounds = self.superview.bounds; + return bounds.size.height - (frame.origin.y + frame.size.height); +} + +- (CGPoint)moBoundsPosition { + return self.bounds.origin; +} + +- (CGSize)moBoundsSize { + return self.bounds.size; +} + +- (CGPoint)moBoundsCenter { + CGRect bounds = self.bounds; + return CGPointMake(bounds.origin.x + (bounds.size.width * 0.5f), bounds.origin.y + (bounds.size.height * 0.5f)); +} + +- (CGFloat)moBoundsCX { + return CGRectGetMidX(self.bounds); +} + +- (CGFloat)moBoundsCY { + return CGRectGetMidY(self.bounds); +} + +- (CGFloat)moBoundsWidth { + return CGRectGetWidth(self.bounds); +} + +- (CGFloat)moBoundsHeight { + return CGRectGetHeight(self.bounds); +} + +- (void)setMoZPosition:(CGFloat)moZPosition { + self.layer.zPosition = moZPosition; +} + +- (CGFloat)moZPosition { + return self.layer.zPosition; +} + +- (void)setMoCornerRadius:(CGFloat)moCornerRadius { + self.layer.cornerRadius = moCornerRadius; +} + +- (CGFloat)moCornerRadius { + return self.layer.cornerRadius; +} + +- (void)setMoBorderWidth:(CGFloat)moBorderWidth { + self.layer.borderWidth = moBorderWidth; +} + +- (CGFloat)moBorderWidth { + return self.layer.borderWidth; +} + +- (void)setMoBorderColor:(UIColor*)moBorderColor { + self.layer.borderColor = moBorderColor.CGColor; +} + +- (UIColor*)moBorderColor { + return [UIColor colorWithCGColor:self.layer.borderColor]; +} + +- (void)setMoShadowColor:(UIColor*)moShadowColor { + self.layer.shadowColor = moShadowColor.CGColor; +} + +- (UIColor*)moShadowColor { + return [UIColor colorWithCGColor:self.layer.shadowColor]; +} + +- (void)setMoShadowOpacity:(CGFloat)moShadowOpacity { + self.layer.shadowOpacity = moShadowOpacity; +} + +- (CGFloat)moShadowOpacity { + return self.layer.shadowOpacity; +} + +- (void)setMoShadowOffset:(CGSize)moShadowOffset { + self.layer.shadowOffset = moShadowOffset; +} + +- (CGSize)moShadowOffset { + return self.layer.shadowOffset; +} + +- (void)setMoShadowRadius:(CGFloat)moShadowRadius { + self.layer.shadowRadius = moShadowRadius; +} + +- (CGFloat)moShadowRadius { + return self.layer.shadowRadius; +} + +- (void)setMoShadowPath:(UIBezierPath*)moShadowPath { + self.layer.shadowPath = moShadowPath.CGPath; +} + +- (UIBezierPath*)moShadowPath { + return [UIBezierPath bezierPathWithCGPath:self.layer.shadowPath]; +} + +#pragma mark Public + +- (NSArray*)moResponders { + NSMutableArray* result = NSMutableArray.array; + if(self.canBecomeFirstResponder == YES) { + [result addObject:self]; + } + for(UIView* view in self.subviews) { + [result addObjectsFromArray:view.moResponders]; + } + [result sortWithOptions:0 usingComparator:^NSComparisonResult(UIView* viewA, UIView* viewB) { + CGRect aFrame = [viewA convertRect:[viewA bounds] toView:nil], bFrame = [viewB convertRect:[viewB bounds] toView:nil]; + CGFloat aOrder = [viewA.layer zPosition], bOrder = [viewB.layer zPosition]; + if(aOrder < bOrder) { + return NSOrderedAscending; + } else if(aOrder > bOrder) { + return NSOrderedDescending; + } else { + if(aFrame.origin.y < bFrame.origin.y) { + return NSOrderedAscending; + } else if(aFrame.origin.y > bFrame.origin.y) { + return NSOrderedDescending; + } else { + if(aFrame.origin.x < bFrame.origin.x) { + return NSOrderedAscending; + } else if(aFrame.origin.x > bFrame.origin.x) { + return NSOrderedDescending; + } + } + } + return NSOrderedSame; + }]; + return result; +} + +- (BOOL)moIsContainsSubview:(UIView*)subview { + NSArray* subviews = self.subviews; + if([subviews containsObject:subview] == YES) { + return YES; + } + for(UIView* view in subviews) { + if([view moIsContainsSubview:subview] == YES) { + return YES; + } + } + return NO; +} + +- (void)moRemoveSubview:(UIView*)subview { + [subview removeFromSuperview]; +} + +- (void)moSetSubviews:(NSArray*)subviews { + NSArray* currentSubviews = self.subviews; + if([currentSubviews isEqualToArray:subviews] == NO) { + for(UIView* view in currentSubviews) { + [view removeFromSuperview]; + } + for(UIView* view in subviews) { + [self addSubview:view]; + } + } +} + +- (void)moRemoveAllSubviews { + for(UIView* view in self.subviews) { + [view removeFromSuperview]; + } +} + +- (void)moBlinkBackgroundColor:(UIColor*)color duration:(NSTimeInterval)duration timeout:(NSTimeInterval)timeout { + UIColor* prevColor = self.backgroundColor; + [UIView animateWithDuration:duration + animations:^{ + self.backgroundColor = color; + } completion:^(BOOL finished __unused) { + [UIView animateWithDuration:duration + delay:timeout + options:0 + animations:^{ + self.backgroundColor = prevColor; + } + completion:nil]; + }]; +} + +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation constant:(CGFloat)constant { + return [self moAddConstraintAttribute:constraintAttribute relation:relation constant:constant priority:UILayoutPriorityRequired multiplier:1.0f]; +} + +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation constant:(CGFloat)constant priority:(UILayoutPriority)priority { + return [self moAddConstraintAttribute:constraintAttribute relation:relation constant:constant priority:priority multiplier:1.0f]; +} + +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation constant:(CGFloat)constant priority:(UILayoutPriority)priority multiplier:(CGFloat)multiplier { + NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem:self attribute:constraintAttribute relatedBy:relation toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:multiplier constant:constant]; + constraint.priority = priority; + [self addConstraint:constraint]; + return constraint; +} + +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation attribute:(NSLayoutAttribute)attribute constant:(CGFloat)constant { + return [self moAddConstraintAttribute:constraintAttribute relation:relation view:self.superview attribute:attribute constant:constant priority:UILayoutPriorityRequired multiplier:1.0f]; +} + +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation attribute:(NSLayoutAttribute)attribute constant:(CGFloat)constant priority:(UILayoutPriority)priority { + return [self moAddConstraintAttribute:constraintAttribute relation:relation view:self.superview attribute:attribute constant:constant priority:priority multiplier:1.0f]; +} + +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation attribute:(NSLayoutAttribute)attribute constant:(CGFloat)constant priority:(UILayoutPriority)priority multiplier:(CGFloat)multiplier { + return [self moAddConstraintAttribute:constraintAttribute relation:relation view:self.superview attribute:attribute constant:constant priority:priority multiplier:multiplier]; +} + +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation view:(UIView*)view attribute:(NSLayoutAttribute)attribute constant:(CGFloat)constant { + return [self moAddConstraintAttribute:constraintAttribute relation:relation view:view attribute:attribute constant:constant priority:UILayoutPriorityRequired multiplier:1.0f]; +} + +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation view:(UIView*)view attribute:(NSLayoutAttribute)attribute constant:(CGFloat)constant priority:(UILayoutPriority)priority { + return [self moAddConstraintAttribute:constraintAttribute relation:relation view:view attribute:attribute constant:constant priority:priority multiplier:1.0f]; +} + +- (NSLayoutConstraint*)moAddConstraintAttribute:(NSLayoutAttribute)constraintAttribute relation:(NSLayoutRelation)relation view:(UIView*)view attribute:(NSLayoutAttribute)attribute constant:(CGFloat)constant priority:(UILayoutPriority)priority multiplier:(CGFloat)multiplier { + NSLayoutConstraint* constraint = [NSLayoutConstraint constraintWithItem:self attribute:constraintAttribute relatedBy:relation toItem:view attribute:attribute multiplier:multiplier constant:constant]; + constraint.priority = priority; + [self.superview addConstraint:constraint]; + return constraint; +} + +- (void)moRemoveAllConstraints { + [self removeConstraints:self.constraints]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface UIScrollView (MobilyUI_Keyboard) + +@property(nonatomic, readwrite, assign) BOOL moKeyboardShowed; +@property(nonatomic, readwrite, weak) UIResponder* moKeyboardResponder; +@property(nonatomic, readwrite, assign) UIEdgeInsets moKeyboardContentInset; +@property(nonatomic, readwrite, assign) UIEdgeInsets moKeyboardIndicatorInset; + +@end + +/*--------------------------------------------------*/ + +@implementation UIScrollView (MobilyUI) + +#pragma mark NSKeyValueCoding + +MOBILY_DEFINE_VALIDATE_POINT(СontentOffset) +MOBILY_DEFINE_VALIDATE_SIZE(ContentSize) +MOBILY_DEFINE_VALIDATE_EDGE_INSETS(ContentInset) +MOBILY_DEFINE_VALIDATE_BOOL(DirectionalLockEnabled) +MOBILY_DEFINE_VALIDATE_BOOL(Bounces) +MOBILY_DEFINE_VALIDATE_BOOL(AlwaysBounceVertical) +MOBILY_DEFINE_VALIDATE_BOOL(AlwaysBounceHorizontal) +MOBILY_DEFINE_VALIDATE_BOOL(PagingEnabled) +MOBILY_DEFINE_VALIDATE_BOOL(ScrollEnabled) +MOBILY_DEFINE_VALIDATE_BOOL(ShowsHorizontalScrollIndicator) +MOBILY_DEFINE_VALIDATE_BOOL(ShowsVerticalScrollIndicator) +MOBILY_DEFINE_VALIDATE_EDGE_INSETS(ScrollIndicatorInsets) +MOBILY_DEFINE_VALIDATE_SCROLL_VIEW_INDICATOR_STYLE(IndicatorStyle) +MOBILY_DEFINE_VALIDATE_NUMBER(DecelerationRate) +MOBILY_DEFINE_VALIDATE_BOOL(DelaysContentTouches) +MOBILY_DEFINE_VALIDATE_BOOL(CanCancelContentTouches) +MOBILY_DEFINE_VALIDATE_NUMBER(MinimumZoomScale) +MOBILY_DEFINE_VALIDATE_NUMBER(MaximumZoomScale) +MOBILY_DEFINE_VALIDATE_NUMBER(ZoomScale) +MOBILY_DEFINE_VALIDATE_NUMBER(BouncesZoom) +MOBILY_DEFINE_VALIDATE_SCROLL_VIEW_KEYBOARD_DISMISS_MODE(KeyboardDismissMode) + +#pragma mark Property + +- (void)setMoKeyboardShowed:(BOOL)moKeyboardShowed { + if(self.moKeyboardShowed != moKeyboardShowed) { + if(moKeyboardShowed == NO) { + if([self isKindOfClass:MobilyDataView.class] == YES) { + MobilyDataView* dataView = (MobilyDataView*)self; + dataView.containerInsets = self.moKeyboardContentInset; + } else { + self.contentInset = self.moKeyboardContentInset; + self.scrollIndicatorInsets = self.moKeyboardIndicatorInset; + } + self.moKeyboardResponder = nil; + } + objc_setAssociatedObject(self, @selector(moKeyboardShowed), @(moKeyboardShowed), OBJC_ASSOCIATION_RETAIN_NONATOMIC); + if(moKeyboardShowed == YES) { + if([self isKindOfClass:MobilyDataView.class] == YES) { + MobilyDataView* dataView = (MobilyDataView*)self; + self.moKeyboardContentInset = dataView.containerInsets; + } else { + self.moKeyboardContentInset = self.contentInset; + self.moKeyboardIndicatorInset = self.scrollIndicatorInsets; + } + self.moKeyboardResponder = [UIResponder moCurrentFirstResponderInView:self]; + } + } +} + +- (BOOL)moKeyboardShowed { + return [objc_getAssociatedObject(self, @selector(moKeyboardShowed)) boolValue]; +} + +- (void)setMoKeyboardResponder:(UIResponder*)moKeyboardResponder { + objc_setAssociatedObject(self, @selector(moKeyboardResponder), moKeyboardResponder, OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (UIResponder*)moKeyboardResponder { + return objc_getAssociatedObject(self, @selector(moKeyboardResponder)); +} + +- (void)setMoKeyboardContentInset:(UIEdgeInsets)moKeyboardContentInset { + objc_setAssociatedObject(self, @selector(moKeyboardContentInset), [NSValue valueWithUIEdgeInsets:moKeyboardContentInset], OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (UIEdgeInsets)moKeyboardContentInset { + return [objc_getAssociatedObject(self, @selector(moKeyboardContentInset)) UIEdgeInsetsValue]; +} + +- (void)setMoKeyboardIndicatorInset:(UIEdgeInsets)moKeyboardIndicatorInset { + objc_setAssociatedObject(self, @selector(moKeyboardIndicatorInset), [NSValue valueWithUIEdgeInsets:moKeyboardIndicatorInset], OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (UIEdgeInsets)moKeyboardIndicatorInset { + return [objc_getAssociatedObject(self, @selector(moKeyboardIndicatorInset)) UIEdgeInsetsValue]; +} + +- (void)setMoKeyboardInset:(UIEdgeInsets)moKeyboardInset { + objc_setAssociatedObject(self, @selector(moKeyboardInset), [NSValue valueWithUIEdgeInsets:moKeyboardInset], OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +- (UIEdgeInsets)moKeyboardInset { + NSValue* value = objc_getAssociatedObject(self, @selector(moKeyboardInset)); + if(value != nil) { + return value.UIEdgeInsetsValue; + } + return UIEdgeInsetsMake(2.0f, 0.0f, 2.0f, 0.0f); +} + +- (void)setMoContentOffsetX:(CGFloat)moContentOffsetX { + [self setContentOffset:CGPointMake(moContentOffsetX, self.contentOffset.y)]; +} + +- (CGFloat)moContentOffsetX { + return self.contentOffset.x; +} + +- (void)setMoContentOffsetY:(CGFloat)moContentOffsetY { + [self setContentOffset:CGPointMake(self.contentOffset.x, moContentOffsetY)]; +} + +- (CGFloat)moContentOffsetY { + return self.contentOffset.y; +} + +- (void)setMoContentSizeWidth:(CGFloat)moContentSizeWidth { + [self setContentSize:CGSizeMake(moContentSizeWidth, self.contentSize.height)]; +} + +- (CGFloat)moContentSizeWidth { + return self.contentSize.width; +} + +- (void)setMoContentSizeHeight:(CGFloat)moContentSizeHeight { + self.contentSize = CGSizeMake(self.contentSize.width, moContentSizeHeight); +} + +- (CGFloat)moContentSizeHeight { + return self.contentSize.height; +} + +- (void)setMoContentInsetTop:(CGFloat)moContentInsetTop { + self.contentInset = UIEdgeInsetsMake(moContentInsetTop, self.contentInset.left, self.contentInset.bottom, self.contentInset.right); +} + +- (CGFloat)moContentInsetTop { + return self.contentInset.top; +} + +- (void)setMoContentInsetRight:(CGFloat)moContentInsetRight { + self.contentInset = UIEdgeInsetsMake(self.contentInset.top, self.contentInset.left, self.contentInset.bottom, moContentInsetRight); +} + +- (CGFloat)moContentInsetRight { + return self.contentInset.right; +} + +- (void)setMoContentInsetBottom:(CGFloat)moContentInsetBottom { + self.contentInset = UIEdgeInsetsMake(self.contentInset.top, self.contentInset.left, moContentInsetBottom, self.contentInset.right); +} + +- (CGFloat)moContentInsetBottom { + return self.contentInset.bottom; +} + +- (void)setMoContentInsetLeft:(CGFloat)moContentInsetLeft { + self.contentInset = UIEdgeInsetsMake(self.contentInset.top, moContentInsetLeft, self.contentInset.bottom, self.contentInset.right); +} + +- (CGFloat)moContentInsetLeft { + return self.contentInset.left; +} + +- (void)setMoScrollIndicatorInsetTop:(CGFloat)moScrollIndicatorInsetTop { + self.scrollIndicatorInsets = UIEdgeInsetsMake(moScrollIndicatorInsetTop, self.scrollIndicatorInsets.left, self.scrollIndicatorInsets.bottom, self.scrollIndicatorInsets.right); +} + +- (CGFloat)moScrollIndicatorInsetTop { + return self.scrollIndicatorInsets.top; +} + +- (void)setMoScrollIndicatorInsetRight:(CGFloat)moScrollIndicatorInsetRight { + self.scrollIndicatorInsets = UIEdgeInsetsMake(self.scrollIndicatorInsets.top, self.scrollIndicatorInsets.left, self.scrollIndicatorInsets.bottom, moScrollIndicatorInsetRight); +} + +- (CGFloat)moScrollIndicatorInsetRight { + return self.scrollIndicatorInsets.right; +} + +- (void)setMoScrollIndicatorInsetBottom:(CGFloat)moScrollIndicatorInsetBottom { + self.scrollIndicatorInsets = UIEdgeInsetsMake(self.scrollIndicatorInsets.top, self.scrollIndicatorInsets.left, moScrollIndicatorInsetBottom, self.scrollIndicatorInsets.right); +} + +- (CGFloat)moScrollIndicatorInsetBottom { + return self.scrollIndicatorInsets.bottom; +} + +- (void)setMoScrollIndicatorInsetLeft:(CGFloat)moScrollIndicatorInsetLeft { + self.scrollIndicatorInsets = UIEdgeInsetsMake(self.scrollIndicatorInsets.top, moScrollIndicatorInsetLeft, self.scrollIndicatorInsets.bottom, self.scrollIndicatorInsets.right); +} + +- (CGFloat)moScrollIndicatorInsetLeft { + return self.scrollIndicatorInsets.left; +} + +- (CGRect)moVisibleBounds { + return UIEdgeInsetsInsetRect(self.bounds, self.contentInset); +} + +#pragma mark Public + +- (void)setMoContentOffsetX:(CGFloat)moContentOffsetX animated:(BOOL)animated { + [self setContentOffset:CGPointMake(moContentOffsetX, self.contentOffset.y) animated:animated]; +} + +- (void)setMoContentOffsetY:(CGFloat)moContentOffsetY animated:(BOOL)animated { + [self setContentOffset:CGPointMake(self.contentOffset.x, moContentOffsetY) animated:animated]; +} + +- (void)moRegisterAdjustmentResponder { + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(adjustmentNotificationKeyboardShow:) name:UIKeyboardWillShowNotification object:nil]; + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(adjustmentNotificationKeyboardShow:) name:UIKeyboardDidShowNotification object:nil]; + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(adjustmentNotificationKeyboardHide:) name:UIKeyboardWillHideNotification object:nil]; + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(adjustmentNotificationKeyboardHide:) name:UIKeyboardDidHideNotification object:nil]; +} + +- (void)moUnregisterAdjustmentResponder { + [NSNotificationCenter.defaultCenter removeObserver:self name:UIKeyboardWillShowNotification object:nil]; + [NSNotificationCenter.defaultCenter removeObserver:self name:UIKeyboardDidShowNotification object:nil]; + [NSNotificationCenter.defaultCenter removeObserver:self name:UIKeyboardWillHideNotification object:nil]; + [NSNotificationCenter.defaultCenter removeObserver:self name:UIKeyboardDidHideNotification object:nil]; +} + +#pragma mark UIKeyboarNotification + +- (void)adjustmentNotificationKeyboardShow:(NSNotification*)notification { + self.moKeyboardShowed = YES; + CGRect scrollRect = [self convertRect:self.bounds toView:nil]; + CGRect keyboardRect = [[notification userInfo][UIKeyboardFrameEndUserInfoKey] CGRectValue]; + CGRect intersectionRect = CGRectIntersection(scrollRect, keyboardRect); + if(CGRectIsNull(intersectionRect) == NO) { + if(intersectionRect.size.height > MOBILY_EPSILON) { + if([self isKindOfClass:MobilyDataView.class] == YES) { + MobilyDataView* dataView = (MobilyDataView*)self; + UIEdgeInsets containerInsets = dataView.containerInsets; + containerInsets.bottom = intersectionRect.size.height; + dataView.containerInsets = containerInsets; + } else { + UIEdgeInsets contentInsets = self.contentInset; + UIEdgeInsets indicatorInsets = self.scrollIndicatorInsets; + contentInsets.bottom = indicatorInsets.bottom = intersectionRect.size.height; + self.contentInset = contentInsets; + self.scrollIndicatorInsets = indicatorInsets; + } + } + if([self.moKeyboardResponder isKindOfClass:UIView.class] == YES) { + CGRect visibleRect = UIEdgeInsetsInsetRect(self.moVisibleBounds, self.moKeyboardInset); + CGRect responderRect = [(UIView*)self.moKeyboardResponder convertRect:((UIView*)self.moKeyboardResponder).bounds toView:self]; + if(CGRectContainsRect(visibleRect, responderRect) == NO) { + CGPoint contentOffset = self.contentOffset; + CGFloat vrsx = CGRectGetMinX(visibleRect), vrsy = CGRectGetMinY(visibleRect); + CGFloat vrex = CGRectGetMaxX(visibleRect), vrey = CGRectGetMaxY(visibleRect); + CGFloat vrcx = CGRectGetMidX(visibleRect), vrcy = CGRectGetMidY(visibleRect); + CGFloat rrsx = CGRectGetMinX(responderRect), rrsy = CGRectGetMinY(responderRect); + CGFloat rrex = CGRectGetMaxX(responderRect), rrey = CGRectGetMaxY(responderRect); + CGFloat rrcx = CGRectGetMidX(responderRect), rrcy = CGRectGetMidY(responderRect); + if((vrex - vrsx) < (rrex - rrsx)) { + contentOffset.x += vrcx - rrcx; + } else if(vrsx > rrsx) { + contentOffset.x -= vrsx - rrsx; + } else if(vrex < rrex) { + contentOffset.x -= vrex - rrex; + } + if((vrey - vrsy) < (rrey - rrsy)) { + contentOffset.y += vrcy - rrcy; + } else if(vrsy > rrsy) { + contentOffset.y -= vrsy - rrsy; + } else if(vrey < rrey) { + contentOffset.y -= vrey - rrey; + } + [self setContentOffset:contentOffset animated:YES]; + } + } + } +} + +- (void)adjustmentNotificationKeyboardHide:(NSNotification* __unused)notification { + self.moKeyboardShowed = NO; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UITabBar (MobilyUI) + +#pragma mark NSKeyValueCoding + +MOBILY_DEFINE_VALIDATE_COLOR(TintColor) +MOBILY_DEFINE_VALIDATE_COLOR(BarTintColor) +MOBILY_DEFINE_VALIDATE_COLOR(SelectedImageTintColor) +MOBILY_DEFINE_VALIDATE_IMAGE(BackgroundImage) +MOBILY_DEFINE_VALIDATE_IMAGE(SelectionIndicatorImage) +MOBILY_DEFINE_VALIDATE_IMAGE(ShadowImage) +MOBILY_DEFINE_VALIDATE_TAB_BAR_ITEM_POSITIONING(ItemPositioning); +MOBILY_DEFINE_VALIDATE_NUMBER(ItemWidth) +MOBILY_DEFINE_VALIDATE_NUMBER(ItemSpacing) +MOBILY_DEFINE_VALIDATE_BAR_STYLE(BarStyle) +MOBILY_DEFINE_VALIDATE_BOOL(Translucent) +MOBILY_DEFINE_VALIDATE_NUMBER(SelectedItemIndex) + +#pragma mark Property + +- (void)setMoSelectedItemIndex:(NSUInteger)moSelectedItemIndex { + self.selectedItem = (self.items)[moSelectedItemIndex]; +} + +- (NSUInteger)moSelectedItemIndex { + return [self.items indexOfObject:self.selectedItem]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UINavigationBar (MobilyUI) + +#pragma mark NSKeyValueCoding + +#pragma mark Property + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UILabel (MobilyUI) + +#pragma mark NSKeyValueCoding + +MOBILY_DEFINE_VALIDATE_STRING(Text) +MOBILY_DEFINE_VALIDATE_FONT(Font) +MOBILY_DEFINE_VALIDATE_COLOR(TextColor) +MOBILY_DEFINE_VALIDATE_COLOR(ShadowColor) +MOBILY_DEFINE_VALIDATE_SIZE(ShadowOffset) +MOBILY_DEFINE_VALIDATE_TEXT_ALIGNMENT(TextAlignment) +MOBILY_DEFINE_VALIDATE_LINE_BREAKMODE(LineBreakMode) +MOBILY_DEFINE_VALIDATE_COLOR(HighlightedTextColor) +MOBILY_DEFINE_VALIDATE_BOOL(Highlighted) +MOBILY_DEFINE_VALIDATE_BOOL(Enabled) +MOBILY_DEFINE_VALIDATE_NUMBER(NumberOfLines) +MOBILY_DEFINE_VALIDATE_BOOL(AdjustsFontSizeToFitWidth) +MOBILY_DEFINE_VALIDATE_BOOL(AdjustsLetterSpacingToFitWidth) +MOBILY_DEFINE_VALIDATE_NUMBER(MinimumFontSize) +MOBILY_DEFINE_VALIDATE_BASELINE_ADJUSTMENT(BaselineAdjustment) +MOBILY_DEFINE_VALIDATE_NUMBER(MinimumScaleFactor) +MOBILY_DEFINE_VALIDATE_NUMBER(PreferredMaxLayoutWidth) + +#pragma mark Public + +- (CGSize)moImplicitSize { + return [self moImplicitSizeForSize:CGSizeMake(NSIntegerMax, NSIntegerMax)]; +} + +- (CGSize)moImplicitSizeForWidth:(CGFloat)width { + return [self moImplicitSizeForSize:CGSizeMake(width, NSIntegerMax)]; +} + +- (CGSize)moImplicitSizeForSize:(CGSize)size { + return [self.text moImplicitSizeWithFont:self.font forSize:size lineBreakMode:self.lineBreakMode]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UIButton (MobilyUI) + +#pragma mark NSKeyValueCoding + +MOBILY_DEFINE_VALIDATE_EDGE_INSETS(ContentEdgeInsets) +MOBILY_DEFINE_VALIDATE_EDGE_INSETS(TitleEdgeInsets) +MOBILY_DEFINE_VALIDATE_BOOL(ReversesTitleShadowWhenHighlighted) +MOBILY_DEFINE_VALIDATE_EDGE_INSETS(ImageEdgeInsets) +MOBILY_DEFINE_VALIDATE_BOOL(AdjustsImageWhenHighlighted) +MOBILY_DEFINE_VALIDATE_BOOL(AdjustsImageWhenDisabled) +MOBILY_DEFINE_VALIDATE_BOOL(ShowsTouchWhenHighlighted) +MOBILY_DEFINE_VALIDATE_COLOR(TintColor) + +MOBILY_DEFINE_VALIDATE_STRING(MoNormalTitle) +MOBILY_DEFINE_VALIDATE_COLOR(MoNormalTitleColor) +MOBILY_DEFINE_VALIDATE_COLOR(MoNormalTitleShadowColor) +MOBILY_DEFINE_VALIDATE_IMAGE(MoNormalImage) +MOBILY_DEFINE_VALIDATE_IMAGE(MoNormalBackgroundImage) +MOBILY_DEFINE_VALIDATE_STRING(MoHighlightedTitle) +MOBILY_DEFINE_VALIDATE_COLOR(MoHighlightedTitleColor) +MOBILY_DEFINE_VALIDATE_COLOR(MoHighlightedTitleShadowColor) +MOBILY_DEFINE_VALIDATE_IMAGE(MoHighlightedImage) +MOBILY_DEFINE_VALIDATE_IMAGE(MoHighlightedBackgroundImage) +MOBILY_DEFINE_VALIDATE_STRING(MoDisabledTitle) +MOBILY_DEFINE_VALIDATE_COLOR(MoDisabledTitleColor) +MOBILY_DEFINE_VALIDATE_COLOR(MoDisabledTitleShadowColor) +MOBILY_DEFINE_VALIDATE_IMAGE(MoDisabledImage) +MOBILY_DEFINE_VALIDATE_IMAGE(MoDisabledBackgroundImage) +MOBILY_DEFINE_VALIDATE_STRING(MoSelectedTitle) +MOBILY_DEFINE_VALIDATE_COLOR(MoSelectedTitleColor) +MOBILY_DEFINE_VALIDATE_COLOR(MoSelectedTitleShadowColor) +MOBILY_DEFINE_VALIDATE_IMAGE(MoSelectedImage) +MOBILY_DEFINE_VALIDATE_IMAGE(MoSelectedBackgroundImage) + +#pragma mark Property + +- (void)setMoNormalTitle:(NSString*)moNormalTitle { + [self setTitle:moNormalTitle forState:UIControlStateNormal]; +} + +- (NSString*)moNormalTitle { + return [self titleForState:UIControlStateNormal]; +} + +- (void)setMoNormalTitleColor:(UIColor*)moNormalTitleColor { + [self setTitleColor:moNormalTitleColor forState:UIControlStateNormal]; +} + +- (UIColor*)moNormalTitleColor { + return [self titleColorForState:UIControlStateNormal]; +} + +- (void)setMoNormalTitleShadowColor:(UIColor*)moNormalTitleShadowColor { + [self setTitleShadowColor:moNormalTitleShadowColor forState:UIControlStateNormal]; +} + +- (UIColor*)moNormalTitleShadowColor { + return [self titleShadowColorForState:UIControlStateNormal]; +} + +- (void)setMoNormalImage:(UIImage*)moNormalImage { + [self setImage:moNormalImage forState:UIControlStateNormal]; +} + +- (UIImage*)moNormalImage { + return [self imageForState:UIControlStateNormal]; +} + +- (void)setMoNormalBackgroundImage:(UIImage*)moNormalBackgroundImage { + [self setBackgroundImage:moNormalBackgroundImage forState:UIControlStateNormal]; +} + +- (UIImage*)moNormalBackgroundImage { + return [self backgroundImageForState:UIControlStateNormal]; +} + +- (void)setMoHighlightedTitle:(NSString*)moHighlightedTitle { + [self setTitle:moHighlightedTitle forState:UIControlStateHighlighted]; +} + +- (NSString*)moHighlightedTitle { + return [self titleForState:UIControlStateHighlighted]; +} + +- (void)setMoHighlightedTitleColor:(UIColor*)moHighlightedTitleColor { + [self setTitleColor:moHighlightedTitleColor forState:UIControlStateHighlighted]; +} + +- (UIColor*)moHighlightedTitleColor { + return [self titleColorForState:UIControlStateHighlighted]; +} + +- (void)setMoHighlightedTitleShadowColor:(UIColor*)moHighlightedTitleShadowColor { + [self setTitleShadowColor:moHighlightedTitleShadowColor forState:UIControlStateHighlighted]; +} + +- (UIColor*)moHighlightedTitleShadowColor { + return [self titleShadowColorForState:UIControlStateHighlighted]; +} + +- (void)setMoHighlightedImage:(UIImage*)moHighlightedImage { + [self setImage:moHighlightedImage forState:UIControlStateHighlighted]; +} + +- (UIImage*)moHighlightedImage { + return [self imageForState:UIControlStateHighlighted]; +} + +- (void)setMoHighlightedBackgroundImage:(UIImage*)moHighlightedBackgroundImage { + [self setBackgroundImage:moHighlightedBackgroundImage forState:UIControlStateHighlighted]; +} + +- (UIImage*)moHighlightedBackgroundImage { + return [self backgroundImageForState:UIControlStateHighlighted]; +} + +- (void)setMoSelectedTitle:(NSString*)moSelectedTitle { + [self setTitle:moSelectedTitle forState:UIControlStateSelected]; +} + +- (NSString*)moSelectedTitle { + return [self titleForState:UIControlStateSelected]; +} + +- (void)setMoSelectedTitleColor:(UIColor*)moSelectedTitleColor { + [self setTitleColor:moSelectedTitleColor forState:UIControlStateSelected]; +} + +- (UIColor*)moSelectedTitleColor { + return [self titleColorForState:UIControlStateSelected]; +} + +- (void)setMoSelectedTitleShadowColor:(UIColor*)moSelectedTitleShadowColor { + [self setTitleShadowColor:moSelectedTitleShadowColor forState:UIControlStateSelected]; +} + +- (UIColor*)moSelectedTitleShadowColor { + return [self titleShadowColorForState:UIControlStateSelected]; +} + +- (void)setMoSelectedImage:(UIImage*)moSelectedImage { + [self setImage:moSelectedImage forState:UIControlStateSelected]; +} + +- (UIImage*)moSelectedImage { + return [self imageForState:UIControlStateSelected]; +} + +- (void)setMoSelectedBackgroundImage:(UIImage*)moSelectedBackgroundImage { + [self setBackgroundImage:moSelectedBackgroundImage forState:UIControlStateSelected]; +} + +- (UIImage*)moSelectedBackgroundImage { + return [self backgroundImageForState:UIControlStateSelected]; +} + +- (void)setMoDisabledTitle:(NSString*)moDisabledTitle { + [self setTitle:moDisabledTitle forState:UIControlStateDisabled]; +} + +- (NSString*)moDisabledTitle { + return [self titleForState:UIControlStateDisabled]; +} + +- (void)setMoDisabledTitleColor:(UIColor*)moDisabledTitleColor { + [self setTitleColor:moDisabledTitleColor forState:UIControlStateDisabled]; +} + +- (UIColor*)moDisabledTitleColor { + return [self titleColorForState:UIControlStateDisabled]; +} + +- (void)setMoDisabledTitleShadowColor:(UIColor*)moDisabledTitleShadowColor { + [self setTitleShadowColor:moDisabledTitleShadowColor forState:UIControlStateDisabled]; +} + +- (UIColor*)moDisabledTitleShadowColor { + return [self titleShadowColorForState:UIControlStateDisabled]; +} + +- (void)setMoDisabledImage:(UIImage*)moDisabledImage { + [self setImage:moDisabledImage forState:UIControlStateDisabled]; +} + +- (UIImage*)moDisabledImage { + return [self imageForState:UIControlStateDisabled]; +} + +- (void)setMoDisabledBackgroundImage:(UIImage*)moDisabledBackgroundImage { + [self setBackgroundImage:moDisabledBackgroundImage forState:UIControlStateDisabled]; +} + +- (UIImage*)moDisabledBackgroundImage { + return [self backgroundImageForState:UIControlStateDisabled]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UIViewController (MobilyUI) + +#pragma mark NSKeyValueCoding + +MOBILY_DEFINE_VALIDATE_STRING(Title) +MOBILY_DEFINE_VALIDATE_BOOL(HidesBottomBarWhenPushed) + +#pragma mark Public + +- (void)moLoadViewIfNeed { + if(self.isViewLoaded == NO) { + [self loadView]; + } +} + +- (void)moUnloadViewIfPossible { + if(self.isViewLoaded == YES) { + if(self.view.window == nil) { + self.view = nil; + } + } +} + +- (void)moUnloadView { + if(self.isViewLoaded == YES) { + self.view = nil; + } +} + +- (UIViewController*)moCurrentController { + return [UIViewController _moCurrentController:self]; +} + +#pragma mark Private + ++ (UIViewController*)_moCurrentController:(UIViewController*)rootViewController { + if([rootViewController presentedViewController] != nil) { + return [self _moCurrentController:[rootViewController presentedViewController]]; + } + if([rootViewController isKindOfClass:UINavigationController.class] == YES) { + UINavigationController* navigationController = (UINavigationController*)rootViewController; + return [self _moCurrentController:navigationController.topViewController]; + } else if([rootViewController isKindOfClass:UITabBarController.class] == YES) { + UITabBarController* tabBarController = (UITabBarController*)rootViewController; + return [self _moCurrentController:tabBarController.selectedViewController]; + } else if([rootViewController isKindOfClass:MobilySlideController.class] == YES) { + MobilySlideController* slideController = (MobilySlideController*)rootViewController; + if(slideController.isShowedLeftController == YES) { + return [self _moCurrentController:slideController.leftController]; + } else if(slideController.isShowedRightController == YES) { + return [self _moCurrentController:slideController.rightController]; + } + return [self _moCurrentController:slideController.centerController]; + } + return rootViewController; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UINavigationController (MobilyUI) + +#pragma mark NSKeyValueCoding + +MOBILY_DEFINE_VALIDATE_BOOL(NavigationBarHidden) +MOBILY_DEFINE_VALIDATE_BOOL(ToolbarHidden) +MOBILY_DEFINE_VALIDATE_BOOL(MoTranslucent) +MOBILY_DEFINE_VALIDATE_COLOR(MoTintColor) +MOBILY_DEFINE_VALIDATE_COLOR(MoBarTintColor) +MOBILY_DEFINE_VALIDATE_IMAGE(MoShadowImage) +//MOBILY_DEFINE_VALIDATE_TEXT_ATTRIBUTES(MoTitleTextAttributes) +MOBILY_DEFINE_VALIDATE_IMAGE(MoBackIndicatorImage) +MOBILY_DEFINE_VALIDATE_IMAGE(MoBackIndicatorTransitionMaskImage) + +#pragma mark Property + +- (void)setMoTranslucent:(BOOL)moTranslucent { + [self.navigationBar setTranslucent:moTranslucent]; +} + +- (BOOL)moTranslucent { + return [self.navigationBar isTranslucent]; +} + +- (void)setMoTintColor:(UIColor*)moTintColor { + [self.navigationBar setTintColor:moTintColor]; +} + +- (UIColor*)moTintColor { + return [self.navigationBar tintColor]; +} + +- (void)setMoBarTintColor:(UIColor*)moBarTintColor { + [self.navigationBar setBarTintColor:moBarTintColor]; +} + +- (UIColor*)moBarTintColor { + return [self.navigationBar barTintColor]; +} + +- (void)setMoShadowImage:(UIImage*)moShadowImage { + [self.navigationBar setShadowImage:moShadowImage]; +} + +- (UIImage*)moShadowImage { + return [self.navigationBar shadowImage]; +} + +- (void)setMoTitleTextAttributes:(NSDictionary*)moTitleTextAttributes { + [self.navigationBar setTitleTextAttributes:moTitleTextAttributes]; +} + +- (NSDictionary*)moTitleTextAttributes { + return [self.navigationBar titleTextAttributes]; +} + +- (void)setMoBackIndicatorImage:(UIImage*)moBackIndicatorImage { + [self.navigationBar setBackIndicatorImage:moBackIndicatorImage]; +} + +- (UIImage*)moBackIndicatorImage { + return [self.navigationBar backIndicatorImage]; +} + +- (void)setMoBackIndicatorTransitionMaskImage:(UIImage*)moBackIndicatorTransitionMaskImage { + [self.navigationBar setBackIndicatorTransitionMaskImage:moBackIndicatorTransitionMaskImage]; +} + +- (UIImage*)moBackIndicatorTransitionMaskImage { + return [self.navigationBar backIndicatorTransitionMaskImage]; +} + +- (UIViewController*)moRootController { + NSArray* viewControllers = self.viewControllers; + if(viewControllers.count > 0) { + return viewControllers[0]; + } + return nil; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation UINavigationItem (MobilyUI) + +#pragma mark NSKeyValueCoding + +#pragma mark Property + +- (UIBarButtonItem*)moAddLeftBarFixedSpace:(CGFloat)fixedSpaceWidth animated:(BOOL)animated { + UIBarButtonItem* fixedSpaceItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; + [fixedSpaceItem setWidth:fixedSpaceWidth]; + [self moAddLeftBarButtonItem:fixedSpaceItem animated:animated]; + return fixedSpaceItem; +} + +- (UIBarButtonItem*)moAddRightBarFixedSpace:(CGFloat)fixedSpaceWidth animated:(BOOL)animated { + UIBarButtonItem* fixedSpaceItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; + [fixedSpaceItem setWidth:fixedSpaceWidth]; + [self moAddRightBarButtonItem:fixedSpaceItem animated:animated]; + return fixedSpaceItem; +} + +- (MobilyImageView*)moAddLeftBarImageUrl:(NSURL*)imageUrl defaultImage:(UIImage*)defaultImage target:(id)target action:(SEL)action animated:(BOOL)animated { + MobilyImageView* imageView = [[MobilyImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 36.0f, 36.0f)]; + imageView.defaultImage = defaultImage; + imageView.imageUrl = imageUrl; + [self moAddLeftBarView:imageView target:target action:action animated:animated]; + return imageView; +} + +- (MobilyImageView*)moAddRightBarImageUrl:(NSURL*)imageUrl defaultImage:(UIImage*)defaultImage target:(id)target action:(SEL)action animated:(BOOL)animated { + MobilyImageView* imageView = [[MobilyImageView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 36.0f, 36.0f)]; + imageView.defaultImage = defaultImage; + imageView.imageUrl = imageUrl; + [self moAddRightBarView:imageView target:target action:action animated:animated]; + return imageView; +} + +- (UIButton*)moAddLeftBarButtonNormalImage:(UIImage*)normalImage target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddLeftBarButtonNormalImage:normalImage highlightedImage:nil selectedImage:nil disabledImage:nil target:target action:action animated:animated]; +} + +- (UIButton*)moAddRightBarButtonNormalImage:(UIImage*)normalImage target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddRightBarButtonNormalImage:normalImage highlightedImage:nil selectedImage:nil disabledImage:nil target:target action:action animated:animated]; +} + +- (UIButton*)moAddLeftBarButtonNormalImage:(UIImage*)normalImage highlightedImage:(UIImage*)highlightedImage target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddLeftBarButtonNormalImage:normalImage highlightedImage:highlightedImage selectedImage:nil disabledImage:nil target:target action:action animated:animated]; +} + +- (UIButton*)moAddRightBarButtonNormalImage:(UIImage*)normalImage highlightedImage:(UIImage*)highlightedImage target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddRightBarButtonNormalImage:normalImage highlightedImage:highlightedImage selectedImage:nil disabledImage:nil target:target action:action animated:animated]; +} + +- (UIButton*)moAddLeftBarButtonNormalImage:(UIImage*)normalImage highlightedImage:(UIImage*)highlightedImage disabledImage:(UIImage*)disabledImage target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddLeftBarButtonNormalImage:normalImage highlightedImage:highlightedImage selectedImage:nil disabledImage:disabledImage target:target action:action animated:animated]; +} + +- (UIButton*)moAddRightBarButtonNormalImage:(UIImage*)normalImage highlightedImage:(UIImage*)highlightedImage disabledImage:(UIImage*)disabledImage target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddRightBarButtonNormalImage:normalImage highlightedImage:highlightedImage selectedImage:nil disabledImage:disabledImage target:target action:action animated:animated]; +} + +- (UIButton*)moAddLeftBarButtonNormalImage:(UIImage*)normalImage highlightedImage:(UIImage*)highlightedImage selectedImage:(UIImage*)selectedImage disabledImage:(UIImage*)disabledImage target:(id)target action:(SEL)action animated:(BOOL)animated { + UIButton* button = [[UIButton alloc] initWithFrame:CGRectZero]; + button.moNormalImage = normalImage; + button.moHighlightedImage = highlightedImage; + button.moSelectedImage = selectedImage; + button.moDisabledImage = disabledImage; + [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside]; + [button sizeToFit]; + [self moAddLeftBarView:button animated:animated]; + return button; +} + +- (UIButton*)moAddRightBarButtonNormalImage:(UIImage*)normalImage highlightedImage:(UIImage*)highlightedImage selectedImage:(UIImage*)selectedImage disabledImage:(UIImage*)disabledImage target:(id)target action:(SEL)action animated:(BOOL)animated { + UIButton* button = [[UIButton alloc] initWithFrame:CGRectZero]; + button.moNormalImage = normalImage; + button.moHighlightedImage = highlightedImage; + button.moSelectedImage = selectedImage; + button.moDisabledImage = disabledImage; + [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside]; + [button sizeToFit]; + [self moAddRightBarView:button animated:animated]; + return button; +} + +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddLeftBarButtonNormalTitle:normalTitle highlightedTitle:nil selectedTitle:nil disabledTitle:nil normalTitleColor:nil highlightedTitleColor:nil selectedTitleColor:nil disabledTitleColor:nil font:nil frame:CGRectZero target:target action:action animated:animated]; +} + +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle normalTitleColor:(UIColor*)normatTitleColor target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddLeftBarButtonNormalTitle:normalTitle highlightedTitle:nil selectedTitle:nil disabledTitle:nil normalTitleColor:normatTitleColor highlightedTitleColor:nil selectedTitleColor:nil disabledTitleColor:nil font:nil frame:CGRectZero target:target action:action animated:animated]; +} + +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle normalTitleColor:(UIColor*)normatTitleColor font:(UIFont*)font target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddLeftBarButtonNormalTitle:normalTitle highlightedTitle:nil selectedTitle:nil disabledTitle:nil normalTitleColor:normatTitleColor highlightedTitleColor:nil selectedTitleColor:nil disabledTitleColor:nil font:font frame:CGRectZero target:target action:action animated:animated]; +} + +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle normalTitleColor:(UIColor*)normatTitleColor font:(UIFont*)font frame:(CGRect)frame target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddLeftBarButtonNormalTitle:normalTitle highlightedTitle:nil selectedTitle:nil disabledTitle:nil normalTitleColor:normatTitleColor highlightedTitleColor:nil selectedTitleColor:nil disabledTitleColor:nil font:font frame:frame target:target action:action animated:animated]; +} + +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle highlightedTitle:(NSString*)highlightedTitle target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddLeftBarButtonNormalTitle:normalTitle highlightedTitle:highlightedTitle selectedTitle:nil disabledTitle:nil normalTitleColor:nil highlightedTitleColor:nil selectedTitleColor:nil disabledTitleColor:nil font:nil frame:CGRectZero target:target action:action animated:animated]; +} + +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle highlightedTitle:(NSString*)highlightedTitle disabledTitle:(NSString*)disabledTitle target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddLeftBarButtonNormalTitle:normalTitle highlightedTitle:highlightedTitle selectedTitle:nil disabledTitle:disabledTitle normalTitleColor:nil highlightedTitleColor:nil selectedTitleColor:nil disabledTitleColor:nil font:nil frame:CGRectZero target:target action:action animated:animated]; +} + +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle highlightedTitle:(NSString*)highlightedTitle selectedTitle:(NSString*)selectedTitle disabledTitle:(NSString*)disabledTitle target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddLeftBarButtonNormalTitle:normalTitle highlightedTitle:highlightedTitle selectedTitle:selectedTitle disabledTitle:disabledTitle normalTitleColor:nil highlightedTitleColor:nil selectedTitleColor:nil disabledTitleColor:nil font:nil frame:CGRectZero target:target action:action animated:animated]; +} + +- (UIButton*)moAddLeftBarButtonNormalTitle:(NSString*)normalTitle + highlightedTitle:(NSString*)highlightedTitle + selectedTitle:(NSString*)selectedTitle + disabledTitle:(NSString*)disabledTitle + normalTitleColor:(UIColor*)normatTitleColor + highlightedTitleColor:(UIColor*)highlightedTitleColor + selectedTitleColor:(UIColor*)selectedTitleColor + disabledTitleColor:(UIColor*)disabledTitleColor + font:(UIFont*)font + frame:(CGRect)frame + target:(id)target + action:(SEL)action + animated:(BOOL)animated { + UIButton* button = [[UIButton alloc] initWithFrame:frame]; + + // titles + button.moNormalTitle = normalTitle; + button.moHighlightedTitle = highlightedTitle; + button.moSelectedTitle = selectedTitle; + button.moDisabledTitle = disabledTitle; + + // title colors + [button setTitleColor:normatTitleColor forState:UIControlStateNormal]; + [button setTitleColor:highlightedTitleColor forState:UIControlStateHighlighted]; + [button setTitleColor:selectedTitleColor forState:UIControlStateSelected]; + [button setTitleColor:disabledTitleColor forState:UIControlStateDisabled]; + + // font + button.titleLabel.font = font; + + [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside]; + [button sizeToFit]; + [self moAddLeftBarView:button animated:animated]; + return button; +} + + +// right + +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddRightBarButtonNormalTitle:normalTitle highlightedTitle:nil selectedTitle:nil disabledTitle:nil normalTitleColor:nil highlightedTitleColor:nil selectedTitleColor:nil disabledTitleColor:nil font:nil frame:CGRectZero target:target action:action animated:animated]; +} + +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle normalTitleColor:(UIColor*)normatTitleColor target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddRightBarButtonNormalTitle:normalTitle highlightedTitle:nil selectedTitle:nil disabledTitle:nil normalTitleColor:normatTitleColor highlightedTitleColor:nil selectedTitleColor:nil disabledTitleColor:nil font:nil frame:CGRectZero target:target action:action animated:animated]; +} + +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle normalTitleColor:(UIColor*)normatTitleColor font:(UIFont*)font target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddRightBarButtonNormalTitle:normalTitle highlightedTitle:nil selectedTitle:nil disabledTitle:nil normalTitleColor:normatTitleColor highlightedTitleColor:nil selectedTitleColor:nil disabledTitleColor:nil font:font frame:CGRectZero target:target action:action animated:animated]; +} + +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle normalTitleColor:(UIColor*)normatTitleColor font:(UIFont*)font frame:(CGRect)frame target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddRightBarButtonNormalTitle:normalTitle highlightedTitle:nil selectedTitle:nil disabledTitle:nil normalTitleColor:normatTitleColor highlightedTitleColor:nil selectedTitleColor:nil disabledTitleColor:nil font:font frame:frame target:target action:action animated:animated]; +} + +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle highlightedTitle:(NSString*)highlightedTitle target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddRightBarButtonNormalTitle:normalTitle highlightedTitle:highlightedTitle selectedTitle:nil disabledTitle:nil normalTitleColor:nil highlightedTitleColor:nil selectedTitleColor:nil disabledTitleColor:nil font:nil frame:CGRectZero target:target action:action animated:animated]; +} + +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle highlightedTitle:(NSString*)highlightedTitle disabledTitle:(NSString*)disabledTitle target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddRightBarButtonNormalTitle:normalTitle highlightedTitle:highlightedTitle selectedTitle:nil disabledTitle:disabledTitle normalTitleColor:nil highlightedTitleColor:nil selectedTitleColor:nil disabledTitleColor:nil font:nil frame:CGRectZero target:target action:action animated:animated]; +} + +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle highlightedTitle:(NSString*)highlightedTitle selectedTitle:(NSString*)selectedTitle disabledTitle:(NSString*)disabledTitle target:(id)target action:(SEL)action animated:(BOOL)animated { + return [self moAddRightBarButtonNormalTitle:normalTitle highlightedTitle:highlightedTitle selectedTitle:selectedTitle disabledTitle:disabledTitle normalTitleColor:nil highlightedTitleColor:nil selectedTitleColor:nil disabledTitleColor:nil font:nil frame:CGRectZero target:target action:action animated:animated]; +} + +- (UIButton*)moAddRightBarButtonNormalTitle:(NSString*)normalTitle + highlightedTitle:(NSString*)highlightedTitle + selectedTitle:(NSString*)selectedTitle + disabledTitle:(NSString*)disabledTitle + normalTitleColor:(UIColor*)normatTitleColor + highlightedTitleColor:(UIColor*)highlightedTitleColor + selectedTitleColor:(UIColor*)selectedTitleColor + disabledTitleColor:(UIColor*)disabledTitleColor + font:(UIFont*)font + frame:(CGRect)frame + target:(id)target + action:(SEL)action + animated:(BOOL)animated { + UIButton* button = [[UIButton alloc] initWithFrame:frame]; + + // titles + button.moNormalTitle = normalTitle; + button.moHighlightedTitle = highlightedTitle; + button.moSelectedTitle = selectedTitle; + button.moDisabledTitle = disabledTitle; + + // title colors + [button setTitleColor:normatTitleColor forState:UIControlStateNormal]; + [button setTitleColor:highlightedTitleColor forState:UIControlStateHighlighted]; + [button setTitleColor:selectedTitleColor forState:UIControlStateSelected]; + [button setTitleColor:disabledTitleColor forState:UIControlStateDisabled]; + + // font + button.titleLabel.font = font; + + [button addTarget:target action:action forControlEvents:UIControlEventTouchUpInside]; + [button sizeToFit]; + [self moAddRightBarView:button animated:animated]; + return button; +} + +- (UIBarButtonItem*)moAddLeftBarView:(UIView*)view animated:(BOOL)animated { + return [self moAddLeftBarView:view target:nil action:nil animated:animated]; +} + +- (UIBarButtonItem*)moAddRightBarView:(UIView*)view animated:(BOOL)animated { + return [self moAddRightBarView:view target:nil action:nil animated:animated]; +} + +- (UIBarButtonItem*)moAddLeftBarView:(UIView*)view target:(id)target action:(SEL)action animated:(BOOL)animated { + UIBarButtonItem* barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:view]; + if((target != nil) && (action != nil)) { + UITapGestureRecognizer* tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:target action:action]; + [view addGestureRecognizer:tapGesture]; + } + [self moAddLeftBarButtonItem:barButtonItem animated:animated]; + return barButtonItem; +} + +- (UIBarButtonItem*)moAddRightBarView:(UIView*)view target:(id)target action:(SEL)action animated:(BOOL)animated { + UIBarButtonItem* barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:view]; + if((target != nil) && (action != nil)) { + UITapGestureRecognizer* tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:target action:action]; + [view addGestureRecognizer:tapGesture]; + } + [self moAddRightBarButtonItem:barButtonItem animated:animated]; + return barButtonItem; +} + +- (void)moAddLeftBarButtonItem:(UIBarButtonItem*)barButtonItem animated:(BOOL)animated { + [self setLeftBarButtonItems:[NSArray moArrayWithArray:self.leftBarButtonItems andAddingObject:barButtonItem] animated:animated]; +} + +- (void)moAddRightBarButtonItem:(UIBarButtonItem*)barButtonItem animated:(BOOL)animated { + [self setRightBarButtonItems:[NSArray moArrayWithArray:self.rightBarButtonItems andAddingObject:barButtonItem] animated:animated]; +} + +- (void)moRemoveLeftBarButtonItem:(UIBarButtonItem*)barButtonItem animated:(BOOL)animated { + [self setLeftBarButtonItems:[NSArray moArrayWithArray:self.leftBarButtonItems andRemovingObject:barButtonItem] animated:animated]; +} + +- (void)moRemoveRightBarButtonItem:(UIBarButtonItem*)barButtonItem animated:(BOOL)animated { + [self setRightBarButtonItems:[NSArray moArrayWithArray:self.rightBarButtonItems andRemovingObject:barButtonItem] animated:animated]; +} + +- (void)moRemoveAllLeftBarButtonItemsAnimated:(BOOL)animated { + [self setLeftBarButtonItems:@[] animated:animated]; +} + +- (void)moRemoveAllRightBarButtonItemsAnimated:(BOOL)animated { + [self setRightBarButtonItems:@[] animated:animated]; +} + +- (void)moSetLeftBarAutomaticAlignmentAnimated:(BOOL)animated { + __block CGFloat rightWidth = 0.0f; + [self.rightBarButtonItems moEach:^(UIBarButtonItem* barButtonItem) { + rightWidth += barButtonItem.width; + }]; + [self setLeftBarButtonItem:[[UIBarButtonItem alloc] initWithCustomView:[[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, rightWidth, 0.0f)]] animated:animated]; +} + +- (void)moSetRightBarAutomaticAlignmentAnimated:(BOOL)animated { + __block CGFloat leftWidth = 0.0f; + [self.leftBarButtonItems moEach:^(UIBarButtonItem* barButtonItem) { + leftWidth += barButtonItem.width; + }]; + [self setRightBarButtonItem:[[UIBarButtonItem alloc] initWithCustomView:[[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, leftWidth, 0.0f)]] animated:animated]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +static CGFloat Mobily_SystemVersion = MOBILY_EPSILON; +static NSString* Mobily_DeviceTypeString = nil; +static NSString* Mobily_DeviceVersionString = nil; +static MobilyDeviceFamily Mobily_DeviceFamily = MobilyDeviceFamilyUnknown; +static MobilyDeviceModel Mobily_DeviceModel = MobilyDeviceModelUnknown; + +/*--------------------------------------------------*/ + +@implementation UIDevice (MobilyUI) + ++ (CGFloat)moSystemVersion { + if(Mobily_SystemVersion <= MOBILY_EPSILON) { + Mobily_SystemVersion = [self.currentDevice.systemVersion floatValue]; + } + return Mobily_SystemVersion; +} + ++ (BOOL)moIsSimulator { +#ifdef MOBILY_SIMULATOR + return YES; +#else + return NO; +#endif +} + ++ (BOOL)moIsIPhone { + return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone); +} + ++ (BOOL)moIsIPad { + return (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad); +} + ++ (NSString*)moDeviceTypeString { + if(Mobily_DeviceTypeString == nil) { + struct utsname systemInfo; + uname(&systemInfo); + Mobily_DeviceTypeString = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding]; + } + return Mobily_DeviceTypeString; +} + ++ (NSString*)moDeviceVersionString { + if(Mobily_DeviceVersionString == nil) { + NSString* deviceType = self.moDeviceTypeString; + NSRegularExpression* regex = [NSRegularExpression regularExpressionWithPattern:@"[0-9]{1,},[0-9]{1,}" options:0 error:nil]; + NSRange rangeOfVersion = [regex rangeOfFirstMatchInString:deviceType options:0 range:NSMakeRange(0, deviceType.length)]; + if((rangeOfVersion.location != NSNotFound) && (rangeOfVersion.length > 0)) { + Mobily_DeviceVersionString = [deviceType substringWithRange:rangeOfVersion]; + } + } + return Mobily_DeviceVersionString; +} + ++ (MobilyDeviceFamily)moFamily { + if(Mobily_DeviceFamily == MobilyDeviceFamilyUnknown) { +#ifdef MOBILY_SIMULATOR + Mobily_DeviceFamily = MobilyDeviceFamilySimulator; +#else + NSDictionary* modelManifest = @{ + @"iPhone": @(MobilyDeviceFamilyPhone), + @"iPad": @(MobilyDeviceFamilyPad), + @"iPod": @(MobilyDeviceFamilyPod), + }; + NSString* deviceType = self.moDeviceTypeString; + [modelManifest enumerateKeysAndObjectsUsingBlock:^(NSString* string, NSNumber* number, BOOL* stop) { + if([deviceType hasPrefix:string] == YES) { + Mobily_DeviceFamily = number.unsignedIntegerValue; + *stop = YES; + } + }]; +#endif + } + return Mobily_DeviceFamily; +} + ++ (MobilyDeviceModel)moModel { + if(Mobily_DeviceModel == MobilyDeviceModelUnknown) { +#ifdef MOBILY_SIMULATOR + switch(UI_USER_INTERFACE_IDIOM()) { + case UIUserInterfaceIdiomPhone: + switch(self.moDisplay) { + case MobilyDeviceDisplayPhone35Inch: Mobily_DeviceModel = MobilyDeviceModelPhone4S; break; + case MobilyDeviceDisplayPhone4Inch: Mobily_DeviceModel = MobilyDeviceModelPhone5S; break; + case MobilyDeviceDisplayPhone47Inch: Mobily_DeviceModel = MobilyDeviceModelPhone6; break; + case MobilyDeviceDisplayPhone55Inch: Mobily_DeviceModel = MobilyDeviceModelPhone6Plus; break; + default: Mobily_DeviceModel = MobilyDeviceModelSimulatorPhone; break; + } + break; + case UIUserInterfaceIdiomPad: Mobily_DeviceModel = MobilyDeviceModelSimulatorPad; break; + default: break; + } +#else + NSDictionary* familyModelManifest = @{ + @(MobilyDeviceFamilyPhone): @{ + @"1,1": @(MobilyDeviceModelPhone1), + @"1,2": @(MobilyDeviceModelPhone3G), + @"2,1": @(MobilyDeviceModelPhone3GS), + @"3,1": @(MobilyDeviceModelPhone4), + @"3,2": @(MobilyDeviceModelPhone4), + @"3,3": @(MobilyDeviceModelPhone4), + @"4,1": @(MobilyDeviceModelPhone4S), + @"5,1": @(MobilyDeviceModelPhone5), + @"5,2": @(MobilyDeviceModelPhone5), + @"5,3": @(MobilyDeviceModelPhone5C), + @"5,4": @(MobilyDeviceModelPhone5C), + @"6,1": @(MobilyDeviceModelPhone5S), + @"6,2": @(MobilyDeviceModelPhone5S), + @"7,1": @(MobilyDeviceModelPhone6Plus), + @"7,2": @(MobilyDeviceModelPhone6), + }, + @(MobilyDeviceFamilyPad): @{ + @"1,1": @(MobilyDeviceModelPad1), + @"2,1": @(MobilyDeviceModelPad2), + @"2,2": @(MobilyDeviceModelPad2), + @"2,3": @(MobilyDeviceModelPad2), + @"2,4": @(MobilyDeviceModelPad2), + @"2,5": @(MobilyDeviceModelPadMini1), + @"2,6": @(MobilyDeviceModelPadMini1), + @"2,7": @(MobilyDeviceModelPadMini1), + @"3,1": @(MobilyDeviceModelPad3), + @"3,2": @(MobilyDeviceModelPad3), + @"3,3": @(MobilyDeviceModelPad3), + @"3,4": @(MobilyDeviceModelPad4), + @"3,5": @(MobilyDeviceModelPad4), + @"3,6": @(MobilyDeviceModelPad4), + @"4,1": @(MobilyDeviceModelPadAir1), + @"4,2": @(MobilyDeviceModelPadAir1), + @"4,3": @(MobilyDeviceModelPadAir1), + @"4,4": @(MobilyDeviceModelPadMini2), + @"4,5": @(MobilyDeviceModelPadMini2), + @"4,6": @(MobilyDeviceModelPadMini2), + @"4,7": @(MobilyDeviceModelPadMini3), + @"4,8": @(MobilyDeviceModelPadMini3), + @"4,9": @(MobilyDeviceModelPadMini3), + @"5,3": @(MobilyDeviceModelPadAir2), + @"5,4": @(MobilyDeviceModelPadAir2), + }, + @(MobilyDeviceFamilyPod): @{ + @"1,1": @(MobilyDeviceModelPod1), + @"2,1": @(MobilyDeviceModelPod2), + @"3,1": @(MobilyDeviceModelPod3), + @"4,1": @(MobilyDeviceModelPod4), + @"5,1": @(MobilyDeviceModelPod5), + }, + }; + NSDictionary* modelManifest = familyModelManifest[@(self.moFamily)]; + if(modelManifest != nil) { + NSNumber* modelType = modelManifest[self.moDeviceVersionString]; + if(modelType != nil) { + Mobily_DeviceModel = modelType.unsignedIntegerValue; + } + } +#endif + } + return Mobily_DeviceModel; +} + ++ (MobilyDeviceDisplay)moDisplay { + static MobilyDeviceDisplay displayType = MobilyDeviceDisplayUnknown; + if(displayType == MobilyDeviceDisplayUnknown) { + CGRect screenRect = UIScreen.mainScreen.bounds; + CGFloat screenWidth = MAX(screenRect.size.width, screenRect.size.height); + CGFloat screenHeight = MIN(screenRect.size.width, screenRect.size.height); + switch(UI_USER_INTERFACE_IDIOM()) { + case UIUserInterfaceIdiomPhone: + if((screenWidth >= 736) && (screenHeight >= 414)) { + displayType = MobilyDeviceDisplayPhone55Inch; + } else if((screenWidth >= 667) && (screenHeight >= 375)) { + displayType = MobilyDeviceDisplayPhone47Inch; + } else if((screenWidth >= 568) && (screenHeight >= 320)) { + displayType = MobilyDeviceDisplayPhone4Inch; + } else if((screenWidth >= 480) && (screenHeight >= 320)) { + displayType = MobilyDeviceDisplayPhone35Inch; + } + break; + case UIUserInterfaceIdiomPad: + if((screenWidth >= 1024) && (screenHeight >= 768)) { + displayType = MobilyDeviceDisplayPad; + } + break; + default: break; + } + } + return displayType; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyValidatedObject.h b/Sources/MobilyCore/MobilyValidatedObject.h new file mode 100644 index 0000000..c8db595 --- /dev/null +++ b/Sources/MobilyCore/MobilyValidatedObject.h @@ -0,0 +1,52 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +@protocol MobilyFieldValidator; +@class MobilyFieldForm; + +/*--------------------------------------------------*/ + +@protocol MobilyValidatedObject + +@property(nonatomic, readwrite, strong) id validator; +@property(nonatomic, readwrite, weak) MobilyFieldForm* form; + +@required +- (void)validate; +- (NSArray*)messages; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyCore/MobilyView.h b/Sources/MobilyCore/MobilyView.h new file mode 100644 index 0000000..cb0cd6a --- /dev/null +++ b/Sources/MobilyCore/MobilyView.h @@ -0,0 +1,49 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyView : UIView< MobilyBuilderObject > + +@property(nonatomic, readwrite, assign) IBInspectable BOOL roundCorners; +@property(nonatomic, readwrite, assign) IBInspectable BOOL automaticShadowPath; + +- (void)setup NS_REQUIRES_SUPER; + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyApplication.m b/Sources/MobilyCore/MobilyView.m similarity index 54% rename from Classes/UI/Core/MobilyApplication.m rename to Sources/MobilyCore/MobilyView.m index adc975b..9b25726 100644 --- a/Classes/UI/Core/MobilyApplication.m +++ b/Sources/MobilyCore/MobilyView.m @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -32,138 +32,137 @@ /* OTHER DEALINGS IN THE SOFTWARE. */ /* */ /*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ -#import "MobilyApplication.h" -#import "MobilyWindow.h" -#import "MobilyEvent.h" +#import +#import /*--------------------------------------------------*/ -@interface MobilyApplication () - -@property(nonatomic, readwrite, strong) NSData* deviceToken; +@interface MobilyView () +- (void)_updateCorners; +- (void)_updateShadow; + @end /*--------------------------------------------------*/ -#pragma mark - -/*--------------------------------------------------*/ -@implementation MobilyApplication +@implementation MobilyView + +#pragma mark Synthesize @synthesize objectName = _objectName; @synthesize objectParent = _objectParent; @synthesize objectChilds = _objectChilds; -#pragma mark Standart +#pragma mark NSKeyValueCoding -- (id)init { - self = [super init]; +#pragma mark Init / Free + +- (instancetype)initWithCoder:(NSCoder*)coder { + self = [super initWithCoder:coder]; if(self != nil) { - [self setupApplication]; + [self setup]; } return self; } -- (void)dealloc { - [self setObjectName:nil]; - [self setObjectParent:nil]; - [self setObjectChilds:nil]; - - MOBILY_SAFE_DEALLOC; -} - -#pragma mark MobilyBuilderObject - -- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIWindow class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andAddingObject:objectChild]]; - } -} - -- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { - if([objectChild isKindOfClass:[UIWindow class]] == YES) { - [self setObjectChilds:[NSArray arrayWithArray:_objectChilds andRemovingObject:objectChild]]; +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + [self setup]; } + return self; } -- (void)willLoadObjectChilds { +- (void)setup { + self.clipsToBounds = YES; } -- (void)didLoadObjectChilds { -} +#pragma mark Property override -- (id< MobilyBuilderObject >)objectForName:(NSString*)name { - return [MobilyBuilderForm object:self forName:name]; +- (void)setFrame:(CGRect)frame { + [super setFrame:frame]; + [self _updateCorners]; + [self _updateShadow]; } -- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { - return [MobilyBuilderForm object:self forSelector:selector]; +- (void)setBounds:(CGRect)bounds { + [super setBounds:bounds]; + [self _updateCorners]; + [self _updateShadow]; } -#pragma mark Public - -- (void)setupApplication { -} +#pragma mark Property -- (BOOL)launchingWithOptions:(NSDictionary*)options { - MobilyWindow* window = nil; - if(_remoteNotificationType != UIRemoteNotificationTypeNone) { - [[UIApplication sharedApplication] registerForRemoteNotificationTypes:_remoteNotificationType]; - } - if([_objectChilds count] < 1) { - window = [[MobilyWindow alloc] init]; - if(window != nil) { - [window setObjectParent:self]; - } - } else { - window = [_objectChilds firstObject]; - } - if(window != nil) { - [window makeKeyAndVisible]; +- (void)setRoundCorners:(BOOL)roundCorners { + if(_roundCorners != roundCorners) { + _roundCorners = roundCorners; + [self _updateCorners]; + [self _updateShadow]; } - return (window != nil); } -- (void)terminate { +- (void)setAutomaticShadowPath:(BOOL)automaticShadowPath { + if(_automaticShadowPath != automaticShadowPath) { + _automaticShadowPath = automaticShadowPath; + self.clipsToBounds = (_automaticShadowPath == NO); + [self _updateShadow]; + } } -- (void)receiveMemoryWarning { -} +#pragma mark Private -- (void)becomeActive { +- (void)_updateCorners { + if(_roundCorners == YES) { + CGRect bounds = self.bounds; + self.layer.cornerRadius = ceilf(MIN(bounds.size.width - 1.0f, bounds.size.height - 1.0f) * 0.5f); + } } -- (void)resignActive { +- (void)_updateShadow { + if(_automaticShadowPath == YES) { + CGRect bounds = self.bounds; + if((bounds.size.width > 0.0f) && (bounds.size.height > 0.0f)) { + self.layer.shadowPath = [[UIBezierPath bezierPathWithRoundedRect:bounds cornerRadius:self.layer.cornerRadius] CGPath]; + } + } } -- (void)enterForeground { -} +#pragma mark MobilyBuilderObject -- (void)enterBackground { +- (NSArray*)relatedObjects { + return self.subviews; } -- (void)registerForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken { - [self setDeviceToken:deviceToken]; +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + [self addSubview:(UIView*)objectChild]; + } } -- (void)failToRegisterForRemoteNotificationsWithError:(NSError*)error { +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIView.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + [self moRemoveSubview:(UIView*)objectChild]; + } } -- (void)receiveRemoteNotification:(NSDictionary*)notification { +- (void)willLoadObjectChilds { } -- (void)receiveLocalNotification:(UILocalNotification*)notification { +- (void)didLoadObjectChilds { } -- (BOOL)openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation { - return NO; +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; } -#pragma mark Property - -- (UIApplicationState)applicationState { - return [[UIApplication sharedApplication] applicationState]; +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; } @end diff --git a/Classes/UI/Core/MobilyControllerView.h b/Sources/MobilyCore/MobilyViewController.h similarity index 88% rename from Classes/UI/Core/MobilyControllerView.h rename to Sources/MobilyCore/MobilyViewController.h index 384894f..df8d6a1 100644 --- a/Classes/UI/Core/MobilyControllerView.h +++ b/Sources/MobilyCore/MobilyViewController.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,16 +33,21 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyController.h" +#import +#import /*--------------------------------------------------*/ -@interface MobilyControllerView : MobilyController +@interface MobilyViewController : MobilyController @property(nonatomic, readwrite, assign, getter=isAutomaticallyHideKeyboard) BOOL automaticallyHideKeyboard; @property(nonatomic, readwrite, assign) UIInterfaceOrientationMask orientation; @property(nonatomic, readonly, strong) NSString* mobilyName; +@property(nonatomic, readonly, strong) MobilyActivityView* activity; + +- (MobilyActivityView*)makeActivity; + @end /*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyControllerView.m b/Sources/MobilyCore/MobilyViewController.m similarity index 60% rename from Classes/UI/Core/MobilyControllerView.m rename to Sources/MobilyCore/MobilyViewController.m index 6f0cbf5..1aaa7a7 100644 --- a/Classes/UI/Core/MobilyControllerView.m +++ b/Sources/MobilyCore/MobilyViewController.m @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -32,15 +32,19 @@ /* OTHER DEALINGS IN THE SOFTWARE. */ /* */ /*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ -#import "MobilyControllerView.h" -#import "MobilyBuilder.h" +#import +#import /*--------------------------------------------------*/ -@interface MobilyControllerView () - -@property(nonatomic, readwrite, strong) NSString* mobilyName; +@interface MobilyViewController () { +@protected + NSString* _mobilyName; + MobilyActivityView* _activity; +} @end @@ -48,25 +52,27 @@ @interface MobilyControllerView () #pragma mark - /*--------------------------------------------------*/ -@implementation MobilyControllerView +@implementation MobilyViewController #pragma mark NSKeyValueCoding MOBILY_DEFINE_VALIDATE_INTERFACE_ORIENTATION_MASK(Orientation) MOBILY_DEFINE_VALIDATE_STRING(MobilyName) -#pragma mark Standart +#pragma mark Init / Free -- (void)setupController { - [super setupController]; +- (void)setup { + [super setup]; - [self setAutomaticallyHideKeyboard:YES]; + self.automaticallyHideKeyboard = YES; + if(UIDevice.moIsIPhone == YES) { + self.orientation = UIInterfaceOrientationMaskPortrait; + } else { + self.orientation = UIInterfaceOrientationMaskLandscape; + } } - (void)dealloc { - [self setMobilyName:nil]; - - MOBILY_SAFE_DEALLOC; } #pragma mark MobilyLoaderObject @@ -74,8 +80,8 @@ - (void)dealloc { - (id< MobilyBuilderObject >)objectForName:(NSString*)name { id< MobilyBuilderObject > result = [MobilyBuilderForm object:self forName:name]; if(result == nil) { - if([self isViewLoaded] == YES) { - UIView< MobilyBuilderObject >* view = (UIView< MobilyBuilderObject >*)[self view]; + if(self.isViewLoaded == YES) { + UIView< MobilyBuilderObject >* view = (UIView< MobilyBuilderObject >*)self.view; if([view respondsToSelector:@selector(objectForName:)] == YES) { result = [view objectForName:name]; } @@ -99,35 +105,61 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientati } - (void)loadView { - if([_mobilyName length] > 0) { - id view = [MobilyBuilderForm objectFromFilename:_mobilyName owner:self]; - if([view isKindOfClass:[UIView class]] == YES) { - [self setView:view]; + if(_mobilyName.length > 0) { + UIView* view = [MobilyBuilderForm objectFromFilename:_mobilyName owner:self]; + if([view isKindOfClass:UIView.class] == YES) { + self.view = view; } else { -#if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) - NSLog(@"Failure load view mobily '%@' object '%@'", _mobilyName, NSStringFromClass([view class])); -#endif [super loadView]; } } else { UINib* nib = nil; - NSString* nibName = [self nibName]; - if([nibName length] > 0) { - nib = [UINib nibWithBaseName:nibName bundle:[self nibBundle]]; + NSString* nibName = self.nibName; + if(nibName.length > 0) { + nib = [UINib moNibWithBaseName:nibName bundle:self.nibBundle]; } else { - nib = [UINib nibWithClass:[self class] bundle:[self nibBundle]]; + nib = [UINib moNibWithClass:self.class bundle:self.nibBundle]; } if(nib != nil) { - [nib instantiateWithOwner:self options:nil]; + NSArray* objects = [nib instantiateWithOwner:self options:nil]; + for(id object in objects) { + if([object isKindOfClass:UIViewController.class] == YES) { + UIViewController* controller = object; + if(controller.isViewLoaded == YES) { + [self addChildViewController:controller]; + [controller didMoveToParentViewController:self]; + } + } + } } else { -#if defined(MOBILY_DEBUG) && ((MOBILY_DEBUG_LEVEL & MOBILY_DEBUG_LEVEL_ERROR) != 0) - NSLog(@"Failure load view nib '%@'", NSStringFromClass([self class])); -#endif [super loadView]; } } } +- (void)viewWillLayoutSubviews { + [super viewWillLayoutSubviews]; + + if(_activity != nil) { + [self.view bringSubviewToFront:_activity]; + } +} + +#pragma mark Property + +- (MobilyActivityView*)activity { + if(_activity == nil) { + _activity = [self makeActivity]; + } + return _activity; +} + +#pragma mark Public + +- (MobilyActivityView*)makeActivity { + return [MobilyActivityView activityViewInView:self.view style:MobilyActivityViewStyleCircle]; +} + @end /*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyWindow.h b/Sources/MobilyCore/MobilyWindow.h similarity index 89% rename from Classes/UI/Core/MobilyWindow.h rename to Sources/MobilyCore/MobilyWindow.h index b086f96..c310d04 100644 --- a/Classes/UI/Core/MobilyWindow.h +++ b/Sources/MobilyCore/MobilyWindow.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,8 +33,8 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyBuilder.h" -#import "MobilyUI.h" +#import +#import /*--------------------------------------------------*/ @@ -44,7 +44,11 @@ @property(nonatomic, readwrite, strong) id< MobilyEvent > eventDidLoad; @property(nonatomic, readwrite, strong) id< MobilyEvent > eventDidUnload; -- (void)setupWindow; +@property(nonatomic, readonly, strong) MobilyActivityView* activity; + +- (void)setup NS_REQUIRES_SUPER; + +- (MobilyActivityView*)makeActivity; @end diff --git a/Sources/MobilyCore/MobilyWindow.m b/Sources/MobilyCore/MobilyWindow.m new file mode 100644 index 0000000..aa49cec --- /dev/null +++ b/Sources/MobilyCore/MobilyWindow.m @@ -0,0 +1,271 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import +#import + +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilyWindow () { +@protected + UIView* _emptyView; + UITapGestureRecognizer* _emptyTabGesture; + UIPanGestureRecognizer* _emptyPanGesture; + MobilyActivityView* _activity; +} + +- (void)willShowKeyboard:(NSNotification*)notification; +- (void)didHideKeyboard:(NSNotification*)notification; + +- (void)resignCurrentFirstResponder; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyWindow + +#pragma mark Synthesize + +@synthesize objectName = _objectName; +@synthesize objectParent = _objectParent; +@synthesize objectChilds = _objectChilds; + +#pragma mark NSKeyValueCoding + +MOBILY_DEFINE_VALIDATE_EVENT(EventDidLoad) +MOBILY_DEFINE_VALIDATE_EVENT(EventDidUnload) + +#pragma mark Init / Free + +- (instancetype)init { + self = [super initWithFrame:[[UIScreen mainScreen] bounds]]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + self.automaticallyHideKeyboard = YES; +} + +- (void)dealloc { + [_eventDidUnload fireSender:self object:nil]; +} + +#pragma mark MobilyBuilderObject + +- (NSArray*)relatedObjects { + return @[ self.rootViewController ]; +} + +- (void)addObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIViewController.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andAddingObject:objectChild]; + } +} + +- (void)removeObjectChild:(id< MobilyBuilderObject >)objectChild { + if([objectChild isKindOfClass:UIViewController.class] == YES) { + self.objectChilds = [NSArray moArrayWithArray:_objectChilds andRemovingObject:objectChild]; + } +} + +- (void)willLoadObjectChilds { +} + +- (void)didLoadObjectChilds { +} + +- (id< MobilyBuilderObject >)objectForName:(NSString*)name { + return [MobilyBuilderForm object:self forName:name]; +} + +- (id< MobilyBuilderObject >)objectForSelector:(SEL)selector { + return [MobilyBuilderForm object:self forSelector:selector]; +} + +#pragma mark UIWindow + +- (void)becomeKeyWindow { + [super becomeKeyWindow]; + + if(_emptyView == nil) { + _emptyView = [[UIView alloc] initWithFrame:self.bounds]; + if(_emptyView != nil) { + _emptyView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); + _emptyView.backgroundColor = [UIColor clearColor]; + _emptyView.hidden = YES; + [self addSubview:_emptyView]; + + _emptyTabGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(resignCurrentFirstResponder)]; + [_emptyView addGestureRecognizer:_emptyTabGesture]; + + _emptyPanGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(resignCurrentFirstResponder)]; + [_emptyView addGestureRecognizer:_emptyPanGesture]; + } + } + + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(willShowKeyboard:) name:UIKeyboardWillShowNotification object:nil]; + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(didHideKeyboard:) name:UIKeyboardDidHideNotification object:nil]; + + if(self.rootViewController == nil) { + UIViewController* controller = [_eventDidLoad fireSender:self object:nil]; + if(self.rootViewController == nil) { + if(controller != nil) { + self.rootViewController = controller; + } else if(_objectChilds.count > 0) { + self.rootViewController = _objectChilds.firstObject; + } + } + } +} + +- (void)resignKeyWindow { + [NSNotificationCenter.defaultCenter removeObserver:self name:UIKeyboardWillShowNotification object:nil]; + [NSNotificationCenter.defaultCenter removeObserver:self name:UIKeyboardDidHideNotification object:nil]; + + if(_emptyView != nil) { + _emptyView.hidden = YES; + } + [super resignKeyWindow]; +} + +- (void)didAddSubview:(UIView*)subview { + [super didAddSubview:subview]; + if(_activity != nil) { + [self bringSubviewToFront:_activity]; + } + [self bringSubviewToFront:_emptyView]; +} + +- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event { + if(_emptyView.isHidden == NO) { + UIViewController* currentController = self.moCurrentController; + UIViewController* parentController = [currentController parentViewController]; + if(parentController == nil) { + parentController = currentController; + } + if(_automaticallyHideKeyboard == YES) { + UIView* view = nil; + if([currentController isKindOfClass:MobilyViewController.class] == YES) { + MobilyViewController* mobilyViewController = (MobilyViewController*)currentController; + if(mobilyViewController.isAutomaticallyHideKeyboard == NO) { + _emptyView.hidden = YES; + view = [super hitTest:point withEvent:event]; + _emptyView.hidden = NO; + } + } + if(view == nil) { + view = [parentController.view hitTest:point withEvent:event]; + if(view.canBecomeFirstResponder == NO) { + if([view isKindOfClass:UIControl.class] == YES) { + UIControl* control = (UIControl*)view; + if([control isEnabled] == NO) { + view = _emptyView; + } + } else { + UIView* superview = view.superview; + if([superview isKindOfClass:[MobilyDataCell class]] == NO) { + view = _emptyView; + } + } + } + } + return view; + } else { + _emptyView.hidden = YES; + UIView* view = [super hitTest:point withEvent:event]; + _emptyView.hidden = NO; + return view; + } + } + return [super hitTest:point withEvent:event]; +} + +#pragma mark Property + +- (MobilyActivityView*)activity { + if(_activity == nil) { + _activity = [self makeActivity]; + } + return _activity; +} + +#pragma mark Public + +- (MobilyActivityView*)makeActivity { + return [MobilyActivityView activityViewInView:self style:MobilyActivityViewStyleCircle]; +} + +#pragma mark Private + +- (void)willShowKeyboard:(NSNotification* __unused)notification { + _emptyView.hidden = NO; +} + +- (void)didHideKeyboard:(NSNotification* __unused)notification { + _emptyView.hidden = YES; +} + +- (void)resignCurrentFirstResponder { + UIResponder* responder = UIResponder.moCurrentFirstResponder; + if(responder != nil) { + [responder resignFirstResponder]; + } +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilySocial/MobilySocial.h b/Sources/MobilySocial/MobilySocial.h new file mode 100644 index 0000000..7a234a0 --- /dev/null +++ b/Sources/MobilySocial/MobilySocial.h @@ -0,0 +1,42 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import +#import +#import +#import + +/*--------------------------------------------------*/ diff --git a/Sources/MobilySocial/MobilySocialFacebookProvider.h b/Sources/MobilySocial/MobilySocialFacebookProvider.h new file mode 100644 index 0000000..304a819 --- /dev/null +++ b/Sources/MobilySocial/MobilySocialFacebookProvider.h @@ -0,0 +1,64 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@class MobilySocialFacebookSession; + +/*--------------------------------------------------*/ + +@interface MobilySocialFacebookProvider : MobilySocialProvider + +@property(nonatomic, readwrite, assign) BOOL allowLoginUI; + +@property(nonatomic, readwrite, strong) MobilySocialFacebookSession* session; + +- (void)signinWithReadPermissions:(NSArray*)readPermissions success:(MobilySocialProviderSuccessBlock)success failure:(MobilySocialProviderFailureBlock)failure; + +@end + +/*--------------------------------------------------*/ + +@interface MobilySocialFacebookSession : MobilySocialSession + +@property(nonatomic, readonly, strong) NSArray* readPermissions; +@property(nonatomic, readonly, strong) NSString* accessToken; +@property(nonatomic, readonly, strong) NSDate* expirationDate; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilySocial/MobilySocialFacebookProvider.m b/Sources/MobilySocial/MobilySocialFacebookProvider.m new file mode 100644 index 0000000..90f8205 --- /dev/null +++ b/Sources/MobilySocial/MobilySocialFacebookProvider.m @@ -0,0 +1,219 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilySocialFacebookProvider () + +@property(nonatomic, readonly, strong) FBSDKLoginManager* manager; +@property(nonatomic, readwrite, strong) NSArray* signinReadPermissions; +@property(nonatomic, readwrite, copy) MobilySocialProviderSuccessBlock signinSuccessBlock; +@property(nonatomic, readwrite, copy) MobilySocialProviderFailureBlock signinFailureBlock; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilySocialFacebookSession () + +@property(nonatomic, readwrite, strong) NSArray* readPermissions; +@property(nonatomic, readwrite, strong) NSString* accessToken; +@property(nonatomic, readwrite, strong) NSDate* expirationDate; + +- (instancetype)initWithReadPermissions:(NSArray*)readPermissions facebookSession:(FBSDKAccessToken*)facebookSession; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilySocialFacebookProvider + +#pragma mark Init / Free + +- (instancetype)init { + return [self initWithName:@"Facebook"]; +} + +- (void)setup { + [super setup]; + + _allowLoginUI = YES; +} + +- (void)dealloc { +} + +#pragma mark Property + +- (void)setSession:(MobilySocialFacebookSession*)session { + super.session = session; +} + +- (MobilySocialFacebookSession*)session { + return super.session; +} + +- (FBSDKLoginManager*)manager { + static FBSDKLoginManager* manager = nil; + if(manager == nil) { + manager = [[FBSDKLoginManager alloc] init]; + manager.loginBehavior = FBSDKLoginBehaviorSystemAccount; + } + return manager; +} + +#pragma mark Public + +- (void)signinWithReadPermissions:(NSArray*)readPermissions success:(MobilySocialProviderSuccessBlock)success failure:(MobilySocialProviderFailureBlock)failure { + if(FBSDKAccessToken.currentAccessToken != nil) { + [self.manager logOut]; + } + self.signinReadPermissions = readPermissions; + self.signinSuccessBlock = success; + self.signinFailureBlock = failure; + [self.manager logInWithReadPermissions:_signinReadPermissions handler:^(FBSDKLoginManagerLoginResult* result, NSError* error) { + if((error != nil) || (result.isCancelled == YES)) { + self.session = nil; + if(_signinFailureBlock != nil) { + _signinFailureBlock(error); + } + self.signinSuccessBlock = nil; + self.signinFailureBlock = nil; + } else { + self.session = [[MobilySocialFacebookSession alloc] initWithReadPermissions:_signinReadPermissions facebookSession:result.token]; + if(_signinSuccessBlock != nil) { + _signinSuccessBlock(); + } + self.signinReadPermissions = nil; + self.signinSuccessBlock = nil; + self.signinFailureBlock = nil; + } + }]; +} + +#pragma mark MobilySocialManager + ++ (Class)sessionClass { + return MobilySocialFacebookSession.class; +} + +- (void)signoutSuccess:(MobilySocialProviderSuccessBlock)success failure:(MobilySocialProviderFailureBlock)failure { + if(self.session.isValid == YES) { + if(FBSDKAccessToken.currentAccessToken != nil) { + [self.manager logOut]; + } + self.session = nil; + if(success != nil) { + success(); + } + } else { + if(failure != nil) { + failure(nil); + } + } +} + +- (BOOL)didLaunchingWithOptions:(NSDictionary*)launchOptions { + [FBSDKApplicationDelegate.sharedInstance application:UIApplication.sharedApplication didFinishLaunchingWithOptions:launchOptions]; + return YES; +} + +- (void)didBecomeActive { + [FBSDKAppEvents activateApp]; +} + +- (BOOL)openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation { + return [FBSDKApplicationDelegate.sharedInstance application:UIApplication.sharedApplication openURL:url sourceApplication:sourceApplication annotation:annotation]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilySocialFacebookSession + +#pragma mark Synthesize + +@synthesize readPermissions = _readPermissions; +@synthesize accessToken = _accessToken; +@synthesize expirationDate = _expirationDate; + +#pragma mark Init / Free + +- (instancetype)initWithReadPermissions:(NSArray*)readPermissions facebookSession:(FBSDKAccessToken*)facebookSession { + self = [super init]; + if(self != nil) { + _readPermissions = readPermissions; + _accessToken = facebookSession.tokenString; + _expirationDate = facebookSession.expirationDate; + } + return self; +} + +#pragma mark MobilyModel + ++ (NSArray*)serializeMap { + return @[ + @"readPermissions", + @"accessToken", + @"expirationDate" + ]; +} + +#pragma mark MobilySocialSession + +- (BOOL)isValid { + return ([_expirationDate compare:NSDate.date] == NSOrderedDescending); +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilySocial/MobilySocialManager.h b/Sources/MobilySocial/MobilySocialManager.h new file mode 100644 index 0000000..b57b657 --- /dev/null +++ b/Sources/MobilySocial/MobilySocialManager.h @@ -0,0 +1,64 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@class MobilySocialProvider; + +/*--------------------------------------------------*/ + +@interface MobilySocialManager : NSObject < MobilyObject > + +@property(nonatomic, readonly, copy) NSArray* providers; + ++ (instancetype)shared; + +- (void)setup NS_REQUIRES_SUPER; + +- (void)registerProvider:(MobilySocialProvider*)provider; +- (void)unregisterProvider:(MobilySocialProvider*)provider; + +- (BOOL)didLaunchingWithOptions:(NSDictionary*)launchOptions; + +- (void)didBecomeActive; +- (void)willResignActive; + +- (BOOL)openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilySocial/MobilySocialManager.m b/Sources/MobilySocial/MobilySocialManager.m new file mode 100644 index 0000000..cc6cb9c --- /dev/null +++ b/Sources/MobilySocial/MobilySocialManager.m @@ -0,0 +1,146 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@interface MobilySocialManager () + + +@property(nonatomic, readwrite, strong) NSMutableArray* mutableProviders; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +#define MOBILY_API_MANAGER_MAX_CONCURRENT_TASK 5 + +/*--------------------------------------------------*/ + +@implementation MobilySocialManager + +#pragma mark Singleton + ++ (instancetype)shared { + static id shared = nil; + if(shared == nil) { + @synchronized(self) { + if(shared == nil) { + shared = [self new]; + } + } + } + return shared; +} + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + self.mutableProviders = NSMutableArray.array; + [self setup]; + } + return self; +} + +- (void)setup { +} + +- (void)dealloc { + self.mutableProviders = nil; +} + +#pragma mark Property + +- (NSArray*)providers { + return [_mutableProviders copy]; +} + +#pragma mark Public + +- (void)registerProvider:(MobilySocialProvider*)provider { + if([_mutableProviders containsObject:provider] == NO) { + [_mutableProviders addObject:provider]; + provider.manager = self; + } +} + +- (void)unregisterProvider:(MobilySocialProvider*)provider { + if([_mutableProviders containsObject:provider] == YES) { + [_mutableProviders removeObject:provider]; + provider.manager = nil; + } +} + +- (BOOL)didLaunchingWithOptions:(NSDictionary*)launchOptions { + for(MobilySocialProvider* provider in _mutableProviders) { + if([provider didLaunchingWithOptions:launchOptions] == NO) { + return NO; + } + } + return YES; +} + +- (void)didBecomeActive { + for(MobilySocialProvider* provider in _mutableProviders) { + [provider didBecomeActive]; + } +} + +- (void)willResignActive { + for(MobilySocialProvider* provider in _mutableProviders) { + [provider willResignActive]; + } +} + +- (BOOL)openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation { + for(MobilySocialProvider* provider in _mutableProviders) { + if([provider openURL:url sourceApplication:sourceApplication annotation:annotation] == YES) { + return YES; + } + } + return NO; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/Core/MobilyApplication.h b/Sources/MobilySocial/MobilySocialProvider.h similarity index 65% rename from Classes/UI/Core/MobilyApplication.h rename to Sources/MobilySocial/MobilySocialProvider.h index 11cf570..d16505f 100644 --- a/Classes/UI/Core/MobilyApplication.h +++ b/Sources/MobilySocial/MobilySocialProvider.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,32 +33,47 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyBuilder.h" +#import +#import /*--------------------------------------------------*/ -@interface MobilyApplication : NSObject < MobilyBuilderObject > +typedef void (^MobilySocialProviderSuccessBlock)(); +typedef void (^MobilySocialProviderFailureBlock)(NSError* error); -@property(nonatomic, readwrite, assign) UIRemoteNotificationType remoteNotificationType; -@property(nonatomic, readonly, assign) UIApplicationState applicationState; -@property(nonatomic, readonly, strong) NSData* deviceToken; +/*--------------------------------------------------*/ + +@interface MobilySocialProvider : NSObject < MobilyObject > + +@property(nonatomic, readwrite, weak) MobilySocialManager* manager; +@property(nonatomic, readonly, strong) NSString* name; +@property(nonatomic, readonly, strong) NSString* userDefaultsKey; + +@property(nonatomic, readwrite, strong) id session; + ++ (Class)sessionClass; + +- (instancetype)initWithName:(NSString*)name; + +- (void)setup NS_REQUIRES_SUPER; -- (void)setupApplication; +- (void)signoutSuccess:(MobilySocialProviderSuccessBlock)success failure:(MobilySocialProviderFailureBlock)failure; -- (BOOL)launchingWithOptions:(NSDictionary*)options; -- (void)terminate; -- (void)receiveMemoryWarning; -- (void)becomeActive; -- (void)resignActive; -- (void)enterForeground; -- (void)enterBackground; -- (void)registerForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken; -- (void)failToRegisterForRemoteNotificationsWithError:(NSError*)error; -- (void)receiveRemoteNotification:(NSDictionary*)notification; -- (void)receiveLocalNotification:(UILocalNotification*)notification; +- (BOOL)didLaunchingWithOptions:(NSDictionary*)launchOptions; + +- (void)didBecomeActive; +- (void)willResignActive; - (BOOL)openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id)annotation; @end /*--------------------------------------------------*/ + +@interface MobilySocialSession : MobilyModel + +- (BOOL)isValid; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilySocial/MobilySocialProvider.m b/Sources/MobilySocial/MobilySocialProvider.m new file mode 100644 index 0000000..dff211b --- /dev/null +++ b/Sources/MobilySocial/MobilySocialProvider.m @@ -0,0 +1,161 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilySocialProvider () + +@property(nonatomic, readwrite, strong) NSString* name; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilySocialProvider + +#pragma mark Init / Free + +- (instancetype)initWithName:(NSString*)name { + self = [super init]; + if(self != nil) { + self.name = name; + if([NSUserDefaults.standardUserDefaults objectForKey:self.userDefaultsKey] != nil) { + self.session = [[self.class.sessionClass alloc] initWithUserDefaultsKey:self.userDefaultsKey]; + if([_session isKindOfClass:MobilySocialSession.class] == YES) { + if(((MobilySocialSession*)_session).isValid == NO) { + self.session = nil; + } + } + } + [self setup]; + } + return self; +} + +- (void)setup { +} + +- (void)dealloc { + self.manager = nil; + self.name = nil; + self.session = nil; +} + +#pragma mark Property + +- (void)setManager:(MobilySocialManager*)manager { + if(_manager != manager) { + if(_manager != nil) { + [_manager unregisterProvider:self]; + } + _manager = manager; + if(_manager != nil) { + [_manager registerProvider:self]; + } + } +} + +- (void)setSession:(id)session { + if(_session != session) { + if(_session != nil) { + [_session erase]; + } + _session = session; + if(_session != nil) { + if([_session isKindOfClass:MobilyModel.class] == YES) { + ((MobilyModel*)_session).userDefaultsKey = self.userDefaultsKey; + } + [_session save]; + } + } +} + +- (NSString*)userDefaultsKey { + return [NSString stringWithFormat:@"MobilySocialSession-%@", _name]; +} + +#pragma mark Public + ++ (Class)sessionClass { + return MobilySocialSession.class; +} + +- (void)signoutSuccess:(MobilySocialProviderSuccessBlock __unused)success failure:(MobilySocialProviderFailureBlock __unused)failure { +} + +- (BOOL)didLaunchingWithOptions:(NSDictionary*)launchOptions { + return YES; +} + +- (void)didBecomeActive { +} + +- (void)willResignActive { +} + +- (BOOL)openURL:(NSURL* __unused)url sourceApplication:(NSString* __unused)sourceApplication annotation:(id __unused)annotation { + return NO; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilySocialSession + +#pragma mark MobilyModel + ++ (NSArray*)serializeMap { + return @[ + ]; +} + +#pragma mark Public + +- (BOOL)isValid { + return NO; +} + +@end + +/*--------------------------------------------------*/ diff --git a/Mobily/ExampleApplication.h b/Sources/MobilySocial/MobilySocialTwitterProvider.h similarity index 64% rename from Mobily/ExampleApplication.h rename to Sources/MobilySocial/MobilySocialTwitterProvider.h index 9f7f6fc..1a0f9e4 100644 --- a/Mobily/ExampleApplication.h +++ b/Sources/MobilySocial/MobilySocialTwitterProvider.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,43 +33,37 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyContext.h" -#import "MobilyApplication.h" -#import "MobilyWindow.h" -#import "MobilyController.h" -#import "MobilyControllerNavigation.h" -#import "MobilyControllerView.h" -#import "MobilyControllerDynamicsDrawer.h" -#import "MobilyControllerSlideMenu.h" -#import "MobilyViewImage.h" -#import "MobilyViewTable.h" +#import /*--------------------------------------------------*/ -@interface ExampleApplication : MobilyApplication +@class MobilySocialTwitterSession; -@property(nonatomic, readwrite, weak) MobilyWindow* window; -@property(nonatomic, readwrite, weak) MobilyControllerSlideMenu* slideView; -@property(nonatomic, readwrite, weak) MobilyControllerView* mainView; -@property(nonatomic, readwrite, weak) MobilyControllerView* leftView; -@property(nonatomic, readwrite, weak) MobilyControllerView* rightView; +/*--------------------------------------------------*/ -@end +@interface MobilySocialTwitterProvider : MobilySocialProvider -/*--------------------------------------------------*/ +@property(nonatomic, readwrite, strong) NSString* consumerKey; +@property(nonatomic, readwrite, strong) NSString* consumerSecret; + +@property(nonatomic, readwrite, strong) MobilySocialTwitterSession* session; -@interface ExampleControllerMain : MobilyControllerView < UITableViewDataSource, UITableViewDelegate > +- (instancetype)initWithConsumerKey:(NSString*)consumerKey consumerSecret:(NSString*)consumerSecret; -@property(nonatomic, readwrite, weak) IBOutlet MobilyViewTable* viewTable; -@property(nonatomic, readwrite, strong) NSArray* dataSource; +- (void)signinSuccess:(MobilySocialProviderSuccessBlock)success failure:(MobilySocialProviderFailureBlock)failure; +- (void)requestEmailSuccess:(MobilySocialProviderSuccessBlock)success failure:(MobilySocialProviderFailureBlock)failure; @end /*--------------------------------------------------*/ -@interface ExampleControllerMainCell : MobilyViewTableCellSwipe +@interface MobilySocialTwitterSession : MobilySocialSession -@property(nonatomic, readwrite, weak) IBOutlet UILabel* viewTitle; +@property(nonatomic, readonly, strong) NSString* authToken; +@property(nonatomic, readonly, strong) NSString* authTokenSecret; +@property(nonatomic, readonly, strong) NSString* userId; +@property(nonatomic, readonly, strong) NSString* userName; +@property(nonatomic, readonly, strong) NSString* email; @end diff --git a/Sources/MobilySocial/MobilySocialTwitterProvider.m b/Sources/MobilySocial/MobilySocialTwitterProvider.m new file mode 100644 index 0000000..932442e --- /dev/null +++ b/Sources/MobilySocial/MobilySocialTwitterProvider.m @@ -0,0 +1,224 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilySocialTwitterProvider () + + + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilySocialTwitterSession () + +@property(nonatomic, readwrite, strong) NSString* authToken; +@property(nonatomic, readwrite, strong) NSString* authTokenSecret; +@property(nonatomic, readwrite, strong) NSString* userId; +@property(nonatomic, readwrite, strong) NSString* userName; +@property(nonatomic, readwrite, strong) NSString* email; + +- (instancetype)initWithSession:(TWTRSession*)session; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilySocialTwitterProvider + +#pragma mark Init / Free + +- (instancetype)initWithConsumerKey:(NSString*)consumerKey consumerSecret:(NSString*)consumerSecret { + self = [super initWithName:@"Twitter"]; + if(self != nil) { + self.consumerKey = consumerKey; + self.consumerSecret = consumerSecret; + } + return self; +} + +- (void)dealloc { +} + +#pragma mark Property + +- (void)setSession:(MobilySocialTwitterSession*)session { + super.session = session; +} + +- (MobilySocialTwitterSession*)session { + return super.session; +} + +#pragma mark Public + +- (void)signinSuccess:(MobilySocialProviderSuccessBlock)success failure:(MobilySocialProviderFailureBlock)failure { + if(Twitter.sharedInstance.authConfig == nil) { + [Twitter.sharedInstance startWithConsumerKey:_consumerKey consumerSecret:_consumerSecret]; + } + if(Twitter.sharedInstance.session != nil) { + [Twitter.sharedInstance logOut]; + } + [Twitter.sharedInstance logInWithCompletion:^(TWTRSession* session, NSError* error) { + if(session != nil) { + self.session = [[MobilySocialTwitterSession alloc] initWithSession:session]; + if(self.session.isValid == YES) { + if(success != nil) { + success(); + } + } else { + if(failure != nil) { + failure(error); + } + } + } else { + if(failure != nil) { + failure(error); + } + } + }]; +} + +- (void)requestEmailSuccess:(MobilySocialProviderSuccessBlock)success failure:(MobilySocialProviderFailureBlock)failure { + if(self.session.isValid == YES) { + TWTRShareEmailViewController* shareEmailViewController = [[TWTRShareEmailViewController alloc] initWithCompletion:^(NSString* email, NSError* error) { + if(error == nil) { + self.session.email = email; + [self.session save]; + if(success != nil) { + success(); + } + } else { + if(failure != nil) { + failure(error); + } + } + }]; + [[UIApplication.sharedApplication.keyWindow moCurrentController] presentViewController:shareEmailViewController animated:YES completion:nil]; + } else { + if(failure != nil) { + failure(nil); + } + } +} + +#pragma mark MobilySocialManager + ++ (Class)sessionClass { + return MobilySocialTwitterSession.class; +} + +- (void)signoutSuccess:(MobilySocialProviderSuccessBlock)success failure:(MobilySocialProviderFailureBlock)failure { + if(self.session.isValid == YES) { + [Twitter.sharedInstance logOut]; + self.session = nil; + if(success != nil) { + success(); + } + } else { + if(failure != nil) { + failure(nil); + } + } +} + +- (BOOL)openURL:(NSURL* __unused)url sourceApplication:(NSString* __unused)sourceApplication annotation:(id __unused)annotation { + return NO; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilySocialTwitterSession + +#pragma mark Synthesize + +@synthesize authToken = _authToken; +@synthesize authTokenSecret = _authTokenSecret; +@synthesize userId = _userId; +@synthesize userName = _userName; +@synthesize email = _email; + +#pragma mark Init / Free + +- (instancetype)initWithSession:(TWTRSession*)session { + self = [super init]; + if(self != nil) { + _authToken = session.authToken; + _authTokenSecret = session.authTokenSecret; + _userId = session.userID; + _userName = session.userName; + } + return self; +} + +#pragma mark MobilyModel + ++ (NSArray*)serializeMap { + return @[ + @"authToken", + @"authTokenSecret", + @"userId", + @"userName", + @"email" + ]; +} + +#pragma mark MobilySocialSession + +- (BOOL)isValid { + return (_authToken.length > 0) && (_authTokenSecret.length > 0) && (_userId.length > 0); +} + +@end + +/*--------------------------------------------------*/ diff --git a/Classes/UI/ViewElements/MobilyViewElementsLayout.h b/Sources/MobilySocial/MobilySocialVKontakteProvider.h similarity index 67% rename from Classes/UI/ViewElements/MobilyViewElementsLayout.h rename to Sources/MobilySocial/MobilySocialVKontakteProvider.h index 706a7e9..921ac9f 100644 --- a/Classes/UI/ViewElements/MobilyViewElementsLayout.h +++ b/Sources/MobilySocial/MobilySocialVKontakteProvider.h @@ -2,7 +2,7 @@ /* */ /* The MIT License (MIT) */ /* */ -/* Copyright (c) 2014 fgengine(Alexander Trifonov) */ +/* Copyright (c) 2014 Mobily TEAM */ /* */ /* Permission is hereby granted, free of charge, */ /* to any person obtaining a copy of this software */ @@ -33,47 +33,35 @@ /* */ /*--------------------------------------------------*/ -#import "MobilyViewElements.h" +#import /*--------------------------------------------------*/ -@interface MobilyViewElementsLayoutList : NSObject < MobilyViewElementsLayout > - -@property(nonatomic, readwrite, assign) CGFloat margin; -@property(nonatomic, readwrite, assign) CGFloat spacing; - -@end - -/*--------------------------------------------------*/ - -@interface MobilyViewElementsLayoutListVertical : MobilyViewElementsLayoutList - -@end +@class MobilySocialVKontakteSession; /*--------------------------------------------------*/ -@interface MobilyViewElementsLayoutListHorizontal : MobilyViewElementsLayoutList +@interface MobilySocialVKontakteProvider : MobilySocialProvider -@end +@property(nonatomic, readwrite, strong) NSString* applicationId; -/*--------------------------------------------------*/ +@property(nonatomic, readwrite, strong) MobilySocialVKontakteSession* session; -@interface MobilyViewElementsLayoutGrid : NSObject < MobilyViewElementsLayout > +- (instancetype)initWithApplicationId:(NSString*)applicationId; -@property(nonatomic, readwrite, assign) CGSize margin; -@property(nonatomic, readwrite, assign) CGSize spacing; +- (void)signinWithPermissions:(NSArray*)permissions success:(MobilySocialProviderSuccessBlock)success failure:(MobilySocialProviderFailureBlock)failure; @end /*--------------------------------------------------*/ -@interface MobilyViewElementsLayoutGridVertical : MobilyViewElementsLayoutGrid - -@end - -/*--------------------------------------------------*/ +@interface MobilySocialVKontakteSession : MobilySocialSession -@interface MobilyViewElementsLayoutGridHorizontal : MobilyViewElementsLayoutGrid +@property(nonatomic, readonly, strong) NSArray* permissions; +@property(nonatomic, readonly, strong) NSString* accessToken; +@property(nonatomic, readonly, strong) NSDate* expirationDate; +@property(nonatomic, readonly, strong) NSString* userId; +@property(nonatomic, readonly, strong) NSString* email; @end diff --git a/Sources/MobilySocial/MobilySocialVKontakteProvider.m b/Sources/MobilySocial/MobilySocialVKontakteProvider.m new file mode 100644 index 0000000..d63b5b6 --- /dev/null +++ b/Sources/MobilySocial/MobilySocialVKontakteProvider.m @@ -0,0 +1,245 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilySocialVKontakteProvider () < VKSdkDelegate > + +@property(nonatomic, readwrite, strong) NSArray* permissions; +@property(nonatomic, readwrite, copy) MobilySocialProviderSuccessBlock successBlock; +@property(nonatomic, readwrite, copy) MobilySocialProviderFailureBlock failureBlock; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilySocialVKontakteSession () + +@property(nonatomic, readwrite, strong) NSArray* permissions; +@property(nonatomic, readwrite, strong) NSString* accessToken; +@property(nonatomic, readwrite, strong) NSDate* expirationDate; +@property(nonatomic, readwrite, strong) NSString* userId; +@property(nonatomic, readwrite, strong) NSString* email; + +- (instancetype)initWithAccessToken:(VKAccessToken*)accessToken; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilySocialVKontakteProvider + +#pragma mark Init / Free + +- (instancetype)initWithApplicationId:(NSString*)applicationId { + self = [super initWithName:@"VKontakte"]; + if(self != nil) { + self.applicationId = applicationId; + } + return self; +} + +#pragma mark Property + +- (void)setApplicationId:(NSString*)applicationId { + if([_applicationId isEqualToString:applicationId] == NO) { + _applicationId = applicationId; + if(_applicationId != nil) { + [VKSdk initializeWithDelegate:self andAppId:_applicationId]; + } + } +} + +- (void)setSession:(MobilySocialVKontakteSession*)session { + super.session = session; +} + +- (MobilySocialVKontakteSession*)session { + return super.session; +} + +#pragma mark Public + +- (void)signinWithPermissions:(NSArray*)permissions success:(MobilySocialProviderSuccessBlock)success failure:(MobilySocialProviderFailureBlock)failure { + self.permissions = permissions; + self.successBlock = success; + self.failureBlock = failure; + + if([VKSdk wakeUpSession] == YES) { + [VKSdk forceLogout]; + } + + if([VKSdk vkAppMayExists] == NO) { + [VKSdk authorize:permissions revokeAccess:YES forceOAuth:NO inApp:YES]; + } else { + [VKSdk authorize:permissions revokeAccess:YES forceOAuth:NO]; + } +} + +#pragma mark MobilySocialManager + ++ (Class)sessionClass { + return MobilySocialVKontakteSession.class; +} + +- (void)signoutSuccess:(MobilySocialProviderSuccessBlock)success failure:(MobilySocialProviderFailureBlock)failure { + if(self.session.isValid == YES) { + [VKSdk forceLogout]; + self.session = nil; + if(success != nil) { + success(); + } + } else { + if(failure != nil) { + failure(nil); + } + } +} + +- (BOOL)openURL:(NSURL*)url sourceApplication:(NSString*)sourceApplication annotation:(id __unused)annotation { + return [VKSdk processOpenURL:url fromApplication:sourceApplication]; +} + +#pragma mark VKSdkDelegate + +- (void)vkSdkNeedCaptchaEnter:(VKError*)captchaError { + [self vkSdkShouldPresentViewController:[VKCaptchaViewController captchaControllerWithError:captchaError]]; +} + +- (void)vkSdkTokenHasExpired:(VKAccessToken* __unused)expiredToken { + if(_failureBlock != nil) { + _failureBlock(nil); + } +} + +- (void)vkSdkUserDeniedAccess:(VKError*)authorizationError { + if(_failureBlock != nil) { + _failureBlock(authorizationError.httpError); + } +} + +- (void)vkSdkShouldPresentViewController:(UIViewController*)controller { + [[UIApplication.sharedApplication.keyWindow moCurrentController] presentViewController:controller animated:YES completion:nil]; +} + +- (void)vkSdkReceivedNewToken:(VKAccessToken*)accessToken { + if(accessToken != nil) { + self.session = [[MobilySocialVKontakteSession alloc] initWithAccessToken:accessToken]; + if(_successBlock != nil) { + _successBlock(); + } + } else { + if(_failureBlock != nil) { + _failureBlock(nil); + } + } +} + +- (BOOL)vkSdkAuthorizationAllowFallbackToSafari { + return NO; +} + +- (BOOL)vkSdkIsBasicAuthorization { + return YES; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilySocialVKontakteSession + +#pragma mark Synthesize + +@synthesize permissions = _permissions; +@synthesize accessToken = _accessToken; +@synthesize expirationDate = _expirationDate; +@synthesize userId = _userId; +@synthesize email = _email; + +#pragma mark Init / Free + +- (instancetype)initWithAccessToken:(VKAccessToken*)accessToken { + self = [super init]; + if(self != nil) { + _permissions = accessToken.permissions; + _accessToken = accessToken.accessToken; + if(accessToken.expiresIn.intValue > 0) { + _expirationDate = [NSDate dateWithTimeIntervalSince1970:accessToken.created + accessToken.expiresIn.intValue]; + } else { + _expirationDate = [NSDate dateWithTimeIntervalSince1970:accessToken.created + MOBILY_YEAR]; + } + _userId = accessToken.userId; + _email = accessToken.email; + } + return self; +} + +#pragma mark MobilyModel + ++ (NSArray*)serializeMap { + return @[ + @"permissions", + @"accessToken", + @"expirationDate", + @"userId", + @"email" + ]; +} + +#pragma mark MobilySocialSession + +- (BOOL)isValid { + return ([_expirationDate compare:[NSDate date]] == NSOrderedDescending); +} + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyStore/MobilyStore.h b/Sources/MobilyStore/MobilyStore.h new file mode 100644 index 0000000..25e3467 --- /dev/null +++ b/Sources/MobilyStore/MobilyStore.h @@ -0,0 +1,38 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyStore/MobilyStoreManager.h b/Sources/MobilyStore/MobilyStoreManager.h new file mode 100644 index 0000000..0d08036 --- /dev/null +++ b/Sources/MobilyStore/MobilyStoreManager.h @@ -0,0 +1,116 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ + +#import +#import + +/*--------------------------------------------------*/ + +@class MobilyStoreProductsRequest; +@class MobilyStorePaymentRequest; + +/*--------------------------------------------------*/ + +typedef void (^MobilyStoreManagerProductsRequestSuccess)(MobilyStoreProductsRequest* productsRequest); +typedef void (^MobilyStoreManagerProductsRequestFailure)(MobilyStoreProductsRequest* productsRequest, NSError* error); + +typedef void (^MobilyStoreManagerPaymentRequestProcessing)(MobilyStorePaymentRequest* paymentRequest); +typedef void (^MobilyStoreManagerPaymentTransactionProcessing)(SKPaymentQueue* paymentQueue, SKPaymentTransaction* paymentTransaction); + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyStoreManager : NSObject < MobilyObject > + +@property(nonatomic, readwrite, copy) MobilyStoreManagerPaymentTransactionProcessing paymentTransactionProcessing; + ++ (instancetype)shared; + +- (void)setup NS_REQUIRES_SUPER; + +- (MobilyStoreProductsRequest*)productsRequestByIdentifiers:(NSSet*)identifiers success:(MobilyStoreManagerProductsRequestSuccess)success failure:(MobilyStoreManagerProductsRequestFailure)failure; +- (void)cancelProductsRequest:(MobilyStoreProductsRequest*)productsRequest; + +- (BOOL)canMakePayments; +- (MobilyStorePaymentRequest*)paymentRequestWithProduct:(SKProduct*)product processing:(MobilyStoreManagerPaymentRequestProcessing)processing; +- (void)finishPaymentRequest:(MobilyStorePaymentRequest*)paymentRequest; + +@end + + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyStoreProductsRequest : NSObject + +@property(nonatomic, readonly, strong) SKProductsRequest* request; +@property(nonatomic, readonly, strong) SKProductsResponse* response; + +- (SKProduct*)productByIdentifier:(NSString*)identifier; + +- (void)cancel; + +@end + +/*--------------------------------------------------*/ + +MOBILY_REQUIRES_PROPERTY_DEFINITIONS +@interface MobilyStorePaymentRequest : NSObject + +@property(nonatomic, readonly, strong) SKProduct* product; +@property(nonatomic, readonly, strong) SKPaymentTransaction* transaction; +@property(nonatomic, readonly, strong) NSData* transactionReceipt; + +- (void)finish; + +@end + +/*--------------------------------------------------*/ + +@interface SKProduct (MobilyStore) + +@property(nonatomic, readonly, strong) NSString* moPriceAsString; + +@end + +/*--------------------------------------------------*/ + +@interface SKPaymentTransaction (MobilyStore) + +@property(nonatomic, readonly, strong) NSData* moReceipt; + +@end + +/*--------------------------------------------------*/ diff --git a/Sources/MobilyStore/MobilyStoreManager.m b/Sources/MobilyStore/MobilyStoreManager.m new file mode 100644 index 0000000..bb14b59 --- /dev/null +++ b/Sources/MobilyStore/MobilyStoreManager.m @@ -0,0 +1,379 @@ +/*--------------------------------------------------*/ +/* */ +/* The MIT License (MIT) */ +/* */ +/* Copyright (c) 2014 Mobily TEAM */ +/* */ +/* Permission is hereby granted, free of charge, */ +/* to any person obtaining a copy of this software */ +/* and associated documentation files */ +/* (the "Software"), to deal in the Software */ +/* without restriction, including without */ +/* limitation the rights to use, copy, modify, */ +/* merge, publish, distribute, sublicense, */ +/* and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished */ +/* to do so, subject to the following conditions: */ +/* */ +/* The above copyright notice and this permission */ +/* notice shall be included in all copies or */ +/* substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT */ +/* WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, */ +/* INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ +/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR */ +/* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL */ +/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR */ +/* ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ +/* WHETHER IN AN ACTION OF CONTRACT, TORT OR */ +/* OTHERWISE, ARISING FROM, OUT OF OR IN */ +/* CONNECTION WITH THE SOFTWARE OR THE USE OR */ +/* OTHER DEALINGS IN THE SOFTWARE. */ +/* */ +/*--------------------------------------------------*/ +#define MOBILY_SOURCE +/*--------------------------------------------------*/ + +#import + +/*--------------------------------------------------*/ + +@interface MobilyStoreManager () < SKPaymentTransactionObserver > { +@protected + NSMutableArray* _requestProducts; + NSMutableArray* _requestPayments; + MobilyStoreManagerPaymentTransactionProcessing _paymentTransactionProcessing; +} + +- (void)_finishProductsRequest:(MobilyStoreProductsRequest*)productsRequest; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyStoreProductsRequest () < SKProductsRequestDelegate > { +@protected + SKProductsRequest* _request; + SKProductsResponse* _response; + MobilyStoreManagerProductsRequestSuccess _success; + MobilyStoreManagerProductsRequestFailure _failure; +} + +@property(nonatomic, readwrite, strong) SKProductsRequest* request; +@property(nonatomic, readwrite, strong) SKProductsResponse* response; +@property(nonatomic, readwrite, copy) MobilyStoreManagerProductsRequestSuccess success; +@property(nonatomic, readwrite, copy) MobilyStoreManagerProductsRequestFailure failure; + +- (instancetype)initWithIdentifiers:(NSSet*)identifiers success:(MobilyStoreManagerProductsRequestSuccess)success failure:(MobilyStoreManagerProductsRequestFailure)failure; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@interface MobilyStorePaymentRequest () { +@protected + SKProduct* _product; + SKPaymentTransaction* _transaction; + MobilyStoreManagerPaymentRequestProcessing _processing; +} + +@property(nonatomic, readwrite, strong) SKProduct* product; +@property(nonatomic, readwrite, strong) SKPaymentTransaction* transaction; +@property(nonatomic, readwrite, copy) MobilyStoreManagerPaymentRequestProcessing processing; + +- (instancetype)initWithProduct:(SKProduct*)product processing:(MobilyStoreManagerPaymentRequestProcessing)processing; +- (void)_updateTransaction:(SKPaymentTransaction*)transaction; + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyStoreManager + +#pragma mark Synthesize + +@synthesize paymentTransactionProcessing = _paymentTransactionProcessing; + +#pragma mark Singleton + ++ (instancetype)shared { + static id shared = nil; + if(shared == nil) { + @synchronized(self) { + if(shared == nil) { + shared = [self new]; + } + } + } + return shared; +} + +#pragma mark Init / Free + +- (instancetype)init { + self = [super init]; + if(self != nil) { + [self setup]; + } + return self; +} + +- (void)setup { + _requestProducts = [NSMutableArray array]; + _requestPayments = [NSMutableArray array]; + + [SKPaymentQueue.defaultQueue addTransactionObserver:self]; +} + +- (void)dealloc { + [SKPaymentQueue.defaultQueue removeTransactionObserver:self]; +} + +#pragma mark Public + +- (MobilyStoreProductsRequest*)productsRequestByIdentifiers:(NSSet*)identifiers success:(MobilyStoreManagerProductsRequestSuccess)success failure:(MobilyStoreManagerProductsRequestFailure)failure { + MobilyStoreProductsRequest* productsRequest = [[MobilyStoreProductsRequest alloc] initWithIdentifiers:identifiers success:success failure:failure]; + if(productsRequest != nil) { + [_requestProducts addObject:productsRequest]; + } + return productsRequest; +} + +- (void)cancelProductsRequest:(MobilyStoreProductsRequest*)productsRequest { + [productsRequest cancel]; +} + +- (BOOL)canMakePayments { + return [SKPaymentQueue canMakePayments]; +} + +- (MobilyStorePaymentRequest*)paymentRequestWithProduct:(SKProduct*)product processing:(MobilyStoreManagerPaymentRequestProcessing)processing { + MobilyStorePaymentRequest* paymentRequest = [[MobilyStorePaymentRequest alloc] initWithProduct:product processing:processing]; + if(paymentRequest != nil) { + [_requestPayments addObject:paymentRequest]; + [SKPaymentQueue.defaultQueue addPayment:[SKPayment paymentWithProduct:product]]; + } + return paymentRequest; +} + +- (void)finishPaymentRequest:(MobilyStorePaymentRequest*)paymentRequest { + [paymentRequest finish]; +} + +#pragma mark Private + +- (void)_finishProductsRequest:(MobilyStoreProductsRequest*)productsRequest { + [_requestProducts removeObject:productsRequest]; +} + +- (void)_finishPaymentRequest:(MobilyStorePaymentRequest*)paymentRequest { + [_requestPayments removeObject:paymentRequest]; +} + +#pragma mark SKPaymentTransactionObserver + +- (void)paymentQueue:(SKPaymentQueue*)queue updatedTransactions:(NSArray*)transactions { + [transactions moEach:^(SKPaymentTransaction* transaction) { + MobilyStorePaymentRequest* paymentRequest = [_requestPayments moFind:^BOOL(MobilyStorePaymentRequest* paymentRequest) { + return [transaction.payment.productIdentifier isEqualToString:paymentRequest.product.productIdentifier]; + }]; + if(paymentRequest == nil) { + if(_paymentTransactionProcessing != nil) { + _paymentTransactionProcessing(queue, transaction); + } + } else { + [paymentRequest _updateTransaction:transaction]; + } + }]; +} + +- (void)paymentQueue:(SKPaymentQueue*)queue removedTransactions:(NSArray*)transactions { + [transactions moEach:^(SKPaymentTransaction* transaction) { + MobilyStorePaymentRequest* paymentRequest = [_requestPayments moFind:^BOOL(MobilyStorePaymentRequest* paymentRequest) { + return [transaction.payment.productIdentifier isEqualToString:paymentRequest.product.productIdentifier]; + }]; + if(paymentRequest == nil) { + if(_paymentTransactionProcessing != nil) { + _paymentTransactionProcessing(queue, transaction); + } + } else { + [self _finishPaymentRequest:paymentRequest]; + } + }]; +} + +- (void)paymentQueue:(SKPaymentQueue*)queue updatedDownloads:(NSArray*)downloads { +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyStoreProductsRequest + +#pragma mark Synthesize + +@synthesize request = _request; +@synthesize response = _response; +@synthesize success = _success; +@synthesize failure = _failure; + +#pragma mark Init / Free + +- (instancetype)initWithIdentifiers:(NSSet*)identifiers success:(MobilyStoreManagerProductsRequestSuccess)success failure:(MobilyStoreManagerProductsRequestFailure)failure { + self = [super init]; + if(self != nil) { + self.request = [[SKProductsRequest alloc] initWithProductIdentifiers:identifiers]; + self.success = success; + self.failure = failure; + } + return self; +} + +#pragma mark Property + +- (void)setRequest:(SKProductsRequest*)request { + if(_request != request) { + if(_request != nil) { + [_request cancel]; + } + _request = request; + if(_request != nil) { + _request.delegate = self; + [_request start]; + } + } +} + +#pragma mark Public + +- (SKProduct*)productByIdentifier:(NSString*)identifier { + return [_response.products moFind:^BOOL(SKProduct* product) { + return [product.productIdentifier isEqualToString:identifier]; + }]; +} + +- (void)cancel { + self.request = nil; +} + +#pragma mark SKProductsRequestDelegate + +- (void)productsRequest:(SKProductsRequest*)request didReceiveResponse:(SKProductsResponse*)response { + self.response = response; + if(_success != nil) { + _success(self); + } + [MobilyStoreManager.shared _finishProductsRequest:self]; +} + +- (void)requestDidFinish:(SKRequest*)request { + [MobilyStoreManager.shared _finishProductsRequest:self]; +} + +- (void)request:(SKRequest*)request didFailWithError:(NSError*)error { + if(_failure != nil) { + _failure(self, error); + } + [MobilyStoreManager.shared _finishProductsRequest:self]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation MobilyStorePaymentRequest + +#pragma mark Synthesize + +@synthesize product = _product; +@synthesize transaction = _transaction; +@synthesize processing = _processing; + +#pragma mark Init / Free + +- (instancetype)initWithProduct:(SKProduct*)product processing:(MobilyStoreManagerPaymentRequestProcessing)processing { + self = [super init]; + if(self != nil) { + self.product = product; + self.processing = processing; + } + return self; +} + +#pragma mark Property + +- (NSData*)transactionReceipt { + return _transaction.moReceipt; +} + +#pragma mark Private + +- (void)_updateTransaction:(SKPaymentTransaction*)transaction { + if(_transaction == nil) { + self.transaction = transaction; + } + if(_processing != nil) { + _processing(self); + } +} + +#pragma mark Public + +- (void)finish { + [SKPaymentQueue.defaultQueue finishTransaction:_transaction]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation SKProduct (MobilyStore) + +- (NSString*)moPriceAsString { + static NSNumberFormatter* formatter = nil; + if(formatter == nil) { + formatter = [NSNumberFormatter new]; + } + formatter.formatterBehavior = NSNumberFormatterBehavior10_4; + formatter.numberStyle = NSNumberFormatterCurrencyStyle; + formatter.locale = self.priceLocale; + return [formatter stringFromNumber:self.price]; +} + +@end + +/*--------------------------------------------------*/ +#pragma mark - +/*--------------------------------------------------*/ + +@implementation SKPaymentTransaction (MobilyStore) + +- (NSData*)moReceipt { + if(UIDevice.moSystemVersion >= 7.0) { + NSData* base64 = [NSData dataWithContentsOfURL:NSBundle.mainBundle.appStoreReceiptURL]; + NSString* receipt = [base64 base64EncodedStringWithOptions:kNilOptions]; + return [receipt dataUsingEncoding:NSUTF8StringEncoding]; + } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return self.transactionReceipt; +#pragma clang diagnostic pop +} + +@end + +/*--------------------------------------------------*/ diff --git a/Project/MobilyExample/MobilyExampleTests/MobilyExampleTests-Info.plist b/Support/MobilyCore.plist similarity index 67% rename from Project/MobilyExample/MobilyExampleTests/MobilyExampleTests-Info.plist rename to Support/MobilyCore.plist index 504c8fc..d3de8ee 100644 --- a/Project/MobilyExample/MobilyExampleTests/MobilyExampleTests-Info.plist +++ b/Support/MobilyCore.plist @@ -5,18 +5,22 @@ CFBundleDevelopmentRegion en CFBundleExecutable - ${EXECUTABLE_NAME} + $(EXECUTABLE_NAME) CFBundleIdentifier - org.fgengine.mobily-example.${PRODUCT_NAME:rfc1034identifier} + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 + CFBundleName + $(PRODUCT_NAME) CFBundlePackageType - BNDL + FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion - 1 + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + diff --git a/Support/MobilySocial.plist b/Support/MobilySocial.plist new file mode 100644 index 0000000..d3de8ee --- /dev/null +++ b/Support/MobilySocial.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/Support/MobilyStore.plist b/Support/MobilyStore.plist new file mode 100644 index 0000000..d3de8ee --- /dev/null +++ b/Support/MobilyStore.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + +