[ReactNative] Refactor DevMenu items construction

Summary:
The idea behind this change it to couple together menu item title
and handler. The code becomes simpler and easier to maintain, but
also makes it possible to extend dev menu in the future.

@public

Test Plan:
All menu items works as before.
Changed websocket executor class name and made sure that when the class
is missing we get nice error message.
This commit is contained in:
Alex Kotliarskyi 2015-06-03 16:40:14 -07:00
parent 63b8262843
commit 9fe7128493
2 changed files with 112 additions and 68 deletions

View File

@ -51,6 +51,12 @@
*/
- (void)reload;
/**
* Add custom item to the development menu. The handler will be called
* when user selects the item.
*/
- (void)addItem:(NSString *)title handler:(dispatch_block_t)handler;
@end
/**

View File

@ -43,6 +43,28 @@ static NSString *const RCTDevMenuSettingsKey = @"RCTDevMenu";
@end
@interface RCTDevMenuItem : NSObject
@property (nonatomic, copy) NSString *title;
@property (nonatomic, copy) dispatch_block_t handler;
- (instancetype)initWithTitle:(NSString *)title handler:(dispatch_block_t)handler;
@end
@implementation RCTDevMenuItem
- (instancetype)initWithTitle:(NSString *)title handler:(dispatch_block_t)handler
{
if (self = [super init]) {
self.title = title;
self.handler = handler;
}
return self;
}
@end
@interface RCTDevMenu () <RCTBridgeModule, UIActionSheetDelegate>
@property (nonatomic, strong) Class executorClass;
@ -57,6 +79,8 @@ static NSString *const RCTDevMenuSettingsKey = @"RCTDevMenu";
NSURLSessionDataTask *_updateTask;
NSURL *_liveReloadURL;
BOOL _jsLoaded;
NSArray *_presentedItems;
NSMutableArray *_extraMenuItems;
}
@synthesize bridge = _bridge;
@ -94,6 +118,7 @@ RCT_EXPORT_MODULE()
_defaults = [NSUserDefaults standardUserDefaults];
_settings = [[NSMutableDictionary alloc] init];
_extraMenuItems = [NSMutableArray array];
// Delay setup until after Bridge init
[self settingsDidChange];
@ -232,32 +257,82 @@ RCT_EXPORT_MODULE()
}
}
- (void)addItem:(NSString *)title handler:(dispatch_block_t)handler
{
[_extraMenuItems addObject:[[RCTDevMenuItem alloc] initWithTitle:title handler:handler]];
}
- (NSArray *)menuItems
{
NSMutableArray *items = [NSMutableArray array];
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:@"Reload" handler:^{
[self reload];
}]];
Class chromeExecutorClass = NSClassFromString(@"RCTWebSocketExecutor");
if (!chromeExecutorClass) {
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:@"Chrome Debugger Unavailable" handler:^{
[[[UIAlertView alloc] initWithTitle:@"Chrome Debugger Unavailable"
message:@"You need to include the RCTWebSocket library to enable Chrome debugging"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil] show];
}]];
} else {
BOOL isDebuggingInChrome = _executorClass && _executorClass == chromeExecutorClass;
NSString *debugTitleChrome = isDebuggingInChrome ? @"Disable Chrome Debugging" : @"Debug in Chrome";
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:debugTitleChrome handler:^{
self.executorClass = isDebuggingInChrome ? Nil : chromeExecutorClass;
}]];
}
Class safariExecutorClass = NSClassFromString(@"RCTWebViewExecutor");
BOOL isDebuggingInSafari = _executorClass && _executorClass == safariExecutorClass;
NSString *debugTitleSafari = isDebuggingInSafari ? @"Disable Safari Debugging" : @"Debug in Safari";
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:debugTitleSafari handler:^{
self.executorClass = isDebuggingInSafari ? Nil : safariExecutorClass;
}]];
NSString *fpsMonitor = _showFPS ? @"Hide FPS Monitor" : @"Show FPS Monitor";
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:fpsMonitor handler:^{
self.showFPS = !_showFPS;
}]];
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:@"Inspect Element" handler:^{
[_bridge.eventDispatcher sendDeviceEventWithName:@"toggleElementInspector" body:nil];
}]];
if (_liveReloadURL) {
NSString *liveReloadTitle = _liveReloadEnabled ? @"Disable Live Reload" : @"Enable Live Reload";
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:liveReloadTitle handler:^{
self.liveReloadEnabled = !_liveReloadEnabled;
}]];
NSString *profilingTitle = RCTProfileIsProfiling() ? @"Stop Profiling" : @"Start Profiling";
[items addObject:[[RCTDevMenuItem alloc] initWithTitle:profilingTitle handler:^{
self.profilingEnabled = !_profilingEnabled;
}]];
}
[items addObjectsFromArray:_extraMenuItems];
return items;
}
RCT_EXPORT_METHOD(show)
{
if (_actionSheet || !_bridge) {
return;
}
NSString *debugTitleChrome = _executorClass && _executorClass == NSClassFromString(@"RCTWebSocketExecutor") ? @"Disable Chrome Debugging" : @"Debug in Chrome";
NSString *debugTitleSafari = _executorClass && _executorClass == NSClassFromString(@"RCTWebViewExecutor") ? @"Disable Safari Debugging" : @"Debug in Safari";
NSString *fpsMonitor = _showFPS ? @"Hide FPS Monitor" : @"Show FPS Monitor";
UIActionSheet *actionSheet = [[UIActionSheet alloc] init];
actionSheet.title = @"React Native: Development";
actionSheet.delegate = self;
UIActionSheet *actionSheet =
[[UIActionSheet alloc] initWithTitle:@"React Native: Development"
delegate:self
cancelButtonTitle:nil
destructiveButtonTitle:nil
otherButtonTitles:@"Reload", debugTitleChrome, debugTitleSafari, fpsMonitor, nil];
[actionSheet addButtonWithTitle:@"Inspect Element"];
if (_liveReloadURL) {
NSString *liveReloadTitle = _liveReloadEnabled ? @"Disable Live Reload" : @"Enable Live Reload";
NSString *profilingTitle = RCTProfileIsProfiling() ? @"Stop Profiling" : @"Start Profiling";
[actionSheet addButtonWithTitle:liveReloadTitle];
[actionSheet addButtonWithTitle:profilingTitle];
NSArray *items = [self menuItems];
for (RCTDevMenuItem *item in items) {
[actionSheet addButtonWithTitle:item.title];
}
[actionSheet addButtonWithTitle:@"Cancel"];
@ -266,13 +341,7 @@ RCT_EXPORT_METHOD(show)
actionSheet.actionSheetStyle = UIBarStyleBlack;
[actionSheet showInView:[UIApplication sharedApplication].keyWindow.rootViewController.view];
_actionSheet = actionSheet;
}
RCT_EXPORT_METHOD(reload)
{
_jsLoaded = NO;
_liveReloadURL = nil;
[_bridge reload];
_presentedItems = items;
}
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
@ -282,48 +351,16 @@ RCT_EXPORT_METHOD(reload)
return;
}
switch (buttonIndex) {
case 0: {
[self reload];
break;
}
case 1: {
Class cls = NSClassFromString(@"RCTWebSocketExecutor");
if (!cls) {
[[[UIAlertView alloc] initWithTitle:@"Chrome Debugger Unavailable"
message:@"You need to include the RCTWebSocket library to enable Chrome debugging"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil] show];
RCTDevMenuItem *item = _presentedItems[buttonIndex];
item.handler();
return;
}
self.executorClass = (_executorClass == cls) ? Nil : cls;
break;
}
case 2: {
Class cls = NSClassFromString(@"RCTWebViewExecutor");
self.executorClass = (_executorClass == cls) ? Nil : cls;
break;
}
case 3: {
self.showFPS = !_showFPS;
break;
}
case 4: {
[_bridge.eventDispatcher sendDeviceEventWithName:@"toggleElementInspector" body:nil];
break;
}
case 5: {
self.liveReloadEnabled = !_liveReloadEnabled;
break;
}
case 6: {
self.profilingEnabled = !_profilingEnabled;
break;
}
default:
break;
}
}
RCT_EXPORT_METHOD(reload)
{
_jsLoaded = NO;
_liveReloadURL = nil;
[_bridge reload];
}
- (void)setShakeToShow:(BOOL)shakeToShow
@ -445,6 +482,7 @@ RCT_EXPORT_METHOD(reload)
- (void)show {}
- (void)reload {}
- (void)addItem:(NSString *)title handler:(dispatch_block_t)handler {}
@end