This commit is contained in:
watrabi
2025-09-18 17:55:52 -04:00
commit 977f1ff4b8
15030 changed files with 17324420 additions and 0 deletions
@@ -0,0 +1,37 @@
//
// NSDictionary+Parsing.h
// RobloxMobile
//
// Created by Ariel Lichtin on 10/28/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSDictionary (Parsing)
- (BOOL) boolValueForKey:(NSString*)key;
- (BOOL) boolValueForKey:(NSString*)key withDefault:(BOOL)defaultValue;
-(NSInteger) intValueForKey:(NSString*)key;
-(NSInteger) intValueForKey:(NSString*)key withDefault:(NSInteger)defaultValue;
-(NSUInteger) unsignedValueForKey:(NSString*)key;
-(NSUInteger) unsignedValueForKey:(NSString*)key withDefault:(NSUInteger)defaultValue;
-(double) doubleValueForKey:(NSString*)key;
-(double) doubleValueForKey:(NSString*)key withDefault:(double)defaultValue;
-(NSNumber*) numberForKey:(NSString*)key;
-(NSNumber*) numberForKey:(NSString*)key withDefault:(NSNumber*)defaultValue;
-(NSString*) stringForKey:(NSString*)key;
-(NSString*) stringForKey:(NSString*)key withDefault:(NSString*)defaultValue;
-(NSArray*) arrayForKey:(NSString*)key;
-(NSArray*) arrayForKey:(NSString*)key withDefault:(NSArray*)defaultValue;
-(NSDictionary*) dictionaryForKey:(NSString*)key;
-(NSDictionary*) dictionaryForKey:(NSString*)key withDefault:(NSDictionary*)defaultValue;
@end
@@ -0,0 +1,132 @@
//
// NSDictionary+Parsing.m
// RobloxMobile
//
// Created by Ariel Lichtin on 10/28/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import "NSDictionary+Parsing.h"
@implementation NSDictionary (Parsing)
- (BOOL) boolValueForKey:(NSString*)key
{
return [self boolValueForKey:key withDefault:NO];
}
- (BOOL) boolValueForKey:(NSString*)key withDefault:(BOOL)defaultValue
{
id object = [self objectForKey:key];
if(object != nil && [object isKindOfClass:[NSNumber class]])
return [object boolValue];
else
return defaultValue;
}
-(NSInteger) intValueForKey:(NSString*)key
{
return [self intValueForKey:key withDefault:0];
}
-(NSInteger) intValueForKey:(NSString*)key withDefault:(NSInteger)defaultValue
{
id object = [self objectForKey:key];
if(object != nil && [object isKindOfClass:[NSNumber class]])
return [object integerValue];
else
return defaultValue;
}
-(NSUInteger) unsignedValueForKey:(NSString*)key
{
return [self unsignedValueForKey:key withDefault:0];
}
-(NSUInteger) unsignedValueForKey:(NSString*)key withDefault:(NSUInteger)defaultValue
{
id object = [self objectForKey:key];
if(object != nil && [object isKindOfClass:[NSNumber class]])
return [object unsignedIntegerValue];
else
return defaultValue;
}
-(double) doubleValueForKey:(NSString*)key
{
return [self doubleValueForKey:key withDefault:0.0];
}
-(double) doubleValueForKey:(NSString*)key withDefault:(double)defaultValue
{
id object = [self objectForKey:key];
if(object != nil && [object isKindOfClass:[NSNumber class]])
return [object doubleValue];
else
return defaultValue;
}
-(NSNumber*) numberForKey:(NSString*)key
{
return [self numberForKey:key withDefault:[NSNumber numberWithInt:0]];
}
-(NSNumber*) numberForKey:(NSString*)key withDefault:(NSNumber*)defaultValue
{
id object = [self objectForKey:key];
if(object != nil && [object isKindOfClass:[NSNumber class]])
return object;
else
return defaultValue;
}
-(NSString*) stringForKey:(NSString*)key
{
return [self stringForKey:key withDefault:@""];
}
-(NSString*) stringForKey:(NSString*)key withDefault:(NSString*)defaultValue
{
id object = [self objectForKey:key];
if(object != nil)
{
if( [object isKindOfClass:[NSString class]] )
return object;
else if( [object isKindOfClass:[NSNumber class]] )
return [object stringValue];
else
return defaultValue;
}
else
return defaultValue;
}
-(NSArray*) arrayForKey:(NSString*)key
{
return [self arrayForKey:key withDefault:[NSArray array]];
}
-(NSArray*) arrayForKey:(NSString*)key withDefault:(NSArray*)defaultValue
{
id object = [self objectForKey:key];
if(object != nil && [object isKindOfClass:[NSArray class]])
return object;
else
return defaultValue;
}
-(NSDictionary*) dictionaryForKey:(NSString*)key
{
return [self dictionaryForKey:key withDefault:[NSDictionary dictionary]];
}
-(NSDictionary*) dictionaryForKey:(NSString*)key withDefault:(NSDictionary*)defaultValue
{
id object = [self objectForKey:key];
if(object != nil && [object isKindOfClass:[NSDictionary class]])
return object;
else
return defaultValue;
}
@end
@@ -0,0 +1,15 @@
//
// NSString+stripHtml.h
// RobloxMobile
//
// Created by Ariel Lichtin on 7/2/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSString (stripHtml)
- (NSString*)stringByStrippingHTML;
@end
@@ -0,0 +1,64 @@
//
// NSString+stripHtml.m
// RobloxMobile
//
// Created by Ariel Lichtin on 7/2/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import "NSString+stripHtml.h"
@interface NSString_stripHtml_XMLParsee : NSObject<NSXMLParserDelegate>
{
NSMutableArray* strings;
}
- (NSString*)getCharsFound;
@end
@implementation NSString_stripHtml_XMLParsee
- (id)init
{
if((self = [super init]))
{
strings = [[NSMutableArray alloc] init];
}
return self;
}
- (void)parser:(NSXMLParser*)parser foundCharacters:(NSString*)string
{
[strings addObject:string];
}
- (NSString*)getCharsFound
{
return [strings componentsJoinedByString:@""];
}
@end
@implementation NSString (stripHtml)
- (NSString*)stringByStrippingHTML
{
// take this string obj and wrap it in a root element to ensure only a single root element exists
NSString* string = [NSString stringWithFormat:@"<root>%@</root>", self];
// add the string to the xml parser
NSStringEncoding encoding = string.fastestEncoding;
NSData* data = [string dataUsingEncoding:encoding];
NSXMLParser* parser = [[NSXMLParser alloc] initWithData:data];
// parse the content keeping track of any chars found outside tags (this will be the stripped content)
NSString_stripHtml_XMLParsee* parsee = [[NSString_stripHtml_XMLParsee alloc] init];
parser.delegate = parsee;
[parser parse];
// any chars found while parsing are the stripped content
NSString* strippedString = [parsee getCharsFound];
// get the raw text out of the parsee after parsing, and return it
return strippedString;
}
@end
@@ -0,0 +1,13 @@
//
// NSTimer+Blocks.h
//
// Created by Jiva DeVoe on 1/14/11.
// Copyright 2011 Random Ideas, LLC. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface NSTimer (Blocks)
+(id)scheduledTimerWithTimeInterval:(NSTimeInterval)inTimeInterval block:(void (^)())inBlock repeats:(BOOL)inRepeats;
+(id)timerWithTimeInterval:(NSTimeInterval)inTimeInterval block:(void (^)())inBlock repeats:(BOOL)inRepeats;
@end
@@ -0,0 +1,35 @@
//
// NSTimer+Blocks.m
//
// Created by Jiva DeVoe on 1/14/11.
// Copyright 2011 Random Ideas, LLC. All rights reserved.
//
#import "NSTimer+Blocks.h"
@implementation NSTimer (Blocks)
+(id)scheduledTimerWithTimeInterval:(NSTimeInterval)inTimeInterval block:(void (^)())inBlock repeats:(BOOL)inRepeats
{
void (^block)() = [inBlock copy];
id ret = [self scheduledTimerWithTimeInterval:inTimeInterval target:self selector:@selector(jdExecuteSimpleBlock:) userInfo:block repeats:inRepeats];
return ret;
}
+(id)timerWithTimeInterval:(NSTimeInterval)inTimeInterval block:(void (^)())inBlock repeats:(BOOL)inRepeats
{
void (^block)() = [inBlock copy];
id ret = [self timerWithTimeInterval:inTimeInterval target:self selector:@selector(jdExecuteSimpleBlock:) userInfo:block repeats:inRepeats];
return ret;
}
+(void)jdExecuteSimpleBlock:(NSTimer *)inTimer;
{
if([inTimer userInfo])
{
void (^block)() = (void (^)())[inTimer userInfo];
block();
}
}
@end
@@ -0,0 +1,31 @@
//
// UIAlertView+NSCookbook.h
// SimpleAlertViewSampleApp
//
// Copyright (c) 2013 NSCookbook. All rights reserved.
//
// 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 <UIKit/UIKit.h>
@interface UIAlertView (Blocks)
- (void)showWithCompletion:(void(^)(UIAlertView *alertView, NSInteger buttonIndex))completion;
@end
@@ -0,0 +1,75 @@
//
// UIAlertView+NSCookbook.m
// SimpleAlertViewSampleApp
//
// Copyright (c) 2013 NSCookbook. All rights reserved.
//
// 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 <objc/runtime.h>
#import "UIAlertView+Blocks.h"
@interface NSCBAlertWrapper : NSObject <UIAlertViewDelegate>
@property (copy) void(^completionBlock)(UIAlertView *alertView, NSInteger buttonIndex);
@end
@implementation NSCBAlertWrapper
#pragma mark - UIAlertViewDelegate
// Called when a button is clicked. The view will be automatically dismissed after this call returns
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (self.completionBlock)
self.completionBlock(alertView, buttonIndex);
}
// Called when we cancel a view (eg. the user clicks the Home button). This is not called when the user clicks the cancel button.
// If not defined in the delegate, we simulate a click in the cancel button
- (void)alertViewCancel:(UIAlertView *)alertView
{
// Just simulate a cancel button click
if (self.completionBlock)
self.completionBlock(alertView, alertView.cancelButtonIndex);
}
@end
static const char kNSCBAlertWrapper;
@implementation UIAlertView (Blocks)
#pragma mark - Class Public
- (void)showWithCompletion:(void(^)(UIAlertView *alertView, NSInteger buttonIndex))completion
{
NSCBAlertWrapper *alertWrapper = [[NSCBAlertWrapper alloc] init];
alertWrapper.completionBlock = completion;
self.delegate = alertWrapper;
// Set the wrapper as an associated object
objc_setAssociatedObject(self, &kNSCBAlertWrapper, alertWrapper, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
// Show the alert as normal
[self show];
}
@end
@@ -0,0 +1,17 @@
//
// UIButton+Extensions.h
// RobloxMobile
//
// Created by Ashish Jain on 9/4/15.
// Copyright (c) 2015 ROBLOX. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIButton (Extensions)
@property (nonatomic, assign) UIEdgeInsets hitTestEdgeInsets;
- (void)setColor:(UIColor *)color forState:(UIControlState)state;
@end
@@ -0,0 +1,57 @@
//
// UIButton+Extensions.m
// RobloxMobile
//
// Created by Ashish Jain on 9/4/15.
// Copyright (c) 2015 ROBLOX. All rights reserved.
//
#import "UIButton+Extensions.h"
#import <objc/runtime.h>
@implementation UIButton (Extensions)
@dynamic hitTestEdgeInsets;
static const NSString *KEY_HIT_TEST_EDGE_INSETS = @"HitTestEdgeInsets";
-(void)setHitTestEdgeInsets:(UIEdgeInsets)hitTestEdgeInsets {
NSValue *value = [NSValue value:&hitTestEdgeInsets withObjCType:@encode(UIEdgeInsets)];
objc_setAssociatedObject(self, &KEY_HIT_TEST_EDGE_INSETS, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(UIEdgeInsets)hitTestEdgeInsets {
NSValue *value = objc_getAssociatedObject(self, &KEY_HIT_TEST_EDGE_INSETS);
if(value) {
UIEdgeInsets edgeInsets; [value getValue:&edgeInsets]; return edgeInsets;
}else {
return UIEdgeInsetsZero;
}
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
if(UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero) || !self.enabled || self.hidden) {
return [super pointInside:point withEvent:event];
}
CGRect relativeFrame = self.bounds;
CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, self.hitTestEdgeInsets);
return CGRectContainsPoint(hitFrame, point);
}
- (void)setColor:(UIColor *)color forState:(UIControlState)state
{
UIView *colorView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
colorView.backgroundColor = color;
UIGraphicsBeginImageContext(colorView.bounds.size);
[colorView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *colorImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self setBackgroundImage:colorImage forState:state];
}
@end
@@ -0,0 +1,15 @@
//
// UIImage+Utils.h
// RobloxMobile
//
// Created by Christian Hresko on 5/30/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIImage (Utils)
- (UIImage *)imageWithRoundedCornersSize:(float)cornerRadius;
@end
@@ -0,0 +1,37 @@
//
// UIImage+Utils.m
// RobloxMobile
//
// Created by Christian Hresko on 5/30/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import "UIImage+Utils.h"
@implementation UIImage (Utils)
- (UIImage *)imageWithRoundedCornersSize:(float)cornerRadius {
__block UIImageView *imageView;
dispatch_sync(dispatch_get_main_queue(), ^{
imageView = [[UIImageView alloc] initWithImage:self];
// Begin a new image that will be the new image with the rounded corners
// (here with the size of an UIImageView)
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0);
// Add a clip before drawing anything, in the shape of an rounded rect
[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds
cornerRadius:cornerRadius] addClip];
// Draw your image
[self drawInRect:imageView.bounds];
// Get the image, here setting the UIImageView image
imageView.image = UIGraphicsGetImageFromCurrentImageContext();
// Lets forget about that we were drawing
UIGraphicsEndImageContext();
});
return imageView.image;
}
@end
@@ -0,0 +1,15 @@
//
// UIPopOverController+Helpers.h
// RobloxMobile
//
// Created by Ashish Jain on 9/4/15.
// Copyright (c) 2015 ROBLOX. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIPopoverController (Helpers)
- (void) dismissPopoverAnimated:(BOOL)animated completionHandler:(void(^)(void))completionHandler;
@end
@@ -0,0 +1,20 @@
//
// UIPopOverController+Helpers.m
// RobloxMobile
//
// Created by Ashish Jain on 9/4/15.
// Copyright (c) 2015 ROBLOX. All rights reserved.
//
#import "UIPopOverController+Helpers.h"
@implementation UIPopoverController (Helpers)
- (void) dismissPopoverAnimated:(BOOL)animated completionHandler:(void(^)(void))completionHandler {
[CATransaction begin];
[CATransaction setCompletionBlock:completionHandler];
[self dismissPopoverAnimated:animated];
[CATransaction commit];
}
@end
@@ -0,0 +1,22 @@
//
// UIScrollView+Auto.h
// RobloxMobile
//
// Created by Ariel Lichtin on 9/17/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import <UIKit/UIKit.h>
typedef NS_ENUM(NSInteger, UIScrollViewDirection) {
UIScrollViewDirectionNone,
UIScrollViewDirectionHorizontal = 0x1 << 1,
UIScrollViewDirectionVertical = 0x1 << 2,
UIScrollViewDirectionBoth = UIScrollViewDirectionHorizontal | UIScrollViewDirectionVertical
};
@interface UIScrollView (Auto)
- (void) setContentSizeForDirection:(UIScrollViewDirection)direction;
@end
@@ -0,0 +1,33 @@
//
// UIScrollView+Auto.m
// RobloxMobile
//
// Created by Ariel Lichtin on 9/17/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import "UIScrollView+Auto.h"
@implementation UIScrollView (Auto)
- (void) setContentSizeForDirection:(UIScrollViewDirection)direction
{
CGRect contentRect = CGRectZero;
for(UIView* view in self.subviews)
{
if(view.hidden == NO)
{
contentRect = CGRectUnion(contentRect, view.frame);
}
}
if((direction & UIScrollViewDirectionHorizontal) == 0)
contentRect.size.width = self.frame.size.width;
if((direction & UIScrollViewDirectionVertical) == 0)
contentRect.size.height = self.frame.size.height;
self.contentSize = contentRect.size;
}
@end
@@ -0,0 +1,22 @@
//
// UITabBarItem+CustomBadge.h
// CityGlance
//
// Created by Enrico Vecchio on 05/18/14.
// Downloaded from Github and additional functionality added by Kyler Mulherin 10/23/2014.
// Copyright (c) 2014 Cityglance SRL. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UITabBarItem (CustomBadge)
-(void) setMyAppCustomBadgeValue: (NSString *) value;
-(void) setCustomBadgeValue: (NSString *) value withColor: (UIColor *) labelColor;
-(void) setCustomBadgeValue: (NSString *) value withFont: (UIFont *) font andFontColor: (UIColor *) color andBackgroundColor: (UIColor *) backColor;
@end
@@ -0,0 +1,92 @@
//
// UITabBarItem+CustomBadge.m
// CityGlance
//
// Created by Enrico Vecchio on 18/05/14.
// Copyright (c) 2014 Cityglance SRL. All rights reserved.
//
#import "UITabBarItem+CustomBadge.h"
#define CUSTOM_BADGE_TAG 99
#define OFFSET 0.6f
@implementation UITabBarItem (CustomBadge)
-(void) setMyAppCustomBadgeValue: (NSString *) value
{
UIFont *myAppFont = [UIFont systemFontOfSize:13.0];
UIColor *myAppFontColor = [UIColor whiteColor];
UIColor *myAppBackColor = [UIColor lightGrayColor];
[self setCustomBadgeValue:value withFont:myAppFont andFontColor:myAppFontColor andBackgroundColor:myAppBackColor];
}
-(void) setCustomBadgeValue: (NSString *) value
withColor: (UIColor *) labelColor
{
UIFont *myAppFont = [UIFont systemFontOfSize:13.0];
UIColor *myAppFontColor = [UIColor whiteColor];
[self setCustomBadgeValue:value withFont:myAppFont andFontColor:myAppFontColor andBackgroundColor:labelColor];
}
-(void) setCustomBadgeValue: (NSString *) value withFont: (UIFont *) font andFontColor: (UIColor *) color andBackgroundColor: (UIColor *) backColor
{
UIView *v = [self valueForKey:@"view"];
[self setBadgeValue:value];
// REMOVE PREVIOUS IF EXIST
for(UIView *sv in v.subviews)
{
if(sv.tag == CUSTOM_BADGE_TAG)
{
[sv removeFromSuperview];
continue;
}
}
for(UIView *sv in v.subviews)
{
NSString *str = NSStringFromClass([sv class]);
if([str isEqualToString:@"_UIBadgeView"])
{
UILabel *l = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, sv.frame.size.width, sv.frame.size.height)];
[l setFont:font];
[l setText:value];
[l setBackgroundColor:backColor];
[l setTextColor:color];
[l setTextAlignment:NSTextAlignmentCenter];
l.layer.cornerRadius = l.frame.size.height/2;
l.layer.masksToBounds = YES;
// Fix for border
sv.layer.borderWidth = 1;
sv.layer.borderColor = [backColor CGColor];
sv.layer.cornerRadius = sv.frame.size.height/2;
sv.layer.masksToBounds = YES;
[sv addSubview:l];
l.tag = CUSTOM_BADGE_TAG;
}
}
}
@end
@@ -0,0 +1,25 @@
//
// UIView+Position.h
// RobloxMobile
//
// Created by Ariel Lichtin on 9/17/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIView (Position)
@property (nonatomic, assign) CGPoint position;
@property (nonatomic, assign) CGSize size;
@property (nonatomic, assign) CGFloat height;
@property (nonatomic, assign) CGFloat width;
@property (nonatomic, assign) CGFloat x;
@property (nonatomic, assign) CGFloat y;
@property (nonatomic, assign) CGFloat right;
@property (nonatomic, assign) CGFloat bottom;
- (void) centerInFrame:(CGRect)aFrame;
@end
@@ -0,0 +1,126 @@
//
// UIView+Position.m
// RobloxMobile
//
// Created by Ariel Lichtin on 9/17/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import "UIView+Position.h"
@implementation UIView (Position)
- (CGPoint) position
{
return self.frame.origin;
}
- (CGFloat) height
{
return self.frame.size.height;
}
- (CGFloat) width
{
return self.frame.size.width;
}
- (CGFloat) x
{
return self.frame.origin.x;
}
- (CGFloat) y
{
return self.frame.origin.y;
}
- (CGFloat) centerY
{
return self.center.y;
}
- (CGFloat) centerX
{
return self.center.x;
}
- (CGSize) size
{
return self.frame.size;
}
- (void)setPosition:(CGPoint)newPosition
{
CGRect frame = self.frame;
frame.origin = newPosition;
self.frame = frame;
}
- (void) setHeight:(CGFloat)newHeight
{
CGRect frame = self.frame;
frame.size.height = newHeight;
self.frame = frame;
}
- (void) setWidth:(CGFloat)newWidth
{
CGRect frame = self.frame;
frame.size.width = newWidth;
self.frame = frame;
}
- (void) setX:(CGFloat)newX
{
CGRect frame = self.frame;
frame.origin.x = newX;
self.frame = frame;
}
- (void) setY:(CGFloat)newY
{
CGRect frame = self.frame;
frame.origin.y = newY;
self.frame = frame;
}
- (void) setSize:(CGSize)size
{
CGRect frame = self.frame;
frame.size = size;
self.frame = frame;
}
- (CGFloat) right
{
return self.x + self.width;
}
- (void)setRight:(CGFloat)right
{
self.x = right - self.width;
}
- (CGFloat) bottom
{
return self.y + self.height;
}
- (void)setBottom:(CGFloat)bottom
{
self.y = bottom - self.height;
}
- (void) centerInFrame:(CGRect)aFrame
{
float h = [self height];
float w = [self width];
//center our frame to the provided frame
CGRect centeredFrame = CGRectMake(CGRectGetMidX(aFrame) - (w * 0.5),
CGRectGetMidY(aFrame) - (h * 0.5),
w, h);
self.frame = centeredFrame;
}
@end
@@ -0,0 +1,42 @@
//
// UIView+DTDebug.h
// DTFoundation
//
// Created by Stefan Gugarel on 2/8/13.
// Copyright (c) 2013 Cocoanetics. All rights reserved.
//
#import <UIKit/UIView.h>
/**
Methods useful for debugging problems with UIView instances.
*/
@interface UIView (DTDebug)
/**
@name Main Thread Checking
*/
/**
Toggles on/off main thread checking on several methods of UIView.
Currently the following methods are swizzeled and checked:
- setNeedsDisplay
- setNeedsDisplayInRect:
- setNeedsLayout
Those are triggered by a variety of methods in UIView, e.g. setBackgroundColor and thus it is not necessary to swizzle all of them.
*/
+ (void)toggleViewMainThreadChecking;
/**
Method that gets called if one of the important methods of UIView is not being called on a main queue.
Toggle this on/off with <toggleViewMainThreadChecking>. Break on -[UIView methodCalledNotFromMainThread:] to catch it in debugger.
@param methodName Symbolic name of the method being called
*/
- (void)methodCalledNotFromMainThread:(NSString *)methodName;
@end
@@ -0,0 +1,79 @@
//
// UIView+DTDebug.m
// DTFoundation
//
// Created by Stefan Gugarel on 2/8/13.
// Copyright (c) 2013 Cocoanetics. All rights reserved.
//
#import "UIView+RBDebug.h"
#import <objc/runtime.h>
@implementation UIView (DTDebug)
+ (void)swizzleMethod:(SEL)selector withMethod:(SEL)otherSelector
{
// my own class is being targetted
Class c = [self class];
// get the methods from the selectors
Method originalMethod = class_getInstanceMethod(c, selector);
Method otherMethod = class_getInstanceMethod(c, otherSelector);
if (class_addMethod(c, selector, method_getImplementation(otherMethod), method_getTypeEncoding(otherMethod)))
{
class_replaceMethod(c, otherSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}
else
{
method_exchangeImplementations(originalMethod, otherMethod);
}
}
- (void)methodCalledNotFromMainThread:(NSString *)methodName
{
NSLog(@"-[%@ %@] being called on background queue. Break on -[UIView methodCalledNotFromMainThread:] to find out where", NSStringFromClass([self class]), methodName);
}
- (void)_setNeedsLayout_MainThreadCheck
{
if (![NSThread isMainThread])
{
[self methodCalledNotFromMainThread:NSStringFromSelector(_cmd)];
}
// not really an endless loop, this calls the original
[self _setNeedsLayout_MainThreadCheck];
}
- (void)_setNeedsDisplay_MainThreadCheck
{
if (![NSThread isMainThread])
{
[self methodCalledNotFromMainThread:NSStringFromSelector(_cmd)];
}
// not really an endless loop, this calls the original
[self _setNeedsDisplay_MainThreadCheck];
}
- (void)_setNeedsDisplayInRect_MainThreadCheck:(CGRect)rect
{
if (![NSThread isMainThread])
{
[self methodCalledNotFromMainThread:NSStringFromSelector(_cmd)];
}
// not really an endless loop, this calls the original
[self _setNeedsDisplayInRect_MainThreadCheck:rect];
}
+ (void)toggleViewMainThreadChecking
{
[UIView swizzleMethod:@selector(setNeedsLayout) withMethod:@selector(_setNeedsLayout_MainThreadCheck)];
[UIView swizzleMethod:@selector(setNeedsDisplay) withMethod:@selector(_setNeedsDisplay_MainThreadCheck)];
[UIView swizzleMethod:@selector(setNeedsDisplayInRect:) withMethod:@selector(_setNeedsDisplayInRect_MainThreadCheck:)];
}
@end
@@ -0,0 +1,16 @@
//
// UIView+Helpers.h
// RobloxMobile
//
// Created by Ariel Lichtin on 6/11/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface UIViewController (Helpers)
// Returns the most topmost view controller
+ (UIViewController*) topViewController;
@end
@@ -0,0 +1,42 @@
//
// UIView+Helpers.m
// RobloxMobile
//
// Created by Ariel Lichtin on 6/11/14.
// Copyright (c) 2014 ROBLOX. All rights reserved.
//
#import "UIViewController+Helpers.h"
#import "RobloxTheme.h"
@implementation UIViewController (Helpers)
+ (UIViewController*) topViewController
{
return [UIViewController topViewController:[UIApplication sharedApplication].keyWindow.rootViewController];
}
+ (UIViewController *)topViewController:(UIViewController *)rootViewController
{
if (rootViewController.presentedViewController == nil)
{
return rootViewController;
}
else if ([rootViewController.presentedViewController isKindOfClass:[UINavigationController class]])
{
UINavigationController *navigationController = (UINavigationController *)rootViewController.presentedViewController;
UIViewController *lastViewController = [[navigationController viewControllers] lastObject];
return [self topViewController:lastViewController];
}
else if([rootViewController.presentedViewController isKindOfClass:[UIAlertController class]])
{
return rootViewController;
}
else
{
UIViewController *presentedViewController = (UIViewController *)rootViewController.presentedViewController;
return [self topViewController:presentedViewController];
}
}
@end
@@ -0,0 +1,15 @@
//
// UIWebView+RBXUIWebView.h
// RobloxMobile
//
// Created by Ashish Jain on 9/30/15.
// Copyright (c) 2015 ROBLOX. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "RBXWebViewProtocol.h"
@interface UIWebView (RBXUIWebView) <RBXWebViewProtocol>
@end
@@ -0,0 +1,72 @@
//
// UIWebView+RBXUIWebView.m
// RobloxMobile
//
// Created by Ashish Jain on 9/30/15.
// Copyright (c) 2015 ROBLOX. All rights reserved.
//
#import "UIWebView+RBXUIWebView.h"
#import "RBXFunctions.h"
#import "RBHybridBridge.h"
@implementation UIWebView (RBXUIWebView)
@dynamic URL;
- (void) setDelegateController:(id)delegate
{
[self setDelegate:delegate];
}
- (NSURL *) URL
{
return [[self request] URL];
}
- (void) evaluateJavaScript:(NSString *)javaScriptString completionHandler:(void (^)(id, NSError *))completionHandler
{
NSString *js = [self stringByEvaluatingJavaScriptFromString:javaScriptString];
if (completionHandler) {
completionHandler(js, nil);
}
}
- (BOOL) canGoBackInHistory
{
BOOL val = self.canGoBack;
return val;
}
- (BOOL) canGoForwardInHistory
{
BOOL val = self.canGoForward;
return val;
}
- (void) goBackInHistory
{
if ([self canGoBack]) {
[self goBack];
}
}
- (void) goForwardInHistory
{
if ([self canGoForward]) {
[self goForward];
}
}
- (void) enableScrolling:(BOOL)enable
{
self.scrollView.scrollEnabled = enable;
}
- (void) enableMultipleTouch:(BOOL)enable
{
self.multipleTouchEnabled = enable;
}
@end
@@ -0,0 +1,15 @@
//
// WKWebView+RBXWKWebView.h
// RobloxMobile
//
// Created by Ashish Jain on 9/30/15.
// Copyright (c) 2015 ROBLOX. All rights reserved.
//
#import <WebKit/WebKit.h>
#import "RBXWebViewProtocol.h"
@interface WKWebView (RBXWKWebView) <RBXWebViewProtocol>
@end
@@ -0,0 +1,130 @@
//
// WKWebView+RBXWKWebView.m
// RobloxMobile
//
// Created by Ashish Jain on 9/30/15.
// Copyright (c) 2015 ROBLOX. All rights reserved.
//
#import "WKWebView+RBXWKWebView.h"
#import "LoginManager.h"
#import "RBXFunctions.h"
#import "RBHybridBridge.h"
#import "RobloxInfo.h"
#import <objc/runtime.h>
@implementation WKWebView (RBXWKWebView)
- (void) setDelegateController:(id)delegate
{
[self setNavigationDelegate:delegate];
[self setUIDelegate:delegate];
}
- (NSURLRequest *) request
{
return objc_getAssociatedObject(self, @selector(request));
}
- (void) setRequest:(NSURLRequest *)request
{
objc_setAssociatedObject(self, @selector(request), request, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
+ (void) load
{
static dispatch_once_t onceToken;
// We want to make sure this is only done once!
dispatch_once(&onceToken, ^{
Class class = [self class];
// Get the representation of the method names to swizzle.
SEL originalSelector = @selector(loadRequest:);
SEL swizzledSelector = @selector(altLoadRequest:);
// Get references to the methods to swizzle.
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
// Attempt to add the new method in place of the old method.
BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
// If we succeeded, put the old method in place of the new method.
if (didAddMethod) {
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
} else {
// Otherwise, just swap their implementations.
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}
// 2015.1026 ajain - This requires a little mental juggling. We do a swizzle (replace implementations) of
// the loadRequest method with altLoadRequest. That way, every time another class calls loadRequest on a WKWebView object, it'll
// actually execute the altLoadRequest method.
// Example: Outside class calls [[WKWebView instance] loadRequest] --> executes
// altLoadRequest implementation (custom code below) --> calls
// [self altLoadRequest:mutableRequest] --> executes
// original loadRequest implementation (apple wkwebview code).
// The method swizzling is why calling altLoadRequest is NOT a recursive method call.
- (void) altLoadRequest:(NSURLRequest *)request
{
NSArray *cookies = [LoginManager cookies];
NSDictionary *cookiesDict = [NSHTTPCookie requestHeaderFieldsWithCookies:cookies];
NSMutableDictionary *requestHeaders = [NSMutableDictionary dictionaryWithDictionary:request.allHTTPHeaderFields];
[requestHeaders addEntriesFromDictionary:cookiesDict];
NSMutableURLRequest *mutableRequest = request.mutableCopy;
[mutableRequest setAllHTTPHeaderFields:requestHeaders];
[self setRequest:mutableRequest];
// 2015.1026 ajain - Since we swizzled with loadRequest, this will actually call the original loadRequest.
[self altLoadRequest:mutableRequest];
}
- (BOOL) canGoBackInHistory
{
BOOL val = self.canGoBack;
return val;
}
- (BOOL) canGoForwardInHistory
{
BOOL val = self.canGoForward;
return val;
}
- (void) goBackInHistory
{
if ([self canGoBack]) {
[self goBack];
}
}
- (void) goForwardInHistory
{
if ([self canGoForward]) {
[self goForward];
}
}
- (void) enableScrolling:(BOOL)enable
{
self.scrollView.scrollEnabled = enable;
}
- (void) enableMultipleTouch:(BOOL)enable
{
self.multipleTouchEnabled = enable;
}
@end