From e88d59952aceba71f69de6e20cf5991fd9ff70ba Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Mon, 6 Oct 2014 15:45:45 -0700 Subject: [PATCH 01/44] fix showing tweaks in the simulator when enabled --- FBTweak/FBTweakShakeWindow.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/FBTweak/FBTweakShakeWindow.m b/FBTweak/FBTweakShakeWindow.m index d91abbd7..cf86d672 100644 --- a/FBTweak/FBTweakShakeWindow.m +++ b/FBTweak/FBTweakShakeWindow.m @@ -43,10 +43,10 @@ - (void)_presentTweaks - (BOOL)_shouldPresentTweaks { -#if FB_TWEAK_ENABLED - return _shaking && [[UIApplication sharedApplication] applicationState] == UIApplicationStateActive; -#elif TARGET_IPHONE_SIMULATOR +#if TARGET_IPHONE_SIMULATOR return YES; +#elif FB_TWEAK_ENABLED + return _shaking && [[UIApplication sharedApplication] applicationState] == UIApplicationStateActive; #else return NO; #endif From 6c9ba8af32ea16ffb005da088cea1440db283bd4 Mon Sep 17 00:00:00 2001 From: Sami Samhuri Date: Tue, 7 Oct 2014 15:32:00 -0700 Subject: [PATCH 02/44] allow disabling in the simulator --- FBTweak/FBTweakShakeWindow.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FBTweak/FBTweakShakeWindow.m b/FBTweak/FBTweakShakeWindow.m index cf86d672..07ab780e 100644 --- a/FBTweak/FBTweakShakeWindow.m +++ b/FBTweak/FBTweakShakeWindow.m @@ -43,7 +43,7 @@ - (void)_presentTweaks - (BOOL)_shouldPresentTweaks { -#if TARGET_IPHONE_SIMULATOR +#if TARGET_IPHONE_SIMULATOR && FB_TWEAK_ENABLED return YES; #elif FB_TWEAK_ENABLED return _shaking && [[UIApplication sharedApplication] applicationState] == UIApplicationStateActive; From 6b54b2e03b5dc8905a1c262e6849488cf4c9ab57 Mon Sep 17 00:00:00 2001 From: John McIntosh Date: Wed, 5 Nov 2014 13:11:16 -0600 Subject: [PATCH 03/44] Implement support for storing a dictionary as a tweak --- FBTweak.xcodeproj/project.pbxproj | 18 +++- FBTweak/FBTweak+Dictionary.h | 24 +++++ FBTweak/FBTweak+Dictionary.m | 71 +++++++++++++ FBTweak/_FBTweakCollectionViewController.m | 27 ++++- FBTweak/_FBTweakDictionaryViewController.h | 17 ++++ FBTweak/_FBTweakDictionaryViewController.m | 86 ++++++++++++++++ FBTweak/_FBTweakTableViewCell.m | 112 +++++++++++++-------- FBTweakExample/FBAppDelegate.m | 7 ++ 8 files changed, 317 insertions(+), 45 deletions(-) create mode 100644 FBTweak/FBTweak+Dictionary.h create mode 100644 FBTweak/FBTweak+Dictionary.m create mode 100644 FBTweak/_FBTweakDictionaryViewController.h create mode 100644 FBTweak/_FBTweakDictionaryViewController.m diff --git a/FBTweak.xcodeproj/project.pbxproj b/FBTweak.xcodeproj/project.pbxproj index 64d146cf..64c800a9 100644 --- a/FBTweak.xcodeproj/project.pbxproj +++ b/FBTweak.xcodeproj/project.pbxproj @@ -40,6 +40,10 @@ 18EFE52D189F250700DA6A5D /* FBTweakInlineTestsMRR.m in Sources */ = {isa = PBXBuildFile; fileRef = 18EFE52C189F250700DA6A5D /* FBTweakInlineTestsMRR.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 18EFE536189F38D500DA6A5D /* FBTweakEnabled.h in Headers */ = {isa = PBXBuildFile; fileRef = 18EFE535189F38D500DA6A5D /* FBTweakEnabled.h */; settings = {ATTRIBUTES = (Public, ); }; }; 29E9F17B18E35C9C001EAF7D /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29E9F17A18E35C9C001EAF7D /* MessageUI.framework */; }; + 5BE25A4E1A0AA90E00C97C3E /* FBTweak+Dictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BE25A4C1A0AA90E00C97C3E /* FBTweak+Dictionary.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5BE25A4F1A0AA90E00C97C3E /* FBTweak+Dictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BE25A4D1A0AA90E00C97C3E /* FBTweak+Dictionary.m */; }; + 5BE25A521A0AA9D500C97C3E /* _FBTweakDictionaryViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BE25A501A0AA9D500C97C3E /* _FBTweakDictionaryViewController.h */; }; + 5BE25A531A0AA9D500C97C3E /* _FBTweakDictionaryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BE25A511A0AA9D500C97C3E /* _FBTweakDictionaryViewController.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -82,12 +86,16 @@ 18EFE4D7189EEED800DA6A5D /* _FBTweakCollectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _FBTweakCollectionViewController.h; sourceTree = ""; }; 18EFE4D8189EEED800DA6A5D /* _FBTweakCollectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = _FBTweakCollectionViewController.m; sourceTree = ""; }; 18EFE4DB189EF75800DA6A5D /* _FBTweakTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _FBTweakTableViewCell.h; sourceTree = ""; }; - 18EFE4DC189EF75800DA6A5D /* _FBTweakTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = _FBTweakTableViewCell.m; sourceTree = ""; }; + 18EFE4DC189EF75800DA6A5D /* _FBTweakTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = _FBTweakTableViewCell.m; sourceTree = ""; tabWidth = 2; }; 18EFE525189F19B300DA6A5D /* FBTweakCategory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBTweakCategory.h; sourceTree = ""; }; 18EFE526189F19B300DA6A5D /* FBTweakCategory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBTweakCategory.m; sourceTree = ""; }; 18EFE52C189F250700DA6A5D /* FBTweakInlineTestsMRR.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBTweakInlineTestsMRR.m; sourceTree = ""; }; 18EFE535189F38D500DA6A5D /* FBTweakEnabled.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBTweakEnabled.h; sourceTree = ""; }; 29E9F17A18E35C9C001EAF7D /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; + 5BE25A4C1A0AA90E00C97C3E /* FBTweak+Dictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FBTweak+Dictionary.h"; sourceTree = ""; }; + 5BE25A4D1A0AA90E00C97C3E /* FBTweak+Dictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = "FBTweak+Dictionary.m"; sourceTree = ""; tabWidth = 2; }; + 5BE25A501A0AA9D500C97C3E /* _FBTweakDictionaryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _FBTweakDictionaryViewController.h; sourceTree = ""; }; + 5BE25A511A0AA9D500C97C3E /* _FBTweakDictionaryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = _FBTweakDictionaryViewController.m; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -194,6 +202,8 @@ 18EFE526189F19B300DA6A5D /* FBTweakCategory.m */, 18EFE4BF189EBEAD00DA6A5D /* FBTweakStore.h */, 18EFE4C0189EBEAD00DA6A5D /* FBTweakStore.m */, + 5BE25A4C1A0AA90E00C97C3E /* FBTweak+Dictionary.h */, + 5BE25A4D1A0AA90E00C97C3E /* FBTweak+Dictionary.m */, ); name = Model; sourceTree = ""; @@ -211,6 +221,8 @@ 18EFE4D8189EEED800DA6A5D /* _FBTweakCollectionViewController.m */, 18EFE4DB189EF75800DA6A5D /* _FBTweakTableViewCell.h */, 18EFE4DC189EF75800DA6A5D /* _FBTweakTableViewCell.m */, + 5BE25A501A0AA9D500C97C3E /* _FBTweakDictionaryViewController.h */, + 5BE25A511A0AA9D500C97C3E /* _FBTweakDictionaryViewController.m */, ); name = UI; sourceTree = ""; @@ -243,8 +255,10 @@ 18EFE4B3189EBAC200DA6A5D /* FBTweakShakeWindow.h in Headers */, 18EFE536189F38D500DA6A5D /* FBTweakEnabled.h in Headers */, 18EFE4D0189EC70300DA6A5D /* FBTweakInlineInternal.h in Headers */, + 5BE25A4E1A0AA90E00C97C3E /* FBTweak+Dictionary.h in Headers */, 18EFE527189F19B300DA6A5D /* FBTweakCategory.h in Headers */, 18EFE4BC189EBC4B00DA6A5D /* FBTweakCollection.h in Headers */, + 5BE25A521A0AA9D500C97C3E /* _FBTweakDictionaryViewController.h in Headers */, 18EFE4DD189EF75800DA6A5D /* _FBTweakTableViewCell.h in Headers */, 184A94F018D26871005F2774 /* _FBTweakBindObserver.h in Headers */, ); @@ -331,6 +345,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 5BE25A531A0AA9D500C97C3E /* _FBTweakDictionaryViewController.m in Sources */, + 5BE25A4F1A0AA90E00C97C3E /* FBTweak+Dictionary.m in Sources */, 18EFE4A7189EBA9E00DA6A5D /* FBTweakViewController.m in Sources */, 18EFE4BD189EBC4B00DA6A5D /* FBTweakCollection.m in Sources */, 18EFE4C2189EBEAD00DA6A5D /* FBTweakStore.m in Sources */, diff --git a/FBTweak/FBTweak+Dictionary.h b/FBTweak/FBTweak+Dictionary.h new file mode 100644 index 00000000..ad188d00 --- /dev/null +++ b/FBTweak/FBTweak+Dictionary.h @@ -0,0 +1,24 @@ +// +// FBTweak+Dictionary.h +// FBTweak +// +// Created by John McIntosh on 11/5/14. +// Copyright (c) 2014 Facebook. All rights reserved. +// + +#import + +/** + Implementation works by storing the dictionary in the tweak's `stepValue`. + */ +@interface FBTweak (Dictionary) + +@property (nonatomic, copy, readonly) NSArray *allKeys; +@property (nonatomic, copy, readonly) NSArray *allValues; +@property (nonatomic, copy, readwrite) NSDictionary *dictionaryValue; + +- (BOOL)isDictionary; + +@end + +FBTweakValue FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, id defaultKey); \ No newline at end of file diff --git a/FBTweak/FBTweak+Dictionary.m b/FBTweak/FBTweak+Dictionary.m new file mode 100644 index 00000000..3229ac9e --- /dev/null +++ b/FBTweak/FBTweak+Dictionary.m @@ -0,0 +1,71 @@ +// +// FBTweak+Dictionary.m +// FBTweak +// +// Created by John McIntosh on 11/5/14. +// Copyright (c) 2014 Facebook. All rights reserved. +// + +#import "FBTweak+Dictionary.h" +#import "FBTweakStore.h" +#import "FBTweakCollection.h" +#import "FBTweakCategory.h" + +@implementation FBTweak (Dictionary) + +- (BOOL)isDictionary { + return (self.dictionaryValue != nil); +} + +- (NSDictionary *)dictionaryValue { + if ([self.stepValue isKindOfClass:[NSDictionary class]]) { + return self.stepValue; + } + return nil; +} + +- (void)setDictionaryValue:(NSDictionary *)dictionaryValue { + self.stepValue = dictionaryValue; +} + +- (NSArray *)allKeys { + return self.dictionaryValue.allKeys; +} + +- (NSArray *)allValues { + return self.dictionaryValue.allValues; +} + +FBTweakValue FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, id defaultKey) +{ + FBTweakStore *store = [FBTweakStore sharedInstance]; + FBTweakCategory *cat = [store tweakCategoryWithName:categoryName]; + + if (!cat) { + cat = [[FBTweakCategory alloc] initWithName:categoryName]; + [store addTweakCategory:cat]; + } + + FBTweakCollection *collection = [cat tweakCollectionWithName:collectionName]; + + if (!collection) { + collection = [[FBTweakCollection alloc] initWithName:collectionName]; + [cat addTweakCollection:collection]; + } + + + FBTweak *tweak = [collection tweakWithIdentifier:tweakName]; + + if (!tweak) { + tweak = [[FBTweak alloc] initWithIdentifier:tweakName]; + tweak.name = tweakName; + tweak.dictionaryValue = dictionary; + tweak.defaultValue = defaultKey; + + [collection addTweak:tweak]; + } + + return tweak.currentValue ?: tweak.defaultValue; +} + +@end diff --git a/FBTweak/_FBTweakCollectionViewController.m b/FBTweak/_FBTweakCollectionViewController.m index 0020d3ea..f787eb81 100644 --- a/FBTweak/_FBTweakCollectionViewController.m +++ b/FBTweak/_FBTweakCollectionViewController.m @@ -11,6 +11,8 @@ #import "FBTweakCategory.h" #import "_FBTweakCollectionViewController.h" #import "_FBTweakTableViewCell.h" +#import "FBTweak+Dictionary.h" +#import "_FBTweakDictionaryViewController.h" @interface _FBTweakCollectionViewController () @end @@ -25,10 +27,7 @@ - (instancetype)initWithTweakCategory:(FBTweakCategory *)category if ((self = [super init])) { _tweakCategory = category; self.title = _tweakCategory.name; - - _sortedCollections = [_tweakCategory.tweakCollections sortedArrayUsingComparator:^(FBTweakCollection *a, FBTweakCollection *b) { - return [a.name localizedStandardCompare:b.name]; - }]; + [self _reloadData]; } return self; @@ -60,6 +59,15 @@ - (void)viewWillAppear:(BOOL)animated [super viewWillAppear:animated]; [_tableView deselectRowAtIndexPath:_tableView.indexPathForSelectedRow animated:animated]; + [self _reloadData]; +} + +- (void)_reloadData +{ + _sortedCollections = [_tweakCategory.tweakCollections sortedArrayUsingComparator:^(FBTweakCollection *a, FBTweakCollection *b) { + return [a.name localizedStandardCompare:b.name]; + }]; + [_tableView reloadData]; } - (void)_done @@ -123,4 +131,15 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N return cell; } +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + FBTweakCollection *collection = _sortedCollections[indexPath.section]; + FBTweak *tweak = collection.tweaks[indexPath.row]; + if ([tweak isDictionary]) { + _FBTweakDictionaryViewController *vc = [[_FBTweakDictionaryViewController alloc] init]; + vc.tweak = tweak; + [self.navigationController pushViewController:vc animated:YES]; + } +} + @end diff --git a/FBTweak/_FBTweakDictionaryViewController.h b/FBTweak/_FBTweakDictionaryViewController.h new file mode 100644 index 00000000..cb6b3843 --- /dev/null +++ b/FBTweak/_FBTweakDictionaryViewController.h @@ -0,0 +1,17 @@ +// +// _FBTweakDictionaryViewController.h +// FBTweak +// +// Created by John McIntosh on 11/5/14. +// Copyright (c) 2014 Facebook. All rights reserved. +// + +#import + +@class FBTweak; + +@interface _FBTweakDictionaryViewController : UIViewController + +@property (nonatomic, strong) FBTweak *tweak; + +@end diff --git a/FBTweak/_FBTweakDictionaryViewController.m b/FBTweak/_FBTweakDictionaryViewController.m new file mode 100644 index 00000000..3a88b37a --- /dev/null +++ b/FBTweak/_FBTweakDictionaryViewController.m @@ -0,0 +1,86 @@ +// +// _FBTweakDictionaryViewController.m +// FBTweak +// +// Created by John McIntosh on 11/5/14. +// Copyright (c) 2014 Facebook. All rights reserved. +// + +#import "_FBTweakDictionaryViewController.h" +#import "FBTweak.h" +#import "FBTweak+Dictionary.h" + +@interface _FBTweakDictionaryViewController () + +@property (nonatomic, strong) UITableView *tableView; + +@end + +@implementation _FBTweakDictionaryViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; + _tableView.delegate = self; + _tableView.dataSource = self; + _tableView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); + [self.view addSubview:_tableView]; +} + +- (void)dealloc +{ + _tableView.delegate = nil; + _tableView.dataSource = nil; +} + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return self.tweak.allKeys.count; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *_FBTweakDictionaryViewControllerCellIdentifier = @"_FBTweakDictionaryViewControllerCellIdentifier"; + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:_FBTweakDictionaryViewControllerCellIdentifier]; + if (cell == nil) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:_FBTweakDictionaryViewControllerCellIdentifier]; + } + + NSArray *allKeys = [self allTweakKeys]; + NSString *key = allKeys[indexPath.row]; + NSString *value = self.tweak.dictionaryValue[key]; + cell.textLabel.text = key; + cell.detailTextLabel.text = value; + + cell.accessoryType = UITableViewCellAccessoryNone; + NSString *selectedKey = (self.tweak.currentValue ?: self.tweak.defaultValue); + if ([selectedKey isEqualToString:key]) { + cell.accessoryType = UITableViewCellAccessoryCheckmark; + } + + return cell; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + NSArray *allKeys = [self allTweakKeys]; + NSString *key = allKeys[indexPath.row]; + + self.tweak.currentValue = key; + [self.navigationController popViewControllerAnimated:YES]; +} + +- (NSArray *)allTweakKeys { + return [self.tweak.allKeys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { + return [obj1 compare:obj2]; + }]; +} + +@end \ No newline at end of file diff --git a/FBTweak/_FBTweakTableViewCell.m b/FBTweak/_FBTweakTableViewCell.m index c1216b22..e536d4da 100644 --- a/FBTweak/_FBTweakTableViewCell.m +++ b/FBTweak/_FBTweakTableViewCell.m @@ -9,6 +9,7 @@ #import "FBTweak.h" #import "_FBTweakTableViewCell.h" +#import "FBTweak+Dictionary.h" typedef NS_ENUM(NSUInteger, _FBTweakTableViewCellMode) { _FBTweakTableViewCellModeNone = 0, @@ -17,6 +18,7 @@ typedef NS_ENUM(NSUInteger, _FBTweakTableViewCellMode) { _FBTweakTableViewCellModeReal, _FBTweakTableViewCellModeString, _FBTweakTableViewCellModeAction, + _FBTweakTableViewCellModeDictionary, }; @interface _FBTweakTableViewCell () @@ -29,13 +31,14 @@ @implementation _FBTweakTableViewCell { UISwitch *_switch; UITextField *_textField; UIStepper *_stepper; + UILabel *_valueLabel; } - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier; { if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier])) { _accessoryView = [[UIView alloc] init]; - + _switch = [[UISwitch alloc] init]; [_switch addTarget:self action:@selector(_switchChanged:) forControlEvents:UIControlEventValueChanged]; [_accessoryView addSubview:_switch]; @@ -48,8 +51,12 @@ - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier; _stepper = [[UIStepper alloc] init]; [_stepper addTarget:self action:@selector(_stepperChanged:) forControlEvents:UIControlEventValueChanged]; [_accessoryView addSubview:_stepper]; + + _valueLabel = [[UILabel alloc] init]; + _valueLabel.textAlignment = NSTextAlignmentRight; + [_accessoryView addSubview:_valueLabel]; } - + return self; } @@ -87,8 +94,14 @@ - (void)layoutSubviews _accessoryView.bounds = CGRectIntegral(textBounds); } else if (_mode == _FBTweakTableViewCellModeAction) { _accessoryView.bounds = CGRectZero; + } else if (_mode == _FBTweakTableViewCellModeDictionary) { + CGFloat margin = CGRectGetMinX(self.textLabel.frame); + CGFloat textFieldWidth = self.bounds.size.width - (margin * 3.0) - [self.textLabel sizeThatFits:CGSizeZero].width; + CGRect textBounds = CGRectMake(0, 0, textFieldWidth, self.bounds.size.height); + _valueLabel.frame = CGRectIntegral(textBounds); + _accessoryView.bounds = CGRectIntegral(textBounds); } - + // This positions the accessory view, so call it after updating its bounds. [super layoutSubviews]; } @@ -97,66 +110,69 @@ - (void)layoutSubviews - (void)setTweak:(FBTweak *)tweak { - if (_tweak != tweak) { - _tweak = tweak; - - self.textLabel.text = tweak.name; - - FBTweakValue value = (_tweak.currentValue ?: _tweak.defaultValue); - - _FBTweakTableViewCellMode mode = _FBTweakTableViewCellModeNone; - if ([value isKindOfClass:[NSString class]]) { - mode = _FBTweakTableViewCellModeString; - } else if ([value isKindOfClass:[NSNumber class]]) { - // In the 64-bit runtime, BOOL is a real boolean. - // NSNumber doesn't always agree; compare both. - if (strcmp([value objCType], @encode(char)) == 0 || - strcmp([value objCType], @encode(_Bool)) == 0) { - mode = _FBTweakTableViewCellModeBoolean; - } else if (strcmp([value objCType], @encode(NSInteger)) == 0 || - strcmp([value objCType], @encode(NSUInteger)) == 0) { - mode = _FBTweakTableViewCellModeInteger; - } else { - mode = _FBTweakTableViewCellModeReal; - } - } else if ([_tweak isAction]) { - mode = _FBTweakTableViewCellModeAction; + _tweak = tweak; + + self.textLabel.text = tweak.name; + + FBTweakValue value = (_tweak.currentValue ?: _tweak.defaultValue); + + _FBTweakTableViewCellMode mode = _FBTweakTableViewCellModeNone; + if ([tweak isDictionary]) { + value = _tweak.dictionaryValue[value]; + mode = _FBTweakTableViewCellModeDictionary; + } else if ([value isKindOfClass:[NSString class]]) { + mode = _FBTweakTableViewCellModeString; + } else if ([value isKindOfClass:[NSNumber class]]) { + // In the 64-bit runtime, BOOL is a real boolean. + // NSNumber doesn't always agree; compare both. + if (strcmp([value objCType], @encode(char)) == 0 || + strcmp([value objCType], @encode(_Bool)) == 0) { + mode = _FBTweakTableViewCellModeBoolean; + } else if (strcmp([value objCType], @encode(NSInteger)) == 0 || + strcmp([value objCType], @encode(NSUInteger)) == 0) { + mode = _FBTweakTableViewCellModeInteger; + } else { + mode = _FBTweakTableViewCellModeReal; } - - [self _updateMode:mode]; - [self _updateValue:value primary:YES write:NO]; + } else if ([_tweak isAction]) { + mode = _FBTweakTableViewCellModeAction; } + + [self _updateMode:mode]; + [self _updateValue:value primary:YES write:NO]; } - (void)_updateMode:(_FBTweakTableViewCellMode)mode { _mode = mode; - + self.accessoryView = _accessoryView; self.accessoryType = UITableViewCellAccessoryNone; self.selectionStyle = UITableViewCellSelectionStyleNone; - + if (_mode == _FBTweakTableViewCellModeBoolean) { _switch.hidden = NO; _textField.hidden = YES; _stepper.hidden = YES; + _valueLabel.hidden = YES; } else if (_mode == _FBTweakTableViewCellModeInteger) { _switch.hidden = YES; _textField.hidden = NO; _textField.keyboardType = UIKeyboardTypeNumberPad; _stepper.hidden = NO; + _valueLabel.hidden = YES; if (_tweak.stepValue) { _stepper.stepValue = [_tweak.stepValue floatValue]; } else { _stepper.stepValue = 1.0; } - + if (_tweak.minimumValue != nil) { _stepper.minimumValue = [_tweak.minimumValue longLongValue]; } else { _stepper.minimumValue = [_tweak.defaultValue longLongValue] / 10.0; } - + if (_tweak.maximumValue != nil) { _stepper.maximumValue = [_tweak.maximumValue longLongValue]; } else { @@ -167,13 +183,14 @@ - (void)_updateMode:(_FBTweakTableViewCellMode)mode _textField.hidden = NO; _textField.keyboardType = UIKeyboardTypeDecimalPad; _stepper.hidden = NO; - + _valueLabel.hidden = YES; + if (_tweak.stepValue) { _stepper.stepValue = [_tweak.stepValue floatValue]; } else { _stepper.stepValue = 1.0; } - + if (_tweak.minimumValue != nil) { _stepper.minimumValue = [_tweak.minimumValue doubleValue]; } else if ([_tweak.defaultValue doubleValue] == 0) { @@ -198,18 +215,26 @@ - (void)_updateMode:(_FBTweakTableViewCellMode)mode _textField.hidden = NO; _textField.keyboardType = UIKeyboardTypeDefault; _stepper.hidden = YES; + _valueLabel.hidden = YES; } else if (_mode == _FBTweakTableViewCellModeAction) { _switch.hidden = YES; _textField.hidden = YES; _stepper.hidden = YES; - + _valueLabel.hidden = YES; + self.accessoryView = nil; self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; self.selectionStyle = UITableViewCellSelectionStyleBlue; + } else if (_mode == _FBTweakTableViewCellModeDictionary) { + _switch.hidden = YES; + _textField.hidden = YES; + _stepper.hidden = YES; + _valueLabel.hidden = NO; } else { _switch.hidden = YES; _textField.hidden = YES; _stepper.hidden = YES; + _valueLabel.hidden = YES; } [self setNeedsLayout]; @@ -221,11 +246,11 @@ - (void)_updateMode:(_FBTweakTableViewCellMode)mode - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; - + if (_mode == _FBTweakTableViewCellModeAction) { if (selected) { [self setSelected:NO animated:YES]; - + dispatch_block_t block = _tweak.defaultValue; if (block != NULL) { block(); @@ -300,9 +325,16 @@ - (void)_updateValue:(FBTweakValue)value primary:(BOOL)primary write:(BOOL)write if (_tweak.precisionValue) { precision = [[_tweak precisionValue] longValue]; } - + NSString *format = [NSString stringWithFormat:@"%%.%ldf", precision]; _textField.text = [NSString stringWithFormat:format, [value doubleValue]]; + } else if (_mode == _FBTweakTableViewCellModeDictionary) { + if (primary) { + if ([value isKindOfClass:[NSString class]]) { + NSString *displayValue = [value stringByAppendingString:@" >"]; + _valueLabel.text = displayValue; + } + } } } diff --git a/FBTweakExample/FBAppDelegate.m b/FBTweakExample/FBAppDelegate.m index be1e6df2..766f26c6 100644 --- a/FBTweakExample/FBAppDelegate.m +++ b/FBTweakExample/FBAppDelegate.m @@ -11,6 +11,7 @@ #import #import #import +#import #import "FBAppDelegate.h" @@ -85,6 +86,12 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [alert show]; }); + NSDictionary *dict = @{@"key1": @"value1", + @"key2": @"value2", + @"key3": @"value3", + }; + FBDictionaryTweak(@"Local Server", @"Auth", @"Login", dict, @"key1"); + return YES; } From 7e896a0eb00728783a718994a20a6e21b4a69980 Mon Sep 17 00:00:00 2001 From: John McIntosh Date: Thu, 6 Nov 2014 13:26:16 -0600 Subject: [PATCH 04/44] Update syntax for import statement --- FBTweak/FBTweak+Dictionary.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FBTweak/FBTweak+Dictionary.h b/FBTweak/FBTweak+Dictionary.h index ad188d00..55b5ed03 100644 --- a/FBTweak/FBTweak+Dictionary.h +++ b/FBTweak/FBTweak+Dictionary.h @@ -6,7 +6,7 @@ // Copyright (c) 2014 Facebook. All rights reserved. // -#import +#import "FBTweak.h" /** Implementation works by storing the dictionary in the tweak's `stepValue`. From d634aeeb3ba816b20954a885e6e8f4d8a124bec5 Mon Sep 17 00:00:00 2001 From: John McIntosh Date: Fri, 7 Nov 2014 14:46:00 -0600 Subject: [PATCH 05/44] Add a new FBDictionaryTweakValue macro to the dictionary tweak --- FBTweak/FBTweak+Dictionary.h | 1 + FBTweak/FBTweak+Dictionary.m | 9 +++++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/FBTweak/FBTweak+Dictionary.h b/FBTweak/FBTweak+Dictionary.h index 55b5ed03..856bae96 100644 --- a/FBTweak/FBTweak+Dictionary.h +++ b/FBTweak/FBTweak+Dictionary.h @@ -21,4 +21,5 @@ @end +FBTweak* FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, id defaultKey); FBTweakValue FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, id defaultKey); \ No newline at end of file diff --git a/FBTweak/FBTweak+Dictionary.m b/FBTweak/FBTweak+Dictionary.m index 3229ac9e..8f35d4c2 100644 --- a/FBTweak/FBTweak+Dictionary.m +++ b/FBTweak/FBTweak+Dictionary.m @@ -36,7 +36,7 @@ - (NSArray *)allValues { return self.dictionaryValue.allValues; } -FBTweakValue FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, id defaultKey) +FBTweak* FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, id defaultKey) { FBTweakStore *store = [FBTweakStore sharedInstance]; FBTweakCategory *cat = [store tweakCategoryWithName:categoryName]; @@ -64,7 +64,12 @@ FBTweakValue FBDictionaryTweak(NSString *categoryName, NSString *collectionName, [collection addTweak:tweak]; } - + return tweak; +} + +FBTweakValue FBDictionaryTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, id defaultKey) +{ + FBTweak *tweak = FBDictionaryTweak(categoryName, collectionName, tweakName, dictionary, defaultKey); return tweak.currentValue ?: tweak.defaultValue; } From 555b3cc17359d28ffc4bf79ec658398731520b90 Mon Sep 17 00:00:00 2001 From: John McIntosh Date: Tue, 11 Nov 2014 14:09:16 -0600 Subject: [PATCH 06/44] Add array tweak support --- FBTweak.xcodeproj/project.pbxproj | 16 +++++ FBTweak/FBTweak+Array.h | 25 ++++++++ FBTweak/FBTweak+Array.m | 68 ++++++++++++++++++++ FBTweak/FBTweak+Dictionary.h | 2 +- FBTweak/_FBTweakArrayViewController.h | 17 +++++ FBTweak/_FBTweakArrayViewController.m | 75 ++++++++++++++++++++++ FBTweak/_FBTweakCollectionViewController.m | 6 ++ FBTweak/_FBTweakTableViewCell.m | 22 +++++++ FBTweakExample/FBAppDelegate.m | 3 + 9 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 FBTweak/FBTweak+Array.h create mode 100644 FBTweak/FBTweak+Array.m create mode 100644 FBTweak/_FBTweakArrayViewController.h create mode 100644 FBTweak/_FBTweakArrayViewController.m diff --git a/FBTweak.xcodeproj/project.pbxproj b/FBTweak.xcodeproj/project.pbxproj index 64c800a9..85a57103 100644 --- a/FBTweak.xcodeproj/project.pbxproj +++ b/FBTweak.xcodeproj/project.pbxproj @@ -40,6 +40,10 @@ 18EFE52D189F250700DA6A5D /* FBTweakInlineTestsMRR.m in Sources */ = {isa = PBXBuildFile; fileRef = 18EFE52C189F250700DA6A5D /* FBTweakInlineTestsMRR.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 18EFE536189F38D500DA6A5D /* FBTweakEnabled.h in Headers */ = {isa = PBXBuildFile; fileRef = 18EFE535189F38D500DA6A5D /* FBTweakEnabled.h */; settings = {ATTRIBUTES = (Public, ); }; }; 29E9F17B18E35C9C001EAF7D /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29E9F17A18E35C9C001EAF7D /* MessageUI.framework */; }; + 5BACB31A1A1280BD00C4F79D /* FBTweak+Array.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BACB3181A1280BD00C4F79D /* FBTweak+Array.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 5BACB31B1A1280BD00C4F79D /* FBTweak+Array.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BACB3191A1280BD00C4F79D /* FBTweak+Array.m */; }; + 5BACB31E1A12813C00C4F79D /* _FBTweakArrayViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BACB31C1A12813C00C4F79D /* _FBTweakArrayViewController.h */; }; + 5BACB31F1A12813C00C4F79D /* _FBTweakArrayViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BACB31D1A12813C00C4F79D /* _FBTweakArrayViewController.m */; }; 5BE25A4E1A0AA90E00C97C3E /* FBTweak+Dictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BE25A4C1A0AA90E00C97C3E /* FBTweak+Dictionary.h */; settings = {ATTRIBUTES = (Public, ); }; }; 5BE25A4F1A0AA90E00C97C3E /* FBTweak+Dictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BE25A4D1A0AA90E00C97C3E /* FBTweak+Dictionary.m */; }; 5BE25A521A0AA9D500C97C3E /* _FBTweakDictionaryViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BE25A501A0AA9D500C97C3E /* _FBTweakDictionaryViewController.h */; }; @@ -92,6 +96,10 @@ 18EFE52C189F250700DA6A5D /* FBTweakInlineTestsMRR.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBTweakInlineTestsMRR.m; sourceTree = ""; }; 18EFE535189F38D500DA6A5D /* FBTweakEnabled.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBTweakEnabled.h; sourceTree = ""; }; 29E9F17A18E35C9C001EAF7D /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; + 5BACB3181A1280BD00C4F79D /* FBTweak+Array.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = "FBTweak+Array.h"; sourceTree = ""; tabWidth = 2; }; + 5BACB3191A1280BD00C4F79D /* FBTweak+Array.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = "FBTweak+Array.m"; sourceTree = ""; tabWidth = 2; }; + 5BACB31C1A12813C00C4F79D /* _FBTweakArrayViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _FBTweakArrayViewController.h; sourceTree = ""; }; + 5BACB31D1A12813C00C4F79D /* _FBTweakArrayViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = _FBTweakArrayViewController.m; sourceTree = ""; }; 5BE25A4C1A0AA90E00C97C3E /* FBTweak+Dictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FBTweak+Dictionary.h"; sourceTree = ""; }; 5BE25A4D1A0AA90E00C97C3E /* FBTweak+Dictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = "FBTweak+Dictionary.m"; sourceTree = ""; tabWidth = 2; }; 5BE25A501A0AA9D500C97C3E /* _FBTweakDictionaryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _FBTweakDictionaryViewController.h; sourceTree = ""; }; @@ -204,6 +212,8 @@ 18EFE4C0189EBEAD00DA6A5D /* FBTweakStore.m */, 5BE25A4C1A0AA90E00C97C3E /* FBTweak+Dictionary.h */, 5BE25A4D1A0AA90E00C97C3E /* FBTweak+Dictionary.m */, + 5BACB3181A1280BD00C4F79D /* FBTweak+Array.h */, + 5BACB3191A1280BD00C4F79D /* FBTweak+Array.m */, ); name = Model; sourceTree = ""; @@ -223,6 +233,8 @@ 18EFE4DC189EF75800DA6A5D /* _FBTweakTableViewCell.m */, 5BE25A501A0AA9D500C97C3E /* _FBTweakDictionaryViewController.h */, 5BE25A511A0AA9D500C97C3E /* _FBTweakDictionaryViewController.m */, + 5BACB31C1A12813C00C4F79D /* _FBTweakArrayViewController.h */, + 5BACB31D1A12813C00C4F79D /* _FBTweakArrayViewController.m */, ); name = UI; sourceTree = ""; @@ -249,6 +261,7 @@ 18EFE4B7189EBC3100DA6A5D /* FBTweak.h in Headers */, 18EFE4D5189EEBC500DA6A5D /* _FBTweakCategoryViewController.h in Headers */, 18EFE4D9189EEED800DA6A5D /* _FBTweakCollectionViewController.h in Headers */, + 5BACB31A1A1280BD00C4F79D /* FBTweak+Array.h in Headers */, 18EFE4B4189EBAC200DA6A5D /* FBTweakViewController.h in Headers */, 18EFE4C1189EBEAD00DA6A5D /* FBTweakStore.h in Headers */, 18EFE4B2189EBAC200DA6A5D /* FBTweakInline.h in Headers */, @@ -261,6 +274,7 @@ 5BE25A521A0AA9D500C97C3E /* _FBTweakDictionaryViewController.h in Headers */, 18EFE4DD189EF75800DA6A5D /* _FBTweakTableViewCell.h in Headers */, 184A94F018D26871005F2774 /* _FBTweakBindObserver.h in Headers */, + 5BACB31E1A12813C00C4F79D /* _FBTweakArrayViewController.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -345,6 +359,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 5BACB31B1A1280BD00C4F79D /* FBTweak+Array.m in Sources */, 5BE25A531A0AA9D500C97C3E /* _FBTweakDictionaryViewController.m in Sources */, 5BE25A4F1A0AA90E00C97C3E /* FBTweak+Dictionary.m in Sources */, 18EFE4A7189EBA9E00DA6A5D /* FBTweakViewController.m in Sources */, @@ -356,6 +371,7 @@ 18EFE528189F19B300DA6A5D /* FBTweakCategory.m in Sources */, 18EFE4D6189EEBC500DA6A5D /* _FBTweakCategoryViewController.m in Sources */, 18EFE4AF189EBABA00DA6A5D /* FBTweakShakeWindow.m in Sources */, + 5BACB31F1A12813C00C4F79D /* _FBTweakArrayViewController.m in Sources */, 18EFE4DA189EEED800DA6A5D /* _FBTweakCollectionViewController.m in Sources */, 184A94F118D26871005F2774 /* _FBTweakBindObserver.m in Sources */, ); diff --git a/FBTweak/FBTweak+Array.h b/FBTweak/FBTweak+Array.h new file mode 100644 index 00000000..b89acbc6 --- /dev/null +++ b/FBTweak/FBTweak+Array.h @@ -0,0 +1,25 @@ +// +// FBTweak+Array.h +// FBTweak +// +// Created by John McIntosh on 11/11/14. +// Copyright (c) 2014 Facebook. All rights reserved. +// + +#import "FBTweak.h" + + +/** + Implementation works by storing the dictionary in the tweak's `stepValue`. + */ +@interface FBTweak (Array) + +@property (nonatomic, copy, readwrite) NSArray *arrayValue; + +- (BOOL)isArray; + +@end + +FBTweak* FBArrayTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue); + +FBTweakValue FBArrayTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue); \ No newline at end of file diff --git a/FBTweak/FBTweak+Array.m b/FBTweak/FBTweak+Array.m new file mode 100644 index 00000000..c4e6f240 --- /dev/null +++ b/FBTweak/FBTweak+Array.m @@ -0,0 +1,68 @@ +// +// FBTweak+Array.m +// FBTweak +// +// Created by John McIntosh on 11/11/14. +// Copyright (c) 2014 Facebook. All rights reserved. +// + +#import "FBTweak+Array.h" +#import "FBTweakStore.h" +#import "FBTweakCollection.h" +#import "FBTweakCategory.h" + +@implementation FBTweak (Array) + +- (BOOL)isArray { + return (self.arrayValue != nil); +} + +- (NSArray *)arrayValue { + if ([self.stepValue isKindOfClass:[NSArray class]]) { + return self.stepValue; + } + return nil; +} + +- (void)setArrayValue:(NSArray *)arrayValue { + self.stepValue = arrayValue; +} + +FBTweak* FBArrayTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue) +{ + FBTweakStore *store = [FBTweakStore sharedInstance]; + FBTweakCategory *cat = [store tweakCategoryWithName:categoryName]; + + if (!cat) { + cat = [[FBTweakCategory alloc] initWithName:categoryName]; + [store addTweakCategory:cat]; + } + + FBTweakCollection *collection = [cat tweakCollectionWithName:collectionName]; + + if (!collection) { + collection = [[FBTweakCollection alloc] initWithName:collectionName]; + [cat addTweakCollection:collection]; + } + + + FBTweak *tweak = [collection tweakWithIdentifier:tweakName]; + + if (!tweak) { + tweak = [[FBTweak alloc] initWithIdentifier:tweakName]; + tweak.name = tweakName; + tweak.arrayValue = array; + tweak.defaultValue = defaultValue; + + [collection addTweak:tweak]; + } + return tweak; +} + +FBTweakValue FBArrayTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue) +{ + FBTweak *tweak = FBArrayTweak(categoryName, collectionName, tweakName, array, defaultValue); + return tweak.currentValue ?: tweak.defaultValue; +} + +@end diff --git a/FBTweak/FBTweak+Dictionary.h b/FBTweak/FBTweak+Dictionary.h index 856bae96..501db912 100644 --- a/FBTweak/FBTweak+Dictionary.h +++ b/FBTweak/FBTweak+Dictionary.h @@ -22,4 +22,4 @@ @end FBTweak* FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, id defaultKey); -FBTweakValue FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, id defaultKey); \ No newline at end of file +FBTweakValue FBDictionaryTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, id defaultKey); \ No newline at end of file diff --git a/FBTweak/_FBTweakArrayViewController.h b/FBTweak/_FBTweakArrayViewController.h new file mode 100644 index 00000000..c5544234 --- /dev/null +++ b/FBTweak/_FBTweakArrayViewController.h @@ -0,0 +1,17 @@ +// +// _FBTweakArrayViewController.h +// FBTweak +// +// Created by John McIntosh on 11/11/14. +// Copyright (c) 2014 Facebook. All rights reserved. +// + +#import + +@class FBTweak; + +@interface _FBTweakArrayViewController : UIViewController + +@property (nonatomic, strong) FBTweak *tweak; + +@end diff --git a/FBTweak/_FBTweakArrayViewController.m b/FBTweak/_FBTweakArrayViewController.m new file mode 100644 index 00000000..152beeb3 --- /dev/null +++ b/FBTweak/_FBTweakArrayViewController.m @@ -0,0 +1,75 @@ +// +// _FBTweakArrayViewController.m +// FBTweak +// +// Created by John McIntosh on 11/11/14. +// Copyright (c) 2014 Facebook. All rights reserved. +// + +#import "_FBTweakArrayViewController.h" +#import "FBTweak.h" +#import "FBTweak+Array.h" + +@interface _FBTweakArrayViewController () + +@property (nonatomic, strong) UITableView *tableView; + +@end + +@implementation _FBTweakArrayViewController + +- (void)viewDidLoad +{ + [super viewDidLoad]; + + _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; + _tableView.delegate = self; + _tableView.dataSource = self; + _tableView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); + [self.view addSubview:_tableView]; +} + +- (void)dealloc +{ + _tableView.delegate = nil; + _tableView.dataSource = nil; +} + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView +{ + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section +{ + return self.tweak.arrayValue.count; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath +{ + static NSString *_FBTweakDictionaryViewControllerCellIdentifier = @"_FBTweakDictionaryViewControllerCellIdentifier"; + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:_FBTweakDictionaryViewControllerCellIdentifier]; + if (cell == nil) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:_FBTweakDictionaryViewControllerCellIdentifier]; + } + + NSString *value = self.tweak.arrayValue[indexPath.row]; + cell.textLabel.text = value; + + cell.accessoryType = UITableViewCellAccessoryNone; + NSString *selectedValue = (self.tweak.currentValue ?: self.tweak.defaultValue); + if ([selectedValue isEqualToString:value]) { + cell.accessoryType = UITableViewCellAccessoryCheckmark; + } + + return cell; +} + +- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath +{ + NSString *value = self.tweak.arrayValue[indexPath.row]; + self.tweak.currentValue = value; + [self.navigationController popViewControllerAnimated:YES]; +} + +@end diff --git a/FBTweak/_FBTweakCollectionViewController.m b/FBTweak/_FBTweakCollectionViewController.m index f787eb81..2864f57e 100644 --- a/FBTweak/_FBTweakCollectionViewController.m +++ b/FBTweak/_FBTweakCollectionViewController.m @@ -13,6 +13,8 @@ #import "_FBTweakTableViewCell.h" #import "FBTweak+Dictionary.h" #import "_FBTweakDictionaryViewController.h" +#import "FBTweak+Array.h" +#import "_FBTweakArrayViewController.h" @interface _FBTweakCollectionViewController () @end @@ -139,6 +141,10 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath _FBTweakDictionaryViewController *vc = [[_FBTweakDictionaryViewController alloc] init]; vc.tweak = tweak; [self.navigationController pushViewController:vc animated:YES]; + } else if ([tweak isArray]) { + _FBTweakArrayViewController *vc = [[_FBTweakArrayViewController alloc] init]; + vc.tweak = tweak; + [self.navigationController pushViewController:vc animated:YES]; } } diff --git a/FBTweak/_FBTweakTableViewCell.m b/FBTweak/_FBTweakTableViewCell.m index e536d4da..2d67db2a 100644 --- a/FBTweak/_FBTweakTableViewCell.m +++ b/FBTweak/_FBTweakTableViewCell.m @@ -10,6 +10,7 @@ #import "FBTweak.h" #import "_FBTweakTableViewCell.h" #import "FBTweak+Dictionary.h" +#import "FBTweak+Array.h" typedef NS_ENUM(NSUInteger, _FBTweakTableViewCellMode) { _FBTweakTableViewCellModeNone = 0, @@ -19,6 +20,7 @@ typedef NS_ENUM(NSUInteger, _FBTweakTableViewCellMode) { _FBTweakTableViewCellModeString, _FBTweakTableViewCellModeAction, _FBTweakTableViewCellModeDictionary, + _FBTweakTableViewCellModeArray, }; @interface _FBTweakTableViewCell () @@ -100,6 +102,12 @@ - (void)layoutSubviews CGRect textBounds = CGRectMake(0, 0, textFieldWidth, self.bounds.size.height); _valueLabel.frame = CGRectIntegral(textBounds); _accessoryView.bounds = CGRectIntegral(textBounds); + } else if (_mode == _FBTweakTableViewCellModeArray) { + CGFloat margin = CGRectGetMinX(self.textLabel.frame); + CGFloat textFieldWidth = self.bounds.size.width - (margin * 3.0) - [self.textLabel sizeThatFits:CGSizeZero].width; + CGRect textBounds = CGRectMake(0, 0, textFieldWidth, self.bounds.size.height); + _valueLabel.frame = CGRectIntegral(textBounds); + _accessoryView.bounds = CGRectIntegral(textBounds); } // This positions the accessory view, so call it after updating its bounds. @@ -120,6 +128,8 @@ - (void)setTweak:(FBTweak *)tweak if ([tweak isDictionary]) { value = _tweak.dictionaryValue[value]; mode = _FBTweakTableViewCellModeDictionary; + } else if ([tweak isArray]) { + mode = _FBTweakTableViewCellModeArray; } else if ([value isKindOfClass:[NSString class]]) { mode = _FBTweakTableViewCellModeString; } else if ([value isKindOfClass:[NSNumber class]]) { @@ -230,6 +240,11 @@ - (void)_updateMode:(_FBTweakTableViewCellMode)mode _textField.hidden = YES; _stepper.hidden = YES; _valueLabel.hidden = NO; + } else if (_mode == _FBTweakTableViewCellModeArray) { + _switch.hidden = YES; + _textField.hidden = YES; + _stepper.hidden = YES; + _valueLabel.hidden = NO; } else { _switch.hidden = YES; _textField.hidden = YES; @@ -335,6 +350,13 @@ - (void)_updateValue:(FBTweakValue)value primary:(BOOL)primary write:(BOOL)write _valueLabel.text = displayValue; } } + } else if (_mode == _FBTweakTableViewCellModeArray) { + if (primary) { + if ([value isKindOfClass:[NSString class]]) { + NSString *displayValue = [value stringByAppendingString:@" >"]; + _valueLabel.text = displayValue; + } + } } } diff --git a/FBTweakExample/FBAppDelegate.m b/FBTweakExample/FBAppDelegate.m index 766f26c6..d70c2eb6 100644 --- a/FBTweakExample/FBAppDelegate.m +++ b/FBTweakExample/FBAppDelegate.m @@ -12,6 +12,7 @@ #import #import #import +#import #import "FBAppDelegate.h" @@ -92,6 +93,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( }; FBDictionaryTweak(@"Local Server", @"Auth", @"Login", dict, @"key1"); + FBArrayTweak(@"Local Server", @"Array", @"endpoint", @[@"success", @"failure", @"unauthorized"], @"success"); + return YES; } From 512ce6d117fa8e494cbbd804f5b5ac9531f227fc Mon Sep 17 00:00:00 2001 From: Chris Streeter Date: Wed, 10 Dec 2014 12:59:04 -0800 Subject: [PATCH 07/44] Allow UI to be launched with a specific category. --- FBTweak/FBTweakViewController.h | 10 +++++++++- FBTweak/FBTweakViewController.m | 16 ++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/FBTweak/FBTweakViewController.h b/FBTweak/FBTweakViewController.h index 580b1482..c946c952 100644 --- a/FBTweak/FBTweakViewController.h +++ b/FBTweak/FBTweakViewController.h @@ -28,10 +28,18 @@ extern NSString *const FBTweakShakeViewControllerDidDismissNotification; /** @abstract Create a tweak view controller. @param store The tweak store to show. Usually +[FBTweakStore sharedInstance]. - @discussion The designated initializer. + @discussion Calls -[initWithStore:category:] with a nil category. */ - (instancetype)initWithStore:(FBTweakStore *)store; +/** + @abstract Create a tweak view controller drilled-down to a specific category + @param store The tweak store to show. Usually +[FBTweakStore sharedInstance]. + @param name The tweak category to drill down to. Use nil to show all categories + @discussion The designated initializer. + */ +- (instancetype)initWithStore:(FBTweakStore *)store category:(NSString *)categoryName; + /** @abstract Responds to tweak view controller actions. @discussion Named {@ref tweaksDelegate} to avoid conflicting with UINavigationController. diff --git a/FBTweak/FBTweakViewController.m b/FBTweak/FBTweakViewController.m index 02d9cb5b..eef8d5c8 100644 --- a/FBTweak/FBTweakViewController.m +++ b/FBTweak/FBTweakViewController.m @@ -22,15 +22,27 @@ @implementation FBTweakViewController { } - (instancetype)initWithStore:(FBTweakStore *)store +{ + return [self initWithStore:store category:nil]; +} + +- (instancetype)initWithStore:(FBTweakStore *)store category:(NSString *)categoryName { if ((self = [super init])) { _store = store; - + _FBTweakCategoryViewController *categoryViewController = [[_FBTweakCategoryViewController alloc] initWithStore:store]; categoryViewController.delegate = self; [self pushViewController:categoryViewController animated:NO]; + + FBTweakCategory *category = nil; + if (categoryName && (category = [store tweakCategoryWithName:categoryName])) { + _FBTweakCollectionViewController *collectionViewController = [[_FBTweakCollectionViewController alloc] initWithTweakCategory:category]; + collectionViewController.delegate = self; + [self pushViewController:collectionViewController animated:YES]; + } } - + return self; } From 1daaacc3d5ef5746f9135a69d8a2bf8aa91986d3 Mon Sep 17 00:00:00 2001 From: Chris Streeter Date: Thu, 11 Dec 2014 11:59:30 -0800 Subject: [PATCH 08/44] Support additional types in _Generics Add support and tests for long and unsigned long types. --- FBTweak/FBTweakInlineInternal.h | 4 ++++ FBTweakTests/FBTweakInlineTestsARC.m | 33 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/FBTweak/FBTweakInlineInternal.h b/FBTweak/FBTweakInlineInternal.h index 32eddd1d..176d8c51 100644 --- a/FBTweak/FBTweakInlineInternal.h +++ b/FBTweak/FBTweakInlineInternal.h @@ -114,6 +114,10 @@ extern NSString *_FBTweakIdentifier(fb_tweak_entry *entry); const int: [currentValue intValue], \ unsigned int: [currentValue unsignedIntValue], \ const unsigned int: [currentValue unsignedIntValue], \ + long: [currentValue longValue], \ + const long: [currentValue longValue], \ + unsigned long: [currentValue unsignedLongValue], \ + const unsigned long: [currentValue unsignedLongValue], \ long long: [currentValue longLongValue], \ const long long: [currentValue longLongValue], \ unsigned long long: [currentValue unsignedLongLongValue], \ diff --git a/FBTweakTests/FBTweakInlineTestsARC.m b/FBTweakTests/FBTweakInlineTestsARC.m index 3cd44f7c..b5380ac4 100644 --- a/FBTweakTests/FBTweakInlineTestsARC.m +++ b/FBTweakTests/FBTweakInlineTestsARC.m @@ -15,6 +15,25 @@ #error ARC is required. #endif +typedef NS_ENUM(unsigned long, UnsignedLongEnum) { + UnsignedLongEnumOff, + UnsignedLongEnumVerbose, + UnsignedLongEnumInfo, + UnsignedLongEnumWarn, + UnsignedLongEnumError, +}; + +@interface FBTweakTestObject : NSObject + +@property (nonatomic, assign, readwrite) UnsignedLongEnum unsignedLongProperty; + +@end + +@implementation FBTweakTestObject + +@end + + @interface FBTweakInlineTestsARC : XCTestCase @end @@ -40,6 +59,12 @@ - (void)testValueTypes __attribute__((unused)) unsigned int testUnsignedInt = FBTweakValue(@"Unsigned Int", @"Unsigned Int", @"Unsigned Int", 1); XCTAssertEqual(testUnsignedInt, (unsigned int)1, @"Unsigned Int %d", testUnsignedInt); + __attribute__((unused)) long testLong = FBTweakValue(@"Long", @"Long", @"Long", -1); + XCTAssertEqual(testLong, (long)-1, @"Long %ld", testLong); + + __attribute__((unused)) unsigned long testUnsignedLong = FBTweakValue(@"Unsigned Long", @"Unsigned Long", @"Unsigned Long", 1); + XCTAssertEqual(testUnsignedLong, (unsigned long)1, @"Unsigned Long %lu", testUnsignedLong); + __attribute__((unused)) long long testLongLong = FBTweakValue(@"Long Long", @"Long Long", @"Long Long", -1); XCTAssertEqual(testLongLong, (long long)-1, @"Long Long %lld", testLongLong); @@ -111,6 +136,14 @@ - (void)testBind FBTweak *m = FBTweakInline(@"URL", @"Request", @"Bind", 5.0); m.currentValue = @(20.0); XCTAssertEqual(v.timeoutInterval, (NSTimeInterval)20.0, @"request %@ %@", v, m); + + FBTweakTestObject *o = [FBTweakTestObject new]; + FBTweakBind(o, unsignedLongProperty, @"Test", @"Object", @"Long", UnsignedLongEnumInfo, UnsignedLongEnumOff, UnsignedLongEnumError); + XCTAssertEqual(o.unsignedLongProperty, UnsignedLongEnumInfo, @"test object: %@", @(o.unsignedLongProperty)); + + FBTweak *oTweak = FBTweakInline(@"Test", @"Object", @"Long", UnsignedLongEnumInfo); + oTweak.currentValue = @(UnsignedLongEnumWarn); + XCTAssertEqual(o.unsignedLongProperty, UnsignedLongEnumWarn, @"test object: %@", @(o.unsignedLongProperty)); } @end From 466c40ef2d9d400d51c320504e9f367406c89aef Mon Sep 17 00:00:00 2001 From: Chris Streeter Date: Thu, 11 Dec 2014 13:55:14 -0800 Subject: [PATCH 09/44] Do not animate the second push --- FBTweak/FBTweakViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FBTweak/FBTweakViewController.m b/FBTweak/FBTweakViewController.m index eef8d5c8..5c863d36 100644 --- a/FBTweak/FBTweakViewController.m +++ b/FBTweak/FBTweakViewController.m @@ -39,7 +39,7 @@ - (instancetype)initWithStore:(FBTweakStore *)store category:(NSString *)categor if (categoryName && (category = [store tweakCategoryWithName:categoryName])) { _FBTweakCollectionViewController *collectionViewController = [[_FBTweakCollectionViewController alloc] initWithTweakCategory:category]; collectionViewController.delegate = self; - [self pushViewController:collectionViewController animated:YES]; + [self pushViewController:collectionViewController animated:NO]; } } From d3af09000bd1f00a2ac25ebebdb229d707e61a87 Mon Sep 17 00:00:00 2001 From: Grant Paul Date: Fri, 23 Jan 2015 10:12:06 -0800 Subject: [PATCH 10/44] Allow Tweaks to be used from within app extensions, by avoiding disallowed APIs. --- FBTweak/_FBTweakCategoryViewController.m | 35 ++++++++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/FBTweak/_FBTweakCategoryViewController.m b/FBTweak/_FBTweakCategoryViewController.m index ce112b87..8b863da8 100644 --- a/FBTweak/_FBTweakCategoryViewController.m +++ b/FBTweak/_FBTweakCategoryViewController.m @@ -85,12 +85,35 @@ - (void)_done - (void)_reset { - UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Are you sure?" - message:@"Are you sure you want to reset your tweaks? This cannot be undone." - delegate:self - cancelButtonTitle:@"Cancel" - otherButtonTitles:@"Reset", nil]; - [alert show]; +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 8000 + if ([UIAlertController class] != nil) { + UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Are you sure?" + message:@"Are you sure you want to reset your tweaks? This cannot be undone." + preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { + // do nothing + }]; + [alertController addAction:cancelAction]; + + UIAlertAction *resetAction = [UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { + [_store reset]; + }]; + [alertController addAction:resetAction]; + + [self presentViewController:alertController animated:YES completion:NULL]; + } else { +#endif + // To allow using Tweaks from within app extensions, which do not allow linking against UIAlertView, load the class dynamically. + // Note this codepath will never be executed in an app extension, since UIAlertController will always be available when they are. + UIAlertView *alert = [[NSClassFromString(@"UIAlertView") alloc] initWithTitle:@"Are you sure?" + message:@"Are you sure you want to reset your tweaks? This cannot be undone." + delegate:self + cancelButtonTitle:@"Cancel" + otherButtonTitles:@"Reset", nil]; + [alert show]; +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 8000 + } +#endif } - (void)_export From 9c6c3b41aba7cd7ccbf2dcdc96172c3d5288a940 Mon Sep 17 00:00:00 2001 From: John McIntosh Date: Sat, 24 Jan 2015 11:08:10 -0600 Subject: [PATCH 11/44] Cleanup dictionary implementation and example, and improve documentation --- FBTweak/FBTweak+Dictionary.h | 37 ++++++++++++++++++++-- FBTweak/FBTweak+Dictionary.m | 15 +++++---- FBTweak/_FBTweakDictionaryViewController.m | 2 -- FBTweak/_FBTweakTableViewCell.m | 7 ++-- FBTweakExample/FBAppDelegate.m | 29 +++++++++++------ 5 files changed, 64 insertions(+), 26 deletions(-) diff --git a/FBTweak/FBTweak+Dictionary.h b/FBTweak/FBTweak+Dictionary.h index 501db912..7eef64b1 100644 --- a/FBTweak/FBTweak+Dictionary.h +++ b/FBTweak/FBTweak+Dictionary.h @@ -13,13 +13,44 @@ */ @interface FBTweak (Dictionary) +/** + @abstract The keys of dictionary contained in the tweak. + @discussion Array containing string values for each of the keys in the dictionary. + */ @property (nonatomic, copy, readonly) NSArray *allKeys; -@property (nonatomic, copy, readonly) NSArray *allValues; + +/** + @abstract The dictionary contained by the tweak. + @discussion The current and default values of the tweak represent a key in + this dictionary. + */ @property (nonatomic, copy, readwrite) NSDictionary *dictionaryValue; +/** + @abstract Indicates whether the tweak instance represents a dictionary tweak. + @return YES if the instance represents a dictionary tweak. + */ - (BOOL)isDictionary; @end -FBTweak* FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, id defaultKey); -FBTweakValue FBDictionaryTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, id defaultKey); \ No newline at end of file + +/** + @abstract Loads a dictionary tweak defined inline. + @return A {@ref FBTweak} for the dictionary tweak. + */ +FBTweak* FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey); + +/** + @abstract Loads the key of a dictionary tweak inine. + @param dictionary A dictionary with string values for keys. + @return The current string key for the tweak, or the default key if none is set. + */ +NSString* FBDictionaryTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey); + +/** + @abstract Loads the dictionary's value associated with the key of a dictionary tweak inine. + @return The dictionary's value associated with the key for the tweak. If the current key is nil, + the value associated with the default key will be returned. + */ +FBTweakValue FBDictionaryTweakValueForKey(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey); \ No newline at end of file diff --git a/FBTweak/FBTweak+Dictionary.m b/FBTweak/FBTweak+Dictionary.m index 8f35d4c2..b4792c21 100644 --- a/FBTweak/FBTweak+Dictionary.m +++ b/FBTweak/FBTweak+Dictionary.m @@ -32,11 +32,7 @@ - (NSArray *)allKeys { return self.dictionaryValue.allKeys; } -- (NSArray *)allValues { - return self.dictionaryValue.allValues; -} - -FBTweak* FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, id defaultKey) +FBTweak* FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey) { FBTweakStore *store = [FBTweakStore sharedInstance]; FBTweakCategory *cat = [store tweakCategoryWithName:categoryName]; @@ -67,10 +63,17 @@ - (NSArray *)allValues { return tweak; } -FBTweakValue FBDictionaryTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, id defaultKey) +NSString* FBDictionaryTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey) { FBTweak *tweak = FBDictionaryTweak(categoryName, collectionName, tweakName, dictionary, defaultKey); return tweak.currentValue ?: tweak.defaultValue; } +FBTweakValue FBDictionaryTweakValueForKey(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey) +{ + FBTweak *tweak = FBDictionaryTweak(categoryName, collectionName, tweakName, dictionary, defaultKey); + NSString *key = tweak.currentValue ?: tweak.defaultValue; + return tweak.dictionaryValue[key]; +} + @end diff --git a/FBTweak/_FBTweakDictionaryViewController.m b/FBTweak/_FBTweakDictionaryViewController.m index 3a88b37a..628c7e0c 100644 --- a/FBTweak/_FBTweakDictionaryViewController.m +++ b/FBTweak/_FBTweakDictionaryViewController.m @@ -55,9 +55,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N NSArray *allKeys = [self allTweakKeys]; NSString *key = allKeys[indexPath.row]; - NSString *value = self.tweak.dictionaryValue[key]; cell.textLabel.text = key; - cell.detailTextLabel.text = value; cell.accessoryType = UITableViewCellAccessoryNone; NSString *selectedKey = (self.tweak.currentValue ?: self.tweak.defaultValue); diff --git a/FBTweak/_FBTweakTableViewCell.m b/FBTweak/_FBTweakTableViewCell.m index 2d67db2a..a02bfc00 100644 --- a/FBTweak/_FBTweakTableViewCell.m +++ b/FBTweak/_FBTweakTableViewCell.m @@ -126,7 +126,6 @@ - (void)setTweak:(FBTweak *)tweak _FBTweakTableViewCellMode mode = _FBTweakTableViewCellModeNone; if ([tweak isDictionary]) { - value = _tweak.dictionaryValue[value]; mode = _FBTweakTableViewCellModeDictionary; } else if ([tweak isArray]) { mode = _FBTweakTableViewCellModeArray; @@ -345,10 +344,8 @@ - (void)_updateValue:(FBTweakValue)value primary:(BOOL)primary write:(BOOL)write _textField.text = [NSString stringWithFormat:format, [value doubleValue]]; } else if (_mode == _FBTweakTableViewCellModeDictionary) { if (primary) { - if ([value isKindOfClass:[NSString class]]) { - NSString *displayValue = [value stringByAppendingString:@" >"]; - _valueLabel.text = displayValue; - } + NSString *displayValue = [[value description] stringByAppendingString:@" >"]; + _valueLabel.text = displayValue; } } else if (_mode == _FBTweakTableViewCellModeArray) { if (primary) { diff --git a/FBTweakExample/FBAppDelegate.m b/FBTweakExample/FBAppDelegate.m index d70c2eb6..e5694507 100644 --- a/FBTweakExample/FBAppDelegate.m +++ b/FBTweakExample/FBAppDelegate.m @@ -24,7 +24,9 @@ @implementation FBAppDelegate { UIViewController *_rootViewController; UILabel *_label; + UIButton *_tweaksButton; FBTweak *_flipTweak; + FBTweak *_buttonColorTweak; } FBTweakAction(@"Actions", @"Global", @"Hello", ^{ @@ -71,11 +73,11 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( CGRect tweaksButtonFrame = _window.bounds; tweaksButtonFrame.origin.y = _label.bounds.size.height; tweaksButtonFrame.size.height = tweaksButtonFrame.size.height - _label.bounds.size.height; - UIButton *tweaksButton = [[UIButton alloc] initWithFrame:tweaksButtonFrame]; - [tweaksButton setTitle:@"Show Tweaks" forState:UIControlStateNormal]; - [tweaksButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; - [tweaksButton addTarget:self action:@selector(buttonTapped) forControlEvents:UIControlEventTouchUpInside]; - [_rootViewController.view addSubview:tweaksButton]; + _tweaksButton = [[UIButton alloc] initWithFrame:tweaksButtonFrame]; + [_tweaksButton setTitle:@"Show Tweaks" forState:UIControlStateNormal]; + [_tweaksButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [_tweaksButton addTarget:self action:@selector(buttonTapped) forControlEvents:UIControlEventTouchUpInside]; + [_rootViewController.view addSubview:_tweaksButton]; FBTweak *animationDurationTweak = FBTweakInline(@"Content", @"Animation", @"Duration", 0.5); animationDurationTweak.stepValue = [NSNumber numberWithFloat:0.005f]; @@ -87,12 +89,15 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [alert show]; }); - NSDictionary *dict = @{@"key1": @"value1", - @"key2": @"value2", - @"key3": @"value3", + NSDictionary *dict = @{@"black": [UIColor blackColor], + @"blue": [UIColor blueColor], + @"green": [UIColor greenColor], }; - FBDictionaryTweak(@"Local Server", @"Auth", @"Login", dict, @"key1"); - + _buttonColorTweak = FBDictionaryTweak(@"Content", @"Tweaks Button", @"Color", dict, @"black"); + [_buttonColorTweak addObserver:self]; + UIColor *color = FBDictionaryTweakValueForKey(@"Content", @"Tweaks Button", @"Color", dict, @"black"); + [_tweaksButton setTitleColor:color forState:UIControlStateNormal]; + FBArrayTweak(@"Local Server", @"Array", @"endpoint", @[@"success", @"failure", @"unauthorized"], @"success"); return YES; @@ -103,6 +108,10 @@ - (void)tweakDidChange:(FBTweak *)tweak if (tweak == _flipTweak) { _window.layer.sublayerTransform = CATransform3DMakeScale(1.0, [_flipTweak.currentValue boolValue] ? -1.0 : 1.0, 1.0); } + else if (tweak == _buttonColorTweak) { + UIColor *titleColor = [_buttonColorTweak dictionaryValue][_buttonColorTweak.currentValue]; + [_tweaksButton setTitleColor:titleColor forState:UIControlStateNormal]; + } } - (void)buttonTapped From 93f947383cffd35617d71be6dec60cab2d4ad4ad Mon Sep 17 00:00:00 2001 From: John McIntosh Date: Sat, 24 Jan 2015 11:24:54 -0600 Subject: [PATCH 12/44] Improve array tweak documentation --- FBTweak/FBTweak+Array.h | 21 ++++++++++++++++++++- FBTweak/FBTweak+Array.m | 1 - FBTweak/FBTweak+Dictionary.m | 1 - FBTweak/_FBTweakArrayViewController.m | 9 +++++---- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/FBTweak/FBTweak+Array.h b/FBTweak/FBTweak+Array.h index b89acbc6..94b80233 100644 --- a/FBTweak/FBTweak+Array.h +++ b/FBTweak/FBTweak+Array.h @@ -10,16 +10,35 @@ /** - Implementation works by storing the dictionary in the tweak's `stepValue`. + Implementation works by storing the array in the tweak's `stepValue`. The values of the array are + exposed through the Tweaks UI through the value's `description`. */ @interface FBTweak (Array) +/** + @abstract The array contained by the tweak. + @discussion The current and default values of the tweak contain an item in this array. + */ @property (nonatomic, copy, readwrite) NSArray *arrayValue; +/** + @abstract Indicates whether the tweak instance represents an array tweak. + @return YES if the instance represents an array tweak. + */ - (BOOL)isArray; @end + +/** + @abstract Loads an array tweak defined inline. + @return A {@ref FBTweak} for the array tweak. + */ FBTweak* FBArrayTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue); +/** + @abstract Loads the array's value of an array tweak inine. + @return The array's value of the tweak. If the current value is nil, the default value will be + returned. + */ FBTweakValue FBArrayTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue); \ No newline at end of file diff --git a/FBTweak/FBTweak+Array.m b/FBTweak/FBTweak+Array.m index c4e6f240..283aacac 100644 --- a/FBTweak/FBTweak+Array.m +++ b/FBTweak/FBTweak+Array.m @@ -45,7 +45,6 @@ - (void)setArrayValue:(NSArray *)arrayValue { [cat addTweakCollection:collection]; } - FBTweak *tweak = [collection tweakWithIdentifier:tweakName]; if (!tweak) { diff --git a/FBTweak/FBTweak+Dictionary.m b/FBTweak/FBTweak+Dictionary.m index b4792c21..6250d132 100644 --- a/FBTweak/FBTweak+Dictionary.m +++ b/FBTweak/FBTweak+Dictionary.m @@ -49,7 +49,6 @@ - (NSArray *)allKeys { [cat addTweakCollection:collection]; } - FBTweak *tweak = [collection tweakWithIdentifier:tweakName]; if (!tweak) { diff --git a/FBTweak/_FBTweakArrayViewController.m b/FBTweak/_FBTweakArrayViewController.m index 152beeb3..68db00b5 100644 --- a/FBTweak/_FBTweakArrayViewController.m +++ b/FBTweak/_FBTweakArrayViewController.m @@ -53,12 +53,13 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:_FBTweakDictionaryViewControllerCellIdentifier]; } - NSString *value = self.tweak.arrayValue[indexPath.row]; - cell.textLabel.text = value; + FBTweakValue rowValue = self.tweak.arrayValue[indexPath.row]; + NSString *stringValue = [rowValue description]; + cell.textLabel.text = stringValue; cell.accessoryType = UITableViewCellAccessoryNone; - NSString *selectedValue = (self.tweak.currentValue ?: self.tweak.defaultValue); - if ([selectedValue isEqualToString:value]) { + FBTweakValue selectedValue = (self.tweak.currentValue ?: self.tweak.defaultValue); + if ([selectedValue isEqual:rowValue]) { cell.accessoryType = UITableViewCellAccessoryCheckmark; } From 8ef42ade5447f386b27da52fa979dee13b9e5c37 Mon Sep 17 00:00:00 2001 From: John McIntosh Date: Sat, 24 Jan 2015 11:30:15 -0600 Subject: [PATCH 13/44] Improve dictionary tweak example --- FBTweakExample/FBAppDelegate.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/FBTweakExample/FBAppDelegate.m b/FBTweakExample/FBAppDelegate.m index e5694507..6d06f8a3 100644 --- a/FBTweakExample/FBAppDelegate.m +++ b/FBTweakExample/FBAppDelegate.m @@ -95,7 +95,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( }; _buttonColorTweak = FBDictionaryTweak(@"Content", @"Tweaks Button", @"Color", dict, @"black"); [_buttonColorTweak addObserver:self]; - UIColor *color = FBDictionaryTweakValueForKey(@"Content", @"Tweaks Button", @"Color", dict, @"black"); + NSString *key = _buttonColorTweak.currentValue ?: _buttonColorTweak.defaultValue; + UIColor *color = _buttonColorTweak.dictionaryValue[key]; [_tweaksButton setTitleColor:color forState:UIControlStateNormal]; FBArrayTweak(@"Local Server", @"Array", @"endpoint", @[@"success", @"failure", @"unauthorized"], @"success"); @@ -109,7 +110,8 @@ - (void)tweakDidChange:(FBTweak *)tweak _window.layer.sublayerTransform = CATransform3DMakeScale(1.0, [_flipTweak.currentValue boolValue] ? -1.0 : 1.0, 1.0); } else if (tweak == _buttonColorTweak) { - UIColor *titleColor = [_buttonColorTweak dictionaryValue][_buttonColorTweak.currentValue]; + NSString *key = _buttonColorTweak.currentValue ?: _buttonColorTweak.defaultValue; + UIColor *titleColor = [_buttonColorTweak dictionaryValue][key]; [_tweaksButton setTitleColor:titleColor forState:UIControlStateNormal]; } } From d159efa5ce8ab31f40c20f1d72324a205405e7b3 Mon Sep 17 00:00:00 2001 From: John McIntosh Date: Sat, 24 Jan 2015 11:51:13 -0600 Subject: [PATCH 14/44] Improve array example --- FBTweak/_FBTweakTableViewCell.m | 1 + FBTweakExample/FBAppDelegate.m | 14 +++++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/FBTweak/_FBTweakTableViewCell.m b/FBTweak/_FBTweakTableViewCell.m index a02bfc00..635a5097 100644 --- a/FBTweak/_FBTweakTableViewCell.m +++ b/FBTweak/_FBTweakTableViewCell.m @@ -128,6 +128,7 @@ - (void)setTweak:(FBTweak *)tweak if ([tweak isDictionary]) { mode = _FBTweakTableViewCellModeDictionary; } else if ([tweak isArray]) { + value = [value description]; mode = _FBTweakTableViewCellModeArray; } else if ([value isKindOfClass:[NSString class]]) { mode = _FBTweakTableViewCellModeString; diff --git a/FBTweakExample/FBAppDelegate.m b/FBTweakExample/FBAppDelegate.m index 6d06f8a3..92be829b 100644 --- a/FBTweakExample/FBAppDelegate.m +++ b/FBTweakExample/FBAppDelegate.m @@ -25,8 +25,9 @@ @implementation FBAppDelegate { UILabel *_label; UIButton *_tweaksButton; - FBTweak *_flipTweak; FBTweak *_buttonColorTweak; + FBTweak *_flipTweak; + FBTweak *_rotationTweak; } FBTweakAction(@"Actions", @"Global", @"Hello", ^{ @@ -99,8 +100,11 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( UIColor *color = _buttonColorTweak.dictionaryValue[key]; [_tweaksButton setTitleColor:color forState:UIControlStateNormal]; - FBArrayTweak(@"Local Server", @"Array", @"endpoint", @[@"success", @"failure", @"unauthorized"], @"success"); - + _rotationTweak = FBArrayTweak(@"Content", @"Text", @"Rotation (radians)", @[@(0), @(M_PI_4), @(M_PI_2)], @(0)); + FBTweakValue rotation = _rotationTweak.currentValue ?: _rotationTweak.defaultValue; + _label.transform = CGAffineTransformRotate(CGAffineTransformIdentity, [rotation floatValue]); + [_rotationTweak addObserver:self]; + return YES; } @@ -114,6 +118,10 @@ - (void)tweakDidChange:(FBTweak *)tweak UIColor *titleColor = [_buttonColorTweak dictionaryValue][key]; [_tweaksButton setTitleColor:titleColor forState:UIControlStateNormal]; } + else if (tweak == _rotationTweak) { + FBTweakValue value = _rotationTweak.currentValue ?: _rotationTweak.defaultValue; + _label.transform = CGAffineTransformRotate(CGAffineTransformIdentity, [value floatValue]); + } } - (void)buttonTapped From 9f6ff57938bef7f7dc0b282f7b77b1523a3eda64 Mon Sep 17 00:00:00 2001 From: John McIntosh Date: Sat, 24 Jan 2015 12:05:46 -0600 Subject: [PATCH 15/44] Cleanup documentation and source formatting --- FBTweak/FBTweak+Array.h | 15 ++++++++------- FBTweak/FBTweak+Array.m | 15 ++++++++------- FBTweak/FBTweak+Dictionary.h | 15 ++++++++------- FBTweak/FBTweak+Dictionary.m | 15 ++++++++------- FBTweak/_FBTweakArrayViewController.h | 21 ++++++++++++++------- FBTweak/_FBTweakArrayViewController.m | 15 ++++++++------- FBTweak/_FBTweakCollectionViewController.m | 14 +++++++------- FBTweak/_FBTweakDictionaryViewController.h | 21 ++++++++++++++------- FBTweak/_FBTweakDictionaryViewController.m | 15 ++++++++------- FBTweak/_FBTweakTableViewCell.m | 18 +++++++++--------- 10 files changed, 92 insertions(+), 72 deletions(-) diff --git a/FBTweak/FBTweak+Array.h b/FBTweak/FBTweak+Array.h index 94b80233..a22c587f 100644 --- a/FBTweak/FBTweak+Array.h +++ b/FBTweak/FBTweak+Array.h @@ -1,10 +1,11 @@ -// -// FBTweak+Array.h -// FBTweak -// -// Created by John McIntosh on 11/11/14. -// Copyright (c) 2014 Facebook. All rights reserved. -// +/** + Copyright (c) 2014-present, Facebook, Inc. + All rights reserved. + + This source code is licensed under the BSD-style license found in the + LICENSE file in the root directory of this source tree. An additional grant + of patent rights can be found in the PATENTS file in the same directory. + */ #import "FBTweak.h" diff --git a/FBTweak/FBTweak+Array.m b/FBTweak/FBTweak+Array.m index 283aacac..5a45a69e 100644 --- a/FBTweak/FBTweak+Array.m +++ b/FBTweak/FBTweak+Array.m @@ -1,10 +1,11 @@ -// -// FBTweak+Array.m -// FBTweak -// -// Created by John McIntosh on 11/11/14. -// Copyright (c) 2014 Facebook. All rights reserved. -// +/** + Copyright (c) 2014-present, Facebook, Inc. + All rights reserved. + + This source code is licensed under the BSD-style license found in the + LICENSE file in the root directory of this source tree. An additional grant + of patent rights can be found in the PATENTS file in the same directory. + */ #import "FBTweak+Array.h" #import "FBTweakStore.h" diff --git a/FBTweak/FBTweak+Dictionary.h b/FBTweak/FBTweak+Dictionary.h index 7eef64b1..db58f5e5 100644 --- a/FBTweak/FBTweak+Dictionary.h +++ b/FBTweak/FBTweak+Dictionary.h @@ -1,10 +1,11 @@ -// -// FBTweak+Dictionary.h -// FBTweak -// -// Created by John McIntosh on 11/5/14. -// Copyright (c) 2014 Facebook. All rights reserved. -// +/** + Copyright (c) 2014-present, Facebook, Inc. + All rights reserved. + + This source code is licensed under the BSD-style license found in the + LICENSE file in the root directory of this source tree. An additional grant + of patent rights can be found in the PATENTS file in the same directory. + */ #import "FBTweak.h" diff --git a/FBTweak/FBTweak+Dictionary.m b/FBTweak/FBTweak+Dictionary.m index 6250d132..92b0de5a 100644 --- a/FBTweak/FBTweak+Dictionary.m +++ b/FBTweak/FBTweak+Dictionary.m @@ -1,10 +1,11 @@ -// -// FBTweak+Dictionary.m -// FBTweak -// -// Created by John McIntosh on 11/5/14. -// Copyright (c) 2014 Facebook. All rights reserved. -// +/** + Copyright (c) 2014-present, Facebook, Inc. + All rights reserved. + + This source code is licensed under the BSD-style license found in the + LICENSE file in the root directory of this source tree. An additional grant + of patent rights can be found in the PATENTS file in the same directory. + */ #import "FBTweak+Dictionary.h" #import "FBTweakStore.h" diff --git a/FBTweak/_FBTweakArrayViewController.h b/FBTweak/_FBTweakArrayViewController.h index c5544234..3f5693ff 100644 --- a/FBTweak/_FBTweakArrayViewController.h +++ b/FBTweak/_FBTweakArrayViewController.h @@ -1,17 +1,24 @@ -// -// _FBTweakArrayViewController.h -// FBTweak -// -// Created by John McIntosh on 11/11/14. -// Copyright (c) 2014 Facebook. All rights reserved. -// +/** + Copyright (c) 2014-present, Facebook, Inc. + All rights reserved. + + This source code is licensed under the BSD-style license found in the + LICENSE file in the root directory of this source tree. An additional grant + of patent rights can be found in the PATENTS file in the same directory. + */ #import @class FBTweak; +/** + @abstract Displays list of values in an array tweak. + */ @interface _FBTweakArrayViewController : UIViewController +/** + @abstract The array tweak to display in the view controller. + */ @property (nonatomic, strong) FBTweak *tweak; @end diff --git a/FBTweak/_FBTweakArrayViewController.m b/FBTweak/_FBTweakArrayViewController.m index 68db00b5..36e9eac8 100644 --- a/FBTweak/_FBTweakArrayViewController.m +++ b/FBTweak/_FBTweakArrayViewController.m @@ -1,10 +1,11 @@ -// -// _FBTweakArrayViewController.m -// FBTweak -// -// Created by John McIntosh on 11/11/14. -// Copyright (c) 2014 Facebook. All rights reserved. -// +/** + Copyright (c) 2014-present, Facebook, Inc. + All rights reserved. + + This source code is licensed under the BSD-style license found in the + LICENSE file in the root directory of this source tree. An additional grant + of patent rights can be found in the PATENTS file in the same directory. + */ #import "_FBTweakArrayViewController.h" #import "FBTweak.h" diff --git a/FBTweak/_FBTweakCollectionViewController.m b/FBTweak/_FBTweakCollectionViewController.m index 2864f57e..1cf2088b 100644 --- a/FBTweak/_FBTweakCollectionViewController.m +++ b/FBTweak/_FBTweakCollectionViewController.m @@ -66,10 +66,10 @@ - (void)viewWillAppear:(BOOL)animated - (void)_reloadData { - _sortedCollections = [_tweakCategory.tweakCollections sortedArrayUsingComparator:^(FBTweakCollection *a, FBTweakCollection *b) { - return [a.name localizedStandardCompare:b.name]; - }]; - [_tableView reloadData]; + _sortedCollections = [_tweakCategory.tweakCollections sortedArrayUsingComparator:^(FBTweakCollection *a, FBTweakCollection *b) { + return [a.name localizedStandardCompare:b.name]; + }]; + [_tableView reloadData]; } - (void)_done @@ -142,9 +142,9 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath vc.tweak = tweak; [self.navigationController pushViewController:vc animated:YES]; } else if ([tweak isArray]) { - _FBTweakArrayViewController *vc = [[_FBTweakArrayViewController alloc] init]; - vc.tweak = tweak; - [self.navigationController pushViewController:vc animated:YES]; + _FBTweakArrayViewController *vc = [[_FBTweakArrayViewController alloc] init]; + vc.tweak = tweak; + [self.navigationController pushViewController:vc animated:YES]; } } diff --git a/FBTweak/_FBTweakDictionaryViewController.h b/FBTweak/_FBTweakDictionaryViewController.h index cb6b3843..475a79e4 100644 --- a/FBTweak/_FBTweakDictionaryViewController.h +++ b/FBTweak/_FBTweakDictionaryViewController.h @@ -1,17 +1,24 @@ -// -// _FBTweakDictionaryViewController.h -// FBTweak -// -// Created by John McIntosh on 11/5/14. -// Copyright (c) 2014 Facebook. All rights reserved. -// +/** + Copyright (c) 2014-present, Facebook, Inc. + All rights reserved. + + This source code is licensed under the BSD-style license found in the + LICENSE file in the root directory of this source tree. An additional grant + of patent rights can be found in the PATENTS file in the same directory. + */ #import @class FBTweak; +/** + @abstract Displays list of keys in a dictionary tweak. + */ @interface _FBTweakDictionaryViewController : UIViewController +/** + @abstract The dictionary tweak to display in the view controller. + */ @property (nonatomic, strong) FBTweak *tweak; @end diff --git a/FBTweak/_FBTweakDictionaryViewController.m b/FBTweak/_FBTweakDictionaryViewController.m index 628c7e0c..94c313a7 100644 --- a/FBTweak/_FBTweakDictionaryViewController.m +++ b/FBTweak/_FBTweakDictionaryViewController.m @@ -1,10 +1,11 @@ -// -// _FBTweakDictionaryViewController.m -// FBTweak -// -// Created by John McIntosh on 11/5/14. -// Copyright (c) 2014 Facebook. All rights reserved. -// +/** + Copyright (c) 2014-present, Facebook, Inc. + All rights reserved. + + This source code is licensed under the BSD-style license found in the + LICENSE file in the root directory of this source tree. An additional grant + of patent rights can be found in the PATENTS file in the same directory. + */ #import "_FBTweakDictionaryViewController.h" #import "FBTweak.h" diff --git a/FBTweak/_FBTweakTableViewCell.m b/FBTweak/_FBTweakTableViewCell.m index 635a5097..5829ae3e 100644 --- a/FBTweak/_FBTweakTableViewCell.m +++ b/FBTweak/_FBTweakTableViewCell.m @@ -40,7 +40,7 @@ - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier; { if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier])) { _accessoryView = [[UIView alloc] init]; - + _switch = [[UISwitch alloc] init]; [_switch addTarget:self action:@selector(_switchChanged:) forControlEvents:UIControlEventValueChanged]; [_accessoryView addSubview:_switch]; @@ -58,7 +58,7 @@ - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier; _valueLabel.textAlignment = NSTextAlignmentRight; [_accessoryView addSubview:_valueLabel]; } - + return self; } @@ -109,7 +109,7 @@ - (void)layoutSubviews _valueLabel.frame = CGRectIntegral(textBounds); _accessoryView.bounds = CGRectIntegral(textBounds); } - + // This positions the accessory view, so call it after updating its bounds. [super layoutSubviews]; } @@ -155,11 +155,11 @@ - (void)setTweak:(FBTweak *)tweak - (void)_updateMode:(_FBTweakTableViewCellMode)mode { _mode = mode; - + self.accessoryView = _accessoryView; self.accessoryType = UITableViewCellAccessoryNone; self.selectionStyle = UITableViewCellSelectionStyleNone; - + if (_mode == _FBTweakTableViewCellModeBoolean) { _switch.hidden = NO; _textField.hidden = YES; @@ -176,13 +176,13 @@ - (void)_updateMode:(_FBTweakTableViewCellMode)mode } else { _stepper.stepValue = 1.0; } - + if (_tweak.minimumValue != nil) { _stepper.minimumValue = [_tweak.minimumValue longLongValue]; } else { _stepper.minimumValue = [_tweak.defaultValue longLongValue] / 10.0; } - + if (_tweak.maximumValue != nil) { _stepper.maximumValue = [_tweak.maximumValue longLongValue]; } else { @@ -261,11 +261,11 @@ - (void)_updateMode:(_FBTweakTableViewCellMode)mode - (void)setSelected:(BOOL)selected animated:(BOOL)animated { [super setSelected:selected animated:animated]; - + if (_mode == _FBTweakTableViewCellModeAction) { if (selected) { [self setSelected:NO animated:YES]; - + dispatch_block_t block = _tweak.defaultValue; if (block != NULL) { block(); From 2248aa79c6984462681647806bd7bf5e5c3ab1ac Mon Sep 17 00:00:00 2001 From: John McIntosh Date: Sat, 24 Jan 2015 12:08:43 -0600 Subject: [PATCH 16/44] Project file cleanup --- FBTweak.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FBTweak.xcodeproj/project.pbxproj b/FBTweak.xcodeproj/project.pbxproj index 85a57103..005f0efb 100644 --- a/FBTweak.xcodeproj/project.pbxproj +++ b/FBTweak.xcodeproj/project.pbxproj @@ -90,7 +90,7 @@ 18EFE4D7189EEED800DA6A5D /* _FBTweakCollectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _FBTweakCollectionViewController.h; sourceTree = ""; }; 18EFE4D8189EEED800DA6A5D /* _FBTweakCollectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = _FBTweakCollectionViewController.m; sourceTree = ""; }; 18EFE4DB189EF75800DA6A5D /* _FBTweakTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _FBTweakTableViewCell.h; sourceTree = ""; }; - 18EFE4DC189EF75800DA6A5D /* _FBTweakTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = _FBTweakTableViewCell.m; sourceTree = ""; tabWidth = 2; }; + 18EFE4DC189EF75800DA6A5D /* _FBTweakTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = _FBTweakTableViewCell.m; sourceTree = ""; }; 18EFE525189F19B300DA6A5D /* FBTweakCategory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBTweakCategory.h; sourceTree = ""; }; 18EFE526189F19B300DA6A5D /* FBTweakCategory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBTweakCategory.m; sourceTree = ""; }; 18EFE52C189F250700DA6A5D /* FBTweakInlineTestsMRR.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBTweakInlineTestsMRR.m; sourceTree = ""; }; From dbd624679c62f37b942667fa0c5d5fd884d0edaa Mon Sep 17 00:00:00 2001 From: John McIntosh Date: Sat, 24 Jan 2015 12:14:48 -0600 Subject: [PATCH 17/44] Cleanup formatting --- FBTweak/FBTweak+Array.h | 2 +- FBTweak/FBTweak+Array.m | 9 ++-- FBTweak/FBTweak+Dictionary.m | 12 +++-- FBTweak/_FBTweakArrayViewController.m | 62 +++++++++++----------- FBTweak/_FBTweakDictionaryViewController.m | 3 +- 5 files changed, 48 insertions(+), 40 deletions(-) diff --git a/FBTweak/FBTweak+Array.h b/FBTweak/FBTweak+Array.h index a22c587f..529d8ea4 100644 --- a/FBTweak/FBTweak+Array.h +++ b/FBTweak/FBTweak+Array.h @@ -42,4 +42,4 @@ FBTweak* FBArrayTweak(NSString *categoryName, NSString *collectionName, NSString @return The array's value of the tweak. If the current value is nil, the default value will be returned. */ -FBTweakValue FBArrayTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue); \ No newline at end of file +FBTweakValue FBArrayTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue); diff --git a/FBTweak/FBTweak+Array.m b/FBTweak/FBTweak+Array.m index 5a45a69e..1f07e025 100644 --- a/FBTweak/FBTweak+Array.m +++ b/FBTweak/FBTweak+Array.m @@ -14,18 +14,21 @@ @implementation FBTweak (Array) -- (BOOL)isArray { +- (BOOL)isArray +{ return (self.arrayValue != nil); } -- (NSArray *)arrayValue { +- (NSArray *)arrayValue +{ if ([self.stepValue isKindOfClass:[NSArray class]]) { return self.stepValue; } return nil; } -- (void)setArrayValue:(NSArray *)arrayValue { +- (void)setArrayValue:(NSArray *)arrayValue +{ self.stepValue = arrayValue; } diff --git a/FBTweak/FBTweak+Dictionary.m b/FBTweak/FBTweak+Dictionary.m index 92b0de5a..63272639 100644 --- a/FBTweak/FBTweak+Dictionary.m +++ b/FBTweak/FBTweak+Dictionary.m @@ -14,22 +14,26 @@ @implementation FBTweak (Dictionary) -- (BOOL)isDictionary { +- (BOOL)isDictionary +{ return (self.dictionaryValue != nil); } -- (NSDictionary *)dictionaryValue { +- (NSDictionary *)dictionaryValue +{ if ([self.stepValue isKindOfClass:[NSDictionary class]]) { return self.stepValue; } return nil; } -- (void)setDictionaryValue:(NSDictionary *)dictionaryValue { +- (void)setDictionaryValue:(NSDictionary *)dictionaryValue +{ self.stepValue = dictionaryValue; } -- (NSArray *)allKeys { +- (NSArray *)allKeys +{ return self.dictionaryValue.allKeys; } diff --git a/FBTweak/_FBTweakArrayViewController.m b/FBTweak/_FBTweakArrayViewController.m index 36e9eac8..681d71f0 100644 --- a/FBTweak/_FBTweakArrayViewController.m +++ b/FBTweak/_FBTweakArrayViewController.m @@ -21,57 +21,57 @@ @implementation _FBTweakArrayViewController - (void)viewDidLoad { - [super viewDidLoad]; - - _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; - _tableView.delegate = self; - _tableView.dataSource = self; - _tableView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); - [self.view addSubview:_tableView]; + [super viewDidLoad]; + + _tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped]; + _tableView.delegate = self; + _tableView.dataSource = self; + _tableView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); + [self.view addSubview:_tableView]; } - (void)dealloc { - _tableView.delegate = nil; - _tableView.dataSource = nil; + _tableView.delegate = nil; + _tableView.dataSource = nil; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - return 1; + return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return self.tweak.arrayValue.count; + return self.tweak.arrayValue.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - static NSString *_FBTweakDictionaryViewControllerCellIdentifier = @"_FBTweakDictionaryViewControllerCellIdentifier"; - UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:_FBTweakDictionaryViewControllerCellIdentifier]; - if (cell == nil) { - cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:_FBTweakDictionaryViewControllerCellIdentifier]; - } - - FBTweakValue rowValue = self.tweak.arrayValue[indexPath.row]; - NSString *stringValue = [rowValue description]; - cell.textLabel.text = stringValue; - - cell.accessoryType = UITableViewCellAccessoryNone; - FBTweakValue selectedValue = (self.tweak.currentValue ?: self.tweak.defaultValue); - if ([selectedValue isEqual:rowValue]) { - cell.accessoryType = UITableViewCellAccessoryCheckmark; - } - - return cell; + static NSString *_FBTweakDictionaryViewControllerCellIdentifier = @"_FBTweakDictionaryViewControllerCellIdentifier"; + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:_FBTweakDictionaryViewControllerCellIdentifier]; + if (cell == nil) { + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:_FBTweakDictionaryViewControllerCellIdentifier]; + } + + FBTweakValue rowValue = self.tweak.arrayValue[indexPath.row]; + NSString *stringValue = [rowValue description]; + cell.textLabel.text = stringValue; + + cell.accessoryType = UITableViewCellAccessoryNone; + FBTweakValue selectedValue = (self.tweak.currentValue ?: self.tweak.defaultValue); + if ([selectedValue isEqual:rowValue]) { + cell.accessoryType = UITableViewCellAccessoryCheckmark; + } + + return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - NSString *value = self.tweak.arrayValue[indexPath.row]; - self.tweak.currentValue = value; - [self.navigationController popViewControllerAnimated:YES]; + NSString *value = self.tweak.arrayValue[indexPath.row]; + self.tweak.currentValue = value; + [self.navigationController popViewControllerAnimated:YES]; } @end diff --git a/FBTweak/_FBTweakDictionaryViewController.m b/FBTweak/_FBTweakDictionaryViewController.m index 94c313a7..83899905 100644 --- a/FBTweak/_FBTweakDictionaryViewController.m +++ b/FBTweak/_FBTweakDictionaryViewController.m @@ -76,7 +76,8 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath [self.navigationController popViewControllerAnimated:YES]; } -- (NSArray *)allTweakKeys { +- (NSArray *)allTweakKeys +{ return [self.tweak.allKeys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { return [obj1 compare:obj2]; }]; From fe61e67301e280d8d6eeb2f221fbb48ae4689813 Mon Sep 17 00:00:00 2001 From: John McIntosh Date: Sat, 24 Jan 2015 12:28:37 -0600 Subject: [PATCH 18/44] Add Tests --- FBTweak/FBTweakInline.h | 2 ++ FBTweakTests/FBTweakInlineTestsARC.m | 9 +++++++++ FBTweakTests/FBTweakInlineTestsMRR.m | 9 +++++++++ 3 files changed, 20 insertions(+) diff --git a/FBTweak/FBTweakInline.h b/FBTweak/FBTweakInline.h index 0e5b6b1b..4e40d473 100644 --- a/FBTweak/FBTweakInline.h +++ b/FBTweak/FBTweakInline.h @@ -8,6 +8,8 @@ */ #import "FBTweakInlineInternal.h" +#import "FBTweak+Array.h" +#import "FBTweak+Dictionary.h" /** @abstract Common parameters in these macros. diff --git a/FBTweakTests/FBTweakInlineTestsARC.m b/FBTweakTests/FBTweakInlineTestsARC.m index b5380ac4..b162603d 100644 --- a/FBTweakTests/FBTweakInlineTestsARC.m +++ b/FBTweakTests/FBTweakInlineTestsARC.m @@ -82,6 +82,15 @@ - (void)testValueTypes __attribute__((unused)) NSString *testNSString = FBTweakValue(@"NSString", @"NSString", @"NSString", @"one"); XCTAssertEqualObjects(testNSString, @"one", @"NSString %@", testNSString); + + __attribute__((unused)) NSString *testNSArray = FBArrayTweakValue(@"NSArray", @"NSArray", @"NSArray", @[@"one", @"two", @"three"], @"two"); + XCTAssertEqualObjects(testNSArray, @"two", @"NSString %@", testNSArray); + + __attribute__((unused)) NSString *testNSDictionaryKey = FBDictionaryTweakValue(@"NSDictionaryKey", @"NSDictionaryKey", @"NSDictionaryKey", @{@"key1":@"value1", @"key2":@"value2"}, @"key2"); + XCTAssertEqualObjects(testNSDictionaryKey, @"key2", @"NSString %@", testNSDictionaryKey); + + __attribute__((unused)) NSString *testNSDictionaryValue = FBDictionaryTweakValueForKey(@"NSDictionaryValue", @"NSDictionaryValue", @"NSDictionaryValue", @{@"key1":@"value1", @"key2":@"value2"}, @"key2"); + XCTAssertEqualObjects(testNSDictionaryValue, @"value2", @"NSString %@", testNSDictionaryValue); } - (void)testConstantValues diff --git a/FBTweakTests/FBTweakInlineTestsMRR.m b/FBTweakTests/FBTweakInlineTestsMRR.m index 807bb2a6..bad43f15 100644 --- a/FBTweakTests/FBTweakInlineTestsMRR.m +++ b/FBTweakTests/FBTweakInlineTestsMRR.m @@ -57,6 +57,15 @@ - (void)testValueTypes __attribute__((unused)) NSString *testNSString = FBTweakValue(@"NSString", @"NSString", @"NSString", @"one"); XCTAssertEqualObjects(testNSString, @"one", @"NSString %@", testNSString); + + __attribute__((unused)) NSString *testNSArray = FBArrayTweakValue(@"NSArray", @"NSArray", @"NSArray", @[@"one", @"two", @"three"], @"two"); + XCTAssertEqualObjects(testNSArray, @"two", @"NSString %@", testNSArray); + + __attribute__((unused)) NSString *testNSDictionaryKey = FBDictionaryTweakValue(@"NSDictionaryKey", @"NSDictionaryKey", @"NSDictionaryKey", @{@"key1":@"value1", @"key2":@"value2"}, @"key2"); + XCTAssertEqualObjects(testNSDictionaryKey, @"key2", @"NSString %@", testNSDictionaryKey); + + __attribute__((unused)) NSString *testNSDictionaryValue = FBDictionaryTweakValueForKey(@"NSDictionaryValue", @"NSDictionaryValue", @"NSDictionaryValue", @{@"key1":@"value1", @"key2":@"value2"}, @"key2"); + XCTAssertEqualObjects(testNSDictionaryValue, @"value2", @"NSString %@", testNSDictionaryValue); } - (void)testConstantValues From 719e68b76a239cdd602788b5fa42e61050ce84de Mon Sep 17 00:00:00 2001 From: John McIntosh Date: Sat, 24 Jan 2015 13:36:39 -0600 Subject: [PATCH 19/44] Adjust function formatting --- FBTweak/FBTweak+Array.h | 2 +- FBTweak/FBTweak+Array.m | 2 +- FBTweak/FBTweak+Dictionary.h | 4 ++-- FBTweak/FBTweak+Dictionary.m | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/FBTweak/FBTweak+Array.h b/FBTweak/FBTweak+Array.h index 529d8ea4..629cd710 100644 --- a/FBTweak/FBTweak+Array.h +++ b/FBTweak/FBTweak+Array.h @@ -35,7 +35,7 @@ @abstract Loads an array tweak defined inline. @return A {@ref FBTweak} for the array tweak. */ -FBTweak* FBArrayTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue); +FBTweak *FBArrayTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue); /** @abstract Loads the array's value of an array tweak inine. diff --git a/FBTweak/FBTweak+Array.m b/FBTweak/FBTweak+Array.m index 1f07e025..f4a10ef1 100644 --- a/FBTweak/FBTweak+Array.m +++ b/FBTweak/FBTweak+Array.m @@ -32,7 +32,7 @@ - (void)setArrayValue:(NSArray *)arrayValue self.stepValue = arrayValue; } -FBTweak* FBArrayTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue) +FBTweak *FBArrayTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue) { FBTweakStore *store = [FBTweakStore sharedInstance]; FBTweakCategory *cat = [store tweakCategoryWithName:categoryName]; diff --git a/FBTweak/FBTweak+Dictionary.h b/FBTweak/FBTweak+Dictionary.h index db58f5e5..03f99626 100644 --- a/FBTweak/FBTweak+Dictionary.h +++ b/FBTweak/FBTweak+Dictionary.h @@ -40,14 +40,14 @@ @abstract Loads a dictionary tweak defined inline. @return A {@ref FBTweak} for the dictionary tweak. */ -FBTweak* FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey); +FBTweak *FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey); /** @abstract Loads the key of a dictionary tweak inine. @param dictionary A dictionary with string values for keys. @return The current string key for the tweak, or the default key if none is set. */ -NSString* FBDictionaryTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey); +NSString *FBDictionaryTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey); /** @abstract Loads the dictionary's value associated with the key of a dictionary tweak inine. diff --git a/FBTweak/FBTweak+Dictionary.m b/FBTweak/FBTweak+Dictionary.m index 63272639..90f291ab 100644 --- a/FBTweak/FBTweak+Dictionary.m +++ b/FBTweak/FBTweak+Dictionary.m @@ -37,7 +37,7 @@ - (NSArray *)allKeys return self.dictionaryValue.allKeys; } -FBTweak* FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey) +FBTweak *FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey) { FBTweakStore *store = [FBTweakStore sharedInstance]; FBTweakCategory *cat = [store tweakCategoryWithName:categoryName]; @@ -67,7 +67,7 @@ - (NSArray *)allKeys return tweak; } -NSString* FBDictionaryTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey) +NSString *FBDictionaryTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey) { FBTweak *tweak = FBDictionaryTweak(categoryName, collectionName, tweakName, dictionary, defaultKey); return tweak.currentValue ?: tweak.defaultValue; From e70e425c993b7a43d8a75cfb5477c511dbe0fd0c Mon Sep 17 00:00:00 2001 From: John McIntosh Date: Sat, 24 Jan 2015 13:52:43 -0600 Subject: [PATCH 20/44] Update to use iOS disclosure indicator rather than appending a > for the table view. --- FBTweak/_FBTweakTableViewCell.m | 42 +++++++++------------------------ 1 file changed, 11 insertions(+), 31 deletions(-) diff --git a/FBTweak/_FBTweakTableViewCell.m b/FBTweak/_FBTweakTableViewCell.m index 5829ae3e..ae3ef649 100644 --- a/FBTweak/_FBTweakTableViewCell.m +++ b/FBTweak/_FBTweakTableViewCell.m @@ -33,12 +33,11 @@ @implementation _FBTweakTableViewCell { UISwitch *_switch; UITextField *_textField; UIStepper *_stepper; - UILabel *_valueLabel; } - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier; { - if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier])) { + if ((self = [super initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:reuseIdentifier])) { _accessoryView = [[UIView alloc] init]; _switch = [[UISwitch alloc] init]; @@ -54,9 +53,7 @@ - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier; [_stepper addTarget:self action:@selector(_stepperChanged:) forControlEvents:UIControlEventValueChanged]; [_accessoryView addSubview:_stepper]; - _valueLabel = [[UILabel alloc] init]; - _valueLabel.textAlignment = NSTextAlignmentRight; - [_accessoryView addSubview:_valueLabel]; + self.detailTextLabel.textColor = [UIColor blackColor]; } return self; @@ -96,18 +93,6 @@ - (void)layoutSubviews _accessoryView.bounds = CGRectIntegral(textBounds); } else if (_mode == _FBTweakTableViewCellModeAction) { _accessoryView.bounds = CGRectZero; - } else if (_mode == _FBTweakTableViewCellModeDictionary) { - CGFloat margin = CGRectGetMinX(self.textLabel.frame); - CGFloat textFieldWidth = self.bounds.size.width - (margin * 3.0) - [self.textLabel sizeThatFits:CGSizeZero].width; - CGRect textBounds = CGRectMake(0, 0, textFieldWidth, self.bounds.size.height); - _valueLabel.frame = CGRectIntegral(textBounds); - _accessoryView.bounds = CGRectIntegral(textBounds); - } else if (_mode == _FBTweakTableViewCellModeArray) { - CGFloat margin = CGRectGetMinX(self.textLabel.frame); - CGFloat textFieldWidth = self.bounds.size.width - (margin * 3.0) - [self.textLabel sizeThatFits:CGSizeZero].width; - CGRect textBounds = CGRectMake(0, 0, textFieldWidth, self.bounds.size.height); - _valueLabel.frame = CGRectIntegral(textBounds); - _accessoryView.bounds = CGRectIntegral(textBounds); } // This positions the accessory view, so call it after updating its bounds. @@ -158,19 +143,18 @@ - (void)_updateMode:(_FBTweakTableViewCellMode)mode self.accessoryView = _accessoryView; self.accessoryType = UITableViewCellAccessoryNone; + self.detailTextLabel.text = nil; self.selectionStyle = UITableViewCellSelectionStyleNone; if (_mode == _FBTweakTableViewCellModeBoolean) { _switch.hidden = NO; _textField.hidden = YES; _stepper.hidden = YES; - _valueLabel.hidden = YES; } else if (_mode == _FBTweakTableViewCellModeInteger) { _switch.hidden = YES; _textField.hidden = NO; _textField.keyboardType = UIKeyboardTypeNumberPad; _stepper.hidden = NO; - _valueLabel.hidden = YES; if (_tweak.stepValue) { _stepper.stepValue = [_tweak.stepValue floatValue]; } else { @@ -193,7 +177,6 @@ - (void)_updateMode:(_FBTweakTableViewCellMode)mode _textField.hidden = NO; _textField.keyboardType = UIKeyboardTypeDecimalPad; _stepper.hidden = NO; - _valueLabel.hidden = YES; if (_tweak.stepValue) { _stepper.stepValue = [_tweak.stepValue floatValue]; @@ -225,12 +208,10 @@ - (void)_updateMode:(_FBTweakTableViewCellMode)mode _textField.hidden = NO; _textField.keyboardType = UIKeyboardTypeDefault; _stepper.hidden = YES; - _valueLabel.hidden = YES; } else if (_mode == _FBTweakTableViewCellModeAction) { _switch.hidden = YES; _textField.hidden = YES; _stepper.hidden = YES; - _valueLabel.hidden = YES; self.accessoryView = nil; self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; @@ -239,17 +220,20 @@ - (void)_updateMode:(_FBTweakTableViewCellMode)mode _switch.hidden = YES; _textField.hidden = YES; _stepper.hidden = YES; - _valueLabel.hidden = NO; + self.accessoryView = nil; + self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + self.selectionStyle = UITableViewCellSelectionStyleBlue; } else if (_mode == _FBTweakTableViewCellModeArray) { _switch.hidden = YES; _textField.hidden = YES; _stepper.hidden = YES; - _valueLabel.hidden = NO; + self.accessoryView = nil; + self.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + self.selectionStyle = UITableViewCellSelectionStyleBlue; } else { _switch.hidden = YES; _textField.hidden = YES; _stepper.hidden = YES; - _valueLabel.hidden = YES; } [self setNeedsLayout]; @@ -345,15 +329,11 @@ - (void)_updateValue:(FBTweakValue)value primary:(BOOL)primary write:(BOOL)write _textField.text = [NSString stringWithFormat:format, [value doubleValue]]; } else if (_mode == _FBTweakTableViewCellModeDictionary) { if (primary) { - NSString *displayValue = [[value description] stringByAppendingString:@" >"]; - _valueLabel.text = displayValue; + self.detailTextLabel.text = value; } } else if (_mode == _FBTweakTableViewCellModeArray) { if (primary) { - if ([value isKindOfClass:[NSString class]]) { - NSString *displayValue = [value stringByAppendingString:@" >"]; - _valueLabel.text = displayValue; - } + self.detailTextLabel.text = value; } } } From 4f4a06946d299ef3ceb40948320ba5fdf7f98973 Mon Sep 17 00:00:00 2001 From: John McIntosh Date: Sat, 24 Jan 2015 14:46:42 -0600 Subject: [PATCH 21/44] Update array and dictionary tweak documentation --- FBTweak/FBTweak+Array.h | 9 +++++++-- FBTweak/FBTweak+Dictionary.h | 7 ++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/FBTweak/FBTweak+Array.h b/FBTweak/FBTweak+Array.h index 629cd710..0256d914 100644 --- a/FBTweak/FBTweak+Array.h +++ b/FBTweak/FBTweak+Array.h @@ -11,8 +11,13 @@ /** - Implementation works by storing the array in the tweak's `stepValue`. The values of the array are - exposed through the Tweaks UI through the value's `description`. + @abstract Implementation works by storing the array in the tweak's `stepValue`. The values of the array are + exposed through the Tweaks UI through the value's `description`. + @discussion Array tweaks contain objects which cannot be evaluated at compile-time like most + other tweaks. As a result, the tweak must be accessed once before it will be available in the + Tweaks UI. Depending on your use-case, an option for this can be to register array tweaks + from a class's `+initialize` method. This will ensure that the tweak is registered immediately on + application launch, and the tweak can be accessed later to retrieve the current value. */ @interface FBTweak (Array) diff --git a/FBTweak/FBTweak+Dictionary.h b/FBTweak/FBTweak+Dictionary.h index 03f99626..317aecd1 100644 --- a/FBTweak/FBTweak+Dictionary.h +++ b/FBTweak/FBTweak+Dictionary.h @@ -10,7 +10,12 @@ #import "FBTweak.h" /** - Implementation works by storing the dictionary in the tweak's `stepValue`. + @abstract Implementation works by storing the dictionary in the tweak's `stepValue`. + @discussion Dictionary tweaks contain objects which cannot be evaluated at compile-time like most + other tweaks. As a result, the tweak must be accessed once before it will be available in the + Tweaks UI. Depending on your use-case, an option for this can be to register dictionary tweaks + from a class's `+initialize` method. This will ensure that the tweak is registered immediately on + application launch, and the tweak can be accessed later to retrieve the current value. */ @interface FBTweak (Dictionary) From c3e4addfe1250961703e596980d6ee81034c5f3d Mon Sep 17 00:00:00 2001 From: Grant Paul Date: Thu, 29 Jan 2015 00:54:16 -0800 Subject: [PATCH 22/44] Generalize minimum/maximum support into 'possible values'. Unfiy minimum and maximum with array and dictionary support. --- FBTweak.xcodeproj/project.pbxproj | 16 ---- FBTweak/FBTweak+Array.h | 50 ----------- FBTweak/FBTweak+Array.m | 71 --------------- FBTweak/FBTweak+Dictionary.h | 62 ------------- FBTweak/FBTweak+Dictionary.m | 83 ----------------- FBTweak/FBTweak.h | 56 ++++++++++-- FBTweak/FBTweak.m | 100 ++++++++++++++++++--- FBTweak/FBTweakInline.h | 2 - FBTweak/FBTweakInline.m | 64 +++++-------- FBTweak/FBTweakInlineInternal.h | 50 +++++++---- FBTweak/_FBTweakArrayViewController.h | 14 ++- FBTweak/_FBTweakArrayViewController.m | 26 ++++-- FBTweak/_FBTweakCollectionViewController.m | 13 ++- FBTweak/_FBTweakDictionaryViewController.h | 14 ++- FBTweak/_FBTweakDictionaryViewController.m | 38 +++++--- FBTweak/_FBTweakTableViewCell.m | 11 +-- FBTweakExample/FBAppDelegate.m | 35 ++------ FBTweakTests/FBTweakInlineTestsARC.m | 17 ++-- FBTweakTests/FBTweakInlineTestsMRR.m | 17 ++-- README.md | 10 ++- 20 files changed, 293 insertions(+), 456 deletions(-) delete mode 100644 FBTweak/FBTweak+Array.h delete mode 100644 FBTweak/FBTweak+Array.m delete mode 100644 FBTweak/FBTweak+Dictionary.h delete mode 100644 FBTweak/FBTweak+Dictionary.m diff --git a/FBTweak.xcodeproj/project.pbxproj b/FBTweak.xcodeproj/project.pbxproj index 005f0efb..ca06fb00 100644 --- a/FBTweak.xcodeproj/project.pbxproj +++ b/FBTweak.xcodeproj/project.pbxproj @@ -40,12 +40,8 @@ 18EFE52D189F250700DA6A5D /* FBTweakInlineTestsMRR.m in Sources */ = {isa = PBXBuildFile; fileRef = 18EFE52C189F250700DA6A5D /* FBTweakInlineTestsMRR.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 18EFE536189F38D500DA6A5D /* FBTweakEnabled.h in Headers */ = {isa = PBXBuildFile; fileRef = 18EFE535189F38D500DA6A5D /* FBTweakEnabled.h */; settings = {ATTRIBUTES = (Public, ); }; }; 29E9F17B18E35C9C001EAF7D /* MessageUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29E9F17A18E35C9C001EAF7D /* MessageUI.framework */; }; - 5BACB31A1A1280BD00C4F79D /* FBTweak+Array.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BACB3181A1280BD00C4F79D /* FBTweak+Array.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5BACB31B1A1280BD00C4F79D /* FBTweak+Array.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BACB3191A1280BD00C4F79D /* FBTweak+Array.m */; }; 5BACB31E1A12813C00C4F79D /* _FBTweakArrayViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BACB31C1A12813C00C4F79D /* _FBTweakArrayViewController.h */; }; 5BACB31F1A12813C00C4F79D /* _FBTweakArrayViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BACB31D1A12813C00C4F79D /* _FBTweakArrayViewController.m */; }; - 5BE25A4E1A0AA90E00C97C3E /* FBTweak+Dictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BE25A4C1A0AA90E00C97C3E /* FBTweak+Dictionary.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 5BE25A4F1A0AA90E00C97C3E /* FBTweak+Dictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BE25A4D1A0AA90E00C97C3E /* FBTweak+Dictionary.m */; }; 5BE25A521A0AA9D500C97C3E /* _FBTweakDictionaryViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 5BE25A501A0AA9D500C97C3E /* _FBTweakDictionaryViewController.h */; }; 5BE25A531A0AA9D500C97C3E /* _FBTweakDictionaryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5BE25A511A0AA9D500C97C3E /* _FBTweakDictionaryViewController.m */; }; /* End PBXBuildFile section */ @@ -96,12 +92,8 @@ 18EFE52C189F250700DA6A5D /* FBTweakInlineTestsMRR.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FBTweakInlineTestsMRR.m; sourceTree = ""; }; 18EFE535189F38D500DA6A5D /* FBTweakEnabled.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FBTweakEnabled.h; sourceTree = ""; }; 29E9F17A18E35C9C001EAF7D /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; - 5BACB3181A1280BD00C4F79D /* FBTweak+Array.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = "FBTweak+Array.h"; sourceTree = ""; tabWidth = 2; }; - 5BACB3191A1280BD00C4F79D /* FBTweak+Array.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = "FBTweak+Array.m"; sourceTree = ""; tabWidth = 2; }; 5BACB31C1A12813C00C4F79D /* _FBTweakArrayViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _FBTweakArrayViewController.h; sourceTree = ""; }; 5BACB31D1A12813C00C4F79D /* _FBTweakArrayViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = _FBTweakArrayViewController.m; sourceTree = ""; }; - 5BE25A4C1A0AA90E00C97C3E /* FBTweak+Dictionary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FBTweak+Dictionary.h"; sourceTree = ""; }; - 5BE25A4D1A0AA90E00C97C3E /* FBTweak+Dictionary.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = "FBTweak+Dictionary.m"; sourceTree = ""; tabWidth = 2; }; 5BE25A501A0AA9D500C97C3E /* _FBTweakDictionaryViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _FBTweakDictionaryViewController.h; sourceTree = ""; }; 5BE25A511A0AA9D500C97C3E /* _FBTweakDictionaryViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = _FBTweakDictionaryViewController.m; sourceTree = ""; tabWidth = 2; usesTabs = 0; }; /* End PBXFileReference section */ @@ -210,10 +202,6 @@ 18EFE526189F19B300DA6A5D /* FBTweakCategory.m */, 18EFE4BF189EBEAD00DA6A5D /* FBTweakStore.h */, 18EFE4C0189EBEAD00DA6A5D /* FBTweakStore.m */, - 5BE25A4C1A0AA90E00C97C3E /* FBTweak+Dictionary.h */, - 5BE25A4D1A0AA90E00C97C3E /* FBTweak+Dictionary.m */, - 5BACB3181A1280BD00C4F79D /* FBTweak+Array.h */, - 5BACB3191A1280BD00C4F79D /* FBTweak+Array.m */, ); name = Model; sourceTree = ""; @@ -261,14 +249,12 @@ 18EFE4B7189EBC3100DA6A5D /* FBTweak.h in Headers */, 18EFE4D5189EEBC500DA6A5D /* _FBTweakCategoryViewController.h in Headers */, 18EFE4D9189EEED800DA6A5D /* _FBTweakCollectionViewController.h in Headers */, - 5BACB31A1A1280BD00C4F79D /* FBTweak+Array.h in Headers */, 18EFE4B4189EBAC200DA6A5D /* FBTweakViewController.h in Headers */, 18EFE4C1189EBEAD00DA6A5D /* FBTweakStore.h in Headers */, 18EFE4B2189EBAC200DA6A5D /* FBTweakInline.h in Headers */, 18EFE4B3189EBAC200DA6A5D /* FBTweakShakeWindow.h in Headers */, 18EFE536189F38D500DA6A5D /* FBTweakEnabled.h in Headers */, 18EFE4D0189EC70300DA6A5D /* FBTweakInlineInternal.h in Headers */, - 5BE25A4E1A0AA90E00C97C3E /* FBTweak+Dictionary.h in Headers */, 18EFE527189F19B300DA6A5D /* FBTweakCategory.h in Headers */, 18EFE4BC189EBC4B00DA6A5D /* FBTweakCollection.h in Headers */, 5BE25A521A0AA9D500C97C3E /* _FBTweakDictionaryViewController.h in Headers */, @@ -359,9 +345,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 5BACB31B1A1280BD00C4F79D /* FBTweak+Array.m in Sources */, 5BE25A531A0AA9D500C97C3E /* _FBTweakDictionaryViewController.m in Sources */, - 5BE25A4F1A0AA90E00C97C3E /* FBTweak+Dictionary.m in Sources */, 18EFE4A7189EBA9E00DA6A5D /* FBTweakViewController.m in Sources */, 18EFE4BD189EBC4B00DA6A5D /* FBTweakCollection.m in Sources */, 18EFE4C2189EBEAD00DA6A5D /* FBTweakStore.m in Sources */, diff --git a/FBTweak/FBTweak+Array.h b/FBTweak/FBTweak+Array.h deleted file mode 100644 index 0256d914..00000000 --- a/FBTweak/FBTweak+Array.h +++ /dev/null @@ -1,50 +0,0 @@ -/** - Copyright (c) 2014-present, Facebook, Inc. - All rights reserved. - - This source code is licensed under the BSD-style license found in the - LICENSE file in the root directory of this source tree. An additional grant - of patent rights can be found in the PATENTS file in the same directory. - */ - -#import "FBTweak.h" - - -/** - @abstract Implementation works by storing the array in the tweak's `stepValue`. The values of the array are - exposed through the Tweaks UI through the value's `description`. - @discussion Array tweaks contain objects which cannot be evaluated at compile-time like most - other tweaks. As a result, the tweak must be accessed once before it will be available in the - Tweaks UI. Depending on your use-case, an option for this can be to register array tweaks - from a class's `+initialize` method. This will ensure that the tweak is registered immediately on - application launch, and the tweak can be accessed later to retrieve the current value. - */ -@interface FBTweak (Array) - -/** - @abstract The array contained by the tweak. - @discussion The current and default values of the tweak contain an item in this array. - */ -@property (nonatomic, copy, readwrite) NSArray *arrayValue; - -/** - @abstract Indicates whether the tweak instance represents an array tweak. - @return YES if the instance represents an array tweak. - */ -- (BOOL)isArray; - -@end - - -/** - @abstract Loads an array tweak defined inline. - @return A {@ref FBTweak} for the array tweak. - */ -FBTweak *FBArrayTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue); - -/** - @abstract Loads the array's value of an array tweak inine. - @return The array's value of the tweak. If the current value is nil, the default value will be - returned. - */ -FBTweakValue FBArrayTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue); diff --git a/FBTweak/FBTweak+Array.m b/FBTweak/FBTweak+Array.m deleted file mode 100644 index f4a10ef1..00000000 --- a/FBTweak/FBTweak+Array.m +++ /dev/null @@ -1,71 +0,0 @@ -/** - Copyright (c) 2014-present, Facebook, Inc. - All rights reserved. - - This source code is licensed under the BSD-style license found in the - LICENSE file in the root directory of this source tree. An additional grant - of patent rights can be found in the PATENTS file in the same directory. - */ - -#import "FBTweak+Array.h" -#import "FBTweakStore.h" -#import "FBTweakCollection.h" -#import "FBTweakCategory.h" - -@implementation FBTweak (Array) - -- (BOOL)isArray -{ - return (self.arrayValue != nil); -} - -- (NSArray *)arrayValue -{ - if ([self.stepValue isKindOfClass:[NSArray class]]) { - return self.stepValue; - } - return nil; -} - -- (void)setArrayValue:(NSArray *)arrayValue -{ - self.stepValue = arrayValue; -} - -FBTweak *FBArrayTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue) -{ - FBTweakStore *store = [FBTweakStore sharedInstance]; - FBTweakCategory *cat = [store tweakCategoryWithName:categoryName]; - - if (!cat) { - cat = [[FBTweakCategory alloc] initWithName:categoryName]; - [store addTweakCategory:cat]; - } - - FBTweakCollection *collection = [cat tweakCollectionWithName:collectionName]; - - if (!collection) { - collection = [[FBTweakCollection alloc] initWithName:collectionName]; - [cat addTweakCollection:collection]; - } - - FBTweak *tweak = [collection tweakWithIdentifier:tweakName]; - - if (!tweak) { - tweak = [[FBTweak alloc] initWithIdentifier:tweakName]; - tweak.name = tweakName; - tweak.arrayValue = array; - tweak.defaultValue = defaultValue; - - [collection addTweak:tweak]; - } - return tweak; -} - -FBTweakValue FBArrayTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSArray *array, id defaultValue) -{ - FBTweak *tweak = FBArrayTweak(categoryName, collectionName, tweakName, array, defaultValue); - return tweak.currentValue ?: tweak.defaultValue; -} - -@end diff --git a/FBTweak/FBTweak+Dictionary.h b/FBTweak/FBTweak+Dictionary.h deleted file mode 100644 index 317aecd1..00000000 --- a/FBTweak/FBTweak+Dictionary.h +++ /dev/null @@ -1,62 +0,0 @@ -/** - Copyright (c) 2014-present, Facebook, Inc. - All rights reserved. - - This source code is licensed under the BSD-style license found in the - LICENSE file in the root directory of this source tree. An additional grant - of patent rights can be found in the PATENTS file in the same directory. - */ - -#import "FBTweak.h" - -/** - @abstract Implementation works by storing the dictionary in the tweak's `stepValue`. - @discussion Dictionary tweaks contain objects which cannot be evaluated at compile-time like most - other tweaks. As a result, the tweak must be accessed once before it will be available in the - Tweaks UI. Depending on your use-case, an option for this can be to register dictionary tweaks - from a class's `+initialize` method. This will ensure that the tweak is registered immediately on - application launch, and the tweak can be accessed later to retrieve the current value. - */ -@interface FBTweak (Dictionary) - -/** - @abstract The keys of dictionary contained in the tweak. - @discussion Array containing string values for each of the keys in the dictionary. - */ -@property (nonatomic, copy, readonly) NSArray *allKeys; - -/** - @abstract The dictionary contained by the tweak. - @discussion The current and default values of the tweak represent a key in - this dictionary. - */ -@property (nonatomic, copy, readwrite) NSDictionary *dictionaryValue; - -/** - @abstract Indicates whether the tweak instance represents a dictionary tweak. - @return YES if the instance represents a dictionary tweak. - */ -- (BOOL)isDictionary; - -@end - - -/** - @abstract Loads a dictionary tweak defined inline. - @return A {@ref FBTweak} for the dictionary tweak. - */ -FBTweak *FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey); - -/** - @abstract Loads the key of a dictionary tweak inine. - @param dictionary A dictionary with string values for keys. - @return The current string key for the tweak, or the default key if none is set. - */ -NSString *FBDictionaryTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey); - -/** - @abstract Loads the dictionary's value associated with the key of a dictionary tweak inine. - @return The dictionary's value associated with the key for the tweak. If the current key is nil, - the value associated with the default key will be returned. - */ -FBTweakValue FBDictionaryTweakValueForKey(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey); \ No newline at end of file diff --git a/FBTweak/FBTweak+Dictionary.m b/FBTweak/FBTweak+Dictionary.m deleted file mode 100644 index 90f291ab..00000000 --- a/FBTweak/FBTweak+Dictionary.m +++ /dev/null @@ -1,83 +0,0 @@ -/** - Copyright (c) 2014-present, Facebook, Inc. - All rights reserved. - - This source code is licensed under the BSD-style license found in the - LICENSE file in the root directory of this source tree. An additional grant - of patent rights can be found in the PATENTS file in the same directory. - */ - -#import "FBTweak+Dictionary.h" -#import "FBTweakStore.h" -#import "FBTweakCollection.h" -#import "FBTweakCategory.h" - -@implementation FBTweak (Dictionary) - -- (BOOL)isDictionary -{ - return (self.dictionaryValue != nil); -} - -- (NSDictionary *)dictionaryValue -{ - if ([self.stepValue isKindOfClass:[NSDictionary class]]) { - return self.stepValue; - } - return nil; -} - -- (void)setDictionaryValue:(NSDictionary *)dictionaryValue -{ - self.stepValue = dictionaryValue; -} - -- (NSArray *)allKeys -{ - return self.dictionaryValue.allKeys; -} - -FBTweak *FBDictionaryTweak(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey) -{ - FBTweakStore *store = [FBTweakStore sharedInstance]; - FBTweakCategory *cat = [store tweakCategoryWithName:categoryName]; - - if (!cat) { - cat = [[FBTweakCategory alloc] initWithName:categoryName]; - [store addTweakCategory:cat]; - } - - FBTweakCollection *collection = [cat tweakCollectionWithName:collectionName]; - - if (!collection) { - collection = [[FBTweakCollection alloc] initWithName:collectionName]; - [cat addTweakCollection:collection]; - } - - FBTweak *tweak = [collection tweakWithIdentifier:tweakName]; - - if (!tweak) { - tweak = [[FBTweak alloc] initWithIdentifier:tweakName]; - tweak.name = tweakName; - tweak.dictionaryValue = dictionary; - tweak.defaultValue = defaultKey; - - [collection addTweak:tweak]; - } - return tweak; -} - -NSString *FBDictionaryTweakValue(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey) -{ - FBTweak *tweak = FBDictionaryTweak(categoryName, collectionName, tweakName, dictionary, defaultKey); - return tweak.currentValue ?: tweak.defaultValue; -} - -FBTweakValue FBDictionaryTweakValueForKey(NSString *categoryName, NSString *collectionName, NSString *tweakName, NSDictionary *dictionary, NSString *defaultKey) -{ - FBTweak *tweak = FBDictionaryTweak(categoryName, collectionName, tweakName, dictionary, defaultKey); - NSString *key = tweak.currentValue ?: tweak.defaultValue; - return tweak.dictionaryValue[key]; -} - -@end diff --git a/FBTweak/FBTweak.h b/FBTweak/FBTweak.h index 3fb97f07..fd1aff38 100644 --- a/FBTweak/FBTweak.h +++ b/FBTweak/FBTweak.h @@ -19,6 +19,34 @@ */ typedef id FBTweakValue; +/** + @abstract Represents a range of values for a numeric tweak. + @discussion Use this for the -possibleValues on a tweak. + */ +@interface FBTweakNumericRange : NSObject + +/** + @abstract Creates a new numeric range. + @discussion This is the designated initializer. + @param minimumValue The minimum value of the range. + @param maximumValue The maximum value of the range. + */ +- (instancetype)initWithMinimumValue:(FBTweakValue)minimumValue maximumValue:(FBTweakValue)maximumValue; + +/** + @abstract The minimum value of the range. + @discussion Will always have a value. + */ +@property (nonatomic, strong, readwrite) FBTweakValue minimumValue; + +/** + @abstract The maximum value of the range. + @discussion Will always have a value. + */ +@property (nonatomic, strong, readwrite) FBTweakValue maximumValue; + +@end + /** @abstract Represents a unique, named tweak. @discussion A tweak contains a persistent, editable value. @@ -28,6 +56,7 @@ typedef id FBTweakValue; /** @abstract Creates a new tweak model. @discussion This is the designated initializer. + @param identifier The identifier for the tweak. Required. */ - (instancetype)initWithIdentifier:(NSString *)identifier; @@ -59,34 +88,45 @@ typedef id FBTweakValue; /** @abstract The current value of the tweak. Can be nil. - @discussion Changes will be propagated to disk. Enforces minimum - and maximum values when changed. Must not be set on actions. + @discussion Changes will be propagated to disk. Enforces within + possible values when changed. Must not be set on actions. */ @property (nonatomic, strong, readwrite) FBTweakValue currentValue; +/** + @abstract The possible values of the tweak. + @discussion Optional. If nil, any value is allowed. If an + FBTweakNumericRange, represents a range of numeric values. + If an array or dictionary, contains all of the allowed values. + Should not be set on tweaks representing actions. + */ +@property (nonatomic, strong, readwrite) id possibleValues; + /** @abstract The minimum value of the tweak. - @discussion Optional. If nil, there is no minimum. + @discussion Optional. If nil, there is no minimum. Numeric only. Should not be set on tweaks representing actions. */ @property (nonatomic, strong, readwrite) FBTweakValue minimumValue; /** @abstract The maximum value of the tweak. - @discussion Optional. If nil, there is no maximum. + @discussion Optional. If nil, there is no maximum. Numeric only. Should not be set on tweaks representing actions. */ @property (nonatomic, strong, readwrite) FBTweakValue maximumValue; /** - @abstract The step value of the tweak. - @discussion Optional. If nil, the step value is calculated of miniumum and maxium. + @abstract The step value of the tweak. + @discussion Optional. If nil, the step value is calculated from + the miniumum and maxium values. Only used for numeric tweaks. */ @property (nonatomic, strong, readwrite) FBTweakValue stepValue; /** - @abstract The decimal precision value of the tweak. - @discussion Optional. If nil, the precision value is calculated of the step value. + @abstract The decimal precision value of the tweak. + @discussion Optional. If nil, the precision value is calculated from + the step value. Only used for numeric tweaks. */ @property (nonatomic, strong, readwrite) FBTweakValue precisionValue; diff --git a/FBTweak/FBTweak.m b/FBTweak/FBTweak.m index 048f13e0..c8e819f6 100644 --- a/FBTweak/FBTweak.m +++ b/FBTweak/FBTweak.m @@ -9,6 +9,23 @@ #import "FBTweak.h" +@implementation FBTweakNumericRange + +- (instancetype)initWithMinimumValue:(FBTweakValue)minimumValue maximumValue:(FBTweakValue)maximumValue +{ + if ((self = [super init])) { + NSParameterAssert(minimumValue != nil); + NSParameterAssert(maximumValue != nil); + + _minimumValue = minimumValue; + _maximumValue = maximumValue; + } + + return self; +} + +@end + @implementation FBTweak { NSHashTable *_observers; } @@ -20,8 +37,16 @@ - (instancetype)initWithCoder:(NSCoder *)coder if ((self = [self initWithIdentifier:identifier])) { _name = [coder decodeObjectForKey:@"name"]; _defaultValue = [coder decodeObjectForKey:@"defaultValue"]; - _minimumValue = [coder decodeObjectForKey:@"minimumValue"]; - _maximumValue = [coder decodeObjectForKey:@"maximumValue"]; + + if ([coder containsValueForKey:@"possibleValues"]) { + _possibleValues = [coder decodeObjectForKey:@"possibleValues"]; + } else { + // Backwards compatbility for before possibleValues was introduced. + FBTweakValue minimumValue = [coder decodeObjectForKey:@"minimumValue"]; + FBTweakValue maximumValue = [coder decodeObjectForKey:@"maximumValue"]; + _possibleValues = [[FBTweakNumericRange alloc] initWithMinimumValue:minimumValue maximumValue:maximumValue]; + } + _precisionValue = [coder decodeObjectForKey:@"precisionValue"]; _stepValue = [coder decodeObjectForKey:@"stepValue"]; @@ -49,8 +74,7 @@ - (void)encodeWithCoder:(NSCoder *)coder if (!self.isAction) { [coder encodeObject:_defaultValue forKey:@"defaultValue"]; - [coder encodeObject:_minimumValue forKey:@"minimumValue"]; - [coder encodeObject:_maximumValue forKey:@"maximumValue"]; + [coder encodeObject:_possibleValues forKey:@"possibleValues"]; [coder encodeObject:_currentValue forKey:@"currentValue"]; [coder encodeObject:_precisionValue forKey:@"precisionValue"]; [coder encodeObject:_stepValue forKey:@"stepValue"]; @@ -69,18 +93,72 @@ - (BOOL)isAction return [_defaultValue isKindOfClass:blockClass]; } +- (FBTweakValue)minimumValue +{ + if ([_possibleValues isKindOfClass:[FBTweakNumericRange class]]) { + return [_possibleValues minimumValue]; + } else { + return nil; + } +} + +- (void)setMinimumValue:(FBTweakValue)minimumValue +{ + if (minimumValue == nil) { + _possibleValues = nil; + } else if ([_possibleValues isKindOfClass:[FBTweakNumericRange class]]) { + _possibleValues = [[FBTweakNumericRange alloc] initWithMinimumValue:minimumValue maximumValue:[_possibleValues maximumValue]]; + } else { + _possibleValues = [[FBTweakNumericRange alloc] initWithMinimumValue:minimumValue maximumValue:minimumValue]; + } +} + +- (FBTweakValue)maximumValue +{ + if ([_possibleValues isKindOfClass:[FBTweakNumericRange class]]) { + return [_possibleValues maximumValue]; + } else { + return nil; + } +} + +- (void)setMaximumValue:(FBTweakValue)maximumValue +{ + if (maximumValue == nil) { + _possibleValues = nil; + } else if ([_possibleValues isKindOfClass:[FBTweakNumericRange class]]) { + _possibleValues = [[FBTweakNumericRange alloc] initWithMinimumValue:[_possibleValues minimumValue] maximumValue:maximumValue]; + } else { + _possibleValues = [[FBTweakNumericRange alloc] initWithMinimumValue:maximumValue maximumValue:maximumValue]; + } +} + - (void)setCurrentValue:(FBTweakValue)currentValue { NSAssert(!self.isAction, @"actions cannot have non-default values"); - if (_minimumValue != nil && currentValue != nil && [_minimumValue compare:currentValue] == NSOrderedDescending) { - currentValue = _minimumValue; - } - - if (_maximumValue != nil && currentValue != nil && [_maximumValue compare:currentValue] == NSOrderedAscending) { - currentValue = _maximumValue; + if (_possibleValues != nil && currentValue != nil) { + if ([_possibleValues isKindOfClass:[NSArray class]]) { + if ([_possibleValues indexOfObject:currentValue] == NSNotFound) { + currentValue = _defaultValue; + } + } else if ([_possibleValues isKindOfClass:[NSDictionary class]]) { + if ([[_possibleValues allKeys] indexOfObject:currentValue] == NSNotFound) { + currentValue = _defaultValue; + } + } else { + FBTweakValue minimumValue = self.minimumValue; + if (self.minimumValue != nil && currentValue != nil && [minimumValue compare:currentValue] == NSOrderedDescending) { + currentValue = minimumValue; + } + + FBTweakValue maximumValue = self.maximumValue; + if (maximumValue != nil && currentValue != nil && [maximumValue compare:currentValue] == NSOrderedAscending) { + currentValue = maximumValue; + } + } } - + if (_currentValue != currentValue) { _currentValue = currentValue; [[NSUserDefaults standardUserDefaults] setObject:_currentValue forKey:_identifier]; diff --git a/FBTweak/FBTweakInline.h b/FBTweak/FBTweakInline.h index 4e40d473..0e5b6b1b 100644 --- a/FBTweak/FBTweakInline.h +++ b/FBTweak/FBTweakInline.h @@ -8,8 +8,6 @@ */ #import "FBTweakInlineInternal.h" -#import "FBTweak+Array.h" -#import "FBTweak+Dictionary.h" /** @abstract Common parameters in these macros. diff --git a/FBTweak/FBTweakInline.m b/FBTweak/FBTweakInline.m index d79d7436..d1b52095 100644 --- a/FBTweak/FBTweakInline.m +++ b/FBTweak/FBTweakInline.m @@ -21,6 +21,10 @@ #if FB_TWEAK_ENABLED +// cast to a pointer to a block, dereferenece said pointer, call said block +#define entry_block_field(type, entry, field) (*(type (^__unsafe_unretained (*))(void))(entry->field))() +#define entry_value(type, entry) entry_block_field(type, entry, value) + extern NSString *_FBTweakIdentifier(fb_tweak_entry *entry) { return [NSString stringWithFormat:@"FBTweak:%@-%@-%@", *entry->category, *entry->collection, *entry->name]; @@ -31,63 +35,35 @@ FBTweak *tweak = [[FBTweak alloc] initWithIdentifier:identifier]; tweak.name = *entry->name; + if (entry->possible != NULL) { + tweak.possibleValues = entry_block_field(id, entry, possible); + } + if (strcmp(*entry->encoding, FBTweakEncodingAction) == 0) { - tweak.defaultValue = *(dispatch_block_t __strong *)entry->value; + tweak.defaultValue = *(__strong dispatch_block_t *)entry->value; } else if (strcmp(*entry->encoding, @encode(BOOL)) == 0) { - tweak.defaultValue = @(*(BOOL *)entry->value); + tweak.defaultValue = @(entry_value(BOOL, entry)); } else if (strcmp(*entry->encoding, @encode(float)) == 0) { - tweak.defaultValue = [NSNumber numberWithFloat:*(float *)entry->value]; - if (entry->min != NULL && entry->max != NULL) { - tweak.minimumValue = [NSNumber numberWithFloat:*(float *)entry->min]; - tweak.maximumValue = [NSNumber numberWithFloat:*(float *)entry->max]; - } + tweak.defaultValue = [NSNumber numberWithFloat:entry_value(float, entry)]; } else if (strcmp(*entry->encoding, @encode(double)) == 0) { - tweak.defaultValue = [NSNumber numberWithDouble:*(double *)entry->value]; - if (entry->min != NULL && entry->max != NULL) { - tweak.minimumValue = [NSNumber numberWithDouble:*(double *)entry->min]; - tweak.maximumValue = [NSNumber numberWithDouble:*(double *)entry->max]; - } + tweak.defaultValue = [NSNumber numberWithDouble:entry_value(double, entry)]; } else if (strcmp(*entry->encoding, @encode(short)) == 0) { - tweak.defaultValue = [NSNumber numberWithShort:*(short *)entry->value]; - if (entry->min != NULL && entry->max != NULL) { - tweak.minimumValue = [NSNumber numberWithShort:*(short *)entry->min]; - tweak.maximumValue = [NSNumber numberWithShort:*(short *)entry->max]; - } + tweak.defaultValue = [NSNumber numberWithShort:entry_value(short, entry)]; } else if (strcmp(*entry->encoding, @encode(unsigned short)) == 0) { - tweak.defaultValue = [NSNumber numberWithUnsignedShort:*(unsigned short int *)entry->value]; - if (entry->min != NULL && entry->max != NULL) { - tweak.minimumValue = [NSNumber numberWithUnsignedShort:*(unsigned short *)entry->min]; - tweak.maximumValue = [NSNumber numberWithUnsignedShort:*(unsigned short *)entry->max]; - } + tweak.defaultValue = [NSNumber numberWithUnsignedShort:entry_value(unsigned short, entry)]; } else if (strcmp(*entry->encoding, @encode(int)) == 0) { - tweak.defaultValue = [NSNumber numberWithInt:*(int *)entry->value]; - if (entry->min != NULL && entry->max != NULL) { - tweak.minimumValue = [NSNumber numberWithInt:*(int *)entry->min]; - tweak.maximumValue = [NSNumber numberWithInt:*(int *)entry->max]; - } + tweak.defaultValue = [NSNumber numberWithInt:entry_value(int, entry)]; } else if (strcmp(*entry->encoding, @encode(unsigned int)) == 0) { - tweak.defaultValue = [NSNumber numberWithUnsignedInt:*(unsigned int *)entry->value]; - if (entry->min != NULL && entry->max != NULL) { - tweak.minimumValue = [NSNumber numberWithUnsignedInt:*(unsigned int *)entry->min]; - tweak.maximumValue = [NSNumber numberWithUnsignedInt:*(unsigned int *)entry->max]; - } + tweak.defaultValue = [NSNumber numberWithUnsignedInt:entry_value(unsigned int, entry)]; } else if (strcmp(*entry->encoding, @encode(long long)) == 0) { - tweak.defaultValue = [NSNumber numberWithLongLong:*(long long *)entry->value]; - if (entry->min != NULL && entry->max != NULL) { - tweak.minimumValue = [NSNumber numberWithLongLong:*(long long *)entry->min]; - tweak.maximumValue = [NSNumber numberWithLongLong:*(long long *)entry->max]; - } + tweak.defaultValue = [NSNumber numberWithLongLong:entry_value(long long, entry)]; } else if (strcmp(*entry->encoding, @encode(unsigned long long)) == 0) { - tweak.defaultValue = [NSNumber numberWithUnsignedLongLong:*(unsigned long long *)entry->value]; - if (entry->min != NULL && entry->max != NULL) { - tweak.minimumValue = [NSNumber numberWithUnsignedLongLong:*(unsigned long long *)entry->min]; - tweak.maximumValue = [NSNumber numberWithUnsignedLongLong:*(unsigned long long *)entry->max]; - } + tweak.defaultValue = [NSNumber numberWithUnsignedLongLong:entry_value(unsigned long long, entry)]; } else if (*entry->encoding[0] == '[') { // Assume it's a C string. - tweak.defaultValue = [NSString stringWithUTF8String:entry->value]; + tweak.defaultValue = [NSString stringWithUTF8String:entry_value(char *, entry)]; } else if (strcmp(*entry->encoding, @encode(id)) == 0) { - tweak.defaultValue = *((__unsafe_unretained id *)entry->value); + tweak.defaultValue = entry_value(id, entry); } else { NSCAssert(NO, @"Unknown encoding %s for tweak %@. Value was %p.", *entry->encoding, _FBTweakIdentifier(entry), entry->value); tweak = nil; diff --git a/FBTweak/FBTweakInlineInternal.h b/FBTweak/FBTweakInlineInternal.h index 176d8c51..edc7ca9d 100644 --- a/FBTweak/FBTweakInlineInternal.h +++ b/FBTweak/FBTweakInlineInternal.h @@ -40,8 +40,7 @@ typedef struct { FBTweakLiteralString *collection; FBTweakLiteralString *name; void *value; - void *min; - void *max; + void *possible; char **encoding; } fb_tweak_entry; @@ -59,31 +58,36 @@ extern NSString *_FBTweakIdentifier(fb_tweak_entry *entry); #define __FBTweakIndex(_1, _2, _3, value, ...) value #define __FBTweakIndexCount(...) __FBTweakIndex(__VA_ARGS__, 3, 2, 1) -#define __FBTweakHasRange1(__withoutRange, __withRange, ...) __withoutRange -#define __FBTweakHasRange2(__withoutRange, __withRange, ...) __FBTweakInvalidNumberOfArgumentsPassed -#define __FBTweakHasRange3(__withoutRange, __withRange, ...) __withRange -#define _FBTweakHasRange(__withoutRange, __withRange, ...) __FBTweakConcat(__FBTweakHasRange, __FBTweakIndexCount(__VA_ARGS__))(__withoutRange, __withRange) +#define __FBTweakDispatch1(__withoutRange, __withRange, __withPossible, ...) __withoutRange +#define __FBTweakDispatch2(__withoutRange, __withRange, __withPossible, ...) __withPossible +#define __FBTweakDispatch3(__withoutRange, __withRange, __withPossible, ...) __withRange +#define _FBTweakDispatch(__withoutRange, __withRange, __withPossible, ...) __FBTweakConcat(__FBTweakDispatch, __FBTweakIndexCount(__VA_ARGS__))(__withoutRange, __withRange, __withPossible) #define _FBTweakInlineWithoutRange(category_, collection_, name_, default_) \ ((^{ \ - return _FBTweakInlineWithRangeInternal(category_, collection_, name_, default_, NULL, NULL); \ + return _FBTweakInlineWithPossibleInternal(category_, collection_, name_, default_, NULL); \ })()) #define _FBTweakInlineWithRange(category_, collection_, name_, default_, min_, max_) \ ((^{ \ __attribute__((used)) static __typeof__(default_) min__ = (__typeof__(default_))min_; \ __attribute__((used)) static __typeof__(default_) max__ = (__typeof__(default_))max_; \ - return _FBTweakInlineWithRangeInternal(category_, collection_, name_, default_, &min__, &max__); \ + return _FBTweakInlineWithPossibleInternal(category_, collection_, name_, default_, [[FBTweakNumericRange alloc] initWithMinimumValue:@(min__) maximumValue:@(max__)]); \ })()) -#define _FBTweakInlineWithRangeInternal(category_, collection_, name_, default_, min__, max__) \ +#define _FBTweakInlineWithPossible(category_, collection_, name_, default_, possible_) \ +((^{ \ + return _FBTweakInlineWithPossibleInternal(category_, collection_, name_, default_, possible_); \ +})()) +#define _FBTweakInlineWithPossibleInternal(category_, collection_, name_, default_, possible_) \ ((^{ \ /* store the tweak data in the binary at compile time. */ \ __attribute__((used)) static FBTweakLiteralString category__ = category_; \ __attribute__((used)) static FBTweakLiteralString collection__ = collection_; \ __attribute__((used)) static FBTweakLiteralString name__ = name_; \ - __attribute__((used)) static __typeof__(default_) default__ = default_; \ + __attribute__((used)) static void *default__ = (__bridge void *) ^{ return default_; }; \ + __attribute__((used)) static void *possible__ = (__bridge void *) ^{ return possible_; }; \ __attribute__((used)) static char *encoding__ = (char *)@encode(__typeof__(default_)); \ __attribute__((used)) __attribute__((section (FBTweakSegmentName "," FBTweakSectionName))) static fb_tweak_entry entry = \ - { &category__, &collection__, &name__, (void *)&default__, (void *)min__, (void *)max__, &encoding__ }; \ + { &category__, &collection__, &name__, (void *)&default__, (void *)&possible__, &encoding__ }; \ \ /* find the registered tweak with the given identifier. */ \ FBTweakStore *store = [FBTweakStore sharedInstance]; \ @@ -95,7 +99,7 @@ extern NSString *_FBTweakIdentifier(fb_tweak_entry *entry); \ return __inline_tweak; \ })()) -#define _FBTweakInline(category_, collection_, name_, ...) _FBTweakHasRange(_FBTweakInlineWithoutRange, _FBTweakInlineWithRange, __VA_ARGS__)(category_, collection_, name_, __VA_ARGS__) +#define _FBTweakInline(category_, collection_, name_, ...) _FBTweakDispatch(_FBTweakInlineWithoutRange, _FBTweakInlineWithRange, _FBTweakInlineWithPossible, __VA_ARGS__)(category_, collection_, name_, __VA_ARGS__) #define _FBTweakValueInternal(tweak_, category_, collection_, name_, default_) \ ((^{ \ @@ -144,19 +148,29 @@ extern NSString *_FBTweakIdentifier(fb_tweak_entry *entry); FBTweak *__value_tweak = _FBTweakInlineWithRange(category_, collection_, name_, default_, min_, max_); \ return _FBTweakValueInternal(__value_tweak, category_, collection_, name_, default_); \ })()) -#define _FBTweakValue(category_, collection_, name_, ...) _FBTweakHasRange(_FBTweakValueWithoutRange, _FBTweakValueWithRange, __VA_ARGS__)(category_, collection_, name_, __VA_ARGS__) +#define _FBTweakValueWithPossible(category_, collection_, name_, default_, possible_) \ +((^{ \ + FBTweak *__value_tweak = _FBTweakInlineWithPossible(category_, collection_, name_, default_, possible_); \ + return _FBTweakValueInternal(__value_tweak, category_, collection_, name_, default_); \ +})()) +#define _FBTweakValue(category_, collection_, name_, ...) _FBTweakDispatch(_FBTweakValueWithoutRange, _FBTweakValueWithRange, _FBTweakValueWithPossible, __VA_ARGS__)(category_, collection_, name_, __VA_ARGS__) #define _FBTweakBindWithoutRange(object_, property_, category_, collection_, name_, default_) \ ((^{ \ FBTweak *__bind_tweak = _FBTweakInlineWithoutRange(category_, collection_, name_, default_); \ - _FBTweakBindWithRangeInternal(object_, property_, category_, collection_, name_, default_, __bind_tweak); \ + _FBTweakBindInternal(object_, property_, category_, collection_, name_, default_, __bind_tweak); \ })()) #define _FBTweakBindWithRange(object_, property_, category_, collection_, name_, default_, min_, max_) \ ((^{ \ FBTweak *__bind_tweak = _FBTweakInlineWithRange(category_, collection_, name_, default_, min_, max_); \ - _FBTweakBindWithRangeInternal(object_, property_, category_, collection_, name_, default_, __bind_tweak); \ + _FBTweakBindInternal(object_, property_, category_, collection_, name_, default_, __bind_tweak); \ +})()) +#define _FBTweakBindWithPossible(object_, property_, category_, collection_, name_, default_, possible_) \ +((^{ \ + FBTweak *__bind_tweak = _FBTweakInlineWithPossible(category_, collection_, name_, default_, possible_); \ + _FBTweakBindInternal(object_, property_, category_, collection_, name_, default_, __bind_tweak); \ })()) -#define _FBTweakBindWithRangeInternal(object_, property_, category_, collection_, name_, default_, tweak_) \ +#define _FBTweakBindInternal(object_, property_, category_, collection_, name_, default_, tweak_) \ ((^{ \ object_.property_ = _FBTweakValueInternal(tweak_, category_, collection_, name_, default_); \ _FBTweakBindObserver *observer__ = [[_FBTweakBindObserver alloc] initWithTweak:tweak_ block:^(id object__) { \ @@ -165,7 +179,7 @@ extern NSString *_FBTweakIdentifier(fb_tweak_entry *entry); }]; \ [observer__ attachToObject:object_]; \ })()) -#define _FBTweakBind(object_, property_, category_, collection_, name_, ...) _FBTweakHasRange(_FBTweakBindWithoutRange, _FBTweakBindWithRange, __VA_ARGS__)(object_, property_, category_, collection_, name_, __VA_ARGS__) +#define _FBTweakBind(object_, property_, category_, collection_, name_, ...) _FBTweakDispatch(_FBTweakBindWithoutRange, _FBTweakBindWithRange, _FBTweakBindWithPossible, __VA_ARGS__)(object_, property_, category_, collection_, name_, __VA_ARGS__) #define _FBTweakAction(category_, collection_, name_, ...) \ _FBTweakActionInternal(category_, collection_, name_, __COUNTER__, __VA_ARGS__) @@ -181,7 +195,7 @@ extern NSString *_FBTweakIdentifier(fb_tweak_entry *entry); &__FBTweakConcat(__fb_tweak_action_collection_, suffix_), \ &__FBTweakConcat(__fb_tweak_action_name_, suffix_), \ &__FBTweakConcat(__fb_tweak_action_block_, suffix_), \ - NULL, NULL, \ + NULL, \ &__FBTweakConcat(__fb_tweak_action_encoding_, suffix_), \ }; \ diff --git a/FBTweak/_FBTweakArrayViewController.h b/FBTweak/_FBTweakArrayViewController.h index 3f5693ff..d0926c2e 100644 --- a/FBTweak/_FBTweakArrayViewController.h +++ b/FBTweak/_FBTweakArrayViewController.h @@ -12,13 +12,21 @@ @class FBTweak; /** - @abstract Displays list of values in an array tweak. + @abstract Displays list of values in an array tweak. */ @interface _FBTweakArrayViewController : UIViewController /** - @abstract The array tweak to display in the view controller. + @abstract Creates a tweak array view controller. + @discussion This is the designated initializer. + @param tweak The tweak the view controller is for. + Must not be nil, and must have an array of possibleValues. */ -@property (nonatomic, strong) FBTweak *tweak; +- (instancetype)initWithTweak:(FBTweak *)tweak; + +/** + @abstract The array tweak to display in the view controller. + */ +@property (nonatomic, strong, readonly) FBTweak *tweak; @end diff --git a/FBTweak/_FBTweakArrayViewController.m b/FBTweak/_FBTweakArrayViewController.m index 681d71f0..bb7b90be 100644 --- a/FBTweak/_FBTweakArrayViewController.m +++ b/FBTweak/_FBTweakArrayViewController.m @@ -9,15 +9,27 @@ #import "_FBTweakArrayViewController.h" #import "FBTweak.h" -#import "FBTweak+Array.h" @interface _FBTweakArrayViewController () -@property (nonatomic, strong) UITableView *tableView; - @end -@implementation _FBTweakArrayViewController +@implementation _FBTweakArrayViewController { + UITableView *_tableView; +} + +- (instancetype)initWithTweak:(FBTweak *)tweak +{ + NSParameterAssert(tweak != nil); + NSParameterAssert([tweak.possibleValues isKindOfClass:[NSArray class]]); + + if ((self = [super init])) { + _tweak = tweak; + self.title = _tweak.name; + } + + return self; +} - (void)viewDidLoad { @@ -43,7 +55,7 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return self.tweak.arrayValue.count; + return [self.tweak.possibleValues count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath @@ -54,7 +66,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:_FBTweakDictionaryViewControllerCellIdentifier]; } - FBTweakValue rowValue = self.tweak.arrayValue[indexPath.row]; + FBTweakValue rowValue = self.tweak.possibleValues[indexPath.row]; NSString *stringValue = [rowValue description]; cell.textLabel.text = stringValue; @@ -69,7 +81,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - NSString *value = self.tweak.arrayValue[indexPath.row]; + NSString *value = self.tweak.possibleValues[indexPath.row]; self.tweak.currentValue = value; [self.navigationController popViewControllerAnimated:YES]; } diff --git a/FBTweak/_FBTweakCollectionViewController.m b/FBTweak/_FBTweakCollectionViewController.m index 1cf2088b..9345f4ea 100644 --- a/FBTweak/_FBTweakCollectionViewController.m +++ b/FBTweak/_FBTweakCollectionViewController.m @@ -9,11 +9,10 @@ #import "FBTweakCollection.h" #import "FBTweakCategory.h" +#import "FBTweak.h" #import "_FBTweakCollectionViewController.h" #import "_FBTweakTableViewCell.h" -#import "FBTweak+Dictionary.h" #import "_FBTweakDictionaryViewController.h" -#import "FBTweak+Array.h" #import "_FBTweakArrayViewController.h" @interface _FBTweakCollectionViewController () @@ -137,13 +136,11 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath { FBTweakCollection *collection = _sortedCollections[indexPath.section]; FBTweak *tweak = collection.tweaks[indexPath.row]; - if ([tweak isDictionary]) { - _FBTweakDictionaryViewController *vc = [[_FBTweakDictionaryViewController alloc] init]; - vc.tweak = tweak; + if ([tweak.possibleValues isKindOfClass:[NSDictionary class]]) { + _FBTweakDictionaryViewController *vc = [[_FBTweakDictionaryViewController alloc] initWithTweak:tweak]; [self.navigationController pushViewController:vc animated:YES]; - } else if ([tweak isArray]) { - _FBTweakArrayViewController *vc = [[_FBTweakArrayViewController alloc] init]; - vc.tweak = tweak; + } else if ([tweak.possibleValues isKindOfClass:[NSArray class]]) { + _FBTweakArrayViewController *vc = [[_FBTweakArrayViewController alloc] initWithTweak:tweak]; [self.navigationController pushViewController:vc animated:YES]; } } diff --git a/FBTweak/_FBTweakDictionaryViewController.h b/FBTweak/_FBTweakDictionaryViewController.h index 475a79e4..5b1b43fd 100644 --- a/FBTweak/_FBTweakDictionaryViewController.h +++ b/FBTweak/_FBTweakDictionaryViewController.h @@ -12,13 +12,21 @@ @class FBTweak; /** - @abstract Displays list of keys in a dictionary tweak. + @abstract Displays list of keys in a dictionary tweak. */ @interface _FBTweakDictionaryViewController : UIViewController /** - @abstract The dictionary tweak to display in the view controller. + @abstract Creates a tweak dictionary view controller. + @discussion This is the designated initializer. + @param tweak The tweak the view controller is for. Must + not be nil, and must have a dictionary of possibleValues. */ -@property (nonatomic, strong) FBTweak *tweak; +- (instancetype)initWithTweak:(FBTweak *)tweak; + +/** + @abstract The dictionary tweak to display in the view controller. + */ +@property (nonatomic, strong, readonly) FBTweak *tweak; @end diff --git a/FBTweak/_FBTweakDictionaryViewController.m b/FBTweak/_FBTweakDictionaryViewController.m index 83899905..ffcff5da 100644 --- a/FBTweak/_FBTweakDictionaryViewController.m +++ b/FBTweak/_FBTweakDictionaryViewController.m @@ -9,15 +9,27 @@ #import "_FBTweakDictionaryViewController.h" #import "FBTweak.h" -#import "FBTweak+Dictionary.h" @interface _FBTweakDictionaryViewController () -@property (nonatomic, strong) UITableView *tableView; - @end -@implementation _FBTweakDictionaryViewController +@implementation _FBTweakDictionaryViewController { + UITableView *_tableView; +} + +- (instancetype)initWithTweak:(FBTweak *)tweak +{ + NSParameterAssert(tweak != nil); + NSParameterAssert([tweak.possibleValues isKindOfClass:[NSDictionary class]]); + + if ((self = [super init])) { + _tweak = tweak; + self.title = _tweak.name; + } + + return self; +} - (void)viewDidLoad { @@ -43,7 +55,7 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - return self.tweak.allKeys.count; + return [_tweak.possibleValues count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath @@ -55,12 +67,13 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } NSArray *allKeys = [self allTweakKeys]; - NSString *key = allKeys[indexPath.row]; - cell.textLabel.text = key; + FBTweakValue key = allKeys[indexPath.row]; + NSString *value = _tweak.possibleValues[key]; + cell.textLabel.text = value; cell.accessoryType = UITableViewCellAccessoryNone; - NSString *selectedKey = (self.tweak.currentValue ?: self.tweak.defaultValue); - if ([selectedKey isEqualToString:key]) { + NSString *selectedKey = (_tweak.currentValue ?: _tweak.defaultValue); + if ([selectedKey isEqual:key]) { cell.accessoryType = UITableViewCellAccessoryCheckmark; } @@ -78,8 +91,11 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath - (NSArray *)allTweakKeys { - return [self.tweak.allKeys sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { - return [obj1 compare:obj2]; + // Sort by visible name. + return [[_tweak.possibleValues allKeys] sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { + id value1 = _tweak.possibleValues[obj1]; + id value2 = _tweak.possibleValues[obj2]; + return [value1 compare:value2]; }]; } diff --git a/FBTweak/_FBTweakTableViewCell.m b/FBTweak/_FBTweakTableViewCell.m index ae3ef649..a49dc067 100644 --- a/FBTweak/_FBTweakTableViewCell.m +++ b/FBTweak/_FBTweakTableViewCell.m @@ -9,8 +9,6 @@ #import "FBTweak.h" #import "_FBTweakTableViewCell.h" -#import "FBTweak+Dictionary.h" -#import "FBTweak+Array.h" typedef NS_ENUM(NSUInteger, _FBTweakTableViewCellMode) { _FBTweakTableViewCellModeNone = 0, @@ -110,10 +108,9 @@ - (void)setTweak:(FBTweak *)tweak FBTweakValue value = (_tweak.currentValue ?: _tweak.defaultValue); _FBTweakTableViewCellMode mode = _FBTweakTableViewCellModeNone; - if ([tweak isDictionary]) { + if ([tweak.possibleValues isKindOfClass:[NSDictionary class]]) { mode = _FBTweakTableViewCellModeDictionary; - } else if ([tweak isArray]) { - value = [value description]; + } else if ([tweak.possibleValues isKindOfClass:[NSArray class]]) { mode = _FBTweakTableViewCellModeArray; } else if ([value isKindOfClass:[NSString class]]) { mode = _FBTweakTableViewCellModeString; @@ -329,11 +326,11 @@ - (void)_updateValue:(FBTweakValue)value primary:(BOOL)primary write:(BOOL)write _textField.text = [NSString stringWithFormat:format, [value doubleValue]]; } else if (_mode == _FBTweakTableViewCellModeDictionary) { if (primary) { - self.detailTextLabel.text = value; + self.detailTextLabel.text = _tweak.possibleValues[value]; } } else if (_mode == _FBTweakTableViewCellModeArray) { if (primary) { - self.detailTextLabel.text = value; + self.detailTextLabel.text = [value description]; } } } diff --git a/FBTweakExample/FBAppDelegate.m b/FBTweakExample/FBAppDelegate.m index 92be829b..614f9231 100644 --- a/FBTweakExample/FBAppDelegate.m +++ b/FBTweakExample/FBAppDelegate.m @@ -11,8 +11,6 @@ #import #import #import -#import -#import #import "FBAppDelegate.h" @@ -27,7 +25,6 @@ @implementation FBAppDelegate { UIButton *_tweaksButton; FBTweak *_buttonColorTweak; FBTweak *_flipTweak; - FBTweak *_rotationTweak; } FBTweakAction(@"Actions", @"Global", @"Hello", ^{ @@ -90,21 +87,16 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [alert show]; }); - NSDictionary *dict = @{@"black": [UIColor blackColor], - @"blue": [UIColor blueColor], - @"green": [UIColor greenColor], - }; - _buttonColorTweak = FBDictionaryTweak(@"Content", @"Tweaks Button", @"Color", dict, @"black"); - [_buttonColorTweak addObserver:self]; - NSString *key = _buttonColorTweak.currentValue ?: _buttonColorTweak.defaultValue; - UIColor *color = _buttonColorTweak.dictionaryValue[key]; - [_tweaksButton setTitleColor:color forState:UIControlStateNormal]; - - _rotationTweak = FBArrayTweak(@"Content", @"Text", @"Rotation (radians)", @[@(0), @(M_PI_4), @(M_PI_2)], @(0)); - FBTweakValue rotation = _rotationTweak.currentValue ?: _rotationTweak.defaultValue; + NSNumber *colorIndex = FBTweakValue(@"Content", @"Tweaks Button", @"Color", @(0), (@{ + @(0) : @"Black", + @(1) : @"Blue", + @(2) : @"Green", + })); + [_tweaksButton setTitleColor:(colorIndex.integerValue == 0 ? [UIColor blackColor] : colorIndex.integerValue == 1 ? [UIColor blueColor] : [UIColor greenColor]) forState:UIControlStateNormal]; + + NSNumber *rotation = FBTweakValue(@"Content", @"Text", @"Rotation (radians)", @(0), (@[@(0), @(M_PI_4), @(M_PI_2)])); _label.transform = CGAffineTransformRotate(CGAffineTransformIdentity, [rotation floatValue]); - [_rotationTweak addObserver:self]; - + return YES; } @@ -113,15 +105,6 @@ - (void)tweakDidChange:(FBTweak *)tweak if (tweak == _flipTweak) { _window.layer.sublayerTransform = CATransform3DMakeScale(1.0, [_flipTweak.currentValue boolValue] ? -1.0 : 1.0, 1.0); } - else if (tweak == _buttonColorTweak) { - NSString *key = _buttonColorTweak.currentValue ?: _buttonColorTweak.defaultValue; - UIColor *titleColor = [_buttonColorTweak dictionaryValue][key]; - [_tweaksButton setTitleColor:titleColor forState:UIControlStateNormal]; - } - else if (tweak == _rotationTweak) { - FBTweakValue value = _rotationTweak.currentValue ?: _rotationTweak.defaultValue; - _label.transform = CGAffineTransformRotate(CGAffineTransformIdentity, [value floatValue]); - } } - (void)buttonTapped diff --git a/FBTweakTests/FBTweakInlineTestsARC.m b/FBTweakTests/FBTweakInlineTestsARC.m index b162603d..839848da 100644 --- a/FBTweakTests/FBTweakInlineTestsARC.m +++ b/FBTweakTests/FBTweakInlineTestsARC.m @@ -83,22 +83,15 @@ - (void)testValueTypes __attribute__((unused)) NSString *testNSString = FBTweakValue(@"NSString", @"NSString", @"NSString", @"one"); XCTAssertEqualObjects(testNSString, @"one", @"NSString %@", testNSString); - __attribute__((unused)) NSString *testNSArray = FBArrayTweakValue(@"NSArray", @"NSArray", @"NSArray", @[@"one", @"two", @"three"], @"two"); - XCTAssertEqualObjects(testNSArray, @"two", @"NSString %@", testNSArray); - - __attribute__((unused)) NSString *testNSDictionaryKey = FBDictionaryTweakValue(@"NSDictionaryKey", @"NSDictionaryKey", @"NSDictionaryKey", @{@"key1":@"value1", @"key2":@"value2"}, @"key2"); - XCTAssertEqualObjects(testNSDictionaryKey, @"key2", @"NSString %@", testNSDictionaryKey); - - __attribute__((unused)) NSString *testNSDictionaryValue = FBDictionaryTweakValueForKey(@"NSDictionaryValue", @"NSDictionaryValue", @"NSDictionaryValue", @{@"key1":@"value1", @"key2":@"value2"}, @"key2"); - XCTAssertEqualObjects(testNSDictionaryValue, @"value2", @"NSString %@", testNSDictionaryValue); + __attribute__((unused)) NSString *testNSArray = FBTweakValue(@"NSArray", @"NSArray", @"NSArray", @"two", (@[@"one", @"two", @"three"])); + XCTAssertEqualObjects(testNSArray, @"two", @"NSArray %@", testNSArray); + + __attribute__((unused)) NSString *testNSDictionary = FBTweakValue(@"NSDictionary", @"NSDictionary", @"NSDictionary", @"key2", (@{@"key1":@"value1", @"key2":@"value2"})); + XCTAssertEqualObjects(testNSDictionary, @"key2", @"NSString %@", testNSDictionary); } - (void)testConstantValues { - const double constInput = 1.0; - double constValue = FBTweakValue(@"Const", @"Const", @"Const", constInput); - XCTAssertEqual(constValue, constInput, @"Const %f %f", constInput, constValue); - static const double staticConstInput = 1.0; double staticConstValue = FBTweakValue(@"Static", @"Static", @"Static", staticConstInput); XCTAssertEqual(staticConstValue, staticConstInput, @"Static %f %f", staticConstInput, staticConstValue); diff --git a/FBTweakTests/FBTweakInlineTestsMRR.m b/FBTweakTests/FBTweakInlineTestsMRR.m index bad43f15..2c6d5a7c 100644 --- a/FBTweakTests/FBTweakInlineTestsMRR.m +++ b/FBTweakTests/FBTweakInlineTestsMRR.m @@ -58,22 +58,15 @@ - (void)testValueTypes __attribute__((unused)) NSString *testNSString = FBTweakValue(@"NSString", @"NSString", @"NSString", @"one"); XCTAssertEqualObjects(testNSString, @"one", @"NSString %@", testNSString); - __attribute__((unused)) NSString *testNSArray = FBArrayTweakValue(@"NSArray", @"NSArray", @"NSArray", @[@"one", @"two", @"three"], @"two"); - XCTAssertEqualObjects(testNSArray, @"two", @"NSString %@", testNSArray); - - __attribute__((unused)) NSString *testNSDictionaryKey = FBDictionaryTweakValue(@"NSDictionaryKey", @"NSDictionaryKey", @"NSDictionaryKey", @{@"key1":@"value1", @"key2":@"value2"}, @"key2"); - XCTAssertEqualObjects(testNSDictionaryKey, @"key2", @"NSString %@", testNSDictionaryKey); - - __attribute__((unused)) NSString *testNSDictionaryValue = FBDictionaryTweakValueForKey(@"NSDictionaryValue", @"NSDictionaryValue", @"NSDictionaryValue", @{@"key1":@"value1", @"key2":@"value2"}, @"key2"); - XCTAssertEqualObjects(testNSDictionaryValue, @"value2", @"NSString %@", testNSDictionaryValue); + __attribute__((unused)) NSString *testNSArray = FBTweakValue(@"NSArray", @"NSArray", @"NSArray", @"two", (@[@"one", @"two", @"three"])); + XCTAssertEqualObjects(testNSArray, @"two", @"NSArray %@", testNSArray); + + __attribute__((unused)) NSString *testNSDictionary = FBTweakValue(@"NSDictionary", @"NSDictionary", @"NSDictionary", @"key2", (@{@"key1":@"value1", @"key2":@"value2"})); + XCTAssertEqualObjects(testNSDictionary, @"key2", @"NSString %@", testNSDictionary); } - (void)testConstantValues { - const double constInput = 1.0; - double constValue = FBTweakValue(@"Const", @"Const", @"Const", constInput); - XCTAssertEqual(constValue, constInput, @"Const %f %f", constInput, constValue); - static const double staticConstInput = 1.0; double staticConstValue = FBTweakValue(@"Static", @"Static", @"Static", staticConstInput); XCTAssertEqual(staticConstValue, staticConstInput, @"Static %f %f", staticConstInput, staticConstValue); diff --git a/README.md b/README.md index 1424d8ac..0b544200 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ The simplest way to create a tweak is to replace a constant with `FBTweakValue`: CGFloat animationDuration = FBTweakValue(@"Category", @"Group", @"Duration", 0.5); ``` -The first three parameters are where the tweak is listed and what it's called, and the last one is the default value. You can pass in many types of constants for the default: +The first three parameters are where the tweak is listed and what it's called, and the last one is the default value. You can pass in many types of values for the default: booleans, numbers, or strings. ```objective-c if (FBTweakValue(@"Category", @"Feature", @"Enabled", YES)) { @@ -32,7 +32,13 @@ if (FBTweakValue(@"Category", @"Feature", @"Enabled", YES)) { In release builds, the `FBTweakValue` macro expands to just the default value, so there's no performance impact. In debug builds, though, it fetches the latest value of the tweak. -For numeric tweaks (`NSInteger`, `CGFloat`, and others), you can pass an extra two parameters which are used as the minimum and maximum value for the tweak: +You can also pass a fourth parameter, which will constrain the possible values for a tweak. The fourth parameter can be an array, dictionary, or an `FBTweakNumericRange`. If it's a dictionary, the values should be strings to show in the list of choices. Arrays will show the values' `description` as choices. (Note that you have to surround array and dictionary literals with an extra set of parentheses.) + +```objective-c +self.initialMode = FBTweakValue(@"Header", @"Initial", @"Mode", @(FBSimpleMode), (@{ @(FBSimpleMode) : @"Simple", @(FBAdvancedMode) : @"Advanced" })); +``` + +For numeric tweaks (`NSInteger`, `CGFloat`, and others), you can instead pass two parameters, which constrain the value to a `FBTweakNumericRange`: ```objective-c self.red = FBTweakValue(@"Header", @"Colors", @"Red", 0.5, 0.0, 1.0); From ea8515fc11642b82830dea81204e933073050397 Mon Sep 17 00:00:00 2001 From: Grant Paul Date: Thu, 29 Jan 2015 00:58:28 -0800 Subject: [PATCH 23/44] Minor cleanup for block-based values and dictionary tweaks. --- FBTweak/FBTweakInline.m | 28 ++++++++++++---------------- FBTweak/FBTweakInlineInternal.h | 3 +++ FBTweakExample/FBAppDelegate.m | 17 ++++++++++++----- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/FBTweak/FBTweakInline.m b/FBTweak/FBTweakInline.m index d1b52095..82a51e68 100644 --- a/FBTweak/FBTweakInline.m +++ b/FBTweak/FBTweakInline.m @@ -21,10 +21,6 @@ #if FB_TWEAK_ENABLED -// cast to a pointer to a block, dereferenece said pointer, call said block -#define entry_block_field(type, entry, field) (*(type (^__unsafe_unretained (*))(void))(entry->field))() -#define entry_value(type, entry) entry_block_field(type, entry, value) - extern NSString *_FBTweakIdentifier(fb_tweak_entry *entry) { return [NSString stringWithFormat:@"FBTweak:%@-%@-%@", *entry->category, *entry->collection, *entry->name]; @@ -36,34 +32,34 @@ tweak.name = *entry->name; if (entry->possible != NULL) { - tweak.possibleValues = entry_block_field(id, entry, possible); + tweak.possibleValues = fb_tweak_entry_block_field(id, entry, possible); } if (strcmp(*entry->encoding, FBTweakEncodingAction) == 0) { tweak.defaultValue = *(__strong dispatch_block_t *)entry->value; } else if (strcmp(*entry->encoding, @encode(BOOL)) == 0) { - tweak.defaultValue = @(entry_value(BOOL, entry)); + tweak.defaultValue = @(fb_tweak_entry_block_field(BOOL, entry, value)); } else if (strcmp(*entry->encoding, @encode(float)) == 0) { - tweak.defaultValue = [NSNumber numberWithFloat:entry_value(float, entry)]; + tweak.defaultValue = [NSNumber numberWithFloat:fb_tweak_entry_block_field(float, entry, value)]; } else if (strcmp(*entry->encoding, @encode(double)) == 0) { - tweak.defaultValue = [NSNumber numberWithDouble:entry_value(double, entry)]; + tweak.defaultValue = [NSNumber numberWithDouble:fb_tweak_entry_block_field(double, entry, value)]; } else if (strcmp(*entry->encoding, @encode(short)) == 0) { - tweak.defaultValue = [NSNumber numberWithShort:entry_value(short, entry)]; + tweak.defaultValue = [NSNumber numberWithShort:fb_tweak_entry_block_field(short, entry, value)]; } else if (strcmp(*entry->encoding, @encode(unsigned short)) == 0) { - tweak.defaultValue = [NSNumber numberWithUnsignedShort:entry_value(unsigned short, entry)]; + tweak.defaultValue = [NSNumber numberWithUnsignedShort:fb_tweak_entry_block_field(unsigned short, entry, value)]; } else if (strcmp(*entry->encoding, @encode(int)) == 0) { - tweak.defaultValue = [NSNumber numberWithInt:entry_value(int, entry)]; + tweak.defaultValue = [NSNumber numberWithInt:fb_tweak_entry_block_field(int, entry, value)]; } else if (strcmp(*entry->encoding, @encode(unsigned int)) == 0) { - tweak.defaultValue = [NSNumber numberWithUnsignedInt:entry_value(unsigned int, entry)]; + tweak.defaultValue = [NSNumber numberWithUnsignedInt:fb_tweak_entry_block_field(unsigned int, entry, value)]; } else if (strcmp(*entry->encoding, @encode(long long)) == 0) { - tweak.defaultValue = [NSNumber numberWithLongLong:entry_value(long long, entry)]; + tweak.defaultValue = [NSNumber numberWithLongLong:fb_tweak_entry_block_field(long long, entry, value)]; } else if (strcmp(*entry->encoding, @encode(unsigned long long)) == 0) { - tweak.defaultValue = [NSNumber numberWithUnsignedLongLong:entry_value(unsigned long long, entry)]; + tweak.defaultValue = [NSNumber numberWithUnsignedLongLong:fb_tweak_entry_block_field(unsigned long long, entry, value)]; } else if (*entry->encoding[0] == '[') { // Assume it's a C string. - tweak.defaultValue = [NSString stringWithUTF8String:entry_value(char *, entry)]; + tweak.defaultValue = [NSString stringWithUTF8String:fb_tweak_entry_block_field(char *, entry, value)]; } else if (strcmp(*entry->encoding, @encode(id)) == 0) { - tweak.defaultValue = entry_value(id, entry); + tweak.defaultValue = fb_tweak_entry_block_field(id, entry, value); } else { NSCAssert(NO, @"Unknown encoding %s for tweak %@. Value was %p.", *entry->encoding, _FBTweakIdentifier(entry), entry->value); tweak = nil; diff --git a/FBTweak/FBTweakInlineInternal.h b/FBTweak/FBTweakInlineInternal.h index edc7ca9d..4335d68b 100644 --- a/FBTweak/FBTweakInlineInternal.h +++ b/FBTweak/FBTweakInlineInternal.h @@ -44,6 +44,9 @@ typedef struct { char **encoding; } fb_tweak_entry; +// cast to a pointer to a block, dereferenece said pointer, call said block +#define fb_tweak_entry_block_field(type, entry, field) (*(type (^__unsafe_unretained (*))(void))(entry->field))() + extern NSString *_FBTweakIdentifier(fb_tweak_entry *entry); #if __has_feature(objc_arc) diff --git a/FBTweakExample/FBAppDelegate.m b/FBTweakExample/FBAppDelegate.m index 614f9231..1ae62f1b 100644 --- a/FBTweakExample/FBAppDelegate.m +++ b/FBTweakExample/FBAppDelegate.m @@ -87,12 +87,19 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [alert show]; }); - NSNumber *colorIndex = FBTweakValue(@"Content", @"Tweaks Button", @"Color", @(0), (@{ - @(0) : @"Black", - @(1) : @"Blue", - @(2) : @"Green", + typedef NS_ENUM(NSUInteger, FBColor) { + FBBlackColor, + FBBlueColor, + FBGreenColor, + }; + + NSNumber *colorIndex = FBTweakValue(@"Content", @"Tweaks Button", @"Color", @(FBBlackColor), (@{ + @(FBBlackColor) : @"Black", + @(FBBlueColor) : @"Blue", + @(FBGreenColor) : @"Green", })); - [_tweaksButton setTitleColor:(colorIndex.integerValue == 0 ? [UIColor blackColor] : colorIndex.integerValue == 1 ? [UIColor blueColor] : [UIColor greenColor]) forState:UIControlStateNormal]; + UIColor *color = (colorIndex.integerValue == FBBlackColor ? [UIColor blackColor] : colorIndex.integerValue == FBBlueColor ? [UIColor blueColor] : [UIColor greenColor]); + [_tweaksButton setTitleColor:color forState:UIControlStateNormal]; NSNumber *rotation = FBTweakValue(@"Content", @"Text", @"Rotation (radians)", @(0), (@[@(0), @(M_PI_4), @(M_PI_2)])); _label.transform = CGAffineTransformRotate(CGAffineTransformIdentity, [rotation floatValue]); From f3ea9b198b67c462a172c08c500dbb76625e0d63 Mon Sep 17 00:00:00 2001 From: Alexey Matjuk Date: Thu, 29 Jan 2015 19:50:10 +0300 Subject: [PATCH 24/44] fixed compilation errors --- FBTweak/FBTweak.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/FBTweak/FBTweak.m b/FBTweak/FBTweak.m index c8e819f6..b2001dbc 100644 --- a/FBTweak/FBTweak.m +++ b/FBTweak/FBTweak.m @@ -96,7 +96,7 @@ - (BOOL)isAction - (FBTweakValue)minimumValue { if ([_possibleValues isKindOfClass:[FBTweakNumericRange class]]) { - return [_possibleValues minimumValue]; + return [(FBTweakNumericRange *)_possibleValues minimumValue]; } else { return nil; } @@ -107,7 +107,7 @@ - (void)setMinimumValue:(FBTweakValue)minimumValue if (minimumValue == nil) { _possibleValues = nil; } else if ([_possibleValues isKindOfClass:[FBTweakNumericRange class]]) { - _possibleValues = [[FBTweakNumericRange alloc] initWithMinimumValue:minimumValue maximumValue:[_possibleValues maximumValue]]; + _possibleValues = [[FBTweakNumericRange alloc] initWithMinimumValue:minimumValue maximumValue:[(FBTweakNumericRange *)_possibleValues maximumValue]]; } else { _possibleValues = [[FBTweakNumericRange alloc] initWithMinimumValue:minimumValue maximumValue:minimumValue]; } @@ -116,7 +116,7 @@ - (void)setMinimumValue:(FBTweakValue)minimumValue - (FBTweakValue)maximumValue { if ([_possibleValues isKindOfClass:[FBTweakNumericRange class]]) { - return [_possibleValues maximumValue]; + return [(FBTweakNumericRange *)_possibleValues maximumValue]; } else { return nil; } @@ -127,7 +127,7 @@ - (void)setMaximumValue:(FBTweakValue)maximumValue if (maximumValue == nil) { _possibleValues = nil; } else if ([_possibleValues isKindOfClass:[FBTweakNumericRange class]]) { - _possibleValues = [[FBTweakNumericRange alloc] initWithMinimumValue:[_possibleValues minimumValue] maximumValue:maximumValue]; + _possibleValues = [[FBTweakNumericRange alloc] initWithMinimumValue:[(FBTweakNumericRange *)_possibleValues minimumValue] maximumValue:maximumValue]; } else { _possibleValues = [[FBTweakNumericRange alloc] initWithMinimumValue:maximumValue maximumValue:maximumValue]; } From edfad0d0557481ee5502983aa26476b9a5416360 Mon Sep 17 00:00:00 2001 From: Grant Paul Date: Thu, 29 Jan 2015 10:48:34 -0800 Subject: [PATCH 25/44] Use notifications rather than querying state to allow Tweaks to be used in app extensions. --- FBTweak/FBTweakShakeWindow.m | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/FBTweak/FBTweakShakeWindow.m b/FBTweak/FBTweakShakeWindow.m index 07ab780e..76af4ccd 100644 --- a/FBTweak/FBTweakShakeWindow.m +++ b/FBTweak/FBTweakShakeWindow.m @@ -17,6 +17,35 @@ @implementation FBTweakShakeWindow { BOOL _shaking; + BOOL _active; +} + +- (instancetype)initWithFrame:(CGRect)frame +{ + if ((self = [super initWithFrame:frame])) { + // Maintain this state manually using notifications so Tweaks can be used in app extensions, where UIApplication is unavailable. + _active = YES; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillResignActiveWithNotification:) name:UIApplicationWillResignActiveNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationDidBecomeActiveWithNotification:) name:UIApplicationDidBecomeActiveNotification object:nil]; + } + + return self; +} + +- (void)dealloc +{ + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; +} + +- (void)_applicationWillResignActiveWithNotification:(NSNotification *)notification +{ + _active = NO; +} + +- (void)_applicationDidBecomeActiveWithNotification:(NSNotification *)notification +{ + _active = YES; } - (void)tweakViewControllerPressedDone:(FBTweakViewController *)tweakViewController @@ -46,7 +75,7 @@ - (BOOL)_shouldPresentTweaks #if TARGET_IPHONE_SIMULATOR && FB_TWEAK_ENABLED return YES; #elif FB_TWEAK_ENABLED - return _shaking && [[UIApplication sharedApplication] applicationState] == UIApplicationStateActive; + return _shaking && _active; #else return NO; #endif From 25c31e747532a0ba6a6fd8fd1dfae0ada510b201 Mon Sep 17 00:00:00 2001 From: Grant Paul Date: Fri, 20 Mar 2015 10:58:13 +0000 Subject: [PATCH 26/44] Update podspec for 2.0.0. --- Tweaks.podspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tweaks.podspec b/Tweaks.podspec index 799a602e..e46c9db2 100644 --- a/Tweaks.podspec +++ b/Tweaks.podspec @@ -1,11 +1,11 @@ Pod::Spec.new do |spec| spec.name = 'Tweaks' - spec.version = '1.1.0' + spec.version = '2.0.0' spec.license = { :type => 'BSD' } spec.homepage = 'https://github.com/facebook/Tweaks' spec.authors = { 'Grant Paul' => 'tweaks@grantpaul.com', 'Kimon Tsinteris' => 'kimon@mac.com' } spec.summary = 'Easily adjust parameters for iOS apps in development.' - spec.source = { :git => 'https://github.com/facebook/Tweaks.git', :tag => '1.1.0' } + spec.source = { :git => 'https://github.com/facebook/Tweaks.git', :tag => '2.0.0' } spec.source_files = 'FBTweak/*.{h,m}' spec.requires_arc = true spec.social_media_url = 'https://twitter.com/fbOpenSource' From 1b58019dfa1fef3a82a7cffb7b3b7c5789356335 Mon Sep 17 00:00:00 2001 From: Dave Lee Date: Sat, 4 Apr 2015 12:12:24 -0700 Subject: [PATCH 27/44] Update README to show range is fifth parameter Unless the README is using zero based counting. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0b544200..3d4aa63e 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ if (FBTweakValue(@"Category", @"Feature", @"Enabled", YES)) { In release builds, the `FBTweakValue` macro expands to just the default value, so there's no performance impact. In debug builds, though, it fetches the latest value of the tweak. -You can also pass a fourth parameter, which will constrain the possible values for a tweak. The fourth parameter can be an array, dictionary, or an `FBTweakNumericRange`. If it's a dictionary, the values should be strings to show in the list of choices. Arrays will show the values' `description` as choices. (Note that you have to surround array and dictionary literals with an extra set of parentheses.) +You can also pass a fifth parameter, which will constrain the possible values for a tweak. The fifth parameter can be an array, dictionary, or an `FBTweakNumericRange`. If it's a dictionary, the values should be strings to show in the list of choices. Arrays will show the values' `description` as choices. (Note that you have to surround array and dictionary literals with an extra set of parentheses.) ```objective-c self.initialMode = FBTweakValue(@"Header", @"Initial", @"Mode", @(FBSimpleMode), (@{ @(FBSimpleMode) : @"Simple", @(FBAdvancedMode) : @"Advanced" })); From b0a5f8f6a327efdc0e5de7ea007c7c2c41048039 Mon Sep 17 00:00:00 2001 From: Grant Paul Date: Fri, 10 Apr 2015 12:15:02 -0700 Subject: [PATCH 28/44] Update patent grant: http://fb.me/patents2 --- PATENTS | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/PATENTS b/PATENTS index 2623c557..3f2b05f5 100644 --- a/PATENTS +++ b/PATENTS @@ -1,23 +1,33 @@ -Additional Grant of Patent Rights +Additional Grant of Patent Rights Version 2 "Software" means the Tweaks software distributed by Facebook, Inc. -Facebook hereby grants you a perpetual, worldwide, royalty-free, non-exclusive, -irrevocable (subject to the termination provision below) license under any -rights in any patent claims owned by Facebook, to make, have made, use, sell, -offer to sell, import, and otherwise transfer the Software. For avoidance of -doubt, no license is granted under Facebook’s rights in any patent claims that -are infringed by (i) modifications to the Software made by you or a third party, -or (ii) the Software in combination with any software or other technology -provided by you or a third party. +Facebook, Inc. ("Facebook") hereby grants to each recipient of the Software +("you") a perpetual, worldwide, royalty-free, non-exclusive, irrevocable +(subject to the termination provision below) license under any Necessary +Claims, to make, have made, use, sell, offer to sell, import, and otherwise +transfer the Software. For avoidance of doubt, no license is granted under +Facebook’s rights in any patent claims that are infringed by (i) modifications +to the Software made by you or any third party or (ii) the Software in +combination with any software or other technology. The license granted hereunder will terminate, automatically and without notice, -for anyone that makes any claim (including by filing any lawsuit, assertion or -other action) alleging (a) direct, indirect, or contributory infringement or -inducement to infringe any patent: (i) by Facebook or any of its subsidiaries or -affiliates, whether or not such claim is related to the Software, (ii) by any -party if such claim arises in whole or in part from any software, product or -service of Facebook or any of its subsidiaries or affiliates, whether or not -such claim is related to the Software, or (iii) by any party relating to the -Software; or (b) that any right in any patent claim of Facebook is invalid or -unenforceable. +if you (or any of your subsidiaries, corporate affiliates or agents) initiate +directly or indirectly, or take a direct financial interest in, any Patent +Assertion: (i) against Facebook or any of its subsidiaries or corporate +affiliates, (ii) against any party if such Patent Assertion arises in whole or +in part from any software, technology, product or service of Facebook or any of +its subsidiaries or corporate affiliates, or (iii) against any party relating +to the Software. Notwithstanding the foregoing, if Facebook or any of its +subsidiaries or corporate affiliates files a lawsuit alleging patent +infringement against you in the first instance, and you respond by filing a +patent infringement counterclaim in that lawsuit against that party that is +unrelated to the Software, the license granted hereunder will not terminate +under section (i) of this paragraph due to such counterclaim. + +A "Necessary Claim" is a claim of a patent owned by Facebook that is +necessarily infringed by the Software standing alone. + +A "Patent Assertion" is any lawsuit or other action alleging direct, indirect, +or contributory infringement or inducement to infringe any patent, including a +cross-claim or counterclaim. From 298047226e59eac35f01a68de2bebdb1f90e8dec Mon Sep 17 00:00:00 2001 From: tuyou Date: Mon, 13 Apr 2015 23:51:56 +0800 Subject: [PATCH 29/44] Press done button directly will not update the last modified tweak data immediately Force the last modified tweak data to be updated once the done button is pressed. --- FBTweak/FBTweakShakeWindow.m | 1 + 1 file changed, 1 insertion(+) diff --git a/FBTweak/FBTweakShakeWindow.m b/FBTweak/FBTweakShakeWindow.m index 76af4ccd..6fed5cdf 100644 --- a/FBTweak/FBTweakShakeWindow.m +++ b/FBTweak/FBTweakShakeWindow.m @@ -51,6 +51,7 @@ - (void)_applicationDidBecomeActiveWithNotification:(NSNotification *)notificati - (void)tweakViewControllerPressedDone:(FBTweakViewController *)tweakViewController { [[NSNotificationCenter defaultCenter] postNotificationName:FBTweakShakeViewControllerDidDismissNotification object:tweakViewController]; + [tweakViewController.view endEditing:YES]; [tweakViewController dismissViewControllerAnimated:YES completion:NULL]; } From b1c5148498369d1f047c08c57dc31aaf33dbca06 Mon Sep 17 00:00:00 2001 From: Nolan Waite Date: Tue, 14 Apr 2015 15:57:44 -0300 Subject: [PATCH 30/44] Override -initWithCoder: in FBTweakShakeWindow so nib-created windows work too. Now changing your window's class in the nib makes tweaks work a-ok. --- FBTweak/FBTweakShakeWindow.m | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/FBTweak/FBTweakShakeWindow.m b/FBTweak/FBTweakShakeWindow.m index 6fed5cdf..77c3b103 100644 --- a/FBTweak/FBTweakShakeWindow.m +++ b/FBTweak/FBTweakShakeWindow.m @@ -23,15 +23,28 @@ @implementation FBTweakShakeWindow { - (instancetype)initWithFrame:(CGRect)frame { if ((self = [super initWithFrame:frame])) { - // Maintain this state manually using notifications so Tweaks can be used in app extensions, where UIApplication is unavailable. - _active = YES; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillResignActiveWithNotification:) name:UIApplicationWillResignActiveNotification object:nil]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationDidBecomeActiveWithNotification:) name:UIApplicationDidBecomeActiveNotification object:nil]; + _FBTweakShakeWindowCommonInit(self); } return self; } +- (instancetype)initWithCoder:(NSCoder *)coder +{ + if ((self = [super initWithCoder:coder])) { + _FBTweakShakeWindowCommonInit(self); + } + return self; +} + +static void _FBTweakShakeWindowCommonInit(FBTweakShakeWindow *self) +{ + // Maintain this state manually using notifications so Tweaks can be used in app extensions, where UIApplication is unavailable. + self->_active = YES; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationWillResignActiveWithNotification:) name:UIApplicationWillResignActiveNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_applicationDidBecomeActiveWithNotification:) name:UIApplicationDidBecomeActiveNotification object:nil]; +} + - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil]; From c85e38070a52e5da145cfc2284d2aafffb1882e1 Mon Sep 17 00:00:00 2001 From: David Callahan Date: Wed, 15 Apr 2015 08:41:31 -0700 Subject: [PATCH 31/44] Baseline code assumes that the DATA segment immediately follows the TEXT segment so that file offsets can be used to compute in memory addresses. The modified code eliminates this assumption and access the FBTweak section correctly when there are holes in the virtual address space. --- FBTweak/FBTweakInline.m | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/FBTweak/FBTweakInline.m b/FBTweak/FBTweakInline.m index 82a51e68..9808a456 100644 --- a/FBTweak/FBTweakInline.m +++ b/FBTweak/FBTweakInline.m @@ -86,10 +86,12 @@ + (void)load #ifdef __LP64__ typedef uint64_t fb_tweak_value; typedef struct section_64 fb_tweak_section; + typedef struct mach_header_64 fb_tweak_header; #define fb_tweak_getsectbynamefromheader getsectbynamefromheader_64 #else typedef uint32_t fb_tweak_value; typedef struct section fb_tweak_section; + typedef struct mach_header fb_tweak_header; #define fb_tweak_getsectbynamefromheader getsectbynamefromheader #endif @@ -99,15 +101,16 @@ + (void)load dladdr(&_FBTweakIdentifier, &info); const fb_tweak_value mach_header = (fb_tweak_value)info.dli_fbase; - const fb_tweak_section *section = fb_tweak_getsectbynamefromheader((void *)mach_header, FBTweakSegmentName, FBTweakSectionName); - - if (section == NULL) { - return; - } - - for (fb_tweak_value addr = section->offset; addr < section->offset + section->size; addr += sizeof(fb_tweak_entry)) { - fb_tweak_entry *entry = (fb_tweak_entry *)(mach_header + addr); - + + unsigned long size; + fb_tweak_entry * data = (fb_tweak_entry *) + getsectiondata((const fb_tweak_header*) mach_header, + FBTweakSegmentName, FBTweakSectionName, &size); + if(data == NULL) + return ; + size_t count = size/sizeof(fb_tweak_entry); + for(int i = 0; i < count; i++) { + fb_tweak_entry * entry = data+i; FBTweakCategory *category = [store tweakCategoryWithName:*entry->category]; if (category == nil) { category = [[FBTweakCategory alloc] initWithName:*entry->category]; From 6da40054db201bb96d177da79ea1bc68169e0eca Mon Sep 17 00:00:00 2001 From: David Callahan Date: Wed, 15 Apr 2015 08:41:31 -0700 Subject: [PATCH 32/44] Baseline code assumes that the DATA segment immediately follows the TEXT segment so that file offsets can be used to compute in memory addresses. The modified code eliminates this assumption and access the FBTweak section correctly when there are holes in the virtual address space. --- FBTweak/FBTweakInline.m | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/FBTweak/FBTweakInline.m b/FBTweak/FBTweakInline.m index 9808a456..7fba75d9 100644 --- a/FBTweak/FBTweakInline.m +++ b/FBTweak/FBTweakInline.m @@ -103,14 +103,13 @@ + (void)load const fb_tweak_value mach_header = (fb_tweak_value)info.dli_fbase; unsigned long size; - fb_tweak_entry * data = (fb_tweak_entry *) - getsectiondata((const fb_tweak_header*) mach_header, - FBTweakSegmentName, FBTweakSectionName, &size); - if(data == NULL) + fb_tweak_entry *data = (fb_tweak_entry *) getsectiondata((const fb_tweak_header *) mach_header, FBTweakSegmentName, FBTweakSectionName, &size); + if (data == NULL) { return ; - size_t count = size/sizeof(fb_tweak_entry); - for(int i = 0; i < count; i++) { - fb_tweak_entry * entry = data+i; + } + size_t count = size / sizeof(fb_tweak_entry); + for (size_t i = 0; i < count; i++) { + fb_tweak_entry *entry = &data[i]; FBTweakCategory *category = [store tweakCategoryWithName:*entry->category]; if (category == nil) { category = [[FBTweakCategory alloc] initWithName:*entry->category]; From 9763b8268e5fb5ef5ea676b0ae9b13c0f1bebd14 Mon Sep 17 00:00:00 2001 From: Arkadiusz Holko Date: Mon, 20 Apr 2015 12:31:24 +0200 Subject: [PATCH 33/44] Add NSCoding conformance to FBTweakNumericRange --- FBTweak/FBTweak.h | 2 +- FBTweak/FBTweak.m | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/FBTweak/FBTweak.h b/FBTweak/FBTweak.h index fd1aff38..a04c10c6 100644 --- a/FBTweak/FBTweak.h +++ b/FBTweak/FBTweak.h @@ -23,7 +23,7 @@ typedef id FBTweakValue; @abstract Represents a range of values for a numeric tweak. @discussion Use this for the -possibleValues on a tweak. */ -@interface FBTweakNumericRange : NSObject +@interface FBTweakNumericRange : NSObject /** @abstract Creates a new numeric range. diff --git a/FBTweak/FBTweak.m b/FBTweak/FBTweak.m index b2001dbc..a0671e50 100644 --- a/FBTweak/FBTweak.m +++ b/FBTweak/FBTweak.m @@ -24,6 +24,21 @@ - (instancetype)initWithMinimumValue:(FBTweakValue)minimumValue maximumValue:(FB return self; } +- (instancetype)initWithCoder:(NSCoder *)coder +{ + FBTweakValue minimumValue = [coder decodeObjectForKey:@"minimumValue"]; + FBTweakValue maximumValue = [coder decodeObjectForKey:@"maximumValue"]; + self = [self initWithMinimumValue:minimumValue maximumValue:maximumValue]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)coder +{ + [coder encodeObject:_minimumValue forKey:@"minimumValue"]; + [coder encodeObject:_maximumValue forKey:@"maximumValue"]; +} + @end @implementation FBTweak { From 0ddf017f806127ad1f6325c11537d056db8ec7fa Mon Sep 17 00:00:00 2001 From: Arkadiusz Holko Date: Tue, 21 Apr 2015 15:46:40 +0200 Subject: [PATCH 34/44] Fix a bug with integer tweak showing as float Previously integer mode wasn't chosen for tweaks, which code path wasn't reached during program execution. --- FBTweak/_FBTweakTableViewCell.m | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/FBTweak/_FBTweakTableViewCell.m b/FBTweak/_FBTweakTableViewCell.m index a49dc067..b344999b 100644 --- a/FBTweak/_FBTweakTableViewCell.m +++ b/FBTweak/_FBTweakTableViewCell.m @@ -121,7 +121,9 @@ - (void)setTweak:(FBTweak *)tweak strcmp([value objCType], @encode(_Bool)) == 0) { mode = _FBTweakTableViewCellModeBoolean; } else if (strcmp([value objCType], @encode(NSInteger)) == 0 || - strcmp([value objCType], @encode(NSUInteger)) == 0) { + strcmp([value objCType], @encode(NSUInteger)) == 0 || + strcmp([value objCType], @encode(int)) == 0 || + strcmp([value objCType], @encode(long)) == 0) { mode = _FBTweakTableViewCellModeInteger; } else { mode = _FBTweakTableViewCellModeReal; From 9a79094bf5a7da061f786d08c8eda84b21e6e692 Mon Sep 17 00:00:00 2001 From: dasmer Date: Wed, 22 Apr 2015 00:35:40 -0400 Subject: [PATCH 35/44] Add Travis CI --- .travis.yml | 2 + .../xcshareddata/xcschemes/FBTweak.xcscheme | 110 ++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 .travis.yml create mode 100644 FBTweak.xcodeproj/xcshareddata/xcschemes/FBTweak.xcscheme diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..6032e889 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,2 @@ +language: objective-c +script: xctool test -project FBTweak.xcodeproj -scheme FBTweak -sdk iphonesimulator8.1 -destination "platform=iOS Simulator,OS=8.1,name=iPhone 6" \ No newline at end of file diff --git a/FBTweak.xcodeproj/xcshareddata/xcschemes/FBTweak.xcscheme b/FBTweak.xcodeproj/xcshareddata/xcschemes/FBTweak.xcscheme new file mode 100644 index 00000000..4375acd2 --- /dev/null +++ b/FBTweak.xcodeproj/xcshareddata/xcschemes/FBTweak.xcscheme @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 3a71bfcdc5f5b2ce050d47210f996e160b400826 Mon Sep 17 00:00:00 2001 From: dasmer Date: Wed, 22 Apr 2015 00:41:24 -0400 Subject: [PATCH 36/44] [README.md] Add Travis badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3d4aa63e..50ce4088 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # Tweaks Tweaks is an easy way to fine-tune an iOS app. +[![Build Status](https://travis-ci.org/facebook/Tweaks.svg?branch=master)](https://travis-ci.org/facebook/Tweaks) ![Tweaks](https://github.com/facebook/Tweaks/blob/master/Images/Tweaks.gif?raw=true) From c50e4addd2cce6189fa6d77cba8a4997729d6859 Mon Sep 17 00:00:00 2001 From: dasmer Date: Wed, 22 Apr 2015 00:48:21 -0400 Subject: [PATCH 37/44] [.travis.yml] Add newline at end of file --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6032e889..c015ace3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,2 +1,3 @@ language: objective-c -script: xctool test -project FBTweak.xcodeproj -scheme FBTweak -sdk iphonesimulator8.1 -destination "platform=iOS Simulator,OS=8.1,name=iPhone 6" \ No newline at end of file +script: xctool test -project FBTweak.xcodeproj -scheme FBTweak -sdk iphonesimulator8.1 -destination "platform=iOS Simulator,OS=8.1,name=iPhone 6" + From c92dbf38b6733b21cd3ef86e0c79e486d5a8fc2e Mon Sep 17 00:00:00 2001 From: James Pearce Date: Wed, 22 Apr 2015 13:43:17 -0700 Subject: [PATCH 38/44] Bump for travis --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 50ce4088..520ed1a5 100644 --- a/README.md +++ b/README.md @@ -145,4 +145,3 @@ See the CONTRIBUTING file for how to help out. ## License Tweaks is BSD-licensed. We also provide an additional patent grant. - From d628caa9fb845b012acb9772c733799966de143e Mon Sep 17 00:00:00 2001 From: Brian Amerige Date: Tue, 16 Jun 2015 19:06:11 -0700 Subject: [PATCH 39/44] Fix Compilation of Tweaks With Stricter UIAlertView Usage Errors Summary: Gate our UIAlertView usage to non-extensions. Task ID: #7351285 Reviewers:natansh, cgenzmer, b3ll, suv, nyn531, zsh, grp, wang, arig Test Plan: Build for iOS 9, it compiles. Buildbot. Differential Revision: https://phabricator.fb.com/D2159720 --- FBTweak/_FBTweakCategoryViewController.m | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/FBTweak/_FBTweakCategoryViewController.m b/FBTweak/_FBTweakCategoryViewController.m index 8b863da8..2d0c2ded 100644 --- a/FBTweak/_FBTweakCategoryViewController.m +++ b/FBTweak/_FBTweakCategoryViewController.m @@ -18,7 +18,7 @@ @interface _FBTweakCategoryViewController () = 8000 } #endif @@ -161,7 +163,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; - + FBTweakCategory *category = _sortedCategories[indexPath.row]; cell.textLabel.text = category.name; From 415c389bc86509cd19ab23f5e42937fe27ad8b52 Mon Sep 17 00:00:00 2001 From: Brian Amerige Date: Tue, 16 Jun 2015 23:35:26 -0700 Subject: [PATCH 40/44] Remove extra whitespace added. --- FBTweak/_FBTweakCategoryViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FBTweak/_FBTweakCategoryViewController.m b/FBTweak/_FBTweakCategoryViewController.m index 2d0c2ded..81cc739f 100644 --- a/FBTweak/_FBTweakCategoryViewController.m +++ b/FBTweak/_FBTweakCategoryViewController.m @@ -99,7 +99,7 @@ - (void)_reset [_store reset]; }]; [alertController addAction:resetAction]; - + [self presentViewController:alertController animated:YES completion:NULL]; } else { #endif From e5f9e6814554f81b604af142e28eeac43f9c3edf Mon Sep 17 00:00:00 2001 From: Brian Amerige Date: Tue, 16 Jun 2015 23:38:15 -0700 Subject: [PATCH 41/44] Remove more inadvertent whitespace. --- FBTweak/_FBTweakCategoryViewController.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/FBTweak/_FBTweakCategoryViewController.m b/FBTweak/_FBTweakCategoryViewController.m index 81cc739f..81bdd6c8 100644 --- a/FBTweak/_FBTweakCategoryViewController.m +++ b/FBTweak/_FBTweakCategoryViewController.m @@ -18,7 +18,7 @@ @interface _FBTweakCategoryViewController () Date: Wed, 15 Jul 2015 14:06:25 +0200 Subject: [PATCH 42/44] static_assert when _FBTweakValueInternal() used from C++ --- FBTweak/FBTweakInlineInternal.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/FBTweak/FBTweakInlineInternal.h b/FBTweak/FBTweakInlineInternal.h index 4335d68b..b79ce42c 100644 --- a/FBTweak/FBTweakInlineInternal.h +++ b/FBTweak/FBTweakInlineInternal.h @@ -103,7 +103,11 @@ extern NSString *_FBTweakIdentifier(fb_tweak_entry *entry); return __inline_tweak; \ })()) #define _FBTweakInline(category_, collection_, name_, ...) _FBTweakDispatch(_FBTweakInlineWithoutRange, _FBTweakInlineWithRange, _FBTweakInlineWithPossible, __VA_ARGS__)(category_, collection_, name_, __VA_ARGS__) - + +#ifdef __cplusplus +#define _FBTweakValueInternal(...) \ +((^{ static_assert(false, "C++ not supported at present. See https://github.com/facebook/Tweaks/issues/84."); nil; })()) +#else #define _FBTweakValueInternal(tweak_, category_, collection_, name_, default_) \ ((^{ \ /* returns a correctly typed version of the current tweak value */ \ @@ -140,6 +144,7 @@ extern NSString *_FBTweakIdentifier(fb_tweak_entry *entry); default: [currentValue UTF8String] \ ); \ })()) +#endif #define _FBTweakValueWithoutRange(category_, collection_, name_, default_) \ ((^{ \ From 53fe17383664578adf16b794b43a450e4eade48d Mon Sep 17 00:00:00 2001 From: Scott Goodfriend Date: Thu, 6 Aug 2015 10:12:15 -0700 Subject: [PATCH 43/44] Fixng warnings from Implicit retain of 'self' within blocks. --- FBTweak/_FBTweakCategoryViewController.m | 3 ++- FBTweak/_FBTweakCollectionViewController.m | 16 +++++++++------- FBTweak/_FBTweakDictionaryViewController.m | 5 +++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/FBTweak/_FBTweakCategoryViewController.m b/FBTweak/_FBTweakCategoryViewController.m index 81bdd6c8..e76ee56d 100644 --- a/FBTweak/_FBTweakCategoryViewController.m +++ b/FBTweak/_FBTweakCategoryViewController.m @@ -95,8 +95,9 @@ - (void)_reset }]; [alertController addAction:cancelAction]; + __weak typeof(self) weakSelf = self; UIAlertAction *resetAction = [UIAlertAction actionWithTitle:@"Reset" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { - [_store reset]; + [weakSelf.store reset]; }]; [alertController addAction:resetAction]; diff --git a/FBTweak/_FBTweakCollectionViewController.m b/FBTweak/_FBTweakCollectionViewController.m index 9345f4ea..397143e9 100644 --- a/FBTweak/_FBTweakCollectionViewController.m +++ b/FBTweak/_FBTweakCollectionViewController.m @@ -84,15 +84,17 @@ - (void)_keyboardFrameChanged:(NSNotification *)notification NSTimeInterval duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; UIViewAnimationCurve curve = [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue]; - + + __weak typeof(self) weakSelf = self; + __weak typeof(_tableView) weakTableView = _tableView; void (^animations)() = ^{ - UIEdgeInsets contentInset = _tableView.contentInset; - contentInset.bottom = (self.view.bounds.size.height - CGRectGetMinY(endFrame)); - _tableView.contentInset = contentInset; + UIEdgeInsets contentInset = weakTableView.contentInset; + contentInset.bottom = (weakSelf.view.bounds.size.height - CGRectGetMinY(endFrame)); + weakTableView.contentInset = contentInset; - UIEdgeInsets scrollIndicatorInsets = _tableView.scrollIndicatorInsets; - scrollIndicatorInsets.bottom = (self.view.bounds.size.height - CGRectGetMinY(endFrame)); - _tableView.scrollIndicatorInsets = scrollIndicatorInsets; + UIEdgeInsets scrollIndicatorInsets = weakTableView.scrollIndicatorInsets; + scrollIndicatorInsets.bottom = (weakSelf.view.bounds.size.height - CGRectGetMinY(endFrame)); + weakTableView.scrollIndicatorInsets = scrollIndicatorInsets; }; UIViewAnimationOptions options = (curve << 16) | UIViewAnimationOptionBeginFromCurrentState; diff --git a/FBTweak/_FBTweakDictionaryViewController.m b/FBTweak/_FBTweakDictionaryViewController.m index ffcff5da..ac36c14e 100644 --- a/FBTweak/_FBTweakDictionaryViewController.m +++ b/FBTweak/_FBTweakDictionaryViewController.m @@ -92,9 +92,10 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath - (NSArray *)allTweakKeys { // Sort by visible name. + __weak typeof(self) weakSelf = self; return [[_tweak.possibleValues allKeys] sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { - id value1 = _tweak.possibleValues[obj1]; - id value2 = _tweak.possibleValues[obj2]; + id value1 = weakSelf.tweak.possibleValues[obj1]; + id value2 = weakSelf.tweak.possibleValues[obj2]; return [value1 compare:value2]; }]; } From 4c28a4d149416069552f4aa86d2be8732e493067 Mon Sep 17 00:00:00 2001 From: Steven Jeram Date: Mon, 21 Mar 2016 17:04:28 -0700 Subject: [PATCH 44/44] Fix Android build errors --- FBTweak/FBTweakInline.m | 4 ++-- FBTweak/_FBTweakCategoryViewController.m | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/FBTweak/FBTweakInline.m b/FBTweak/FBTweakInline.m index 7fba75d9..11b4e4de 100644 --- a/FBTweak/FBTweakInline.m +++ b/FBTweak/FBTweakInline.m @@ -14,13 +14,13 @@ #import "FBTweakStore.h" #import "FBTweakCategory.h" +#if FB_TWEAK_ENABLED + #import #import #import #import -#if FB_TWEAK_ENABLED - extern NSString *_FBTweakIdentifier(fb_tweak_entry *entry) { return [NSString stringWithFormat:@"FBTweak:%@-%@-%@", *entry->category, *entry->collection, *entry->name]; diff --git a/FBTweak/_FBTweakCategoryViewController.m b/FBTweak/_FBTweakCategoryViewController.m index e76ee56d..162b0034 100644 --- a/FBTweak/_FBTweakCategoryViewController.m +++ b/FBTweak/_FBTweakCategoryViewController.m @@ -85,7 +85,7 @@ - (void)_done - (void)_reset { -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 8000 +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 if ([UIAlertController class] != nil) { UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Are you sure?" message:@"Are you sure you want to reset your tweaks? This cannot be undone." @@ -114,7 +114,7 @@ - (void)_reset otherButtonTitles:@"Reset", nil]; [alert show]; #endif -#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 8000 +#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 } #endif }