From 64ebe5bbdd32fc3b3a243a8a81a6f724d8f81267 Mon Sep 17 00:00:00 2001 From: Gabriel Donadel Dall'Agnol Date: Fri, 11 Mar 2022 16:33:17 -0800 Subject: [PATCH] feat: Add dismissActionSheet method to ActionSheetIOS (#33189) Summary: This PR adds a `dismissActionSheet` method to `ActionSheetIOS` in order to allow dismissing an ActionSheet programmatically. This is especially useful in apps where a user has the ability to open an ActionSheet and then open a push notification that will redirect them to another screen which usually leads to scenarios where the presented ActionSheet has no relation with the current screen. #### TODO - [ ] Submit react-native-website PR updating ActionSheetIOS documentation. ## Changelog [iOS] [Added] - Add dismissActionSheet method to ActionSheetIOS Pull Request resolved: https://github.com/facebook/react-native/pull/33189 Test Plan: 1. Open the RNTester app and navigate to the ActionSheetIOS page 2. Test `dismissActionSheet` through the `Show Action Sheet and automatically dismiss it` example https://user-images.githubusercontent.com/11707729/155867546-c6770a49-9b09-45e3-a6b1-4f7645d67dbf.mov Reviewed By: lunaleaps Differential Revision: D34518952 Pulled By: cortinico fbshipit-source-id: 912a9b83ee078f791b42efddf5abb7e1cd09d520 --- Libraries/ActionSheetIOS/ActionSheetIOS.js | 7 ++++ .../NativeActionSheetManager.js | 1 + React/CoreModules/RCTActionSheetManager.mm | 30 ++++++++++++++++ .../ActionSheetIOS/ActionSheetIOSExample.js | 34 +++++++++++++++++++ 4 files changed, 72 insertions(+) diff --git a/Libraries/ActionSheetIOS/ActionSheetIOS.js b/Libraries/ActionSheetIOS/ActionSheetIOS.js index 30ecf4a3d0..0904d14024 100644 --- a/Libraries/ActionSheetIOS/ActionSheetIOS.js +++ b/Libraries/ActionSheetIOS/ActionSheetIOS.js @@ -143,6 +143,13 @@ const ActionSheetIOS = { successCallback, ); }, + + dismissActionSheet: () => { + invariant(RCTActionSheetManager, "ActionSheetManager doesn't exist"); + if (typeof RCTActionSheetManager.dismissActionSheet === 'function') { + RCTActionSheetManager.dismissActionSheet(); + } + }, }; module.exports = ActionSheetIOS; diff --git a/Libraries/ActionSheetIOS/NativeActionSheetManager.js b/Libraries/ActionSheetIOS/NativeActionSheetManager.js index fb0a92ddb5..1f9ead0bdd 100644 --- a/Libraries/ActionSheetIOS/NativeActionSheetManager.js +++ b/Libraries/ActionSheetIOS/NativeActionSheetManager.js @@ -47,6 +47,7 @@ export interface Spec extends TurboModule { |}) => void, successCallback: (completed: boolean, activityType: ?string) => void, ) => void; + +dismissActionSheet?: () => void; } export default (TurboModuleRegistry.get('ActionSheetManager'): ?Spec); diff --git a/React/CoreModules/RCTActionSheetManager.mm b/React/CoreModules/RCTActionSheetManager.mm index e2b579244d..433a2cfa74 100644 --- a/React/CoreModules/RCTActionSheetManager.mm +++ b/React/CoreModules/RCTActionSheetManager.mm @@ -21,10 +21,27 @@ using namespace facebook::react; @interface RCTActionSheetManager () + +@property (nonatomic, strong) NSMutableArray *alertControllers; + @end @implementation RCTActionSheetManager +- (instancetype)init +{ + self = [super init]; + if (self) { + _alertControllers = [NSMutableArray new]; + } + return self; +} + ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + RCT_EXPORT_MODULE() @synthesize viewRegistry_DEPRECATED = _viewRegistry_DEPRECATED; @@ -137,6 +154,7 @@ RCT_EXPORT_METHOD(showActionSheetWithOptions handler:^(__unused UIAlertAction *action) { if (!callbackInvoked) { callbackInvoked = true; + [self->_alertControllers removeObject:alertController]; callback(@[ @(localIndex) ]); } }]; @@ -178,9 +196,21 @@ RCT_EXPORT_METHOD(showActionSheetWithOptions } #endif + [_alertControllers addObject:alertController]; [self presentViewController:alertController onParentViewController:controller anchorViewTag:anchorViewTag]; } +RCT_EXPORT_METHOD(dismissActionSheet) +{ + if (_alertControllers.count == 0) { + RCTLogWarn(@"Unable to dismiss action sheet"); + } + + id _alertController = [_alertControllers lastObject]; + [_alertController dismissViewControllerAnimated:YES completion:nil]; + [_alertControllers removeLastObject]; +} + RCT_EXPORT_METHOD(showShareActionSheetWithOptions : (JS::NativeActionSheetManager::SpecShowShareActionSheetWithOptionsOptions &)options failureCallback : (RCTResponseSenderBlock)failureCallback successCallback diff --git a/packages/rn-tester/js/examples/ActionSheetIOS/ActionSheetIOSExample.js b/packages/rn-tester/js/examples/ActionSheetIOS/ActionSheetIOSExample.js index c9af0c16ff..4b7ada70a3 100644 --- a/packages/rn-tester/js/examples/ActionSheetIOS/ActionSheetIOSExample.js +++ b/packages/rn-tester/js/examples/ActionSheetIOS/ActionSheetIOSExample.js @@ -204,6 +204,34 @@ class ActionSheetDisabledExample extends React.Component { }; } +class ActionSheetDismissExample extends React.Component<{...}> { + render() { + return ( + + + Click to show and automatically dismiss the ActionSheet after 3 + seconds + + + ); + } + + showAndDismissActionSheet = () => { + ActionSheetIOS.showActionSheetWithOptions( + { + options: BUTTONS, + cancelButtonIndex: CANCEL_INDEX, + destructiveButtonIndex: DESTRUCTIVE_INDEX, + }, + () => {}, + ); + + setTimeout(() => { + ActionSheetIOS.dismissActionSheet(); + }, 3000); + }; +} + class ShareActionSheetExample extends React.Component< $FlowFixMeProps, $FlowFixMeState, @@ -394,6 +422,12 @@ exports.examples = [ return ; }, }, + { + title: 'Show Action Sheet and automatically dismiss it', + render(): React.Element { + return ; + }, + }, { title: 'Show Share Action Sheet', render(): React.Element {