├── GBToolboxUnitTests
├── en.lproj
│ └── InfoPlist.strings
├── GBToolboxUnitTests-Prefix.pch
├── GBToolboxUnitTests.h
└── GBToolboxUnitTests-Info.plist
├── GBToolbox.xcodeproj
└── project.xcworkspace
│ └── contents.xcworkspacedata
├── GBToolbox
├── GBAddress.m
├── GBTestView.h
├── GBTypes_OSX.h
├── GBToolbox-Prefix.pch
├── NSData+GBToolbox.h
├── NSImage+GBToolbox.h
├── UISearchBar+GBToolbox.h
├── GBEnumWrapper.h
├── GBSolidColorView.h
├── GBConstants_Common.h
├── GBFrameChangedProtocol.h
├── CALayer+GBToolbox.h
├── GBMessageInterceptor.h
├── UIColor+GBToolbox.h
├── GBUtility_OSX.h
├── UIScreen+GBToolbox.h
├── GBResizableImageView.h
├── UIControl+GBToolbox.h
├── GBTypes_iOS.h
├── GBGlowingImageButtonCell.h
├── GBConstants_Common.m
├── GBDebuggableInstanceVendor.h
├── UISearchBar+GBToolbox.m
├── GBCustomNavigationBar.h
├── NSDate+GBToolbox.h
├── UINavigationBar+GBToolbox.h
├── GBControlAggregator.h
├── NSMutableDictionary+GBToolbox.h
├── UIView+GBOwningViewController.h
├── NSView+GBToolbox.h
├── GBTextView.h
├── GBUtility_OSX.m
├── GBCache.h
├── UIColor+GBToolbox.m
├── NSTimer+GBToolbox.h
├── UITableViewCell+AdditionalViews.h
├── GBGradientView.h
├── UIScrollView+GBToolbox.h
├── CALayer+GBToolbox.m
├── NSInvocation+GBToolbox.h
├── GBAddress.h
├── GBCustomImageButtonCell.h
├── GBRadialGradientView.h
├── GBEnumWrapper.m
├── GBButton.h
├── GBMacros_OSX.h
├── GBToggleControl.h
├── GBSolidColorView.m
├── UIScreen+GBToolbox.m
├── UITableView+GBToolbox.h
├── GBCustomViewButtonCell.h
├── NSImage+GBToolbox.m
├── UINavigationBar+GBToolbox.m
├── NSMutableDictionary+GBToolbox.m
├── GBColoredBarView.h
├── MKMapView+GBToolbox.h
├── UIImageView+GBToolbox.h
├── NSData+GBToolbox.m
├── GBCAAnimationDelegateHandler.h
├── GBTestView.m
├── GBCAAnimationDelegateHandler.m
├── GBCache.m
├── GBMessageInterceptor.m
├── GBCompletable.h
├── GBAsyncOperation.h
├── NSSet+GBToolbox.h
├── GBRoundBadgeView.h
├── GBToolbox-Info.plist
├── GBTableViewController.h
├── GBRemoteDebugMessages.h
├── NSView+GBToolbox.m
├── UIScrollView+GBToolbox.m
├── GBCustomNavigationBar.m
├── NSMapTable+GBToolbox.h
├── NSSet+GBToolbox.m
├── GBToggleControlRadioGroupManager.h
├── NSMapTable+GBToolbox.m
├── NSOrderedSet+GBToolbox.h
├── GBHighPrecisionTimer.h
├── GBKeyboardListener.h
├── NSMutableArray+GBToolbox.h
├── UIImage+GBToolbox.h
├── UITableView+GBToolbox.m
├── NSTimer+GBToolbox.m
├── NSInvocation+GBToolbox.m
├── UIView+GBOwningViewController.m
├── UIViewController+GBToolbox.h
├── GBAlertBadge.h
├── GBGradientView.m
├── UIView+GBPopUp.h
├── NSObject+GBToolbox.h
├── NSOrderedSet+GBToolbox.m
├── UIImageView+GBToolbox.m
├── NSDictionary+GBToolbox.h
├── GBAlertBadgeView.h
├── GBRadialGradientView.m
├── GBTextField.h
├── GBGlowingImageButtonCell.m
├── NSDate+GBToolbox.m
├── MKMapView+GBToolbox.m
├── GBTextBox.h
├── GBAsyncOperation.m
├── GBMultiStateButton.h
├── GBCustomImageButtonCell.m
├── UIControl+GBToolbox.m
├── NSDictionary+GBToolbox.m
├── NSObject+GBToolbox.m
├── UIView+GBFloatingPopoverView.h
├── NSMutableURLRequest+GBToolbox.h
├── NSMutableArray+GBToolbox.m
├── GBToggleControl.m
├── GBCompletable.m
├── GBButton.m
├── GBHighPrecisionTimer.m
├── GBTextView.m
├── UITableViewCell+AdditionalViews.m
├── UIViewController+GBToolbox.m
├── GBFastArray.h
├── GBMacros_iOS.h
├── NSString+GBToolbox.h
├── GBToolbox.h
├── GBToggleControlRadioGroupManager.m
├── GBTypes_Common.h
├── GBKeyboardListener.m
├── UIView+GBToolbox.h
├── GBUtility_iOS.h
├── NSArray+GBToolbox.h
├── GBFastArray.m
├── GBRemoteDebugMessages.m
├── GBRoundBadgeView.m
└── GBColoredBarView.m
├── README.md
└── .gitignore
/GBToolboxUnitTests/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/GBToolbox.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/GBToolbox/GBAddress.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBAddress.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 07/06/2014.
6 | // Copyright (c) 2014 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBAddress.h"
10 |
11 | @implementation GBAddress
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/GBToolboxUnitTests/GBToolboxUnitTests-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header for all source files of the 'GBToolboxUnitTests' target in the 'GBToolboxUnitTests' project
3 | //
4 |
5 | #ifdef __OBJC__
6 | #import
7 | #import
8 | #endif
9 |
--------------------------------------------------------------------------------
/GBToolbox/GBTestView.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBTestView.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 12/07/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GBTestView : UIView
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/GBToolbox/GBTypes_OSX.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBTypes_OSX.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 11/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #ifndef GBToolbox_GBTypes_OSX_h
10 | #define GBToolbox_GBTypes_OSX_h
11 |
12 | #endif
13 |
--------------------------------------------------------------------------------
/GBToolbox/GBToolbox-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header for all source files of the 'GBToolbox' target in the 'GBToolbox' project
3 | //
4 |
5 | #ifdef __OBJC__
6 | #if IPHONE
7 | #import
8 | #import
9 | #else
10 | #import
11 | #endif
12 | #endif
13 |
--------------------------------------------------------------------------------
/GBToolbox/NSData+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSData+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSData (GBToolbox)
12 |
13 | //md5 hash
14 | -(NSString *)md5;
15 |
16 | @end
--------------------------------------------------------------------------------
/GBToolbox/NSImage+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSImage+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSImage (GBToolbox)
12 |
13 | -(void)saveAsJpegWithName:(NSString *)fileName;
14 |
15 | @end
--------------------------------------------------------------------------------
/GBToolboxUnitTests/GBToolboxUnitTests.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBToolboxUnitTests.h
3 | // GBToolboxUnitTests
4 | //
5 | // Created by Luka Mirosevic on 23/11/2012.
6 | // Copyright (c) 2012 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GBToolboxUnitTests : SenTestCase
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/GBToolbox/UISearchBar+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // UISearchBar+GBToolbox.h
3 | // Pods
4 | //
5 | // Created by Luka Mirosevic on 18/10/2016.
6 | //
7 | //
8 |
9 | #import
10 |
11 | @interface UISearchBar (GBToolbox)
12 |
13 | /**
14 | Returns the UITextField inside the UISearchBar.
15 | */
16 | - (nullable UITextField *)textField;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/GBToolbox/GBEnumWrapper.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBEnumWrapper.h
3 | // World Cup Survival Guide
4 | //
5 | // Created by Luka Mirosevic on 06/06/2014.
6 | // Copyright (c) 2014 Goonbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GBEnumWrapper : NSObject
12 |
13 | -(id)initWithInt:(int)value;
14 | -(int)intValue;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/GBToolbox/GBSolidColorView.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBSolidColorView.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 13/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GBSolidColorView : NSView
12 |
13 | @property (strong, nonatomic) NSColor *color;
14 |
15 | -(id)initWithColor:(NSColor *)color;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/GBToolbox/GBConstants_Common.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBConstants_Common.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 15/05/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | //Exceptions
10 | extern NSString * const GBTypeMismatchException;
11 | extern NSString * const GBUnexpectedMessageException;
12 |
13 | //Constants
14 | extern NSUInteger const kGBSearchResultNotFound;
--------------------------------------------------------------------------------
/GBToolbox/GBFrameChangedProtocol.h:
--------------------------------------------------------------------------------
1 | //
2 | // FrameChangedProtocol.h
3 | // Russia
4 | //
5 | // Created by Luka Mirosevic on 02/07/2013.
6 | // Copyright (c) 2013 Goonbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @protocol GBFrameChangedProtocol
12 | @required
13 |
14 | -(void)viewController:(id)viewController didChangeFrameTo:(CGRect)frame;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/GBToolbox/CALayer+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // CALayer+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 11/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface CALayer (GBToolbox)
12 |
13 | //enumarate all sublayers depth first
14 | -(void)enumerateSublayersWithBlock:(void(^)(CALayer *layer))block;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/GBToolbox/GBMessageInterceptor.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBMessageInterceptor.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 21/06/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GBMessageInterceptor : NSObject
12 |
13 | @property (nonatomic, assign) id receiver;
14 | @property (nonatomic, assign) id middleMan;
15 |
16 | @end
--------------------------------------------------------------------------------
/GBToolbox/UIColor+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 28/08/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIColor (GBToolbox)
12 |
13 | //returns a random color (random hue with brightness: 0.5, saturation: 0.5, alpha: 1.0)
14 | +(UIColor *)randomColor;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/GBToolbox/GBUtility_OSX.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBUtility_OSX.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBTypes_Common.h"
10 | #import "GBTypes_OSX.h"
11 |
12 | #import "GBUtility_Common.h"
13 |
14 | @interface GBToolbox (OSX)
15 |
16 | #pragma mark - App Store redirect
17 |
18 | void RedirectToAppStore(NSString *appID);
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/GBToolbox/UIScreen+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIScreen+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 23/02/16.
6 | // Copyright © 2016 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIScreen (GBToolbox)
12 |
13 | /**
14 | Returns the bounds of the display, irrespective of the rotation.
15 | */
16 | @property (assign, nonatomic, readonly) CGRect fixedBounds;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/GBToolbox/GBResizableImageView.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBResizableImageView.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 04/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "GBToolbox.h"
12 |
13 | @interface GBResizableImageView : NSImageView
14 |
15 | @property (strong, atomic) NSImage *image;
16 | @property (assign, nonatomic) GBEdgeInsets capInsets;
17 |
18 | @end
--------------------------------------------------------------------------------
/GBToolbox/UIControl+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIControl+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 20/02/2016.
6 | // Copyright © 2016 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | typedef void(^GBActionBlock)(id sender, UIEvent *event);
12 |
13 | @interface UIControl (GBToolbox)
14 |
15 | - (void)addTargetActionForControlEvents:(UIControlEvents)controlEvents withBlock:(GBActionBlock)block;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/GBToolbox/GBTypes_iOS.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBTypes_iOS.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 11/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #ifndef GBToolbox_GBTypes_iOS_h
10 | #define GBToolbox_GBTypes_iOS_h
11 |
12 | #pragma mark - Device stuff
13 |
14 | typedef enum {
15 | Phone,
16 | Pad
17 | } GBDevice;
18 |
19 | typedef enum {
20 | Portrait,
21 | Landscape
22 | } GBOrientation;
23 |
24 | #endif
25 |
--------------------------------------------------------------------------------
/GBToolbox/GBGlowingImageButtonCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBGlowingImageButtonCell.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 13/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBCustomImageButtonCell.h"
10 |
11 | @interface GBGlowingImageButtonCell : GBCustomImageButtonCell
12 |
13 | @property (assign, nonatomic) BOOL isGlowing;
14 | @property (assign, nonatomic) GBEdgeInsets glowEdgeInsets;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/GBToolbox/GBConstants_Common.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBConstants_Common.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 15/05/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBConstants_Common.h"
10 |
11 | NSString * const GBTypeMismatchException = @"GBTypeMismatchException";
12 | NSString * const GBUnexpectedMessageException = @"GBUnexpectedMessageException";
13 |
14 | NSUInteger const kGBSearchResultNotFound = NSNotFound;
--------------------------------------------------------------------------------
/GBToolbox/GBDebuggableInstanceVendor.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBDebuggableInstanceVendor.h
3 | // BindSafe
4 | //
5 | // Created by Luka Mirosevic on 28/03/16.
6 | // Copyright © 2016 Goonbee e.U. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @protocol GBDebuggableInstanceVendor
12 |
13 | @required
14 |
15 | /**
16 | Convenience method for creating a new instance for debugging purposes.
17 | */
18 | + (instancetype)debuggingInstance;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/GBToolbox/UISearchBar+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // UISearchBar+GBToolbox.m
3 | // Pods
4 | //
5 | // Created by Luka Mirosevic on 18/10/2016.
6 | //
7 | //
8 |
9 | #import "UISearchBar+GBToolbox.h"
10 |
11 | @implementation UISearchBar (GBToolbox)
12 |
13 | - (nullable UITextField *)textField {
14 | if (@available(iOS 13, *)) {
15 | return [self searchTextField];
16 | } else {
17 | return (UITextField *)[self valueForKey:@"searchField"];
18 | }
19 | }
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/GBToolbox/GBCustomNavigationBar.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBCustomNavigationBar.h
3 | // Xmas List
4 | //
5 | // Created by Luka Mirosevic on 29/11/2012.
6 | // Copyright (c) 2012 Goonbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GBCustomNavigationBar : UINavigationBar
12 |
13 | @property (assign, nonatomic, readonly) CGFloat navBarHeight;
14 |
15 | +(Class)navigationBarClassWithHeight:(CGFloat)height;
16 | -(id)initWithNavBarHeight:(CGFloat)height;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/GBToolbox/NSDate+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSDate+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 21/06/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSDate (GBToolbox)
12 |
13 | +(NSDate *)dateWithISO8601String:(NSString *)dateString;
14 | -(NSString *)iso8601String;
15 | -(BOOL)isInPast;
16 | -(BOOL)isDateBetweenStartDate:(NSDate*)beginDate andEndDate:(NSDate*)endDate;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/GBToolbox/UINavigationBar+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // UINavigationBar+GBToolbox.h
3 | // Pods
4 | //
5 | // Created by Luka Mirosevic on 18/09/2016.
6 | //
7 | //
8 |
9 | #import
10 |
11 | @interface UINavigationBar (GBToolbox)
12 |
13 | /**
14 | Set the navigation bar background color with a more sane behaviour than the standard Cocoa Touch methods.
15 |
16 | If color is nil, the bar will be transparent.
17 | */
18 | - (void)styleWithColor:(nullable UIColor *)color;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/GBToolbox/GBControlAggregator.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBControlAggregator.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 20/02/2016.
6 | // Copyright © 2016 Goonbee e.U. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GBControlAggregator : UIControl
12 |
13 | @property (strong, nonatomic, readonly) NSArray<__kindof UIControl *> *controls;
14 |
15 | - (instancetype)initWithControls:(NSArray *)controls axis:(UILayoutConstraintAxis)axis;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/GBToolbox/NSMutableDictionary+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSMutableDictionary+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 06/06/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSMutableDictionary (GBToolbox)
12 |
13 | #pragma mark - Pruning
14 |
15 | /**
16 | Removes all intances of NSNull from this dictionary (shallow search only).
17 | */
18 | - (void)pruneNulls;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/GBToolbox/UIView+GBOwningViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+GBOwningViewController.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 08/06/2017.
6 | // Copyright (c) 2017 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIView (GBOwningViewController)
12 |
13 | /**
14 | The view controller that currently has this view set as its `view` property.
15 | */
16 | @property (weak, nonatomic, nullable, readonly) UIViewController *GBOwningViewController;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/GBToolbox/NSView+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSView+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSView (GBToolbox)
12 |
13 | //returns the view's frame in global coordinates
14 | @property (assign, nonatomic, readonly) NSRect globalFrame;
15 |
16 | //enumarate all subviews depth first
17 | -(void)enumerateSubviewsWithBlock:(void(^)(NSView *view))block;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/GBToolbox/GBTextView.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBTextView.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 28/06/2013.
6 | // Copyright (c) 2013 Goonbee. All rights reserved.
7 | //
8 | // Original code from SO: http://stackoverflow.com/a/1704469/399772
9 |
10 | #import
11 |
12 | @interface GBTextView : UITextView
13 |
14 | @property (nonatomic, retain) NSString *placeholder;
15 | @property (nonatomic, retain) UIColor *placeholderColor;
16 |
17 | -(void)textChanged:(NSNotification*)notification;
18 |
19 | @end
--------------------------------------------------------------------------------
/GBToolbox/GBUtility_OSX.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBUtility_OSX.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBUtility_OSX.h"
10 |
11 | @implementation GBToolbox (OSX)
12 |
13 | #pragma mark - App Store redirect
14 |
15 | void RedirectToAppStore(NSString *appID) {
16 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[NSString stringWithFormat:@"macappstore://itunes.apple.com/app/id%@?mt=12", appID]]];
17 | }
18 |
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/GBToolbox/GBCache.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBCache.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 10/04/2014.
6 | // Copyright (c) 2014 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | extern NSUInteger const kGBCacheUnlimitedCacheSize;
12 |
13 | @interface GBCache : NSCache
14 |
15 | @property (assign, nonatomic) NSUInteger maxCacheSize;//default: kGBCacheUnlimitedCacheSize
16 |
17 | -(id)objectForKeyedSubscript:(id)key;
18 | -(void)setObject:(id)obj forKeyedSubscript:(id)key;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/GBToolbox/UIColor+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 28/08/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "UIColor+GBToolbox.h"
10 |
11 | #define ARC4RANDOM_MAX 0x100000000
12 |
13 | @implementation UIColor (GBToolbox)
14 |
15 | +(UIColor *)randomColor {
16 | CGFloat randomHue = ((double)arc4random() / ARC4RANDOM_MAX);
17 | return [UIColor colorWithHue:randomHue saturation:0.5 brightness:0.5 alpha:1];
18 | }
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/GBToolbox/NSTimer+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSTimer+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSTimer (GBToolbox)
12 |
13 | //blocks
14 | +(NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats withBlock:(void(^)(void))block;
15 | +(NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats withBlock:(void(^)(void))block;
16 |
17 | @end
--------------------------------------------------------------------------------
/GBToolbox/UITableViewCell+AdditionalViews.h:
--------------------------------------------------------------------------------
1 | //
2 | // UITableViewCell+AdditionalViews.h
3 | // Russia
4 | //
5 | // Created by Luka Mirosevic on 27/06/2013.
6 | // Copyright (c) 2013 Goonbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UITableViewCell (AdditionalViews)
12 |
13 | @property (strong, nonatomic) UIView *leftView;
14 | @property (assign, nonatomic) CGRect leftViewFrame;
15 | @property (strong, nonatomic) UIView *rightView;
16 | @property (assign, nonatomic) CGRect rightViewFrame;
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/GBToolbox/GBGradientView.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBGradientView.h
3 | // Pods
4 | //
5 | // Created by Luka Mirosevic on 13/11/2014.
6 | //
7 | //
8 |
9 | #import
10 |
11 | @interface GBGradientView : UIView
12 |
13 | typedef NS_ENUM(NSInteger, GBGradientDimension) {
14 | GBGradientDimensionVertical,
15 | GBGradientDimensionHorizontal,
16 | };
17 |
18 | /**
19 | Creates a GBGradientView with it's background set to a gradient.
20 | */
21 | + (instancetype)gradientViewWithColors:(NSArray *)colors dimension:(GBGradientDimension)dimension;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/GBToolbox/UIScrollView+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIScrollView+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 27/06/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIScrollView (GBToolbox)
12 |
13 | //Scrolling
14 | -(void)scrollToOriginAnimated:(BOOL)animated;
15 | -(void)scrollToTopAnimated:(BOOL)animated;
16 | -(void)scrollToBottomAnimated:(BOOL)animated;
17 | -(void)scrollToLeftAnimated:(BOOL)animated;
18 | -(void)scrollToRightAnimated:(BOOL)animated;
19 |
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/GBToolbox/CALayer+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // CALayer+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 11/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "CALayer+GBToolbox.h"
10 |
11 | @implementation CALayer (GBToolbox)
12 |
13 | -(void)enumerateSublayersWithBlock:(void(^)(CALayer *layer))block {
14 | //itself
15 | block(self);
16 |
17 | //then all its subviews
18 | for (CALayer *sublayer in self.sublayers) {
19 | [sublayer enumerateSublayersWithBlock:block];
20 | }
21 | }
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/GBToolbox/NSInvocation+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSInvocation+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 30/04/2014.
6 | // Copyright (c) 2014 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSInvocation (GBToolbox)
12 |
13 | +(NSInvocation *)invocationWithTarget:(id)target selector:(SEL)selector arguments:(void *)argument, ... NS_REQUIRES_NIL_TERMINATION;
14 | +(NSInvocation *)invocationWithTarget:(id)target selector:(SEL)selector argument:(void *)argument argumentList:(va_list)argumentList;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/GBToolbox/GBAddress.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBAddress.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 07/06/2014.
6 | // Copyright (c) 2014 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GBAddress : NSObject
12 |
13 | @property (copy, nonatomic) NSString *street;
14 | @property (copy, nonatomic) NSString *city;
15 | @property (copy, nonatomic) NSString *postCode;
16 | @property (copy, nonatomic) NSString *country;
17 | @property (copy, nonatomic) NSString *countryCode;
18 | @property (copy, nonatomic) NSString *state;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/GBToolbox/GBCustomImageButtonCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBCustomImageButtonCell.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 13/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBCustomViewButtonCell.h"
10 |
11 | #import "GBTypes_Common.h"
12 |
13 | @interface GBCustomImageButtonCell : GBCustomViewButtonCell
14 |
15 | @property (strong, nonatomic) NSImage *backgroundImage;
16 | @property (assign, nonatomic) GBEdgeInsets backgroundImageCapInsets;
17 | @property (strong, nonatomic) NSImage *foregroundImage;
18 |
19 | @end
20 |
--------------------------------------------------------------------------------
/GBToolbox/GBRadialGradientView.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBRadialGradientView.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 11/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "GBToolbox.h"
12 |
13 | @interface GBRadialGradientView : NSView
14 |
15 | @property (strong, nonatomic) NSColor *innerColor;
16 | @property (strong, nonatomic) NSColor *outerColor;
17 | @property (assign, nonatomic) CGFloat cornerRadius;
18 | @property (assign, nonatomic) GBEdgeInsets edgeInsets;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/GBToolbox/GBEnumWrapper.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBEnumWrapper.m
3 | // World Cup Survival Guide
4 | //
5 | // Created by Luka Mirosevic on 06/06/2014.
6 | // Copyright (c) 2014 Goonbee. All rights reserved.
7 | //
8 |
9 | #import "GBEnumWrapper.h"
10 |
11 | @interface GBEnumWrapper ()
12 |
13 | @property (assign, nonatomic) int value;
14 |
15 | @end
16 |
17 | @implementation GBEnumWrapper
18 |
19 | -(id)initWithInt:(int)value {
20 | if (self = [super init]) {
21 | self.value = value;
22 | }
23 |
24 | return self;
25 | }
26 |
27 | -(int)intValue {
28 | return self.value;
29 | }
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/GBToolbox/GBButton.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBButton.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 28/06/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GBButton : UIButton
12 |
13 | @property (strong, nonatomic) UIView *leftView;
14 | @property (assign, nonatomic) CGFloat leftViewLeftOffset;
15 | @property (assign, nonatomic) CGFloat leftViewVerticalOffset;
16 | @property (strong, nonatomic) UIView *rightView;
17 | @property (assign, nonatomic) CGFloat rightViewRightOffset;
18 | @property (assign, nonatomic) CGFloat rightViewVerticalOffset;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/GBToolbox/GBMacros_OSX.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBMacros_OSX.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #ifndef GBToolbox_GBMacros_OSX_h
10 | #define GBToolbox_GBMacros_OSX_h
11 |
12 | #import
13 |
14 | //View controller instantiation
15 | static inline id InstantiateViewControllerWithXib(NSString *xibName) {
16 | NSString *className = [xibName stringByAppendingString:@"ViewController"];
17 | return [([NSClassFromString(className) alloc]) initWithNibName:className bundle:nil];
18 | }
19 | #define vc(xibName) InstantiateViewControllerWithXib(xibName)
20 |
21 | #endif
22 |
--------------------------------------------------------------------------------
/GBToolbox/GBToggleControl.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBToggleControl.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 28/06/2013.
6 | // Copyright (c) 2013 Goonbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GBToggleControl : UIControl
12 |
13 | @property (strong, nonatomic) IBInspectable UIImage *imageWhenOff;
14 | @property (strong, nonatomic) IBInspectable UIImage *imageWhenOn;
15 | @property (strong, nonatomic) IBInspectable UIImage *backgroundImageWhenOff;
16 | @property (strong, nonatomic) IBInspectable UIImage *backgroundImageWhenOn;
17 |
18 | @property (assign, nonatomic) IBInspectable BOOL isOn;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/GBToolbox/GBSolidColorView.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBSolidColorView.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 13/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBSolidColorView.h"
10 |
11 | @implementation GBSolidColorView
12 |
13 | -(id)initWithColor:(NSColor *)color {
14 | if (self = [super init]) {
15 | self.color = color;
16 | }
17 |
18 | return self;
19 | }
20 |
21 | -(void)setColor:(NSColor *)color {
22 | _color = color;
23 |
24 | [self setNeedsDisplay:YES];
25 | }
26 |
27 | - (void)drawRect:(NSRect)dirtyRect {
28 | [self.color setFill];
29 | NSRectFill(dirtyRect);
30 | }
31 |
32 | @end
33 |
--------------------------------------------------------------------------------
/GBToolbox/UIScreen+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIScreen+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 23/02/16.
6 | // Copyright © 2016 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "UIScreen+GBToolbox.h"
10 |
11 | @implementation UIScreen (GBToolbox)
12 |
13 | - (CGRect)fixedBounds {
14 | // iOS 8+
15 | if ([[UIScreen mainScreen] respondsToSelector:@selector(fixedCoordinateSpace)]) {
16 | return [[UIScreen mainScreen].coordinateSpace convertRect:[UIScreen mainScreen].bounds toCoordinateSpace:[UIScreen mainScreen].fixedCoordinateSpace];
17 | }
18 | // iOS 7 and prior
19 | else {
20 | return [UIScreen mainScreen].bounds;
21 | }
22 | }
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/GBToolbox/UITableView+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // UITableView+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UITableView (GBToolbox)
12 |
13 | //detecting when the tableview is scrolled fully down
14 | @property (nonatomic, readonly) BOOL isScrolledToBottom;
15 | -(BOOL)isScrolledToBottomWithTolerance:(CGFloat)tolerance;
16 |
17 | //updates the tableview header height
18 | -(void)recalculateHeaderHeightAnimated:(BOOL)animated;
19 |
20 | //lets you change the height of the header view
21 | -(void)updateHeaderHeightTo:(CGFloat)newHeight animated:(BOOL)animated;
22 |
23 | @end
24 |
--------------------------------------------------------------------------------
/GBToolbox/GBCustomViewButtonCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBCustomViewButtonCell.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 13/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GBCustomViewButtonCell : NSButtonCell
12 |
13 | @property (strong, nonatomic) NSView *customView;
14 | @property (assign, nonatomic) BOOL shouldDarkenOnTouch;
15 | @property (copy, nonatomic) NSString *text;
16 | @property (copy, nonatomic) NSAttributedString *attributedText;
17 | @property (strong, nonatomic) NSColor *textColor;
18 | @property (strong, atomic) NSFont *font;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/GBToolbox/NSImage+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSImage+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "NSImage+GBToolbox.h"
10 |
11 | @implementation NSImage (GBToolbox)
12 |
13 | -(void)saveAsJpegWithName:(NSString*)fileName {
14 | NSData *imageData = [self TIFFRepresentation];
15 | NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData:imageData];
16 | NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:1.0] forKey:NSImageCompressionFactor];
17 | imageData = [imageRep representationUsingType:NSJPEGFileType properties:imageProps];
18 | [imageData writeToFile:fileName atomically:NO];
19 | }
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/GBToolboxUnitTests/GBToolboxUnitTests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | com.goonbee.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/GBToolbox/UINavigationBar+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // UINavigationBar+GBToolbox.m
3 | // Pods
4 | //
5 | // Created by Luka Mirosevic on 18/09/2016.
6 | //
7 | //
8 |
9 | #import "UINavigationBar+GBToolbox.h"
10 |
11 | @implementation UINavigationBar (GBToolbox)
12 |
13 | - (void)styleWithColor:(nullable UIColor *)color {
14 | // an actual color
15 | if (color && ![color isEqual:[UIColor clearColor]]) {
16 | [self setBackgroundImage:nil forBarMetrics:UIBarMetricsDefault];
17 | self.shadowImage = nil;
18 | self.barTintColor = color;
19 | }
20 | // no color -> seethrough bar
21 | else {
22 | [self setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
23 | self.shadowImage = [UIImage new];
24 | self.barTintColor = nil;
25 | }
26 | }
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/GBToolbox/NSMutableDictionary+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSMutableDictionary+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 06/06/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "NSMutableDictionary+GBToolbox.h"
10 |
11 | #import "NSDictionary+GBToolbox.h"
12 |
13 | @implementation NSMutableDictionary (GBToolbox)
14 |
15 | #pragma mark - pruning
16 |
17 | - (void)pruneNulls {
18 | // create a pruned copy
19 | NSDictionary *prunedVersion = [NSDictionary dictionaryByPruningNullsInDictionary:self];
20 |
21 | // now reassing everything in so that this object retains it's identity
22 | [self removeAllObjects];
23 | for (id key in prunedVersion) {
24 | [self setObject:[prunedVersion objectForKey:key] forKey:key];
25 | }
26 | }
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/GBToolbox/GBColoredBarView.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBColoredBarView.h
3 | // Russia
4 | //
5 | // Created by Luka Mirosevic on 27/06/2013.
6 | // Copyright (c) 2013 Goonbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GBColoredBarView : UIView
12 |
13 | @property (strong, nonatomic) NSArray *colors;
14 | @property (strong, nonatomic) NSArray *fractions;
15 | @property (strong, nonatomic) UIColor *backgroundColorWhenEmpty;
16 | @property (strong, nonatomic) UIColor *backgroundColorWhenFull;
17 | @property (strong, nonatomic) UIColor *borderColor;
18 | @property (assign, nonatomic) CGFloat borderThickness;
19 | @property (assign, nonatomic) BOOL showBorderWhenFull;
20 | @property (assign, nonatomic) BOOL showBorderWhenEmpty;
21 |
22 | @end
23 |
--------------------------------------------------------------------------------
/GBToolbox/MKMapView+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // MKMapView+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 10/07/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface MKMapView (GBToolbox)
12 |
13 | //pans and zooms the map to include the points in the locationsArray, which should be CLLocation objects. second method lets you zoom out a little so the contained points arent right on the edges
14 | -(void)moveToRegionIncludingLocations:(NSArray *)locationsArray animated:(BOOL)animated;
15 | -(void)moveToRegionIncludingLocations:(NSArray *)locationsArray withPaddingFactor:(CGFloat)paddingFactor animated:(BOOL)animated;
16 |
17 | //radius in meters
18 | -(void)moveToLocation:(CLLocation *)location showingRadius:(CGFloat)radius animated:(BOOL)animated;
19 |
20 | @end
21 |
--------------------------------------------------------------------------------
/GBToolbox/UIImageView+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIImageView+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 28/06/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIImageView (GBToolbox)
12 |
13 | /**
14 | Returns a UIImageView with its image set to image, and its frame size set to the image size
15 | */
16 | + (UIImageView *)imageViewWithImage:(UIImage *)image;
17 |
18 | /**
19 | Returns a UIImageView with its image set to the image with name imageName, and its frame size set to the image size.
20 | */
21 | + (UIImageView *)imageViewWithImageNamed:(NSString *)imageName;
22 |
23 | /**
24 | Returns the image bounds of the displayed image inside the receiver. Useful when the contentMode is aspect fit.
25 | */
26 | - (CGRect)displayedImageBounds;
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/GBToolbox/NSData+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSData+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "NSData+GBToolbox.h"
10 |
11 | #import
12 |
13 | @implementation NSData (NSData_GBUtil)
14 |
15 | //md5 hash
16 | -(NSString *)md5 {
17 | unsigned char result[16];
18 | CC_MD5(self.bytes, (CC_LONG)self.length, result);
19 |
20 | return [NSString stringWithFormat: @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
21 | result[0], result[1], result[2], result[3],
22 | result[4], result[5], result[6], result[7],
23 | result[8], result[9], result[10], result[11],
24 | result[12], result[13], result[14], result[15]
25 | ];
26 | }
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/GBToolbox/GBCAAnimationDelegateHandler.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBCAAnimationDelegateHandler.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 16/09/2016.
6 | //
7 | //
8 |
9 | #import
10 | #import
11 |
12 | typedef void(^GBCAAnimationDidStartBlock)(CAAnimation * _Nonnull animation);
13 | typedef void(^GBCAAnimationDidStopBlock)(CAAnimation * _Nonnull animation, BOOL finished);
14 |
15 | @interface GBCAAnimationDelegateHandler : NSObject
16 |
17 | + (nonnull instancetype)delegateWithDidStart:(nullable GBCAAnimationDidStartBlock)didStart didStop:(nullable GBCAAnimationDidStopBlock)didStop;
18 |
19 | @end
20 |
21 | @interface GBCAAnimationDelegateHandler ()
22 |
23 | @property (copy, nonatomic, nullable) GBCAAnimationDidStartBlock didStart;
24 | @property (copy, nonatomic, nullable) GBCAAnimationDidStopBlock didStop;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/GBToolbox/GBTestView.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBTestView.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 12/07/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBTestView.h"
10 |
11 | #import "GBToolbox.h"
12 |
13 | @implementation GBTestView
14 |
15 | - (id)initWithFrame:(CGRect)frame {
16 | self = [super initWithFrame:frame];
17 | if (self) {
18 | // Initialization code
19 | }
20 | return self;
21 | }
22 |
23 | /*
24 | // Only override drawRect: if you perform custom drawing.
25 | // An empty implementation adversely affects performance during animation.
26 | - (void)drawRect:(CGRect)rect
27 | {
28 | // Drawing code
29 | }
30 | */
31 |
32 | - (void)setFrame:(CGRect)frame {
33 | // _lRect(frame);
34 | [super setFrame:frame];
35 | }
36 |
37 | - (void)dealloc {
38 | NSLog(@"deallocating GBTestView instance %@", self);
39 | }
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/GBToolbox/GBCAAnimationDelegateHandler.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBCAAnimationDelegateHandler.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 16/09/2016.
6 | //
7 | //
8 |
9 | #import "GBCAAnimationDelegateHandler.h"
10 |
11 | #pragma mark - API
12 |
13 | @implementation GBCAAnimationDelegateHandler
14 |
15 | + (nonnull instancetype)delegateWithDidStart:(nullable GBCAAnimationDidStartBlock)didStart didStop:(nullable GBCAAnimationDidStopBlock)didStop {
16 | GBCAAnimationDelegateHandler *delegate = [self.class new];
17 | delegate.didStart = didStart;
18 | delegate.didStop = didStop;
19 |
20 | return delegate;
21 | }
22 |
23 | #pragma mark - CAAnimationDelegate
24 |
25 | - (void)animationDidStart:(CAAnimation *)animation {
26 | if (self.didStart) self.didStart(animation);
27 | }
28 |
29 | - (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag {
30 | if (self.didStop) self.didStop(animation, flag);
31 | }
32 |
33 | @end
34 |
35 |
--------------------------------------------------------------------------------
/GBToolbox/GBCache.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBCache.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 10/04/2014.
6 | // Copyright (c) 2014 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBCache.h"
10 |
11 | #import
12 |
13 | NSUInteger const kGBCacheUnlimitedCacheSize = 0;
14 |
15 | @implementation GBCache
16 |
17 | #pragma mark - CA
18 |
19 | -(void)setMaxCacheSize:(NSUInteger)maxCacheSize {
20 | self.totalCostLimit = maxCacheSize;
21 | }
22 |
23 | -(NSUInteger)maxCacheSize {
24 | return self.totalCostLimit;
25 | }
26 |
27 | #pragma mark - Life
28 |
29 | -(id)init {
30 | if (self = [super init]) {
31 | self.maxCacheSize = kGBCacheUnlimitedCacheSize;
32 | }
33 |
34 | return self;
35 | }
36 |
37 | #pragma mark - API
38 |
39 | -(id)objectForKeyedSubscript:(id)key {
40 | return [self objectForKey:key];
41 | }
42 |
43 | -(void)setObject:(id)obj forKeyedSubscript:(id)key {
44 | [self setObject:obj forKey:key];
45 | }
46 |
47 | @end
48 |
--------------------------------------------------------------------------------
/GBToolbox/GBMessageInterceptor.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBMessageInterceptor.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 21/06/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 | // Originally from this SO answer: http://stackoverflow.com/a/3862591/399772
9 |
10 |
11 | #import "GBMessageInterceptor.h"
12 |
13 | @implementation GBMessageInterceptor
14 |
15 | - (id)forwardingTargetForSelector:(SEL)aSelector {
16 | if ([_middleMan respondsToSelector:aSelector]) { return _middleMan; }
17 | if ([_receiver respondsToSelector:aSelector]) { return _receiver; }
18 | return [super forwardingTargetForSelector:aSelector];
19 | }
20 |
21 | - (BOOL)respondsToSelector:(SEL)aSelector {
22 | if ([[_middleMan superclass] instancesRespondToSelector:aSelector]) return NO;
23 | if ([_middleMan respondsToSelector:aSelector]) return YES;
24 | if ([_receiver respondsToSelector:aSelector]) return YES;
25 | return [super respondsToSelector:aSelector];
26 | }
27 |
28 | @end
--------------------------------------------------------------------------------
/GBToolbox/GBCompletable.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBCompletable.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 15/07/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "GBToolbox.h"
12 |
13 | typedef enum {
14 | GBCompletableStateUnresolved,
15 | GBCompletableStateSuccess,
16 | GBCompletableStateFailed,
17 | } GBCompletableState;
18 |
19 | @interface GBCompletable : NSObject
20 |
21 | @property (assign, nonatomic, readonly) BOOL isResolved;
22 | @property (assign, nonatomic, readonly) BOOL isCompleted;
23 | @property (assign, nonatomic, readonly) BOOL isFailed;
24 | @property (assign, nonatomic, readonly) GBCompletableState state;
25 |
26 | //provider uses the
27 | +(GBCompletable *)completableWithSuccess:(VoidBlock)success fail:(VoidBlock)fail resolve:(VoidBlock)resolve;
28 |
29 | //client uses this
30 | -(void)success;
31 | -(void)fail;
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/GBToolbox/GBAsyncOperation.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBAsyncOperation.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 22/11/16.
6 | // Copyright © 2016 Goonbee e.U.. All rights reserved.
7 | //
8 |
9 | @import Foundation;
10 |
11 | @interface GBAsyncOperation : NSOperation
12 |
13 | /**
14 | Init.
15 | */
16 | - (nonnull instancetype)init NS_DESIGNATED_INITIALIZER;
17 |
18 | /**
19 | The method that is called for subclasses to do their work. You must override this method WITHOUT calling super. When your work is completed, you must call `completeAsyncOperation`. This method is called on the same thread as start was called for the operation.
20 | */
21 | - (void)main;
22 |
23 | /**
24 | You must also override cancel, and call `completeAsyncOperation` somewhere in your implementation. You SHOULD call super first.
25 | */
26 | - (void)cancel;
27 |
28 | /**
29 | Marks this operation as completed and sends all the right KVO notifications as per the NSOperation subsclassing contract.
30 | */
31 | - (void)completeAsyncOperation;
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/GBToolbox/NSSet+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSSet+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 28/03/16.
6 | // Copyright © 2016 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSSet<__covariant ObjectType> (GBToolbox)
12 |
13 | /**
14 | Returns YES if any the function returns YES for at least one object in the set.
15 | */
16 | - (BOOL)contains:(BOOL(^ _Nonnull)(ObjectType _Nonnull object))function;
17 |
18 | /**
19 | Returns a copy of the array containing only the objects for which function returns YES.
20 | */
21 | - (nonnull NSSet *)filter:(BOOL(^ _Nonnull)(ObjectType _Nonnull object))function;
22 |
23 | /**
24 | Returns the first object for which the function returns YES, nil otherwise.
25 |
26 | First might be undeterministic for an NSSet, so this is really only useful for when you know that only 1 object in the set will return YES for the function.
27 | */
28 | - (nullable ObjectType)first:(BOOL(^ _Nonnull)(ObjectType _Nonnull object))function;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/GBToolbox/GBRoundBadgeView.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBRoundBadgeView.h
3 | // Russia
4 | //
5 | // Created by Luka Mirosevic on 26/06/2013.
6 | // Copyright (c) 2013 Goonbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | /**
12 | A round badge view, that is composed of a background image that is aspect filled and a foreground image whose content mode can be freely specified.
13 |
14 | It clips the edges to create a circle.
15 |
16 | Useful for rounded profile pics, with an optional background image.
17 | */
18 | @interface GBRoundBadgeView : UIView
19 |
20 | @property (strong, nonatomic) UIImage *backgroundImage;
21 | @property (strong, nonatomic) UIImage *foregroundImage;
22 | @property (assign, nonatomic) UIViewContentMode foregroundImageContentMode;
23 | @property (assign, nonatomic) UIEdgeInsets clippingMargin;
24 | @property (assign, nonatomic) UIEdgeInsets backgroundImageMargin;
25 | @property (assign, nonatomic) UIEdgeInsets foregroundImageMargin;
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/GBToolbox/GBToolbox-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | English
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | com.goonbee.${PRODUCT_NAME:rfc1034identifier}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | FMWK
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | NSHumanReadableCopyright
26 | Copyright © 2013 Luka Mirosevic. All rights reserved.
27 | NSPrincipalClass
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/GBToolbox/GBTableViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBTableViewController.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 14/07/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GBTableViewController : UIViewController
12 |
13 | @property (strong, nonatomic) UITableView *tableView;
14 | @property (assign, nonatomic) BOOL clearsSelectionOnViewWillAppear;// defaults to YES. If YES, any selection is cleared in viewWillAppear:
15 | @property (strong, nonatomic) UIView *emptyView;
16 |
17 | -(id)initWithStyle:(UITableViewStyle)style;
18 |
19 | -(void)clearEmpty;//don't show the empty (e.g. if you have an error condition and you want to show an error message instead)
20 | -(void)handleEmpty;
21 |
22 | //for subclasses to override
23 | -(Class)classForTableView;
24 | -(void)tableView:(UITableView *)tableView didBeginFullyDisplayingCellForRowAtIndexPath:(NSIndexPath *)indexPath;
25 | -(void)tableView:(UITableView *)tableView didEndFullyDisplayingCellForRowAtIndexPath:(NSIndexPath *)indexPath;
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/GBToolbox/GBRemoteDebugMessages.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBRemoteDebugMessages.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 08/11/2014.
6 | // Copyright (c) 2014 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GBRemoteDebugMessages : NSObject
12 |
13 | @property (assign, nonatomic) BOOL shouldLogLocallyAsWell;// default: NO
14 |
15 | + (instancetype)sharedMessages;
16 | - (id)init;
17 |
18 | /**
19 | Sends a debug message via the network for remote debugging. To listen for messages run `nc -l -k 10000` on the target host, where 10000 is the default port to which messages are sent if you don't specify a custom route. If you specify a port using `RouteRemoteDebugMessagesToServerOnPort` then you should listen on that port.
20 | */
21 | - (void)sendRemoteDebugMessage:(NSString *)message, ...;
22 |
23 | /**
24 | Determines where to remote debug messages will be sent.
25 | */
26 | - (void)routeRemoteDebugMessagesToServer:(NSString *)server onPort:(UInt32)port;
27 |
28 | @end
29 |
30 | // Shorthands
31 | void SendRemoteDebugMessage(NSString *message, ...);
32 | void RouteRemoteDebugMessagesToServerOnPort(NSString *server, UInt32 port);
33 |
--------------------------------------------------------------------------------
/GBToolbox/NSView+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSView+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "NSView+GBToolbox.h"
10 |
11 | #import "GBToolbox.h"
12 |
13 | @implementation NSView (GBToolbox)
14 |
15 | //returns the view's frame in global coordinates
16 | -(NSRect)globalFrame {
17 | if ([self.window respondsToSelector:@selector(convertRectToScreen:)]) {//10.7
18 | return [self.window convertRectToScreen:self.frame];
19 | }
20 | else {
21 | #pragma clang diagnostic push
22 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
23 | NSRect frame = [self frame];
24 | frame.origin = [self.window convertBaseToScreen:frame.origin];
25 | return frame;
26 | #pragma clang diagnostic pop
27 | }
28 | }
29 |
30 | //enumarate all subviews depth first
31 | -(void)enumerateSubviewsWithBlock:(void(^)(NSView *view))block {
32 | //itself
33 | block(self);
34 |
35 | //then all its subviews
36 | for (NSView *subview in self.subviews) {
37 | [subview enumerateSubviewsWithBlock:block];
38 | }
39 | }
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/GBToolbox/UIScrollView+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIScrollView+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 27/06/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "UIScrollView+GBToolbox.h"
10 |
11 | @implementation UIScrollView (GBToolbox)
12 |
13 | -(void)scrollToOriginAnimated:(BOOL)animated {
14 | [self setContentOffset:CGPointZero animated:animated];
15 | }
16 |
17 | -(void)scrollToTopAnimated:(BOOL)animated {
18 | [self setContentOffset:CGPointMake(self.contentOffset.x, 0 - self.contentInset.top) animated:animated];
19 | }
20 |
21 | -(void)scrollToBottomAnimated:(BOOL)animated {
22 | [self setContentOffset:CGPointMake(self.contentOffset.x, MAX(-self.contentInset.top, self.contentSize.height - self.bounds.size.height + self.contentInset.bottom)) animated:animated];
23 | }
24 |
25 | -(void)scrollToLeftAnimated:(BOOL)animated {
26 | self.contentOffset = CGPointMake(0 - self.contentInset.left, self.contentOffset.y);
27 | }
28 |
29 | -(void)scrollToRightAnimated:(BOOL)animated {
30 | [self setContentOffset:CGPointMake(MAX(-self.contentInset.right, self.contentSize.width - self.bounds.size.width + self.contentInset.right), self.contentOffset.y) animated:animated];
31 | }
32 |
33 | @end
34 |
--------------------------------------------------------------------------------
/GBToolbox/GBCustomNavigationBar.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBCustomNavigationBar.m
3 | // Xmas List
4 | //
5 | // Created by Luka Mirosevic on 29/11/2012.
6 | // Copyright (c) 2012 Goonbee. All rights reserved.
7 | //
8 |
9 | #import "GBCustomNavigationBar.h"
10 |
11 | @interface GBCustomNavigationBar ()
12 |
13 | @property (assign, nonatomic, readwrite) CGFloat navBarHeight;
14 |
15 | @end
16 |
17 | @implementation GBCustomNavigationBar
18 |
19 | #pragma mark - life
20 |
21 | static CGFloat _defaultNavBarHeightForClass = 44;
22 |
23 | +(Class)navigationBarClassWithHeight:(CGFloat)height {
24 | _defaultNavBarHeightForClass = height;
25 |
26 | return [self class];
27 | }
28 |
29 | -(id)initWithFrame:(CGRect)frame {
30 | if (self = [super initWithFrame:frame]) {
31 | self.navBarHeight = _defaultNavBarHeightForClass;
32 | }
33 |
34 | return self;
35 | }
36 |
37 | -(id)initWithNavBarHeight:(CGFloat)height {
38 | if (self = [self init]) {
39 | self.navBarHeight = height;
40 | }
41 |
42 | return self;
43 | }
44 |
45 | #pragma mark - customizations
46 |
47 | -(CGSize)sizeThatFits:(CGSize)size {
48 | CGRect frame = [UIScreen mainScreen].bounds;
49 |
50 | return CGSizeMake(frame.size.width , self.navBarHeight);
51 | }
52 |
53 | @end
54 |
--------------------------------------------------------------------------------
/GBToolbox/NSMapTable+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSMapTable+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 01/06/2014.
6 | // Copyright (c) 2014 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSMapTable (GBToolbox)
12 |
13 | /**
14 | Returns the object for a key, assuming both object and key are objects.
15 | */
16 | - (nullable ObjectType)objectForKeyedSubscript:(nullable KeyType)key;
17 |
18 | /**
19 | Stores an object into the map table for the given key. Assumes both object and key are objects.
20 | */
21 | - (void)setObject:(nullable ObjectType)object forKeyedSubscript:(nullable KeyType)key;
22 |
23 | /**
24 | Returns an array holding all the keys.
25 | */
26 | @property (strong, nonatomic, nonnull, readonly) NSArray *allKeys;
27 |
28 | /**
29 | Returns an array holding all the objects.
30 | */
31 | @property (strong, nonatomic, nonnull, readonly) NSArray *allObjects;
32 |
33 | /**
34 | Checks whether the map table contains the object.
35 | */
36 | - (BOOL)containsObject:(nullable ObjectType)object;
37 |
38 | /**
39 | Returns the first matching key for the object.
40 | */
41 | - (nullable KeyType)keyForObject:(nullable ObjectType)object;
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/GBToolbox/NSSet+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSSet+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 28/03/16.
6 | // Copyright © 2016 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "NSSet+GBToolbox.h"
10 |
11 | @implementation NSSet (GBToolbox)
12 |
13 | - (BOOL)contains:(BOOL(^)(id object))function {
14 | for (id object in self) {
15 | if (function(object)) {
16 | return YES;
17 | }
18 | }
19 |
20 | return NO;
21 | }
22 |
23 | - (NSSet *)filter:(BOOL(^)(id object))function {
24 | // creates a results set in which to store results, sets the capacity for faster writes
25 | NSMutableSet *resultsSet = [[NSMutableSet alloc] initWithCapacity:self.count];
26 |
27 | // apply the function to each object in self and store the results in the new set
28 | for (id object in self) {
29 | if (function(object)) {
30 | [resultsSet addObject:object];
31 | }
32 | }
33 |
34 | // return an immutable copy
35 | return [resultsSet copy];
36 | }
37 |
38 | - (id)first:(BOOL(^)(id object))function {
39 | for (id object in self) {
40 | if (function(object)) {
41 | return object;
42 | }
43 | }
44 |
45 | return nil;
46 | }
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/GBToolbox/GBToggleControlRadioGroupManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBToggleControlRadioGroupManager.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 08/07/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class GBToggleControl;
12 |
13 | @protocol GBToggleControlRadioGroupManagerDelegate;
14 |
15 | @interface GBToggleControlRadioGroupManager : NSObject
16 |
17 | @property (weak, nonatomic) id delegate;
18 |
19 | @property (strong, nonatomic) NSArray *toggleControls;
20 |
21 | @property (assign, nonatomic) NSInteger selectedControlIndex;
22 | @property (strong, nonatomic) GBToggleControl *selectedControl;
23 |
24 | -(void)deselectAllControls;
25 |
26 | @end
27 |
28 | @protocol GBToggleControlRadioGroupManagerDelegate
29 | @optional
30 |
31 | -(void)toggleControlRadioGroupManager:(GBToggleControlRadioGroupManager *)toggleControlRadioGroupManager didSelectToggleControl:(GBToggleControl *)toggleControl withIndex:(NSInteger)index;
32 |
33 | -(void)toggleControlRadioGroupManagerDidResetSelection:(GBToggleControlRadioGroupManager *)toggleControlRadioGroupManager;
34 |
35 | @end
--------------------------------------------------------------------------------
/GBToolbox/NSMapTable+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSMapTable+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 01/06/2014.
6 | // Copyright (c) 2014 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "NSMapTable+GBToolbox.h"
10 |
11 | #import "NSArray+GBToolbox.h"
12 |
13 | @implementation NSMapTable (GBToolbox)
14 |
15 | - (id)objectForKeyedSubscript:(id)key {
16 | return [self objectForKey:key];
17 | }
18 |
19 | - (void)setObject:(id)object forKeyedSubscript:(id)key {
20 | [self setObject:object forKey:key];
21 | }
22 |
23 | - (NSArray *)allKeys {
24 | NSMutableArray *allKeys = [[NSMutableArray alloc] initWithCapacity:self.count];
25 |
26 | for (id key in self) {
27 | [allKeys addObject:key];
28 | }
29 |
30 | return allKeys;
31 | }
32 |
33 | - (NSArray *)allObjects {
34 | return [self.allKeys map:^id(id key) {
35 | return [self objectForKey:key];
36 | }];
37 | }
38 |
39 | - (BOOL)containsObject:(id)object {
40 | return [self.allObjects containsObject:object];
41 | }
42 |
43 | - (id)keyForObject:(id)object {
44 | for (id key in self) {
45 | if ([self[key] isEqual:object]) {
46 | return key;
47 | }
48 | }
49 |
50 | // fallback in case nothing is found
51 | return nil;
52 | }
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/GBToolbox/NSOrderedSet+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSOrderedSet+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 28/03/16.
6 | // Copyright © 2016 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSOrderedSet<__covariant ObjectType> (GBToolbox)
12 |
13 | /**
14 | Returns the index of the object that is identical to anObject, or NSNotFound if the set doesn't contain it.
15 | */
16 | - (NSUInteger)indexOfObjectIdenticalTo:(nonnull id)anObject;
17 |
18 | /**
19 | Returns a new set with the elements from the receiver transformed by function.
20 | */
21 | - (nonnull NSOrderedSet *)map:(id _Nonnull(^ _Nonnull)(ObjectType _Nonnull object))function;
22 |
23 | /**
24 | Fold Left
25 | */
26 | - (nonnull ObjectType)foldLeft:(ObjectType _Nonnull(^ _Nonnull)(ObjectType _Nonnull objectA, ObjectType _Nonnull objectB))function lastObject:(nonnull ObjectType)lastObject;
27 |
28 | /**
29 | Fold Right.
30 | */
31 | - (nonnull ObjectType)foldRight:(ObjectType _Nonnull(^ _Nonnull)(ObjectType _Nonnull objectA, ObjectType _Nonnull objectB))function initialObject:(nonnull ObjectType)initialObject;
32 |
33 | /**
34 | Synonym for foldLeft
35 | */
36 | - (nonnull ObjectType)reduce:(ObjectType _Nonnull(^ _Nonnull)(ObjectType _Nonnull objectA, ObjectType _Nonnull objectB))function lastObject:(nonnull ObjectType)lastObject;
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/GBToolbox/GBHighPrecisionTimer.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBHighPrecisionTimer.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 13/12/2016.
6 | // Copyright © 2016 Goonbee e.U.. All rights reserved.
7 | //
8 |
9 | @import Foundation;
10 |
11 | @interface GBHighPrecisionTimer : NSObject
12 |
13 | /**
14 | Initialises a new timer, that will call `block` every `period`.
15 |
16 | Warning: The object will retain itself for as long as the timer doesn't get stopped. The object will store a copy of the block and release it when the timer is stopped. `block` will be called on a background thread.
17 | */
18 | - (nonnull instancetype)initWithPeriod:(NSTimeInterval)period repeats:(BOOL)repeats block:(void(^ _Nonnull)(void))block NS_DESIGNATED_INITIALIZER;
19 |
20 | /**
21 | Initialises a new timer, that will call the `selector` on `target` every `period`.
22 |
23 | Warning: The object will retain itself for as long as the timer doesn't get stopped. `selector` will be called from a background thread.
24 | */
25 | - (nonnull instancetype)initWithPeriod:(NSTimeInterval)period repeats:(BOOL)repeats taget:(nonnull id)target selector:(nonnull SEL)selector;
26 |
27 | - (nonnull instancetype)init NS_UNAVAILABLE;
28 |
29 | /**
30 | Fires the timer immediately. Will be called on a background thread.
31 | */
32 | - (void)fire;
33 |
34 | /**
35 | Stops the timer from firing again.
36 | */
37 | - (void)stop;
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/GBToolbox/GBKeyboardListener.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBKeyboardListener.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 22/05/2017.
6 | // Copyright © 2017 Goonbee e.U. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | /**
12 | The block that is called when the keyboard moves.
13 | */
14 | typedef void(^GBKeyboardWillMoveBlock)(BOOL willShow, CGRect beginFrame, CGRect endFrame, NSTimeInterval animationDuration, UIViewAnimationOptions animationCurve);
15 |
16 | /**
17 | A class for listening on changes to the keyboard.
18 | */
19 | @interface GBKeyboardListener : NSObject
20 |
21 | + (nonnull GBKeyboardListener *)sharedListener;
22 |
23 | /**
24 | Whether or not the keyboard is currently visible.
25 | */
26 | @property (assign, nonatomic, readonly, getter=isVisible) BOOL visible;
27 |
28 | /**
29 | The frame of the keyboard, in screen coordinates.
30 | */
31 | @property (assign, nonatomic, readonly) CGRect keyboardFrame;
32 |
33 | /**
34 | Returns the rect of the keyboard, translated to view's coordinates.
35 | */
36 | - (CGRect)frameInCoordinatesOfView:(nonnull UIView *)view;
37 |
38 | /**
39 | Adds a block in a context.
40 | */
41 | - (void)addListenerForContext:(nonnull id)context block:(nonnull GBKeyboardWillMoveBlock)block;
42 |
43 | /**
44 | Removes all notification blocks in a certain context.
45 | */
46 | - (void)removeListenersForContext:(nonnull id)context;
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/GBToolbox/NSMutableArray+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSMutableArray+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 17/05/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSMutableArray (GBToolbox)
12 |
13 | #pragma mark - Array padding
14 | //These are all non-destructive and leave existing elements in, only when extendin the array do we actually pad it
15 |
16 | /**
17 | Pads the array out so the last index is the one that's passed in, with [NSNull null].
18 | */
19 | - (void)padToIndex:(NSUInteger)index;
20 |
21 | /**
22 | Pads the array out so the last index is the one that's passed in, with any non nil object
23 | */
24 | - (void)padToIndex:(NSUInteger)index withObject:(nonnull id)object;
25 |
26 | /**
27 | Pads the array out to the desired size with [NSNull null] objects.
28 | */
29 | - (void)padToSize:(NSUInteger)count;
30 |
31 | /**
32 | Pads the array out to the desired size with any object you supply.
33 | */
34 | - (void)padToSize:(NSUInteger)count withObject:(nonnull id)object;
35 |
36 | #pragma mark - Deleting
37 |
38 | /**
39 | Removes an object from the array by searching using pointer equality, rather than sending the isEqual: message.
40 | */
41 | - (void)removeObjectByIdentity:(nonnull id)object;
42 |
43 | #pragma mark - Moving
44 |
45 | /**
46 | Moves an object from one index to another. toIndex is the final index *after* the move.
47 | */
48 | - (void)moveObjectAtIndex:(NSUInteger)fromIndex toIndex:(NSUInteger)toIndex;
49 |
50 | @end
51 |
--------------------------------------------------------------------------------
/GBToolbox/UIImage+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIImage+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIImage (GBToolbox)
12 |
13 | -(UIImage *)cropToRect:(CGRect)rect;
14 | -(UIImage *)resizedImage:(CGSize)newSize interpolationQuality:(CGInterpolationQuality)quality;
15 | -(UIImage *)resizedImageWithContentMode:(UIViewContentMode)contentMode bounds:(CGSize)bounds interpolationQuality:(CGInterpolationQuality)quality;
16 | -(UIImage *)downscaledImageWithMaxResolution:(CGFloat)maxResolution;
17 |
18 | #pragma mark - Programmatic images
19 |
20 | + (UIImage *)imageWithSolidColor:(UIColor *)color size:(CGSize)size;
21 | + (UIImage *)imageWithSolidColor:(UIColor *)color size:(CGSize)size capInsets:(UIEdgeInsets)capInsets;
22 |
23 | #pragma mark - Apple UIImage+ImageEffects
24 |
25 | -(UIImage *)applyLightEffect;
26 | -(UIImage *)applyExtraLightEffect;
27 | -(UIImage *)applyDarkEffect;
28 | -(UIImage *)applyTintEffectWithColor:(UIColor *)tintColor;
29 |
30 | -(UIImage *)applyBlurWithRadius:(CGFloat)blurRadius tintColor:(UIColor *)tintColor saturationDeltaFactor:(CGFloat)saturationDeltaFactor maskImage:(UIImage *)maskImage;
31 |
32 | #pragma mark - Tint
33 |
34 | - (UIImage *)tintedImage:(UIColor *)tintColor;
35 |
36 | #pragma mark - Blending
37 |
38 | /**
39 | Blends multiple images together, by drawing each successive image in the array on top of the previous one.
40 | */
41 | + (UIImage *)imageByBlending:(NSArray *)images;
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/GBToolbox/UITableView+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // UITableView+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "UITableView+GBToolbox.h"
10 |
11 | @implementation UITableView (GBToolbox)
12 |
13 | -(BOOL)isScrolledToBottomWithTolerance:(CGFloat)tolerance {
14 | if (self.contentSize.height - self.bounds.size.height - self.contentOffset.y <= tolerance) {
15 | return YES;
16 | }
17 | else {
18 | return NO;
19 | }
20 | }
21 |
22 | -(BOOL)isScrolledToBottom {
23 | return [self isScrolledToBottomWithTolerance:0];
24 | }
25 |
26 | -(void)recalculateHeaderHeightAnimated:(BOOL)animated {
27 | if (animated) [self beginUpdates];
28 | self.tableHeaderView = self.tableHeaderView;//causes it to refresh the height
29 | if (animated) [self endUpdates];
30 | }
31 |
32 | -(void)updateHeaderHeightTo:(CGFloat)newHeight animated:(BOOL)animated {
33 | if (animated) {
34 | [UIView animateWithDuration:0.25 animations:^{
35 | self.tableHeaderView.frame = CGRectMake(self.tableHeaderView.frame.origin.x,
36 | self.tableHeaderView.frame.origin.y,
37 | self.tableHeaderView.frame.size.width,
38 | newHeight);
39 |
40 | self.tableHeaderView = self.tableHeaderView;//causes it to reconsider the height
41 |
42 | } completion:nil];
43 | }
44 | }
45 |
46 | @end
--------------------------------------------------------------------------------
/GBToolbox/NSTimer+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSTimer+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "NSTimer+GBToolbox.h"
10 |
11 | @implementation NSTimer (GBToolbox)
12 |
13 | //blocks
14 | +(NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats withBlock:(void(^)(void))block {
15 | return [self _timerFactory:interval repeats:repeats withBlock:block shouldSchedule:YES];
16 | }
17 |
18 | +(NSTimer *)timerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats withBlock:(void(^)(void))block {
19 | return [self _timerFactory:interval repeats:repeats withBlock:block shouldSchedule:NO];
20 | }
21 |
22 | +(NSTimer *)_timerFactory:(NSTimeInterval)interval repeats:(BOOL)repeats withBlock:(void(^)(void))block shouldSchedule:(BOOL)shouldSchedule {
23 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[self instanceMethodSignatureForSelector:@selector(callBlock:)]];
24 | NSTimer *timer = shouldSchedule ?
25 | [NSTimer scheduledTimerWithTimeInterval:interval invocation:invocation repeats:repeats] :
26 | [NSTimer timerWithTimeInterval:interval invocation:invocation repeats:repeats];
27 |
28 | [invocation setTarget:timer];
29 | [invocation setSelector:@selector(callBlock:)];
30 |
31 | void(^copy)(void) = [block copy];
32 | [invocation setArgument:© atIndex:2];
33 |
34 | return timer;
35 | }
36 |
37 | -(void)callBlock:(void(^)(void))block {
38 | block();
39 | }
40 |
41 | @end
42 |
--------------------------------------------------------------------------------
/GBToolbox/NSInvocation+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSInvocation+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 30/04/2014.
6 | // Copyright (c) 2014 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "NSInvocation+GBToolbox.h"
10 |
11 | @implementation NSInvocation (GBToolbox)
12 |
13 | +(NSInvocation *)invocationWithTarget:(id)target selector:(SEL)selector arguments:(void *)argument, ... NS_REQUIRES_NIL_TERMINATION {
14 | va_list argumentList;
15 | va_start(argumentList, argument);
16 | NSInvocation *invocation = [self invocationWithTarget:target selector:selector argument:argument argumentList:argumentList];
17 | va_end(argumentList);
18 |
19 | return invocation;
20 | }
21 |
22 | +(NSInvocation *)invocationWithTarget:(id)target selector:(SEL)selector argument:(void *)argument argumentList:(va_list)argumentList {
23 | // prepare the invocation
24 | NSMethodSignature *methodSignature = [[target class] instanceMethodSignatureForSelector:selector];
25 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
26 | [invocation setTarget:target];
27 | [invocation setSelector:selector];
28 | void *anArgumentPointer;
29 |
30 | if (argument) {
31 | [invocation setArgument:argument atIndex:2];
32 | NSUInteger counter = 3;
33 | while ((anArgumentPointer = va_arg(argumentList, void *))) {
34 | [invocation setArgument:anArgumentPointer atIndex:counter];
35 | counter += 1;
36 | }
37 | }
38 | [invocation retainArguments];
39 |
40 | return invocation;
41 | }
42 |
43 | @end
44 |
--------------------------------------------------------------------------------
/GBToolbox/UIView+GBOwningViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+GBOwningViewController.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 08/06/2017.
6 | // Copyright (c) 2017 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "UIView+GBToolbox.h"
10 |
11 | #import "GBUtility_Common.h"
12 | #import
13 |
14 | @interface UIView ()
15 |
16 | @property (weak, nonatomic, nullable, readwrite) UIViewController *GBOwningViewController;
17 |
18 | @end
19 |
20 | @implementation UIView (GBOwningViewController)
21 |
22 | #pragma mark - CA
23 |
24 | static char gbOwningViewController;
25 |
26 | - (void)setGBOwningViewController:(UIViewController *)owningViewController {
27 | objc_setAssociatedObject(self, &gbOwningViewController, owningViewController, OBJC_ASSOCIATION_ASSIGN);
28 | }
29 |
30 | - (UIViewController *)GBOwningViewController {
31 | return objc_getAssociatedObject(self, &gbOwningViewController);
32 | }
33 |
34 | @end
35 |
36 | @interface UIViewController (GBOwningViewController)
37 |
38 | @end
39 |
40 | @implementation UIViewController (GBOwningViewController)
41 |
42 | #pragma mark - Overrides
43 |
44 | + (void)load {
45 | SwizzleInstanceMethodsInClass(self, @selector(setView:), @selector(_swizz_setView:));
46 | }
47 |
48 | - (void)_swizz_setView:(UIView *)view {
49 | // deassociate self from old view
50 | if (self.isViewLoaded) {
51 | self.view.GBOwningViewController = nil;
52 | }
53 |
54 | // call default implementation
55 | [self _swizz_setView:view];
56 |
57 | // associate self to new view
58 | view.GBOwningViewController = self;
59 | }
60 |
61 | @end
62 |
--------------------------------------------------------------------------------
/GBToolbox/UIViewController+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIViewController (GBToolbox)
12 |
13 | /**
14 | Returns YES when the view controller is visible (in between viewWillAppear: and viewDidDisappear:)
15 | */
16 | @property (assign, nonatomic) BOOL isVisible;
17 |
18 | /**
19 | Returns YES when the view controller is visible (in between viewWillAppear: and viewWillDisappear:)
20 | */
21 | @property (assign, nonatomic) BOOL isVisibleCurrently;
22 |
23 | /**
24 | Makes sure that the view is loaded
25 | */
26 | - (void)ensureViewIsLoaded;
27 |
28 | /**
29 | Returns the preferred status bar style of the view controller that's currently shown.
30 | */
31 | @property (assign, nonatomic, readonly) UIStatusBarStyle inheritedPreferredStatusBarStyle;
32 |
33 | /**
34 | Set this viewcontroller's navigation bar background color with a more sane behaviour than the standard Cocoa Touch methods.
35 |
36 | If color is nil, the bar will be transparent.
37 | */
38 | - (void)styleNavigationBarWithColor:(nullable UIColor *)color;
39 |
40 | /**
41 | Hides the title next to the back button, showing only the chevron.
42 | */
43 | - (void)hideBackButtonTitle;
44 |
45 | /**
46 | Returns the view controller that is modally presenting the receiver, even if the receiver is embedded inside a tab bar or navigation controller
47 | */
48 | @property (strong, nonatomic, readonly, nullable) UIViewController *presentingViewControllerAcrossParents;
49 |
50 | @end
51 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # GBToolbox  
2 |
3 | Goonbee's iOS & Mac development toolbox
4 |
5 | Categories
6 | ------------
7 |
8 | * NSString
9 | * UIImage
10 | * NSData
11 | * NSTimer
12 | * NSObject
13 | * UIViewController
14 | * UITableView
15 |
16 | Functions
17 | ------------
18 |
19 | * Math
20 | * UI
21 | * Timing
22 | * Convenience
23 |
24 | Macros
25 | ------------
26 |
27 | * Logging
28 | * Localisation
29 | * Universal app device detection
30 | * View controller instantiation (Storyboards)
31 | * Object instantiation
32 | * Rotation
33 | * Lazy instantiation
34 | * Set
35 | * Resource Bundles
36 | * Singleton
37 | * Debugging
38 | * Strings
39 |
40 | Feature list
41 | ------------
42 |
43 | Look inside header files.
44 |
45 | Dependencies
46 | ------------
47 |
48 | * [JRSwizzle](https://github.com/rentzsch/jrswizzle)
49 |
50 | Copyright & License
51 | ------------
52 |
53 | Copyright 2017 Luka Mirosevic
54 |
55 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. You may obtain a copy of the License in the LICENSE file, or at:
56 |
57 | http://www.apache.org/licenses/LICENSE-2.0
58 |
59 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
60 |
61 | [](https://bitdeli.com/free "Bitdeli Badge")
62 |
--------------------------------------------------------------------------------
/GBToolbox/GBAlertBadge.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBAlertBadge.h
3 | // GBToolBox
4 | //
5 | // Created by Luka Mirosevic on 10/10/2016.
6 | // Copyright © 2016 Goonbee e.U. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | /**
12 | The classic alert badge with a number/string inside it.
13 |
14 | Useful for signalling things that have unread notifications or similar.
15 | */
16 | @interface GBAlertBadge : UIView
17 |
18 | @property (copy, nonatomic, nullable) NSString *badgeText;
19 | @property (assign, nonatomic) NSInteger badgeCount;
20 | @property (strong, nonatomic, nonnull) UIFont *font;
21 | @property (strong, nonatomic, nonnull) UIColor *textColor;
22 | @property (strong, nonatomic, nullable) UIImage *backgroundImage;
23 | @property (assign, nonatomic) UIEdgeInsets padding;
24 | @property (assign, nonatomic) BOOL hidesWhenCountZero;//default: NO
25 | @property (assign, nonatomic) BOOL clipsToPillShape;//default: YES
26 |
27 | /**
28 | Creates a badge with a background color and clipped to a pill shape.
29 | */
30 | + (nonnull instancetype)badgeWithFont:(nonnull UIFont *)font textColor:(nonnull UIColor *)textColor backgroundColor:(nonnull UIColor *)backgroundColor padding:(UIEdgeInsets)padding;
31 |
32 | /**
33 | Creates a badge with a background image.
34 | */
35 | + (nonnull instancetype)badgeWithFont:(nonnull UIFont *)font textColor:(nonnull UIColor *)textColor backgroundImage:(nullable UIImage *)backgroundImage padding:(UIEdgeInsets)padding;
36 | - (nonnull instancetype)initWithFont:(nonnull UIFont *)font textColor:(nonnull UIColor *)textColor backgroundImage:(nullable UIImage *)backgroundImage padding:(UIEdgeInsets)padding;
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/GBToolbox/GBGradientView.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBGradientView.m
3 | // Pods
4 | //
5 | // Created by Luka Mirosevic on 13/11/2014.
6 | //
7 | //
8 |
9 | #import "GBGradientView.h"
10 |
11 | #import "NSArray+GBToolbox.h"
12 |
13 | @interface GBGradientView ()
14 |
15 | @property (strong, nonatomic) CAGradientLayer *myGradientLayer;
16 |
17 | @end
18 |
19 | @implementation GBGradientView
20 |
21 | #pragma mark - API
22 |
23 | + (instancetype)gradientViewWithColors:(NSArray *)colors dimension:(GBGradientDimension)dimension {
24 | // configure my view
25 | GBGradientView *view = [[self alloc] initWithFrame:CGRectMake(0., 0., 0., 0.)];
26 | CAGradientLayer *gradientLayer = [CAGradientLayer layer];
27 |
28 | switch (dimension) {
29 | case GBGradientDimensionHorizontal: {
30 | gradientLayer.startPoint = CGPointMake(0.0, 0.5);
31 | gradientLayer.endPoint = CGPointMake(1.0, 0.5);
32 | } break;
33 |
34 | case GBGradientDimensionVertical: {
35 | gradientLayer.startPoint = CGPointMake(0.5, 0.0);
36 | gradientLayer.endPoint = CGPointMake(0.5, 1.0);
37 | } break;
38 | }
39 |
40 | gradientLayer.frame = view.bounds;
41 | gradientLayer.colors = [colors map:^id(id object) {
42 | return (id)[object CGColor];
43 | }];
44 | [view.layer insertSublayer:gradientLayer atIndex:0];
45 |
46 | // store the layer
47 | view.myGradientLayer = gradientLayer;
48 |
49 | return view;
50 | }
51 |
52 | #pragma mark - Overrides
53 |
54 | - (void)layoutSubviews {
55 | [super layoutSubviews];
56 |
57 | // resize the layer when the view changes size
58 | self.myGradientLayer.frame = self.bounds;
59 | }
60 |
61 | @end
62 |
--------------------------------------------------------------------------------
/GBToolbox/UIView+GBPopUp.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+GBPopUp.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 08/07/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | typedef enum {
12 | GBPopUpAnimationFlyUp,
13 | GBPopUpAnimationFadeAway,
14 | } GBPopUpAnimation;
15 |
16 | typedef void(^GBPopUpAutolayoutInstallationBlock)(UIView *superview, UIView *view);
17 |
18 | @interface UIView (GBPopUp)
19 |
20 | @property (strong, nonatomic) UIColor *popUpBackgroundColor;
21 | @property (assign, nonatomic, readonly) BOOL isPresentedAsPopUp;
22 |
23 | /**
24 | Presents this view directly onto the key window.
25 | */
26 | - (void)presentAsPopUpOnWindowAnimated:(BOOL)animated;
27 |
28 | /**
29 | Presents this view directly onto the key window, with an optional block for installing autolayout constraints.
30 | */
31 | - (void)presentAsPopUpOnWindowAnimated:(BOOL)animated installingAutolayout:(GBPopUpAutolayoutInstallationBlock)autolayoutInstallation;
32 |
33 | /**
34 | Presents this view onto the desired view.
35 | */
36 | - (void)presentAsPopUpOnView:(UIView *)targetView animated:(BOOL)animated;
37 |
38 | /**
39 | Presents this view onto the desired view, with an optional block for installing autolayout constraints.
40 | */
41 | - (void)presentAsPopUpOnView:(UIView *)targetView animated:(BOOL)animated installingAutolayout:(GBPopUpAutolayoutInstallationBlock)autolayoutInstallation;
42 |
43 | /**
44 | Dismisses the popup with the default fade animation.
45 | */
46 | - (void)dismissPopUpAnimated:(BOOL)animated;
47 |
48 | /**
49 | Dismisses the popup with a specific animation style.
50 | */
51 | - (void)dismissPopUpWithAnimation:(GBPopUpAnimation)animationType;
52 |
53 | @end
54 |
--------------------------------------------------------------------------------
/GBToolbox/NSObject+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSObject (GBToolbox)
12 |
13 | /**
14 | An easy way to associate an arbitrary payload with an object. e.g. when you create a button which pertains to changing some model, you can attach the model to the button and then get to it in the button action method.
15 | */
16 | @property (strong, nonatomic, nullable) id GBPayload;
17 |
18 | /**
19 | An easy way to associate arbitrary key value paris to an object. e.g. when you create a button which pertains to changing some model, you can attach the model to the button and then get to it in the button action method.
20 |
21 | Keys and values are strongly retained. Keys are not copied in.
22 | */
23 | @property (strong, nonatomic, nonnull, readonly) NSMapTable *GBPayloadMap;
24 |
25 | /**
26 | Returns the pointer address of an object as a string.
27 | */
28 | @property (copy, nonatomic, readonly, nonnull) NSString *pointerAddress;
29 |
30 | /**
31 | Yields self to the block, and then returns self. The primary purpose of this method is to “tap into” a method chain, in order to perform operations on intermediate results within the chain.
32 | */
33 | - (nonnull instancetype)tap:(void (^ _Nonnull)(id _Nonnull object))block;
34 |
35 | /**
36 | Returns the getter selector for a property with a name.
37 | */
38 | + (nullable SEL)getterForPropertyWithName:(nonnull NSString *)name;
39 |
40 | /**
41 | Returns the setter selector for a property with a name.
42 | */
43 | + (nullable SEL)setterForPropertyWithName:(nonnull NSString *)name;
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/GBToolbox/NSOrderedSet+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSOrderedSet+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 28/03/16.
6 | // Copyright © 2016 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "NSOrderedSet+GBToolbox.h"
10 |
11 | @implementation NSOrderedSet (GBToolbox)
12 |
13 | - (NSUInteger)indexOfObjectIdenticalTo:(id)anObject {
14 | for (NSUInteger i = 0; i < self.count; i++) {
15 | if (self[i] == anObject) {
16 | return i;
17 | }
18 | }
19 |
20 | return NSNotFound;
21 | }
22 |
23 | - (NSOrderedSet *)map:(id(^)(id object))function {
24 | NSMutableOrderedSet *results = [[NSMutableOrderedSet alloc] initWithCapacity:self.count];
25 |
26 | for (id object in self) {
27 | id transformed = function(object);
28 | if (transformed) {
29 | [results addObject:transformed];
30 | } else {
31 | @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Mapping function must return a non-nil object" userInfo:nil];
32 | }
33 | }
34 |
35 | return [results copy];
36 | }
37 |
38 | - (id)foldLeft:(id(^)(id objectA, id objectB))function lastObject:(id)accumulator {
39 | for (id object in self) {
40 | accumulator = function(accumulator, object);
41 | }
42 |
43 | return accumulator;
44 | }
45 |
46 | - (id)foldRight:(id(^)(id objectA, id objectB))function initialObject:(id)accumulator {
47 | for (id object in [self reverseObjectEnumerator]) {
48 | accumulator = function(accumulator, object);
49 | }
50 |
51 | return accumulator;
52 | }
53 |
54 | - (id)reduce:(id(^)(id objectA, id objectB))function lastObject:(id)lastObject {
55 | return [self foldLeft:function lastObject:lastObject];
56 | }
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/GBToolbox/UIImageView+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIImageView+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 28/06/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "UIImageView+GBToolbox.h"
10 |
11 | @implementation UIImageView (GBToolbox)
12 |
13 | + (UIImageView *)imageViewWithImage:(UIImage *)image {
14 | UIImageView *imageView = [[UIImageView new] initWithImage:image];
15 | imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height);
16 | return imageView;
17 | }
18 |
19 | + (UIImageView *)imageViewWithImageNamed:(NSString *)imageName {
20 | return [self imageViewWithImage:[UIImage imageNamed:imageName]];
21 | }
22 |
23 | // based on http://stackoverflow.com/a/15447942/399772
24 | - (CGRect)displayedImageBounds {
25 | UIImage *image = [self image];
26 | if (self.contentMode != UIViewContentModeScaleAspectFit || !image) {
27 | return self.bounds;
28 | }
29 |
30 | CGFloat boundsWidth = self.bounds.size.width,
31 | boundsHeight = self.bounds.size.height;
32 |
33 | CGSize imageSize = image.size;
34 | CGFloat imageRatio = imageSize.width / imageSize.height;
35 | CGFloat viewRatio = boundsWidth / boundsHeight;
36 |
37 | if (imageRatio < viewRatio) {
38 | CGFloat scale = boundsHeight / imageSize.height;
39 | CGFloat width = scale * imageSize.width;
40 | CGFloat topLeftX = (boundsWidth - width) * 0.5;
41 | return CGRectMake(topLeftX, 0, width, boundsHeight);
42 | }
43 |
44 | CGFloat scale = boundsWidth / imageSize.width;
45 | CGFloat height = scale * imageSize.height;
46 | CGFloat topLeftY = (boundsHeight - height) * 0.5;
47 |
48 | return CGRectMake(0, topLeftY, boundsWidth, height);
49 | }
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/GBToolbox/NSDictionary+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSDictionary+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 06/06/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSDictionary<__covariant KeyType, __covariant ObjectType> (GBToolbox)
12 |
13 | #pragma mark - Funtional Programming
14 |
15 | /**
16 | Classic functional filter.
17 | */
18 | - (nonnull NSDictionary *)filter:(nonnull BOOL(^)(KeyType _Nonnull key, ObjectType _Nonnull object))function;
19 |
20 | /**
21 | Returns a random key for which the function returns YES.
22 | */
23 | - (nullable KeyType)aKey:(BOOL(^ _Nonnull)(KeyType _Nonnull key, ObjectType _Nonnull object))function;
24 |
25 | /**
26 | Returns a random object for which the function return YES.
27 | */
28 | - (nullable ObjectType)anObject:(BOOL(^ _Nonnull)(KeyType _Nonnull key, ObjectType _Nonnull object))function;
29 |
30 | /**
31 | Returns a new dictionary with all key/value pairs from dictionary removed whose values was an instance of NSNull. Works recursively.
32 | */
33 | + (nonnull NSDictionary *)dictionaryByPruningNullsInDictionary:(nullable NSDictionary *)dictionary;
34 |
35 | /**
36 | Returns a copy of the receiver with all key/value pairs removed whose values was an instance of NSNull. Works recursively.
37 | */
38 | - (nonnull NSDictionary *)dictionaryByPruningNulls;
39 |
40 | /**
41 | Returns a new dictionary (shallow copy) that contains both key/value pairs from the receiver and dictionary. In case of duplicate keys, dictionary's values will override those of the receiver.
42 | */
43 | - (nonnull NSDictionary *)dictionaryByMergingWithDictionary:(nullable NSDictionary *)dictionary;
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/GBToolbox/GBAlertBadgeView.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBAlertBadgeView.h
3 | // Russia
4 | //
5 | // Created by Luka Mirosevic on 01/07/2013.
6 | // Copyright (c) 2013 Goonbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | /**
12 | The classic alert badge with a number/string inside it.
13 |
14 | Useful for signalling things that have unread notifications or similar.
15 | */
16 | __deprecated_msg("Deprecated since 21.7. Use GBAlertBadgeView2 instead.")
17 | @interface GBAlertBadgeView : UIView
18 |
19 | @property (copy, nonatomic) NSString *badgeText NS_AVAILABLE_IOS(7_0);
20 | @property (assign, nonatomic) NSInteger badgeCount NS_AVAILABLE_IOS(7_0);
21 | @property (copy, nonatomic) UIFont *font NS_AVAILABLE_IOS(7_0);
22 | @property (copy, nonatomic) UIColor *textColor NS_AVAILABLE_IOS(7_0);
23 | @property (strong, nonatomic) UIImage *backgroundImage NS_AVAILABLE_IOS(7_0);
24 | @property (assign, nonatomic) CGFloat height NS_AVAILABLE_IOS(7_0);
25 | @property (assign, nonatomic) CGFloat horizontalPadding NS_AVAILABLE_IOS(7_0);
26 | @property (assign, nonatomic) BOOL hidesWhenCountZero NS_AVAILABLE_IOS(7_0);//default: NO
27 |
28 | + (GBAlertBadgeView *)badgeWithHeight:(CGFloat)height font:(UIFont *)font textColor:(UIColor *)textColor backgroundImage:(UIImage *)backgroundImage horizontalPadding:(CGFloat)horizontalPadding NS_AVAILABLE_IOS(7_0);
29 | - (id)initWithHeight:(CGFloat)height font:(UIFont *)font textColor:(UIColor *)textColor backgroundImage:(UIImage *)backgroundImage horizontalPadding:(CGFloat)horizontalPadding NS_AVAILABLE_IOS(7_0);
30 |
31 | - (void)syncFrameWithView:(UIView *)view offset:(CGPoint)offset NS_AVAILABLE_IOS(7_0) __deprecated_msg("Deprecated since 21.7. Use Autolayout instead.");
32 | - (void)stopSyncingFrame NS_AVAILABLE_IOS(7_0) __deprecated_msg("Deprecated since 21.7. When using Autolayout this should no longer be called.");
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/GBToolbox/GBRadialGradientView.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBRadialGradientView.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 11/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBRadialGradientView.h"
10 |
11 | @implementation GBRadialGradientView
12 |
13 | #pragma mark - init
14 |
15 | -(id)initWithFrame:(NSRect)frameRect {
16 | if (self = [super initWithFrame:frameRect]) {
17 | self.innerColor = [[NSColor whiteColor] colorWithAlphaComponent:.12];
18 | self.outerColor = [NSColor clearColor];
19 | self.cornerRadius = 4;
20 | }
21 |
22 | return self;
23 | }
24 |
25 | #pragma mark - custom properties
26 |
27 | -(void)setEdgeInsets:(GBEdgeInsets)edgeInsets {
28 | _edgeInsets = edgeInsets;
29 |
30 | [self setNeedsDisplay:YES];
31 | }
32 |
33 | -(void)setInnerColor:(NSColor *)innerColor {
34 | _innerColor = innerColor;
35 |
36 | [self setNeedsDisplay:YES];
37 | }
38 |
39 | -(void)setOuterColor:(NSColor *)outerColor {
40 | _outerColor = outerColor;
41 |
42 | [self setNeedsDisplay:YES];
43 | }
44 |
45 | -(void)setCornerRadius:(CGFloat)cornerRadius {
46 | _cornerRadius = cornerRadius;
47 |
48 | [self setNeedsDisplay:YES];
49 | }
50 |
51 | #pragma mark - drawing
52 |
53 | - (void)drawRect:(NSRect)dirtyRect {
54 | CGRect preliminaryClipRect = CGRectMake(self.edgeInsets.left, self.edgeInsets.bottom, self.bounds.size.width - self.edgeInsets.left - self.edgeInsets.right, self.bounds.size.height - self.edgeInsets.bottom - self.edgeInsets.top);
55 | NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:preliminaryClipRect xRadius:self.cornerRadius yRadius:self.cornerRadius];
56 | NSGradient *gradient = [[NSGradient alloc] initWithStartingColor:self.innerColor endingColor:self.outerColor];
57 | [gradient drawInBezierPath:path relativeCenterPosition:NSMakePoint(0, 0)];
58 | }
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/GBToolbox/GBTextField.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBTextField.h
3 | // Business cards
4 | //
5 | // Created by Luka Mirosevic on 28/09/2012.
6 | // Copyright (c) 2012 Luka Mirosevic.
7 | //
8 | // Licensed under the Apache License, Version 2.0 (the "License");
9 | // you may not use this file except in compliance with the License.
10 | // You may obtain a copy of the License at
11 | //
12 | // http://www.apache.org/licenses/LICENSE-2.0
13 | //
14 | // Unless required by applicable law or agreed to in writing, software
15 | // distributed under the License is distributed on an "AS IS" BASIS,
16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | // See the License for the specific language governing permissions and
18 | // limitations under the License.
19 |
20 | #import
21 |
22 | #import "GBTypes_Common.h"
23 |
24 | @protocol GBTextFieldDelegate;
25 |
26 | @interface GBTextField : UITextField
27 |
28 | @property (assign, nonatomic) UIEdgeInsets padding;
29 | @property (assign, nonatomic, readonly) BOOL isDirty;
30 | @property (assign, nonatomic) CGFloat leftViewLeftOffset;
31 | @property (assign, nonatomic) CGFloat rightViewRightOffset;
32 | @property (assign, nonatomic) CGRect leftViewFrame;
33 | @property (assign, nonatomic) CGRect rightViewFrame;
34 |
35 | @property (assign, nonatomic) BOOL invalidatesIntrinsicContentSizeDuringEditing;// default: YES
36 |
37 | //This is an augmented protocol. Adds 2 new methods, see below.
38 | -(id)delegate;
39 | -(void)setDelegate:(id)delegate;
40 |
41 | @end
42 |
43 | @protocol GBTextFieldDelegate
44 | @optional
45 |
46 | -(void)textField:(GBTextField *)textField keyPressed:(NSString *)string;
47 | -(void)textField:(GBTextField *)textField specialKeyPressed:(GBSpecialKey)specialKey;
48 |
49 | @end
50 |
--------------------------------------------------------------------------------
/GBToolbox/GBGlowingImageButtonCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBGlowingImageButtonCell.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 13/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBGlowingImageButtonCell.h"
10 |
11 | #import "GBToolbox.h"
12 |
13 |
14 | @interface GBGlowingImageButtonCell ()
15 |
16 | @property (strong, nonatomic) GBRadialGradientView *glowView;
17 |
18 | @end
19 |
20 |
21 | @implementation GBGlowingImageButtonCell
22 |
23 |
24 | #pragma mark - lazy
25 |
26 | -(GBRadialGradientView *)glowView {
27 | if (!_glowView) {
28 | _glowView = [[GBRadialGradientView alloc] initWithFrame:self.controlView.bounds];
29 | _glowView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
30 | _glowView.innerColor = [[NSColor whiteColor] colorWithAlphaComponent:.07];
31 | _glowView.outerColor = [NSColor clearColor];
32 | _glowView.cornerRadius = 4;
33 | _glowView.edgeInsets = GBEdgeInsetsMake(0, 0, 0, 0);
34 | }
35 |
36 | return _glowView;
37 | }
38 |
39 | #pragma mark - custom accessor
40 |
41 | -(void)setGlowEdgeInsets:(GBEdgeInsets)glowEdgeInsets {
42 | self.glowView.edgeInsets = glowEdgeInsets;
43 | }
44 |
45 | -(GBEdgeInsets)glowEdgeInsets {
46 | return self.glowView.edgeInsets;
47 | }
48 |
49 | -(void)setIsGlowing:(BOOL)isGlowing {
50 | //if theres a change
51 | if (isGlowing != _isGlowing) {
52 | if (isGlowing) {
53 | //add glow on top
54 | [self.controlView addSubview:self.glowView positioned:NSWindowAbove relativeTo:self.controlView.subviews.lastObject];
55 | }
56 | else {
57 | //remove the glow
58 | [self.glowView removeFromSuperview];
59 | }
60 | }
61 |
62 | //save ivar
63 | _isGlowing = isGlowing;
64 | }
65 |
66 | #pragma mark - init
67 |
68 | -(void)awakeFromNib {
69 | [super awakeFromNib];
70 |
71 | self.isGlowing = YES;
72 | }
73 |
74 | @end
75 |
--------------------------------------------------------------------------------
/GBToolbox/NSDate+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSDate+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 21/06/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "NSDate+GBToolbox.h"
10 |
11 | @implementation NSDate (GBToolbox)
12 |
13 | static NSDateFormatter *outDateFormatter;
14 | static NSArray *inDateFormatters;
15 |
16 | +(void)load {
17 | static dispatch_once_t onceToken;
18 | dispatch_once(&onceToken, ^{
19 | outDateFormatter = [NSDateFormatter new];
20 | outDateFormatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZZ";
21 | outDateFormatter.timeZone = [NSTimeZone timeZoneWithName:@"UTC"];
22 |
23 | NSDateFormatter *inDateFormatter1 = [NSDateFormatter new];
24 | inDateFormatter1.dateFormat = @"yyyy-MM-dd'T'HH:mm:ssZZ";
25 | NSDateFormatter *inDateFormatter2 = [NSDateFormatter new];
26 | inDateFormatter2.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss.SSSZZ";
27 | inDateFormatters = @[inDateFormatter1, inDateFormatter2];
28 | });
29 | }
30 |
31 | +(NSDate *)dateWithISO8601String:(NSString *)dateString {
32 | if (!dateString) return nil;
33 | if ([dateString hasSuffix:@"Z"]) dateString = [[dateString substringToIndex:(dateString.length-1)] stringByAppendingString:@"+0000"];
34 |
35 | NSDate *date;
36 | for (NSDateFormatter *dateFormatter in inDateFormatters) {
37 | date = [dateFormatter dateFromString:dateString];
38 | if (date) break;
39 | }
40 |
41 | return date;
42 | }
43 |
44 | -(NSString *)iso8601String {
45 | return [outDateFormatter stringFromDate:self];
46 | }
47 |
48 | -(BOOL)isInPast {
49 | return ([self timeIntervalSinceNow] < 0.);
50 | }
51 |
52 | -(BOOL)isDateBetweenStartDate:(NSDate*)beginDate andEndDate:(NSDate*)endDate {
53 | if ([self compare:beginDate] == NSOrderedAscending) {
54 | return NO;
55 | }
56 | else if ([self compare:endDate] == NSOrderedDescending) {
57 | return NO;
58 | }
59 | else {
60 | return YES;
61 | }
62 | }
63 |
64 | @end
65 |
--------------------------------------------------------------------------------
/GBToolbox/MKMapView+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // MKMapView+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 10/07/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "MKMapView+GBToolbox.h"
10 |
11 | @implementation MKMapView (GBToolbox)
12 |
13 | -(void)moveToRegionIncludingLocations:(NSArray *)locationsArray animated:(BOOL)animated {
14 | [self moveToRegionIncludingLocations:locationsArray withPaddingFactor:1.0 animated:animated];
15 | }
16 |
17 | -(void)moveToRegionIncludingLocations:(NSArray *)locationsArray withPaddingFactor:(CGFloat)paddingFactor animated:(BOOL)animated {
18 | MKMapRect zoomRect = MKMapRectNull;
19 | for (CLLocation *location in locationsArray) {
20 | MKMapPoint annotationPoint = MKMapPointForCoordinate(location.coordinate);
21 | MKMapRect pointRect = MKMapRectMake(annotationPoint.x-5, annotationPoint.y-5, 10, 10);
22 | zoomRect = MKMapRectUnion(zoomRect, pointRect);
23 | }
24 |
25 | CGSize sizeDelta = CGSizeMake(zoomRect.size.width*(paddingFactor - 1.0),
26 | zoomRect.size.height*(paddingFactor - 1.0));
27 |
28 | MKMapRect paddedMapRect = MKMapRectMake(zoomRect.origin.x - (sizeDelta.width / 2.),
29 | zoomRect.origin.y - (sizeDelta.height / 2.),
30 | zoomRect.size.width + sizeDelta.width,
31 | zoomRect.size.height + sizeDelta.height);
32 |
33 | [self setVisibleMapRect:paddedMapRect animated:animated];
34 | }
35 |
36 | -(void)moveToLocation:(CLLocation *)location showingRadius:(CGFloat)radius animated:(BOOL)animated {
37 | //111111m = 1deg lat
38 | //111111m * cos(lat) = 1deg lng
39 | CGFloat dlat = radius / 111111.;
40 | CGFloat dlng = radius*cos(dlat) / 111111.;
41 |
42 | MKCoordinateSpan span = MKCoordinateSpanMake(dlat, dlng);
43 | MKCoordinateRegion region = MKCoordinateRegionMake(location.coordinate, span);
44 |
45 | [self setRegion:region animated:animated];
46 | }
47 |
48 | @end
49 |
--------------------------------------------------------------------------------
/GBToolbox/GBTextBox.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBTextBox.h
3 | // Russia
4 | //
5 | // Created by Luka Mirosevic on 05/07/2013.
6 | // Copyright (c) 2013 Goonbee. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | typedef enum {
12 | GBTextBoxFlexibleDimensionHeight,
13 | GBTextBoxFlexibleDimensionWidth
14 | } GBTextBoxFlexibleDimension;
15 |
16 | @protocol GBTextBoxDelegate;
17 |
18 | @interface GBTextBox : UIView
19 |
20 | @property (weak, nonatomic) id delegate;
21 |
22 | @property (assign, nonatomic) GBTextBoxFlexibleDimension flexibleDimension;//defaults to height
23 | @property (strong, nonatomic) UIImage *icon;
24 | @property (assign, nonatomic) CGFloat iconLeftMargin;
25 | @property (assign, nonatomic) CGFloat iconVerticalOffset;
26 | @property (strong, nonatomic) UIImage *rightIcon;
27 | @property (assign, nonatomic) CGFloat rightIconRightMargin;
28 | @property (assign, nonatomic) CGFloat rightIconVerticalOffset;
29 | @property (strong, nonatomic) UIImage *backgroundImage;
30 | @property (strong, nonatomic) NSString *text;
31 | @property (strong, nonatomic) UIColor *textColor;
32 | @property (strong, nonatomic) UIColor *textShadowColor;
33 | @property (assign, nonatomic) CGSize textShadowOffset;
34 | @property (strong, nonatomic) UIFont *font;
35 | @property (assign, nonatomic) NSTextAlignment textAlignment;
36 | @property (assign, nonatomic) UIEdgeInsets textPadding;
37 |
38 | //forces it to recalculate the height based on the current text and it's properties. you would call this after you set the frame of this view so that it recalculated it's own height
39 | -(void)recalculateHeight;
40 |
41 | @end
42 |
43 | @protocol GBTextBoxDelegate
44 | @optional
45 |
46 | -(void)textBox:(GBTextBox *)textBox didChangeSizeFrom:(CGSize)oldSize to:(CGSize)newSize;
47 |
48 | @end
--------------------------------------------------------------------------------
/GBToolbox/GBAsyncOperation.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBAsyncOperation.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 22/11/16.
6 | // Copyright © 2016 Goonbee e.U.. All rights reserved.
7 | //
8 |
9 | #import "GBAsyncOperation.h"
10 |
11 | @implementation GBAsyncOperation {
12 | BOOL _executing;
13 | BOOL _finished;
14 | }
15 |
16 | #pragma mark - API
17 |
18 | - (instancetype)init {
19 | if (self = [super init]) {
20 | _executing = NO;
21 | _finished = NO;
22 | }
23 |
24 | return self;
25 | }
26 |
27 | - (void)completeAsyncOperation {
28 | [self willChangeValueForKey:@"isFinished"];
29 | [self willChangeValueForKey:@"isExecuting"];
30 |
31 | _executing = NO;
32 | _finished = YES;
33 |
34 | [self didChangeValueForKey:@"isExecuting"];
35 | [self didChangeValueForKey:@"isFinished"];
36 | }
37 |
38 | #pragma mark - Overrides
39 |
40 | - (void)main {
41 | @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"You must override main in your NSOperation subclass." userInfo:nil];
42 | }
43 |
44 | - (void)start {
45 | // Always check for cancellation before launching the task.
46 | if (self.isCancelled) {
47 | // Must move the operation to the finished state if it is canceled.
48 | [self willChangeValueForKey:@"isFinished"];
49 | _finished = YES;
50 | [self didChangeValueForKey:@"isFinished"];
51 |
52 | return;
53 | }
54 |
55 | // If the operation is not canceled, begin executing the task.
56 | [self willChangeValueForKey:@"isExecuting"];
57 | [self performSelector:@selector(main)];// using performSelector to avoid NS_UNAVAILABLE compiler warning
58 | _executing = YES;
59 | [self didChangeValueForKey:@"isExecuting"];
60 | }
61 |
62 | - (void)cancel {
63 | // we implement this only so that we can highlight it in the interface, and to keep the compiler happy
64 | [super cancel];
65 | }
66 |
67 | - (BOOL)isConcurrent {
68 | return YES;
69 | }
70 |
71 | - (BOOL)isExecuting {
72 | return _executing;
73 | }
74 |
75 | - (BOOL)isFinished {
76 | return _finished;
77 | }
78 |
79 | @end
80 |
--------------------------------------------------------------------------------
/GBToolbox/GBMultiStateButton.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBMultiStateButton.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 20/02/2016.
6 | // Copyright © 2016 Goonbee e.U. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class GBMultiStateButtonState;
12 |
13 | @interface GBMultiStateButton : UIControl
14 |
15 | @property (strong, nonatomic, readonly) NSArray *states;
16 | @property (strong, nonatomic) GBMultiStateButtonState *activeState;
17 | @property (strong, nonatomic) id activeStateIdentifier;
18 | @property (assign, nonatomic) BOOL adjustsImageWhenHighlighted;
19 |
20 | - (instancetype)initWithStates:(NSArray *)states;
21 |
22 | @end
23 |
24 | @interface GBMultiStateButtonState : NSObject
25 |
26 | @property (strong, nonatomic) id stateIdentifier;
27 | @property (strong, nonatomic) UIImage *image;
28 | @property (strong, nonatomic) UIImage *backgroundImage;
29 | @property (strong, nonatomic) UIImage *imageWhenHighlighted;
30 | @property (strong, nonatomic) UIImage *backgroundImageWhenHighlighted;
31 | @property (assign, nonatomic, getter=isUserSelectable) BOOL userSelectable;
32 |
33 | + (instancetype)stateWithIdentifier:(id)identifier image:(UIImage *)image;
34 | + (instancetype)stateWithIdentifier:(id)identifier image:(UIImage *)image backgroundImage:(UIImage *)backgroundImage;
35 | + (instancetype)stateWithIdentifier:(id)identifier image:(UIImage *)image backgroundImage:(UIImage *)backgroundImage imageWhenHighlighted:(UIImage *)imageWhenHighlighted backgroundImageWhenHighlighted:(UIImage *)backgroundImageWhenHighlighted;
36 | + (instancetype)stateWithIdentifier:(id)identifier image:(UIImage *)image backgroundImage:(UIImage *)backgroundImage imageWhenHighlighted:(UIImage *)imageWhenHighlighted backgroundImageWhenHighlighted:(UIImage *)backgroundImageWhenHighlighted userSelectable:(BOOL)userSelectable;
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/GBToolbox/GBCustomImageButtonCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBCustomImageButtonCell.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 13/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBCustomImageButtonCell.h"
10 |
11 | #import "GBToolbox.h"
12 |
13 |
14 | @interface GBCustomImageButtonCell ()
15 |
16 | @property (strong, nonatomic) GBResizableImageView *resizableImageView;
17 | @property (strong, nonatomic) NSImageView *foregroundImageView;
18 |
19 | @end
20 |
21 |
22 | @implementation GBCustomImageButtonCell
23 |
24 | #pragma mark - lazy
25 |
26 | -(GBResizableImageView *)resizableImageView {
27 | if (!_resizableImageView) {
28 | _resizableImageView = [[GBResizableImageView alloc] initWithFrame:self.controlView.bounds];
29 | _resizableImageView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
30 | }
31 |
32 | return _resizableImageView;
33 | }
34 |
35 | -(NSImageView *)foregroundImageView {
36 | if (!_foregroundImageView) {
37 | _foregroundImageView = [[NSImageView alloc] initWithFrame:self.controlView.bounds];
38 | _foregroundImageView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
39 | //set scaling and alignment to just center the image without resizing
40 | _foregroundImageView.imageAlignment = NSImageAlignCenter;
41 | _foregroundImageView.imageScaling = NSImageScaleNone;
42 | }
43 |
44 | return _foregroundImageView;
45 | }
46 |
47 | #pragma mark - custom setter
48 |
49 | -(void)setForegroundImage:(NSImage *)foregroundImage {
50 | _foregroundImage = foregroundImage;
51 |
52 | self.foregroundImageView.image = foregroundImage;
53 | }
54 |
55 | -(void)setBackgroundImage:(NSImage *)backgroundImage {
56 | self.resizableImageView.image = backgroundImage;
57 | }
58 |
59 | -(NSImage *)backgroundImage {
60 | return self.resizableImageView.image;
61 | }
62 |
63 | -(void)setBackgroundImageCapInsets:(GBEdgeInsets)backgroundImageCapInsets {
64 | self.resizableImageView.capInsets = backgroundImageCapInsets;
65 | }
66 |
67 | -(GBEdgeInsets)backgroundImageCapInsets {
68 | return self.resizableImageView.capInsets;
69 | }
70 |
71 | #pragma mark - init
72 |
73 | -(void)awakeFromNib {
74 | [super awakeFromNib];
75 |
76 | self.customView = self.resizableImageView;
77 | [self.customView addSubview:self.foregroundImageView];
78 | }
79 |
80 | @end
81 |
--------------------------------------------------------------------------------
/GBToolbox/UIControl+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIControl+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 20/02/2016.
6 | // Copyright © 2016 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "UIControl+GBToolbox.h"
10 |
11 | #import "GBMacros_Common.h"
12 | #import
13 |
14 | @interface GBControlTargetActionTarget : NSObject
15 |
16 | @property (copy, nonatomic) GBActionBlock block;
17 |
18 | @end
19 |
20 | @implementation GBControlTargetActionTarget
21 |
22 | #pragma mark - API
23 |
24 | + (instancetype)targetActionTargetWithBlock:(GBActionBlock)block {
25 | GBControlTargetActionTarget *targetActionTarget = [self new];
26 | targetActionTarget.block = block;
27 |
28 | return targetActionTarget;
29 | }
30 |
31 | - (void)fireForSender:(id)sender event:(UIEvent *)event {
32 | if (self.block) self.block(sender, event);
33 | }
34 |
35 | @end
36 |
37 | @interface UIControl ()
38 |
39 | @property (strong, nonatomic, readonly) NSHashTable *targetActionTargets;
40 |
41 | @end
42 |
43 | @implementation UIControl (GBToolbox)
44 |
45 | #pragma mark - CA
46 |
47 | static void *AssociatedTargetActionsKey = &AssociatedTargetActionsKey;
48 |
49 | - (NSHashTable *)targetActionTargets {
50 | NSHashTable *targetActionTargets = objc_getAssociatedObject(self, &AssociatedTargetActionsKey);
51 |
52 | // lazily create out hashTable
53 | if (!targetActionTargets) {
54 | targetActionTargets = [NSHashTable hashTableWithOptions:NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPointerPersonality];
55 | objc_setAssociatedObject(self, &AssociatedTargetActionsKey, targetActionTargets, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
56 | }
57 |
58 | return targetActionTargets;
59 | }
60 |
61 | #pragma mark - API
62 |
63 | - (void)addTargetActionForControlEvents:(UIControlEvents)controlEvents withBlock:(GBActionBlock)block {
64 | // Create the target that will store and trigger the block, exposed by a method that we can pass to the target/action mechanism
65 | GBControlTargetActionTarget *target = [GBControlTargetActionTarget targetActionTargetWithBlock:block];
66 |
67 | // Retain our target, so it lives for as long as this object lives
68 | [self.targetActionTargets addObject:target];
69 |
70 | // Add the target using normal target/action, setting the action to our fire trigger
71 | [self addTarget:target action:@selector(fireForSender:event:) forControlEvents:controlEvents];
72 | }
73 |
74 | @end
75 |
--------------------------------------------------------------------------------
/GBToolbox/NSDictionary+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSDictionary+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 06/06/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "NSDictionary+GBToolbox.h"
10 |
11 | @implementation NSDictionary (GBToolbox)
12 |
13 | #pragma mark - Funtional Programming
14 |
15 | - (NSDictionary *)filter:(BOOL(^)(id key, id object))function {
16 | // creates a results array in which to store results, sets the capacity for faster writes
17 | NSUInteger count = self.count;
18 | NSMutableDictionary *resultsDictionary = [[NSMutableDictionary alloc] initWithCapacity:count];
19 |
20 | // applies the function to each item and stores the result in the new dictionary
21 | for (id key in self) {
22 | if (function(key, self[key])) {
23 | resultsDictionary[key] = self[key];
24 | }
25 | }
26 |
27 | // returns an immutable copy
28 | return [resultsDictionary copy];
29 | }
30 |
31 | - (id)aKey:(BOOL(^)(id key, id object))function {
32 | for (id key in self) {
33 | if (function(key, self[key])) {
34 | return key;
35 | }
36 | }
37 |
38 | return nil;
39 | }
40 |
41 | - (id)anObject:(BOOL(^)(id key, id object))function {
42 | id key = [self aKey:function];
43 | if (key) {
44 | return self[key];
45 | }
46 | else {
47 | return nil;
48 | }
49 | }
50 |
51 | #pragma mark - pruning
52 |
53 | + (NSDictionary *)dictionaryByPruningNullsInDictionary:(NSDictionary *)dictionary {
54 | // fallback for nil dictionaries.
55 | if (!dictionary) dictionary = @{};
56 |
57 | NSMutableDictionary *temp = [[NSMutableDictionary alloc] initWithCapacity:dictionary.count];
58 |
59 | for (id key in dictionary) {
60 | id value = [dictionary objectForKey:key];
61 |
62 | if ([value isKindOfClass:[NSDictionary class]]) {
63 | [temp setObject:[NSDictionary dictionaryByPruningNullsInDictionary:value] forKey:key];
64 | }
65 | else if ([value isKindOfClass:[NSNull class]]) {
66 | continue;
67 | }
68 | else {
69 | [temp setObject:value forKey:key];
70 | }
71 | }
72 |
73 | return temp;
74 | }
75 |
76 | - (nonnull NSDictionary *)dictionaryByPruningNulls {
77 | return [self.class dictionaryByPruningNullsInDictionary:self];
78 | }
79 |
80 | - (nonnull NSDictionary *)dictionaryByMergingWithDictionary:(nullable NSDictionary *)dictionary {
81 | NSMutableDictionary *newDictionary = [self mutableCopy];
82 |
83 | for (id key in dictionary) {
84 | newDictionary[key] = dictionary[key];
85 | }
86 |
87 | return newDictionary;
88 | }
89 |
90 | @end
91 |
--------------------------------------------------------------------------------
/GBToolbox/NSObject+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "NSObject+GBToolbox.h"
10 |
11 | #import "GBMacros_Common.h"
12 |
13 | @interface NSObject ()
14 |
15 | @property (strong, nonatomic, readwrite) NSMapTable *GBPayloadMap_storage;
16 |
17 | @end
18 |
19 | @implementation NSObject (GBToolbox)
20 |
21 | _associatedObject(strong, nonatomic, id, GBPayload, setGBPayload)
22 |
23 | _associatedObject(strong, nonatomic, NSMapTable *, GBPayloadMap_storage, setGBPayloadMap_storage)
24 |
25 | - (NSMapTable *)GBPayloadMap {
26 | if (!self.GBPayloadMap_storage) {
27 | self.GBPayloadMap_storage = [NSMapTable strongToStrongObjectsMapTable];
28 | }
29 |
30 | return self.GBPayloadMap_storage;
31 | }
32 |
33 | - (NSString *)pointerAddress {
34 | return [NSString stringWithFormat:@"%p", self];
35 | }
36 |
37 | - (instancetype)tap:(void (^)(id object))block {
38 | if (block) block(self);
39 |
40 | return self;
41 | }
42 |
43 | // http://stackoverflow.com/a/38759825/399772
44 | + (SEL)getterForPropertyWithName:(NSString *)name {
45 | const char *propertyName = [name cStringUsingEncoding:NSASCIIStringEncoding];
46 | objc_property_t prop = class_getProperty(self, propertyName);
47 |
48 | const char *selectorName = property_copyAttributeValue(prop, "G");
49 | if (selectorName == NULL) {
50 | selectorName = [name cStringUsingEncoding:NSASCIIStringEncoding];
51 | }
52 | NSString *selectorString = [NSString stringWithCString:selectorName encoding:NSASCIIStringEncoding];
53 | return NSSelectorFromString(selectorString);
54 | }
55 |
56 | // http://stackoverflow.com/a/38759825/399772
57 | + (SEL)setterForPropertyWithName:(NSString *)name {
58 | const char *propertyName = [name cStringUsingEncoding:NSASCIIStringEncoding];
59 | objc_property_t prop = class_getProperty(self, propertyName);
60 |
61 | char *selectorName = property_copyAttributeValue(prop, "S");
62 | NSString *selectorString;
63 | if (selectorName == NULL) {
64 | char firstChar = (char)toupper(propertyName[0]);
65 | NSString *capitalLetter = [NSString stringWithFormat:@"%c", firstChar];
66 | NSString *reminder = [NSString stringWithCString: propertyName+1
67 | encoding: NSASCIIStringEncoding];
68 | selectorString = [@[@"set", capitalLetter, reminder, @":"] componentsJoinedByString:@""];
69 | } else {
70 | selectorString = [NSString stringWithCString:selectorName encoding:NSASCIIStringEncoding];
71 | }
72 |
73 | return NSSelectorFromString(selectorString);
74 | }
75 |
76 | @end
77 |
--------------------------------------------------------------------------------
/GBToolbox/UIView+GBFloatingPopoverView.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+GBFloatingPopoverView.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 16/09/16.
6 | // Copyright © 2016 Goonbee e.U. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | FOUNDATION_EXPORT NSTimeInterval const kGBFloatingPopoverShowForever;
12 |
13 | typedef void(^GBFloatingPopoverAutolayoutConfigurationBlock)(UIView * _Nonnull view);
14 |
15 | @interface UIView (GBFloatingPopoverView)
16 |
17 | /**
18 | Shows receiver on the targetView. `layoutBlock` is called synchronously as soon as the view has been added to targetView (unless if the view is already a subview of targetView. Handles intelligent nesting of views within a context.
19 | */
20 | - (void)floatOnView:(nonnull UIView *)targetView animated:(BOOL)animated context:(nonnull id)context layoutConfigurationBlock:(nullable GBFloatingPopoverAutolayoutConfigurationBlock)layoutBlock;
21 |
22 | /**
23 | Shows receiver on the targetView. `layoutBlock` is called synchronously as soon as the view has been added to targetView (unless if the view is already a subview of targetView. Handles intelligent nesting of views within a context. If autoDismiss is set to YES, this view will show for a while and then dismiss itself.
24 | */
25 | - (void)floatOnView:(nonnull UIView *)targetView animated:(BOOL)animated autoDismiss:(BOOL)autoDismiss context:(nonnull id)context layoutConfigurationBlock:(nullable GBFloatingPopoverAutolayoutConfigurationBlock)layoutBlock;
26 |
27 | /**
28 | Shows receiver on the targetView. `layoutBlock` is called synchronously as soon as the view has been added to targetView (unless if the view is already a subview of targetView. Handles intelligent nesting of views within a context. If you do not want the view to dismiss, pass a `kGBFloatingPopoverShowForever` as the `showDuration.`
29 |
30 | Note: If you pass a non-nil layoutConfigurationBlock, the `view` will have its `translatesAutoresizingMaskIntoConstraints` property set to NO.
31 |
32 | Warning: Passing different durations for a particular context, will have undefined behaviour if another view is already being shown in this context.
33 | */
34 | - (void)floatOnView:(nonnull UIView *)targetView context:(nonnull id)context fadeInDuration:(NSTimeInterval)fadeInDuration showDuration:(NSTimeInterval)showDuration fadeOutDuration:(NSTimeInterval)fadeOutDuration layoutConfigurationBlock:(nullable GBFloatingPopoverAutolayoutConfigurationBlock)layoutBlock;
35 |
36 | /**
37 | Dismisses the receiver.
38 | */
39 | - (void)floatingViewDismissForContext:(nonnull id)context animated:(BOOL)animated;
40 |
41 | /**
42 | Dismisses the receiver with a desired animation duration.
43 | */
44 | - (void)floatingViewDismissForContext:(nonnull id)context fadeOutDuration:(NSTimeInterval)fadeOutDuration;
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/GBToolbox/NSMutableURLRequest+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSMutableURLRequest+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 13/06/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface GBFormPayload : NSObject
12 |
13 | @property (copy, nonatomic) NSString *contentType;
14 | @property (copy, nonatomic) NSString *name;
15 | @property (copy, nonatomic) NSString *filename;
16 | @property (strong, nonatomic) NSData *data;
17 |
18 | +(GBFormPayload *)formPayloadWithName:(NSString *)name filename:(NSString *)filename contentType:(NSString *)contentType data:(NSData *)data;
19 | +(GBFormPayload *)formPayloadWithName:(NSString *)name contentType:(NSString *)contentType data:(NSData *)data;
20 | -(id)initWithName:(NSString *)name filename:(NSString *)filename contentType:(NSString *)contentType data:(NSData *)data;
21 | -(id)initWithName:(NSString *)name contentType:(NSString *)contentType data:(NSData *)data;
22 |
23 | -(NSData *)representationInMultipartForm;
24 |
25 | @end
26 |
27 | @interface NSMutableURLRequest (GBToolbox)
28 |
29 | +(NSMutableURLRequest *)postRequestWithURLString:(NSString *)urlString jsonPayload:(NSData *)data;
30 | +(NSMutableURLRequest *)postRequestWithURLString:(NSString *)urlString jsonPayload:(NSData *)data headers:(NSDictionary *)headers;
31 | +(NSMutableURLRequest *)postRequestWithURLString:(NSString *)urlString jsonPayload:(NSData *)data headers:(NSDictionary *)headers timeout:(NSTimeInterval)timeout;
32 |
33 | +(NSMutableURLRequest *)postRequestWithURLString:(NSString *)urlString payloadType:(NSString *)contentType payloadData:(NSData *)data;
34 | +(NSMutableURLRequest *)postRequestWithURLString:(NSString *)urlString payloadType:(NSString *)contentType payloadData:(NSData *)data headers:(NSDictionary *)headers;
35 | +(NSMutableURLRequest *)postRequestWithURLString:(NSString *)urlString payloadType:(NSString *)contentType payloadData:(NSData *)data headers:(NSDictionary *)headers timeout:(NSTimeInterval)timeout;
36 |
37 | +(NSMutableURLRequest *)multipartPostRequestWithURLString:(NSString *)urlString payloads:(NSArray *)payloads;
38 | +(NSMutableURLRequest *)multipartPostRequestWithURLString:(NSString *)urlString payloads:(NSArray *)payloads headers:(NSDictionary *)headers;
39 | +(NSMutableURLRequest *)multipartPostRequestWithURLString:(NSString *)urlString payloads:(NSArray *)payloads headers:(NSDictionary *)headers timeout:(NSTimeInterval)timeout;
40 |
41 | +(NSMutableURLRequest *)requestWithURLString:(NSString *)urlString method:(NSString *)method body:(NSData *)body headers:(NSDictionary *)headers;
42 | +(NSMutableURLRequest *)requestWithURLString:(NSString *)urlString method:(NSString *)method body:(NSData *)body headers:(NSDictionary *)headers timeout:(NSTimeInterval)timeout;
43 |
44 | @end
45 |
--------------------------------------------------------------------------------
/GBToolbox/NSMutableArray+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // NSMutableArray+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 17/05/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "NSMutableArray+GBToolbox.h"
10 |
11 | #import "GBConstants_Common.h"
12 |
13 | @implementation NSMutableArray (GBToolbox)
14 |
15 | #pragma mark - Array padding
16 | //These are all non-destructive and leave existing elements in, only when extendin the array do we actually pad it
17 |
18 | //Pads the array out so the last index is the one that's passed in, with [NSNull null]
19 | -(void)padToIndex:(NSUInteger)index {
20 | [self padToIndex:index withObject:[NSNull null]];
21 | }
22 |
23 | //Pads the array out so the last index is the one that's passed in, with any non nil object
24 | -(void)padToIndex:(NSUInteger)index withObject:(id)object {
25 | [self padToSize:index+1 withObject:object];
26 | }
27 |
28 | //Pads the array out to the desired size with [NSNull null] objects
29 | -(void)padToSize:(NSUInteger)count {
30 | [self padToSize:count withObject:[NSNull null]];
31 | }
32 |
33 | //Pads the array out to the desired size with any object you supply
34 | -(void)padToSize:(NSUInteger)count withObject:(id)object {
35 | //make sure it's not nil
36 | if (object) {
37 | //if the size is already bigger or equal then we're done
38 | if (self.count >= count) {
39 | //noop
40 | }
41 | else {
42 | //enumerate from the last element+1 and assign until we are at the desired length
43 | for (NSUInteger i=self.count; i 0 )
77 | {
78 | if (_placeHolderLabel == nil )
79 | {
80 | _placeHolderLabel = [[UILabel alloc] initWithFrame:CGRectMake(8,8,self.bounds.size.width - 16,0)];
81 | _placeHolderLabel.lineBreakMode = NSLineBreakByWordWrapping;
82 | _placeHolderLabel.numberOfLines = 0;
83 | _placeHolderLabel.font = self.font;
84 | _placeHolderLabel.backgroundColor = [UIColor clearColor];
85 | _placeHolderLabel.textColor = self.placeholderColor;
86 | _placeHolderLabel.alpha = 0;
87 | _placeHolderLabel.tag = 999;
88 | [self addSubview:_placeHolderLabel];
89 | }
90 |
91 | _placeHolderLabel.text = self.placeholder;
92 | [_placeHolderLabel sizeToFit];
93 | [self sendSubviewToBack:_placeHolderLabel];
94 | }
95 |
96 | if( [[self text] length] == 0 && [[self placeholder] length] > 0 )
97 | {
98 | [[self viewWithTag:999] setAlpha:1];
99 | }
100 |
101 | [super drawRect:rect];
102 | }
103 |
104 | -(UIColor *)defaultPlaceHolderColor {
105 | if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
106 | return [UIColor colorWithRed:0 green:0 blue:0.098039 alpha:0.22];
107 | }
108 | else {
109 | return [UIColor colorWithWhite:0.7 alpha:1.];
110 | }
111 | }
112 |
113 | @end
--------------------------------------------------------------------------------
/GBToolbox/UITableViewCell+AdditionalViews.m:
--------------------------------------------------------------------------------
1 | //
2 | // UITableViewCell+AdditionalViews.m
3 | // Russia
4 | //
5 | // Created by Luka Mirosevic on 27/06/2013.
6 | // Copyright (c) 2013 Goonbee. All rights reserved.
7 | //
8 |
9 | #import "UITableViewCell+AdditionalViews.h"
10 |
11 | #import "GBMacros_Common.h"
12 |
13 | @interface UITableViewCell ()
14 |
15 | @property (strong, nonatomic) UIView *internalLeftView;
16 | @property (assign, nonatomic) NSValue *internalLeftViewFrame;
17 | @property (strong, nonatomic) UIView *internalRightView;
18 | @property (assign, nonatomic) NSValue *internalRightViewFrame;
19 |
20 | @end
21 |
22 | @implementation UITableViewCell (AdditionalViews)
23 |
24 | #pragma mark - mem
25 |
26 | _associatedObject(strong, nonatomic, UIView *, internalLeftView, setInternalLeftView)
27 | _associatedObject(strong, nonatomic, NSValue *, internalLeftViewFrame, setInternalLeftViewFrame)
28 |
29 | _associatedObject(strong, nonatomic, UIView *, internalRightView, setInternalRightView)
30 | _associatedObject(strong, nonatomic, NSValue *, internalRightViewFrame, setInternalRightViewFrame)
31 |
32 | #pragma mark - custom accessors
33 |
34 | -(void)setLeftView:(UIView *)leftView {
35 | if (self.internalLeftView != leftView) {
36 | //remove old one
37 | [self.internalLeftView removeFromSuperview];
38 |
39 | //remeber it
40 | self.internalLeftView = leftView;
41 |
42 | //show new one
43 | [self.contentView addSubview:leftView];
44 |
45 | //configure it
46 | [self _layoutLeftView];
47 | }
48 | }
49 |
50 | -(UIView *)leftView {
51 | return self.internalLeftView;
52 | }
53 |
54 | -(void)setLeftViewFrame:(CGRect)leftViewFrame {
55 | self.internalLeftViewFrame = [NSValue valueWithCGRect:leftViewFrame];
56 |
57 | [self _layoutLeftView];
58 | }
59 |
60 | -(CGRect)leftViewFrame {
61 | return [self.internalLeftViewFrame CGRectValue];
62 | }
63 |
64 | -(void)setRightView:(UIView *)rightView {
65 | if (self.internalRightView != rightView) {
66 | //remove old one
67 | [self.internalRightView removeFromSuperview];
68 |
69 | //remeber it
70 | self.internalRightView = rightView;
71 |
72 | //show new one
73 | [self.contentView addSubview:rightView];
74 |
75 | //configure it
76 | [self _layoutRightView];
77 | }
78 | }
79 |
80 | -(UIView *)rightView {
81 | return self.internalRightView;
82 | }
83 |
84 | -(void)setRightViewFrame:(CGRect)rightViewFrame {
85 | self.internalRightViewFrame = [NSValue valueWithCGRect:rightViewFrame];
86 |
87 | [self _layoutRightView];
88 | }
89 |
90 | -(CGRect)rightViewFrame {
91 | return [self.internalRightViewFrame CGRectValue];
92 | }
93 |
94 | #pragma mark - util
95 |
96 | -(void)_layoutLeftView {
97 | self.internalLeftView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin;
98 | self.internalLeftView.frame = self.leftViewFrame;
99 | }
100 |
101 | -(void)_layoutRightView {
102 | self.internalRightView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin;
103 | self.internalRightView.frame = self.rightViewFrame;
104 | }
105 |
106 | @end
107 |
--------------------------------------------------------------------------------
/GBToolbox/UIViewController+GBToolbox.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIViewController+GBToolbox.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "UIViewController+GBToolbox.h"
10 |
11 | #import "GBUtility_Common.h"
12 | #import "UINavigationBar+GBToolbox.h"
13 | #import
14 |
15 | @implementation UIViewController (GBToolbox)
16 |
17 | static char gbIsVisibleKey;
18 | static char gbIsVisibleCurrentlyKey;
19 |
20 | #pragma mark - CA
21 |
22 | - (void)setIsVisible:(BOOL)isVisible {
23 | objc_setAssociatedObject(self, &gbIsVisibleKey, @(isVisible), OBJC_ASSOCIATION_COPY);
24 | }
25 |
26 | - (BOOL)isVisible {
27 | return [objc_getAssociatedObject(self, &gbIsVisibleKey) boolValue];
28 | }
29 |
30 | - (void)setIsVisibleCurrently:(BOOL)isVisibleCurrently {
31 | objc_setAssociatedObject(self, &gbIsVisibleCurrentlyKey, @(isVisibleCurrently), OBJC_ASSOCIATION_COPY);
32 | }
33 |
34 | - (BOOL)isVisibleCurrently {
35 | return [objc_getAssociatedObject(self, &gbIsVisibleCurrentlyKey) boolValue];
36 | }
37 |
38 | #pragma mark - Overrides
39 |
40 | + (void)load {
41 | SwizzleInstanceMethodsInClass(self, @selector(viewWillAppear:), @selector(_swizz_viewWillAppear:));
42 | SwizzleInstanceMethodsInClass(self, @selector(viewWillDisappear:), @selector(_swizz_viewWillDisappear:));
43 | SwizzleInstanceMethodsInClass(self, @selector(viewDidDisappear:), @selector(_swizz_viewDidDisappear:));
44 | }
45 |
46 | - (void)_swizz_viewWillAppear:(BOOL)animated {
47 | self.isVisible = YES;
48 | self.isVisibleCurrently = YES;
49 |
50 | [self _swizz_viewWillAppear:animated];
51 | }
52 |
53 | - (void)_swizz_viewWillDisappear:(BOOL)animated {
54 | self.isVisibleCurrently = NO;
55 |
56 | [self _swizz_viewWillDisappear:animated];
57 | }
58 |
59 | - (void)_swizz_viewDidDisappear:(BOOL)animated {
60 | self.isVisible = NO;
61 |
62 | [self _swizz_viewDidDisappear:animated];
63 | }
64 |
65 | #pragma mark - Extensions
66 |
67 | - (void)ensureViewIsLoaded {
68 | [self view];//this causes the view to get loaded
69 | }
70 |
71 | - (UIStatusBarStyle)inheritedPreferredStatusBarStyle {
72 | UIViewController *targetViewController = self.presentingViewController;
73 | if (!targetViewController) {
74 | return UIStatusBarStyleLightContent;
75 | }
76 |
77 | // walk all the way up the presenting chain
78 | while (targetViewController.parentViewController) {
79 | targetViewController = targetViewController.parentViewController;
80 | }
81 |
82 | // walk all the way down the status bar style chain
83 | while (targetViewController.childViewControllerForStatusBarStyle) {
84 | targetViewController = targetViewController.childViewControllerForStatusBarStyle;
85 | }
86 |
87 | return [targetViewController preferredStatusBarStyle];
88 | }
89 |
90 | - (void)styleNavigationBarWithColor:(nullable UIColor *)color {
91 | [self.navigationController.navigationBar styleWithColor:color];
92 | }
93 |
94 | - (void)hideBackButtonTitle {
95 | self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:self.navigationItem.backBarButtonItem.style target:nil action:nil];
96 | }
97 |
98 | - (UIViewController *)presentingViewControllerAcrossParents {
99 | // parent view controller
100 | if (self.parentViewController) {
101 | // -> recurse out at the parent;s level
102 | return self.tabBarController.presentingViewControllerAcrossParents;
103 | }
104 | // base case
105 | else {
106 | return self.presentingViewController;
107 | }
108 | }
109 |
110 | @end
111 |
--------------------------------------------------------------------------------
/GBToolbox/GBFastArray.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBFastArray.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 01/05/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "GBConstants_Common.h"
12 |
13 | typedef enum {
14 | GBSearchResultMatch,
15 | GBSearchResultLow,
16 | GBSearchResultHigh,
17 | } GBSearchResult;
18 |
19 | //lambda for guiding binary search algo. there's no param for target item, but no need cuz it will get closed over from your calling context
20 | typedef GBSearchResult(^SearchLambda)(void *candidateItem);
21 |
22 | @interface GBFastArray : NSObject
23 |
24 | @property (assign, nonatomic, readonly) NSUInteger count;
25 | @property (assign, nonatomic, readonly) BOOL isEmpty;
26 |
27 | /**
28 | Initializes the array with for a specific typesize.
29 |
30 | Example: [[GBFastArray alloc] initWithTypeSize:sizeof(MyStruct)];
31 | */
32 | - (instancetype)initWithTypeSize:(NSUInteger)typeSize;
33 |
34 | /**
35 | Initializes the array with for a specific typesize.
36 |
37 | Initial capacity is the amount of contiguous memory allocated for the array, and the resizingFactor is the factor used for resizing the array, the new capacity will be oldCapacity * resizingFactor. Tune these values to find the right balance between minimizing the count of resizing operations (which are slow), whilst not overallocating memory (which is wasteful).
38 |
39 | Example: [[GBFastArray alloc] initWithTypeSize:sizeof(MyStruct)];
40 | */
41 | - (instancetype)initWithTypeSize:(NSUInteger)typeSize initialCapacity:(NSUInteger)initialCapacity resizingFactor:(CGFloat)resizingFactor;
42 |
43 | /**
44 | Inserts an item into the array.
45 |
46 | The item is dereferenced and copied using memcpy.
47 | The array will resize itself in order to accomodate the new index. If you choose a large index, beware that memory will be allocated for all the intermediary items, that is GBFastArray is not a sparse array.
48 |
49 | Example: [myFastArray insertItem:&myItem atIndex:10];
50 | */
51 | - (void)insertItem:(void *)itemAddress atIndex:(NSUInteger)index;
52 |
53 | /**
54 | Appends an item to the end of the array, increasing the length of the array by 1.
55 |
56 | The item is dereferenced and copied using memcpy.
57 | This method does not reallocate memory for the array unless it has to.
58 | */
59 | - (void)appendItem:(void *)itemAddress;
60 |
61 | /**
62 | Returns a pointer to the item at the specific index. This is the actual item stored, and is not a copy, so beware that when dereferencing and changing, that these changes will persist.
63 |
64 | Example: MyStruct myItem = *(MyStruct *)[myFastArray itemAtIndex:10];
65 | */
66 | - (void *)itemAtIndex:(NSUInteger)index;
67 |
68 | /**
69 | Do a binary search through the array using the searchLambda predicate block
70 | */
71 | - (NSUInteger)binarySearchForIndexWithSearchLambda:(SearchLambda)searchLambda;
72 |
73 | /**
74 | Do a binary search through the array using the searchLambda predicate block. You can specify subarray in which to search using the lowIndex and highIndex.
75 | */
76 | - (NSUInteger)binarySearchForIndexWithLow:(NSUInteger)lowIndex high:(NSUInteger)highIndex searchLambda:(SearchLambda)searchLambda;
77 |
78 | /**
79 | Return the size in bytes of the type that is being stored in the array.
80 | */
81 | - (NSUInteger)typeSize;
82 |
83 | /**
84 | Return the length of the array.
85 | */
86 | - (NSUInteger)currentAllocationSize;
87 |
88 | /**
89 | Reallocate the array to a specific size. You don't need to call this methid as the array will resize itself, however if you know ahead of time that the array will have to resize itself multiple times in order to fulfill some set of operations, you can optimize this down to a single resizing by preemtively calling this method before you start your set of operations which will insert items into the array.
90 | */
91 | - (void)reallocToSize:(NSUInteger)newSize;
92 |
93 | /**
94 | You can adjust the resizingFactor here at any time.
95 | */
96 | - (void)setResizingFactor:(CGFloat)resizingFactor;
97 |
98 | @end
99 |
--------------------------------------------------------------------------------
/GBToolbox/GBMacros_iOS.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBMacros_iOS.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #ifndef GBToolbox_GBMacros_iOS_h
10 | #define GBToolbox_GBMacros_iOS_h
11 |
12 | #import
13 |
14 | //Universal app device detection
15 | #define _d ((UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone) ? Phone : Pad)
16 |
17 | //View controller instantiation
18 | #define __sb(ARGC, ARGS...) sb_ ## ARGC (ARGS)
19 | #define _sb(ARGC, ARGS...) __sb(ARGC, ARGS)
20 | #define sb(...) _sb(NARGS(__VA_ARGS__), __VA_ARGS__)
21 | #define sb_0(...) (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone) ? @"StoryboardPhone" : @"StoryboardPad"
22 | #define sb_1(ARG, ...) (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone) ? ARG @"Phone" : ARG @"Pad"
23 |
24 | #define vc(storyboardID) [[UIStoryboard storyboardWithName:sb() bundle:nil] instantiateViewControllerWithIdentifier:storyboardID]
25 | #define vcsb(storyboardID, storyboardName) [[UIStoryboard storyboardWithName:sb(storyboardName) bundle:nil] instantiateViewControllerWithIdentifier:storyboardID]
26 |
27 | //View instantiation and controller hookup
28 | #define vSelfLink(nibName) [[NSBundle.mainBundle loadNibNamed:nibName owner:self options:nil] objectAtIndex:0]
29 | #define v(nibName) [[NSBundle.mainBundle loadNibNamed:nibName owner:nil options:nil] objectAtIndex:0]
30 |
31 | //View loading from nib
32 | #define _loadFromNib(nibName) -(id)awakeAfterUsingCoder:(NSCoder *)aDecoder { \
33 | BOOL needsLoading = (self.subviews.count == 0); \
34 | if (needsLoading) { \
35 | UIView *nibView = [[NSBundle.mainBundle loadNibNamed:nibName owner:nil options:nil] objectAtIndex:0]; \
36 | \
37 | nibView.frame = self.frame; \
38 | nibView.autoresizingMask = self.autoresizingMask; \
39 | nibView.alpha = self.alpha; \
40 | nibView.opaque = self.opaque; \
41 | nibView.hidden = self.hidden; \
42 | nibView.backgroundColor = self.backgroundColor; \
43 | nibView.userInteractionEnabled = self.userInteractionEnabled; \
44 | nibView.contentMode = self.contentMode; \
45 | nibView.clearsContextBeforeDrawing = self.clearsContextBeforeDrawing; \
46 | nibView.clipsToBounds = self.clipsToBounds; \
47 | nibView.autoresizesSubviews = self.autoresizesSubviews; \
48 | nibView.multipleTouchEnabled = self.multipleTouchEnabled; \
49 | nibView.tag = self.tag; \
50 | \
51 | return nibView; \
52 | } \
53 | \
54 | return self; \
55 | }
56 |
57 | //Rotation
58 | #define _o (UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation]) ? Portrait : Landscape)
59 |
60 | //Debugging
61 | static inline void _lEdgeInsets(UIEdgeInsets edgeInsets) {NSLog(@"EdgeInsets: %f %f %f %f", edgeInsets.top, edgeInsets.left, edgeInsets.bottom, edgeInsets.right);}
62 | #ifdef DEBUG
63 | #define EnableAutolayoutDebugHotkeyWithCrash(shouldCrashIfAmbiguous) -(void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event { AutoLayoutDebugOn(shouldCrashIfAmbiguous); }
64 | #else
65 | #define EnableAutolayoutDebugHotkeyWithCrash(shouldCrashIfAmbiguous) /* noop */
66 | #endif
67 |
68 | //Animation
69 | static inline UIViewAnimationOptions UIAnimationOptionsWithCurve(UIViewAnimationCurve curve) {
70 | switch (curve) {
71 | case UIViewAnimationCurveEaseInOut: {
72 | return UIViewAnimationOptionCurveEaseInOut;
73 | } break;
74 |
75 | case UIViewAnimationCurveEaseIn: {
76 | return UIViewAnimationOptionCurveEaseIn;
77 | } break;
78 |
79 | case UIViewAnimationCurveEaseOut: {
80 | return UIViewAnimationOptionCurveEaseOut;
81 | } break;
82 |
83 | case UIViewAnimationCurveLinear: {
84 | return UIViewAnimationOptionCurveLinear;
85 | } break;
86 | }
87 | }
88 |
89 | //Views
90 | static inline id AutoLayout(UIView *view) {
91 | [view setTranslatesAutoresizingMaskIntoConstraints:NO];
92 | return view;
93 | }
94 |
95 | #endif
96 |
--------------------------------------------------------------------------------
/GBToolbox/NSString+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSString+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSString (GBToolbox)
12 |
13 | #define GBStringUtilsLocalDNSSuffixes @{@"local", @"lan", @"group"}
14 |
15 | /**
16 | Checks if string is an integer.
17 | */
18 | - (BOOL)isInteger;
19 |
20 | /**
21 | Checks if the receiver contains a substring.
22 |
23 | This check is case sensitive.
24 | */
25 | - (BOOL)containsSubstring:(nullable NSString *)substring;
26 |
27 | /**
28 | Checks if the receiver contains a substring.
29 | */
30 | - (BOOL)containsSubstring:(nullable NSString *)substring caseSensitive:(BOOL)isCaseSensitive;
31 |
32 | /**
33 | Returns YES if the receiver equals any of the strings in the strings array.
34 | */
35 | - (BOOL)isEqualToOneOf:(nonnull NSArray *)strings;
36 |
37 | /**
38 | Returns a new string with the DNS suffix removed from the receiver.
39 |
40 | Requires 10.7+
41 | */
42 | - (nonnull NSString *)stringByDeletingDNSSuffix;
43 |
44 | /**
45 | Checks to see if the receiver looks like an IPv4 IP address.
46 |
47 | Requires 10.7+
48 | */
49 | - (BOOL)isIP;
50 |
51 | /**
52 | Attempt to get int out of string.
53 | */
54 | - (int)attemptConversionToInt;
55 |
56 | /**
57 | Attempt to get float out of a string.
58 | */
59 | - (float)attemptConversionToFloat;
60 |
61 | /**
62 | Attempt to get double out of a string.
63 | */
64 | - (double)attemptConversionToDouble;
65 |
66 | /**
67 | Return a new string with the leading and trailing whitespace trimmed.
68 | */
69 | -(nonnull NSString *)stringByTrimmingLeadingAndTrailingWhitespace;
70 |
71 | /**
72 | Return a new string with the leading and trailing whitespace trimmed, and multiple whitespaces coalesced into a single space.
73 | */
74 | - (nonnull NSString *)stringByCleaningWhitespace;
75 |
76 | /**
77 | Returns a string with all the characters in the set removed from receiver.
78 | */
79 | - (nonnull NSString *)stringByRemovingCharactersInSet:(nonnull NSCharacterSet *)characterSet;
80 |
81 | /**
82 | Returns a string consisting only of the characters in the characterSet.
83 | */
84 | - (nonnull NSString *)stringByRemovingCharactersNotInSet:(nonnull NSCharacterSet *)characterSet;
85 |
86 | /**
87 | Converts "Mirosevic" -> "M." and "sloppy" -> "S."
88 | */
89 | - (nonnull NSString *)stringByAbbreviating;
90 |
91 | /**
92 | Converts "Luka Mirosevic" -> "Luka M." and "Vincent Van Gogh" -> "Vincent V. G."
93 | */
94 | - (nonnull NSString *)abbreviatedName;
95 |
96 | /**
97 | Return a string with the trailing slash removed from the receiver if there was one.
98 | */
99 | - (nonnull NSString *)stringByRemovingTrailingSlash;
100 |
101 | /**
102 | Returns a new string with the prefix from the receiver removed if found, otherwise returns the receiver.
103 | */
104 | - (nonnull NSString *)stringByRemovingPrefix:(nonnull NSString *)prefix;
105 |
106 | /**
107 | Removes a new string with the suffix from the receiver removed if found, otherwise returns the receiver.
108 | */
109 | - (nonnull NSString *)stringByRemovingSuffix:(nonnull NSString *)suffix;
110 |
111 | /**
112 | Returns an attributed string initialized with self, with the attributes from `attributes`.
113 | */
114 | - (nonnull NSAttributedString *)attributedStringWithAttributes:(nullable NSDictionary *)attributes;
115 |
116 | /**
117 | Returns a copy of the receiver sanitized by removing all characters which could be unsafe inside a filename. Not just for OS X but across other systems as well.
118 | */
119 | - (nonnull NSString *)filenameSanitizedString;
120 |
121 | //Hashes
122 | @property (nonatomic, readonly, nonnull) NSString *md5;
123 | @property (nonatomic, readonly, nonnull) NSString *sha1;
124 | @property (nonatomic, readonly, nonnull) NSString *sha224;
125 | @property (nonatomic, readonly, nonnull) NSString *sha256;
126 | @property (nonatomic, readonly, nonnull) NSString *sha384;
127 | @property (nonatomic, readonly, nonnull) NSString *sha512;
128 |
129 | @end
130 |
--------------------------------------------------------------------------------
/GBToolbox/GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 28/09/2012.
6 | // Copyright (c) 2012 Luka Mirosevic. All rights reserved.
7 | //
8 | // Licensed under the Apache License, Version 2.0 (the "License");
9 | // you may not use this file except in compliance with the License.
10 | // You may obtain a copy of the License at
11 | //
12 | // http://www.apache.org/licenses/LICENSE-2.0
13 | //
14 | // Unless required by applicable law or agreed to in writing, software
15 | // distributed under the License is distributed on an "AS IS" BASIS,
16 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | // See the License for the specific language governing permissions and
18 | // limitations under the License.
19 |
20 |
21 | /* Common imports */
22 |
23 | #import "GBTypes_Common.h"
24 |
25 | #import "GBConstants_Common.h"
26 |
27 | #import "GBMacros_Common.h"
28 | #import "GBUtility_Common.h"
29 |
30 | #import "GBFastArray.h"
31 | #import "GBMessageInterceptor.h"
32 | #import "GBCompletable.h"
33 | #import "GBCache.h"
34 | #import "GBEnumWrapper.h"
35 | #import "GBAddress.h"
36 | #import "GBRemoteDebugMessages.h"
37 | #import "GBCAAnimationDelegateHandler.h"
38 | #import "GBAsyncOperation.h"
39 | #import "GBHighPrecisionTimer.h"
40 |
41 | #import "NSObject+GBToolbox.h"
42 | #import "NSTimer+GBToolbox.h"
43 | #import "NSData+GBToolbox.h"
44 | #import "NSString+GBToolbox.h"
45 | #import "CALayer+GBToolbox.h"
46 | #import "NSArray+GBToolbox.h"
47 | #import "NSMutableArray+GBToolbox.h"
48 | #import "NSDictionary+GBToolbox.h"
49 | #import "NSMutableDictionary+GBToolbox.h"
50 | #import "NSMutableURLRequest+GBToolbox.h"
51 | #import "NSDate+GBToolbox.h"
52 | #import "NSInvocation+GBToolbox.h"
53 | #import "NSMapTable+GBToolbox.h"
54 | #import "NSSet+GBToolbox.h"
55 | #import "NSOrderedSet+GBToolbox.h"
56 |
57 | #import "GBFrameChangedProtocol.h"
58 | #import "GBDebuggableInstanceVendor.h"
59 |
60 |
61 | /* iOS imports */
62 |
63 | #if TARGET_OS_IPHONE
64 |
65 | #import "GBTypes_iOS.h"
66 |
67 | #import "GBMacros_iOS.h"
68 | #import "GBUtility_iOS.h"
69 |
70 | #import "GBCustomNavigationBar.h"
71 | #import "GBTextField.h"
72 | #import "GBTextView.h"
73 | #import "GBButton.h"
74 | #import "GBToggleControl.h"
75 | #import "GBToggleControlRadioGroupManager.h"
76 | #import "GBAlertBadgeView.h"
77 | #import "GBRoundBadgeView.h"
78 | #import "GBColoredBarView.h"
79 | #import "GBTextBox.h"
80 | #import "GBTestView.h"
81 | #import "GBTableViewController.h"
82 | #import "GBGradientView.h"
83 | #import "GBControlAggregator.h"
84 | #import "GBMultiStateButton.h"
85 | #import "GBAlertBadge.h"
86 | #import "GBKeyboardListener.h"
87 |
88 | #import "UITableView+GBToolbox.h"
89 | #import "UIViewController+GBToolbox.h"
90 | #import "UIView+GBToolbox.h"
91 | #import "UIImage+GBToolbox.h"
92 | #import "UIScrollView+GBToolbox.h"
93 | #import "UIImageView+GBToolbox.h"
94 | #import "MKMapView+GBToolbox.h"
95 | #import "UIColor+GBToolbox.h"
96 | #import "UIControl+GBToolbox.h"
97 | #import "UIScreen+GBToolbox.h"
98 | #import "UISearchBar+GBToolbox.h"
99 |
100 | #import "UITableViewCell+AdditionalViews.h"
101 | #import "UIView+GBPopUp.h"
102 | #import "UIView+GBFloatingPopoverView.h"
103 | #import "UIView+GBOwningViewController.h"
104 | #import "UINavigationBar+GBToolbox.h"
105 |
106 | #endif
107 |
108 |
109 | /* OS X imports */
110 |
111 | #if !TARGET_OS_IPHONE
112 |
113 | #import "GBTypes_OSX.h"
114 |
115 | #import "GBMacros_OSX.h"
116 | #import "GBUtility_OSX.h"
117 |
118 | #import "GBResizableImageView.h"
119 | #import "GBRadialGradientView.h"
120 | #import "GBCustomViewButtonCell.h"
121 | #import "GBCustomImageButtonCell.h"
122 | #import "GBGlowingImageButtonCell.h"
123 | #import "GBSolidColorView.h"
124 |
125 | #import "NSImage+GBToolbox.h"
126 | #import "NSView+GBToolbox.h"
127 |
128 | #endif
129 |
130 |
131 | /* Notes */
132 |
133 |
134 | //distill the press and hold guy from GBPingInitiatorViewController, look at the following methods:
135 | //
136 | //-(void)touchUp:(id)sender tapHandler:(void(^)(void))tapHandler;
137 | //-(void)touchDown:(id)sender pressAndHoldHandler:(void(^)(void))pressAndHoldHandler;
138 |
--------------------------------------------------------------------------------
/GBToolbox/GBToggleControlRadioGroupManager.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBToggleControlRadioGroupManager.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 08/07/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBToggleControlRadioGroupManager.h"
10 |
11 | #import "GBToggleControl.h"
12 |
13 | @implementation GBToggleControlRadioGroupManager
14 |
15 | #pragma mark - ca
16 |
17 | -(void)dealloc {
18 | //must do this to remove old targets
19 | self.toggleControls = nil;
20 | }
21 |
22 | -(void)setToggleControls:(NSArray *)toggleControls {
23 | //if they're not all toggle controls, then throw exception
24 | for (id object in toggleControls) {
25 | if (![object isKindOfClass:GBToggleControl.class]) {
26 | @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Must pass in an array of GBToggleControls" userInfo:nil];
27 | }
28 | }
29 |
30 | //make sure to remove self as target from old controls
31 | for (GBToggleControl *toggle in _toggleControls) {
32 | [toggle removeTarget:self action:@selector(toggleAction:) forControlEvents:UIControlEventValueChanged];
33 | }
34 |
35 | //add self as target for new controls
36 | for (GBToggleControl *toggle in toggleControls) {
37 | [toggle addTarget:self action:@selector(toggleAction:) forControlEvents:UIControlEventValueChanged];
38 | }
39 |
40 | _toggleControls = toggleControls;
41 | }
42 |
43 | -(void)setSelectedControl:(GBToggleControl *)selectedControl {
44 | [self _selectControl:selectedControl];
45 | }
46 |
47 | -(void)setSelectedControlIndex:(NSInteger)selectedControlIndex {
48 | [self _selectControlWithIndex:selectedControlIndex];
49 | }
50 |
51 | #pragma mark - API
52 |
53 | -(void)deselectAllControls {
54 | [self _resetState];
55 | }
56 |
57 | #pragma mark - util
58 |
59 | -(void)_resetState {
60 | for (GBToggleControl *toggle in self.toggleControls) {
61 | toggle.isOn = NO;
62 | }
63 |
64 | _selectedControlIndex = -1;
65 | _selectedControl = nil;
66 |
67 | //tell delegate
68 | if ([self.delegate respondsToSelector:@selector(toggleControlRadioGroupManagerDidResetSelection:)]) {
69 | [self.delegate toggleControlRadioGroupManagerDidResetSelection:self];
70 | }
71 | }
72 |
73 | -(void)_selectControl:(GBToggleControl *)control {
74 | //find the index
75 | NSUInteger index = [self.toggleControls indexOfObject:control];
76 | [self _selectControlWithIndex:index];
77 | }
78 |
79 | -(void)_selectControlWithIndex:(NSUInteger)index {
80 | if (index == NSNotFound) {
81 | NSLog(@"Warning: trying to select control which has not been added to the GBRadioToggleControlsManager");
82 | }
83 | else if (index >= self.toggleControls.count) {
84 | NSLog(@"Warning: trying to select control whose index is out of bounds of the controls added to the GBRadioToggleControlsManager");
85 | }
86 | else {
87 | //select my control and deselect all the other ones
88 | for (NSUInteger i=0; i
13 | #import
14 |
15 | #pragma mark - General
16 |
17 | typedef void(^VoidBlock)(void);
18 | typedef BOOL(^BoolBlock)(void);
19 | typedef void(^VoidBlockObject)(id object);
20 | typedef void(^VoidBlockDictionary)(NSDictionary *dictionary);
21 | typedef void(^VoidBlockBool)(BOOL isTrue);
22 |
23 | #pragma mark - Range
24 |
25 | typedef struct {
26 | CGFloat min;
27 | CGFloat max;
28 | } GBRange;
29 |
30 | #pragma mark - Linear algebra
31 |
32 | typedef struct {
33 | CGFloat x;
34 | CGFloat y;
35 | } GBVector2D;
36 |
37 | #pragma mark - UI
38 |
39 | typedef struct {
40 | NSUInteger rows;
41 | NSUInteger columns;
42 | } GBMatrixGrid;
43 |
44 | typedef struct {
45 | CGFloat top;
46 | CGFloat left;
47 | CGFloat bottom;
48 | CGFloat right;
49 | } GBEdgeInsets;
50 |
51 | #pragma mark - GBBoolean
52 |
53 | typedef enum {
54 | BUndefined,
55 | BYES,
56 | BNO,
57 | } GBBoolean;
58 |
59 | static inline GBBoolean GBBooleanToggle(GBBoolean boolean) {
60 | switch (boolean) {
61 | case BYES: return BNO;
62 | case BNO: return BYES;
63 | case BUndefined: return BUndefined;
64 | }
65 | }
66 |
67 | static inline GBBoolean Bool2GBBoolean(BOOL boolean) {
68 | if (boolean) {
69 | return BYES;
70 | }
71 | else {
72 | return BNO;
73 | }
74 | }
75 |
76 | static inline BOOL IsTruthyGBBoolean(GBBoolean boolean) {
77 | return boolean == BYES;
78 | }
79 |
80 |
81 | static inline GBBoolean GBBooleanNot(GBBoolean boolean) {
82 | switch (boolean) {
83 | case BYES:
84 | return BNO;
85 |
86 | case BNO:
87 | case BUndefined:
88 | return BYES;
89 | }
90 | }
91 |
92 | static inline GBBoolean GBBooleanAnd(GBBoolean booleanA, GBBoolean booleanB) {
93 | return Bool2GBBoolean(IsTruthyGBBoolean(booleanA) && IsTruthyGBBoolean(booleanB));
94 | }
95 |
96 | static inline GBBoolean GBBooleanOr(GBBoolean booleanA, GBBoolean booleanB) {
97 | return Bool2GBBoolean(IsTruthyGBBoolean(booleanA) || IsTruthyGBBoolean(booleanB));
98 | }
99 |
100 | static inline GBBoolean Number2GBBoolean(NSNumber *number) {
101 | if ([number isKindOfClass:[NSNumber class]]) {
102 | if ([number boolValue] == YES) {
103 | return BYES;
104 | }
105 | else if ([number boolValue] == NO) {
106 | return BNO;
107 | }
108 | }
109 |
110 | return BUndefined;
111 | }
112 |
113 | static inline NSNumber * GBBoolean2Number(GBBoolean boolean) {
114 | switch (boolean) {
115 | case BYES:
116 | return @(YES);
117 |
118 | case BNO:
119 | return @(NO);
120 |
121 | case BUndefined:
122 | return nil;
123 | }
124 | }
125 |
126 | #pragma mark - Special keys
127 |
128 | typedef enum {
129 | GBSpecialKeyReturn = 1,
130 | GBSpecialKeyBackspace = 2,
131 | GBSpecialKeyF1 = 3,
132 | GBSpecialKeyF2 = 4,
133 | GBSpecialKeyF3 = 5,
134 | GBSpecialKeyF4 = 6,
135 | GBSpecialKeyF5 = 7,
136 | GBSpecialKeyF6 = 8,
137 | GBSpecialKeyF7 = 9,
138 | GBSpecialKeyF8 = 10,
139 | GBSpecialKeyF9 = 11,
140 | GBSpecialKeyF10 = 12,
141 | GBSpecialKeyF11 = 13,
142 | GBSpecialKeyF12 = 14,
143 | GBSpecialKeyEsc = 15,
144 | GBSpecialKeyCmdDown = 16,
145 | GBSpecialKeyCtrlDown = 17,
146 | GBSpecialKeyAltDown = 18,
147 | GBSpecialKeyHome = 19,
148 | GBSpecialKeyPageUp = 20,
149 | GBSpecialKeyEnd = 21,
150 | GBSpecialKeyPageDown = 22,
151 | GBSpecialKeyUp = 23,
152 | GBSpecialKeyLeft = 24,
153 | GBSpecialKeyDown = 25,
154 | GBSpecialKeyRight = 26,
155 | GBSpecialKeyCtrlUp = 27,
156 | GBSpecialKeyAltUp = 28,
157 | GBSpecialKeyCmdUp = 29,
158 | } GBSpecialKey;
159 |
160 | #endif
161 |
--------------------------------------------------------------------------------
/GBToolbox/GBKeyboardListener.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBKeyboardListener.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 22/05/2017.
6 | // Copyright © 2017 Goonbee e.U. All rights reserved.
7 | //
8 |
9 | #import "GBKeyboardListener.h"
10 |
11 | #import "NSMapTable+GBToolbox.h"
12 |
13 | @interface GBKeyboardListener ()
14 |
15 | @property (assign, nonatomic, readwrite, getter=isVisible) BOOL visible;
16 | @property (assign, nonatomic, readwrite) CGRect keyboardFrame;
17 |
18 | @property (strong, nonatomic) NSMapTable *> *contexts;
19 |
20 | @end
21 |
22 | @implementation GBKeyboardListener
23 |
24 | #pragma mark - Life and Setup
25 |
26 | + (void)load {
27 | @autoreleasepool {
28 | [self sharedListener];
29 | }
30 | }
31 |
32 | - (id)init {
33 | if (self = [super init]) {
34 | _contexts = [NSMapTable weakToStrongObjectsMapTable];
35 |
36 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_willShowNotification:) name:UIKeyboardWillShowNotification object:nil];
37 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_willHideNotification:) name:UIKeyboardWillHideNotification object:nil];
38 | }
39 |
40 | return self;
41 | }
42 |
43 | + (GBKeyboardListener *)sharedListener {
44 | static GBKeyboardListener *_sharedListener;
45 | static dispatch_once_t onceToken;
46 | dispatch_once(&onceToken, ^{
47 | _sharedListener = [[GBKeyboardListener alloc] init];
48 | });
49 |
50 | return _sharedListener;
51 | }
52 |
53 | - (void)dealloc {
54 | [[NSNotificationCenter defaultCenter] removeObserver:self];
55 | }
56 |
57 | #pragma mark - Notifications
58 |
59 | - (void)_willShowNotification:(NSNotification *)notification {
60 | NSTimeInterval duration = ((NSNumber *)notification.userInfo[UIKeyboardAnimationDurationUserInfoKey]).doubleValue;
61 | UIViewAnimationOptions curve = ((NSNumber *)notification.userInfo[UIKeyboardAnimationCurveUserInfoKey]).integerValue;
62 | CGRect endFrame = ((NSValue *)notification.userInfo[UIKeyboardFrameEndUserInfoKey]).CGRectValue;
63 | CGRect beginFrame = ((NSValue *)notification.userInfo[UIKeyboardFrameBeginUserInfoKey]).CGRectValue;
64 |
65 | self.visible = YES;
66 | self.keyboardFrame = endFrame;
67 |
68 | [self _fireListenersWithShown:YES beginFrame:beginFrame endFrame:endFrame animationDuration:duration animationCurve:curve];
69 | }
70 |
71 | - (void)_willHideNotification:(NSNotification *)notification {
72 | NSTimeInterval duration = ((NSNumber *)notification.userInfo[UIKeyboardAnimationDurationUserInfoKey]).doubleValue;
73 | UIViewAnimationOptions curve = ((NSNumber *)notification.userInfo[UIKeyboardAnimationCurveUserInfoKey]).integerValue;
74 | CGRect endFrame = ((NSValue *)notification.userInfo[UIKeyboardFrameEndUserInfoKey]).CGRectValue;
75 | CGRect beginFrame = ((NSValue *)notification.userInfo[UIKeyboardFrameBeginUserInfoKey]).CGRectValue;
76 |
77 | self.visible = NO;
78 | self.keyboardFrame = endFrame;
79 |
80 | [self _fireListenersWithShown:NO beginFrame:beginFrame endFrame:endFrame animationDuration:duration animationCurve:curve];
81 | }
82 |
83 |
84 | #pragma mark - Private
85 |
86 | - (void)_fireListenersWithShown:(BOOL)shown beginFrame:(CGRect)beginFrame endFrame:(CGRect)endFrame animationDuration:(NSTimeInterval)animationDuration animationCurve:(UIViewAnimationOptions)animationCurve {
87 | for (id context in self.contexts) {
88 | for (GBKeyboardWillMoveBlock listener in self.contexts[context]) {
89 | listener(shown, beginFrame, endFrame, animationDuration, animationCurve);
90 | }
91 | }
92 | }
93 |
94 | #pragma mark - API
95 |
96 | - (CGRect)frameInCoordinatesOfView:(UIView *)view {
97 | return [[UIApplication sharedApplication].windows.firstObject convertRect:self.keyboardFrame toView:view];
98 | }
99 |
100 | - (void)addListenerForContext:(id)context block:(GBKeyboardWillMoveBlock)block {
101 | if (!self.contexts[context]) {
102 | self.contexts[context] = [NSMutableArray new];
103 | }
104 |
105 | [self.contexts[context] addObject:block];
106 | }
107 |
108 | - (void)removeListenersForContext:(id)context {
109 | [self.contexts removeObjectForKey:context];
110 | }
111 |
112 | @end
113 |
--------------------------------------------------------------------------------
/GBToolbox/UIView+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 22/05/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @protocol GBViewViewRelatedChangesDelegate;
12 |
13 | @interface UIView (GBToolbox)
14 |
15 | /**
16 | Set this to YES if the background color that you specifed in IB was for design time only and you would like the background to be clearColor when it is unarchived from the NIB. Useful if you want IB to show a different color at design time, such as a placeholder color, but you don't want this visible at runtime.
17 | */
18 | @property (assign, nonatomic) IBInspectable BOOL designTimeOnlyBackgroundColor;
19 |
20 | /**
21 | Removes all subviews.
22 | */
23 | - (void)removeAllSubviews;
24 |
25 | /**
26 | Sets the view's frame to the receiver's bounds and adds it as a subview.
27 | */
28 | - (void)embedView:(UIView *)view;
29 |
30 | /**
31 | Resigns the first responder for any subview of the receiver. Some code from SO: http://stackoverflow.com/a/1823360/399772
32 | */
33 | - (BOOL)findAndResignFirstResponder;
34 |
35 | /**
36 | Returns a view controller whose view has the receiver added as a subview, laid out in Autolayout to have it's view the same size as the receiver (edges are pinned).
37 |
38 | Warning: Always creates a new instance, every time it is called.
39 | */
40 | - (UIViewController *)wrappingViewController;
41 |
42 | /**
43 | Returns a view controller whose view has the receiver added as a subview, laid out in Autolayout to have it's view the same size as the receiver (edges are pinned) taking into account the edge margins.
44 |
45 | Warning: Always creates a new instance, every time it is called.
46 | */
47 | - (UIViewController *)wrappingViewControllerWithMargins:(UIEdgeInsets)margins;
48 |
49 | /**
50 | Returns a view with the receiver added as a subview, laid out in Autolayout to have it's view the same size as the receiver (edges are pinned) taking into account the edge margins.
51 |
52 | Warning: Always creates a new instance, every time it is called.
53 | */
54 | - (UIView *)wrappingViewWithMargins:(UIEdgeInsets)margins;
55 |
56 | /**
57 | Returns the part of the view rendered into an image inside the rect.
58 |
59 | Setting legacy to YES will use the older (more reliable) method of rendering. Always try with legacy:NO first as it is more efficient in iOS7+. If it doesn't work fallback to legacy:YES.
60 | */
61 | - (UIImage *)renderToImageForRect:(CGRect)rect legacy:(BOOL)legacy;
62 |
63 | /**
64 | Adds a fade animation to receiver's layer. A useful case is for animating label content changes.
65 | */
66 | - (void)addCrossFadeAnimationToLayerWithDuration:(NSTimeInterval)duration;
67 |
68 | /**
69 | Setting this to YES disables user interactions on the the receiver, without disabling it for the child views.
70 |
71 | This is in contrast to simply setting userInteractionEnabled to NO, in which case the view will not receive touch input, will however also not forward it to it's children.
72 |
73 | Setting this to YES is useful in cases where one might want to add a container view that has some children, where the container view should not exist for purposes of handling touch input--it should neither receive touch input, not prevent its children from receiving it.
74 |
75 | Defaults to YES.
76 | */
77 | @property (assign, nonatomic) BOOL shouldParticipateInUserInput;
78 |
79 | /**
80 | Sets a mask to this view's layer that clips the corners by cornerRadius.
81 |
82 | You must call this again if your view resizes.
83 | */
84 | - (void)roundCorners:(UIRectCorner)corners withRadius:(CGFloat)cornerRadius;
85 |
86 | /**
87 | The delegate that will be notified of view related changes.
88 | */
89 | @property (weak, nonatomic) id viewRelatedChangesDelegate;
90 |
91 | @end
92 |
93 | /**
94 | Allows getting notified of changes to the view from outside of the view.
95 | */
96 | @protocol GBViewViewRelatedChangesDelegate
97 | @optional
98 |
99 | - (void)view:(UIView *)view didAddSubview:(UIView *)subview;
100 | - (void)view:(UIView *)view willRemoveSubview:(UIView *)subview;
101 | - (void)view:(UIView *)view willMoveToSuperview:(UIView *)superview;
102 | - (void)view:(UIView *)view didMoveToSuperview:(UIView *)superview;
103 | - (void)view:(UIView *)view willMoveToWindow:(UIWindow *)window;
104 | - (void)view:(UIView *)view didMoveToWindow:(UIWindow *)window;
105 |
106 | @end
107 |
--------------------------------------------------------------------------------
/GBToolbox/GBUtility_iOS.h:
--------------------------------------------------------------------------------
1 | //
2 | // GBUtility_iOS.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 05/02/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBTypes_Common.h"
10 | #import "GBTypes_iOS.h"
11 |
12 | #import "GBUtility_Common.h"
13 | #import "UIControl+GBToolbox.h"
14 |
15 | #import
16 | #import
17 | #import
18 | #import
19 |
20 | @class GBAddress;
21 |
22 | @interface GBToolbox (iOS)
23 |
24 | #pragma mark - UIView
25 |
26 | NSUInteger tagFromUIViewSubclass(_Nullable id sender);
27 |
28 | #pragma mark - View Hierarchy
29 |
30 | UIViewController * _Nullable TopmostViewController();
31 | UIViewController * _Nullable TopmostViewControllerWithRootViewController(UIViewController * _Nullable rootViewController);
32 |
33 | #pragma mark - Screen Locking
34 |
35 | +(BOOL)isAutoScreenLockingEnabled;
36 | +(void)enableAutoScreenLocking:(BOOL)enable;
37 |
38 | #pragma mark - Torch
39 |
40 | /**
41 | Enables or disables the device's flash/torch if the device has one
42 | */
43 | void EnableTorch(BOOL enable);
44 |
45 | #pragma mark - App Store redirect
46 |
47 | void RedirectToAppStore(NSString * _Nonnull appID);
48 |
49 | #pragma mark - Images
50 |
51 | UIImage * _Nullable Image(NSString * _Nonnull name);
52 | UIImage * _Nullable ImageResizableWithCapInsets(NSString * _Nonnull name, CGFloat topCap, CGFloat leftCap, CGFloat bottomCap, CGFloat rightCap);
53 |
54 | #pragma mark - Clipping
55 |
56 | CAShapeLayer * _Nonnull RoundClippingMaskInRectWithMargin(CGRect rect, UIEdgeInsets margin);
57 | UIBezierPath * _Nonnull RoundBezierPathForRectWithMargin(CGRect rect, UIEdgeInsets margin);
58 |
59 | #pragma mark - Push Notifications
60 |
61 | BOOL IsPushDisabled();
62 |
63 | #pragma mark - UITableView
64 |
65 | BOOL IsCellAtIndexPathFullyVisible(NSIndexPath * _Nullable indexPath, UITableView * _Nullable tableView);
66 |
67 | #pragma mark - Keyboard hiding
68 |
69 | void DismissKeyboard();
70 |
71 | #pragma mark - Twitter
72 |
73 | BOOL IsTwitterAccountAvailable();
74 |
75 | #pragma mark - Localisation
76 |
77 | NSString * _Nullable UIKitLocalizedString(NSString * _Nullable string);
78 |
79 | #pragma mark - Vibration
80 |
81 | void VibrateDevice();
82 |
83 | #pragma mark - Colors
84 |
85 | //Returns a random color with a bias towards the more saturated and brighter colors
86 | UIColor * _Nonnull RandomColor();
87 |
88 | #pragma mark - Auto Layout
89 |
90 | void AutoLayoutDebugOn(BOOL crashOnTrigger);
91 | NSString * _Nonnull AutoLayoutViewPointer(NSObject * _Nonnull object);
92 | NSDictionary * _Nonnull AutoLayoutPointerViewsDictionaryForViews(NSArray * _Nonnull views);
93 |
94 | #pragma mark - Debugging
95 |
96 | void DebugCode(VoidBlock _Nonnull code);
97 |
98 | UIButton * _Nonnull RegisterDebugButton(NSString * _Nonnull title, GBActionBlock _Nonnull action);
99 |
100 | #pragma mark - Geocoding
101 |
102 | void ReverseGeocodeLocation(CLLocation * _Nullable location, void(^_Nullable block)(GBAddress * _Nullable address));
103 |
104 | #pragma mark - UIViewController containment
105 |
106 | void AddChildViewController(UIViewController * _Nonnull hostViewController, UIViewController * _Nonnull childViewController);
107 | void AddChildViewControllerToView(UIViewController * _Nonnull hostViewController, UIView * _Nonnull hostView, UIViewController * _Nonnull childViewController);
108 | void RemoveChildViewController(UIViewController * _Nonnull childViewController);
109 |
110 | #pragma mark - Actions
111 |
112 | void OpenLinkInSafari(NSString * _Nullable link);
113 | void OpenMap(CLLocation * _Nonnull location, NSString * _Nullable name);
114 | void CallPhone(NSString * _Nonnull number);
115 | void SendSMS(NSString * _Nonnull number);
116 |
117 | #pragma mark - Fonts
118 |
119 | void ListAvailableFonts();
120 |
121 | #pragma mark - Disk utils
122 |
123 | NSString * _Nonnull DocumentsDirectoryPath();
124 | NSURL * _Nonnull DocumentsDirectoryURL();
125 |
126 | #pragma mark - Cookies
127 |
128 | void ClearCookies();
129 |
130 | #pragma mark - Email
131 |
132 | void ShowContactEmailOnViewController(UIViewController * _Nonnull viewController, NSArray * _Nullable toAdresses, NSString * _Nullable subject, NSString * _Nullable body);
133 |
134 | #pragma mark - Alerts
135 |
136 | void ShowAlert(NSString * _Nullable title, NSString * _Nullable message, NSString * _Nullable dismissButtonTitle);
137 |
138 | #pragma mark - Network
139 |
140 | NSString * _Nullable CurrentWifiNetworkName();
141 |
142 | @end
143 |
144 |
--------------------------------------------------------------------------------
/GBToolbox/NSArray+GBToolbox.h:
--------------------------------------------------------------------------------
1 | //
2 | // NSArray+GBToolbox.h
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 20/03/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface NSArray<__covariant ObjectType> (GBToolbox)
12 |
13 | #pragma mark - Helper methods
14 |
15 | /**
16 | Returns a random object from the array, or nil if the array is empty.
17 | */
18 | @property (strong, nonatomic, readonly, nullable) ObjectType randomObject;
19 |
20 | #pragma mark - Functional Programming
21 |
22 | /**
23 | Returns a new array with the elements from the receiver transformed by function.
24 | */
25 | - (nonnull NSArray *)map:(id _Nonnull(^ _Nonnull)(ObjectType _Nonnull object))function;
26 |
27 | /**
28 | Returns a new array with the elements from the receiver transformed by function.
29 | */
30 | - (nonnull NSArray *)mapWithIndex:(id _Nonnull(^ _Nonnull)(ObjectType _Nonnull object, NSUInteger index))function;
31 |
32 | /**
33 | Fold Left.
34 | */
35 | - (nonnull ObjectType)foldLeft:(ObjectType _Nonnull(^ _Nonnull)(ObjectType _Nonnull objectA, ObjectType _Nonnull objectB))function lastObject:(nonnull ObjectType)lastObject;
36 |
37 | /**
38 | Fold Right.
39 | */
40 | - (nonnull ObjectType)foldRight:(ObjectType _Nonnull(^ _Nonnull)(ObjectType _Nonnull objectA, ObjectType _Nonnull objectB))function initialObject:(nonnull ObjectType)initialObject;
41 |
42 | /**
43 | Synonym for foldLeft
44 | */
45 | - (nonnull ObjectType)reduce:(ObjectType _Nonnull(^ _Nonnull)(ObjectType _Nonnull objectA, ObjectType _Nonnull objectB))function lastObject:(nonnull ObjectType)lastObject;
46 |
47 | /**
48 | Returns a copy of the array containing only the objects for which function returns YES.
49 | */
50 | - (nonnull NSArray *)filter:(BOOL(^ _Nonnull)(ObjectType _Nonnull object))function;
51 |
52 | /**
53 | Returns YES if all of the elements in the receiver return true for the function.
54 |
55 | Returns NO for an empty array.
56 | */
57 | - (BOOL)all:(BOOL(^ _Nonnull)(ObjectType _Nonnull object))function;
58 |
59 | /**
60 | Returns YES if at least one of the elements in the receiver return true for the function.
61 |
62 | Returns NO for an empty array.
63 | */
64 | - (BOOL)any:(BOOL(^ _Nonnull)(ObjectType _Nonnull object))function;
65 |
66 | /**
67 | Returns the first object for which the function returns YES, nil otherwise.
68 | */
69 | - (nullable ObjectType)first:(BOOL(^ _Nonnull)(ObjectType _Nonnull object))function;
70 |
71 | /**
72 | Returns the count of objects for which function returns YES.
73 | */
74 | - (NSUInteger)count:(BOOL(^ _Nonnull)(ObjectType _Nonnull object))function;
75 |
76 | /**
77 | Returns the index of the first object that returns YES for the block. If no object returns YES, returns NSNotFound
78 | */
79 | - (NSUInteger)indexOfFirst:(BOOL(^ _Nonnull)(ObjectType _Nonnull object))function;
80 |
81 | /**
82 | Returns YES if any the function returns YES for at least one object in the set.
83 | */
84 | - (BOOL)contains:(BOOL(^ _Nonnull)(ObjectType _Nonnull object))function;
85 |
86 | #pragma mark - Conveniences
87 |
88 | /**
89 | Returns the first object inside the receiver which is equal to the object (compared using isEqual:). Returns nil if no object is equal.
90 | */
91 | - (nullable ObjectType)firstObjectEqualToObject:(id _Nonnull)object;
92 |
93 | /**
94 | Returns YES if the received contains the specific passed in object instance.
95 | */
96 | - (BOOL)containsObjectIdenticalTo:(nonnull id)anObject;
97 |
98 | #pragma mark - Set like operations
99 |
100 | /**
101 | Returns a new array which is a copy of the receiver with all objects removed that are inside `array`
102 | */
103 | - (nonnull NSArray *)arrayBySubtractingArray:(nonnull NSArray *)array;
104 |
105 | #pragma mark - Description
106 |
107 | /**
108 | Returns the array concatenated by ", "
109 | */
110 | @property (copy, nonatomic, nonnull, readonly) NSString *shortStringRepresentation;
111 |
112 | #pragma mark - Sorting
113 |
114 | /**
115 | Returns an array sorted by the properties in the objects.
116 | */
117 | - (nonnull NSArray *)sortedArrayByPropertiesOfObjects:(nonnull NSArray *)properties ascending:(BOOL)ascending;
118 |
119 | /**
120 | Returns an array sorted by the properties in the objects in ascending order.
121 | */
122 | - (nonnull NSArray *)sortedArrayByPropertiesOfObjects:(nonnull NSArray *)properties;
123 |
124 | #pragma mark - Unique
125 |
126 | /**
127 | Returns a copy of the receiver with all duplicates removed.
128 | */
129 | - (nonnull NSArray *)uniquedArray;
130 |
131 | #pragma mark - Convenience
132 |
133 | /**
134 | Returns a set initialized with the contents of the receiver.
135 | */
136 | - (nonnull NSSet *)set;
137 |
138 | /**
139 | Returns an ordered set initialized with the contents of the receiver.
140 | */
141 | - (nonnull NSOrderedSet *)orderedSet;
142 |
143 | #pragma mark - NSAttributedString
144 |
145 | /**
146 | Returns a new NSAttributedString by concatenating all the NSAttributedString's in the receiver.
147 | */
148 | - (nonnull NSAttributedString *)concatenatedArrayOfAttributedStrings;
149 |
150 | @end
151 |
--------------------------------------------------------------------------------
/GBToolbox/GBFastArray.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBFastArray.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 01/05/2013.
6 | // Copyright (c) 2013 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBFastArray.h"
10 |
11 | static CGFloat const kDefaultResizingFactor = 1.5;
12 | static CGFloat const kDefaultInitialCapacity = 100;
13 |
14 | @implementation GBFastArray {
15 | NSUInteger _allocationSize;
16 | NSUInteger _lastElementIndex;
17 | NSUInteger _typeSize;
18 | CGFloat _resizingFactor;
19 | char *_theArray;
20 | }
21 |
22 | #pragma mark - Public API: Init
23 |
24 | - (instancetype)initWithTypeSize:(NSUInteger)typeSize {
25 | return [self initWithTypeSize:typeSize initialCapacity:kDefaultInitialCapacity resizingFactor:kDefaultResizingFactor];
26 | }
27 |
28 | - (instancetype)initWithTypeSize:(NSUInteger)typeSize initialCapacity:(NSUInteger)initialCapacity resizingFactor:(CGFloat)resizingFactor {
29 | if (self = [super init]) {
30 | //State
31 | _typeSize = typeSize;
32 | _allocationSize = initialCapacity;
33 | _lastElementIndex = NSUIntegerMax;
34 | [self setResizingFactor:resizingFactor];
35 |
36 | //Alloc array
37 | _theArray = malloc(_typeSize * _allocationSize);
38 | }
39 |
40 | return self;
41 | }
42 |
43 | - (void)dealloc {
44 | //clean up array
45 | free(_theArray);
46 | }
47 |
48 | #pragma mark - Public API: Properties
49 |
50 | - (NSUInteger)count {
51 | if (_lastElementIndex == NSUIntegerMax) {
52 | return 0;
53 | }
54 | else {
55 | return _lastElementIndex + 1;
56 | }
57 | }
58 |
59 | - (BOOL)isEmpty {
60 | return (_lastElementIndex == NSUIntegerMax);
61 | }
62 |
63 | #pragma mark - Public API: Querying
64 |
65 | - (void)insertItem:(void *)itemAddress atIndex:(NSUInteger)index {
66 | //if its too short, resize the array
67 | if (index >= _allocationSize) {
68 | [self reallocToSize:(_allocationSize * _resizingFactor)];
69 | }
70 |
71 | //if it stretches the lastElementIndex, set it
72 | if (index > _lastElementIndex || _lastElementIndex == NSUIntegerMax) {
73 | _lastElementIndex = index;
74 | }
75 |
76 | //put it in
77 | memcpy(_theArray + (index * _typeSize), itemAddress, _typeSize);
78 | }
79 |
80 | - (void)appendItem:(void *)itemAddress {
81 | [self insertItem:itemAddress atIndex:_lastElementIndex + 1];
82 | }
83 |
84 | - (void *)itemAtIndex:(NSUInteger)index {
85 | return _theArray + (index * _typeSize);
86 | }
87 |
88 | #pragma mark - Public API: Searching
89 |
90 | - (NSUInteger)binarySearchForIndexWithSearchLambda:(SearchLambda)searchLambda {
91 | return [self binarySearchForIndexWithLow:0 high:_lastElementIndex searchLambda:searchLambda];
92 | }
93 |
94 | - (NSUInteger)binarySearchForIndexWithLow:(NSUInteger)lowIndex high:(NSUInteger)highIndex searchLambda:(SearchLambda)searchLambda {
95 | //make sure its well formed
96 | if (searchLambda && lowIndex <= highIndex) {
97 | //prepare
98 | NSUInteger midIndex;
99 | GBSearchResult searchResult;
100 |
101 | //search while the subarray has at least 1 item
102 | while (highIndex >= lowIndex) {
103 | //calculate midpoint (as simple downrounded average)
104 | midIndex = (highIndex+lowIndex)*0.5;
105 |
106 | //eval our search lambda
107 | searchResult = searchLambda([self itemAtIndex:midIndex]);
108 |
109 | switch (searchResult) {
110 | case GBSearchResultMatch: {
111 | return midIndex;
112 | } break;
113 |
114 | case GBSearchResultHigh: {
115 | if (midIndex == 0) return kGBSearchResultNotFound;
116 |
117 | highIndex = midIndex - 1;
118 | } break;
119 |
120 | case GBSearchResultLow: {
121 | if (midIndex == _lastElementIndex) return kGBSearchResultNotFound;
122 |
123 | lowIndex = midIndex + 1;
124 | } break;
125 | }
126 | }
127 | }
128 |
129 | //if we got here it means we didnt find anything, or the params were bad
130 | return kGBSearchResultNotFound;
131 | }
132 |
133 | #pragma mark - Public API: Size management
134 |
135 | - (NSUInteger)typeSize {
136 | return _typeSize;
137 | }
138 |
139 | -( NSUInteger)currentAllocationSize {
140 | return _allocationSize;
141 | }
142 |
143 | - (void)reallocToSize:(NSUInteger)newSize {
144 | _allocationSize = newSize;
145 | _theArray = realloc(_theArray, (newSize * _typeSize));
146 |
147 | if (newSize < self.count) {
148 | _lastElementIndex = newSize - 1;
149 | }
150 | }
151 |
152 | - (void)setResizingFactor:(CGFloat)resizingFactor {
153 | if (resizingFactor > 1.0) {
154 | _resizingFactor = resizingFactor;
155 | }
156 | else {
157 | @throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Resizing factor must be bigger than 1.0" userInfo:@{@"resizingFactor": @(resizingFactor)}];
158 | }
159 | }
160 |
161 | @end
162 |
--------------------------------------------------------------------------------
/GBToolbox/GBRemoteDebugMessages.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBRemoteDebugMessages.m
3 | // GBToolbox
4 | //
5 | // Created by Luka Mirosevic on 08/11/2014.
6 | // Copyright (c) 2014 Luka Mirosevic. All rights reserved.
7 | //
8 |
9 | #import "GBRemoteDebugMessages.h"
10 |
11 | static NSString * const kDefaultServer = @"localhost";
12 | static UInt32 const kDefaultPort = 10000;
13 | static BOOL const kDefaultShouldLogLocallyAsWell = NO;
14 |
15 | @interface GBRemoteDebugMessages ()
16 |
17 | @property (strong, nonatomic) NSMutableString *buffer;
18 | @property (strong, nonatomic) dispatch_queue_t messagesQueue;
19 | @property (strong, nonatomic) NSOutputStream *outputStream;
20 |
21 | @end
22 |
23 | @implementation GBRemoteDebugMessages
24 |
25 | + (instancetype)sharedMessages {
26 | static GBRemoteDebugMessages *sharedMessages;
27 | static dispatch_once_t onceToken;
28 | dispatch_once(&onceToken, ^{
29 | sharedMessages = [self new];
30 | });
31 | return sharedMessages;
32 | }
33 |
34 | - (id)init {
35 | if (self = [super init]) {
36 | self.messagesQueue = dispatch_queue_create("com.goonbee.GBToolbox.GBRemoteDebugMessages.Queue", DISPATCH_QUEUE_SERIAL);
37 | self.shouldLogLocallyAsWell = kDefaultShouldLogLocallyAsWell;
38 | dispatch_async(self.messagesQueue, ^{
39 | self.buffer = [NSMutableString new];
40 | });
41 | }
42 |
43 | return self;
44 | }
45 |
46 | #pragma mark - API
47 |
48 | - (void)sendRemoteDebugMessage:(NSString *)message, ... {
49 | va_list args;
50 | va_start(args, message);
51 | NSString *completeMessage = [[NSString alloc] initWithFormat:message arguments:args];
52 | va_end(args);
53 |
54 | [[GBRemoteDebugMessages sharedMessages] _sendRemoteDebugMessage:completeMessage];
55 | }
56 |
57 | - (void)_sendRemoteDebugMessage:(NSString *)completeMessage {
58 | dispatch_async(self.messagesQueue, ^{
59 | if (self.shouldLogLocallyAsWell) NSLog(@"%@", completeMessage);
60 |
61 | // make sure the stream exists
62 | if (!self.outputStream || !self.outputStream.hasSpaceAvailable) {
63 | [self _setupOutputStreamToServer:kDefaultServer onPort:kDefaultPort];
64 | }
65 |
66 | // just write the message to our buffer
67 | [self _addMessageToBuffer:completeMessage];
68 | });
69 | }
70 |
71 | - (void)routeRemoteDebugMessagesToServer:(NSString *)server onPort:(UInt32)port {
72 | dispatch_async(self.messagesQueue, ^{
73 | // sets up our stream
74 | [self _setupOutputStreamToServer:server onPort:port];
75 | });
76 | }
77 |
78 | #pragma mark - NSStreamDelegate
79 |
80 | - (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {
81 | switch (eventCode) {
82 | case NSStreamEventHasSpaceAvailable: {
83 | dispatch_async(self.messagesQueue, ^{
84 | [self _flushBufferToStream];
85 | });
86 | } break;
87 |
88 | default: {
89 | // noop
90 | } break;
91 | }
92 | }
93 |
94 | #pragma mark - Private
95 |
96 | - (void)_addMessageToBuffer:(NSString *)message {
97 | // append it with a newline
98 | [self.buffer appendFormat:@"%@\n", message];
99 |
100 | // if we have space on our stream
101 | // if ([self.outputStream hasSpaceAvailable]) {
102 | // we flush the buffer
103 | [self _flushBufferToStream];
104 | // }
105 | }
106 |
107 | - (void)_flushBufferToStream {
108 | [self _writeStringToStream:self.buffer stream:self.outputStream];
109 | [self.buffer setString:@""];
110 | }
111 |
112 | - (void)_writeStringToStream:(NSString *)string stream:(NSOutputStream *)stream {
113 | // convert string to bytes
114 | NSData *messageData = [string dataUsingEncoding:NSUTF8StringEncoding];
115 |
116 | // send string
117 | uint8_t *bytes = (uint8_t *)[messageData bytes];
118 | [stream write:bytes maxLength:messageData.length];
119 | }
120 |
121 | - (void)_setupOutputStreamToServer:(NSString *)server onPort:(UInt32)port {
122 | // clean up an old one if we have one
123 | if (self.outputStream) {
124 | [self.outputStream close];
125 | self.outputStream = nil;
126 | }
127 |
128 | // open socket and stream
129 | NSOutputStream *outputStream;
130 | [NSStream getStreamsToHostWithName:server port:port inputStream:nil outputStream:&outputStream];
131 | self.outputStream = outputStream;
132 | self.outputStream.delegate = self;
133 | [self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
134 | [self.outputStream open];
135 | }
136 |
137 | @end
138 |
139 | void SendRemoteDebugMessage(NSString *message, ...) {
140 | va_list args;
141 | va_start(args, message);
142 | NSString *completeMessage = [[NSString alloc] initWithFormat:message arguments:args];
143 | va_end(args);
144 |
145 | [[GBRemoteDebugMessages sharedMessages] _sendRemoteDebugMessage:completeMessage];
146 | }
147 |
148 | void RouteRemoteDebugMessagesToServerOnPort(NSString *server, UInt32 port) {
149 | [[GBRemoteDebugMessages sharedMessages] routeRemoteDebugMessagesToServer:server onPort:port];
150 | }
151 |
--------------------------------------------------------------------------------
/GBToolbox/GBRoundBadgeView.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBRoundBadgeView.m
3 | // Russia
4 | //
5 | // Created by Luka Mirosevic on 26/06/2013.
6 | // Copyright (c) 2013 Goonbee. All rights reserved.
7 | //
8 |
9 | #import "GBRoundBadgeView.h"
10 |
11 | #import
12 | #import "GBUtility_iOS.h"
13 |
14 | static UIViewContentMode const kDefaultForegroundImageContentMode = UIViewContentModeScaleToFill;
15 | static UIEdgeInsets const kDefaultClippingMargin = (UIEdgeInsets){0, 0, 0, 0};
16 | static UIEdgeInsets const kDefaultBackgroundImageMargin = (UIEdgeInsets){0, 0, 0, 0};
17 | static UIEdgeInsets const kDefaultForegroundImageMargin = (UIEdgeInsets){0, 0, 0, 0};
18 |
19 | @interface GBRoundBadgeView ()
20 |
21 | @property (strong, nonatomic) UIImageView *backgroundImageView;
22 | @property (strong, nonatomic) UIImageView *foregroundImageView;
23 |
24 | @end
25 |
26 | @implementation GBRoundBadgeView
27 |
28 | #pragma mark - custom accessors
29 |
30 | -(void)setForegroundImage:(UIImage *)foregroundImage {
31 | self.foregroundImageView.image = foregroundImage;
32 | }
33 |
34 | -(UIImage *)foregroundImage {
35 | return self.foregroundImageView.image;
36 | }
37 |
38 | -(void)setBackgroundImage:(UIImage *)backgroundImage {
39 | self.backgroundImageView.image = backgroundImage;
40 | }
41 |
42 | -(UIImage *)backgroundImage {
43 | return self.backgroundImageView.image;
44 | }
45 |
46 | -(void)setClippingMargin:(UIEdgeInsets)clippingMargin {
47 | _clippingMargin = clippingMargin;
48 |
49 | [self _updateClippingMask];
50 | }
51 |
52 | -(void)setForegroundImageMargin:(UIEdgeInsets)foregroundImageMargin {
53 | _foregroundImageMargin = foregroundImageMargin;
54 |
55 | [self _updateImageViewFrames];
56 | }
57 |
58 | -(void)setBackgroundImageMargin:(UIEdgeInsets)backgroundImageMargin {
59 | _backgroundImageMargin = backgroundImageMargin;
60 |
61 | [self _updateImageViewFrames];
62 | }
63 |
64 | -(void)setForegroundImageContentMode:(UIViewContentMode)foregroundImageContentMode {
65 | self.foregroundImageView.contentMode = foregroundImageContentMode;
66 | }
67 |
68 | -(UIViewContentMode)foregroundImageContentMode {
69 | return self.foregroundImageContentMode;
70 | }
71 |
72 | #pragma mark - life
73 |
74 | -(id)initWithFrame:(CGRect)frame {
75 | self = [super initWithFrame:frame];
76 | if (self) {
77 | [self _init];
78 | }
79 | return self;
80 | }
81 |
82 | - (id)initWithCoder:(NSCoder *)coder {
83 | self = [super initWithCoder:coder];
84 | if (self) {
85 | [self _init];
86 | }
87 | return self;
88 | }
89 |
90 | -(void)_init {
91 | self.backgroundColor = [UIColor clearColor];
92 |
93 | self.foregroundImageView = [UIImageView new];
94 | self.foregroundImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
95 |
96 | self.backgroundImageView = [UIImageView new];
97 | self.backgroundImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
98 |
99 | [self addSubview:self.backgroundImageView];
100 | [self addSubview:self.foregroundImageView];
101 |
102 | //defaults
103 | self.foregroundImageContentMode = kDefaultForegroundImageContentMode;
104 | self.clippingMargin = kDefaultClippingMargin;
105 | self.backgroundImageMargin = kDefaultBackgroundImageMargin;
106 | self.foregroundImageMargin = kDefaultForegroundImageMargin;
107 |
108 | [self _updateImageViewFrames];
109 | }
110 |
111 | #pragma mark - overrides
112 |
113 | -(void)setFrame:(CGRect)frame {
114 | [super setFrame:frame];
115 |
116 | [self _updateClippingMask];
117 | }
118 |
119 | #pragma mark - util
120 |
121 | -(void)_updateImageViewFrames {
122 | self.backgroundImageView.frame = CGRectMake(self.bounds.origin.x + self.backgroundImageMargin.left,
123 | self.bounds.origin.y + self.backgroundImageMargin.top,
124 | self.bounds.size.width - (self.backgroundImageMargin.left + self.backgroundImageMargin.right),
125 | self.bounds.size.height - (self.backgroundImageMargin.top + self.backgroundImageMargin.bottom));
126 |
127 | self.foregroundImageView.frame = CGRectMake(self.bounds.origin.x + self.foregroundImageMargin.left,
128 | self.bounds.origin.y + self.foregroundImageMargin.top,
129 | self.bounds.size.width - (self.foregroundImageMargin.left + self.foregroundImageMargin.right),
130 | self.bounds.size.height - (self.foregroundImageMargin.top + self.foregroundImageMargin.bottom));
131 |
132 | self.foregroundImageView.layer.mask = RoundClippingMaskInRectWithMargin(self.foregroundImageView.bounds, UIEdgeInsetsZero);
133 | self.backgroundImageView.layer.mask = RoundClippingMaskInRectWithMargin(self.backgroundImageView.bounds, UIEdgeInsetsZero);
134 | }
135 |
136 | -(void)_updateClippingMask {
137 | self.layer.mask = RoundClippingMaskInRectWithMargin(self.bounds, self.clippingMargin);
138 | }
139 |
140 | @end
141 |
--------------------------------------------------------------------------------
/GBToolbox/GBColoredBarView.m:
--------------------------------------------------------------------------------
1 | //
2 | // GBColoredBarView.m
3 | // Russia
4 | //
5 | // Created by Luka Mirosevic on 27/06/2013.
6 | // Copyright (c) 2013 Goonbee. All rights reserved.
7 | //
8 |
9 | #import "GBColoredBarView.h"
10 |
11 | #define kDefaultBorderColor [UIColor blackColor]
12 | #define kDefaultBackgroundColorWhenEmpty [UIColor clearColor]
13 | #define kDefaultBackgroundColorWhenFull [UIColor clearColor]
14 | static BOOL const kDefaultShowBorderWhenFull = NO;
15 | static BOOL const kDefaultShowBorderWhenEmpty = YES;
16 | static CGFloat const kDefaultBorderThickness = 1;
17 |
18 | @implementation GBColoredBarView
19 |
20 | #pragma mark - custom accessors
21 |
22 | -(void)setColors:(NSArray *)colors {
23 | if (colors.count >= self.fractions.count) {
24 | _colors = colors;
25 |
26 | [self setNeedsDisplay];
27 | }
28 | else {
29 | NSLog(@"ColoredBarView: You must set more colors than fractions!");
30 | }
31 | }
32 |
33 | -(void)setFractions:(NSArray *)fractions {
34 | if (fractions.count <= self.colors.count) {
35 | _fractions = fractions;
36 |
37 | [self setNeedsDisplay];
38 | }
39 | else {
40 | NSLog(@"ColoredBarView: You must set less colors than fractions, set colors first!");
41 | }
42 | }
43 |
44 | -(void)setBackgroundColorWhenEmpty:(UIColor *)backgroundColorWhenEmpty {
45 | _backgroundColorWhenEmpty = backgroundColorWhenEmpty;
46 |
47 | [self setNeedsDisplay];
48 | }
49 |
50 | -(void)setBackgroundColorWhenFull:(UIColor *)backgroundColorWhenFull {
51 | _backgroundColorWhenFull = backgroundColorWhenFull;
52 |
53 | [self setNeedsDisplay];
54 | }
55 |
56 | -(void)setBorderColor:(UIColor *)borderColor {
57 | _borderColor = borderColor;
58 |
59 | [self setNeedsDisplay];
60 | }
61 |
62 | -(void)setBorderThickness:(CGFloat)borderThickness {
63 | _borderThickness = borderThickness;
64 |
65 | [self setNeedsDisplay];
66 | }
67 |
68 | -(void)setShowBorderWhenFull:(BOOL)showBorderWhenFull {
69 | _showBorderWhenFull = showBorderWhenFull;
70 |
71 | [self setNeedsDisplay];
72 | }
73 |
74 | -(void)setShowBorderWhenEmpty:(BOOL)showBorderWhenEmpty {
75 | _showBorderWhenEmpty = showBorderWhenEmpty;
76 |
77 | [self setNeedsDisplay];
78 | }
79 |
80 | #pragma mark - life
81 |
82 | -(id)initWithFrame:(CGRect)frame {
83 | self = [super initWithFrame:frame];
84 | if (self) {
85 | [self _init];
86 | }
87 | return self;
88 | }
89 |
90 | -(id)initWithCoder:(NSCoder *)coder {
91 | self = [super initWithCoder:coder];
92 | if (self) {
93 | [self _init];
94 | }
95 | return self;
96 | }
97 |
98 | -(void)_init {
99 | self.backgroundColorWhenEmpty = kDefaultBackgroundColorWhenEmpty;
100 | self.backgroundColorWhenFull = kDefaultBackgroundColorWhenFull;
101 | self.borderColor = kDefaultBorderColor;
102 | self.showBorderWhenFull = kDefaultShowBorderWhenFull;
103 | self.showBorderWhenEmpty = kDefaultShowBorderWhenEmpty;
104 | self.borderThickness = kDefaultBorderThickness;
105 |
106 | self.backgroundColor = [UIColor clearColor];
107 | }
108 |
109 | #pragma mark - util
110 |
111 | -(BOOL)_isEmpty {
112 | //bail if no fractions set
113 | if (!self.fractions) return YES;
114 |
115 | for (NSNumber *fraction in self.fractions) {
116 | //find a non zero fraction
117 | if (![fraction isEqualToNumber:@(0)]) {
118 | return NO;
119 | }
120 | }
121 |
122 | //if we didn't return yet, it means we're empty
123 | return YES;
124 | }
125 |
126 | -(UIColor *)_currentBackgroundColor {
127 | if ([self _isEmpty]) {
128 | return self.backgroundColorWhenEmpty;
129 | }
130 | else {
131 | return self.backgroundColorWhenFull;
132 | }
133 | }
134 |
135 | #pragma mark - drawing
136 |
137 | -(void)drawRect:(CGRect)rect {
138 | CGContextRef c = UIGraphicsGetCurrentContext();
139 |
140 | //background
141 | CGContextSetFillColorWithColor(c, [self _currentBackgroundColor].CGColor);
142 | CGContextFillRect(c, rect);
143 |
144 | //fill areas
145 | if (![self _isEmpty]) {
146 | //calculate sum
147 | CGFloat fractionsSum = 0;
148 | for (NSNumber *fraction in self.fractions) {
149 | fractionsSum += [fraction floatValue];
150 | }
151 |
152 | //do the drawing of individual areas
153 | CGFloat lastX1 = rect.origin.x;
154 | for (NSUInteger i=0; i