[React Native] Added RCTSettings

This commit is contained in:
Alex Akers
2015-05-05 05:34:38 -07:00
parent 65a3da3003
commit 5eca2e1d3c
8 changed files with 559 additions and 0 deletions

View File

@@ -103,6 +103,13 @@
remoteGlobalIDString = 580C376F1AB104AF0015E709;
remoteInfo = RCTTest;
};
834C36D11AF8DA610019C93C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 13CC9D481AEED2B90020D1C2 /* RCTSettings.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RCTSettings;
};
D85B829B1AB6D5CE003F4FE2 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D85B82911AB6D5CE003F4FE2 /* RCTVibration.xcodeproj */;
@@ -129,6 +136,7 @@
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = UIExplorer/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = UIExplorer/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = UIExplorer/main.m; sourceTree = "<group>"; };
13CC9D481AEED2B90020D1C2 /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = ../../Libraries/Settings/RCTSettings.xcodeproj; sourceTree = "<group>"; };
14AADEFF1AC3DB95002390C9 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../../React/React.xcodeproj; sourceTree = "<group>"; };
14DC67E71AB71876001358AB /* RCTPushNotification.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTPushNotification.xcodeproj; path = ../../Libraries/PushNotificationIOS/RCTPushNotification.xcodeproj; sourceTree = "<group>"; };
14E0EEC81AB118F7000DECC3 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = ../../Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = "<group>"; };
@@ -200,6 +208,7 @@
134A8A201AACED6A00945AAE /* RCTGeolocation.xcodeproj */,
13417FE31AA91428003F314A /* RCTImage.xcodeproj */,
134180261AA91779003F314A /* RCTNetwork.xcodeproj */,
13CC9D481AEED2B90020D1C2 /* RCTSettings.xcodeproj */,
58005BE41ABA80530062E044 /* RCTTest.xcodeproj */,
13417FEA1AA914B8003F314A /* RCTText.xcodeproj */,
00D2770E1AB8C2C700DC1E48 /* RCTWebSocketDebugger.xcodeproj */,
@@ -293,6 +302,14 @@
name = Products;
sourceTree = "<group>";
};
834C36CE1AF8DA610019C93C /* Products */ = {
isa = PBXGroup;
children = (
834C36D21AF8DA610019C93C /* libRCTSettings.a */,
);
name = Products;
sourceTree = "<group>";
};
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
@@ -411,6 +428,10 @@
ProductGroup = 14DC67E81AB71876001358AB /* Products */;
ProjectRef = 14DC67E71AB71876001358AB /* RCTPushNotification.xcodeproj */;
},
{
ProductGroup = 834C36CE1AF8DA610019C93C /* Products */;
ProjectRef = 13CC9D481AEED2B90020D1C2 /* RCTSettings.xcodeproj */;
},
{
ProductGroup = 58005BE51ABA80530062E044 /* Products */;
ProjectRef = 58005BE41ABA80530062E044 /* RCTTest.xcodeproj */;
@@ -511,6 +532,13 @@
remoteRef = 58005BED1ABA80530062E044 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
834C36D21AF8DA610019C93C /* libRCTSettings.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTSettings.a;
remoteRef = 834C36D11AF8DA610019C93C /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
D85B829C1AB6D5CE003F4FE2 /* libRCTVibration.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;

View File

@@ -0,0 +1,250 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
13DBA45E1AEE749000A17CF8 /* RCTSettingsManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13DBA45D1AEE749000A17CF8 /* RCTSettingsManager.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
58B511D91A9E6C8500147676 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
134814201AA4EA6300B7C361 /* libRCTSettings.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTSettings.a; sourceTree = BUILT_PRODUCTS_DIR; };
13DBA45C1AEE749000A17CF8 /* RCTSettingsManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTSettingsManager.h; sourceTree = "<group>"; };
13DBA45D1AEE749000A17CF8 /* RCTSettingsManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTSettingsManager.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
58B511D81A9E6C8500147676 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
134814211AA4EA7D00B7C361 /* Products */ = {
isa = PBXGroup;
children = (
134814201AA4EA6300B7C361 /* libRCTSettings.a */,
);
name = Products;
sourceTree = "<group>";
};
58B511D21A9E6C8500147676 = {
isa = PBXGroup;
children = (
13DBA45C1AEE749000A17CF8 /* RCTSettingsManager.h */,
13DBA45D1AEE749000A17CF8 /* RCTSettingsManager.m */,
134814211AA4EA7D00B7C361 /* Products */,
);
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
58B511DA1A9E6C8500147676 /* RCTSettings */ = {
isa = PBXNativeTarget;
buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTSettings" */;
buildPhases = (
58B511D71A9E6C8500147676 /* Sources */,
58B511D81A9E6C8500147676 /* Frameworks */,
58B511D91A9E6C8500147676 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = RCTSettings;
productName = RCTDataManager;
productReference = 134814201AA4EA6300B7C361 /* libRCTSettings.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
58B511D31A9E6C8500147676 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0610;
ORGANIZATIONNAME = Facebook;
TargetAttributes = {
58B511DA1A9E6C8500147676 = {
CreatedOnToolsVersion = 6.1.1;
};
};
};
buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTSettings" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 58B511D21A9E6C8500147676;
productRefGroup = 58B511D21A9E6C8500147676;
projectDirPath = "";
projectRoot = "";
targets = (
58B511DA1A9E6C8500147676 /* RCTSettings */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
58B511D71A9E6C8500147676 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
13DBA45E1AEE749000A17CF8 /* RCTSettingsManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
58B511ED1A9E6C8500147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
58B511EE1A9E6C8500147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
58B511F01A9E6C8500147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../React/**",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RCTSettings;
SKIP_INSTALL = YES;
};
name = Debug;
};
58B511F11A9E6C8500147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../React/**",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RCTSettings;
SKIP_INSTALL = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTSettings" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B511ED1A9E6C8500147676 /* Debug */,
58B511EE1A9E6C8500147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTSettings" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B511F01A9E6C8500147676 /* Debug */,
58B511F11A9E6C8500147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 58B511D31A9E6C8500147676 /* Project object */;
}

View File

@@ -0,0 +1,18 @@
/**
* Copyright (c) 2015-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 <Foundation/Foundation.h>
#import "RCTBridgeModule.h"
@interface RCTSettingsManager : NSObject <RCTBridgeModule>
- (instancetype)initWithUserDefaults:(NSUserDefaults *)defaults NS_DESIGNATED_INITIALIZER;
@end

View File

@@ -0,0 +1,100 @@
/**
* Copyright (c) 2015-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 "RCTSettingsManager.h"
#import "RCTBridge.h"
#import "RCTConvert.h"
#import "RCTEventDispatcher.h"
@implementation RCTSettingsManager
{
BOOL _ignoringUpdates;
NSUserDefaults *_defaults;
}
@synthesize bridge = _bridge;
RCT_EXPORT_MODULE()
- (instancetype)init
{
return [self initWithUserDefaults:[NSUserDefaults standardUserDefaults]];
}
- (instancetype)initWithUserDefaults:(NSUserDefaults *)defaults
{
if ((self = [super init])) {
_defaults = defaults;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(userDefaultsDidChange:)
name:NSUserDefaultsDidChangeNotification
object:_defaults];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)userDefaultsDidChange:(NSNotification *)note
{
if (_ignoringUpdates) {
return;
}
[_bridge.eventDispatcher sendDeviceEventWithName:@"settingsUpdated" body:[_defaults dictionaryRepresentation]];
}
- (NSDictionary *)constantsToExport
{
return @{
@"settings": [_defaults dictionaryRepresentation]
};
}
/**
* Set one or more values in the settings.
* TODO: would it be useful to have a callback for when this has completed?
*/
RCT_EXPORT_METHOD(setValues:(NSDictionary *)values)
{
_ignoringUpdates = YES;
[values enumerateKeysAndObjectsUsingBlock:^(NSString *key, id json, BOOL *stop) {
id plist = [RCTConvert NSPropertyList:json];
if (plist) {
[_defaults setObject:plist forKey:key];
} else {
[_defaults removeObjectForKey:key];
}
}];
[_defaults synchronize];
_ignoringUpdates = NO;
}
/**
* Remove some values from the settings.
*/
RCT_EXPORT_METHOD(deleteValues:(NSStringArray *)keys)
{
_ignoringUpdates = YES;
for (NSString *key in keys) {
[_defaults removeObjectForKey:key];
}
[_defaults synchronize];
_ignoringUpdates = NO;
}
@end

View File

@@ -0,0 +1,34 @@
/**
* Copyright (c) 2015-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.
*
* @providesModule Settings
* @flow
*/
'use strict';
var Settings = {
get(key: string): mixed {
console.warn('Settings is not yet supported on Android');
return null;
},
set(settings: Object) {
console.warn('Settings is not yet supported on Android');
},
watchKeys(keys: string | Array<string>, callback: Function): number {
console.warn('Settings is not yet supported on Android');
return -1;
},
clearWatch(watchId: number) {
console.warn('Settings is not yet supported on Android');
},
};
module.exports = Settings;

View File

@@ -0,0 +1,77 @@
/**
* Copyright (c) 2015-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.
*
* @providesModule Settings
* @flow
*/
'use strict';
var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter');
var RCTSettingsManager = require('NativeModules').SettingsManager;
var invariant = require('invariant');
var subscriptions: Array<{keys: Array<string>; callback: ?Function}> = [];
var Settings = {
_settings: RCTSettingsManager.settings,
get(key: string): mixed {
return this._settings[key];
},
set(settings: Object) {
this._settings = merge(this._settings, settings);
RCTSettingsManager.set(settings);
},
watchKeys(keys: string | Array<string>, callback: Function): number {
if (typeof keys == 'string') {
keys = [keys];
}
invariant(
Array.isArray(keys),
'keys should be a string or array of strings'
);
var sid = subscriptions.length;
subscriptions.push({keys: keys, callback: callback})
return sid;
},
clearWatch(watchId: number) {
if (watchId < subscriptions.length) {
subscriptions[watchId] = {keys: [], callback: null};
}
},
_sendObservations(body: Object) {
var $this = this;
Object.keys(body).forEach((key) => {
var newValue = body[key];
var didChange = $this._settings[key] !== newValue;
$this._settings[key] = newValue;
if (didChange) {
subscriptions.forEach((sub) => {
if (~sub.keys.indexOf(key) && sub.callback) {
sub.callback();
}
});
}
});
},
};
RCTDeviceEventEmitter.addListener(
'settingsUpdated',
Settings._sendObservations,
);
module.exports = Settings;

View File

@@ -101,6 +101,12 @@ typedef NSArray UIColorArray;
typedef NSArray CGColorArray;
+ (CGColorArray *)CGColorArray:(id)json;
/**
* Convert a JSON object to a Plist-safe equivalent by stripping null values.
*/
typedef id NSPropertyList;
+ (NSPropertyList)NSPropertyList:(id)json;
typedef BOOL css_overflow;
+ (css_overflow)css_overflow:(id)json;
+ (css_flex_direction_t)css_flex_direction_t:(id)json;

View File

@@ -828,6 +828,52 @@ RCT_ARRAY_CONVERTER(UIColor)
return colors;
}
static id RCTConvertPropertyListValue(id json)
{
if (!json || json == (id)kCFNull) {
return nil;
} else if ([json isKindOfClass:[NSDictionary class]]) {
__block BOOL copy = NO;
NSMutableDictionary *values = [[NSMutableDictionary alloc] initWithCapacity:[json count]];
[json enumerateKeysAndObjectsUsingBlock:^(NSString *key, id jsonValue, BOOL *stop) {
id value = RCTConvertPropertyListValue(jsonValue);
if (value) {
values[key] = value;
}
copy |= value != jsonValue;
}];
return copy ? values : json;
} else if ([json isKindOfClass:[NSArray class]]) {
__block BOOL copy = NO;
__block NSArray *values = json;
[json enumerateObjectsUsingBlock:^(id jsonValue, NSUInteger idx, BOOL *stop) {
id value = RCTConvertPropertyListValue(jsonValue);
if (copy) {
if (value) {
[(NSMutableArray *)values addObject:value];
}
} else if (value != jsonValue) {
// Converted value is different, so we'll need to copy the array
values = [[NSMutableArray alloc] initWithCapacity:values.count];
for (NSInteger i = 0; i < idx; i++) {
[(NSMutableArray *)values addObject:json[i]];
}
[(NSMutableArray *)values addObject:value];
copy = YES;
}
}];
return values;
} else {
// All other JSON types are supported by property lists
return json;
}
}
+ (NSPropertyList)NSPropertyList:(id)json
{
return RCTConvertPropertyListValue(json);
}
RCT_ENUM_CONVERTER(css_overflow, (@{
@"hidden": @NO,
@"visible": @YES