From 61ba698238e652bf6e2c63fb7ad72bb111420e64 Mon Sep 17 00:00:00 2001 From: azimgd Date: Thu, 2 Feb 2023 21:05:28 +0500 Subject: [PATCH 01/38] enable keycommands on native devices --- .../java/com/expensify/chat/MainActivity.java | 12 +++ ios/Podfile.lock | 6 ++ package-lock.json | 59 ++++++++++++++ package.json | 1 + src/CONST.js | 38 +++++++++ src/components/KeyboardShortcutsModal.js | 6 +- src/libs/KeyboardShortcut/index.js | 79 +++---------------- src/libs/KeyboardShortcut/index.native.js | 12 --- src/libs/KeyboardShortcut/keyboard.js | 77 ++++++++++++++++++ src/libs/KeyboardShortcut/keyboard.native.js | 59 ++++++++++++++ .../getModalStyles/getBaseModalStyles.js | 1 - src/styles/styles.js | 1 - 12 files changed, 265 insertions(+), 86 deletions(-) delete mode 100644 src/libs/KeyboardShortcut/index.native.js create mode 100644 src/libs/KeyboardShortcut/keyboard.js create mode 100644 src/libs/KeyboardShortcut/keyboard.native.js diff --git a/android/app/src/main/java/com/expensify/chat/MainActivity.java b/android/app/src/main/java/com/expensify/chat/MainActivity.java index 24dcf36a177b..42966aab23ad 100644 --- a/android/app/src/main/java/com/expensify/chat/MainActivity.java +++ b/android/app/src/main/java/com/expensify/chat/MainActivity.java @@ -2,7 +2,9 @@ import android.os.Bundle; import android.content.pm.ActivityInfo; +import android.view.KeyEvent; import com.expensify.chat.bootsplash.BootSplash; +import com.expensify.reactnativekeycommand.KeyCommandModule; import com.facebook.react.ReactActivity; import com.facebook.react.ReactActivityDelegate; import com.facebook.react.ReactRootView; @@ -57,4 +59,14 @@ protected void onCreate(Bundle savedInstanceState) { } BootSplash.init(R.drawable.bootsplash, MainActivity.this); // <- display the generated bootsplash.xml drawable over our MainActivity } + + /** + * This method is called when a key down event has occurred. + * Forwards the event to the KeyCommandModule + */ + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event); + return super.onKeyDown(keyCode, event); + } } diff --git a/ios/Podfile.lock b/ios/Podfile.lock index fbccc4067560..a01518056f5c 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -474,6 +474,8 @@ PODS: - React - react-native-image-picker (5.0.1): - React-Core + - react-native-key-command (0.5.0): + - React-Core - react-native-netinfo (8.3.1): - React-Core - react-native-pdf (6.6.2): @@ -704,6 +706,7 @@ DEPENDENCIES: - react-native-flipper (from `../node_modules/react-native-flipper`) - "react-native-image-manipulator (from `../node_modules/@oguzhnatly/react-native-image-manipulator`)" - react-native-image-picker (from `../node_modules/react-native-image-picker`) + - react-native-key-command (from `../node_modules/react-native-key-command`) - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" - react-native-pdf (from `../node_modules/react-native-pdf`) - react-native-performance (from `../node_modules/react-native-performance`) @@ -849,6 +852,8 @@ EXTERNAL SOURCES: :path: "../node_modules/@oguzhnatly/react-native-image-manipulator" react-native-image-picker: :path: "../node_modules/react-native-image-picker" + react-native-key-command: + :path: "../node_modules/react-native-key-command" react-native-netinfo: :path: "../node_modules/@react-native-community/netinfo" react-native-pdf: @@ -993,6 +998,7 @@ SPEC CHECKSUMS: react-native-flipper: dc5290261fbeeb2faec1bdc57ae6dd8d562e1de4 react-native-image-manipulator: c48f64221cfcd46e9eec53619c4c0374f3328a56 react-native-image-picker: 8cb4280e2c1efc3daeb2d9d597f9429a60472e40 + react-native-key-command: bdc18250128146769441ddc8f77e4bc9e625bde1 react-native-netinfo: 1a6035d3b9780221d407c277ebfb5722ace00658 react-native-pdf: 33c622cbdf776a649929e8b9d1ce2d313347c4fa react-native-performance: 224bd53e6a835fda4353302cf891d088a0af7406 diff --git a/package-lock.json b/package-lock.json index 7e91c3818c1b..06cfa0c0ff59 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,6 +68,7 @@ "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^5.0.1", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972", + "react-native-key-command": "^0.5.0", "react-native-modal": "^13.0.0", "react-native-onyx": "1.0.36", "react-native-pdf": "^6.6.2", @@ -35615,6 +35616,21 @@ "integrity": "sha512-jNNpW5byieb7pb/l0HRvmCav4BtzpTzgC+ybT+Wbi2yyroOukveVvnjwWnmoOeuGynsYB4Yt5eGrWZnPnJSwqQ==", "license": "MIT" }, + "node_modules/react-native-key-command": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.5.0.tgz", + "integrity": "sha512-FPpTrcSl/+D/yPmvSUvLFqMvqZ/wkgGNttfIbs4kRna0xAA0Wzg3JBs3N6ofLORxlT4gJFL9sRAkCEqzB50Faw==", + "dependencies": { + "events": "^3.3.0", + "underscore": "^1.13.4" + }, + "peerDependencies": { + "react": "18.1.0", + "react-dom": "18.1.0", + "react-native": "0.70.4", + "react-native-web": "0.18.1" + } + }, "node_modules/react-native-modal": { "version": "13.0.1", "resolved": "https://registry.npmjs.org/react-native-modal/-/react-native-modal-13.0.1.tgz", @@ -35850,6 +35866,25 @@ "react-native-svg": ">=12.0.0" } }, + "node_modules/react-native-web": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.18.1.tgz", + "integrity": "sha512-kWZKJU/OIvVriC7R7WN2Wpai6QllD9f7RDUuaBj2G9FdXaybSQFgmuhey4n6naqbLnj720im2PtcnH54Cn/UXw==", + "peer": true, + "dependencies": { + "create-react-class": "^15.7.0", + "fbjs": "^3.0.0", + "inline-style-prefixer": "^6.0.0", + "normalize-css-color": "^1.0.2", + "postcss-value-parser": "^4.2.0", + "prop-types": "^15.6.0", + "styleq": "^0.1.2" + }, + "peerDependencies": { + "react": ">=17.0.2", + "react-dom": ">=17.0.2" + } + }, "node_modules/react-native-webview": { "version": "11.23.0", "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-11.23.0.tgz", @@ -70034,6 +70069,15 @@ "integrity": "sha512-jNNpW5byieb7pb/l0HRvmCav4BtzpTzgC+ybT+Wbi2yyroOukveVvnjwWnmoOeuGynsYB4Yt5eGrWZnPnJSwqQ==", "from": "react-native-image-size@git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972" }, + "react-native-key-command": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.5.0.tgz", + "integrity": "sha512-FPpTrcSl/+D/yPmvSUvLFqMvqZ/wkgGNttfIbs4kRna0xAA0Wzg3JBs3N6ofLORxlT4gJFL9sRAkCEqzB50Faw==", + "requires": { + "events": "^3.3.0", + "underscore": "^1.13.4" + } + }, "react-native-modal": { "version": "13.0.1", "resolved": "https://registry.npmjs.org/react-native-modal/-/react-native-modal-13.0.1.tgz", @@ -70189,6 +70233,21 @@ "path-dirname": "^1.0.2" } }, + "react-native-web": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.18.1.tgz", + "integrity": "sha512-kWZKJU/OIvVriC7R7WN2Wpai6QllD9f7RDUuaBj2G9FdXaybSQFgmuhey4n6naqbLnj720im2PtcnH54Cn/UXw==", + "peer": true, + "requires": { + "create-react-class": "^15.7.0", + "fbjs": "^3.0.0", + "inline-style-prefixer": "^6.0.0", + "normalize-css-color": "^1.0.2", + "postcss-value-parser": "^4.2.0", + "prop-types": "^15.6.0", + "styleq": "^0.1.2" + } + }, "react-native-webview": { "version": "11.23.0", "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-11.23.0.tgz", diff --git a/package.json b/package.json index db52903f6d17..8790d1278cb5 100644 --- a/package.json +++ b/package.json @@ -99,6 +99,7 @@ "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^5.0.1", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972", + "react-native-key-command": "^0.5.0", "react-native-modal": "^13.0.0", "react-native-onyx": "1.0.36", "react-native-pdf": "^6.6.2", diff --git a/src/CONST.js b/src/CONST.js index ae3ffca7f025..66ea74817807 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -1,6 +1,7 @@ import lodashGet from 'lodash/get'; import Config from 'react-native-config'; import * as Url from './libs/Url'; +import * as KeyCommand from 'react-native-key-command'; const CLOUDFRONT_URL = 'https://d2k5nsl2zxldvw.cloudfront.net'; const ACTIVE_EXPENSIFY_URL = Url.addTrailingForwardSlash(lodashGet(Config, 'NEW_EXPENSIFY_URL', 'https://new.expensify.com')); @@ -199,46 +200,83 @@ const CONST = { descriptionKey: 'search', shortcutKey: 'K', modifiers: ['CTRL'], + trigger: { + DEFAULT: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierControl}, + [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierCommand}, + }, }, NEW_GROUP: { descriptionKey: 'newGroup', shortcutKey: 'K', modifiers: ['CTRL', 'SHIFT'], + trigger: { + // fix library bug, web: keyModifierControlShift, android: keyModifierShiftControl + DEFAULT: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierShiftControl}, + [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierShiftCommand}, + }, }, SHORTCUT_MODAL: { descriptionKey: 'openShortcutDialog', shortcutKey: 'I', modifiers: ['CTRL'], + trigger: { + DEFAULT: {input: 'i', modifierFlags: KeyCommand.constants.keyModifierControl}, + [PLATFORM_OS_MACOS]: {input: 'i', modifierFlags: KeyCommand.constants.keyModifierCommand}, + }, }, ESCAPE: { descriptionKey: 'escape', shortcutKey: 'Escape', modifiers: [], + trigger: { + DEFAULT: {input: KeyCommand.constants.keyInputEscape}, + [PLATFORM_OS_MACOS]: {input: KeyCommand.constants.keyInputEscape}, + }, }, ENTER: { descriptionKey: null, shortcutKey: 'Enter', modifiers: [], + trigger: { + DEFAULT: {input: KeyCommand.constants.keyInputEnter}, + [PLATFORM_OS_MACOS]: {input: KeyCommand.constants.keyInputEnter}, + }, }, CTRL_ENTER: { descriptionKey: null, shortcutKey: 'Enter', modifiers: ['CTRL'], + trigger: { + DEFAULT: {input: KeyCommand.constants.keyInputEnter, modifierFlags: KeyCommand.constants.keyModifierControl}, + [PLATFORM_OS_MACOS]: {input: KeyCommand.constants.keyInputEnter, modifierFlags: KeyCommand.constants.keyModifierCommand}, + }, }, COPY: { descriptionKey: 'copy', shortcutKey: 'C', modifiers: ['CTRL'], + trigger: { + DEFAULT: {input: 'c', modifierFlags: KeyCommand.constants.keyModifierControl}, + [PLATFORM_OS_MACOS]: {input: 'c', modifierFlags: KeyCommand.constants.keyModifierCommand}, + }, }, ARROW_UP: { descriptionKey: null, shortcutKey: 'ArrowUp', modifiers: [], + trigger: { + DEFAULT: {input: KeyCommand.constants.keyInputUpArrow}, + [PLATFORM_OS_MACOS]: {input: KeyCommand.constants.keyInputUpArrow}, + }, }, ARROW_DOWN: { descriptionKey: null, shortcutKey: 'ArrowDown', modifiers: [], + trigger: { + DEFAULT: {input: KeyCommand.constants.keyInputDownArrow}, + [PLATFORM_OS_MACOS]: {input: KeyCommand.constants.keyInputDownArrow}, + }, }, }, KEYBOARD_SHORTCUT_KEY_DISPLAY_NAME: { diff --git a/src/components/KeyboardShortcutsModal.js b/src/components/KeyboardShortcutsModal.js index c45ced82f11b..b1b1a91f01aa 100644 --- a/src/components/KeyboardShortcutsModal.js +++ b/src/components/KeyboardShortcutsModal.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {View} from 'react-native'; +import {View, ScrollView} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import HeaderWithCloseButton from './HeaderWithCloseButton'; @@ -54,7 +54,7 @@ class KeyboardShortcutsModal extends React.Component { */ renderRow(shortcut, isFirstRow) { return ( - {this.props.translate(`keyboardShortcutModal.shortcuts.${shortcut.descriptionKey}`)} - + ); } diff --git a/src/libs/KeyboardShortcut/index.js b/src/libs/KeyboardShortcut/index.js index f948d6991461..943ca551e0db 100644 --- a/src/libs/KeyboardShortcut/index.js +++ b/src/libs/KeyboardShortcut/index.js @@ -1,9 +1,13 @@ import _ from 'underscore'; import lodashGet from 'lodash/get'; import Str from 'expensify-common/lib/str'; +import * as KeyCommand from 'react-native-key-command'; +import * as Keyboard from './keyboard.native'; import getOperatingSystem from '../getOperatingSystem'; import CONST from '../../CONST'; +const operatingSystem = getOperatingSystem(); + // Handlers for the various keyboard listeners we set up const eventHandlers = {}; @@ -17,29 +21,6 @@ function getDocumentedShortcuts() { return _.values(documentedShortcuts); } -/** - * Gets modifiers from a keyboard event. - * - * @param {Event} event - * @returns {Array} - */ -function getKeyEventModifiers(event) { - const modifiers = []; - if (event.shiftKey) { - modifiers.push('SHIFT'); - } - if (event.ctrlKey) { - modifiers.push('CONTROL'); - } - if (event.altKey) { - modifiers.push('ALT'); - } - if (event.metaKey) { - modifiers.push('META'); - } - return modifiers; -} - /** * Generates the normalized display name for keyboard shortcuts. * @@ -60,51 +41,12 @@ function getDisplayName(key, modifiers) { return displayName.join(' + '); } -/** - * Checks if an event for that key is configured and if so, runs it. - * @param {Event} event - * @private - */ -function bindHandlerToKeydownEvent(event) { - if (!(event instanceof KeyboardEvent)) { - return; - } - - const eventModifiers = getKeyEventModifiers(event); - const displayName = getDisplayName(event.key, eventModifiers); - - // Loop over all the callbacks - _.every(eventHandlers[displayName], (callback) => { - // If configured to do so, prevent input text control to trigger this event - if (!callback.captureOnInputs && ( - event.target.nodeName === 'INPUT' - || event.target.nodeName === 'TEXTAREA' - || event.target.contentEditable === 'true' - )) { - return true; - } - - // Determine if the event should bubble before executing the callback (which may have side-effects) - let shouldBubble = callback.shouldBubble || false; - if (_.isFunction(callback.shouldBubble)) { - shouldBubble = callback.shouldBubble(); - } - - if (_.isFunction(callback.callback)) { - callback.callback(event); - } - if (callback.shouldPreventDefault) { - event.preventDefault(); - } - - // If the event should not bubble, short-circuit the loop - return shouldBubble; - }); -} - -// Make sure we don't add multiple listeners -document.removeEventListener('keydown', bindHandlerToKeydownEvent, {capture: true}); -document.addEventListener('keydown', bindHandlerToKeydownEvent, {capture: true}); +_.each(CONST.KEYBOARD_SHORTCUTS, (shortcut) => { + KeyCommand.addListener( + shortcut.trigger[operatingSystem] || shortcut.trigger.DEFAULT, + (keycommandEvent, event) => Keyboard.bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEvent, event), + ); +}); /** * Unsubscribes a keyboard event handler. @@ -124,7 +66,6 @@ function unsubscribe(displayName, callbackID) { * @returns {Array} */ function getPlatformEquivalentForKeys(keys) { - const operatingSystem = getOperatingSystem(); return _.map(keys, (key) => { if (!_.has(CONST.PLATFORM_SPECIFIC_KEYS, key)) { return key; diff --git a/src/libs/KeyboardShortcut/index.native.js b/src/libs/KeyboardShortcut/index.native.js deleted file mode 100644 index 8c97f2daf343..000000000000 --- a/src/libs/KeyboardShortcut/index.native.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * This is a no-op component for native devices because they wouldn't be able to support keyboard shortcuts like - * a website. - */ -const KeyboardShortcut = { - subscribe() { - return () => {}; - }, - getDocumentedShortcuts() { return []; }, -}; - -export default KeyboardShortcut; diff --git a/src/libs/KeyboardShortcut/keyboard.js b/src/libs/KeyboardShortcut/keyboard.js new file mode 100644 index 000000000000..eedd2bcd4e63 --- /dev/null +++ b/src/libs/KeyboardShortcut/keyboard.js @@ -0,0 +1,77 @@ +import _ from 'underscore'; + +/** + * Gets modifiers from a keyboard event. + * + * @param {Event} event + * @returns {Array} + */ +function getKeyEventModifiers(event) { + const modifiers = []; + + if ((event instanceof KeyboardEvent)) { + if (event.shiftKey) { + modifiers.push('SHIFT'); + } + if (event.ctrlKey) { + modifiers.push('CONTROL'); + } + if (event.metaKey) { + modifiers.push('META'); + } + + return modifiers; + } + + return []; +} + +/** + * Checks if an event for that key is configured and if so, runs it. + * @param {Function} getDisplayName + * @param {Object} eventHandlers + * @param {Object} keycommandEvent + * @param {Event} event + * @private + */ +function bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEvent, event) { + if (!(event instanceof KeyboardEvent)) { + return; + } + + const eventModifiers = getKeyEventModifiers(event); + const displayName = getDisplayName(event.key, eventModifiers); + + // Loop over all the callbacks + _.every(eventHandlers[displayName], (callback) => { + // If configured to do so, prevent input text control to trigger this event + if (!callback.captureOnInputs && ( + event.target.nodeName === 'INPUT' + || event.target.nodeName === 'TEXTAREA' + || event.target.contentEditable === 'true' + )) { + return true; + } + + // Determine if the event should bubble before executing the callback (which may have side-effects) + let shouldBubble = callback.shouldBubble || false; + if (_.isFunction(callback.shouldBubble)) { + shouldBubble = callback.shouldBubble(); + } + + if (_.isFunction(callback.callback)) { + callback.callback(event); + } + if (callback.shouldPreventDefault) { + event.preventDefault(); + } + + // If the event should not bubble, short-circuit the loop + return shouldBubble; + }); +} + +export { + getKeyEventModifiers, + bindHandlerToKeydownEvent, +}; diff --git a/src/libs/KeyboardShortcut/keyboard.native.js b/src/libs/KeyboardShortcut/keyboard.native.js new file mode 100644 index 000000000000..f0a43c400cb1 --- /dev/null +++ b/src/libs/KeyboardShortcut/keyboard.native.js @@ -0,0 +1,59 @@ +import _ from 'underscore'; +import * as KeyCommand from 'react-native-key-command'; + +/** + * Gets modifiers from a keyboard event. + * + * @param {Event} event + * @returns {Array} + */ +function getKeyEventModifiers(event) { + if (event.modifierFlags === KeyCommand.constants.keyModifierControl) { + return ['CONTROL']; + } + if (event.modifierFlags === KeyCommand.constants.keyModifierCommand) { + return ['META']; + } + if (event.modifierFlags === KeyCommand.constants.keyModifierShiftControl) { + return ['SHIFT', 'CONTROL']; + } + if (event.modifierFlags === KeyCommand.constants.keyModifierShiftCommand) { + return ['META', 'CONTROL']; + } + + return []; +} + +/** + * Checks if an event for that key is configured and if so, runs it. + * @param {Function} getDisplayName + * @param {Object} eventHandlers + * @param {Object} keycommandEvent + * @param {Event} event + * @private + */ +function bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEvent, event) { + const eventModifiers = getKeyEventModifiers(keycommandEvent); + const displayName = getDisplayName(keycommandEvent.input, eventModifiers); + + // Loop over all the callbacks + _.every(eventHandlers[displayName], (callback) => { + // Determine if the event should bubble before executing the callback (which may have side-effects) + let shouldBubble = callback.shouldBubble || false; + if (_.isFunction(callback.shouldBubble)) { + shouldBubble = callback.shouldBubble(); + } + + if (_.isFunction(callback.callback)) { + callback.callback(event); + } + + // If the event should not bubble, short-circuit the loop + return shouldBubble; + }); +} + +export { + getKeyEventModifiers, + bindHandlerToKeydownEvent, +}; diff --git a/src/styles/getModalStyles/getBaseModalStyles.js b/src/styles/getModalStyles/getBaseModalStyles.js index aea136f6818a..1e74188db9ef 100644 --- a/src/styles/getModalStyles/getBaseModalStyles.js +++ b/src/styles/getModalStyles/getBaseModalStyles.js @@ -107,7 +107,6 @@ export default (type, windowDimensions, popoverAnchorPosition = {}, containerSty shadowOpacity: 0.1, shadowRadius: 5, - flex: 1, marginTop: isSmallScreenWidth ? 0 : 20, marginBottom: isSmallScreenWidth ? 0 : 20, borderRadius: isSmallScreenWidth ? 0 : 12, diff --git a/src/styles/styles.js b/src/styles/styles.js index 65d97d416a0f..ca1373bff0fc 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -2673,7 +2673,6 @@ const styles = { keyboardShortcutModalContainer: { maxHeight: '100%', - flex: '0 0 auto', }, keyboardShortcutTableWrapper: { From f71d9aa1113956110454875569ed349fa87cc356 Mon Sep 17 00:00:00 2001 From: azimgd Date: Thu, 2 Feb 2023 21:07:57 +0500 Subject: [PATCH 02/38] merge main --- android/app/build.gradle | 4 +- .../simple-illustration__shield.svg | 77 +++++++++++++++++++ ios/NewExpensify/Info.plist | 4 +- ios/NewExpensifyTests/Info.plist | 4 +- package-lock.json | 4 +- package.json | 2 +- src/components/Icon/Illustrations.js | 2 + src/languages/en.js | 3 + src/languages/es.js | 3 + src/pages/LogOutPreviousUserPage.js | 12 +++ .../ReimbursementAccount/Enable2FAPrompt.js | 45 +++++++++++ .../ReimbursementAccount/ValidationStep.js | 45 +++++++++-- 12 files changed, 190 insertions(+), 15 deletions(-) create mode 100644 assets/images/simple-illustrations/simple-illustration__shield.svg create mode 100644 src/pages/ReimbursementAccount/Enable2FAPrompt.js diff --git a/android/app/build.gradle b/android/app/build.gradle index f41e0e7f8fec..0a170feca730 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -156,8 +156,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001026301 - versionName "1.2.63-1" + versionCode 1001026401 + versionName "1.2.64-1" buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() if (isNewArchitectureEnabled()) { diff --git a/assets/images/simple-illustrations/simple-illustration__shield.svg b/assets/images/simple-illustrations/simple-illustration__shield.svg new file mode 100644 index 000000000000..5d56b9c3acb2 --- /dev/null +++ b/assets/images/simple-illustrations/simple-illustration__shield.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 6d5e5b26c6f3..f7f3b511ef98 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.2.63 + 1.2.64 CFBundleSignature ???? CFBundleURLTypes @@ -30,7 +30,7 @@ CFBundleVersion - 1.2.63.1 + 1.2.64.1 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 4a1d8af8ac9e..87b043a3880f 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.2.63 + 1.2.64 CFBundleSignature ???? CFBundleVersion - 1.2.63.1 + 1.2.64.1 diff --git a/package-lock.json b/package-lock.json index 06cfa0c0ff59..a73e49c7e8fc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.2.63-1", + "version": "1.2.64-1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.2.63-1", + "version": "1.2.64-1", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 8790d1278cb5..367b5562c68f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.2.63-1", + "version": "1.2.64-1", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", diff --git a/src/components/Icon/Illustrations.js b/src/components/Icon/Illustrations.js index db6660717185..329e9f2b028f 100644 --- a/src/components/Icon/Illustrations.js +++ b/src/components/Icon/Illustrations.js @@ -18,6 +18,7 @@ import RocketOrange from '../../../assets/images/product-illustrations/rocket--o import TadaYellow from '../../../assets/images/product-illustrations/tada--yellow.svg'; import TadaBlue from '../../../assets/images/product-illustrations/tada--blue.svg'; import GpsTrackOrange from '../../../assets/images/product-illustrations/gps-track--orange.svg'; +import ShieldYellow from '../../../assets/images/simple-illustrations/simple-illustration__shield.svg'; import MoneyReceipts from '../../../assets/images/simple-illustrations/simple-illustration__money-receipts.svg'; import PinkBill from '../../../assets/images/simple-illustrations/simple-illustration__bill.svg'; import CreditCardsNew from '../../../assets/images/simple-illustrations/simple-illustration__credit-cards.svg'; @@ -56,6 +57,7 @@ export { TadaYellow, TadaBlue, GpsTrackOrange, + ShieldYellow, MoneyReceipts, PinkBill, CreditCardsNew, diff --git a/src/languages/en.js b/src/languages/en.js index 69ae592a7b3b..dddf50173b61 100755 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -827,6 +827,9 @@ export default { letsChatCTA: 'Yes, let\'s chat', letsChatText: 'Thanks for doing that. We need your help verifying a few pieces of information, but we can work this out quickly over chat. Ready?', letsChatTitle: 'Let\'s chat!', + enable2FATitle: 'Prevent fraud, enable two-factor authentication!', + enable2FAText: 'We take your security seriously, so please set up two-factor authentication for your account now. That will allow us to dispute Expensify Card digital transactions, and will reduce your risk for fraud.', + secureYourAccount: 'Secure your account', }, beneficialOwnersStep: { additionalInformation: 'Additional information', diff --git a/src/languages/es.js b/src/languages/es.js index 8b1ac18ef8e4..ef5bf45b1a10 100644 --- a/src/languages/es.js +++ b/src/languages/es.js @@ -829,6 +829,9 @@ export default { letsChatCTA: 'Sí, vamos a chatear', letsChatText: 'Gracias. Necesitamos tu ayuda para verificar la información, pero podemos hacerlo rápidamente a través del chat. ¿Estás listo?', letsChatTitle: '¡Vamos a chatear!', + enable2FATitle: 'Evita fraudes, activa la autenticación de dos factores!', + enable2FAText: 'Tu seguridad es importante para nosotros, por favor configura ahora la autenticación de dos factores. Eso nos permitirá disputar las transacciones de la Tarjeta Expensify y reducirá tu riesgo de fraude.', + secureYourAccount: 'Asegura tu cuenta', }, beneficialOwnersStep: { additionalInformation: 'Información adicional', diff --git a/src/pages/LogOutPreviousUserPage.js b/src/pages/LogOutPreviousUserPage.js index d9d36602721d..843930b14e8a 100644 --- a/src/pages/LogOutPreviousUserPage.js +++ b/src/pages/LogOutPreviousUserPage.js @@ -22,9 +22,21 @@ class LogOutPreviousUserPage extends Component { .then((transitionURL) => { const sessionEmail = lodashGet(this.props.session, 'email', ''); const isLoggingInAsNewUser = SessionUtils.isLoggingInAsNewUser(transitionURL, sessionEmail); + if (isLoggingInAsNewUser) { Session.signOutAndRedirectToSignIn(); } + + // We need to signin and fetch a new authToken, if a user was already authenticated in NewDot, and was redirected to OldDot + // and their authToken stored in Onyx becomes invalid. + // This workflow is triggered while setting up VBBA. User is redirected from NewDot to OldDot to set up 2FA, and then redirected back to NewDot + // On Enabling 2FA, authToken stored in Onyx becomes expired and hence we need to fetch new authToken + const shouldForceLogin = lodashGet(this.props, 'route.params.shouldForceLogin', '') === 'true'; + if (shouldForceLogin) { + const email = lodashGet(this.props, 'route.params.email', ''); + const shortLivedAuthToken = lodashGet(this.props, 'route.params.shortLivedAuthToken', ''); + Session.signInWithShortLivedAuthToken(email, shortLivedAuthToken); + } }); } diff --git a/src/pages/ReimbursementAccount/Enable2FAPrompt.js b/src/pages/ReimbursementAccount/Enable2FAPrompt.js new file mode 100644 index 000000000000..51c62b8957c1 --- /dev/null +++ b/src/pages/ReimbursementAccount/Enable2FAPrompt.js @@ -0,0 +1,45 @@ +import React from 'react'; +import {View} from 'react-native'; +import Text from '../../components/Text'; +import styles from '../../styles/styles'; +import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; +import * as Expensicons from '../../components/Icon/Expensicons'; +import * as Illustrations from '../../components/Icon/Illustrations'; +import Section from '../../components/Section'; +import * as Link from '../../libs/actions/Link'; +import ROUTES from '../../ROUTES'; +import themeColors from '../../styles/themes/default'; + +const propTypes = { + ...withLocalizePropTypes, +}; +const Enable2FAPrompt = props => ( +
{ + Link.openOldDotLink(encodeURI(`settings?param={"section":"account","action":"enableTwoFactorAuth","exitTo":"${ROUTES.getBankAccountRoute()}","isFromNewDot":"true"}`)); + }, + icon: Expensicons.Shield, + shouldShowRightIcon: true, + iconRight: Expensicons.NewWindow, + iconFill: themeColors.success, + wrapperStyle: [styles.cardMenuItem], + }, + ]} + > + + + {props.translate('validationStep.enable2FAText')} + + +
+); + +Enable2FAPrompt.propTypes = propTypes; +Enable2FAPrompt.displayName = 'Enable2FAPrompt'; + +export default withLocalize(Enable2FAPrompt); diff --git a/src/pages/ReimbursementAccount/ValidationStep.js b/src/pages/ReimbursementAccount/ValidationStep.js index 282c1c0fa974..ea3d5a93c115 100644 --- a/src/pages/ReimbursementAccount/ValidationStep.js +++ b/src/pages/ReimbursementAccount/ValidationStep.js @@ -1,11 +1,13 @@ import lodashGet from 'lodash/get'; import React from 'react'; -import {View} from 'react-native'; +import {ScrollView, View} from 'react-native'; +import {withOnyx} from 'react-native-onyx'; import Str from 'expensify-common/lib/str'; import _ from 'underscore'; import PropTypes from 'prop-types'; import styles from '../../styles/styles'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; +import compose from '../../libs/compose'; import * as BankAccounts from '../../libs/actions/BankAccounts'; import * as Report from '../../libs/actions/Report'; import HeaderWithCloseButton from '../../components/HeaderWithCloseButton'; @@ -25,6 +27,7 @@ import Section from '../../components/Section'; import CONST from '../../CONST'; import Button from '../../components/Button'; import MenuItem from '../../components/MenuItem'; +import Enable2FAPrompt from './Enable2FAPrompt'; const propTypes = { ...withLocalizePropTypes, @@ -33,6 +36,19 @@ const propTypes = { reimbursementAccount: ReimbursementAccountProps.reimbursementAccountPropTypes.isRequired, onBackButtonPress: PropTypes.func.isRequired, + + /** User's account who is setting up bank account */ + account: PropTypes.shape({ + + /** If user has Two factor authentication enabled */ + requiresTwoFactorAuth: PropTypes.bool, + }), +}; + +const defaultProps = { + account: { + requiresTwoFactorAuth: false, + }, }; class ValidationStep extends React.Component { @@ -109,6 +125,7 @@ class ValidationStep extends React.Component { const maxAttemptsReached = lodashGet(this.props.reimbursementAccount, 'maxAttemptsReached'); const isVerifying = !maxAttemptsReached && state === BankAccount.STATE.VERIFYING; + const requiresTwoFactorAuth = lodashGet(this.props, 'account.requiresTwoFactorAuth'); return ( @@ -152,7 +169,7 @@ class ValidationStep extends React.Component { {this.props.translate('validationStep.descriptionCTA')} - + + {!requiresTwoFactorAuth && ( + + + + )} )} {isVerifying && ( - +
-
+ {!requiresTwoFactorAuth && ( + + )} + )}
); @@ -212,5 +237,13 @@ class ValidationStep extends React.Component { } ValidationStep.propTypes = propTypes; - -export default withLocalize(ValidationStep); +ValidationStep.defaultProps = defaultProps; + +export default compose( + withLocalize, + withOnyx({ + account: { + key: ONYXKEYS.ACCOUNT, + }, + }), +)(ValidationStep); From fd695f29e5705337dd109d1e540cf6cdd6e54807 Mon Sep 17 00:00:00 2001 From: azimgd Date: Thu, 2 Feb 2023 22:09:20 +0500 Subject: [PATCH 03/38] fix shortcuts modal view --- src/components/KeyboardShortcutsModal.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/KeyboardShortcutsModal.js b/src/components/KeyboardShortcutsModal.js index b1b1a91f01aa..cacaf5270b2f 100644 --- a/src/components/KeyboardShortcutsModal.js +++ b/src/components/KeyboardShortcutsModal.js @@ -54,7 +54,7 @@ class KeyboardShortcutsModal extends React.Component { */ renderRow(shortcut, isFirstRow) { return ( - {this.props.translate(`keyboardShortcutModal.shortcuts.${shortcut.descriptionKey}`)} - + ); } @@ -83,7 +83,7 @@ class KeyboardShortcutsModal extends React.Component { onClose={KeyboardShortcutsActions.hideKeyboardShortcutModal} > - + {this.props.translate('keyboardShortcutModal.subtitle')} @@ -93,7 +93,7 @@ class KeyboardShortcutsModal extends React.Component { })} - + ); } From c39fab6241f213253eecb227fb9f04ec85f71c20 Mon Sep 17 00:00:00 2001 From: azimgd Date: Fri, 3 Feb 2023 00:11:44 +0500 Subject: [PATCH 04/38] unify keycommands on web and native --- src/CONST.js | 1 - .../index.js} | 36 +++---------------- .../index.native.js} | 30 ++-------------- .../KeyboardShortcut/getKeyEventModifiers.js | 26 ++++++++++++++ src/libs/KeyboardShortcut/index.js | 15 ++++++-- 5 files changed, 44 insertions(+), 64 deletions(-) rename src/libs/KeyboardShortcut/{keyboard.js => bindHandlerToKeydownEvent/index.js} (67%) rename src/libs/KeyboardShortcut/{keyboard.native.js => bindHandlerToKeydownEvent/index.native.js} (58%) create mode 100644 src/libs/KeyboardShortcut/getKeyEventModifiers.js diff --git a/src/CONST.js b/src/CONST.js index 66ea74817807..7bb35796cfa1 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -210,7 +210,6 @@ const CONST = { shortcutKey: 'K', modifiers: ['CTRL', 'SHIFT'], trigger: { - // fix library bug, web: keyModifierControlShift, android: keyModifierShiftControl DEFAULT: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierShiftControl}, [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierShiftCommand}, }, diff --git a/src/libs/KeyboardShortcut/keyboard.js b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.js similarity index 67% rename from src/libs/KeyboardShortcut/keyboard.js rename to src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.js index eedd2bcd4e63..339904f0bbef 100644 --- a/src/libs/KeyboardShortcut/keyboard.js +++ b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.js @@ -1,30 +1,5 @@ import _ from 'underscore'; - -/** - * Gets modifiers from a keyboard event. - * - * @param {Event} event - * @returns {Array} - */ -function getKeyEventModifiers(event) { - const modifiers = []; - - if ((event instanceof KeyboardEvent)) { - if (event.shiftKey) { - modifiers.push('SHIFT'); - } - if (event.ctrlKey) { - modifiers.push('CONTROL'); - } - if (event.metaKey) { - modifiers.push('META'); - } - - return modifiers; - } - - return []; -} +import getKeyEventModifiers from '../getKeyEventModifiers'; /** * Checks if an event for that key is configured and if so, runs it. @@ -39,8 +14,8 @@ function bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEven return; } - const eventModifiers = getKeyEventModifiers(event); - const displayName = getDisplayName(event.key, eventModifiers); + const eventModifiers = getKeyEventModifiers(keycommandEvent); + const displayName = getDisplayName(keycommandEvent.input, eventModifiers); // Loop over all the callbacks _.every(eventHandlers[displayName], (callback) => { @@ -71,7 +46,4 @@ function bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEven }); } -export { - getKeyEventModifiers, - bindHandlerToKeydownEvent, -}; +export default bindHandlerToKeydownEvent; diff --git a/src/libs/KeyboardShortcut/keyboard.native.js b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.js similarity index 58% rename from src/libs/KeyboardShortcut/keyboard.native.js rename to src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.js index f0a43c400cb1..de59c819c504 100644 --- a/src/libs/KeyboardShortcut/keyboard.native.js +++ b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.js @@ -1,28 +1,5 @@ import _ from 'underscore'; -import * as KeyCommand from 'react-native-key-command'; - -/** - * Gets modifiers from a keyboard event. - * - * @param {Event} event - * @returns {Array} - */ -function getKeyEventModifiers(event) { - if (event.modifierFlags === KeyCommand.constants.keyModifierControl) { - return ['CONTROL']; - } - if (event.modifierFlags === KeyCommand.constants.keyModifierCommand) { - return ['META']; - } - if (event.modifierFlags === KeyCommand.constants.keyModifierShiftControl) { - return ['SHIFT', 'CONTROL']; - } - if (event.modifierFlags === KeyCommand.constants.keyModifierShiftCommand) { - return ['META', 'CONTROL']; - } - - return []; -} +import getKeyEventModifiers from '../getKeyEventModifiers'; /** * Checks if an event for that key is configured and if so, runs it. @@ -53,7 +30,4 @@ function bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEven }); } -export { - getKeyEventModifiers, - bindHandlerToKeydownEvent, -}; +export default bindHandlerToKeydownEvent; diff --git a/src/libs/KeyboardShortcut/getKeyEventModifiers.js b/src/libs/KeyboardShortcut/getKeyEventModifiers.js new file mode 100644 index 000000000000..9d3e5defce84 --- /dev/null +++ b/src/libs/KeyboardShortcut/getKeyEventModifiers.js @@ -0,0 +1,26 @@ +import * as KeyCommand from 'react-native-key-command'; + +/** + * Gets modifiers from a keyboard event. + * + * @param {Event} event + * @returns {Array} + */ +function getKeyEventModifiers(event) { + if (event.modifierFlags === KeyCommand.constants.keyModifierControl) { + return ['CONTROL']; + } + if (event.modifierFlags === KeyCommand.constants.keyModifierCommand) { + return ['META']; + } + if (event.modifierFlags === KeyCommand.constants.keyModifierShiftControl) { + return ['SHIFT', 'CONTROL']; + } + if (event.modifierFlags === KeyCommand.constants.keyModifierShiftCommand) { + return ['META', 'CONTROL']; + } + + return []; +} + +export default getKeyEventModifiers; diff --git a/src/libs/KeyboardShortcut/index.js b/src/libs/KeyboardShortcut/index.js index 943ca551e0db..0931e383250d 100644 --- a/src/libs/KeyboardShortcut/index.js +++ b/src/libs/KeyboardShortcut/index.js @@ -2,7 +2,7 @@ import _ from 'underscore'; import lodashGet from 'lodash/get'; import Str from 'expensify-common/lib/str'; import * as KeyCommand from 'react-native-key-command'; -import * as Keyboard from './keyboard.native'; +import bindHandlerToKeydownEvent from './bindHandlerToKeydownEvent'; import getOperatingSystem from '../getOperatingSystem'; import CONST from '../../CONST'; @@ -29,7 +29,16 @@ function getDocumentedShortcuts() { * @returns {String} */ function getDisplayName(key, modifiers) { - let displayName = [key.toUpperCase()]; + let displayName = (() => { + if (key === KeyCommand.constants.keyInputEnter) { + return ['ENTER']; + } + if (key === KeyCommand.constants.keyInputEscape) { + return ['ESCAPE']; + } + return [key.toUpperCase()]; + })(); + if (_.isString(modifiers)) { displayName.unshift(modifiers); } else if (_.isArray(modifiers)) { @@ -44,7 +53,7 @@ function getDisplayName(key, modifiers) { _.each(CONST.KEYBOARD_SHORTCUTS, (shortcut) => { KeyCommand.addListener( shortcut.trigger[operatingSystem] || shortcut.trigger.DEFAULT, - (keycommandEvent, event) => Keyboard.bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEvent, event), + (keycommandEvent, event) => bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEvent, event), ); }); From cc1122620d168575ef0551f2b9194c0d4ef77dad Mon Sep 17 00:00:00 2001 From: azimgd Date: Mon, 6 Feb 2023 21:45:06 +0500 Subject: [PATCH 05/38] bump keycommand package --- ios/Podfile.lock | 4 ++-- package-lock.json | 14 +++++++------- package.json | 2 +- src/libs/KeyboardShortcut/getKeyEventModifiers.js | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index a01518056f5c..f1cdd24809d7 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -474,7 +474,7 @@ PODS: - React - react-native-image-picker (5.0.1): - React-Core - - react-native-key-command (0.5.0): + - react-native-key-command (0.6.0): - React-Core - react-native-netinfo (8.3.1): - React-Core @@ -998,7 +998,7 @@ SPEC CHECKSUMS: react-native-flipper: dc5290261fbeeb2faec1bdc57ae6dd8d562e1de4 react-native-image-manipulator: c48f64221cfcd46e9eec53619c4c0374f3328a56 react-native-image-picker: 8cb4280e2c1efc3daeb2d9d597f9429a60472e40 - react-native-key-command: bdc18250128146769441ddc8f77e4bc9e625bde1 + react-native-key-command: 4e6264bd9bb31d7d1453e1306553300f5c5411e4 react-native-netinfo: 1a6035d3b9780221d407c277ebfb5722ace00658 react-native-pdf: 33c622cbdf776a649929e8b9d1ce2d313347c4fa react-native-performance: 224bd53e6a835fda4353302cf891d088a0af7406 diff --git a/package-lock.json b/package-lock.json index 098e53ad2501..7d4f860c6686 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,7 +68,7 @@ "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^5.0.1", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972", - "react-native-key-command": "^0.5.0", + "react-native-key-command": "^0.6.0", "react-native-modal": "^13.0.0", "react-native-onyx": "1.0.36", "react-native-pdf": "^6.6.2", @@ -35617,9 +35617,9 @@ "license": "MIT" }, "node_modules/react-native-key-command": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.5.0.tgz", - "integrity": "sha512-FPpTrcSl/+D/yPmvSUvLFqMvqZ/wkgGNttfIbs4kRna0xAA0Wzg3JBs3N6ofLORxlT4gJFL9sRAkCEqzB50Faw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.6.0.tgz", + "integrity": "sha512-hQxg8odkiL5B/W/vMRe6Za6Q22b84Mqs6Bn0zURLnUExtWdCywzj2dKpCmT7B0yKixjHo7NEf3pWKTYgxj5NYw==", "dependencies": { "events": "^3.3.0", "underscore": "^1.13.4" @@ -70070,9 +70070,9 @@ "from": "react-native-image-size@git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972" }, "react-native-key-command": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.5.0.tgz", - "integrity": "sha512-FPpTrcSl/+D/yPmvSUvLFqMvqZ/wkgGNttfIbs4kRna0xAA0Wzg3JBs3N6ofLORxlT4gJFL9sRAkCEqzB50Faw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.6.0.tgz", + "integrity": "sha512-hQxg8odkiL5B/W/vMRe6Za6Q22b84Mqs6Bn0zURLnUExtWdCywzj2dKpCmT7B0yKixjHo7NEf3pWKTYgxj5NYw==", "requires": { "events": "^3.3.0", "underscore": "^1.13.4" diff --git a/package.json b/package.json index c3941def6fe9..f91a4c2609f7 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^5.0.1", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972", - "react-native-key-command": "^0.5.0", + "react-native-key-command": "^0.6.0", "react-native-modal": "^13.0.0", "react-native-onyx": "1.0.36", "react-native-pdf": "^6.6.2", diff --git a/src/libs/KeyboardShortcut/getKeyEventModifiers.js b/src/libs/KeyboardShortcut/getKeyEventModifiers.js index 9d3e5defce84..cf96348b4490 100644 --- a/src/libs/KeyboardShortcut/getKeyEventModifiers.js +++ b/src/libs/KeyboardShortcut/getKeyEventModifiers.js @@ -14,10 +14,10 @@ function getKeyEventModifiers(event) { return ['META']; } if (event.modifierFlags === KeyCommand.constants.keyModifierShiftControl) { - return ['SHIFT', 'CONTROL']; + return ['CMD', 'Shift']; } if (event.modifierFlags === KeyCommand.constants.keyModifierShiftCommand) { - return ['META', 'CONTROL']; + return ['CMD', 'Shift']; } return []; From d073edde7d6f54a38905859c5e702062fdb919ed Mon Sep 17 00:00:00 2001 From: azimgd Date: Mon, 6 Feb 2023 22:04:12 +0500 Subject: [PATCH 06/38] register arrow keys --- src/libs/KeyboardShortcut/index.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libs/KeyboardShortcut/index.js b/src/libs/KeyboardShortcut/index.js index 0931e383250d..4f8e1ba60491 100644 --- a/src/libs/KeyboardShortcut/index.js +++ b/src/libs/KeyboardShortcut/index.js @@ -36,6 +36,12 @@ function getDisplayName(key, modifiers) { if (key === KeyCommand.constants.keyInputEscape) { return ['ESCAPE']; } + if (key === KeyCommand.constants.keyInputUpArrow) { + return ['ARROWUP']; + } + if (key === KeyCommand.constants.keyInputDownArrow) { + return ['ARROWDOWN']; + } return [key.toUpperCase()]; })(); From 24c461be3b5d7c15b7df6e2bf2a7a7c2a566857b Mon Sep 17 00:00:00 2001 From: azimgd Date: Mon, 6 Feb 2023 23:17:49 +0500 Subject: [PATCH 07/38] update keycommand import order --- src/CONST.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CONST.js b/src/CONST.js index 7bb35796cfa1..98bcd9c2a0e6 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -1,7 +1,7 @@ import lodashGet from 'lodash/get'; import Config from 'react-native-config'; -import * as Url from './libs/Url'; import * as KeyCommand from 'react-native-key-command'; +import * as Url from './libs/Url'; const CLOUDFRONT_URL = 'https://d2k5nsl2zxldvw.cloudfront.net'; const ACTIVE_EXPENSIFY_URL = Url.addTrailingForwardSlash(lodashGet(Config, 'NEW_EXPENSIFY_URL', 'https://new.expensify.com')); From 4e47695c09be59fbf058826ea343f54567ba14ca Mon Sep 17 00:00:00 2001 From: azimgd Date: Mon, 6 Feb 2023 23:41:18 +0500 Subject: [PATCH 08/38] adjust non apple environment shortcuts --- src/libs/KeyboardShortcut/getKeyEventModifiers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/KeyboardShortcut/getKeyEventModifiers.js b/src/libs/KeyboardShortcut/getKeyEventModifiers.js index cf96348b4490..2d0839d2c35d 100644 --- a/src/libs/KeyboardShortcut/getKeyEventModifiers.js +++ b/src/libs/KeyboardShortcut/getKeyEventModifiers.js @@ -14,10 +14,10 @@ function getKeyEventModifiers(event) { return ['META']; } if (event.modifierFlags === KeyCommand.constants.keyModifierShiftControl) { - return ['CMD', 'Shift']; + return ['CONTROL', 'Shift']; } if (event.modifierFlags === KeyCommand.constants.keyModifierShiftCommand) { - return ['CMD', 'Shift']; + return ['META', 'Shift']; } return []; From bafa42aeec1886b65da893d6ff8c6ca7c54dbe46 Mon Sep 17 00:00:00 2001 From: azimgd Date: Tue, 7 Feb 2023 02:03:49 +0500 Subject: [PATCH 09/38] package version bump --- ios/Podfile.lock | 4 ++-- package-lock.json | 14 +++++++------- package.json | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index f1cdd24809d7..d2f76248f41b 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -474,7 +474,7 @@ PODS: - React - react-native-image-picker (5.0.1): - React-Core - - react-native-key-command (0.6.0): + - react-native-key-command (0.7.0): - React-Core - react-native-netinfo (8.3.1): - React-Core @@ -998,7 +998,7 @@ SPEC CHECKSUMS: react-native-flipper: dc5290261fbeeb2faec1bdc57ae6dd8d562e1de4 react-native-image-manipulator: c48f64221cfcd46e9eec53619c4c0374f3328a56 react-native-image-picker: 8cb4280e2c1efc3daeb2d9d597f9429a60472e40 - react-native-key-command: 4e6264bd9bb31d7d1453e1306553300f5c5411e4 + react-native-key-command: bfa17378a6c49090b83e904ddcfc9ffb261448b2 react-native-netinfo: 1a6035d3b9780221d407c277ebfb5722ace00658 react-native-pdf: 33c622cbdf776a649929e8b9d1ce2d313347c4fa react-native-performance: 224bd53e6a835fda4353302cf891d088a0af7406 diff --git a/package-lock.json b/package-lock.json index 129cef2bca67..aed7a5f13270 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,7 +68,7 @@ "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^5.0.1", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972", - "react-native-key-command": "^0.6.0", + "react-native-key-command": "^0.7.0", "react-native-modal": "^13.0.0", "react-native-onyx": "1.0.36", "react-native-pdf": "^6.6.2", @@ -35617,9 +35617,9 @@ "license": "MIT" }, "node_modules/react-native-key-command": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.6.0.tgz", - "integrity": "sha512-hQxg8odkiL5B/W/vMRe6Za6Q22b84Mqs6Bn0zURLnUExtWdCywzj2dKpCmT7B0yKixjHo7NEf3pWKTYgxj5NYw==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.7.0.tgz", + "integrity": "sha512-iFFXfsyTWJoo3F7A1cy01I66RldcmJOfys1NQQs2EKz9ZVY8LSOmHuJUTqgpPu96bGV4l2fHqyNfI98qc4DMCA==", "dependencies": { "events": "^3.3.0", "underscore": "^1.13.4" @@ -70070,9 +70070,9 @@ "from": "react-native-image-size@git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972" }, "react-native-key-command": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.6.0.tgz", - "integrity": "sha512-hQxg8odkiL5B/W/vMRe6Za6Q22b84Mqs6Bn0zURLnUExtWdCywzj2dKpCmT7B0yKixjHo7NEf3pWKTYgxj5NYw==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.7.0.tgz", + "integrity": "sha512-iFFXfsyTWJoo3F7A1cy01I66RldcmJOfys1NQQs2EKz9ZVY8LSOmHuJUTqgpPu96bGV4l2fHqyNfI98qc4DMCA==", "requires": { "events": "^3.3.0", "underscore": "^1.13.4" diff --git a/package.json b/package.json index f51bb72d9c78..fa7193bbb628 100644 --- a/package.json +++ b/package.json @@ -99,7 +99,7 @@ "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^5.0.1", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972", - "react-native-key-command": "^0.6.0", + "react-native-key-command": "^0.7.0", "react-native-modal": "^13.0.0", "react-native-onyx": "1.0.36", "react-native-pdf": "^6.6.2", From e9f04a15c02f39d5ccfedf7597c3d78fc8bc111a Mon Sep 17 00:00:00 2001 From: azimgd Date: Fri, 10 Feb 2023 01:03:57 +0500 Subject: [PATCH 10/38] CR request, putting back flex:1 on unswipeable modal --- src/styles/getModalStyles/getBaseModalStyles.js | 1 + src/styles/styles.js | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/styles/getModalStyles/getBaseModalStyles.js b/src/styles/getModalStyles/getBaseModalStyles.js index 1e74188db9ef..aea136f6818a 100644 --- a/src/styles/getModalStyles/getBaseModalStyles.js +++ b/src/styles/getModalStyles/getBaseModalStyles.js @@ -107,6 +107,7 @@ export default (type, windowDimensions, popoverAnchorPosition = {}, containerSty shadowOpacity: 0.1, shadowRadius: 5, + flex: 1, marginTop: isSmallScreenWidth ? 0 : 20, marginBottom: isSmallScreenWidth ? 0 : 20, borderRadius: isSmallScreenWidth ? 0 : 12, diff --git a/src/styles/styles.js b/src/styles/styles.js index 7d8fcbab016f..ba2a4638b1de 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -2673,6 +2673,9 @@ const styles = { keyboardShortcutModalContainer: { maxHeight: '100%', + flexShrink: 0, + flexGrow: 0, + flexBasis: 'auto', }, keyboardShortcutTableWrapper: { From f67f793f09d36bc79ae5f81c0258fcfc1ff3deab Mon Sep 17 00:00:00 2001 From: azimgd Date: Fri, 10 Feb 2023 01:58:49 +0500 Subject: [PATCH 11/38] fix shortcut comparison operator --- src/libs/KeyboardShortcut/index.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libs/KeyboardShortcut/index.js b/src/libs/KeyboardShortcut/index.js index 4f8e1ba60491..beed3518a698 100644 --- a/src/libs/KeyboardShortcut/index.js +++ b/src/libs/KeyboardShortcut/index.js @@ -30,16 +30,17 @@ function getDocumentedShortcuts() { */ function getDisplayName(key, modifiers) { let displayName = (() => { - if (key === KeyCommand.constants.keyInputEnter) { + // typeof key -> string, typeof KeyCommand.constants.* -> number | string + if (_.isEqual(key, KeyCommand.constants.keyInputEnter.toString())) { return ['ENTER']; } - if (key === KeyCommand.constants.keyInputEscape) { + if (_.isEqual(key, KeyCommand.constants.keyInputEscape.toString())) { return ['ESCAPE']; } - if (key === KeyCommand.constants.keyInputUpArrow) { + if (_.isEqual(key, KeyCommand.constants.keyInputUpArrow.toString())) { return ['ARROWUP']; } - if (key === KeyCommand.constants.keyInputDownArrow) { + if (_.isEqual(key, KeyCommand.constants.keyInputDownArrow.toString())) { return ['ARROWDOWN']; } return [key.toUpperCase()]; From 3c2242ed49868fa5a577bdfb16150fd87bbd10a7 Mon Sep 17 00:00:00 2001 From: azimgd Date: Fri, 10 Feb 2023 02:30:08 +0500 Subject: [PATCH 12/38] enable aboutPage.viewKeyboardShortcuts link on native --- src/pages/settings/AboutPage/AboutPage.js | 10 ++++++---- .../getPlatformSpecificMenuItems/index.js | 15 --------------- .../getPlatformSpecificMenuItems/index.native.js | 1 - 3 files changed, 6 insertions(+), 20 deletions(-) delete mode 100644 src/pages/settings/AboutPage/getPlatformSpecificMenuItems/index.js delete mode 100644 src/pages/settings/AboutPage/getPlatformSpecificMenuItems/index.native.js diff --git a/src/pages/settings/AboutPage/AboutPage.js b/src/pages/settings/AboutPage/AboutPage.js index a9a809c6d0a2..317c7169a503 100644 --- a/src/pages/settings/AboutPage/AboutPage.js +++ b/src/pages/settings/AboutPage/AboutPage.js @@ -17,8 +17,8 @@ import Logo from '../../../../assets/images/new-expensify.svg'; import pkg from '../../../../package.json'; import * as Report from '../../../libs/actions/Report'; import * as Link from '../../../libs/actions/Link'; -import getPlatformSpecificMenuItems from './getPlatformSpecificMenuItems'; import compose from '../../../libs/compose'; +import * as KeyboardShortcuts from '../../../libs/actions/KeyboardShortcuts'; const propTypes = { ...withLocalizePropTypes, @@ -26,8 +26,6 @@ const propTypes = { }; const AboutPage = (props) => { - const platformSpecificMenuItems = getPlatformSpecificMenuItems(props.isSmallScreenWidth); - const menuItems = [ { translationKey: 'initialSettingsPage.aboutPage.appDownloadLinks', @@ -36,7 +34,11 @@ const AboutPage = (props) => { Navigation.navigate(ROUTES.SETTINGS_APP_DOWNLOAD_LINKS); }, }, - ...platformSpecificMenuItems, + { + translationKey: 'initialSettingsPage.aboutPage.viewKeyboardShortcuts', + icon: Expensicons.Keyboard, + action: KeyboardShortcuts.showKeyboardShortcutModal, + }, { translationKey: 'initialSettingsPage.aboutPage.viewTheCode', icon: Expensicons.Eye, diff --git a/src/pages/settings/AboutPage/getPlatformSpecificMenuItems/index.js b/src/pages/settings/AboutPage/getPlatformSpecificMenuItems/index.js deleted file mode 100644 index 52f8ffa2250f..000000000000 --- a/src/pages/settings/AboutPage/getPlatformSpecificMenuItems/index.js +++ /dev/null @@ -1,15 +0,0 @@ -import * as KeyboardShortcuts from '../../../../libs/actions/KeyboardShortcuts'; -import * as Expensicons from '../../../../components/Icon/Expensicons'; - -export default (isSmallScreenWidth) => { - if (isSmallScreenWidth) { - return []; - } - return [ - { - translationKey: 'initialSettingsPage.aboutPage.viewKeyboardShortcuts', - icon: Expensicons.Keyboard, - action: KeyboardShortcuts.showKeyboardShortcutModal, - }, - ]; -}; diff --git a/src/pages/settings/AboutPage/getPlatformSpecificMenuItems/index.native.js b/src/pages/settings/AboutPage/getPlatformSpecificMenuItems/index.native.js deleted file mode 100644 index 4ba9480748fc..000000000000 --- a/src/pages/settings/AboutPage/getPlatformSpecificMenuItems/index.native.js +++ /dev/null @@ -1 +0,0 @@ -export default () => []; From c5f466ca0ebc8352714bad142c164db807f0ee55 Mon Sep 17 00:00:00 2001 From: azimgd Date: Fri, 10 Feb 2023 02:42:11 +0500 Subject: [PATCH 13/38] cr comment Co-authored-by: Rajat Parashar --- src/libs/KeyboardShortcut/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/KeyboardShortcut/index.js b/src/libs/KeyboardShortcut/index.js index beed3518a698..f095f4ab8d11 100644 --- a/src/libs/KeyboardShortcut/index.js +++ b/src/libs/KeyboardShortcut/index.js @@ -30,7 +30,7 @@ function getDocumentedShortcuts() { */ function getDisplayName(key, modifiers) { let displayName = (() => { - // typeof key -> string, typeof KeyCommand.constants.* -> number | string + // Type of key is string and the type of KeyCommand.constants.* is number | string. Use _.isEqual to match different types. if (_.isEqual(key, KeyCommand.constants.keyInputEnter.toString())) { return ['ENTER']; } From f2a9ed9735d9b0c14d6f6ce8c6e560c53cd97b45 Mon Sep 17 00:00:00 2001 From: azimgd Date: Sun, 12 Feb 2023 20:06:08 +0500 Subject: [PATCH 14/38] keycommand library mock --- __mocks__/react-native-key-command.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 __mocks__/react-native-key-command.js diff --git a/__mocks__/react-native-key-command.js b/__mocks__/react-native-key-command.js new file mode 100644 index 000000000000..092ab120a142 --- /dev/null +++ b/__mocks__/react-native-key-command.js @@ -0,0 +1,13 @@ +const registerKeyCommands = () => {}; +const unregisterKeyCommands = () => {}; +const constants = {}; +const eventEmitter = () => {}; +const addListener = () => {}; + +export { + registerKeyCommands, + unregisterKeyCommands, + constants, + eventEmitter, + addListener, +}; From 10a080eab1c68bdebdfe0d8bc3b777b892cb21c2 Mon Sep 17 00:00:00 2001 From: azimgd Date: Wed, 1 Mar 2023 13:28:04 +0500 Subject: [PATCH 15/38] handle longpress events on some android devices --- .../java/com/expensify/chat/MainActivity.java | 12 +++++++ src/components/{Button.js => Button/index.js} | 31 ++++++++++--------- .../Button/validateSubmitShortcut/index.js | 10 ++++++ .../validateSubmitShortcut/index.native.js | 9 ++++++ 4 files changed, 47 insertions(+), 15 deletions(-) rename src/components/{Button.js => Button/index.js} (93%) create mode 100644 src/components/Button/validateSubmitShortcut/index.js create mode 100644 src/components/Button/validateSubmitShortcut/index.native.js diff --git a/android/app/src/main/java/com/expensify/chat/MainActivity.java b/android/app/src/main/java/com/expensify/chat/MainActivity.java index 42966aab23ad..a4de1361ccfa 100644 --- a/android/app/src/main/java/com/expensify/chat/MainActivity.java +++ b/android/app/src/main/java/com/expensify/chat/MainActivity.java @@ -69,4 +69,16 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event); return super.onKeyDown(keyCode, event); } + + @Override + public boolean onKeyLongPress(int keyCode, KeyEvent event) { + KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event); + return super.onKeyLongPress(keyCode, event); + } + + @Override + public boolean onKeyUp(int keyCode, KeyEvent event) { + KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event); + return super.onKeyUp(keyCode, event); + } } diff --git a/src/components/Button.js b/src/components/Button/index.js similarity index 93% rename from src/components/Button.js rename to src/components/Button/index.js index 5a8236e675d0..70431e6c9cf5 100644 --- a/src/components/Button.js +++ b/src/components/Button/index.js @@ -1,19 +1,20 @@ import React, {Component} from 'react'; import {Pressable, ActivityIndicator, View} from 'react-native'; import PropTypes from 'prop-types'; -import styles from '../styles/styles'; -import themeColors from '../styles/themes/default'; -import OpacityView from './OpacityView'; -import Text from './Text'; -import KeyboardShortcut from '../libs/KeyboardShortcut'; -import Icon from './Icon'; -import CONST from '../CONST'; -import * as StyleUtils from '../styles/StyleUtils'; -import HapticFeedback from '../libs/HapticFeedback'; -import withNavigationFallback from './withNavigationFallback'; -import compose from '../libs/compose'; -import * as Expensicons from './Icon/Expensicons'; -import withNavigationFocus from './withNavigationFocus'; +import styles from '../../styles/styles'; +import themeColors from '../../styles/themes/default'; +import OpacityView from '../OpacityView'; +import Text from '../Text'; +import KeyboardShortcut from '../../libs/KeyboardShortcut'; +import Icon from '../Icon'; +import CONST from '../../CONST'; +import * as StyleUtils from '../../styles/StyleUtils'; +import HapticFeedback from '../../libs/HapticFeedback'; +import withNavigationFallback from '../withNavigationFallback'; +import compose from '../../libs/compose'; +import * as Expensicons from '../Icon/Expensicons'; +import withNavigationFocus from '../withNavigationFocus'; +import validateSubmitShortcut from './validateSubmitShortcut'; const propTypes = { /** The text for the button label */ @@ -157,10 +158,10 @@ class Button extends Component { // Setup and attach keypress handler for pressing the button with Enter key this.unsubscribe = KeyboardShortcut.subscribe(shortcutConfig.shortcutKey, (e) => { - if (!this.props.isFocused || this.props.isDisabled || this.props.isLoading || (e && e.target.nodeName === 'TEXTAREA')) { + if (!validateSubmitShortcut(this.props.isFocused, this.props.isDisabled, this.props.isLoading, e)) { return; } - e.preventDefault(); + this.props.onPress(); }, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true, false, this.props.enterKeyEventListenerPriority, false); } diff --git a/src/components/Button/validateSubmitShortcut/index.js b/src/components/Button/validateSubmitShortcut/index.js new file mode 100644 index 000000000000..6a48fc32c89d --- /dev/null +++ b/src/components/Button/validateSubmitShortcut/index.js @@ -0,0 +1,10 @@ +function validateSubmitShortcut(isFocused, isDisabled, isLoading, event) { + if (!isFocused || isDisabled || isLoading || (event && event.target.nodeName === 'TEXTAREA')) { + return false; + } + + event.preventDefault(); + return true; +} + +export default validateSubmitShortcut; diff --git a/src/components/Button/validateSubmitShortcut/index.native.js b/src/components/Button/validateSubmitShortcut/index.native.js new file mode 100644 index 000000000000..60b9243b1181 --- /dev/null +++ b/src/components/Button/validateSubmitShortcut/index.native.js @@ -0,0 +1,9 @@ +function validateSubmitShortcut(isFocused, isDisabled, isLoading) { + if (!isFocused || isDisabled || isLoading) { + return false; + } + + return true; +} + +export default validateSubmitShortcut; From db23ea51c0251cc0762940380219714953b6b620 Mon Sep 17 00:00:00 2001 From: azimgd Date: Wed, 1 Mar 2023 13:51:58 +0500 Subject: [PATCH 16/38] update function comments --- src/components/Button/validateSubmitShortcut/index.js | 9 +++++++++ .../Button/validateSubmitShortcut/index.native.js | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/src/components/Button/validateSubmitShortcut/index.js b/src/components/Button/validateSubmitShortcut/index.js index 6a48fc32c89d..bfe5c79483fa 100644 --- a/src/components/Button/validateSubmitShortcut/index.js +++ b/src/components/Button/validateSubmitShortcut/index.js @@ -1,3 +1,12 @@ +/** + * Validate if the submit shortcut should be triggered depending on the button state + * + * @param {boolean} isFocused Whether Button is on active screen + * @param {boolean} isDisabled Indicates whether the button should be disabled + * @param {boolean} isLoading Indicates whether the button should be disabled and in the loading state + * @param {Object} event Focused input event + * @returns {boolean} Returns `true` if the shortcut should be triggered + */ function validateSubmitShortcut(isFocused, isDisabled, isLoading, event) { if (!isFocused || isDisabled || isLoading || (event && event.target.nodeName === 'TEXTAREA')) { return false; diff --git a/src/components/Button/validateSubmitShortcut/index.native.js b/src/components/Button/validateSubmitShortcut/index.native.js index 60b9243b1181..2822fa56d590 100644 --- a/src/components/Button/validateSubmitShortcut/index.native.js +++ b/src/components/Button/validateSubmitShortcut/index.native.js @@ -1,3 +1,11 @@ +/** + * Validate if the submit shortcut should be triggered depending on the button state + * + * @param {boolean} isFocused Whether Button is on active screen + * @param {boolean} isDisabled Indicates whether the button should be disabled + * @param {boolean} isLoading Indicates whether the button should be disabled and in the loading state + * @returns {boolean} Returns `true` if the shortcut should be triggered + */ function validateSubmitShortcut(isFocused, isDisabled, isLoading) { if (!isFocused || isDisabled || isLoading) { return false; From 6bf85eac94d25f6fc57631b4bf54d75a806883f9 Mon Sep 17 00:00:00 2001 From: azimgd Date: Thu, 2 Mar 2023 16:48:42 +0500 Subject: [PATCH 17/38] fix ESC button interference with default RN instance by disabling ESC event propagation --- .../java/com/expensify/chat/MainActivity.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/MainActivity.java b/android/app/src/main/java/com/expensify/chat/MainActivity.java index a4de1361ccfa..478cce4d529a 100644 --- a/android/app/src/main/java/com/expensify/chat/MainActivity.java +++ b/android/app/src/main/java/com/expensify/chat/MainActivity.java @@ -66,19 +66,25 @@ protected void onCreate(Bundle savedInstanceState) { */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { + // disabling hardware ESCAPE support which is handled by Android + if (keyCode == 111) { return false; } KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event); return super.onKeyDown(keyCode, event); } @Override - public boolean onKeyLongPress(int keyCode, KeyEvent event) { - KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event); - return super.onKeyLongPress(keyCode, event); + public boolean onKeyLongPress(int keyCode, KeyEvent event) { + // disabling hardware ESCAPE support which is handled by Android + if (keyCode == 111) { return false; } + KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event); + return super.onKeyLongPress(keyCode, event); } @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event); - return super.onKeyUp(keyCode, event); + public boolean onKeyUp(int keyCode, KeyEvent event) { + // disabling hardware ESCAPE support which is handled by Android + if (keyCode == 111) { return false; } + KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event); + return super.onKeyUp(keyCode, event); } } From 64c0843e57b4eb9955e00bcd1e557ad178008f30 Mon Sep 17 00:00:00 2001 From: azimgd Date: Thu, 2 Mar 2023 17:41:38 +0500 Subject: [PATCH 18/38] move escape disable into const --- .../app/src/main/java/com/expensify/chat/MainActivity.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/android/app/src/main/java/com/expensify/chat/MainActivity.java b/android/app/src/main/java/com/expensify/chat/MainActivity.java index 478cce4d529a..a3861d191de7 100644 --- a/android/app/src/main/java/com/expensify/chat/MainActivity.java +++ b/android/app/src/main/java/com/expensify/chat/MainActivity.java @@ -67,7 +67,7 @@ protected void onCreate(Bundle savedInstanceState) { @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // disabling hardware ESCAPE support which is handled by Android - if (keyCode == 111) { return false; } + if (event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE) { return false; } KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event); return super.onKeyDown(keyCode, event); } @@ -75,7 +75,7 @@ public boolean onKeyDown(int keyCode, KeyEvent event) { @Override public boolean onKeyLongPress(int keyCode, KeyEvent event) { // disabling hardware ESCAPE support which is handled by Android - if (keyCode == 111) { return false; } + if (event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE) { return false; } KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event); return super.onKeyLongPress(keyCode, event); } @@ -83,7 +83,7 @@ public boolean onKeyLongPress(int keyCode, KeyEvent event) { @Override public boolean onKeyUp(int keyCode, KeyEvent event) { // disabling hardware ESCAPE support which is handled by Android - if (keyCode == 111) { return false; } + if (event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE) { return false; } KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event); return super.onKeyUp(keyCode, event); } From 1f90cc31ed10c52dba5a89b459146133235f2c41 Mon Sep 17 00:00:00 2001 From: azimgd Date: Tue, 7 Mar 2023 19:51:34 +0500 Subject: [PATCH 19/38] merge commit --- android/app/build.gradle | 4 +- assets/emojis.js | 17 +++++++ ios/NewExpensify/Info.plist | 4 +- ios/NewExpensifyTests/Info.plist | 4 +- package-lock.json | 4 +- package.json | 2 +- src/CONST.js | 3 +- src/components/ArchivedReportFooter.js | 6 +++ .../EmojiPicker/CategoryShortcutBar.js | 51 +++++++------------ .../EmojiPicker/CategoryShortcutButton.js | 19 +++++-- .../EmojiPicker/EmojiPickerMenu/index.js | 9 ++-- .../EmojiPickerMenu/index.native.js | 9 ++-- src/components/LocalePicker.js | 2 +- src/libs/EmojiUtils.js | 12 +++-- src/libs/OptionsListUtils.js | 10 ++-- src/pages/home/ReportScreen.js | 4 +- src/pages/home/report/ReportActionCompose.js | 21 ++++---- .../report/ReportActionItemMessageEdit.js | 2 +- src/pages/home/report/ReportActionsView.js | 26 ++++------ src/pages/home/report/ReportFooter.js | 14 ++--- src/styles/styles.js | 6 +-- tests/unit/OptionsListUtilsTest.js | 11 ++++ 22 files changed, 134 insertions(+), 106 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 0f0cc258c8ea..4f75e9e40482 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -156,8 +156,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001027800 - versionName "1.2.78-0" + versionCode 1001027900 + versionName "1.2.79-0" buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString() if (isNewArchitectureEnabled()) { diff --git a/assets/emojis.js b/assets/emojis.js index cf3270a78fe4..880cf7e32389 100644 --- a/assets/emojis.js +++ b/assets/emojis.js @@ -1,3 +1,12 @@ +import Smiley from './images/emoji.svg'; +import AnimalsAndNature from './images/emojiCategoryIcons/plant.svg'; +import FoodAndDrink from './images/emojiCategoryIcons/hamburger.svg'; +import TravelAndPlaces from './images/emojiCategoryIcons/plane.svg'; +import Activities from './images/emojiCategoryIcons/soccer-ball.svg'; +import Objects from './images/emojiCategoryIcons/light-bulb.svg'; +import Symbols from './images/emojiCategoryIcons/peace-sign.svg'; +import Flags from './images/emojiCategoryIcons/flag.svg'; + /* * This list is generated from the code here https://github.com/github/gemoji/blob/master/db/emoji.json * Each code is then converted to hex by replacing the "U+" with "0x" @@ -68,6 +77,7 @@ const emojis = [ { code: 'smileysAndEmotion', header: true, + icon: Smiley, }, { name: 'grinning', @@ -6965,6 +6975,7 @@ const emojis = [ { code: 'animalsAndNature', header: true, + icon: AnimalsAndNature, }, { name: 'monkey_face', @@ -8138,6 +8149,7 @@ const emojis = [ { code: 'foodAndDrink', header: true, + icon: FoodAndDrink, }, { name: 'grapes', @@ -9315,6 +9327,7 @@ const emojis = [ { code: 'travelAndPlaces', header: true, + icon: TravelAndPlaces, }, { name: 'earth_africa', @@ -11434,6 +11447,7 @@ const emojis = [ { code: 'activities', header: true, + icon: Activities, }, { name: 'jack_o_lantern', @@ -12271,6 +12285,7 @@ const emojis = [ { code: 'objects', header: true, + icon: Objects, }, { name: 'eyeglasses', @@ -14600,6 +14615,7 @@ const emojis = [ { code: 'symbols', header: true, + icon: Symbols, }, { name: 'atm', @@ -16590,6 +16606,7 @@ const emojis = [ { code: 'flags', header: true, + icon: Flags, }, { name: 'checkered_flag', diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index d427cc8a061c..eaf92163a1b9 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.2.78 + 1.2.79 CFBundleSignature ???? CFBundleURLTypes @@ -30,7 +30,7 @@ CFBundleVersion - 1.2.78.0 + 1.2.79.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 99534496e50d..10f4523c5a68 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.2.78 + 1.2.79 CFBundleSignature ???? CFBundleVersion - 1.2.78.0 + 1.2.79.0 diff --git a/package-lock.json b/package-lock.json index 3b165b9bf74c..44da12af07de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.2.78-0", + "version": "1.2.79-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.2.78-0", + "version": "1.2.79-0", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 0b7e21a7e76b..36ad340ffb90 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.2.78-0", + "version": "1.2.79-0", "author": "Expensify, Inc.", "homepage": "https://new.expensify.com", "description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.", diff --git a/src/CONST.js b/src/CONST.js index 98111be2a9b8..48af5d7164c4 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -835,7 +835,7 @@ const CONST = { US_PHONE_WITH_OPTIONAL_COUNTRY_CODE: /^(\+1)?\d{10}$/, DIGITS_AND_PLUS: /^\+?[0-9]*$/, PHONE_E164_PLUS: /^\+?[1-9]\d{1,14}$/, - PHONE_WITH_SPECIAL_CHARS: /^[+]*[(]{0,1}[0-9]{1,3}[)]{0,1}[-\s\\./0-9]{0,12}$/, + PHONE_WITH_SPECIAL_CHARS: /^\s*(?:\+?(\d{1,3}))?[-. (]*(\d{3})[-. )]*(\d{3})[-. ]*(\d{4})(?: *x(\d+))?\s*$/, ALPHABETIC_CHARS: /[a-zA-Z]+/, POSITIVE_INTEGER: /^\d+$/, NON_ALPHA_NUMERIC: /[^A-Za-z0-9+]/g, @@ -858,6 +858,7 @@ const CONST = { EMOJIS: /[\p{Extended_Pictographic}\u200d\u{1f1e6}-\u{1f1ff}\u{1f3fb}-\u{1f3ff}\u{e0020}-\u{e007f}\u20E3\uFE0F]|[#*0-9]\uFE0F?\u20E3/gu, TAX_ID: /^\d{9}$/, NON_NUMERIC: /\D/g, + NON_NUMERIC_WITH_PLUS: /[^0-9+]/g, EMOJI_NAME: /:[\w+-]+:/g, EMOJI_SUGGESTIONS: /:[a-zA-Z0-9_+-]{1,40}$/, AFTER_FIRST_LINE_BREAK: /\n.*/g, diff --git a/src/components/ArchivedReportFooter.js b/src/components/ArchivedReportFooter.js index bd795f8db476..44dd223e8bbc 100644 --- a/src/components/ArchivedReportFooter.js +++ b/src/components/ArchivedReportFooter.js @@ -10,6 +10,7 @@ import personalDetailsPropType from '../pages/personalDetailsPropType'; import ONYXKEYS from '../ONYXKEYS'; import * as ReportUtils from '../libs/ReportUtils'; import reportPropTypes from '../pages/reportPropTypes'; +import * as ReportActionsUtils from '../libs/ReportActionsUtils'; import styles from '../styles/styles'; const propTypes = { @@ -90,5 +91,10 @@ export default compose( policies: { key: ONYXKEYS.COLLECTION.POLICY, }, + reportClosedAction: { + key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`, + canEvict: false, + selector: ReportActionsUtils.getLastClosedReportAction, + }, }), )(ArchivedReportFooter); diff --git a/src/components/EmojiPicker/CategoryShortcutBar.js b/src/components/EmojiPicker/CategoryShortcutBar.js index abab8400ad06..8a6ef79f5044 100644 --- a/src/components/EmojiPicker/CategoryShortcutBar.js +++ b/src/components/EmojiPicker/CategoryShortcutBar.js @@ -3,48 +3,33 @@ import PropTypes from 'prop-types'; import {View} from 'react-native'; import _ from 'underscore'; import styles from '../../styles/styles'; -import FrequentlyUsed from '../../../assets/images/history.svg'; -import Smiley from '../../../assets/images/emoji.svg'; -import AnimalsAndNature from '../../../assets/images/emojiCategoryIcons/plant.svg'; -import FoodAndDrink from '../../../assets/images/emojiCategoryIcons/hamburger.svg'; -import TravelAndPlaces from '../../../assets/images/emojiCategoryIcons/plane.svg'; -import Activities from '../../../assets/images/emojiCategoryIcons/soccer-ball.svg'; -import Objects from '../../../assets/images/emojiCategoryIcons/light-bulb.svg'; -import Symbols from '../../../assets/images/emojiCategoryIcons/peace-sign.svg'; -import Flags from '../../../assets/images/emojiCategoryIcons/flag.svg'; import CategoryShortcutButton from './CategoryShortcutButton'; -import getOperatingSystem from '../../libs/getOperatingSystem'; -import CONST from '../../CONST'; const propTypes = { /** The function to call when an emoji is selected */ onPress: PropTypes.func.isRequired, - /** The indices that the icons should link to */ - headerIndices: PropTypes.arrayOf(PropTypes.number).isRequired, + /** The emojis consisting emoji code and indices that the icons should link to */ + headerEmojis: PropTypes.arrayOf(PropTypes.shape({ + code: PropTypes.string.isRequired, + index: PropTypes.number.isRequired, + icon: PropTypes.func.isRequired, + })).isRequired, }; -const CategoryShortcutBar = (props) => { - const icons = [Smiley, AnimalsAndNature, FoodAndDrink, TravelAndPlaces, Activities, Objects, Symbols, Flags]; +const CategoryShortcutBar = props => ( + + {_.map(props.headerEmojis, (headerEmoji, i) => ( + props.onPress(headerEmoji.index)} + key={`categoryShortcut${i}`} + code={headerEmoji.code} + /> + ))} + +); - // If the user has frequently used emojis, there will be 9 headers, otherwise there will be 8 - // Or for Windows OS there will be 8 headers, otherwise there will be 7 - if (props.headerIndices.length === 9 || (getOperatingSystem() === CONST.OS.WINDOWS && props.headerIndices.length === 8)) { - icons.unshift(FrequentlyUsed); - } - - return ( - - {_.map(props.headerIndices, (headerIndex, i) => ( - props.onPress(headerIndex)} - key={`categoryShortcut${i}`} - /> - ))} - - ); -}; CategoryShortcutBar.propTypes = propTypes; CategoryShortcutBar.displayName = 'CategoryShortcutBar'; diff --git a/src/components/EmojiPicker/CategoryShortcutButton.js b/src/components/EmojiPicker/CategoryShortcutButton.js index 3b5d43f9b10d..2c5f061327ae 100644 --- a/src/components/EmojiPicker/CategoryShortcutButton.js +++ b/src/components/EmojiPicker/CategoryShortcutButton.js @@ -1,7 +1,9 @@ import React, {PureComponent} from 'react'; import PropTypes from 'prop-types'; -import {Pressable, View} from 'react-native'; +import {Pressable} from 'react-native'; import Icon from '../Icon'; +import Tooltip from '../Tooltip'; +import withLocalize, {withLocalizePropTypes} from '../withLocalize'; import variables from '../../styles/variables'; import styles from '../../styles/styles'; import * as StyleUtils from '../../styles/StyleUtils'; @@ -9,11 +11,16 @@ import getButtonState from '../../libs/getButtonState'; import themeColors from '../../styles/themes/default'; const propTypes = { + /** The emoji code of the category header */ + code: PropTypes.string.isRequired, + /** The icon representation of the category that this button links to */ icon: PropTypes.func.isRequired, /** The function to call when an emoji is selected */ onPress: PropTypes.func.isRequired, + + ...withLocalizePropTypes, }; class CategoryShortcutButton extends PureComponent { @@ -36,18 +43,22 @@ class CategoryShortcutButton extends PureComponent { this.state.isHighlighted && styles.emojiItemHighlighted, ])} > - + - + ); } } CategoryShortcutButton.propTypes = propTypes; -export default CategoryShortcutButton; +export default withLocalize(CategoryShortcutButton); diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js index 8c1665a7750b..c8dd15a4d373 100755 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js @@ -64,13 +64,14 @@ class EmojiPickerMenu extends Component { ? EmojiUtils.mergeEmojisWithFrequentlyUsedEmojis(emojis.slice(0, flagHeaderIndex), this.props.frequentlyUsedEmojis) : EmojiUtils.mergeEmojisWithFrequentlyUsedEmojis(emojis, this.props.frequentlyUsedEmojis); - // This is the actual header index starting at the first emoji and counting each one - this.headerIndices = EmojiUtils.getHeaderIndices(this.emojis); + // Get the header emojis along with the code, index and icon. + // index is the actual header index starting at the first emoji and counting each one + this.headerEmojis = EmojiUtils.getHeaderEmojis(this.emojis); // This is the indices of each header's Row // The positions are static, and are calculated as index/numColumns (8 in our case) // This is because each row of 8 emojis counts as one index to the flatlist - this.headerRowIndices = _.map(this.headerIndices, headerIndex => Math.floor(headerIndex / CONST.EMOJI_NUM_PER_ROW)); + this.headerRowIndices = _.map(this.headerEmojis, headerEmoji => Math.floor(headerEmoji.index / CONST.EMOJI_NUM_PER_ROW)); this.filterEmojis = _.debounce(this.filterEmojis.bind(this), 300); this.highlightAdjacentEmoji = this.highlightAdjacentEmoji.bind(this); @@ -491,7 +492,7 @@ class EmojiPickerMenu extends Component { )} {!isFiltered && ( )} diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js index edf383eda1d8..39591b369b14 100644 --- a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js +++ b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js @@ -51,13 +51,14 @@ class EmojiPickerMenu extends Component { this.emojis = EmojiUtils.mergeEmojisWithFrequentlyUsedEmojis(emojis, this.props.frequentlyUsedEmojis); - // This is the actual header index starting at the first emoji and counting each one - this.headerIndices = EmojiUtils.getHeaderIndices(this.emojis); + // Get the header emojis along with the code, index and icon. + // index is the actual header index starting at the first emoji and counting each one + this.headerEmojis = EmojiUtils.getHeaderEmojis(this.emojis); // This is the indices of each header's Row // The positions are static, and are calculated as index/numColumns (8 in our case) // This is because each row of 8 emojis counts as one index to the flatlist - this.headerRowIndices = _.map(this.headerIndices, headerIndex => Math.floor(headerIndex / CONST.EMOJI_NUM_PER_ROW)); + this.headerRowIndices = _.map(this.headerEmojis, headerEmoji => Math.floor(headerEmoji.index / CONST.EMOJI_NUM_PER_ROW)); this.renderItem = this.renderItem.bind(this); this.isMobileLandscape = this.isMobileLandscape.bind(this); @@ -151,7 +152,7 @@ class EmojiPickerMenu extends Component { diff --git a/src/components/LocalePicker.js b/src/components/LocalePicker.js index 6d1b56ecaa27..fa30093e8787 100644 --- a/src/components/LocalePicker.js +++ b/src/components/LocalePicker.js @@ -48,7 +48,7 @@ const LocalePicker = (props) => { size={props.size} value={props.preferredLocale} containerStyles={props.size === 'small' ? [styles.pickerContainerSmall] : []} - backgroundColor={themeColors.transparent} + backgroundColor={themeColors.midtone} /> ); }; diff --git a/src/libs/EmojiUtils.js b/src/libs/EmojiUtils.js index bee46547a3e8..0e813076015a 100644 --- a/src/libs/EmojiUtils.js +++ b/src/libs/EmojiUtils.js @@ -5,6 +5,7 @@ import Str from 'expensify-common/lib/str'; import CONST from '../CONST'; import * as User from './actions/User'; import emojisTrie from './EmojiTrie'; +import FrequentlyUsed from '../../assets/images/history.svg'; /** * Get the unicode code of an emoji in base 16. @@ -82,17 +83,17 @@ function containsOnlyEmojis(message) { } /** - * Get the header indices based on the max emojis per row + * Get the header emojis with their code, icon and index * @param {Object[]} emojis - * @returns {Number[]} + * @returns {Object[]} */ -function getHeaderIndices(emojis) { +function getHeaderEmojis(emojis) { const headerIndices = []; _.each(emojis, (emoji, index) => { if (!emoji.header) { return; } - headerIndices.push(index); + headerIndices.push({code: emoji.code, index, icon: emoji.icon}); }); return headerIndices; } @@ -149,6 +150,7 @@ function mergeEmojisWithFrequentlyUsedEmojis(emojis, frequentlyUsedEmojis = []) let allEmojis = [{ header: true, code: 'frequentlyUsed', + icon: FrequentlyUsed, }]; allEmojis = allEmojis.concat(frequentlyUsedEmojis, emojis); @@ -246,7 +248,7 @@ function suggestEmojis(text, limit = 5) { } export { - getHeaderIndices, + getHeaderEmojis, mergeEmojisWithFrequentlyUsedEmojis, addToFrequentlyUsedEmojis, containsOnlyEmojis, diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js index 1f2833357bd9..03fbede4db30 100644 --- a/src/libs/OptionsListUtils.js +++ b/src/libs/OptionsListUtils.js @@ -442,7 +442,7 @@ function getOptions(reports, personalDetails, { // When sortByReportTypeInSearch flag is true, recentReports will include the personalDetails options as well. sortByReportTypeInSearch = false, - searchValue = '', + searchInputValue = '', showChatPreviewLine = false, sortPersonalDetailsByAlphaAsc = true, forcePolicyNamePreview = false, @@ -450,6 +450,8 @@ function getOptions(reports, personalDetails, { let recentReportOptions = []; let personalDetailsOptions = []; const reportMapForLogins = {}; + const isPhoneNumber = CONST.REGEX.PHONE_WITH_SPECIAL_CHARS.test(searchInputValue); + const searchValue = isPhoneNumber ? searchInputValue.replace(CONST.REGEX.NON_NUMERIC_WITH_PLUS, '') : searchInputValue; // Filter out all the reports that shouldn't be displayed const filteredReports = _.filter(reports, report => ReportUtils.shouldReportBeInOptionList( @@ -645,7 +647,7 @@ function getSearchOptions( ) { return getOptions(reports, personalDetails, { betas, - searchValue: searchValue.trim(), + searchInputValue: searchValue.trim(), includeRecentReports: true, includeMultipleParticipantReports: true, maxRecentReportsToShow: 0, // Unlimited @@ -713,7 +715,7 @@ function getNewChatOptions( ) { return getOptions(reports, personalDetails, { betas, - searchValue: searchValue.trim(), + searchInputValue: searchValue.trim(), selectedOptions, excludeChatRooms: true, includeRecentReports: true, @@ -740,7 +742,7 @@ function getMemberInviteOptions( ) { return getOptions([], personalDetails, { betas, - searchValue: searchValue.trim(), + searchInputValue: searchValue.trim(), excludeDefaultRooms: true, includePersonalDetails: true, excludeLogins, diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 467ce7b70a70..d0de441dd08f 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -33,6 +33,7 @@ import reportPropTypes from '../reportPropTypes'; import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView'; import ReportHeaderSkeletonView from '../../components/ReportHeaderSkeletonView'; import withViewportOffsetTop, {viewportOffsetTopPropTypes} from '../../components/withViewportOffsetTop'; +import * as ReportActionsUtils from '../../libs/ReportActionsUtils'; const propTypes = { /** Navigation route context info provided by react navigation */ @@ -51,7 +52,7 @@ const propTypes = { report: reportPropTypes, /** Array of report actions for this report */ - reportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), + reportActions: PropTypes.arrayOf(PropTypes.shape(reportActionPropTypes)), /** Whether the composer is full size */ isComposerFullSize: PropTypes.bool, @@ -324,6 +325,7 @@ export default compose( reportActions: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getReportID(route)}`, canEvict: false, + selector: ReportActionsUtils.getSortedReportActionsForDisplay, }, report: { key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${getReportID(route)}`, diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 6af89e25dbb6..e525bc0b31a0 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -74,7 +74,7 @@ const propTypes = { report: reportPropTypes, /** Array of report actions for this report */ - reportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), + reportActions: PropTypes.arrayOf(PropTypes.shape(reportActionPropTypes)), /** Is the report view covered by the drawer */ isDrawerOpen: PropTypes.bool.isRequired, @@ -108,7 +108,7 @@ const defaultProps = { comment: '', modal: {}, report: {}, - reportActions: {}, + reportActions: [], blockedFromConcierge: {}, personalDetails: {}, ...withCurrentUserPersonalDetailsDefaultProps, @@ -190,9 +190,13 @@ class ReportActionCompose extends React.Component { this.setMaxLines(); } + // Value state does not have the same value as comment props when the comment gets changed from another tab. + // In this case, we should synchronize the value between tabs. + const shouldSyncComment = prevProps.comment !== this.props.comment && this.state.value !== this.props.comment; + // As the report IDs change, make sure to update the composer comment as we need to make sure // we do not show incorrect data in there (ie. draft of message from other report). - if (this.props.report.reportID === prevProps.report.reportID) { + if (this.props.report.reportID === prevProps.report.reportID && !shouldSyncComment) { return; } @@ -443,14 +447,13 @@ class ReportActionCompose extends React.Component { if (e.key === 'ArrowUp' && this.textInput.selectionStart === 0 && this.state.isCommentEmpty && !ReportUtils.chatIncludesChronos(this.props.report)) { e.preventDefault(); - const reportActionKey = _.find( - _.keys(this.props.reportActions).reverse(), - key => ReportUtils.canEditReportAction(this.props.reportActions[key]), + const lastReportAction = _.find( + this.props.reportActions, + action => ReportUtils.canEditReportAction(action), ); - if (reportActionKey !== -1 && this.props.reportActions[reportActionKey]) { - const {reportActionID, message} = this.props.reportActions[reportActionKey]; - Report.saveReportActionDraft(this.props.reportID, reportActionID, _.last(message).html); + if (lastReportAction !== -1 && lastReportAction) { + Report.saveReportActionDraft(this.props.reportID, lastReportAction.reportActionID, _.last(lastReportAction.message).html); } } } diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js index 37369611f190..bc0c97534019 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.js +++ b/src/pages/home/report/ReportActionItemMessageEdit.js @@ -258,13 +258,13 @@ class ReportActionItemMessageEdit extends React.Component { toggleReportActionComposeView(false, this.props.isSmallScreenWidth); }} onBlur={(event) => { + this.setState({isFocused: false}); const relatedTargetId = lodashGet(event, 'nativeEvent.relatedTarget.id'); // Return to prevent re-render when save/cancel button is pressed which cancels the onPress event by re-rendering if (_.contains([this.saveButtonID, this.cancelButtonID, this.emojiButtonID], relatedTargetId)) { return; } - this.setState({isFocused: false}); if (this.messageEditInput === relatedTargetId) { return; diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js index 2c65533800f9..6288d398f74f 100755 --- a/src/pages/home/report/ReportActionsView.js +++ b/src/pages/home/report/ReportActionsView.js @@ -29,7 +29,7 @@ const propTypes = { report: reportPropTypes.isRequired, /** Array of report actions for this report */ - reportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), + reportActions: PropTypes.arrayOf(PropTypes.shape(reportActionPropTypes)), /** The session of the logged in person */ session: PropTypes.shape({ @@ -49,7 +49,7 @@ const propTypes = { }; const defaultProps = { - reportActions: {}, + reportActions: [], session: {}, }; @@ -62,12 +62,9 @@ class ReportActionsView extends React.Component { this.unsubscribeVisibilityListener = null; this.hasCachedActions = _.size(props.reportActions) > 0; - // We need this.sortedAndFilteredReportActions to be set before this.state is initialized because the function to calculate the newMarkerReportActionID uses the sorted report actions - this.sortedAndFilteredReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(props.reportActions); - this.state = { isFloatingMessageCounterVisible: false, - newMarkerReportActionID: ReportUtils.getNewMarkerReportActionID(this.props.report, this.sortedAndFilteredReportActions), + newMarkerReportActionID: ReportUtils.getNewMarkerReportActionID(this.props.report, props.reportActions), }; this.currentScrollOffset = 0; @@ -132,7 +129,6 @@ class ReportActionsView extends React.Component { shouldComponentUpdate(nextProps, nextState) { if (!_.isEqual(nextProps.reportActions, this.props.reportActions)) { - this.sortedAndFilteredReportActions = ReportActionsUtils.getSortedReportActionsForDisplay(nextProps.reportActions); this.mostRecentIOUReportActionID = ReportActionsUtils.getMostRecentIOUReportActionID(nextProps.reportActions); return true; } @@ -203,16 +199,17 @@ class ReportActionsView extends React.Component { if (didReportBecomeVisible) { this.setState({ newMarkerReportActionID: ReportUtils.isUnread(this.props.report) - ? ReportUtils.getNewMarkerReportActionID(this.props.report, this.sortedAndFilteredReportActions) + ? ReportUtils.getNewMarkerReportActionID(this.props.report, this.props.reportActions) : '', }); this.openReportIfNecessary(); } - // If the report action marking the unread point is deleted we need to recalculate which action should be the unread marker - if (this.state.newMarkerReportActionID && _.isEmpty(lodashGet(this.props.reportActions[this.state.newMarkerReportActionID], 'message[0].html'))) { + // If the report is unread, we want to check if the number of actions has decreased. If so, then it seems that one of them was deleted. In this case, if the deleted action was the + // one marking the unread point, we need to recalculate which action should be the unread marker. + if (ReportUtils.isUnread(this.props.report) && prevProps.reportActions.length > this.props.reportActions.length) { this.setState({ - newMarkerReportActionID: ReportUtils.getNewMarkerReportActionID(this.props.report, this.sortedAndFilteredReportActions), + newMarkerReportActionID: ReportUtils.getNewMarkerReportActionID(this.props.report, this.props.reportActions), }); } @@ -229,7 +226,7 @@ class ReportActionsView extends React.Component { const didManuallyMarkReportAsUnread = (prevProps.report.lastReadTime !== this.props.report.lastReadTime) && ReportUtils.isUnread(this.props.report); if (didManuallyMarkReportAsUnread) { - this.setState({newMarkerReportActionID: ReportUtils.getNewMarkerReportActionID(this.props.report, this.sortedAndFilteredReportActions)}); + this.setState({newMarkerReportActionID: ReportUtils.getNewMarkerReportActionID(this.props.report, this.props.reportActions)}); } // Ensures subscription event succeeds when the report/workspace room is created optimistically. @@ -283,7 +280,7 @@ class ReportActionsView extends React.Component { return; } - const oldestReportAction = _.last(this.sortedAndFilteredReportActions); + const oldestReportAction = _.last(this.props.reportActions); // Don't load more chats if we're already at the beginning of the chat history if (oldestReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) { @@ -347,7 +344,6 @@ class ReportActionsView extends React.Component { if (!_.size(this.props.reportActions)) { return null; } - return ( <> {!this.props.isComposerFullSize && ( @@ -360,7 +356,7 @@ class ReportActionsView extends React.Component { report={this.props.report} onScroll={this.trackScroll} onLayout={this.recordTimeToMeasureItemLayout} - sortedReportActions={this.sortedAndFilteredReportActions} + sortedReportActions={this.props.reportActions} mostRecentIOUReportActionID={this.mostRecentIOUReportActionID} isLoadingMoreReportActions={this.props.report.isLoadingMoreReportActions} loadMoreChats={this.loadMoreChats} diff --git a/src/pages/home/report/ReportFooter.js b/src/pages/home/report/ReportFooter.js index 06f39e777c8a..fa3f300fc6e5 100644 --- a/src/pages/home/report/ReportFooter.js +++ b/src/pages/home/report/ReportFooter.js @@ -3,10 +3,8 @@ import _ from 'underscore'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; import {View, Keyboard} from 'react-native'; - import CONST from '../../../CONST'; import ReportActionCompose from './ReportActionCompose'; -import * as ReportUtils from '../../../libs/ReportUtils'; import SwipeableView from '../../../components/SwipeableView'; import OfflineIndicator from '../../../components/OfflineIndicator'; import OfflineWithFeedback from '../../../components/OfflineWithFeedback'; @@ -17,14 +15,14 @@ import withWindowDimensions, {windowDimensionsPropTypes} from '../../../componen import styles from '../../../styles/styles'; import reportActionPropTypes from './reportActionPropTypes'; import reportPropTypes from '../../reportPropTypes'; -import * as ReportActionsUtils from '../../../libs/ReportActionsUtils'; +import * as ReportUtils from '../../../libs/ReportUtils'; const propTypes = { /** Report object for the current report */ report: reportPropTypes, /** Report actions for the current report */ - reportActions: PropTypes.objectOf(PropTypes.shape(reportActionPropTypes)), + reportActions: PropTypes.arrayOf(PropTypes.shape(reportActionPropTypes)), /** Offline status */ isOffline: PropTypes.bool.isRequired, @@ -50,7 +48,7 @@ const propTypes = { const defaultProps = { report: {reportID: '0'}, - reportActions: {}, + reportActions: [], onSubmitComment: () => {}, errors: {}, pendingAction: null, @@ -68,18 +66,14 @@ class ReportFooter extends React.Component { render() { const isArchivedRoom = ReportUtils.isArchivedRoom(this.props.report); - let reportClosedAction; - if (isArchivedRoom) { - reportClosedAction = ReportActionsUtils.getLastClosedReportAction(this.props.reportActions); - } const hideComposer = isArchivedRoom || !_.isEmpty(this.props.errors); + return ( <> {(isArchivedRoom || hideComposer) && ( {isArchivedRoom && ( )} diff --git a/src/styles/styles.js b/src/styles/styles.js index 69b1c7345770..bd1c504cbca7 100644 --- a/src/styles/styles.js +++ b/src/styles/styles.js @@ -568,7 +568,6 @@ const styles = { paddingRight: 17, paddingTop: 6, paddingBottom: 6, - borderRadius: variables.componentBorderRadius, borderWidth: 0, color: themeColors.text, height: 26, @@ -593,7 +592,6 @@ const styles = { paddingTop: 6, paddingBottom: 6, borderWidth: 0, - borderRadius: variables.componentBorderRadius, color: themeColors.text, appearance: 'none', height: 26, @@ -609,7 +607,6 @@ const styles = { paddingTop: 6, paddingBottom: 6, borderWidth: 0, - borderRadius: variables.componentBorderRadius, color: themeColors.text, height: 26, opacity: 1, @@ -1536,9 +1533,8 @@ const styles = { categoryShortcutButton: { flex: 1, borderRadius: 8, - paddingTop: 2, - paddingBottom: 2, height: CONST.EMOJI_PICKER_ITEM_HEIGHT, + alignItems: 'center', justifyContent: 'center', }, diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index c48dec63801f..8a71c44e8825 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -515,6 +515,17 @@ describe('OptionsListUtils', () => { expect(results.userToInvite).not.toBe(null); expect(results.userToInvite.login).toBe('+15005550006'); + // When we add a search term for which no options exist and the searchValue itself + // is a potential phone number with special characters added + results = OptionsListUtils.getNewChatOptions(REPORTS, PERSONAL_DETAILS, [], '+1 (800)324-3233'); + + // Then we should have no options or personal details at all but there should be a userToInvite and the login + // should have the country code included + expect(results.recentReports.length).toBe(0); + expect(results.personalDetails.length).toBe(0); + expect(results.userToInvite).not.toBe(null); + expect(results.userToInvite.login).toBe('+18003243233'); + // Test Concierge's existence in new group options results = OptionsListUtils.getNewChatOptions(REPORTS_WITH_CONCIERGE, PERSONAL_DETAILS_WITH_CONCIERGE); From 6e0468b87e3252427b0307a0f1fea254ea8e13a6 Mon Sep 17 00:00:00 2001 From: azimgd Date: Tue, 7 Mar 2023 19:52:07 +0500 Subject: [PATCH 20/38] missing ios config --- src/CONST.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/CONST.js b/src/CONST.js index 48af5d7164c4..fac3bc7c3d73 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -7,6 +7,7 @@ const CLOUDFRONT_URL = 'https://d2k5nsl2zxldvw.cloudfront.net'; const ACTIVE_EXPENSIFY_URL = Url.addTrailingForwardSlash(lodashGet(Config, 'NEW_EXPENSIFY_URL', 'https://new.expensify.com')); const USE_EXPENSIFY_URL = 'https://use.expensify.com'; const PLATFORM_OS_MACOS = 'Mac OS'; +const PLATFORM_IOS = 'iOS'; const ANDROID_PACKAGE_NAME = 'com.expensify.chat'; const USA_COUNTRY_NAME = 'United States'; @@ -210,6 +211,7 @@ const CONST = { trigger: { DEFAULT: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierControl}, [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierCommand}, + [PLATFORM_IOS]: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierCommand}, }, }, NEW_GROUP: { @@ -219,6 +221,7 @@ const CONST = { trigger: { DEFAULT: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierShiftControl}, [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierShiftCommand}, + [PLATFORM_IOS]: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierShiftCommand}, }, }, SHORTCUT_MODAL: { @@ -228,6 +231,7 @@ const CONST = { trigger: { DEFAULT: {input: 'i', modifierFlags: KeyCommand.constants.keyModifierControl}, [PLATFORM_OS_MACOS]: {input: 'i', modifierFlags: KeyCommand.constants.keyModifierCommand}, + [PLATFORM_IOS]: {input: 'i', modifierFlags: KeyCommand.constants.keyModifierCommand}, }, }, ESCAPE: { @@ -237,6 +241,7 @@ const CONST = { trigger: { DEFAULT: {input: KeyCommand.constants.keyInputEscape}, [PLATFORM_OS_MACOS]: {input: KeyCommand.constants.keyInputEscape}, + [PLATFORM_IOS]: {input: KeyCommand.constants.keyInputEscape}, }, }, ENTER: { @@ -246,6 +251,7 @@ const CONST = { trigger: { DEFAULT: {input: KeyCommand.constants.keyInputEnter}, [PLATFORM_OS_MACOS]: {input: KeyCommand.constants.keyInputEnter}, + [PLATFORM_IOS]: {input: KeyCommand.constants.keyInputEnter}, }, }, CTRL_ENTER: { @@ -255,6 +261,7 @@ const CONST = { trigger: { DEFAULT: {input: KeyCommand.constants.keyInputEnter, modifierFlags: KeyCommand.constants.keyModifierControl}, [PLATFORM_OS_MACOS]: {input: KeyCommand.constants.keyInputEnter, modifierFlags: KeyCommand.constants.keyModifierCommand}, + [PLATFORM_IOS]: {input: KeyCommand.constants.keyInputEnter, modifierFlags: KeyCommand.constants.keyModifierCommand}, }, }, COPY: { @@ -264,6 +271,7 @@ const CONST = { trigger: { DEFAULT: {input: 'c', modifierFlags: KeyCommand.constants.keyModifierControl}, [PLATFORM_OS_MACOS]: {input: 'c', modifierFlags: KeyCommand.constants.keyModifierCommand}, + [PLATFORM_IOS]: {input: 'c', modifierFlags: KeyCommand.constants.keyModifierCommand}, }, }, ARROW_UP: { @@ -273,6 +281,7 @@ const CONST = { trigger: { DEFAULT: {input: KeyCommand.constants.keyInputUpArrow}, [PLATFORM_OS_MACOS]: {input: KeyCommand.constants.keyInputUpArrow}, + [PLATFORM_IOS]: {input: KeyCommand.constants.keyInputUpArrow}, }, }, ARROW_DOWN: { @@ -282,6 +291,7 @@ const CONST = { trigger: { DEFAULT: {input: KeyCommand.constants.keyInputDownArrow}, [PLATFORM_OS_MACOS]: {input: KeyCommand.constants.keyInputDownArrow}, + [PLATFORM_IOS]: {input: KeyCommand.constants.keyInputDownArrow}, }, }, }, @@ -723,7 +733,7 @@ const CONST = { WINDOWS: 'Windows', MAC_OS: PLATFORM_OS_MACOS, ANDROID: 'Android', - IOS: 'iOS', + IOS: PLATFORM_IOS, LINUX: 'Linux', NATIVE: 'Native', }, From 4bb5eb34cc2724329c98490a79da20ef39bdc861 Mon Sep 17 00:00:00 2001 From: azimgd Date: Tue, 7 Mar 2023 22:50:01 +0500 Subject: [PATCH 21/38] fix ios --- src/CONST.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CONST.js b/src/CONST.js index fac3bc7c3d73..1b3ce58fff56 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -198,6 +198,7 @@ const CONST = { CTRL: { DEFAULT: 'control', [PLATFORM_OS_MACOS]: 'meta', + [PLATFORM_IOS]: 'meta', }, SHIFT: { DEFAULT: 'shift', From 2bbb9fcb02eb0a161cecc8a27a0081d8a6a9750b Mon Sep 17 00:00:00 2001 From: azimgd Date: Tue, 7 Mar 2023 23:02:22 +0500 Subject: [PATCH 22/38] validate tests --- src/CONST.js | 54 +++++++++---------- .../KeyboardShortcut/getKeyEventModifiers.js | 9 ++-- src/libs/KeyboardShortcut/index.js | 8 +-- 3 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 1b3ce58fff56..a12594b16960 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -210,9 +210,9 @@ const CONST = { shortcutKey: 'K', modifiers: ['CTRL'], trigger: { - DEFAULT: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierControl}, - [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierCommand}, - [PLATFORM_IOS]: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierCommand}, + DEFAULT: {input: 'k', modifierFlags: keyModifierControl}, + [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: keyModifierCommand}, + [PLATFORM_IOS]: {input: 'k', modifierFlags: keyModifierCommand}, }, }, NEW_GROUP: { @@ -220,9 +220,9 @@ const CONST = { shortcutKey: 'K', modifiers: ['CTRL', 'SHIFT'], trigger: { - DEFAULT: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierShiftControl}, - [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierShiftCommand}, - [PLATFORM_IOS]: {input: 'k', modifierFlags: KeyCommand.constants.keyModifierShiftCommand}, + DEFAULT: {input: 'k', modifierFlags: keyModifierShiftControl}, + [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: keyModifierShiftCommand}, + [PLATFORM_IOS]: {input: 'k', modifierFlags: keyModifierShiftCommand}, }, }, SHORTCUT_MODAL: { @@ -230,9 +230,9 @@ const CONST = { shortcutKey: 'I', modifiers: ['CTRL'], trigger: { - DEFAULT: {input: 'i', modifierFlags: KeyCommand.constants.keyModifierControl}, - [PLATFORM_OS_MACOS]: {input: 'i', modifierFlags: KeyCommand.constants.keyModifierCommand}, - [PLATFORM_IOS]: {input: 'i', modifierFlags: KeyCommand.constants.keyModifierCommand}, + DEFAULT: {input: 'i', modifierFlags: keyModifierControl}, + [PLATFORM_OS_MACOS]: {input: 'i', modifierFlags: keyModifierCommand}, + [PLATFORM_IOS]: {input: 'i', modifierFlags: keyModifierCommand}, }, }, ESCAPE: { @@ -240,9 +240,9 @@ const CONST = { shortcutKey: 'Escape', modifiers: [], trigger: { - DEFAULT: {input: KeyCommand.constants.keyInputEscape}, - [PLATFORM_OS_MACOS]: {input: KeyCommand.constants.keyInputEscape}, - [PLATFORM_IOS]: {input: KeyCommand.constants.keyInputEscape}, + DEFAULT: {input: keyInputEscape}, + [PLATFORM_OS_MACOS]: {input: keyInputEscape}, + [PLATFORM_IOS]: {input: keyInputEscape}, }, }, ENTER: { @@ -250,9 +250,9 @@ const CONST = { shortcutKey: 'Enter', modifiers: [], trigger: { - DEFAULT: {input: KeyCommand.constants.keyInputEnter}, - [PLATFORM_OS_MACOS]: {input: KeyCommand.constants.keyInputEnter}, - [PLATFORM_IOS]: {input: KeyCommand.constants.keyInputEnter}, + DEFAULT: {input: keyInputEnter}, + [PLATFORM_OS_MACOS]: {input: keyInputEnter}, + [PLATFORM_IOS]: {input: keyInputEnter}, }, }, CTRL_ENTER: { @@ -260,9 +260,9 @@ const CONST = { shortcutKey: 'Enter', modifiers: ['CTRL'], trigger: { - DEFAULT: {input: KeyCommand.constants.keyInputEnter, modifierFlags: KeyCommand.constants.keyModifierControl}, - [PLATFORM_OS_MACOS]: {input: KeyCommand.constants.keyInputEnter, modifierFlags: KeyCommand.constants.keyModifierCommand}, - [PLATFORM_IOS]: {input: KeyCommand.constants.keyInputEnter, modifierFlags: KeyCommand.constants.keyModifierCommand}, + DEFAULT: {input: keyInputEnter), modifierFlags: keyModifierControl}, + [PLATFORM_OS_MACOS]: {input: keyInputEnter), modifierFlags: keyModifierCommand}, + [PLATFORM_IOS]: {input: keyInputEnter), modifierFlags: keyModifierCommand}, }, }, COPY: { @@ -270,9 +270,9 @@ const CONST = { shortcutKey: 'C', modifiers: ['CTRL'], trigger: { - DEFAULT: {input: 'c', modifierFlags: KeyCommand.constants.keyModifierControl}, - [PLATFORM_OS_MACOS]: {input: 'c', modifierFlags: KeyCommand.constants.keyModifierCommand}, - [PLATFORM_IOS]: {input: 'c', modifierFlags: KeyCommand.constants.keyModifierCommand}, + DEFAULT: {input: 'c', modifierFlags: keyModifierControl}, + [PLATFORM_OS_MACOS]: {input: 'c', modifierFlags: keyModifierCommand}, + [PLATFORM_IOS]: {input: 'c', modifierFlags: keyModifierCommand}, }, }, ARROW_UP: { @@ -280,9 +280,9 @@ const CONST = { shortcutKey: 'ArrowUp', modifiers: [], trigger: { - DEFAULT: {input: KeyCommand.constants.keyInputUpArrow}, - [PLATFORM_OS_MACOS]: {input: KeyCommand.constants.keyInputUpArrow}, - [PLATFORM_IOS]: {input: KeyCommand.constants.keyInputUpArrow}, + DEFAULT: {input: keyInputUpArrow}, + [PLATFORM_OS_MACOS]: {input: keyInputUpArrow}, + [PLATFORM_IOS]: {input: keyInputUpArrow}, }, }, ARROW_DOWN: { @@ -290,9 +290,9 @@ const CONST = { shortcutKey: 'ArrowDown', modifiers: [], trigger: { - DEFAULT: {input: KeyCommand.constants.keyInputDownArrow}, - [PLATFORM_OS_MACOS]: {input: KeyCommand.constants.keyInputDownArrow}, - [PLATFORM_IOS]: {input: KeyCommand.constants.keyInputDownArrow}, + DEFAULT: {input: keyInputDownArrow}, + [PLATFORM_OS_MACOS]: {input: keyInputDownArrow}, + [PLATFORM_IOS]: {input: keyInputDownArrow}, }, }, }, diff --git a/src/libs/KeyboardShortcut/getKeyEventModifiers.js b/src/libs/KeyboardShortcut/getKeyEventModifiers.js index 2d0839d2c35d..7865d51a0507 100644 --- a/src/libs/KeyboardShortcut/getKeyEventModifiers.js +++ b/src/libs/KeyboardShortcut/getKeyEventModifiers.js @@ -1,4 +1,5 @@ import * as KeyCommand from 'react-native-key-command'; +import lodashGet from 'lodash/get'; /** * Gets modifiers from a keyboard event. @@ -7,16 +8,16 @@ import * as KeyCommand from 'react-native-key-command'; * @returns {Array} */ function getKeyEventModifiers(event) { - if (event.modifierFlags === KeyCommand.constants.keyModifierControl) { + if (event.modifierFlags === lodashGet(KeyCommand, 'constants.keyModifierControl', 'keyModifierControl')) { return ['CONTROL']; } - if (event.modifierFlags === KeyCommand.constants.keyModifierCommand) { + if (event.modifierFlags === lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')) { return ['META']; } - if (event.modifierFlags === KeyCommand.constants.keyModifierShiftControl) { + if (event.modifierFlags === lodashGet(KeyCommand, 'constants.keyModifierShiftControl', 'keyModifierShiftControl')) { return ['CONTROL', 'Shift']; } - if (event.modifierFlags === KeyCommand.constants.keyModifierShiftCommand) { + if (event.modifierFlags === lodashGet(KeyCommand, 'constants.keyModifierShiftCommand', 'keyModifierShiftCommand')) { return ['META', 'Shift']; } diff --git a/src/libs/KeyboardShortcut/index.js b/src/libs/KeyboardShortcut/index.js index b0b31fa1897d..f20be44096d4 100644 --- a/src/libs/KeyboardShortcut/index.js +++ b/src/libs/KeyboardShortcut/index.js @@ -31,16 +31,16 @@ function getDocumentedShortcuts() { function getDisplayName(key, modifiers) { let displayName = (() => { // Type of key is string and the type of KeyCommand.constants.* is number | string. Use _.isEqual to match different types. - if (_.isEqual(key, KeyCommand.constants.keyInputEnter.toString())) { + if (_.isEqual(key, lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter').toString())) { return ['ENTER']; } - if (_.isEqual(key, KeyCommand.constants.keyInputEscape.toString())) { + if (_.isEqual(key, lodashGet(KeyCommand, 'constants.keyInputEscape', 'keyInputEscape').toString())) { return ['ESCAPE']; } - if (_.isEqual(key, KeyCommand.constants.keyInputUpArrow.toString())) { + if (_.isEqual(key, lodashGet(KeyCommand, 'constants.keyInputUpArrow', 'keyInputUpArrow').toString())) { return ['ARROWUP']; } - if (_.isEqual(key, KeyCommand.constants.keyInputDownArrow.toString())) { + if (_.isEqual(key, lodashGet(KeyCommand, 'constants.keyInputDownArrow', 'keyInputDownArrow').toString())) { return ['ARROWDOWN']; } return [key.toUpperCase()]; From 5603110e87493857f0a40116841ea50c44f52d16 Mon Sep 17 00:00:00 2001 From: azimgd Date: Tue, 7 Mar 2023 23:13:02 +0500 Subject: [PATCH 23/38] unpushed changes for const file --- src/CONST.js | 54 ++++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index a12594b16960..5ada4e64630c 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -210,9 +210,9 @@ const CONST = { shortcutKey: 'K', modifiers: ['CTRL'], trigger: { - DEFAULT: {input: 'k', modifierFlags: keyModifierControl}, - [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: keyModifierCommand}, - [PLATFORM_IOS]: {input: 'k', modifierFlags: keyModifierCommand}, + DEFAULT: {input: 'k', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierControl', 'keyModifierControl')}, + [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, + [PLATFORM_IOS]: {input: 'k', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, }, }, NEW_GROUP: { @@ -220,9 +220,9 @@ const CONST = { shortcutKey: 'K', modifiers: ['CTRL', 'SHIFT'], trigger: { - DEFAULT: {input: 'k', modifierFlags: keyModifierShiftControl}, - [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: keyModifierShiftCommand}, - [PLATFORM_IOS]: {input: 'k', modifierFlags: keyModifierShiftCommand}, + DEFAULT: {input: 'k', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierShiftControl', 'keyModifierShiftControl')}, + [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierShiftCommand', 'keyModifierShiftCommand')}, + [PLATFORM_IOS]: {input: 'k', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierShiftCommand', 'keyModifierShiftCommand')}, }, }, SHORTCUT_MODAL: { @@ -230,9 +230,9 @@ const CONST = { shortcutKey: 'I', modifiers: ['CTRL'], trigger: { - DEFAULT: {input: 'i', modifierFlags: keyModifierControl}, - [PLATFORM_OS_MACOS]: {input: 'i', modifierFlags: keyModifierCommand}, - [PLATFORM_IOS]: {input: 'i', modifierFlags: keyModifierCommand}, + DEFAULT: {input: 'i', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierControl', 'keyModifierControl')}, + [PLATFORM_OS_MACOS]: {input: 'i', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, + [PLATFORM_IOS]: {input: 'i', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, }, }, ESCAPE: { @@ -240,9 +240,9 @@ const CONST = { shortcutKey: 'Escape', modifiers: [], trigger: { - DEFAULT: {input: keyInputEscape}, - [PLATFORM_OS_MACOS]: {input: keyInputEscape}, - [PLATFORM_IOS]: {input: keyInputEscape}, + DEFAULT: {input: lodashGet(KeyCommand, 'constants.keyInputEscape', 'keyInputEscape')}, + [PLATFORM_OS_MACOS]: {input: lodashGet(KeyCommand, 'constants.keyInputEscape', 'keyInputEscape')}, + [PLATFORM_IOS]: {input: lodashGet(KeyCommand, 'constants.keyInputEscape', 'keyInputEscape')}, }, }, ENTER: { @@ -250,9 +250,9 @@ const CONST = { shortcutKey: 'Enter', modifiers: [], trigger: { - DEFAULT: {input: keyInputEnter}, - [PLATFORM_OS_MACOS]: {input: keyInputEnter}, - [PLATFORM_IOS]: {input: keyInputEnter}, + DEFAULT: {input: lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter')}, + [PLATFORM_OS_MACOS]: {input: lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter')}, + [PLATFORM_IOS]: {input: lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter')}, }, }, CTRL_ENTER: { @@ -260,9 +260,9 @@ const CONST = { shortcutKey: 'Enter', modifiers: ['CTRL'], trigger: { - DEFAULT: {input: keyInputEnter), modifierFlags: keyModifierControl}, - [PLATFORM_OS_MACOS]: {input: keyInputEnter), modifierFlags: keyModifierCommand}, - [PLATFORM_IOS]: {input: keyInputEnter), modifierFlags: keyModifierCommand}, + DEFAULT: {input: lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter'), modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierControl', 'keyModifierControl')}, + [PLATFORM_OS_MACOS]: {input: lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter'), modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, + [PLATFORM_IOS]: {input: lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter'), modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, }, }, COPY: { @@ -270,9 +270,9 @@ const CONST = { shortcutKey: 'C', modifiers: ['CTRL'], trigger: { - DEFAULT: {input: 'c', modifierFlags: keyModifierControl}, - [PLATFORM_OS_MACOS]: {input: 'c', modifierFlags: keyModifierCommand}, - [PLATFORM_IOS]: {input: 'c', modifierFlags: keyModifierCommand}, + DEFAULT: {input: 'c', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierControl', 'keyModifierControl')}, + [PLATFORM_OS_MACOS]: {input: 'c', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, + [PLATFORM_IOS]: {input: 'c', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, }, }, ARROW_UP: { @@ -280,9 +280,9 @@ const CONST = { shortcutKey: 'ArrowUp', modifiers: [], trigger: { - DEFAULT: {input: keyInputUpArrow}, - [PLATFORM_OS_MACOS]: {input: keyInputUpArrow}, - [PLATFORM_IOS]: {input: keyInputUpArrow}, + DEFAULT: {input: lodashGet(KeyCommand, 'constants.keyInputUpArrow', 'keyInputUpArrow')}, + [PLATFORM_OS_MACOS]: {input: lodashGet(KeyCommand, 'constants.keyInputUpArrow', 'keyInputUpArrow')}, + [PLATFORM_IOS]: {input: lodashGet(KeyCommand, 'constants.keyInputUpArrow', 'keyInputUpArrow')}, }, }, ARROW_DOWN: { @@ -290,9 +290,9 @@ const CONST = { shortcutKey: 'ArrowDown', modifiers: [], trigger: { - DEFAULT: {input: keyInputDownArrow}, - [PLATFORM_OS_MACOS]: {input: keyInputDownArrow}, - [PLATFORM_IOS]: {input: keyInputDownArrow}, + DEFAULT: {input: lodashGet(KeyCommand, 'constants.keyInputDownArrow', 'keyInputDownArrow')}, + [PLATFORM_OS_MACOS]: {input: lodashGet(KeyCommand, 'constants.keyInputDownArrow', 'keyInputDownArrow')}, + [PLATFORM_IOS]: {input: lodashGet(KeyCommand, 'constants.keyInputDownArrow', 'keyInputDownArrow')}, }, }, }, From 9cc6c74c579ea8bd592ff8f171c6789ff42b7c0d Mon Sep 17 00:00:00 2001 From: azimgd Date: Mon, 20 Mar 2023 19:35:18 +0100 Subject: [PATCH 24/38] different platforms have different event casings --- src/libs/KeyboardShortcut/index.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libs/KeyboardShortcut/index.js b/src/libs/KeyboardShortcut/index.js index f20be44096d4..b055a35988c8 100644 --- a/src/libs/KeyboardShortcut/index.js +++ b/src/libs/KeyboardShortcut/index.js @@ -31,16 +31,16 @@ function getDocumentedShortcuts() { function getDisplayName(key, modifiers) { let displayName = (() => { // Type of key is string and the type of KeyCommand.constants.* is number | string. Use _.isEqual to match different types. - if (_.isEqual(key, lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter').toString())) { + if (_.isEqual(key.toLowerCase(), lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter').toString().toLowerCase())) { return ['ENTER']; } - if (_.isEqual(key, lodashGet(KeyCommand, 'constants.keyInputEscape', 'keyInputEscape').toString())) { + if (_.isEqual(key.toLowerCase(), lodashGet(KeyCommand, 'constants.keyInputEscape', 'keyInputEscape').toString().toLowerCase())) { return ['ESCAPE']; } - if (_.isEqual(key, lodashGet(KeyCommand, 'constants.keyInputUpArrow', 'keyInputUpArrow').toString())) { + if (_.isEqual(key.toLowerCase(), lodashGet(KeyCommand, 'constants.keyInputUpArrow', 'keyInputUpArrow').toString().toLowerCase())) { return ['ARROWUP']; } - if (_.isEqual(key, lodashGet(KeyCommand, 'constants.keyInputDownArrow', 'keyInputDownArrow').toString())) { + if (_.isEqual(key.toLowerCase(), lodashGet(KeyCommand, 'constants.keyInputDownArrow', 'keyInputDownArrow').toString().toLowerCase())) { return ['ARROWDOWN']; } return [key.toUpperCase()]; From 0ceb40ae3abc34fc8378368997fbb902d1944b8d Mon Sep 17 00:00:00 2001 From: azimgd Date: Mon, 20 Mar 2023 21:10:08 +0100 Subject: [PATCH 25/38] fix eslint warnings --- src/CONST.js | 63 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/src/CONST.js b/src/CONST.js index 5ada4e64630c..de8dca851700 100755 --- a/src/CONST.js +++ b/src/CONST.js @@ -11,6 +11,15 @@ const PLATFORM_IOS = 'iOS'; const ANDROID_PACKAGE_NAME = 'com.expensify.chat'; const USA_COUNTRY_NAME = 'United States'; +const keyModifierControl = lodashGet(KeyCommand, 'constants.keyModifierControl', 'keyModifierControl'); +const keyModifierCommand = lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand'); +const keyModifierShiftControl = lodashGet(KeyCommand, 'constants.keyModifierShiftControl', 'keyModifierShiftControl'); +const keyModifierShiftCommand = lodashGet(KeyCommand, 'constants.keyModifierShiftCommand', 'keyModifierShiftCommand'); +const keyInputEscape = lodashGet(KeyCommand, 'constants.keyInputEscape', 'keyInputEscape'); +const keyInputEnter = lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter'); +const keyInputUpArrow = lodashGet(KeyCommand, 'constants.keyInputUpArrow', 'keyInputUpArrow'); +const keyInputDownArrow = lodashGet(KeyCommand, 'constants.keyInputDownArrow', 'keyInputDownArrow'); + const CONST = { ANDROID_PACKAGE_NAME, ANIMATED_TRANSITION: 300, @@ -210,9 +219,9 @@ const CONST = { shortcutKey: 'K', modifiers: ['CTRL'], trigger: { - DEFAULT: {input: 'k', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierControl', 'keyModifierControl')}, - [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, - [PLATFORM_IOS]: {input: 'k', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, + DEFAULT: {input: 'k', modifierFlags: keyModifierControl}, + [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: keyModifierCommand}, + [PLATFORM_IOS]: {input: 'k', modifierFlags: keyModifierCommand}, }, }, NEW_GROUP: { @@ -220,9 +229,9 @@ const CONST = { shortcutKey: 'K', modifiers: ['CTRL', 'SHIFT'], trigger: { - DEFAULT: {input: 'k', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierShiftControl', 'keyModifierShiftControl')}, - [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierShiftCommand', 'keyModifierShiftCommand')}, - [PLATFORM_IOS]: {input: 'k', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierShiftCommand', 'keyModifierShiftCommand')}, + DEFAULT: {input: 'k', modifierFlags: keyModifierShiftControl}, + [PLATFORM_OS_MACOS]: {input: 'k', modifierFlags: keyModifierShiftCommand}, + [PLATFORM_IOS]: {input: 'k', modifierFlags: keyModifierShiftCommand}, }, }, SHORTCUT_MODAL: { @@ -230,9 +239,9 @@ const CONST = { shortcutKey: 'I', modifiers: ['CTRL'], trigger: { - DEFAULT: {input: 'i', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierControl', 'keyModifierControl')}, - [PLATFORM_OS_MACOS]: {input: 'i', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, - [PLATFORM_IOS]: {input: 'i', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, + DEFAULT: {input: 'i', modifierFlags: keyModifierControl}, + [PLATFORM_OS_MACOS]: {input: 'i', modifierFlags: keyModifierCommand}, + [PLATFORM_IOS]: {input: 'i', modifierFlags: keyModifierCommand}, }, }, ESCAPE: { @@ -240,9 +249,9 @@ const CONST = { shortcutKey: 'Escape', modifiers: [], trigger: { - DEFAULT: {input: lodashGet(KeyCommand, 'constants.keyInputEscape', 'keyInputEscape')}, - [PLATFORM_OS_MACOS]: {input: lodashGet(KeyCommand, 'constants.keyInputEscape', 'keyInputEscape')}, - [PLATFORM_IOS]: {input: lodashGet(KeyCommand, 'constants.keyInputEscape', 'keyInputEscape')}, + DEFAULT: {input: keyInputEscape}, + [PLATFORM_OS_MACOS]: {input: keyInputEscape}, + [PLATFORM_IOS]: {input: keyInputEscape}, }, }, ENTER: { @@ -250,9 +259,9 @@ const CONST = { shortcutKey: 'Enter', modifiers: [], trigger: { - DEFAULT: {input: lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter')}, - [PLATFORM_OS_MACOS]: {input: lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter')}, - [PLATFORM_IOS]: {input: lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter')}, + DEFAULT: {input: keyInputEnter}, + [PLATFORM_OS_MACOS]: {input: keyInputEnter}, + [PLATFORM_IOS]: {input: keyInputEnter}, }, }, CTRL_ENTER: { @@ -260,9 +269,9 @@ const CONST = { shortcutKey: 'Enter', modifiers: ['CTRL'], trigger: { - DEFAULT: {input: lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter'), modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierControl', 'keyModifierControl')}, - [PLATFORM_OS_MACOS]: {input: lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter'), modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, - [PLATFORM_IOS]: {input: lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter'), modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, + DEFAULT: {input: keyInputEnter, modifierFlags: keyModifierControl}, + [PLATFORM_OS_MACOS]: {input: keyInputEnter, modifierFlags: keyModifierCommand}, + [PLATFORM_IOS]: {input: keyInputEnter, modifierFlags: keyModifierCommand}, }, }, COPY: { @@ -270,9 +279,9 @@ const CONST = { shortcutKey: 'C', modifiers: ['CTRL'], trigger: { - DEFAULT: {input: 'c', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierControl', 'keyModifierControl')}, - [PLATFORM_OS_MACOS]: {input: 'c', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, - [PLATFORM_IOS]: {input: 'c', modifierFlags: lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')}, + DEFAULT: {input: 'c', modifierFlags: keyModifierControl}, + [PLATFORM_OS_MACOS]: {input: 'c', modifierFlags: keyModifierCommand}, + [PLATFORM_IOS]: {input: 'c', modifierFlags: keyModifierCommand}, }, }, ARROW_UP: { @@ -280,9 +289,9 @@ const CONST = { shortcutKey: 'ArrowUp', modifiers: [], trigger: { - DEFAULT: {input: lodashGet(KeyCommand, 'constants.keyInputUpArrow', 'keyInputUpArrow')}, - [PLATFORM_OS_MACOS]: {input: lodashGet(KeyCommand, 'constants.keyInputUpArrow', 'keyInputUpArrow')}, - [PLATFORM_IOS]: {input: lodashGet(KeyCommand, 'constants.keyInputUpArrow', 'keyInputUpArrow')}, + DEFAULT: {input: keyInputUpArrow}, + [PLATFORM_OS_MACOS]: {input: keyInputUpArrow}, + [PLATFORM_IOS]: {input: keyInputUpArrow}, }, }, ARROW_DOWN: { @@ -290,9 +299,9 @@ const CONST = { shortcutKey: 'ArrowDown', modifiers: [], trigger: { - DEFAULT: {input: lodashGet(KeyCommand, 'constants.keyInputDownArrow', 'keyInputDownArrow')}, - [PLATFORM_OS_MACOS]: {input: lodashGet(KeyCommand, 'constants.keyInputDownArrow', 'keyInputDownArrow')}, - [PLATFORM_IOS]: {input: lodashGet(KeyCommand, 'constants.keyInputDownArrow', 'keyInputDownArrow')}, + DEFAULT: {input: keyInputDownArrow}, + [PLATFORM_OS_MACOS]: {input: keyInputDownArrow}, + [PLATFORM_IOS]: {input: keyInputDownArrow}, }, }, }, From 2c5c2e94f1dca5d2a32c3730fb642bef5049cccf Mon Sep 17 00:00:00 2001 From: azimgd Date: Mon, 20 Mar 2023 21:16:13 +0100 Subject: [PATCH 26/38] safe check to event triggers --- src/libs/KeyboardShortcut/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/KeyboardShortcut/index.js b/src/libs/KeyboardShortcut/index.js index b055a35988c8..90cb3436e210 100644 --- a/src/libs/KeyboardShortcut/index.js +++ b/src/libs/KeyboardShortcut/index.js @@ -59,7 +59,7 @@ function getDisplayName(key, modifiers) { _.each(CONST.KEYBOARD_SHORTCUTS, (shortcut) => { KeyCommand.addListener( - shortcut.trigger[operatingSystem] || shortcut.trigger.DEFAULT, + _.lodashGet(shortcut, ['trigger', operatingSystem], shortcut.trigger.DEFAULT), (keycommandEvent, event) => bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEvent, event), ); }); From 2c602c5ed942f13d969fef973749322f2062f18a Mon Sep 17 00:00:00 2001 From: azimgd Date: Mon, 20 Mar 2023 21:23:44 +0100 Subject: [PATCH 27/38] typo fix --- src/libs/KeyboardShortcut/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/KeyboardShortcut/index.js b/src/libs/KeyboardShortcut/index.js index 90cb3436e210..ecd656d8865b 100644 --- a/src/libs/KeyboardShortcut/index.js +++ b/src/libs/KeyboardShortcut/index.js @@ -59,7 +59,7 @@ function getDisplayName(key, modifiers) { _.each(CONST.KEYBOARD_SHORTCUTS, (shortcut) => { KeyCommand.addListener( - _.lodashGet(shortcut, ['trigger', operatingSystem], shortcut.trigger.DEFAULT), + lodashGet(shortcut, ['trigger', operatingSystem], shortcut.trigger.DEFAULT), (keycommandEvent, event) => bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEvent, event), ); }); From 63ada03dc8df93f2719aba11f4a52cc2b763de32 Mon Sep 17 00:00:00 2001 From: azimgd Date: Mon, 20 Mar 2023 21:31:04 +0100 Subject: [PATCH 28/38] add more safety checks --- src/libs/KeyboardShortcut/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/KeyboardShortcut/index.js b/src/libs/KeyboardShortcut/index.js index ecd656d8865b..b9672f29e406 100644 --- a/src/libs/KeyboardShortcut/index.js +++ b/src/libs/KeyboardShortcut/index.js @@ -58,8 +58,10 @@ function getDisplayName(key, modifiers) { } _.each(CONST.KEYBOARD_SHORTCUTS, (shortcut) => { + const shortcutTrigger = lodashGet(shortcut, ['trigger', operatingSystem], lodashGet(shortcut, 'trigger.DEFAULT')); + KeyCommand.addListener( - lodashGet(shortcut, ['trigger', operatingSystem], shortcut.trigger.DEFAULT), + shortcutTrigger, (keycommandEvent, event) => bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEvent, event), ); }); From c0d5ad7fcf50b8c9e4f83b877d8004202dd8320c Mon Sep 17 00:00:00 2001 From: azimgd Date: Tue, 21 Mar 2023 14:42:59 +0100 Subject: [PATCH 29/38] bump react-native-key-command --- ios/Podfile.lock | 4 ++-- package-lock.json | 14 +++++++------- package.json | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2e41c2db6908..6c2a936e57ad 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -478,7 +478,7 @@ PODS: - React - react-native-image-picker (5.0.2): - React-Core - - react-native-key-command (0.7.0): + - react-native-key-command (0.8.0): - React-Core - react-native-netinfo (8.3.1): - React-Core @@ -1013,7 +1013,7 @@ SPEC CHECKSUMS: react-native-flipper: dc5290261fbeeb2faec1bdc57ae6dd8d562e1de4 react-native-image-manipulator: c48f64221cfcd46e9eec53619c4c0374f3328a56 react-native-image-picker: a5dddebb4d2955ac4712a4ed66b00a85f62a63ac - react-native-key-command: bfa17378a6c49090b83e904ddcfc9ffb261448b2 + react-native-key-command: daf2ab522c266db74bf2c2804883620379ed08b5 react-native-netinfo: 1a6035d3b9780221d407c277ebfb5722ace00658 react-native-pdf: 33c622cbdf776a649929e8b9d1ce2d313347c4fa react-native-performance: 224bd53e6a835fda4353302cf891d088a0af7406 diff --git a/package-lock.json b/package-lock.json index 3a71af5cb2d8..ab184b3a06eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -69,7 +69,7 @@ "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^5.0.2", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972", - "react-native-key-command": "^0.7.0", + "react-native-key-command": "^0.8.0", "react-native-modal": "^13.0.0", "react-native-onyx": "1.0.36", "react-native-pdf": "^6.6.2", @@ -37549,9 +37549,9 @@ "license": "MIT" }, "node_modules/react-native-key-command": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.7.0.tgz", - "integrity": "sha512-iFFXfsyTWJoo3F7A1cy01I66RldcmJOfys1NQQs2EKz9ZVY8LSOmHuJUTqgpPu96bGV4l2fHqyNfI98qc4DMCA==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.8.0.tgz", + "integrity": "sha512-yUZwOk/OoLLyOIyVAiPN4l+Fdhv28H0Q+vyAI71V8ccVDXLLdC4YfjBPFZFW6RX05qdKMGEBL2g4OF5eWfz6Sg==", "dependencies": { "events": "^3.3.0", "underscore": "^1.13.4" @@ -73528,9 +73528,9 @@ "from": "react-native-image-size@git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972" }, "react-native-key-command": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.7.0.tgz", - "integrity": "sha512-iFFXfsyTWJoo3F7A1cy01I66RldcmJOfys1NQQs2EKz9ZVY8LSOmHuJUTqgpPu96bGV4l2fHqyNfI98qc4DMCA==", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.8.0.tgz", + "integrity": "sha512-yUZwOk/OoLLyOIyVAiPN4l+Fdhv28H0Q+vyAI71V8ccVDXLLdC4YfjBPFZFW6RX05qdKMGEBL2g4OF5eWfz6Sg==", "requires": { "events": "^3.3.0", "underscore": "^1.13.4" diff --git a/package.json b/package.json index 1e7d8df1eb0d..675c3f3e88ee 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^5.0.2", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972", - "react-native-key-command": "^0.7.0", + "react-native-key-command": "^0.8.0", "react-native-modal": "^13.0.0", "react-native-onyx": "1.0.36", "react-native-pdf": "^6.6.2", From 951953441b6eeb8d68a685a9341a0109ef08e976 Mon Sep 17 00:00:00 2001 From: azimgd Date: Wed, 22 Mar 2023 20:49:39 +0100 Subject: [PATCH 30/38] implement show keyboard shortcuts modal close --- src/components/KeyboardShortcutsModal.js | 20 ++++++++++++++------ src/components/ScreenWrapper/index.js | 2 +- src/pages/home/report/ReportActionCompose.js | 2 +- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/components/KeyboardShortcutsModal.js b/src/components/KeyboardShortcutsModal.js index db93f79bc15f..a5454e280f0d 100644 --- a/src/components/KeyboardShortcutsModal.js +++ b/src/components/KeyboardShortcutsModal.js @@ -34,18 +34,26 @@ const defaultProps = { class KeyboardShortcutsModal extends React.Component { componentDidMount() { - const shortcutConfig = CONST.KEYBOARD_SHORTCUTS.SHORTCUT_MODAL; - this.unsubscribeShortcutModal = KeyboardShortcut.subscribe(shortcutConfig.shortcutKey, () => { + const openShortcutModalConfig = CONST.KEYBOARD_SHORTCUTS.SHORTCUT_MODAL; + this.unsubscribeShortcutModal = KeyboardShortcut.subscribe(openShortcutModalConfig.shortcutKey, () => { ModalActions.close(); KeyboardShortcutsActions.showKeyboardShortcutModal(); - }, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true); + }, openShortcutModalConfig.descriptionKey, openShortcutModalConfig.modifiers, true); + + const closeShortcutModalConfig = CONST.KEYBOARD_SHORTCUTS.ESCAPE; + this.unsubscribeEscapeModal = KeyboardShortcut.subscribe(closeShortcutModalConfig.shortcutKey, () => { + ModalActions.close(); + KeyboardShortcutsActions.hideKeyboardShortcutModal(); + }, closeShortcutModalConfig.descriptionKey, closeShortcutModalConfig.modifiers, true, true); } componentWillUnmount() { - if (!this.unsubscribeShortcutModal) { - return; + if (this.unsubscribeShortcutModal) { + this.unsubscribeShortcutModal(); + } + if (this.unsubscribeEscapeModal) { + this.unsubscribeEscapeModal(); } - this.unsubscribeShortcutModal(); } /** diff --git a/src/components/ScreenWrapper/index.js b/src/components/ScreenWrapper/index.js index 5c83dda89619..44fd9c3db22e 100644 --- a/src/components/ScreenWrapper/index.js +++ b/src/components/ScreenWrapper/index.js @@ -36,7 +36,7 @@ class ScreenWrapper extends React.Component { } Navigation.dismissModal(); - }, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true); + }, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true, true); this.unsubscribeTransitionStart = this.props.navigation.addListener('transitionStart', () => { Navigation.setIsNavigating(true); diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index 843c8586c3df..f9af754e896b 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -177,7 +177,7 @@ class ReportActionCompose extends React.Component { } this.updateComment(''); - }, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true); + }, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true, true); this.setMaxLines(); this.updateComment(this.comment); From e0340815caed09139f3b937bab5acdb21fce8c38 Mon Sep 17 00:00:00 2001 From: azimgd Date: Wed, 29 Mar 2023 02:36:30 +0500 Subject: [PATCH 31/38] Update android/app/src/main/java/com/expensify/chat/MainActivity.java Co-authored-by: Andrew Gable --- .../app/src/main/java/com/expensify/chat/MainActivity.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/java/com/expensify/chat/MainActivity.java b/android/app/src/main/java/com/expensify/chat/MainActivity.java index a3861d191de7..5f9ce2ba92c4 100644 --- a/android/app/src/main/java/com/expensify/chat/MainActivity.java +++ b/android/app/src/main/java/com/expensify/chat/MainActivity.java @@ -67,7 +67,9 @@ protected void onCreate(Bundle savedInstanceState) { @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // disabling hardware ESCAPE support which is handled by Android - if (event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE) { return false; } + if (event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE) { + return false; + } KeyCommandModule.getInstance().onKeyDownEvent(keyCode, event); return super.onKeyDown(keyCode, event); } From 4dd7d6216139f0d1985aee1dc7dd24ddcf84e481 Mon Sep 17 00:00:00 2001 From: azimgd Date: Wed, 29 Mar 2023 04:23:24 +0500 Subject: [PATCH 32/38] Update android/app/src/main/java/com/expensify/chat/MainActivity.java Co-authored-by: Rajat Parashar --- android/app/src/main/java/com/expensify/chat/MainActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/app/src/main/java/com/expensify/chat/MainActivity.java b/android/app/src/main/java/com/expensify/chat/MainActivity.java index 5f9ce2ba92c4..8a1168c3bd48 100644 --- a/android/app/src/main/java/com/expensify/chat/MainActivity.java +++ b/android/app/src/main/java/com/expensify/chat/MainActivity.java @@ -66,7 +66,7 @@ protected void onCreate(Bundle savedInstanceState) { */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { - // disabling hardware ESCAPE support which is handled by Android + // Disabling hardware ESCAPE support which is handled by Android if (event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE) { return false; } From a18b07da53405293983d7baad634cb2a9649109d Mon Sep 17 00:00:00 2001 From: azimgd Date: Fri, 31 Mar 2023 05:22:33 +0500 Subject: [PATCH 33/38] validate shortcutTrigger existance --- src/libs/KeyboardShortcut/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libs/KeyboardShortcut/index.js b/src/libs/KeyboardShortcut/index.js index b9672f29e406..9ffd01bbc406 100644 --- a/src/libs/KeyboardShortcut/index.js +++ b/src/libs/KeyboardShortcut/index.js @@ -60,6 +60,11 @@ function getDisplayName(key, modifiers) { _.each(CONST.KEYBOARD_SHORTCUTS, (shortcut) => { const shortcutTrigger = lodashGet(shortcut, ['trigger', operatingSystem], lodashGet(shortcut, 'trigger.DEFAULT')); + // If there is no trigger for the current OS nor a default trigger, then we don't need to do anything + if (!shortcutTrigger) { + return; + } + KeyCommand.addListener( shortcutTrigger, (keycommandEvent, event) => bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEvent, event), From adbd53cb8495101badc543e34547f8805a281cf4 Mon Sep 17 00:00:00 2001 From: azimgd Date: Fri, 31 Mar 2023 15:19:56 +0500 Subject: [PATCH 34/38] bump react-native-key-command --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3c4ec5d150dd..65f0a80945d6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -70,7 +70,7 @@ "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^5.0.2", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972", - "react-native-key-command": "^0.8.0", + "react-native-key-command": "^0.9.0", "react-native-modal": "^13.0.0", "react-native-onyx": "1.0.36", "react-native-pdf": "^6.6.2", @@ -37557,9 +37557,9 @@ "license": "MIT" }, "node_modules/react-native-key-command": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.8.0.tgz", - "integrity": "sha512-yUZwOk/OoLLyOIyVAiPN4l+Fdhv28H0Q+vyAI71V8ccVDXLLdC4YfjBPFZFW6RX05qdKMGEBL2g4OF5eWfz6Sg==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.9.0.tgz", + "integrity": "sha512-lS9tSNiOt8jO2ngeFY2aTKHxQhvyWY5Bk0S0YV7hQqgk01F1tNvk0Bczalmn30u4Di6gbksKwUQUblwKyx9wow==", "dependencies": { "events": "^3.3.0", "underscore": "^1.13.4" @@ -73531,9 +73531,9 @@ "from": "react-native-image-size@git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972" }, "react-native-key-command": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.8.0.tgz", - "integrity": "sha512-yUZwOk/OoLLyOIyVAiPN4l+Fdhv28H0Q+vyAI71V8ccVDXLLdC4YfjBPFZFW6RX05qdKMGEBL2g4OF5eWfz6Sg==", + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.9.0.tgz", + "integrity": "sha512-lS9tSNiOt8jO2ngeFY2aTKHxQhvyWY5Bk0S0YV7hQqgk01F1tNvk0Bczalmn30u4Di6gbksKwUQUblwKyx9wow==", "requires": { "events": "^3.3.0", "underscore": "^1.13.4" diff --git a/package.json b/package.json index 1600cf15d45d..093b5c845cc8 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^5.0.2", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972", - "react-native-key-command": "^0.8.0", + "react-native-key-command": "^0.9.0", "react-native-modal": "^13.0.0", "react-native-onyx": "1.0.36", "react-native-pdf": "^6.6.2", From 298805ae0ff568a6f1720a6ba4d48d142d8458e6 Mon Sep 17 00:00:00 2001 From: azimgd Date: Fri, 31 Mar 2023 20:19:44 +0500 Subject: [PATCH 35/38] update podfile --- ios/Podfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 3fc2b5215c02..93e5952ec593 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -487,7 +487,7 @@ PODS: - React - react-native-image-picker (5.0.2): - React-Core - - react-native-key-command (0.8.0): + - react-native-key-command (0.9.0): - React-Core - react-native-netinfo (8.3.1): - React-Core @@ -1022,7 +1022,7 @@ SPEC CHECKSUMS: react-native-flipper: dc5290261fbeeb2faec1bdc57ae6dd8d562e1de4 react-native-image-manipulator: c48f64221cfcd46e9eec53619c4c0374f3328a56 react-native-image-picker: a5dddebb4d2955ac4712a4ed66b00a85f62a63ac - react-native-key-command: daf2ab522c266db74bf2c2804883620379ed08b5 + react-native-key-command: fc8c541a9612c5ce98a6af882774cc809ecf0ce7 react-native-netinfo: 1a6035d3b9780221d407c277ebfb5722ace00658 react-native-pdf: 33c622cbdf776a649929e8b9d1ce2d313347c4fa react-native-performance: 224bd53e6a835fda4353302cf891d088a0af7406 From b384dbb62b656aaa1e065035089592d5b571d61a Mon Sep 17 00:00:00 2001 From: azimgd Date: Thu, 13 Apr 2023 21:26:15 +0500 Subject: [PATCH 36/38] react-native-keycommand version bump --- ios/Podfile.lock | 8 ++++---- package-lock.json | 20 ++++++++++---------- package.json | 2 +- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 919f1972bc50..86707162d74c 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -514,7 +514,7 @@ PODS: - React - react-native-image-picker (5.1.0): - React-Core - - react-native-key-command (0.9.0): + - react-native-key-command (0.9.1): - React-Core - react-native-netinfo (8.3.1): - React-Core @@ -1007,7 +1007,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Airship: 19ead2c0bdc791c1b9d6ebb7940aaac99614414e AirshipFrameworkProxy: 037a0ad6491757c45de2c70a6cc47bae5fcfa32b - boost: 57d2868c099736d80fcd648bf211b4431e51a558 + boost: a7c83b31436843459a1961bfd74b96033dc77234 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 FBLazyVector: ff54429f0110d3c722630a98096ba689c39f6d5f @@ -1050,7 +1050,7 @@ SPEC CHECKSUMS: Permission-LocationWhenInUse: 3ba99e45c852763f730eabecec2870c2382b7bd4 Plaid: 7d340abeadb46c7aa1a91f896c5b22395a31fcf2 PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef - RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 + RCT-Folly: 0080d0a6ebf2577475bda044aa59e2ca1f909cda RCTRequired: e9e7b8b45aa9bedb2fdad71740adf07a7265b9be RCTTypeSafety: 9ae0e9206625e995f0df4d5b9ddc94411929fb30 React: a71c8e1380f07e01de721ccd52bcf9c03e81867d @@ -1072,7 +1072,7 @@ SPEC CHECKSUMS: react-native-flipper: dc5290261fbeeb2faec1bdc57ae6dd8d562e1de4 react-native-image-manipulator: c48f64221cfcd46e9eec53619c4c0374f3328a56 react-native-image-picker: c33d4e79f0a14a2b66e5065e14946ae63749660b - react-native-key-command: fc8c541a9612c5ce98a6af882774cc809ecf0ce7 + react-native-key-command: e49d6e44d44705779696d8d3a5ac6b9e3a198941 react-native-netinfo: 1a6035d3b9780221d407c277ebfb5722ace00658 react-native-pdf: 33c622cbdf776a649929e8b9d1ce2d313347c4fa react-native-performance: 224bd53e6a835fda4353302cf891d088a0af7406 diff --git a/package-lock.json b/package-lock.json index cebf90c7e89d..e27ede6ea085 100644 --- a/package-lock.json +++ b/package-lock.json @@ -70,7 +70,7 @@ "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^5.1.0", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972", - "react-native-key-command": "^0.9.0", + "react-native-key-command": "^0.9.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", "react-native-onyx": "1.0.38", @@ -34670,18 +34670,18 @@ "license": "MIT" }, "node_modules/react-native-key-command": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.9.0.tgz", - "integrity": "sha512-lS9tSNiOt8jO2ngeFY2aTKHxQhvyWY5Bk0S0YV7hQqgk01F1tNvk0Bczalmn30u4Di6gbksKwUQUblwKyx9wow==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.9.1.tgz", + "integrity": "sha512-di7G5q66eI0xL14B4kcVfm7azGET07henwu21N8hb71sZpDZGsAJ1WFuR32SwbnkLVNhEk7FJAIH/5Sh+dDQoA==", "dependencies": { "events": "^3.3.0", "underscore": "^1.13.4" }, "peerDependencies": { - "react": "18.1.0", + "react": "^18.1.0", "react-dom": "18.1.0", - "react-native": "0.70.4", - "react-native-web": "0.18.1" + "react-native": "^0.70.4", + "react-native-web": "^0.18.1" } }, "node_modules/react-native-localize": { @@ -64347,9 +64347,9 @@ "from": "react-native-image-size@git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972" }, "react-native-key-command": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.9.0.tgz", - "integrity": "sha512-lS9tSNiOt8jO2ngeFY2aTKHxQhvyWY5Bk0S0YV7hQqgk01F1tNvk0Bczalmn30u4Di6gbksKwUQUblwKyx9wow==", + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-0.9.1.tgz", + "integrity": "sha512-di7G5q66eI0xL14B4kcVfm7azGET07henwu21N8hb71sZpDZGsAJ1WFuR32SwbnkLVNhEk7FJAIH/5Sh+dDQoA==", "requires": { "events": "^3.3.0", "underscore": "^1.13.4" diff --git a/package.json b/package.json index 88097e21f820..63e0647f8587 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^5.1.0", "react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#6b5ab5110dc3ed554f8eafbc38d7d87c17147972", - "react-native-key-command": "^0.9.0", + "react-native-key-command": "^0.9.1", "react-native-localize": "^2.2.6", "react-native-modal": "^13.0.0", "react-native-onyx": "1.0.38", From 8c903730c7ab0dc4d07e6e2e91b566da8c53dbb6 Mon Sep 17 00:00:00 2001 From: azimgd Date: Thu, 13 Apr 2023 21:36:59 +0500 Subject: [PATCH 37/38] unroll reportactioncompose change --- src/pages/home/report/ReportActionCompose.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js index ab8d853daa6e..8bf3a9ee354e 100644 --- a/src/pages/home/report/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose.js @@ -222,7 +222,7 @@ class ReportActionCompose extends React.Component { } this.updateComment('', true); - }, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true, true); + }, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true); this.setMaxLines(); this.updateComment(this.comment); From e73d257545871146ef510f79742e7abcd1c2320d Mon Sep 17 00:00:00 2001 From: azimgd Date: Thu, 13 Apr 2023 21:43:24 +0500 Subject: [PATCH 38/38] apply reverted ReportActionCompose subscriber change --- src/pages/home/report/ReportActionCompose/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/report/ReportActionCompose/index.js b/src/pages/home/report/ReportActionCompose/index.js index 741bf50d1056..5914ed916d91 100644 --- a/src/pages/home/report/ReportActionCompose/index.js +++ b/src/pages/home/report/ReportActionCompose/index.js @@ -228,7 +228,7 @@ class ReportActionCompose extends React.Component { } this.updateComment('', true); - }, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true); + }, shortcutConfig.descriptionKey, shortcutConfig.modifiers, true, true); this.setMaxLines(); this.updateComment(this.comment);