flip_the_switch 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/.travis.yml +3 -1
  4. data/CHANGELOG.md +10 -0
  5. data/Classes/FlipTheSwitch/Shared/FTSFeature.h +11 -0
  6. data/Classes/FlipTheSwitch/Shared/FTSFeature.m +67 -0
  7. data/Classes/FlipTheSwitch/Shared/FTSFlipTheSwitch.h +21 -0
  8. data/Classes/FlipTheSwitch/Shared/FTSFlipTheSwitch.m +144 -0
  9. data/Classes/FlipTheSwitch/iOS/FTSFeatureCell.h +17 -0
  10. data/Classes/FlipTheSwitch/iOS/FTSFeatureCell.m +12 -0
  11. data/Classes/FlipTheSwitch/iOS/FTSFeatureConfigurationViewController.h +5 -0
  12. data/Classes/FlipTheSwitch/iOS/FTSFeatureConfigurationViewController.m +142 -0
  13. data/Classes/FlipTheSwitch/iOS/FTSFeatureDescriptionLabel.h +5 -0
  14. data/Classes/FlipTheSwitch/iOS/FTSFeatureDescriptionLabel.m +13 -0
  15. data/Example/Colors-OSX/AppDelegate.h +7 -0
  16. data/Example/Colors-OSX/AppDelegate.m +17 -0
  17. data/Example/Colors-OSX/Base.lproj/Main.storyboard +744 -0
  18. data/Example/Colors-OSX/ColoredViews/GreenView.h +5 -0
  19. data/Example/Colors-OSX/ColoredViews/GreenView.m +12 -0
  20. data/Example/Colors-OSX/ColoredViews/PurpleView.h +5 -0
  21. data/Example/Colors-OSX/ColoredViews/PurpleView.m +12 -0
  22. data/Example/Colors-OSX/ColoredViews/RedView.h +5 -0
  23. data/Example/Colors-OSX/ColoredViews/RedView.m +12 -0
  24. data/Example/Colors-OSX/ColoredViews/YellowView.h +5 -0
  25. data/Example/Colors-OSX/ColoredViews/YellowView.m +12 -0
  26. data/Example/Colors-OSX/FTSFlipTheSwitch+Features.h +45 -0
  27. data/Example/Colors-OSX/FTSFlipTheSwitch+Features.m +165 -0
  28. data/Example/Colors-OSX/Features.plist +39 -0
  29. data/Example/Colors-OSX/Images.xcassets/AppIcon.appiconset/Contents.json +58 -0
  30. data/Example/Colors-OSX/Info.plist +32 -0
  31. data/Example/Colors-OSX/Settings.bundle/Features.plist +59 -0
  32. data/Example/Colors-OSX/Settings.bundle/Root.plist +23 -0
  33. data/Example/Colors-OSX/ViewController.h +14 -0
  34. data/Example/Colors-OSX/ViewController.m +152 -0
  35. data/Example/Colors-OSX/main.m +5 -0
  36. data/Example/Colors-iOS/Base.lproj/Main.storyboard +111 -0
  37. data/Example/Colors-iOS/Colors-iOS-Info.plist +2 -2
  38. data/Example/Colors-iOS/FTSFlipTheSwitch+Features.h +45 -0
  39. data/Example/Colors-iOS/FTSFlipTheSwitch+Features.m +165 -0
  40. data/Example/Colors-iOS/Images.xcassets/AppIcon.appiconset/Contents.json +15 -0
  41. data/Example/Colors-iOS/ViewControlleriOS.m +55 -20
  42. data/Example/Colors.xcodeproj/project.pbxproj +273 -25
  43. data/Example/Colors.xcodeproj/xcshareddata/xcschemes/Colors-OSX.xcscheme +115 -0
  44. data/Example/Colors.xcodeproj/xcshareddata/xcschemes/Colors-iOS.xcscheme +9 -15
  45. data/Example/FTSFlipTheSwitch+Features.h +45 -0
  46. data/Example/FTSFlipTheSwitch+Features.m +165 -0
  47. data/Example/Features.plist +39 -0
  48. data/Example/Gemfile +4 -0
  49. data/Example/Podfile +11 -2
  50. data/Example/README.md +13 -0
  51. data/Example/Rakefile +5 -1
  52. data/Example/features.json +23 -0
  53. data/FlipTheSwitch.podspec +9 -4
  54. data/Gemfile +2 -1
  55. data/README.md +101 -21
  56. data/Resources/FlipTheSwitch/FlipTheSwitch.storyboard +208 -0
  57. data/Tests/FlipTheSwitchSpec-iOS/Features.plist +6 -1
  58. data/Tests/{FlipTheSwitchSpec-Mac/Features.plist → FlipTheSwitchSpec-iOS/OtherFeatures.plist} +5 -2
  59. data/Tests/FlipTheSwitchSpec.xcodeproj/project.pbxproj +101 -38
  60. data/Tests/FlipTheSwitchSpec.xcodeproj/xcshareddata/xcschemes/FlipTheSwitchSpec-Mac.xcscheme +9 -7
  61. data/Tests/FlipTheSwitchSpec.xcodeproj/xcshareddata/xcschemes/FlipTheSwitchSpec-iOS.xcscheme +9 -7
  62. data/Tests/Rakefile +1 -1
  63. data/Tests/Spec/Classes/FlipTheSwitch/FlipTheSwitchSpec.m +134 -28
  64. data/flip_the_switch.gemspec +2 -1
  65. data/images/feature_configuration_screen.png +0 -0
  66. data/lib/flip_the_switch.rb +2 -0
  67. data/lib/flip_the_switch/cli.rb +16 -24
  68. data/lib/flip_the_switch/environment.rb +11 -0
  69. data/lib/flip_the_switch/feature.rb +11 -0
  70. data/lib/flip_the_switch/generator/base.rb +3 -3
  71. data/lib/flip_the_switch/generator/category.rb +13 -5
  72. data/lib/flip_the_switch/generator/header.h.erb +15 -8
  73. data/lib/flip_the_switch/generator/implementation.m.erb +36 -12
  74. data/lib/flip_the_switch/generator/plist.rb +19 -1
  75. data/lib/flip_the_switch/generator/settings.rb +6 -6
  76. data/lib/flip_the_switch/reader/features.rb +136 -22
  77. data/spec/flip_the_switch/cli_spec.rb +12 -12
  78. data/spec/flip_the_switch/environment_spec.rb +20 -0
  79. data/spec/flip_the_switch/feature_spec.rb +20 -0
  80. data/spec/flip_the_switch/generator/category_spec.rb +14 -8
  81. data/spec/flip_the_switch/generator/plist_spec.rb +23 -7
  82. data/spec/flip_the_switch/generator/settings_spec.rb +6 -3
  83. data/spec/flip_the_switch/reader/defaults_spec.rb +0 -18
  84. data/spec/flip_the_switch/reader/features_spec.rb +74 -17
  85. data/spec/resources/ExpectedFeatures.plist +10 -2
  86. data/spec/resources/expected_header.h +8 -3
  87. data/spec/resources/expected_implementation.m +37 -10
  88. data/spec/resources/invalid_layout/features.json +7 -0
  89. data/spec/resources/invalid_type/features.json +23 -0
  90. data/spec/resources/real/features.json +38 -0
  91. data/tmp/.keep +0 -0
  92. metadata +74 -16
  93. data/Classes/FlipTheSwitch/FlipTheSwitch.h +0 -9
  94. data/Classes/FlipTheSwitch/FlipTheSwitch.m +0 -88
  95. data/Example/Colors-iOS/Base.lproj/Main_iPhone.storyboard +0 -76
  96. data/Example/features.yml +0 -3
  97. data/Tests/Spec/Helpers/GcovTestObserver.h +0 -4
  98. data/Tests/Spec/Helpers/GcovTestObserver.m +0 -12
  99. data/spec/resources/invalid_layout/features.yml +0 -4
  100. data/spec/resources/invalid_type/features.yml +0 -7
  101. data/spec/resources/real/features.yml +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1e9b8507bbc66a9479d3fe174c8a42fba3495200
4
- data.tar.gz: 01f913063a72ab9a2bd670fe7600f0d4b16fc830
3
+ metadata.gz: 4e4c3d08117d7df04e9f0b072c46ceaa37677bae
4
+ data.tar.gz: 129fd88d8381ebc2caac41d0cc28a52640043d2c
5
5
  SHA512:
6
- metadata.gz: 8077a424aec23a34f08139b7213c8f17d8c650d980a3cea097c1d137609f08d5af256823eacf89b9fd67af9b5fd3255a6d7cf70e9a4a6d0a8e62a34bd7256144
7
- data.tar.gz: a5a65e6aa1a43e8e22a4424a76efd73a90c99106c851ff5cfb2880ee4ea71529d7a159c352b57ebcfa02e34456c439661015f0fa86ebe9599f51dd5190489ce1
6
+ metadata.gz: aeb03d159b4a890318eea4976566d192c15c780558ec15eb2267047fd33f23891126acd287052d58f1a308fbd4414a8a19ec99fdcfb6107b30742f73940c02f0
7
+ data.tar.gz: 7120397022f1507790cd58763fc28fbb10fcc50d30ccf695eaeb21a7687474bd788c16bdb281b2d68accfc26eb01d375605955f32fb51bc8ac7eb61d42d22bb5
data/.gitignore CHANGED
@@ -41,7 +41,7 @@ profile
41
41
 
42
42
  ####
43
43
  # Xcode temporary files that should never be committed
44
- #
44
+ #
45
45
  # NB: NIB/XIB files still exist even on Storyboard projects, so we want this...
46
46
 
47
47
  *~.nib
@@ -139,6 +139,9 @@ xcuserdata
139
139
 
140
140
  *.moved-aside
141
141
 
142
+ ####
143
+ # AppCode
144
+ .idea/
142
145
 
143
146
  ####
144
147
  # UNKNOWN: recommended by others, but I can't discover what these files are
data/.travis.yml CHANGED
@@ -1,7 +1,9 @@
1
1
  language: objective-c
2
+ osx_image: xcode7
2
3
  before_install:
3
4
  - brew update
4
- - brew upgrade xctool
5
+ - brew uninstall xctool
6
+ - brew install xctool
5
7
  - sudo easy_install cpp-coveralls
6
8
  - gem install bundler
7
9
  - bundle install
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ # 1.0.0 / 2015-10-15
2
+
3
+ * [ENHANCEMENT] Using JSON instead of YAML for features
4
+ * [ENHANCEMENT] #37 Add Mac OSX Example Project
5
+ * [FEATURE] #36 Possibility to reset all features button (according to original plist at once)
6
+ * [FEATURE] #24 Adding reset to defaults functionality
7
+ * [FEATURE] #22 Adding support for subfeature
8
+ * [FEATURE] #21 Notifications on Feature Status
9
+ * [FEATURE] #20 Possibility to add description for feature flags
10
+
1
11
  # 0.4.0 / 2014-07-16
2
12
 
3
13
  * [FEATURE] #17 Use environments for feature states
@@ -0,0 +1,11 @@
1
+ @import Foundation;
2
+
3
+ @interface FTSFeature : NSObject
4
+ @property (nonatomic, readonly) NSString *name;
5
+ @property (nonatomic, readonly) NSString *featureDescription;
6
+ @property (nonatomic, readonly) BOOL enabled;
7
+
8
+ - (id)init NS_UNAVAILABLE;
9
+ - (instancetype)initWithName:(NSString *)name enabled:(BOOL)enabled featureDescription:(NSString *)featureDescription;
10
+
11
+ @end
@@ -0,0 +1,67 @@
1
+ #import "FTSFeature.h"
2
+
3
+ @implementation FTSFeature
4
+
5
+ - (instancetype)initWithName:(NSString *)name enabled:(BOOL)enabled featureDescription:(NSString *)featureDescription
6
+ {
7
+ self = [super init];
8
+ if (self) {
9
+ NSParameterAssert(name);
10
+ _name = name;
11
+ _featureDescription = featureDescription;
12
+ _enabled = enabled;
13
+ }
14
+ return self;
15
+ }
16
+
17
+ - (BOOL)isEqual:(id)other
18
+ {
19
+ if (other == self) {
20
+ return YES;
21
+ }
22
+ if (!other || ![[other class] isEqual:[self class]]) {
23
+ return NO;
24
+ }
25
+
26
+ return [self isEqualToFeature:other];
27
+ }
28
+
29
+ - (BOOL)isEqualToFeature:(FTSFeature *)feature
30
+ {
31
+ if (self == feature) {
32
+ return YES;
33
+ }
34
+ if (feature == nil) {
35
+ return NO;
36
+ }
37
+ if (self.name != feature.name && ![self.name isEqualToString:feature.name]) {
38
+ return NO;
39
+ }
40
+ if (self.featureDescription != feature.featureDescription && ![self.featureDescription isEqualToString:feature.featureDescription]) {
41
+ return NO;
42
+ }
43
+ if (self.enabled != feature.enabled) {
44
+ return NO;
45
+ }
46
+ return YES;
47
+ }
48
+
49
+ - (NSUInteger)hash
50
+ {
51
+ NSUInteger hash = [self.name hash];
52
+ hash = hash * 31u + [self.featureDescription hash];
53
+ hash = hash * 31u + self.enabled;
54
+ return hash;
55
+ }
56
+
57
+ - (NSString *)description
58
+ {
59
+ NSMutableString *description = [NSMutableString stringWithFormat:@"<%@: ", NSStringFromClass([self class])];
60
+ [description appendFormat:@"self.name=%@", self.name];
61
+ [description appendFormat:@", self.featureDescription=%@", self.featureDescription];
62
+ [description appendFormat:@", self.enabled=%d", self.enabled];
63
+ [description appendString:@">"];
64
+ return description;
65
+ }
66
+
67
+ @end
@@ -0,0 +1,21 @@
1
+ @import Foundation;
2
+
3
+ #import "FTSFeature.h"
4
+
5
+ extern NSString *const FTSFeatureStatusChangedNotification;
6
+ extern NSString *const FTSFeatureStatusChangedNotificationFeatureKey;
7
+ extern NSString *const FTSFeatureStatusChangedNotificationEnabledKey;
8
+ extern NSString *const FTSFeaturePlistNameKey;
9
+
10
+ @interface FTSFlipTheSwitch : NSObject
11
+ - (instancetype)init NS_UNAVAILABLE;
12
+ + (instancetype)sharedInstance;
13
+
14
+ - (NSArray *)features;
15
+ - (BOOL)isFeatureEnabled:(NSString *)feature;
16
+ - (void)enableFeature:(NSString *)feature;
17
+ - (void)disableFeature:(NSString *)feature;
18
+ - (void)setFeature:(NSString *)feature enabled:(BOOL)enabled;
19
+ - (void)resetFeature:(NSString *)feature;
20
+ - (void)resetAllFeatures;
21
+ @end
@@ -0,0 +1,144 @@
1
+ #import "FTSFlipTheSwitch.h"
2
+
3
+ NSString *const FTSFeatureStatusChangedNotification = @"FTSFeatureStatusChangedNotification";
4
+ NSString *const FTSFeatureStatusChangedNotificationFeatureKey = @"FTSFeatureStatusChangedNotificationFeatureKey";
5
+ NSString *const FTSFeatureStatusChangedNotificationEnabledKey = @"FTSFeatureStatusChangedNotificationEnabledKey";
6
+ NSString *const FTSFeaturePlistNameKey = @"FTSFeaturePlistNameKey";
7
+
8
+
9
+ @interface FTSFlipTheSwitch ()
10
+ @property (nonatomic, readonly) NSUserDefaults *userDefaults;
11
+ @property (nonatomic, readonly) NSBundle *bundle;
12
+ @property (nonatomic, readonly) NSNotificationCenter *notificationCenter;
13
+ @end
14
+
15
+ @implementation FTSFlipTheSwitch {
16
+ NSDictionary *_plistEnabledFeatures;
17
+ }
18
+
19
+ #pragma mark - Singleton
20
+
21
+ + (instancetype)sharedInstance
22
+ {
23
+ static FTSFlipTheSwitch *sharedInstance;
24
+ static dispatch_once_t once;
25
+ dispatch_once(&once, ^{
26
+ sharedInstance = [[self alloc] initWithUserDefaults:[NSUserDefaults standardUserDefaults]
27
+ bundle:[NSBundle mainBundle]
28
+ notificationCenter:[NSNotificationCenter defaultCenter]];
29
+ });
30
+ return sharedInstance;
31
+ }
32
+
33
+ #pragma mark - Initialization
34
+
35
+ - (instancetype)initWithUserDefaults:(NSUserDefaults *)userDefaults
36
+ bundle:(NSBundle *)bundle
37
+ notificationCenter:(NSNotificationCenter *)notificationCenter
38
+ {
39
+ self = [super init];
40
+ if (self) {
41
+ NSParameterAssert(userDefaults);
42
+ NSParameterAssert(bundle);
43
+ NSParameterAssert(notificationCenter);
44
+ _userDefaults = userDefaults;
45
+ _bundle = bundle;
46
+ _notificationCenter = notificationCenter;
47
+ }
48
+ return self;
49
+ }
50
+
51
+ #pragma mark - Public
52
+
53
+ - (NSArray *)features
54
+ {
55
+ NSMutableArray *featureArray = [NSMutableArray array];
56
+ for (NSString *featureName in [self plistEnabledFeatures]) {
57
+ FTSFeature *feature = [[FTSFeature alloc] initWithName:featureName
58
+ enabled:[self isFeatureEnabled:featureName]
59
+ featureDescription:[self plistEnabledFeatures][featureName][@"description"]];
60
+ [featureArray addObject:feature];
61
+ }
62
+ return [featureArray copy];
63
+ }
64
+
65
+ - (BOOL)isFeatureEnabled:(NSString *)feature
66
+ {
67
+ NSNumber *userEnabledFeature = [self.userDefaults objectForKey:[self userKeyForFeature:feature]];
68
+ if (userEnabledFeature) {
69
+ return [userEnabledFeature boolValue];
70
+ } else {
71
+ return [[self plistEnabledFeatures][feature][@"enabled"] boolValue];
72
+ }
73
+ }
74
+
75
+ - (void)enableFeature:(NSString *)feature
76
+ {
77
+ [self setFeature:feature enabled:YES];
78
+ }
79
+
80
+ - (void)disableFeature:(NSString *)feature
81
+ {
82
+ [self setFeature:feature enabled:NO];
83
+ }
84
+
85
+ - (void)setFeature:(NSString *)feature enabled:(BOOL)enabled
86
+ {
87
+ if (![self isFeatureEnabled:feature] == enabled) {
88
+ [self.userDefaults setObject:@(enabled) forKey:[self userKeyForFeature:feature]];
89
+ [self.userDefaults synchronize];
90
+ [self.notificationCenter postNotification:[self statusChangeNotificationForFeature:feature
91
+ enabled:enabled]];
92
+ }
93
+ }
94
+
95
+ - (void)resetFeature:(NSString *)feature
96
+ {
97
+ [self.userDefaults removeObjectForKey:[self userKeyForFeature:feature]];
98
+ [self.userDefaults synchronize];
99
+ [self.notificationCenter postNotification:[self statusChangeNotificationForFeature:feature
100
+ enabled:[self isFeatureEnabled:feature]]];
101
+ }
102
+
103
+ - (void)resetAllFeatures
104
+ {
105
+ for (NSString *featureName in [self plistEnabledFeatures]) {
106
+ [self resetFeature:featureName];
107
+ }
108
+ }
109
+
110
+ #pragma mark - Private
111
+
112
+ - (NSString *)userKeyForFeature:(NSString *)feature
113
+ {
114
+ return [NSString stringWithFormat:@"FTS_FEATURE_%@", feature];
115
+ }
116
+
117
+ - (NSDictionary *)plistEnabledFeatures
118
+ {
119
+ if (!_plistEnabledFeatures) {
120
+ _plistEnabledFeatures = [[NSDictionary alloc] initWithContentsOfFile:[self featurePlistPath]];
121
+ }
122
+ return _plistEnabledFeatures;
123
+ }
124
+
125
+ - (NSString *)featurePlistPath
126
+ {
127
+ NSString *plistName = [self.userDefaults objectForKey:FTSFeaturePlistNameKey];
128
+ if (plistName == nil) {
129
+ plistName = @"Features";
130
+ }
131
+ return [self.bundle pathForResource:plistName ofType:@"plist"];
132
+ }
133
+
134
+ - (NSNotification *)statusChangeNotificationForFeature:(NSString *)feature enabled:(BOOL)enabled
135
+ {
136
+ return [NSNotification notificationWithName:FTSFeatureStatusChangedNotification
137
+ object:self
138
+ userInfo:@{
139
+ FTSFeatureStatusChangedNotificationFeatureKey : feature,
140
+ FTSFeatureStatusChangedNotificationEnabledKey : @(enabled)
141
+ }];
142
+ }
143
+
144
+ @end
@@ -0,0 +1,17 @@
1
+ @import Foundation;
2
+ @import UIKit;
3
+
4
+ @class FTSFeatureCell;
5
+ #import "FTSFeatureDescriptionLabel.h"
6
+
7
+ @protocol FlipTheSwitchCellDelegate <NSObject>
8
+ - (void)flipTheSwitchCellDidToggleFeature:(FTSFeatureCell *)cell;
9
+ @end
10
+
11
+ @interface FTSFeatureCell : UITableViewCell
12
+ @property (nonatomic, weak) IBOutlet UILabel *featureNameLabel;
13
+ @property (nonatomic, weak) IBOutlet UISwitch *toggle;
14
+ @property (nonatomic, weak) IBOutlet FTSFeatureDescriptionLabel *featureDescriptionLabel;
15
+
16
+ @property (nonatomic, weak) id<FlipTheSwitchCellDelegate> delegate;
17
+ @end
@@ -0,0 +1,12 @@
1
+ #import "FTSFeatureCell.h"
2
+
3
+ @implementation FTSFeatureCell
4
+
5
+ #pragma mark - Action
6
+
7
+ - (IBAction)featureToggled:(id)sender
8
+ {
9
+ [self.delegate flipTheSwitchCellDidToggleFeature:self];
10
+ }
11
+
12
+ @end
@@ -0,0 +1,5 @@
1
+ @import Foundation;
2
+ @import UIKit;
3
+
4
+ @interface FTSFeatureConfigurationViewController : UIViewController
5
+ @end
@@ -0,0 +1,142 @@
1
+ #import "FTSFeatureConfigurationViewController.h"
2
+ #import "FTSFlipTheSwitch.h"
3
+ #import "FTSFeatureCell.h"
4
+
5
+ static NSString * const FTSFeatureCellIdentifier = @"featureCell";
6
+
7
+ @interface FTSFeatureConfigurationViewController () <UITableViewDelegate, UITableViewDataSource, FlipTheSwitchCellDelegate>
8
+ @property (nonatomic) NSArray *dataSource;
9
+ @property (weak, nonatomic) IBOutlet UITableView *tableView;
10
+
11
+ @end
12
+
13
+ @implementation FTSFeatureConfigurationViewController
14
+
15
+ #pragma mark - UIViewController
16
+
17
+ - (void)viewDidLoad
18
+ {
19
+ [super viewDidLoad];
20
+
21
+ self.tableView.delegate = self;
22
+ self.tableView.dataSource = self;
23
+ [self setupDataSource];
24
+ }
25
+
26
+ #pragma mark - Actions
27
+
28
+ - (IBAction)doneButtonTapped:(id)sender
29
+ {
30
+ [self dismissViewControllerAnimated:YES completion:nil];
31
+ }
32
+
33
+ - (IBAction)resetFeatures:(UIButton *)sender {
34
+ [self resetFeatures];
35
+ }
36
+
37
+ - (void)resetFeatures{
38
+ [[FTSFlipTheSwitch sharedInstance] resetAllFeatures];
39
+ [self reloadData];
40
+ }
41
+
42
+ #pragma mark - UITableViewDataSource
43
+
44
+ - (void)reloadData
45
+ {
46
+ [self loadFeatureData];
47
+ [self.tableView reloadData];
48
+ }
49
+
50
+ - (void)setupDataSource
51
+ {
52
+ [self loadFeatureData];
53
+ }
54
+
55
+ - (void)loadFeatureData{
56
+ self.dataSource = [[FTSFlipTheSwitch sharedInstance] features];
57
+ }
58
+
59
+ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
60
+ {
61
+ return 1;
62
+ }
63
+
64
+ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
65
+ {
66
+ return [self.dataSource count];
67
+ }
68
+
69
+ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
70
+ {
71
+ return [self heightForBasicCellAtIndexPath:indexPath];
72
+ }
73
+
74
+ #pragma mark - UITableViewDelegate
75
+
76
+ - (CGFloat)heightForBasicCellAtIndexPath:(NSIndexPath *)indexPath
77
+ {
78
+ [self configureFeatureCell:self.sizingCell atIndexPath:indexPath];
79
+ return [self calculateHeightForConfiguredSizingCell:self.sizingCell];
80
+ }
81
+
82
+ - (CGFloat)calculateHeightForConfiguredSizingCell:(UITableViewCell *)sizingCell
83
+ {
84
+ sizingCell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.tableView.frame), CGRectGetHeight(sizingCell.bounds));
85
+ [sizingCell layoutIfNeeded];
86
+
87
+ CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
88
+ return size.height + 1.0f; // seperator
89
+ }
90
+
91
+ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
92
+ {
93
+ return [self featureCellAtIndexPath:indexPath];
94
+ }
95
+
96
+ #pragma mark - FlipTheSwitchCellDelegate
97
+
98
+ - (void)flipTheSwitchCellDidToggleFeature:(FTSFeatureCell *)cell
99
+ {
100
+ NSUInteger index = (NSUInteger)[self.tableView indexPathForCell:cell].row;
101
+ FTSFeature *feature = self.dataSource[index];
102
+ [[FTSFlipTheSwitch sharedInstance] setFeature:feature.name
103
+ enabled:cell.toggle.on];
104
+ }
105
+
106
+ #pragma mark - Private
107
+
108
+ - (void)configureFeatureCell:(FTSFeatureCell *)cell atIndexPath:(NSIndexPath *)indexPath{
109
+ FTSFeature *feature = self.dataSource[(NSUInteger)indexPath.row];
110
+ [self presentCell:cell withFeature:feature];
111
+ }
112
+
113
+ - (FTSFeatureCell *)featureCellAtIndexPath:(NSIndexPath *)indexPath
114
+ {
115
+ FTSFeatureCell *cell = [self.tableView dequeueReusableCellWithIdentifier:FTSFeatureCellIdentifier forIndexPath:indexPath];
116
+ cell.delegate = self;
117
+ [self configureFeatureCell:cell atIndexPath:indexPath];
118
+
119
+ return cell;
120
+ }
121
+
122
+ - (void)presentCell:(FTSFeatureCell *)cell withFeature:(FTSFeature *)feature
123
+ {
124
+ cell.featureNameLabel.text = feature.name;
125
+ [cell.toggle setOn:feature.enabled animated:NO];
126
+ cell.featureDescriptionLabel.text = feature.featureDescription;
127
+ }
128
+
129
+ - (FTSFeatureCell *)sizingCell
130
+ {
131
+ static FTSFeatureCell *sizingCell = nil;
132
+ static dispatch_once_t onceToken;
133
+ dispatch_once(&onceToken, ^{
134
+ sizingCell = [self.tableView dequeueReusableCellWithIdentifier:FTSFeatureCellIdentifier];
135
+ // iOS bug fix to avoid breaking a by system added 'UIView-Encapsulated-Layout-Height' constraint
136
+ sizingCell.frame = CGRectMake(0, 0, 100, 100);
137
+ sizingCell.contentView.frame = sizingCell.frame;
138
+ });
139
+ return sizingCell;
140
+ }
141
+
142
+ @end