diff --git a/app/containers/EmojiPicker/EmojiCategory.tsx b/app/containers/EmojiPicker/EmojiCategory.tsx index a7fb07b11..a1cf1f981 100644 --- a/app/containers/EmojiPicker/EmojiCategory.tsx +++ b/app/containers/EmojiPicker/EmojiCategory.tsx @@ -65,6 +65,7 @@ class EmojiCategory extends React.Component { initialNumToRender={45} removeClippedSubviews {...scrollPersistTaps} + keyboardDismissMode={'none'} /> ); } diff --git a/app/containers/EmojiPicker/index.tsx b/app/containers/EmojiPicker/index.tsx index 4bfa17b6a..558a23bb4 100644 --- a/app/containers/EmojiPicker/index.tsx +++ b/app/containers/EmojiPicker/index.tsx @@ -17,7 +17,7 @@ import protectedFunction from '../../lib/methods/helpers/protectedFunction'; import shortnameToUnicode from '../../lib/methods/helpers/shortnameToUnicode'; import log from '../../lib/methods/helpers/log'; import { themes } from '../../lib/constants'; -import { TSupportedThemes, withTheme } from '../../theme'; +import { TSupportedThemes } from '../../theme'; import { IEmoji, TGetCustomEmoji, IApplicationState, ICustomEmojis, TFrequentlyUsedEmojiModel } from '../../definitions'; interface IEmojiPickerProps { @@ -198,7 +198,8 @@ class EmojiPicker extends Component { } const mapStateToProps = (state: IApplicationState) => ({ - customEmojis: state.customEmojis + customEmojis: state.customEmojis, + baseUrl: state.share.server.server || state.server.server }); -export default connect(mapStateToProps)(withTheme(EmojiPicker)); +export default connect(mapStateToProps)(EmojiPicker); diff --git a/app/containers/MessageBox/EmojiKeyboard.tsx b/app/containers/MessageBox/EmojiKeyboard.tsx index 172b7f4b8..114733eeb 100644 --- a/app/containers/MessageBox/EmojiKeyboard.tsx +++ b/app/containers/MessageBox/EmojiKeyboard.tsx @@ -1,39 +1,28 @@ import React from 'react'; import { View } from 'react-native'; import { KeyboardRegistry } from 'react-native-ui-lib/keyboard'; +import { Provider } from 'react-redux'; -import { store } from '../../lib/store/auxStore'; +import store from '../../lib/store'; import EmojiPicker from '../EmojiPicker'; import styles from './styles'; import { themes } from '../../lib/constants'; -import { TSupportedThemes, withTheme } from '../../theme'; +import { TSupportedThemes } from '../../theme'; -interface IMessageBoxEmojiKeyboard { - theme: TSupportedThemes; -} - -export default class EmojiKeyboard extends React.PureComponent { - private readonly baseUrl: string; - - constructor(props: IMessageBoxEmojiKeyboard) { - super(props); - const state = store.getState(); - this.baseUrl = state.share.server.server || state.server.server; - } - - onEmojiSelected = (emoji: string) => { +const EmojiKeyboard = ({ theme }: { theme: TSupportedThemes }) => { + const onEmojiSelected = (emoji: string) => { KeyboardRegistry.onItemSelected('EmojiKeyboard', { emoji }); }; - render() { - const { theme } = this.props; - return ( + return ( + - + - ); - } -} -KeyboardRegistry.registerKeyboard('EmojiKeyboard', () => withTheme(EmojiKeyboard)); + + ); +}; + +KeyboardRegistry.registerKeyboard('EmojiKeyboard', () => EmojiKeyboard); diff --git a/app/containers/MessageBox/LeftButtons.ios.tsx b/app/containers/MessageBox/LeftButtons.ios.tsx deleted file mode 100644 index 94d253705..000000000 --- a/app/containers/MessageBox/LeftButtons.ios.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import { View } from 'react-native'; - -import { ActionsButton, CancelEditingButton } from './buttons'; -import styles from './styles'; - -interface IMessageBoxLeftButtons { - showMessageBoxActions(): void; - editing: boolean; - editCancel(): void; - isActionsEnabled: boolean; -} - -const LeftButtons = React.memo(({ showMessageBoxActions, editing, editCancel, isActionsEnabled }: IMessageBoxLeftButtons) => { - if (editing) { - return ; - } - if (isActionsEnabled) { - return ; - } - return ; -}); - -export default LeftButtons; diff --git a/app/containers/MessageBox/LeftButtons.android.tsx b/app/containers/MessageBox/LeftButtons.tsx similarity index 100% rename from app/containers/MessageBox/LeftButtons.android.tsx rename to app/containers/MessageBox/LeftButtons.tsx diff --git a/app/containers/MessageBox/RecordAudio.tsx b/app/containers/MessageBox/RecordAudio.tsx index 4b550b62b..1dd5e99ec 100644 --- a/app/containers/MessageBox/RecordAudio.tsx +++ b/app/containers/MessageBox/RecordAudio.tsx @@ -17,6 +17,7 @@ interface IMessageBoxRecordAudioProps { permissionToUpload: boolean; recordingCallback: Function; onFinish: Function; + onStart: Function; } const RECORDING_EXTENSION = '.m4a'; @@ -116,6 +117,9 @@ export default class RecordAudio extends React.PureComponent { + const { onStart } = this.props; + onStart(); + logEvent(events.ROOM_AUDIO_RECORD); if (!this.isRecorderBusy) { this.isRecorderBusy = true; diff --git a/app/containers/MessageBox/RightButtons.ios.tsx b/app/containers/MessageBox/RightButtons.ios.tsx deleted file mode 100644 index f2cf2bca5..000000000 --- a/app/containers/MessageBox/RightButtons.ios.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; - -import { SendButton } from './buttons'; - -interface IMessageBoxRightButtons { - showSend: boolean; - submit(): void; -} - -const RightButtons = ({ showSend, submit }: IMessageBoxRightButtons) => { - if (showSend) { - return ; - } - return null; -}; - -export default RightButtons; diff --git a/app/containers/MessageBox/RightButtons.android.tsx b/app/containers/MessageBox/RightButtons.tsx similarity index 83% rename from app/containers/MessageBox/RightButtons.android.tsx rename to app/containers/MessageBox/RightButtons.tsx index 4af8d5027..d19109e61 100644 --- a/app/containers/MessageBox/RightButtons.android.tsx +++ b/app/containers/MessageBox/RightButtons.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { View } from 'react-native'; +import { isIOS } from '../../lib/methods/helpers'; import { ActionsButton, SendButton } from './buttons'; import styles from './styles'; @@ -18,7 +19,7 @@ const RightButtons = React.memo(({ showSend, submit, showMessageBoxActions, isAc if (isActionsEnabled) { return ; } - return ; + return !isIOS ? : null; }); export default RightButtons; diff --git a/app/containers/MessageBox/constants.ts b/app/containers/MessageBox/constants.ts index dabaee497..c966c60ce 100644 --- a/app/containers/MessageBox/constants.ts +++ b/app/containers/MessageBox/constants.ts @@ -4,3 +4,5 @@ export const MENTIONS_TRACKING_TYPE_COMMANDS = '/'; export const MENTIONS_TRACKING_TYPE_ROOMS = '#'; export const MENTIONS_TRACKING_TYPE_CANNED = '!'; export const MENTIONS_COUNT_TO_DISPLAY = 4; + +export const TIMEOUT_CLOSE_EMOJI = 300; diff --git a/app/containers/MessageBox/index.tsx b/app/containers/MessageBox/index.tsx index 107edd64d..e42c30905 100644 --- a/app/containers/MessageBox/index.tsx +++ b/app/containers/MessageBox/index.tsx @@ -19,11 +19,7 @@ import RecordAudio from './RecordAudio'; import I18n from '../../i18n'; import ReplyPreview from './ReplyPreview'; import { themes } from '../../lib/constants'; -// @ts-ignore -// eslint-disable-next-line import/extensions,import/no-unresolved import LeftButtons from './LeftButtons'; -// @ts-ignore -// eslint-disable-next-line import/extensions,import/no-unresolved import RightButtons from './RightButtons'; import { canUploadFile } from '../../lib/methods/helpers/media'; import EventEmiter from '../../lib/methods/helpers/events'; @@ -37,12 +33,13 @@ import { MENTIONS_TRACKING_TYPE_COMMANDS, MENTIONS_TRACKING_TYPE_EMOJIS, MENTIONS_TRACKING_TYPE_ROOMS, - MENTIONS_TRACKING_TYPE_USERS + MENTIONS_TRACKING_TYPE_USERS, + TIMEOUT_CLOSE_EMOJI } from './constants'; import CommandsPreview from './CommandsPreview'; import { getUserSelector } from '../../selectors/login'; import Navigation from '../../lib/navigation/appNavigation'; -import { withActionSheet } from '../ActionSheet'; +import { TActionSheetOptionsItem, withActionSheet } from '../ActionSheet'; import { sanitizeLikeString } from '../../lib/database/utils'; import { CustomIcon } from '../CustomIcon'; import { forceJpgExtension } from './forceJpgExtension'; @@ -58,14 +55,12 @@ import { } from '../../definitions'; import { MasterDetailInsideStackParamList } from '../../stacks/MasterDetailStack/types'; import { getPermalinkMessage, search, sendFileMessage } from '../../lib/methods'; -import { hasPermission, debounce, isAndroid, isTablet } from '../../lib/methods/helpers'; +import { hasPermission, debounce, isAndroid, isIOS, isTablet } from '../../lib/methods/helpers'; import { Services } from '../../lib/services'; import { TSupportedThemes } from '../../theme'; import { ChatsStackParamList } from '../../stacks/types'; -if (isAndroid) { - require('./EmojiKeyboard'); -} +require('./EmojiKeyboard'); const imagePickerConfig = { cropping: true, @@ -270,6 +265,7 @@ class MessageBox extends Component { }, 500); }); this.unsubscribeBlur = navigation.addListener('blur', () => { + this.closeEmoji(); this.component?.blur(); }); } @@ -330,6 +326,9 @@ class MessageBox extends Component { if (nextProps.theme !== theme) { return true; } + if (nextState.showEmojiKeyboard !== showEmojiKeyboard) { + return true; + } if (!isFocused()) { return false; } @@ -342,9 +341,6 @@ class MessageBox extends Component { if (nextProps.editing !== editing) { return true; } - if (nextState.showEmojiKeyboard !== showEmojiKeyboard) { - return true; - } if (nextState.trackingType !== trackingType) { return true; } @@ -809,7 +805,7 @@ class MessageBox extends Component { const { permissionToUpload } = this.state; const { showActionSheet, goToCannedResponses } = this.props; - const options = []; + const options: TActionSheetOptionsItem[] = []; if (goToCannedResponses) { options.push({ title: I18n.t('Canned_Responses'), @@ -847,7 +843,8 @@ class MessageBox extends Component { icon: 'discussions', onPress: this.createDiscussion }); - showActionSheet({ options }); + + this.closeEmojiAndAction(showActionSheet, { options }); }; editCancel = () => { @@ -883,6 +880,13 @@ class MessageBox extends Component { this.setState({ showEmojiKeyboard: false }); }; + closeEmojiAndAction = (action?: Function, params?: any) => { + const { showEmojiKeyboard } = this.state; + + this.closeEmoji(); + setTimeout(() => action && action(params), showEmojiKeyboard && isIOS ? TIMEOUT_CLOSE_EMOJI : null); + }; + submit = async () => { const { tshow } = this.state; const { onSubmit, rid: roomId, tmid, showSend, sharing } = this.props; @@ -1089,6 +1093,7 @@ class MessageBox extends Component { recordingCallback={this.recordingCallback} onFinish={this.finishAudioMessage} permissionToUpload={permissionToUpload} + onStart={this.closeEmoji} /> ); @@ -1112,14 +1117,11 @@ class MessageBox extends Component { const textInputAndButtons = !recording ? ( <> (this.component = component)} @@ -1138,7 +1140,6 @@ class MessageBox extends Component { {...isAndroidTablet} /> { renderContent={this.renderContent} kbInputRef={this.component} kbComponent={showEmojiKeyboard ? 'EmojiKeyboard' : null} + kbInitialProps={{ theme }} onKeyboardResigned={this.onKeyboardResigned} onItemSelected={this.onEmojiSelected} trackInteractive diff --git a/app/containers/message/index.tsx b/app/containers/message/index.tsx index 7af7f0899..e123bb34a 100644 --- a/app/containers/message/index.tsx +++ b/app/containers/message/index.tsx @@ -58,6 +58,7 @@ interface IMessageContainerProps { jumpToMessage?: (link: string) => void; onPress?: () => void; theme: TSupportedThemes; + closeEmojiAndAction?: (action?: Function, params?: any) => void; } interface IMessageContainerState { @@ -114,6 +115,14 @@ class MessageContainer extends React.Component { + const { closeEmojiAndAction } = this.props; + + if (closeEmojiAndAction) { + closeEmojiAndAction(this.onPress); + } + }; + onPress = debounce( () => { const { onPress } = this.props; @@ -373,7 +382,7 @@ class MessageContainer extends React.Component { }; render() { - const { width, height, show, baseUrl, reactionClose, isMasterDetail, theme } = this.props; + const { width, height, show, reactionClose, isMasterDetail, theme } = this.props; let widthStyle = width - margin; let heightStyle = Math.min(width, height) - margin * 2; @@ -70,7 +69,7 @@ class ReactionPicker extends React.Component { } ]} testID='reaction-picker'> - + ) : null; @@ -78,7 +77,6 @@ class ReactionPicker extends React.Component { } const mapStateToProps = (state: IApplicationState) => ({ - baseUrl: state.server.server, isMasterDetail: state.app.isMasterDetail }); diff --git a/app/views/RoomView/RightButtons.tsx b/app/views/RoomView/RightButtons.tsx index 6aaabdcc8..308169094 100644 --- a/app/views/RoomView/RightButtons.tsx +++ b/app/views/RoomView/RightButtons.tsx @@ -13,7 +13,7 @@ import { events, logEvent } from '../../lib/methods/helpers/log'; import { isTeamRoom } from '../../lib/methods/helpers/room'; import { IApplicationState, SubscriptionType, TMessageModel, TSubscriptionModel } from '../../definitions'; import { ChatsStackParamList } from '../../stacks/types'; -import { IActionSheetProvider, TActionSheetOptionsItem, withActionSheet } from '../../containers/ActionSheet'; +import { TActionSheetOptionsItem } from '../../containers/ActionSheet'; import i18n from '../../i18n'; import { showConfirmationAlert, showErrorAlert } from '../../lib/methods/helpers'; import { onHoldLivechat, returnLivechat } from '../../lib/services/restApi'; @@ -21,10 +21,10 @@ import { closeLivechat as closeLivechatService } from '../../lib/methods/helpers import { Services } from '../../lib/services'; import { ILivechatDepartment } from '../../definitions/ILivechatDepartment'; -interface IRightButtonsProps extends IActionSheetProvider { +interface IRightButtonsProps { userId?: string; threadsEnabled: boolean; - rid: string; + rid?: string; t: string; tmid?: string; teamId?: string; @@ -34,7 +34,6 @@ interface IRightButtonsProps extends IActionSheetProvider { status?: string; dispatch: Dispatch; encrypted?: boolean; - transferLivechatGuestPermission: boolean; navigation: StackNavigationProp; omnichannelPermissions: { canForwardGuest: boolean; @@ -42,6 +41,7 @@ interface IRightButtonsProps extends IActionSheetProvider { canPlaceLivechatOnHold: boolean; }; livechatRequestComment: boolean; + showActionSheet: Function; departmentId?: string; } @@ -187,34 +187,38 @@ class RightButtonsContainer extends Component { const { rid } = this.props; - showConfirmationAlert({ - message: i18n.t('Would_you_like_to_return_the_inquiry'), - confirmationText: i18n.t('Yes'), - onPress: async () => { - try { - await returnLivechat(rid); - } catch (e: any) { - showErrorAlert(e.reason, i18n.t('Oops')); + if (rid) { + showConfirmationAlert({ + message: i18n.t('Would_you_like_to_return_the_inquiry'), + confirmationText: i18n.t('Yes'), + onPress: async () => { + try { + await returnLivechat(rid); + } catch (e: any) { + showErrorAlert(e.reason, i18n.t('Oops')); + } } - } - }); + }); + } }; placeOnHoldLivechat = () => { const { navigation, rid } = this.props; - showConfirmationAlert({ - title: i18n.t('Are_you_sure_question_mark'), - message: i18n.t('Would_like_to_place_on_hold'), - confirmationText: i18n.t('Yes'), - onPress: async () => { - try { - await onHoldLivechat(rid); - navigation.navigate('RoomsListView'); - } catch (e: any) { - showErrorAlert(e.data?.error, i18n.t('Oops')); + if (rid) { + showConfirmationAlert({ + title: i18n.t('Are_you_sure_question_mark'), + message: i18n.t('Would_like_to_place_on_hold'), + confirmationText: i18n.t('Yes'), + onPress: async () => { + try { + await onHoldLivechat(rid); + navigation.navigate('RoomsListView'); + } catch (e: any) { + showErrorAlert(e.data?.error, i18n.t('Oops')); + } } - } - }); + }); + } }; closeLivechat = async () => { @@ -234,18 +238,20 @@ class RightButtonsContainer extends Component { - if (isMasterDetail) { - navigation.navigate('ModalStackNavigator', { - screen: 'ForwardLivechatView', - params: { rid } - }); - } else { - navigation.navigate('ForwardLivechatView', { rid }); + if (rid) { + if (isMasterDetail) { + navigation.navigate('ModalStackNavigator', { + screen: 'ForwardLivechatView', + params: { rid } + }); + } else { + navigation.navigate('ForwardLivechatView', { rid }); + } } } }); @@ -379,4 +387,4 @@ const mapStateToProps = (state: IApplicationState) => ({ livechatRequestComment: state.settings.Livechat_request_comment_when_closing_conversation as boolean }); -export default connect(mapStateToProps)(withActionSheet(RightButtonsContainer)); +export default connect(mapStateToProps)(RightButtonsContainer); diff --git a/app/views/RoomView/index.tsx b/app/views/RoomView/index.tsx index f12177925..1803974bb 100644 --- a/app/views/RoomView/index.tsx +++ b/app/views/RoomView/index.tsx @@ -99,7 +99,7 @@ import { hasPermission } from '../../lib/methods/helpers'; import { Services } from '../../lib/services'; -import { withActionSheet, TActionSheetOptions } from '../../containers/ActionSheet'; +import { withActionSheet, IActionSheetProvider } from '../../containers/ActionSheet'; type TStateAttrsUpdate = keyof IRoomViewState; @@ -150,7 +150,7 @@ const roomAttrsUpdate = [ 't' ] as TRoomUpdate[]; -interface IRoomViewProps extends IBaseScreen { +interface IRoomViewProps extends IActionSheetProvider, IBaseScreen { user: Pick; appState: string; useRealName?: boolean; @@ -170,7 +170,6 @@ interface IRoomViewProps extends IBaseScreen { transferLivechatGuestPermission?: string[]; // TODO: Check if its the correct type viewCannedResponsesPermission?: string[]; // TODO: Check if its the correct type livechatAllowManualOnHold?: boolean; - showActionSheet: (options: TActionSheetOptions) => void; } interface IRoomViewState { @@ -185,7 +184,7 @@ interface IRoomViewState { fname?: string; prid?: string; joinCodeRequired?: boolean; - status?: boolean; + status?: string; lastMessage?: ILastMessage; sysMes?: boolean; onHold?: boolean; @@ -635,6 +634,7 @@ class RoomView extends React.Component { encrypted={encrypted} navigation={navigation} toggleFollowThread={this.toggleFollowThread} + showActionSheet={this.showActionSheet} departmentId={departmentId} /> ) @@ -785,7 +785,12 @@ class RoomView extends React.Component { }; errorActionsShow = (message: TAnyMessageModel) => { - this.messageErrorActions?.showMessageErrorActions(message); + this.messagebox?.current?.closeEmojiAndAction(this.messageErrorActions?.showMessageErrorActions, message); + }; + + showActionSheet = (options: any) => { + const { showActionSheet } = this.props; + this.messagebox?.current?.closeEmojiAndAction(showActionSheet, options); }; onEditInit = (message: TAnyMessageModel) => { @@ -834,7 +839,7 @@ class RoomView extends React.Component { }; onMessageLongPress = (message: TAnyMessageModel) => { - this.messageActions?.showMessageActions(message); + this.messagebox?.current?.closeEmojiAndAction(this.messageActions?.showMessageActions, message); }; showAttachment = (attachment: IAttachment) => { @@ -857,7 +862,7 @@ class RoomView extends React.Component { this.setState({ selectedMessage: message }); const { showActionSheet, baseUrl, width } = this.props; const { selectedMessage } = this.state; - showActionSheet({ + this.messagebox?.current?.closeEmojiAndAction(showActionSheet, { children: ( { jumpToMessage={this.jumpToMessageByUrl} highlighted={highlightedMessage === item.id} theme={theme} + closeEmojiAndAction={this.messagebox?.current?.closeEmojiAndAction} /> ); } diff --git a/package.json b/package.json index c3a015060..e5e246116 100644 --- a/package.json +++ b/package.json @@ -117,7 +117,7 @@ "react-native-simple-crypto": "RocketChat/react-native-simple-crypto#0.5.0", "react-native-slowlog": "^1.0.2", "react-native-svg": "^12.3.0", - "react-native-ui-lib": "RocketChat/react-native-ui-lib#minor-improvements", + "react-native-ui-lib": "RocketChat/react-native-ui-lib", "react-native-unimodules": "^0.14.8", "react-native-vector-icons": "9.1.0", "react-native-webview": "10.3.2", diff --git a/yarn.lock b/yarn.lock index cb3170660..36a9eeaed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15491,9 +15491,9 @@ react-native-text-size@4.0.0-rc.1: resolved "https://registry.yarnpkg.com/react-native-text-size/-/react-native-text-size-4.0.0-rc.1.tgz#1e048d345dd6a5a8e1269e0585c1a5948c478da5" integrity sha512-CysqjU2jK6Yc+a+kEI222pUyTY2ywcU2HqbFqf1KHymW6OPTdvBBHqbEJKL0QiLhQaFYDbqicM+h990s9TP00g== -react-native-ui-lib@RocketChat/react-native-ui-lib#minor-improvements: - version "4.2.1" - resolved "https://codeload.github.com/RocketChat/react-native-ui-lib/tar.gz/a80f38aaa947849736ce8643253991cdcb639414" +react-native-ui-lib@RocketChat/react-native-ui-lib: + version "4.2.0" + resolved "https://codeload.github.com/RocketChat/react-native-ui-lib/tar.gz/d20c1bcd09b694fc5133fc2232fd510f5f4ba581" dependencies: babel-plugin-transform-inline-environment-variables "^0.0.2" color "^3.1.0"