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:
Родитель
b58c8ad916
Коммит
abf1438f54
|
@ -117,6 +117,7 @@
|
||||||
83636F8F1B53F22C009F943E /* RCTUIManagerScenarioTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 83636F8E1B53F22C009F943E /* RCTUIManagerScenarioTests.m */; };
|
83636F8F1B53F22C009F943E /* RCTUIManagerScenarioTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 83636F8E1B53F22C009F943E /* RCTUIManagerScenarioTests.m */; };
|
||||||
8385CEF51B873B5C00C6273E /* RCTImageLoaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8385CEF41B873B5C00C6273E /* RCTImageLoaderTests.m */; };
|
8385CEF51B873B5C00C6273E /* RCTImageLoaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8385CEF41B873B5C00C6273E /* RCTImageLoaderTests.m */; };
|
||||||
8385CF041B87479200C6273E /* RCTImageLoaderHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 8385CF031B87479200C6273E /* RCTImageLoaderHelpers.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 */; };
|
D85B829E1AB6D5D7003F4FE2 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D85B829C1AB6D5CE003F4FE2 /* libRCTVibration.a */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
|
@ -446,6 +447,7 @@
|
||||||
8385CEF41B873B5C00C6273E /* RCTImageLoaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoaderTests.m; sourceTree = "<group>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
D85B82911AB6D5CE003F4FE2 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = ../../Libraries/Vibration/RCTVibration.xcodeproj; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
|
@ -679,6 +681,7 @@
|
||||||
001BFCE31D838343008E587E /* RCTMultipartStreamReaderTests.m */,
|
001BFCE31D838343008E587E /* RCTMultipartStreamReaderTests.m */,
|
||||||
138D6A161B53CD440074A87E /* RCTShadowViewTests.m */,
|
138D6A161B53CD440074A87E /* RCTShadowViewTests.m */,
|
||||||
1497CFAB1B21F5E400C1F8F2 /* RCTUIManagerTests.m */,
|
1497CFAB1B21F5E400C1F8F2 /* RCTUIManagerTests.m */,
|
||||||
|
BC9C033F1DC9F1D600B1C635 /* RCTDevMenuTests.m */,
|
||||||
13BCE84E1C9C209600DD7AAD /* RCTComponentPropsTests.m */,
|
13BCE84E1C9C209600DD7AAD /* RCTComponentPropsTests.m */,
|
||||||
39AA31A31DC1DFDC000F7EBB /* RCTUnicodeDecodeTests.m */,
|
39AA31A31DC1DFDC000F7EBB /* RCTUnicodeDecodeTests.m */,
|
||||||
143BC57E1B21E18100462512 /* Info.plist */,
|
143BC57E1B21E18100462512 /* Info.plist */,
|
||||||
|
@ -1442,6 +1445,7 @@
|
||||||
39AA31A41DC1DFDC000F7EBB /* RCTUnicodeDecodeTests.m in Sources */,
|
39AA31A41DC1DFDC000F7EBB /* RCTUnicodeDecodeTests.m in Sources */,
|
||||||
13B6C1A31C34225900D3FAF5 /* RCTURLUtilsTests.m in Sources */,
|
13B6C1A31C34225900D3FAF5 /* RCTURLUtilsTests.m in Sources */,
|
||||||
8385CF041B87479200C6273E /* RCTImageLoaderHelpers.m in Sources */,
|
8385CF041B87479200C6273E /* RCTImageLoaderHelpers.m in Sources */,
|
||||||
|
BC9C03401DC9F1D600B1C635 /* RCTDevMenuTests.m in Sources */,
|
||||||
68FF44381CF6111500720EFD /* RCTBundleURLProviderTests.m in Sources */,
|
68FF44381CF6111500720EFD /* RCTBundleURLProviderTests.m in Sources */,
|
||||||
8385CEF51B873B5C00C6273E /* RCTImageLoaderTests.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;
|
@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).
|
* 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, assign, readonly) RCTDevMenuType type;
|
||||||
@property (nonatomic, copy, readonly) NSString *key;
|
@property (nonatomic, copy, readonly) NSString *key;
|
||||||
@property (nonatomic, copy, readonly) NSString *title;
|
|
||||||
@property (nonatomic, copy, readonly) NSString *selectedTitle;
|
|
||||||
@property (nonatomic, copy) id value;
|
@property (nonatomic, copy) id value;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -56,6 +54,9 @@ typedef NS_ENUM(NSInteger, RCTDevMenuType) {
|
||||||
@implementation RCTDevMenuItem
|
@implementation RCTDevMenuItem
|
||||||
{
|
{
|
||||||
id _handler; // block
|
id _handler; // block
|
||||||
|
|
||||||
|
NSString *_title;
|
||||||
|
NSString *_selectedTitle;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithType:(RCTDevMenuType)type
|
- (instancetype)initWithType:(RCTDevMenuType)type
|
||||||
|
@ -75,6 +76,15 @@ typedef NS_ENUM(NSInteger, RCTDevMenuType) {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString *)title
|
||||||
|
{
|
||||||
|
if (_type == RCTDevMenuTypeToggle && [_value boolValue]) {
|
||||||
|
return _selectedTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _title;
|
||||||
|
}
|
||||||
|
|
||||||
RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||||
|
|
||||||
+ (instancetype)buttonItemWithTitle:(NSString *)title
|
+ (instancetype)buttonItemWithTitle:(NSString *)title
|
||||||
|
@ -119,6 +129,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
typedef void(^RCTDevMenuAlertActionHandler)(UIAlertAction *action);
|
||||||
|
|
||||||
@interface RCTDevMenu () <RCTBridgeModule, RCTInvalidating, RCTWebSocketProxyDelegate>
|
@interface RCTDevMenu () <RCTBridgeModule, RCTInvalidating, RCTWebSocketProxyDelegate>
|
||||||
|
|
||||||
@property (nonatomic, strong) Class executorClass;
|
@property (nonatomic, strong) Class executorClass;
|
||||||
|
@ -133,7 +145,6 @@ RCT_NOT_IMPLEMENTED(- (instancetype)init)
|
||||||
NSURLSessionDataTask *_updateTask;
|
NSURLSessionDataTask *_updateTask;
|
||||||
NSURL *_liveReloadURL;
|
NSURL *_liveReloadURL;
|
||||||
BOOL _jsLoaded;
|
BOOL _jsLoaded;
|
||||||
NSArray<RCTDevMenuItem *> *_presentedItems;
|
|
||||||
NSMutableArray<RCTDevMenuItem *> *_extraMenuItems;
|
NSMutableArray<RCTDevMenuItem *> *_extraMenuItems;
|
||||||
NSString *_webSocketExecutorName;
|
NSString *_webSocketExecutorName;
|
||||||
NSString *_executorOverride;
|
NSString *_executorOverride;
|
||||||
|
@ -515,37 +526,40 @@ RCT_EXPORT_METHOD(show)
|
||||||
|
|
||||||
NSArray<RCTDevMenuItem *> *items = [self menuItems];
|
NSArray<RCTDevMenuItem *> *items = [self menuItems];
|
||||||
for (RCTDevMenuItem *item in items) {
|
for (RCTDevMenuItem *item in items) {
|
||||||
switch (item.type) {
|
|
||||||
case RCTDevMenuTypeButton: {
|
|
||||||
[_actionSheet addAction:[UIAlertAction actionWithTitle:item.title
|
[_actionSheet addAction:[UIAlertAction actionWithTitle:item.title
|
||||||
style:UIAlertActionStyleDefault
|
style:UIAlertActionStyleDefault
|
||||||
handler:^(__unused UIAlertAction *action) {
|
handler:[self alertActionHandlerForDevItem:item]]];
|
||||||
[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:@"Cancel"
|
[_actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel"
|
||||||
style:UIAlertActionStyleCancel
|
style:UIAlertActionStyleCancel
|
||||||
handler:nil]];
|
handler:[self alertActionHandlerForDevItem:nil]]];
|
||||||
|
|
||||||
_presentedItems = items;
|
_presentedItems = items;
|
||||||
[RCTPresentedViewController() presentViewController:_actionSheet animated:YES completion:nil];
|
[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)
|
RCT_EXPORT_METHOD(reload)
|
||||||
{
|
{
|
||||||
|
@ -675,6 +689,11 @@ RCT_EXPORT_METHOD(setHotLoadingEnabled:(BOOL)enabled)
|
||||||
[_updateTask resume];
|
[_updateTask resume];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL)isActionSheetShown
|
||||||
|
{
|
||||||
|
return _actionSheet != nil;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#else // Unavailable when not in dev mode
|
#else // Unavailable when not in dev mode
|
||||||
|
@ -685,6 +704,7 @@ RCT_EXPORT_METHOD(setHotLoadingEnabled:(BOOL)enabled)
|
||||||
- (void)reload {}
|
- (void)reload {}
|
||||||
- (void)addItem:(NSString *)title handler:(dispatch_block_t)handler {}
|
- (void)addItem:(NSString *)title handler:(dispatch_block_t)handler {}
|
||||||
- (void)addItem:(RCTDevMenu *)item {}
|
- (void)addItem:(RCTDevMenu *)item {}
|
||||||
|
- (BOOL)isActionSheetShown { return NO; }
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче