diff --git a/Libraries/Alert/Alert.js b/Libraries/Alert/Alert.js index 9d64acda4e6..1e03d1d136d 100644 --- a/Libraries/Alert/Alert.js +++ b/Libraries/Alert/Alert.js @@ -10,9 +10,13 @@ 'use strict'; -const NativeModules = require('../BatchedBridge/NativeModules'); +import NativeModules from '../BatchedBridge/NativeModules'; +import Platform from '../Utilities/Platform'; +import DialogManagerAndroid, { + type DialogOptions, +} from '../NativeModules/specs/NativeDialogManagerAndroid'; + const RCTAlertManager = NativeModules.AlertManager; -const Platform = require('../Utilities/Platform'); export type Buttons = Array<{ text?: string, @@ -53,14 +57,19 @@ class Alert { if (Platform.OS === 'ios') { Alert.prompt(title, message, buttons, 'default'); } else if (Platform.OS === 'android') { - let config = { + if (!DialogManagerAndroid) { + return; + } + const constants = DialogManagerAndroid.getConstants(); + + const config: DialogOptions = { title: title || '', message: message || '', cancelable: false, }; - if (options) { - config = {...config, cancelable: options.cancelable}; + if (options && options.cancelable) { + config.cancelable = options.cancelable; } // At most three buttons (neutral, negative, positive). Ignore rest. // The text 'OK' should be probably localized. iOS Alert does that in native. @@ -70,38 +79,32 @@ class Alert { const buttonPositive = validButtons.pop(); const buttonNegative = validButtons.pop(); const buttonNeutral = validButtons.pop(); + if (buttonNeutral) { - config = {...config, buttonNeutral: buttonNeutral.text || ''}; + config.buttonNeutral = buttonNeutral.text || ''; } if (buttonNegative) { - config = {...config, buttonNegative: buttonNegative.text || ''}; + config.buttonNegative = buttonNegative.text || ''; } if (buttonPositive) { - config = {...config, buttonPositive: buttonPositive.text || ''}; + config.buttonPositive = buttonPositive.text || ''; } - NativeModules.DialogManagerAndroid.showAlert( - config, - errorMessage => console.warn(errorMessage), - (action, buttonKey) => { - if (action === NativeModules.DialogManagerAndroid.buttonClicked) { - if ( - buttonKey === NativeModules.DialogManagerAndroid.buttonNeutral - ) { - buttonNeutral.onPress && buttonNeutral.onPress(); - } else if ( - buttonKey === NativeModules.DialogManagerAndroid.buttonNegative - ) { - buttonNegative.onPress && buttonNegative.onPress(); - } else if ( - buttonKey === NativeModules.DialogManagerAndroid.buttonPositive - ) { - buttonPositive.onPress && buttonPositive.onPress(); - } - } else if (action === NativeModules.DialogManagerAndroid.dismissed) { - options && options.onDismiss && options.onDismiss(); + + const onAction = (action, buttonKey) => { + if (action === constants.buttonClicked) { + if (buttonKey === constants.buttonNeutral) { + buttonNeutral.onPress && buttonNeutral.onPress(); + } else if (buttonKey === constants.buttonNegative) { + buttonNegative.onPress && buttonNegative.onPress(); + } else if (buttonKey === constants.buttonPositive) { + buttonPositive.onPress && buttonPositive.onPress(); } - }, - ); + } else if (action === constants.dismissed) { + options && options.onDismiss && options.onDismiss(); + } + }; + const onError = errorMessage => console.warn(errorMessage); + DialogManagerAndroid.showAlert(config, onError, onAction); } } diff --git a/Libraries/Alert/RCTAlertManager.android.js b/Libraries/Alert/RCTAlertManager.android.js index 843dec92fe4..43f49a94e50 100644 --- a/Libraries/Alert/RCTAlertManager.android.js +++ b/Libraries/Alert/RCTAlertManager.android.js @@ -9,14 +9,18 @@ 'use strict'; -const NativeModules = require('../BatchedBridge/NativeModules'); +import NativeDialogManagerAndroid from '../NativeModules/specs/NativeDialogManagerAndroid'; function emptyCallback() {} module.exports = { alertWithArgs: function(args, callback) { // TODO(5998984): Polyfill it correctly with DialogManagerAndroid - NativeModules.DialogManagerAndroid.showAlert( + if (!NativeDialogManagerAndroid) { + return; + } + + NativeDialogManagerAndroid.showAlert( args, emptyCallback, callback || emptyCallback, diff --git a/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js b/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js new file mode 100644 index 00000000000..ae8c121529f --- /dev/null +++ b/Libraries/NativeModules/specs/NativeDialogManagerAndroid.js @@ -0,0 +1,49 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow strict-local + * @format + */ + +'use strict'; + +import type {TurboModule} from 'RCTExport'; +import * as TurboModuleRegistry from 'TurboModuleRegistry'; + +/* 'buttonClicked' | 'dismissed' */ +type DialogAction = string; +/* + buttonPositive = -1, + buttonNegative = -2, + buttonNeutral = -3 +*/ +type DialogButtonKey = number; +export type DialogOptions = {| + title?: string, + message?: string, + buttonPositive?: string, + buttonNegative?: string, + buttonNeutral?: string, + items?: Array, + cancelable?: boolean, +|}; + +export interface Spec extends TurboModule { + +getConstants: () => {| + +buttonClicked: DialogAction, + +dismissed: DialogAction, + +buttonPositive: DialogButtonKey, + +buttonNegative: DialogButtonKey, + +buttonNeutral: DialogButtonKey, + |}; + +showAlert: ( + config: DialogOptions, + onError: (string) => void, + onAction: (action: DialogAction, buttonKey?: DialogButtonKey) => void, + ) => void; +} + +export default TurboModuleRegistry.get('DialogManagerAndroid'); diff --git a/Libraries/PermissionsAndroid/PermissionsAndroid.js b/Libraries/PermissionsAndroid/PermissionsAndroid.js index ae35e07cac6..91522c89109 100644 --- a/Libraries/PermissionsAndroid/PermissionsAndroid.js +++ b/Libraries/PermissionsAndroid/PermissionsAndroid.js @@ -10,6 +10,7 @@ 'use strict'; +import NativeDialogManagerAndroid from '../NativeModules/specs/NativeDialogManagerAndroid'; const NativeModules = require('../BatchedBridge/NativeModules'); export type Rationale = { @@ -134,10 +135,13 @@ class PermissionsAndroid { permission, ); - if (shouldShowRationale) { + if (shouldShowRationale && !!NativeDialogManagerAndroid) { return new Promise((resolve, reject) => { - NativeModules.DialogManagerAndroid.showAlert( - rationale, + const options = { + ...rationale, + }; + NativeDialogManagerAndroid.showAlert( + options, () => reject(new Error('Error showing rationale')), () => resolve(