diff --git a/android/app/build.gradle b/android/app/build.gradle index 794cabd15..ff92aa27c 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -263,7 +263,9 @@ dependencies { implementation project(':@sentry_react-native') implementation project(':react-native-android-open-settings') implementation project(':react-native-haptic-feedback') + implementation project(':react-native-hw-keyboard-event') implementation project(':react-native-permissions') + implementation project(':react-native-fast-image') // For animated GIF support diff --git a/android/app/src/main/java/com/mattermost/rnbeta/MainActivity.java b/android/app/src/main/java/com/mattermost/rnbeta/MainActivity.java index c1ec6b302..41508156a 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/MainActivity.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/MainActivity.java @@ -4,6 +4,8 @@ import android.os.Bundle; import androidx.annotation.Nullable; import com.reactnativenavigation.NavigationActivity; +import android.view.KeyEvent; +import com.github.emilioicai.hwkeyboardevent.HWKeyboardEventModule; public class MainActivity extends NavigationActivity { @Override @@ -11,4 +13,19 @@ public class MainActivity extends NavigationActivity { super.onCreate(savedInstanceState); setContentView(R.layout.launch_screen); } + + /* + https://mattermost.atlassian.net/browse/MM-10601 + Required by react-native-hw-keyboard-event + (https://github.com/emilioicai/react-native-hw-keyboard-event) + */ + @Override + public boolean dispatchKeyEvent(KeyEvent event) { + if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER && event.getAction() == KeyEvent.ACTION_UP) { + String keyPressed = event.isShiftPressed() ? "shift-enter" : "enter"; + HWKeyboardEventModule.getInstance().keyPressed(keyPressed); + return true; + } + return super.dispatchKeyEvent(event); + }; } diff --git a/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java b/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java index a3881fe93..230f8195a 100644 --- a/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java +++ b/android/app/src/main/java/com/mattermost/rnbeta/MainApplication.java @@ -6,6 +6,7 @@ import android.content.Context; import android.content.RestrictionsManager; import android.os.Bundle; import android.util.Log; +import android.view.KeyEvent; import java.io.File; import java.util.HashMap; import java.util.Arrays; @@ -69,6 +70,8 @@ import com.facebook.soloader.SoLoader; import com.mattermost.share.RealPathUtil; +import com.github.emilioicai.hwkeyboardevent.HWKeyboardEventPackage; + public class MainApplication extends NavigationApplication implements INotificationsApplication, INotificationsDrawerApplication { public static MainApplication instance; @@ -202,7 +205,8 @@ public class MainApplication extends NavigationApplication implements INotificat new LinearGradientPackage(), new ReactVideoPackage(), new RNGestureHandlerPackage(), - new RNPasteableTextInputPackage() + new RNPasteableTextInputPackage(), + new HWKeyboardEventPackage() ); } diff --git a/android/settings.gradle b/android/settings.gradle index 36dff8af6..be7912111 100644 --- a/android/settings.gradle +++ b/android/settings.gradle @@ -53,3 +53,5 @@ include ':@react-native-community_async-storage' project(':@react-native-community_async-storage').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/async-storage/android') include ':@react-native-community_netinfo' project(':@react-native-community_netinfo').projectDir = new File(rootProject.projectDir, '../node_modules/@react-native-community/netinfo/android') +include ':react-native-hw-keyboard-event' +project(':react-native-hw-keyboard-event').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-hw-keyboard-event/android') diff --git a/app/components/post_textbox/post_textbox_base.js b/app/components/post_textbox/post_textbox_base.js index 1fe70d29c..0b3209284 100644 --- a/app/components/post_textbox/post_textbox_base.js +++ b/app/components/post_textbox/post_textbox_base.js @@ -21,6 +21,7 @@ import { import {intlShape} from 'react-intl'; import RNFetchBlob from 'rn-fetch-blob'; import Button from 'react-native-button'; +import HWKeyboardEvent from 'react-native-hw-keyboard-event'; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import slashForwardBoxIcon from 'assets/images/icons/slash-forward-box.png'; @@ -129,6 +130,7 @@ export default class PostTextBoxBase extends PureComponent { EventEmitter.on(event, this.handleInsertTextToDraft); AppState.addEventListener('change', this.handleAppStateChange); + HWKeyboardEvent.onHWKeyPressed(this.handleHardwareEnterPress); if (Platform.OS === 'android') { Keyboard.addListener('keyboardDidHide', this.handleAndroidKeyboard); @@ -156,6 +158,7 @@ export default class PostTextBoxBase extends PureComponent { EventEmitter.off(event, this.handleInsertTextToDraft); AppState.removeEventListener('change', this.handleAppStateChange); + HWKeyboardEvent.removeOnHWKeyPressed(); if (Platform.OS === 'android') { Keyboard.removeListener('keyboardDidHide', this.handleAndroidKeyboard); @@ -375,6 +378,14 @@ export default class PostTextBoxBase extends PureComponent { this.blur(); }; + handleHardwareEnterPress = (keyEvent) => { + switch (keyEvent.pressedKey) { + case 'enter': this.handleSendMessage(); + break; + case 'shift-enter': this.handleInsertTextToDraft('\n'); + } + } + handleAndroidBack = () => { const {channelId, files, rootId} = this.props; if (files.length) { diff --git a/ios/Mattermost/AppDelegate.m b/ios/Mattermost/AppDelegate.m index 4ae336881..433d5771a 100644 --- a/ios/Mattermost/AppDelegate.m +++ b/ios/Mattermost/AppDelegate.m @@ -18,6 +18,7 @@ #import #import "Mattermost-Swift.h" #import +#import @implementation AppDelegate @@ -139,4 +140,30 @@ NSString* const NOTIFICATION_UPDATE_BADGE_ACTION = @"update_badge"; restorationHandler:restorationHandler]; } +/* + https://mattermost.atlassian.net/browse/MM-10601 + Required by react-native-hw-keyboard-event + (https://github.com/emilioicai/react-native-hw-keyboard-event) +*/ +RNHWKeyboardEvent *hwKeyEvent = nil; +- (NSMutableArray *)keyCommands { + NSMutableArray *keys = [NSMutableArray new]; + if (hwKeyEvent == nil) { + hwKeyEvent = [[RNHWKeyboardEvent alloc] init]; + } + if ([hwKeyEvent isListening]) { + [keys addObject: [UIKeyCommand keyCommandWithInput:@"\r" modifierFlags:0 action:@selector(sendEnter:)]]; + [keys addObject: [UIKeyCommand keyCommandWithInput:@"\r" modifierFlags:UIKeyModifierShift action:@selector(sendShiftEnter:)]]; + } + return keys; +} + +- (void)sendEnter:(UIKeyCommand *)sender { + NSString *selected = sender.input; + [hwKeyEvent sendHWKeyEvent:@"enter"]; +} +- (void)sendShiftEnter:(UIKeyCommand *)sender { + NSString *selected = sender.input; + [hwKeyEvent sendHWKeyEvent:@"shift-enter"]; +} @end diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 2d3a72dfb..e64f26a20 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -210,6 +210,8 @@ PODS: - React - react-native-document-picker (3.2.4): - React + - react-native-hw-keyboard-event (0.0.4): + - React - react-native-image-picker (2.0.0): - React - react-native-local-auth (1.5.0): @@ -335,6 +337,7 @@ DEPENDENCIES: - "react-native-cameraroll (from `../node_modules/@react-native-community/cameraroll`)" - react-native-cookies (from `../node_modules/react-native-cookies/ios`) - react-native-document-picker (from `../node_modules/react-native-document-picker`) + - react-native-hw-keyboard-event (from `../node_modules/react-native-hw-keyboard-event`) - react-native-image-picker (from `../node_modules/react-native-image-picker`) - react-native-local-auth (from `../node_modules/react-native-local-auth`) - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" @@ -430,6 +433,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-cookies/ios" react-native-document-picker: :path: "../node_modules/react-native-document-picker" + react-native-hw-keyboard-event: + :path: "../node_modules/react-native-hw-keyboard-event" react-native-image-picker: :path: "../node_modules/react-native-image-picker" react-native-local-auth: @@ -523,6 +528,7 @@ SPEC CHECKSUMS: react-native-cameraroll: ad20f5a93c25cb83a76455df57a2c62fbb63aaed react-native-cookies: 854d59c4135c70b92a02ca4930e68e4e2eb58150 react-native-document-picker: c36bf5f067a581657ecaf7124dcd921a8be19061 + react-native-hw-keyboard-event: b517cefb8d5c659a38049c582de85ff43337dc53 react-native-image-picker: ba7fe85b3373ff33d4827210d989dfcbbd68f7f9 react-native-local-auth: 5081a70211643de74bb207e007401a0c81b37a20 react-native-netinfo: 892a5130be97ff8bb69c523739c424a2ffc296d1 diff --git a/package-lock.json b/package-lock.json index 8b6b94514..e4b1a997d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7065,8 +7065,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -7084,13 +7083,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -7103,18 +7100,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -7217,8 +7211,7 @@ }, "inherits": { "version": "2.0.3", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -7228,7 +7221,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -7241,20 +7233,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.3.5", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -7271,7 +7260,6 @@ "mkdirp": { "version": "0.5.1", "bundled": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -7344,8 +7332,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -7355,7 +7342,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -7431,8 +7417,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -7462,7 +7447,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -7480,7 +7464,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -7519,13 +7502,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.0.3", - "bundled": true, - "optional": true + "bundled": true } } }, @@ -12740,6 +12721,11 @@ "resolved": "https://registry.npmjs.org/react-native-haptic-feedback/-/react-native-haptic-feedback-1.8.2.tgz", "integrity": "sha512-arY2vsQtcF6Z/HggcfASTFzXm5HLUvK08rj6xPs6b95mpUDyStxEoC2c6MCFx+GSqnpBuOQvQCf42Zp0ATnWoQ==" }, + "react-native-hw-keyboard-event": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/react-native-hw-keyboard-event/-/react-native-hw-keyboard-event-0.0.4.tgz", + "integrity": "sha512-G8qp0nm17PHigLb/axgdF9xg51BKCG2p1AGeq//J/luLp5zNczIcQJh+nm02R1MeEUE3e53wqO4LMe0MV3raZg==" + }, "react-native-image-gallery": { "version": "github:mattermost/react-native-image-gallery#c1a9f7118e90cc87d47620bc0584c9cac4b0cf38", "from": "github:mattermost/react-native-image-gallery#c1a9f7118e90cc87d47620bc0584c9cac4b0cf38", diff --git a/package.json b/package.json index ef701a66f..d6946f323 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "react-native-fast-image": "7.0.2", "react-native-gesture-handler": "1.5.3", "react-native-haptic-feedback": "1.8.2", + "react-native-hw-keyboard-event": "0.0.4", "react-native-image-gallery": "github:mattermost/react-native-image-gallery#c1a9f7118e90cc87d47620bc0584c9cac4b0cf38", "react-native-image-picker": "2.0.0", "react-native-keyboard-aware-scroll-view": "0.9.1",