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.
- checksums.yaml +4 -4
- data/.gitignore +4 -1
- data/.travis.yml +3 -1
- data/CHANGELOG.md +10 -0
- data/Classes/FlipTheSwitch/Shared/FTSFeature.h +11 -0
- data/Classes/FlipTheSwitch/Shared/FTSFeature.m +67 -0
- data/Classes/FlipTheSwitch/Shared/FTSFlipTheSwitch.h +21 -0
- data/Classes/FlipTheSwitch/Shared/FTSFlipTheSwitch.m +144 -0
- data/Classes/FlipTheSwitch/iOS/FTSFeatureCell.h +17 -0
- data/Classes/FlipTheSwitch/iOS/FTSFeatureCell.m +12 -0
- data/Classes/FlipTheSwitch/iOS/FTSFeatureConfigurationViewController.h +5 -0
- data/Classes/FlipTheSwitch/iOS/FTSFeatureConfigurationViewController.m +142 -0
- data/Classes/FlipTheSwitch/iOS/FTSFeatureDescriptionLabel.h +5 -0
- data/Classes/FlipTheSwitch/iOS/FTSFeatureDescriptionLabel.m +13 -0
- data/Example/Colors-OSX/AppDelegate.h +7 -0
- data/Example/Colors-OSX/AppDelegate.m +17 -0
- data/Example/Colors-OSX/Base.lproj/Main.storyboard +744 -0
- data/Example/Colors-OSX/ColoredViews/GreenView.h +5 -0
- data/Example/Colors-OSX/ColoredViews/GreenView.m +12 -0
- data/Example/Colors-OSX/ColoredViews/PurpleView.h +5 -0
- data/Example/Colors-OSX/ColoredViews/PurpleView.m +12 -0
- data/Example/Colors-OSX/ColoredViews/RedView.h +5 -0
- data/Example/Colors-OSX/ColoredViews/RedView.m +12 -0
- data/Example/Colors-OSX/ColoredViews/YellowView.h +5 -0
- data/Example/Colors-OSX/ColoredViews/YellowView.m +12 -0
- data/Example/Colors-OSX/FTSFlipTheSwitch+Features.h +45 -0
- data/Example/Colors-OSX/FTSFlipTheSwitch+Features.m +165 -0
- data/Example/Colors-OSX/Features.plist +39 -0
- data/Example/Colors-OSX/Images.xcassets/AppIcon.appiconset/Contents.json +58 -0
- data/Example/Colors-OSX/Info.plist +32 -0
- data/Example/Colors-OSX/Settings.bundle/Features.plist +59 -0
- data/Example/Colors-OSX/Settings.bundle/Root.plist +23 -0
- data/Example/Colors-OSX/ViewController.h +14 -0
- data/Example/Colors-OSX/ViewController.m +152 -0
- data/Example/Colors-OSX/main.m +5 -0
- data/Example/Colors-iOS/Base.lproj/Main.storyboard +111 -0
- data/Example/Colors-iOS/Colors-iOS-Info.plist +2 -2
- data/Example/Colors-iOS/FTSFlipTheSwitch+Features.h +45 -0
- data/Example/Colors-iOS/FTSFlipTheSwitch+Features.m +165 -0
- data/Example/Colors-iOS/Images.xcassets/AppIcon.appiconset/Contents.json +15 -0
- data/Example/Colors-iOS/ViewControlleriOS.m +55 -20
- data/Example/Colors.xcodeproj/project.pbxproj +273 -25
- data/Example/Colors.xcodeproj/xcshareddata/xcschemes/Colors-OSX.xcscheme +115 -0
- data/Example/Colors.xcodeproj/xcshareddata/xcschemes/Colors-iOS.xcscheme +9 -15
- data/Example/FTSFlipTheSwitch+Features.h +45 -0
- data/Example/FTSFlipTheSwitch+Features.m +165 -0
- data/Example/Features.plist +39 -0
- data/Example/Gemfile +4 -0
- data/Example/Podfile +11 -2
- data/Example/README.md +13 -0
- data/Example/Rakefile +5 -1
- data/Example/features.json +23 -0
- data/FlipTheSwitch.podspec +9 -4
- data/Gemfile +2 -1
- data/README.md +101 -21
- data/Resources/FlipTheSwitch/FlipTheSwitch.storyboard +208 -0
- data/Tests/FlipTheSwitchSpec-iOS/Features.plist +6 -1
- data/Tests/{FlipTheSwitchSpec-Mac/Features.plist → FlipTheSwitchSpec-iOS/OtherFeatures.plist} +5 -2
- data/Tests/FlipTheSwitchSpec.xcodeproj/project.pbxproj +101 -38
- data/Tests/FlipTheSwitchSpec.xcodeproj/xcshareddata/xcschemes/FlipTheSwitchSpec-Mac.xcscheme +9 -7
- data/Tests/FlipTheSwitchSpec.xcodeproj/xcshareddata/xcschemes/FlipTheSwitchSpec-iOS.xcscheme +9 -7
- data/Tests/Rakefile +1 -1
- data/Tests/Spec/Classes/FlipTheSwitch/FlipTheSwitchSpec.m +134 -28
- data/flip_the_switch.gemspec +2 -1
- data/images/feature_configuration_screen.png +0 -0
- data/lib/flip_the_switch.rb +2 -0
- data/lib/flip_the_switch/cli.rb +16 -24
- data/lib/flip_the_switch/environment.rb +11 -0
- data/lib/flip_the_switch/feature.rb +11 -0
- data/lib/flip_the_switch/generator/base.rb +3 -3
- data/lib/flip_the_switch/generator/category.rb +13 -5
- data/lib/flip_the_switch/generator/header.h.erb +15 -8
- data/lib/flip_the_switch/generator/implementation.m.erb +36 -12
- data/lib/flip_the_switch/generator/plist.rb +19 -1
- data/lib/flip_the_switch/generator/settings.rb +6 -6
- data/lib/flip_the_switch/reader/features.rb +136 -22
- data/spec/flip_the_switch/cli_spec.rb +12 -12
- data/spec/flip_the_switch/environment_spec.rb +20 -0
- data/spec/flip_the_switch/feature_spec.rb +20 -0
- data/spec/flip_the_switch/generator/category_spec.rb +14 -8
- data/spec/flip_the_switch/generator/plist_spec.rb +23 -7
- data/spec/flip_the_switch/generator/settings_spec.rb +6 -3
- data/spec/flip_the_switch/reader/defaults_spec.rb +0 -18
- data/spec/flip_the_switch/reader/features_spec.rb +74 -17
- data/spec/resources/ExpectedFeatures.plist +10 -2
- data/spec/resources/expected_header.h +8 -3
- data/spec/resources/expected_implementation.m +37 -10
- data/spec/resources/invalid_layout/features.json +7 -0
- data/spec/resources/invalid_type/features.json +23 -0
- data/spec/resources/real/features.json +38 -0
- data/tmp/.keep +0 -0
- metadata +74 -16
- data/Classes/FlipTheSwitch/FlipTheSwitch.h +0 -9
- data/Classes/FlipTheSwitch/FlipTheSwitch.m +0 -88
- data/Example/Colors-iOS/Base.lproj/Main_iPhone.storyboard +0 -76
- data/Example/features.yml +0 -3
- data/Tests/Spec/Helpers/GcovTestObserver.h +0 -4
- data/Tests/Spec/Helpers/GcovTestObserver.m +0 -12
- data/spec/resources/invalid_layout/features.yml +0 -4
- data/spec/resources/invalid_type/features.yml +0 -7
- data/spec/resources/real/features.yml +0 -6
data/Example/README.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
## Colors
|
2
|
+
|
3
|
+
In order to run the project, be sure to run:
|
4
|
+
|
5
|
+
$ bundle install
|
6
|
+
|
7
|
+
$ bundle exec pod install
|
8
|
+
|
9
|
+
$ bundle exec flip-the-switch category -o Colors-iOS
|
10
|
+
|
11
|
+
$ bundle exec flip-the-switch plist -o Colors-iOS
|
12
|
+
|
13
|
+
$ bundle exec flip-the-switch settings -o Colors-iOS
|
data/Example/Rakefile
CHANGED
@@ -20,5 +20,9 @@ task :test => podfile_lock do
|
|
20
20
|
sh 'bundle exec ../bin/flip-the-switch plist -o Colors-iOS'
|
21
21
|
sh 'bundle exec ../bin/flip-the-switch category -o Colors-iOS'
|
22
22
|
sh 'bundle exec ../bin/flip-the-switch settings -o Colors-iOS'
|
23
|
-
sh
|
23
|
+
sh 'bundle exec ../bin/flip-the-switch plist -o Colors-OSX'
|
24
|
+
sh 'bundle exec ../bin/flip-the-switch category -o Colors-OSX'
|
25
|
+
sh 'bundle exec ../bin/flip-the-switch settings -o Colors-OSX'
|
26
|
+
sh "xcodebuild build -scheme #{workspace}-OSX -workspace #{workspace}.xcworkspace -sdk macosx OBJROOT=#{build} SHARED_PRECOMPS_DIR=#{build}"
|
27
|
+
sh "xcodebuild build -scheme #{workspace}-iOS -workspace #{workspace}.xcworkspace -sdk iphonesimulator OBJROOT=#{build} SHARED_PRECOMPS_DIR=#{build}"
|
24
28
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
{
|
2
|
+
"default": {
|
3
|
+
"features_controller" : {
|
4
|
+
"enabled": true,
|
5
|
+
"description": "Enable feature switching UI"
|
6
|
+
},
|
7
|
+
"purple_color": {
|
8
|
+
"enabled": true,
|
9
|
+
"description": "The color purple"
|
10
|
+
},
|
11
|
+
"red_color": {
|
12
|
+
"enabled": false,
|
13
|
+
"description": "The color red"
|
14
|
+
},
|
15
|
+
"no_description_feature": {
|
16
|
+
"enabled": false
|
17
|
+
},
|
18
|
+
"long_description_feature": {
|
19
|
+
"enabled": false,
|
20
|
+
"description": "The path of the righteous man is beset on all sides by the iniquities of the selfish and the tyranny of evil men. Blessed is he who, in the name of charity and good will, shepherds the weak through the valley of darkness, for he is truly his brother's keeper and the finder of lost children. And I will strike down upon thee with great vengeance and furious anger those who would attempt to poison and destroy My brothers. And you will know My name is the Lord when I lay My vengeance upon thee."
|
21
|
+
}
|
22
|
+
}
|
23
|
+
}
|
data/FlipTheSwitch.podspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Pod::Spec.new do |s|
|
2
2
|
s.name = 'FlipTheSwitch'
|
3
|
-
s.version = '0.
|
3
|
+
s.version = '1.0.0'
|
4
4
|
s.summary = 'A simple library to help enabling/disabling features on iOS/Mac applications.'
|
5
5
|
s.authors = {
|
6
6
|
'Michael England' => 'mg.england@gmail.com',
|
@@ -9,8 +9,13 @@ Pod::Spec.new do |s|
|
|
9
9
|
s.homepage = 'https://github.com/michaelengland/FlipTheSwitch'
|
10
10
|
|
11
11
|
s.license = {:type => 'MIT', :file => 'LICENSE'}
|
12
|
-
s.source = {:git => '
|
13
|
-
s.source_files = 'Classes/FlipTheSwitch/*.{h,m}'
|
14
|
-
s.public_header_files = 'Classes/FlipTheSwitch/*.h'
|
12
|
+
s.source = {:git => 'https://github.com/michaelengland/FlipTheSwitch.git', :tag => s.version.to_s}
|
13
|
+
s.osx.source_files = 'Classes/FlipTheSwitch/Shared/*.{h,m}'
|
14
|
+
s.osx.public_header_files = 'Classes/FlipTheSwitch/Shared/*.h'
|
15
|
+
s.osx.deployment_target = '10.8'
|
16
|
+
s.ios.source_files = 'Classes/FlipTheSwitch/**/*.{h,m}'
|
17
|
+
s.ios.public_header_files = 'Classes/FlipTheSwitch/**/*.h'
|
18
|
+
s.ios.resource_bundles = { 'FlipTheSwitch' => 'Resources/FlipTheSwitch/*.storyboard' }
|
19
|
+
s.ios.deployment_target = '7.0'
|
15
20
|
s.requires_arc = true
|
16
21
|
end
|
data/Gemfile
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
3
|
gem 'travis', '~> 1.6.11'
|
4
|
-
gem 'cocoapods', '~> 0.
|
4
|
+
gem 'cocoapods', '~> 0.37.2'
|
5
5
|
gem 'rake', '~> 10.3.2'
|
6
6
|
|
7
7
|
gemspec
|
@@ -14,4 +14,5 @@ group :development, :test do
|
|
14
14
|
gem 'guard-bundler', '~> 2.0.0'
|
15
15
|
gem 'guard-spork', '~> 1.5.1'
|
16
16
|
gem 'guard-rspec', '~> 4.2.10'
|
17
|
+
gem 'json-schema', '2.5.1'
|
17
18
|
end
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@ A feature switching/toggling/flipping library for ObjectiveC.
|
|
4
4
|
|
5
5
|
# flip_the_switch [![Build Status](https://travis-ci.org/michaelengland/FlipTheSwitch.svg?branch=master)](https://travis-ci.org/michaelengland/FlipTheSwitch) [![Code Climate](https://codeclimate.com/github/michaelengland/FlipTheSwitch.png)](https://codeclimate.com/github/michaelengland/FlipTheSwitch) [![Code Climate](https://codeclimate.com/github/michaelengland/FlipTheSwitch/coverage.png)](https://codeclimate.com/github/michaelengland/FlipTheSwitch) [![Gem Version](https://badge.fury.io/rb/flip_the_switch.svg)](http://badge.fury.io/rb/flip_the_switch)
|
6
6
|
|
7
|
-
A gem command line tool for generating the `Features.plist` & `
|
7
|
+
A gem command line tool for generating the `Features.plist` & `FTSFlipTheSwitch+Features.{h,m}` categories to help with the corresponding Pod.
|
8
8
|
|
9
9
|
## The Problem
|
10
10
|
|
@@ -19,24 +19,26 @@ How can we get the benefits of working on `master` branch, while still not worry
|
|
19
19
|
|
20
20
|
## Introducing FlipTheSwitch
|
21
21
|
|
22
|
-
|
22
|
+
### Auto-Generated Files:
|
23
|
+
|
24
|
+
With 'FTSFlipTheSwitch', we can choose different code paths at runtime:
|
23
25
|
|
24
26
|
```objective-c
|
25
|
-
self.newFeatureButton.hidden = [[
|
27
|
+
self.newFeatureButton.hidden = [[FTSFlipTheSwitch sharedInstance] isFeatureEnabled:@"new_feature"];
|
26
28
|
```
|
27
29
|
|
28
30
|
The features can be enabled/disabled at runtime:
|
29
31
|
|
30
32
|
```objective-c
|
31
|
-
[[
|
33
|
+
[[FTSFlipTheSwitch sharedInstance] enableFeature:@"new_feature"];
|
32
34
|
```
|
33
35
|
|
34
36
|
```objective-c
|
35
|
-
[[
|
37
|
+
[[FTSFlipTheSwitch sharedInstance] disableFeature:@"new_feature"];
|
36
38
|
```
|
37
39
|
|
38
40
|
```objective-c
|
39
|
-
[[
|
41
|
+
[[FTSFlipTheSwitch sharedInstance] setFeature:@"new_feature" enabled:YES];
|
40
42
|
```
|
41
43
|
|
42
44
|
All enabled features will persist between app loads through `NSUserDefaults`.
|
@@ -45,47 +47,123 @@ The features can defaulted to enabled/disabled via a plist file `Features.plist`
|
|
45
47
|
|
46
48
|
```xml
|
47
49
|
<?xml version="1.0" encoding="UTF-8"?>
|
48
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
50
|
+
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
49
51
|
<plist version="1.0">
|
50
52
|
<dict>
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
53
|
+
<key>disabled_feature</key>
|
54
|
+
<dict>
|
55
|
+
<key>description</key>
|
56
|
+
<string>is disabled description</string>
|
57
|
+
<key>enabled</key>
|
58
|
+
<false/>
|
59
|
+
</dict>
|
60
|
+
<key>enabled_feature</key>
|
61
|
+
<dict>
|
62
|
+
<key>enabled</key>
|
63
|
+
<true/>
|
64
|
+
</dict>
|
55
65
|
</dict>
|
56
66
|
</plist>
|
67
|
+
|
68
|
+
```
|
69
|
+
|
70
|
+
### Subfeatures
|
71
|
+
|
72
|
+
You can add as many subfeatures to a feature recursively. Resulting in a plist as e.g. :
|
73
|
+
|
74
|
+
```xml
|
75
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
76
|
+
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
77
|
+
<plist version="1.0">
|
78
|
+
<dict>
|
79
|
+
<key>description</key>
|
80
|
+
<string>is disabled description</string>
|
81
|
+
<key>enabled</key>
|
82
|
+
<false/>
|
83
|
+
<key>subfeature</key>
|
84
|
+
<dict>
|
85
|
+
<key>enabled</key>
|
86
|
+
<true/>
|
87
|
+
</dict>
|
88
|
+
</dict>
|
89
|
+
</plist>
|
57
90
|
```
|
58
91
|
|
92
|
+
### Configuration Screen
|
93
|
+
|
94
|
+
![Screenshot of configuration screen](images/feature_configuration_screen.png)
|
95
|
+
|
96
|
+
* shows all features, their description texts and enabled state
|
97
|
+
* easily switching features on and off
|
98
|
+
* reset all feature back to the original setting from the plist (based on the json)
|
99
|
+
|
100
|
+
### Notifications
|
101
|
+
|
102
|
+
When a feature status changes, you can find out about it by listening for the notification titled `FTSFeatureStatusChangedNotification`, which contains:
|
103
|
+
|
104
|
+
* `FTSFeatureStatusChangedNotificationFeatureKey` - the key of the feature being enabled/disabled
|
105
|
+
* `FTSFeatureStatusChangedNotificationEnabledKey` - the `NSNumber` of whether the feature was enabled or disabled
|
106
|
+
|
107
|
+
### Plattform Support
|
108
|
+
|
109
|
+
* iOS
|
110
|
+
* example project
|
111
|
+
* full test coverage
|
112
|
+
* configuration screen
|
113
|
+
* Mac OSX
|
114
|
+
* example project
|
115
|
+
* full test coverage
|
116
|
+
|
59
117
|
## Command-Line-Interface
|
60
118
|
|
61
119
|
If you install the gem, you will be able to use the Command-Line-Interface.
|
62
120
|
|
63
|
-
The CLI consists of
|
121
|
+
The CLI consists of 3 commands:
|
64
122
|
|
65
|
-
- `plist` - creates a `Features.plist` file for enabled/disabled features like that mentioned above.
|
123
|
+
- `plist` - creates a `Features.plist` file for enabled/disabled features including their description (optional) like that mentioned above.
|
66
124
|
- `settings` - creates a `Settings.bundle` used by the OS settings. These can then be used to enable/disable the features at runtime.
|
67
|
-
- `category` - creates `
|
125
|
+
- `category` - creates `FTSFlipTheSwitch+Features.{h,m}` files for features, thus giving compile-time checks for adding/removal of new features.
|
68
126
|
e.g:
|
69
127
|
|
70
128
|
```objective-c
|
71
129
|
/* AUTO-GENERATED. DO NOT ALTER */
|
72
|
-
#import <FlipTheSwitch/
|
130
|
+
#import <FlipTheSwitch/FTSFlipTheSwitch.h>
|
73
131
|
|
74
|
-
@interface
|
132
|
+
@interface FTSFlipTheSwitch (Features)
|
75
133
|
|
76
134
|
+ (BOOL)isAwesomeFeatureEnabled;
|
77
135
|
+ (void)enableAwesomeFeature;
|
78
136
|
+ (void)disableAwesomeFeature;
|
79
137
|
+ (void)setAwesomeFeatureEnabled:(BOOL)enabled;
|
138
|
+
+ (void)resetAwesomeFeatureController;
|
139
|
+
+ (NSString *)awesomeFeatureControllerKey;
|
80
140
|
|
81
141
|
@end
|
82
142
|
```
|
83
143
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
144
|
+
### Define Features and subfeatures
|
145
|
+
|
146
|
+
The features and subfeatures, along with their default enabled/disabled state, are read from a `features.json` file. e.g.:
|
147
|
+
|
148
|
+
```json
|
149
|
+
{
|
150
|
+
"default": {
|
151
|
+
"awesome_feature": {
|
152
|
+
"enabled": true,
|
153
|
+
"description": "Makes this project awesome",
|
154
|
+
"sub_feature": {
|
155
|
+
"enabled": true,
|
156
|
+
"description": "Makes this project even more awesome"
|
157
|
+
}
|
158
|
+
}
|
159
|
+
},
|
160
|
+
"beta": {
|
161
|
+
"awesome_feature": {
|
162
|
+
"enabled": false
|
163
|
+
}
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
89
167
|
```
|
90
168
|
|
91
169
|
In order to avoid typing in the same options all the time, you can create a `.flip.yml` file for the default options, e.g.:
|
@@ -108,6 +186,8 @@ Add `gem 'flip_the_switch'` to your Gemfile
|
|
108
186
|
|
109
187
|
- [Michael England](https://github.com/michaelengland) @ [SoundCloud](https://github.com/soundcloud)
|
110
188
|
- [Rob Siwek](https://github.com/nerdsRob) @ [SoundCloud](https://github.com/soundcloud)
|
189
|
+
- [Kristina Roddewig](https://github.com/FrauR) @ [SoundCloud](https://github.com/soundcloud)
|
190
|
+
- [Vincent Garrigues](https://github.com/garriguv) @ [SoundCloud](https://github.com/soundcloud)
|
111
191
|
|
112
192
|
## License
|
113
193
|
|
@@ -0,0 +1,208 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
2
|
+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14F27" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="7Me-Uf-CYC">
|
3
|
+
<dependencies>
|
4
|
+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
5
|
+
<capability name="Constraints to layout margins" minToolsVersion="6.0"/>
|
6
|
+
</dependencies>
|
7
|
+
<scenes>
|
8
|
+
<!--Features-->
|
9
|
+
<scene sceneID="HmN-ks-p58">
|
10
|
+
<objects>
|
11
|
+
<tableViewController storyboardIdentifier="FeatureConfigurationScreen" useStoryboardIdentifierAsRestorationIdentifier="YES" id="MfP-lZ-lJZ" sceneMemberID="viewController">
|
12
|
+
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" id="qox-Cy-iKL">
|
13
|
+
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
14
|
+
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
15
|
+
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
16
|
+
<prototypes>
|
17
|
+
<tableViewCell contentMode="scaleToFill" selectionStyle="default" indentationWidth="10" reuseIdentifier="featureCell" rowHeight="80" id="D45-mi-SWk" customClass="FTSFeatureCell">
|
18
|
+
<rect key="frame" x="0.0" y="22" width="320" height="80"/>
|
19
|
+
<autoresizingMask key="autoresizingMask"/>
|
20
|
+
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="D45-mi-SWk" id="SUw-kE-nVw">
|
21
|
+
<rect key="frame" x="0.0" y="0.0" width="320" height="79"/>
|
22
|
+
<autoresizingMask key="autoresizingMask"/>
|
23
|
+
<subviews>
|
24
|
+
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="249" text="FeatureDescription" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="243" translatesAutoresizingMaskIntoConstraints="NO" id="WCn-j6-JQJ" customClass="FTSFeatureDescriptionLabel">
|
25
|
+
<rect key="frame" x="10" y="38" width="243" height="31"/>
|
26
|
+
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
|
27
|
+
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
28
|
+
<nil key="highlightedColor"/>
|
29
|
+
</label>
|
30
|
+
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" verticalCompressionResistancePriority="751" text="FeatureName" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="243" translatesAutoresizingMaskIntoConstraints="NO" id="JrP-11-dyn">
|
31
|
+
<rect key="frame" x="10" y="10" width="243" height="20"/>
|
32
|
+
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
|
33
|
+
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
34
|
+
<nil key="highlightedColor"/>
|
35
|
+
</label>
|
36
|
+
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="FXx-pu-gXY">
|
37
|
+
<rect key="frame" x="261" y="10" width="51" height="31"/>
|
38
|
+
</switch>
|
39
|
+
</subviews>
|
40
|
+
<constraints>
|
41
|
+
<constraint firstAttribute="bottom" secondItem="WCn-j6-JQJ" secondAttribute="bottom" constant="10" id="1VP-zB-7id"/>
|
42
|
+
<constraint firstItem="WCn-j6-JQJ" firstAttribute="leading" secondItem="SUw-kE-nVw" secondAttribute="leading" constant="10" id="1ha-yE-GKY"/>
|
43
|
+
<constraint firstItem="JrP-11-dyn" firstAttribute="trailing" secondItem="WCn-j6-JQJ" secondAttribute="trailing" id="9Bo-eH-7qf"/>
|
44
|
+
<constraint firstItem="JrP-11-dyn" firstAttribute="top" secondItem="SUw-kE-nVw" secondAttribute="top" constant="10" id="axL-pe-FFk"/>
|
45
|
+
<constraint firstItem="JrP-11-dyn" firstAttribute="leading" secondItem="SUw-kE-nVw" secondAttribute="leading" constant="10" id="iuu-aZ-hyf"/>
|
46
|
+
<constraint firstItem="FXx-pu-gXY" firstAttribute="leading" secondItem="WCn-j6-JQJ" secondAttribute="trailing" constant="8" id="jq5-8Y-uyk"/>
|
47
|
+
<constraint firstAttribute="trailingMargin" secondItem="FXx-pu-gXY" secondAttribute="trailing" constant="2" id="nsd-Sy-5Xy"/>
|
48
|
+
<constraint firstItem="JrP-11-dyn" firstAttribute="top" secondItem="FXx-pu-gXY" secondAttribute="top" id="y4U-Do-c8a"/>
|
49
|
+
<constraint firstItem="WCn-j6-JQJ" firstAttribute="top" secondItem="JrP-11-dyn" secondAttribute="bottom" constant="8" id="ywP-47-8cN"/>
|
50
|
+
</constraints>
|
51
|
+
</tableViewCellContentView>
|
52
|
+
</tableViewCell>
|
53
|
+
</prototypes>
|
54
|
+
<connections>
|
55
|
+
<outlet property="dataSource" destination="MfP-lZ-lJZ" id="WKz-RW-2Ip"/>
|
56
|
+
<outlet property="delegate" destination="MfP-lZ-lJZ" id="TeA-Cq-pD2"/>
|
57
|
+
</connections>
|
58
|
+
</tableView>
|
59
|
+
<navigationItem key="navigationItem" title="Features" id="CmQ-ny-cRX">
|
60
|
+
<barButtonItem key="rightBarButtonItem" systemItem="done" id="Fxb-5D-mkV">
|
61
|
+
<connections>
|
62
|
+
<action selector="doneButtonTapped:" destination="MfP-lZ-lJZ" id="l1S-0q-bey"/>
|
63
|
+
</connections>
|
64
|
+
</barButtonItem>
|
65
|
+
</navigationItem>
|
66
|
+
</tableViewController>
|
67
|
+
<placeholder placeholderIdentifier="IBFirstResponder" id="TNm-zL-vN8" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
68
|
+
</objects>
|
69
|
+
<point key="canvasLocation" x="286.39999999999998" y="381.50666666666666"/>
|
70
|
+
</scene>
|
71
|
+
<!--Features-->
|
72
|
+
<scene sceneID="d4s-di-gRP">
|
73
|
+
<objects>
|
74
|
+
<viewController id="VNR-A9-bVe" customClass="FTSFeatureConfigurationViewController" sceneMemberID="viewController">
|
75
|
+
<layoutGuides>
|
76
|
+
<viewControllerLayoutGuide type="top" id="CZV-QH-phi"/>
|
77
|
+
<viewControllerLayoutGuide type="bottom" id="Hl8-DJ-f5M"/>
|
78
|
+
</layoutGuides>
|
79
|
+
<view key="view" contentMode="scaleToFill" id="FK5-Sw-fHL">
|
80
|
+
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
81
|
+
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
82
|
+
<subviews>
|
83
|
+
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jTG-0P-p33" userLabel="button view">
|
84
|
+
<rect key="frame" x="0.0" y="64" width="320" height="30"/>
|
85
|
+
<subviews>
|
86
|
+
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="right" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Ak9-OY-hUu">
|
87
|
+
<rect key="frame" x="0.0" y="0.0" width="304" height="30"/>
|
88
|
+
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
|
89
|
+
<state key="normal" title="reset features">
|
90
|
+
<color key="titleColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
91
|
+
</state>
|
92
|
+
<connections>
|
93
|
+
<action selector="resetFeatures:" destination="VNR-A9-bVe" eventType="touchUpInside" id="Wtx-Jk-Rnw"/>
|
94
|
+
</connections>
|
95
|
+
</button>
|
96
|
+
</subviews>
|
97
|
+
<color key="backgroundColor" red="0.83727904040000001" green="0.23504479617310975" blue="0.046994104183399457" alpha="1" colorSpace="calibratedRGB"/>
|
98
|
+
<constraints>
|
99
|
+
<constraint firstItem="Ak9-OY-hUu" firstAttribute="height" secondItem="jTG-0P-p33" secondAttribute="height" id="4P0-bd-VAF"/>
|
100
|
+
<constraint firstItem="Ak9-OY-hUu" firstAttribute="leading" secondItem="jTG-0P-p33" secondAttribute="leading" id="aS8-Zg-5nf"/>
|
101
|
+
<constraint firstAttribute="trailing" secondItem="Ak9-OY-hUu" secondAttribute="trailing" constant="16" id="l9R-D4-Gtg"/>
|
102
|
+
<constraint firstAttribute="height" constant="30" id="pY4-gc-j0P"/>
|
103
|
+
<constraint firstAttribute="centerY" secondItem="Ak9-OY-hUu" secondAttribute="centerY" id="q85-e1-Msa"/>
|
104
|
+
</constraints>
|
105
|
+
</view>
|
106
|
+
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" allowsSelection="NO" rowHeight="44" sectionHeaderHeight="22" sectionFooterHeight="22" translatesAutoresizingMaskIntoConstraints="NO" id="CAV-UP-hYJ">
|
107
|
+
<rect key="frame" x="0.0" y="96" width="320" height="472"/>
|
108
|
+
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
109
|
+
<prototypes>
|
110
|
+
<tableViewCell contentMode="scaleToFill" selectionStyle="default" hidesAccessoryWhenEditing="NO" indentationWidth="10" reuseIdentifier="featureCell" rowHeight="80" id="WYa-NK-09p" customClass="FTSFeatureCell">
|
111
|
+
<rect key="frame" x="0.0" y="22" width="320" height="80"/>
|
112
|
+
<autoresizingMask key="autoresizingMask"/>
|
113
|
+
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="WYa-NK-09p" id="rl5-2d-YAl">
|
114
|
+
<rect key="frame" x="0.0" y="0.0" width="320" height="79"/>
|
115
|
+
<autoresizingMask key="autoresizingMask"/>
|
116
|
+
<subviews>
|
117
|
+
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="T5e-hB-sUM">
|
118
|
+
<rect key="frame" x="255" y="18" width="51" height="31"/>
|
119
|
+
<connections>
|
120
|
+
<action selector="featureToggled:" destination="WYa-NK-09p" eventType="valueChanged" id="eed-Vv-qb7"/>
|
121
|
+
</connections>
|
122
|
+
</switch>
|
123
|
+
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="251" horizontalCompressionResistancePriority="751" verticalCompressionResistancePriority="751" text="FeatureName" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="243" translatesAutoresizingMaskIntoConstraints="NO" id="kZ7-Ia-TXE">
|
124
|
+
<rect key="frame" x="18" y="18" width="102" height="20"/>
|
125
|
+
<fontDescription key="fontDescription" style="UICTFontTextStyleHeadline"/>
|
126
|
+
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
127
|
+
<nil key="highlightedColor"/>
|
128
|
+
</label>
|
129
|
+
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" verticalHuggingPriority="249" text="FeatureDescription" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" preferredMaxLayoutWidth="243" translatesAutoresizingMaskIntoConstraints="NO" id="MwL-gA-zbI" customClass="FTSFeatureDescriptionLabel">
|
130
|
+
<rect key="frame" x="18" y="46" width="229" height="15"/>
|
131
|
+
<fontDescription key="fontDescription" style="UICTFontTextStyleCaption1"/>
|
132
|
+
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
133
|
+
<nil key="highlightedColor"/>
|
134
|
+
</label>
|
135
|
+
</subviews>
|
136
|
+
<constraints>
|
137
|
+
<constraint firstItem="T5e-hB-sUM" firstAttribute="top" secondItem="kZ7-Ia-TXE" secondAttribute="top" id="4sp-vs-EGn"/>
|
138
|
+
<constraint firstItem="MwL-gA-zbI" firstAttribute="leading" secondItem="kZ7-Ia-TXE" secondAttribute="leading" id="KLd-Mh-rhV"/>
|
139
|
+
<constraint firstItem="kZ7-Ia-TXE" firstAttribute="leading" secondItem="rl5-2d-YAl" secondAttribute="leadingMargin" constant="10" id="Own-CZ-DEv"/>
|
140
|
+
<constraint firstAttribute="bottomMargin" secondItem="MwL-gA-zbI" secondAttribute="bottom" constant="10" id="VHJ-KA-U0P"/>
|
141
|
+
<constraint firstItem="kZ7-Ia-TXE" firstAttribute="top" secondItem="rl5-2d-YAl" secondAttribute="topMargin" constant="10" id="afa-9Z-kyZ"/>
|
142
|
+
<constraint firstItem="MwL-gA-zbI" firstAttribute="leading" secondItem="kZ7-Ia-TXE" secondAttribute="leading" id="bHw-Lq-K8w"/>
|
143
|
+
<constraint firstAttribute="trailingMargin" secondItem="T5e-hB-sUM" secondAttribute="trailing" constant="8" id="fib-2g-StW"/>
|
144
|
+
<constraint firstItem="kZ7-Ia-TXE" firstAttribute="top" secondItem="T5e-hB-sUM" secondAttribute="top" id="pt9-Lw-QSL"/>
|
145
|
+
<constraint firstItem="MwL-gA-zbI" firstAttribute="top" secondItem="kZ7-Ia-TXE" secondAttribute="bottom" constant="8" id="tgd-Hc-Aoy"/>
|
146
|
+
<constraint firstItem="T5e-hB-sUM" firstAttribute="leading" secondItem="MwL-gA-zbI" secondAttribute="trailing" constant="8" id="xWp-xU-WYT"/>
|
147
|
+
</constraints>
|
148
|
+
</tableViewCellContentView>
|
149
|
+
<connections>
|
150
|
+
<outlet property="featureDescriptionLabel" destination="MwL-gA-zbI" id="d62-i0-CsK"/>
|
151
|
+
<outlet property="featureNameLabel" destination="kZ7-Ia-TXE" id="qYa-fX-kfb"/>
|
152
|
+
<outlet property="toggle" destination="T5e-hB-sUM" id="7AF-V8-nFY"/>
|
153
|
+
</connections>
|
154
|
+
</tableViewCell>
|
155
|
+
</prototypes>
|
156
|
+
</tableView>
|
157
|
+
</subviews>
|
158
|
+
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
159
|
+
<constraints>
|
160
|
+
<constraint firstAttribute="trailingMargin" secondItem="jTG-0P-p33" secondAttribute="trailing" constant="-16" id="7XB-JS-ZUB"/>
|
161
|
+
<constraint firstItem="jTG-0P-p33" firstAttribute="leading" secondItem="FK5-Sw-fHL" secondAttribute="leadingMargin" constant="-16" id="Ccp-Z5-hK7"/>
|
162
|
+
<constraint firstItem="jTG-0P-p33" firstAttribute="top" secondItem="CZV-QH-phi" secondAttribute="bottom" id="N8Y-lp-UcX"/>
|
163
|
+
<constraint firstItem="CAV-UP-hYJ" firstAttribute="top" secondItem="jTG-0P-p33" secondAttribute="bottom" constant="2" id="TpK-0d-Kg8"/>
|
164
|
+
<constraint firstAttribute="bottomMargin" secondItem="CAV-UP-hYJ" secondAttribute="bottom" id="Vwk-5q-UCu"/>
|
165
|
+
<constraint firstAttribute="trailingMargin" secondItem="CAV-UP-hYJ" secondAttribute="trailing" constant="-16" id="ZbZ-ha-pGQ"/>
|
166
|
+
<constraint firstItem="CAV-UP-hYJ" firstAttribute="leading" secondItem="FK5-Sw-fHL" secondAttribute="leadingMargin" constant="-16" id="xyC-iY-xjJ"/>
|
167
|
+
</constraints>
|
168
|
+
</view>
|
169
|
+
<navigationItem key="navigationItem" title="Features" id="3uf-ZL-7jI">
|
170
|
+
<barButtonItem key="rightBarButtonItem" systemItem="done" id="RdH-Dv-eEC">
|
171
|
+
<connections>
|
172
|
+
<action selector="doneButtonTapped:" destination="VNR-A9-bVe" id="9gW-r3-wTk"/>
|
173
|
+
</connections>
|
174
|
+
</barButtonItem>
|
175
|
+
</navigationItem>
|
176
|
+
<connections>
|
177
|
+
<outlet property="tableView" destination="CAV-UP-hYJ" id="dGn-6y-wnj"/>
|
178
|
+
</connections>
|
179
|
+
</viewController>
|
180
|
+
<placeholder placeholderIdentifier="IBFirstResponder" id="SNb-iL-KWt" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
181
|
+
</objects>
|
182
|
+
<point key="canvasLocation" x="1217" y="981"/>
|
183
|
+
</scene>
|
184
|
+
<!--Navigation Controller-->
|
185
|
+
<scene sceneID="QDo-Id-00w">
|
186
|
+
<objects>
|
187
|
+
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="7Me-Uf-CYC" sceneMemberID="viewController">
|
188
|
+
<toolbarItems/>
|
189
|
+
<navigationBar key="navigationBar" contentMode="scaleToFill" id="Atc-Ob-RNj">
|
190
|
+
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
191
|
+
<autoresizingMask key="autoresizingMask"/>
|
192
|
+
</navigationBar>
|
193
|
+
<nil name="viewControllers"/>
|
194
|
+
<connections>
|
195
|
+
<segue destination="VNR-A9-bVe" kind="relationship" relationship="rootViewController" id="tmG-Lz-Fw1"/>
|
196
|
+
</connections>
|
197
|
+
</navigationController>
|
198
|
+
<placeholder placeholderIdentifier="IBFirstResponder" id="Uty-I5-CH8" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
199
|
+
</objects>
|
200
|
+
<point key="canvasLocation" x="826" y="981"/>
|
201
|
+
</scene>
|
202
|
+
</scenes>
|
203
|
+
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
204
|
+
<simulatedStatusBarMetrics key="statusBar"/>
|
205
|
+
<simulatedOrientationMetrics key="orientation"/>
|
206
|
+
<simulatedScreenMetrics key="destination" type="retina4"/>
|
207
|
+
</simulatedMetricsContainer>
|
208
|
+
</document>
|