fixing shake to open Dev Menu only work once
Summary:
Fixing issues https://github.com/facebook/react-native/issues/10588
This bug has been introduced during refactoring UIActionSheet to UIAlertController d368ebfab2 (diff-f78a84ff95f2bcee5a70d3accb504528)
**Test plan**
- shake to open DevMenu, choose random menu item, it should close DevMenu and after another shaking it should open again
Closes https://github.com/facebook/react-native/pull/10676
Differential Revision: D4168254
Pulled By: javache
fbshipit-source-id: 6e2935b765053a2b55809af357d2b6ea03e04e8b
This commit is contained in:
parent
b58c8ad916
commit
abf1438f54
|
@ -117,6 +117,7 @@
|
|||
83636F8F1B53F22C009F943E /* RCTUIManagerScenarioTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 83636F8E1B53F22C009F943E /* RCTUIManagerScenarioTests.m */; };
|
||||
8385CEF51B873B5C00C6273E /* RCTImageLoaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8385CEF41B873B5C00C6273E /* RCTImageLoaderTests.m */; };
|
||||
8385CF041B87479200C6273E /* RCTImageLoaderHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 8385CF031B87479200C6273E /* RCTImageLoaderHelpers.m */; };
|
||||
BC9C03401DC9F1D600B1C635 /* RCTDevMenuTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BC9C033F1DC9F1D600B1C635 /* RCTDevMenuTests.m */; };
|
||||
D85B829E1AB6D5D7003F4FE2 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D85B829C1AB6D5CE003F4FE2 /* libRCTVibration.a */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
|
@ -446,6 +447,7 @@
|
|||
8385CEF41B873B5C00C6273E /* RCTImageLoaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoaderTests.m; sourceTree = "<group>"; };
|
||||
8385CF031B87479200C6273E /* RCTImageLoaderHelpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoaderHelpers.m; sourceTree = "<group>"; };
|
||||
8385CF051B8747A000C6273E /* RCTImageLoaderHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTImageLoaderHelpers.h; sourceTree = "<group>"; };
|
||||
BC9C033F1DC9F1D600B1C635 /* RCTDevMenuTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevMenuTests.m; sourceTree = "<group>"; };
|
||||
D85B82911AB6D5CE003F4FE2 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = ../../Libraries/Vibration/RCTVibration.xcodeproj; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
|
@ -679,6 +681,7 @@
|
|||
001BFCE31D838343008E587E /* RCTMultipartStreamReaderTests.m */,
|
||||
138D6A161B53CD440074A87E /* RCTShadowViewTests.m */,
|
||||
1497CFAB1B21F5E400C1F8F2 /* RCTUIManagerTests.m */,
|
||||
BC9C033F1DC9F1D600B1C635 /* RCTDevMenuTests.m */,
|
||||
13BCE84E1C9C209600DD7AAD /* RCTComponentPropsTests.m */,
|
||||
39AA31A31DC1DFDC000F7EBB /* RCTUnicodeDecodeTests.m */,
|
||||
143BC57E1B21E18100462512 /* Info.plist */,
|
||||
|
@ -1442,6 +1445,7 @@
|
|||
39AA31A41DC1DFDC000F7EBB /* RCTUnicodeDecodeTests.m in Sources */,
|
||||
13B6C1A31C34225900D3FAF5 /* RCTURLUtilsTests.m in Sources */,
|
||||
8385CF041B87479200C6273E /* RCTImageLoaderHelpers.m in Sources */,
|
||||
BC9C03401DC9F1D600B1C635 /* RCTDevMenuTests.m in Sources */,
|
||||
68FF44381CF6111500720EFD /* RCTBundleURLProviderTests.m in Sources */,
|
||||
8385CEF51B873B5C00C6273E /* RCTImageLoaderTests.m in Sources */,
|
||||
);
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* The examples provided by Facebook are for non-commercial testing and
|
||||
* evaluation purposes only.
|
||||
*
|
||||
* Facebook reserves all rights not expressly granted.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL
|
||||
* FACEBOOK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#import "RCTBridge.h"
|
||||
#import "RCTDevMenu.h"
|
||||
|
||||
typedef void(^RCTDevMenuAlertActionHandler)(UIAlertAction *action);
|
||||
|
||||
@interface RCTDevMenu ()
|
||||
|
||||
- (RCTDevMenuAlertActionHandler)alertActionHandlerForDevItem:(RCTDevMenuItem *)item;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTDevMenuTests : XCTestCase
|
||||
|
||||
@end
|
||||
|
||||
@implementation RCTDevMenuTests
|
||||
{
|
||||
RCTBridge *_bridge;
|
||||
}
|
||||
|
||||
- (void)setUp
|
||||
{
|
||||
[super setUp];
|
||||
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
_bridge = [[RCTBridge alloc] initWithBundleURL:[bundle URLForResource:@"TestBundle" withExtension:@"js"]
|
||||
moduleProvider:nil
|
||||
launchOptions:nil];
|
||||
}
|
||||
|
||||
- (void)testShowCreatingActionSheet
|
||||
{
|
||||
XCTAssertFalse([_bridge.devMenu isActionSheetShown]);
|
||||
[_bridge.devMenu show];
|
||||
XCTAssertTrue([_bridge.devMenu isActionSheetShown]);
|
||||
}
|
||||
|
||||
|
||||
- (void)testClosingActionSheetAfterAction
|
||||
{
|
||||
for (RCTDevMenuItem *item in _bridge.devMenu.presentedItems) {
|
||||
RCTDevMenuAlertActionHandler handler = [_bridge.devMenu alertActionHandlerForDevItem:item];
|
||||
XCTAssertTrue([_bridge.devMenu isActionSheetShown]);
|
||||
|
||||
handler(nil);
|
||||
XCTAssertFalse([_bridge.devMenu isActionSheetShown]);
|
||||
|
||||
[_bridge.devMenu show];
|
||||
XCTAssertTrue([_bridge.devMenu isActionSheetShown]);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
|
@ -46,6 +46,18 @@
|
|||
*/
|
||||
@property (nonatomic, assign) BOOL showFPS;
|
||||
|
||||
/**
|
||||
* Presented items in development menu
|
||||
*/
|
||||
@property (nonatomic, copy, readonly) NSArray<RCTDevMenuItem *> *presentedItems;
|
||||
|
||||
|
||||
/**
|
||||
* Detect if actions sheet (development menu) is shown
|
||||
*/
|
||||
- (BOOL)isActionSheetShown;
|
||||
|
||||
|
||||
/**
|
||||
* Manually show the dev menu (can be called from JS).
|
||||
*/
|
||||
|
|
|
@ -47,8 +47,6 @@ typedef NS_ENUM(NSInteger, RCTDevMenuType) {
|
|||
|
||||
@property (nonatomic, assign, readonly) RCTDevMenuType type;
|
||||
@property (nonatomic, copy, readonly) NSString *key;
|
||||
@property (nonatomic, copy, readonly) NSString *title;
|
||||
@property (nonatomic, copy, readonly) NSString *selectedTitle;
|
||||
@property (nonatomic, copy) id value;
|
||||
|
||||
@end
|
||||
|
@ -56,6 +54,9 @@ typedef NS_ENUM(NSInteger, RCTDevMenuType) {
|
|||
@implementation RCTDevMenuItem
|
||||
{
|
||||
id _handler; // block
|
||||
|
||||
NSString *_title;
|
||||
NSString *_selectedTitle;
|
||||
}
|
||||
|
||||
- (instancetype)initWithType:(RCTDevMenuType)type
|
||||
|
@ -75,6 +76,15 @@ typedef NS_ENUM(NSInteger, RCTDevMenuType) {
|
|||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)title
|
||||
{
|
||||
if (_type == RCTDevMenuTypeToggle && [_value boolValue]) {
|
||||
return _selectedTitle;
|
||||
}
|
||||
|
||||
return _title;
|
||||
}
|
||||
|
||||
RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||
|
||||
+ (instancetype)buttonItemWithTitle:(NSString *)title
|
||||
|
@ -119,6 +129,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
|
||||
@end
|
||||
|
||||
typedef void(^RCTDevMenuAlertActionHandler)(UIAlertAction *action);
|
||||
|
||||
@interface RCTDevMenu () <RCTBridgeModule, RCTInvalidating, RCTWebSocketProxyDelegate>
|
||||
|
||||
@property (nonatomic, strong) Class executorClass;
|
||||
|
@ -133,7 +145,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
|||
NSURLSessionDataTask *_updateTask;
|
||||
NSURL *_liveReloadURL;
|
||||
BOOL _jsLoaded;
|
||||
NSArray<RCTDevMenuItem *> *_presentedItems;
|
||||
NSMutableArray<RCTDevMenuItem *> *_extraMenuItems;
|
||||
NSString *_webSocketExecutorName;
|
||||
NSString *_executorOverride;
|
||||
|
@ -515,37 +526,40 @@ RCT_EXPORT_METHOD(show)
|
|||
|
||||
NSArray<RCTDevMenuItem *> *items = [self menuItems];
|
||||
for (RCTDevMenuItem *item in items) {
|
||||
switch (item.type) {
|
||||
case RCTDevMenuTypeButton: {
|
||||
[_actionSheet addAction:[UIAlertAction actionWithTitle:item.title
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(__unused UIAlertAction *action) {
|
||||
[item callHandler];
|
||||
}]];
|
||||
break;
|
||||
}
|
||||
case RCTDevMenuTypeToggle: {
|
||||
BOOL selected = [item.value boolValue];
|
||||
[_actionSheet addAction:[UIAlertAction actionWithTitle:(selected? item.selectedTitle : item.title)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(__unused UIAlertAction *action) {
|
||||
BOOL value = [self->_settings[item.key] boolValue];
|
||||
[self updateSetting:item.key value:@(!value)]; // will call handler
|
||||
}]];
|
||||
break;
|
||||
}
|
||||
}
|
||||
[_actionSheet addAction:[UIAlertAction actionWithTitle:item.title
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:[self alertActionHandlerForDevItem:item]]];
|
||||
}
|
||||
|
||||
[_actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel"
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:nil]];
|
||||
handler:[self alertActionHandlerForDevItem:nil]]];
|
||||
|
||||
_presentedItems = items;
|
||||
[RCTPresentedViewController() presentViewController:_actionSheet animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (RCTDevMenuAlertActionHandler)alertActionHandlerForDevItem:(RCTDevMenuItem *__nullable)item
|
||||
{
|
||||
return ^(__unused UIAlertAction *action) {
|
||||
if (item) {
|
||||
switch (item.type) {
|
||||
case RCTDevMenuTypeButton: {
|
||||
[item callHandler];
|
||||
break;
|
||||
}
|
||||
|
||||
case RCTDevMenuTypeToggle: {
|
||||
BOOL value = [self->_settings[item.key] boolValue];
|
||||
[self updateSetting:item.key value:@(!value)]; // will call handler
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self->_actionSheet = nil;
|
||||
};
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(reload)
|
||||
{
|
||||
|
@ -675,6 +689,11 @@ RCT_EXPORT_METHOD(setHotLoadingEnabled:(BOOL)enabled)
|
|||
[_updateTask resume];
|
||||
}
|
||||
|
||||
- (BOOL)isActionSheetShown
|
||||
{
|
||||
return _actionSheet != nil;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#else // Unavailable when not in dev mode
|
||||
|
@ -685,6 +704,7 @@ RCT_EXPORT_METHOD(setHotLoadingEnabled:(BOOL)enabled)
|
|||
- (void)reload {}
|
||||
- (void)addItem:(NSString *)title handler:(dispatch_block_t)handler {}
|
||||
- (void)addItem:(RCTDevMenu *)item {}
|
||||
- (BOOL)isActionSheetShown { return NO; }
|
||||
|
||||
@end
|
||||
|
||||
|
|
Loading…
Reference in New Issue