Changeset View
Changeset View
Standalone View
Standalone View
native/chat/chat-input-bar.react.js
Show First 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | import { | ||||
threadHasPermission, | threadHasPermission, | ||||
viewerIsMember, | viewerIsMember, | ||||
threadFrozenDueToViewerBlock, | threadFrozenDueToViewerBlock, | ||||
threadActualMembers, | threadActualMembers, | ||||
checkIfDefaultMembersAreVoiced, | checkIfDefaultMembersAreVoiced, | ||||
draftKeyFromThreadID, | draftKeyFromThreadID, | ||||
} from 'lib/shared/thread-utils.js'; | } from 'lib/shared/thread-utils.js'; | ||||
import type { CalendarQuery } from 'lib/types/entry-types.js'; | import type { CalendarQuery } from 'lib/types/entry-types.js'; | ||||
import type { SetState } from 'lib/types/hook-types.js'; | |||||
import type { LoadingStatus } from 'lib/types/loading-types.js'; | import type { LoadingStatus } from 'lib/types/loading-types.js'; | ||||
import type { PhotoPaste } from 'lib/types/media-types.js'; | import type { PhotoPaste } from 'lib/types/media-types.js'; | ||||
import { messageTypes } from 'lib/types/message-types-enum.js'; | import { messageTypes } from 'lib/types/message-types-enum.js'; | ||||
import type { | import type { | ||||
SendEditMessageResponse, | SendEditMessageResponse, | ||||
MessageInfo, | MessageInfo, | ||||
} from 'lib/types/message-types.js'; | } from 'lib/types/message-types.js'; | ||||
import type { Dispatch } from 'lib/types/redux-types.js'; | import type { Dispatch } from 'lib/types/redux-types.js'; | ||||
▲ Show 20 Lines • Show All 228 Lines • ▼ Show 20 Lines | type Props = { | ||||
+editedMessageInfo: ?MessageInfo, | +editedMessageInfo: ?MessageInfo, | ||||
+editMessage: ( | +editMessage: ( | ||||
messageID: string, | messageID: string, | ||||
text: string, | text: string, | ||||
) => Promise<SendEditMessageResponse>, | ) => Promise<SendEditMessageResponse>, | ||||
+navigation: ?ChatNavigationProp<'MessageList'>, | +navigation: ?ChatNavigationProp<'MessageList'>, | ||||
+overlayContext: ?OverlayContextType, | +overlayContext: ?OverlayContextType, | ||||
+messageEditingContext: ?MessageEditingContextType, | +messageEditingContext: ?MessageEditingContextType, | ||||
+selectionState: SyncedSelectionData, | |||||
+setSelectionState: SetState<SyncedSelectionData>, | |||||
}; | }; | ||||
type State = { | type State = { | ||||
+text: string, | +text: string, | ||||
+textEdited: boolean, | +textEdited: boolean, | ||||
+buttonsExpanded: boolean, | +buttonsExpanded: boolean, | ||||
+selectionState: SyncedSelectionData, | |||||
+isExitingDuringEditMode: boolean, | +isExitingDuringEditMode: boolean, | ||||
}; | }; | ||||
class ChatInputBar extends React.PureComponent<Props, State> { | class ChatInputBar extends React.PureComponent<Props, State> { | ||||
textInput: ?React.ElementRef<typeof TextInput>; | textInput: ?React.ElementRef<typeof TextInput>; | ||||
clearableTextInput: ?ClearableTextInput; | clearableTextInput: ?ClearableTextInput; | ||||
selectableTextInput: ?React.ElementRef<typeof SelectableTextInput>; | selectableTextInput: ?React.ElementRef<typeof SelectableTextInput>; | ||||
expandoButtonsOpen: Value; | expandoButtonsOpen: Value; | ||||
Show All 12 Lines | class ChatInputBar extends React.PureComponent<Props, State> { | ||||
clearBlurListener: () => void; | clearBlurListener: () => void; | ||||
constructor(props: Props) { | constructor(props: Props) { | ||||
super(props); | super(props); | ||||
this.state = { | this.state = { | ||||
text: props.draft, | text: props.draft, | ||||
textEdited: false, | textEdited: false, | ||||
buttonsExpanded: true, | buttonsExpanded: true, | ||||
selectionState: { text: props.draft, selection: { start: 0, end: 0 } }, | |||||
isExitingDuringEditMode: false, | isExitingDuringEditMode: false, | ||||
}; | }; | ||||
this.setUpActionIconAnimations(); | this.setUpActionIconAnimations(); | ||||
this.setUpSendIconAnimations(); | this.setUpSendIconAnimations(); | ||||
} | } | ||||
setUpActionIconAnimations() { | setUpActionIconAnimations() { | ||||
▲ Show 20 Lines • Show All 312 Lines • ▼ Show 20 Lines | if (!isMember && canJoin && !this.props.threadCreationInProgress) { | ||||
> | > | ||||
{buttonContent} | {buttonContent} | ||||
</Button> | </Button> | ||||
</View> | </View> | ||||
); | ); | ||||
} | } | ||||
const typeaheadRegexMatches = getTypeaheadRegexMatches( | const typeaheadRegexMatches = getTypeaheadRegexMatches( | ||||
this.state.selectionState.text, | this.props.selectionState.text, | ||||
this.state.selectionState.selection, | this.props.selectionState.selection, | ||||
nativeMentionTypeaheadRegex, | nativeMentionTypeaheadRegex, | ||||
); | ); | ||||
let typeaheadTooltip = null; | let typeaheadTooltip = null; | ||||
if (typeaheadRegexMatches && !isEditMode) { | if (typeaheadRegexMatches && !isEditMode) { | ||||
const typeaheadMatchedStrings = { | const typeaheadMatchedStrings = { | ||||
textBeforeAtSymbol: typeaheadRegexMatches[1] ?? '', | textBeforeAtSymbol: typeaheadRegexMatches[1] ?? '', | ||||
▲ Show 20 Lines • Show All 172 Lines • ▼ Show 20 Lines | return ( | ||||
</TouchableOpacity> | </TouchableOpacity> | ||||
{this.state.buttonsExpanded ? null : expandoButton} | {this.state.buttonsExpanded ? null : expandoButton} | ||||
</View> | </View> | ||||
</AnimatedView> | </AnimatedView> | ||||
<SelectableTextInput | <SelectableTextInput | ||||
allowImagePasteForThreadID={this.props.threadInfo.id} | allowImagePasteForThreadID={this.props.threadInfo.id} | ||||
value={this.state.text} | value={this.state.text} | ||||
onChangeText={this.updateText} | onChangeText={this.updateText} | ||||
selection={this.state.selectionState.selection} | selection={this.props.selectionState.selection} | ||||
onUpdateSyncedSelectionData={this.updateSelectionState} | onUpdateSyncedSelectionData={this.props.setSelectionState} | ||||
placeholder="Send a message..." | placeholder="Send a message..." | ||||
placeholderTextColor={this.props.colors.listInputButton} | placeholderTextColor={this.props.colors.listInputButton} | ||||
multiline={true} | multiline={true} | ||||
style={this.props.styles.textInput} | style={this.props.styles.textInput} | ||||
textInputRef={this.textInputRef} | textInputRef={this.textInputRef} | ||||
clearableTextInputRef={this.clearableTextInputRef} | clearableTextInputRef={this.clearableTextInputRef} | ||||
ref={this.selectableTextInputRef} | ref={this.selectableTextInputRef} | ||||
selectionColor={`#${this.props.threadInfo.color}`} | selectionColor={`#${this.props.threadInfo.color}`} | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | this.props.messageEditingContext?.setEditedMessageChanged( | ||||
this.isMessageEdited(text), | this.isMessageEdited(text), | ||||
); | ); | ||||
if (this.isEditMode()) { | if (this.isEditMode()) { | ||||
return; | return; | ||||
} | } | ||||
this.saveDraft(text); | this.saveDraft(text); | ||||
}; | }; | ||||
updateSelectionState: (data: SyncedSelectionData) => void = data => { | |||||
this.setState({ selectionState: data }); | |||||
}; | |||||
saveDraft: (text: string) => void = _throttle(text => { | saveDraft: (text: string) => void = _throttle(text => { | ||||
this.props.dispatch({ | this.props.dispatch({ | ||||
type: updateDraftActionType, | type: updateDraftActionType, | ||||
payload: { | payload: { | ||||
key: draftKeyFromThreadID(this.props.threadInfo.id), | key: draftKeyFromThreadID(this.props.threadInfo.id), | ||||
text, | text, | ||||
}, | }, | ||||
}); | }); | ||||
}, 400); | }, 400); | ||||
focusAndUpdateTextAndSelection = (text: string, selection: Selection) => { | focusAndUpdateTextAndSelection = (text: string, selection: Selection) => { | ||||
this.selectableTextInput?.prepareForSelectionMutation(text, selection); | this.selectableTextInput?.prepareForSelectionMutation(text, selection); | ||||
this.setState({ | this.setState({ | ||||
text, | text, | ||||
textEdited: true, | textEdited: true, | ||||
selectionState: { text, selection }, | |||||
}); | }); | ||||
this.props.setSelectionState({ text, selection }); | |||||
this.saveDraft(text); | this.saveDraft(text); | ||||
this.focusAndUpdateButtonsVisibility(); | this.focusAndUpdateButtonsVisibility(); | ||||
}; | }; | ||||
focusAndUpdateText = (params: EditInputBarMessageParameters) => { | focusAndUpdateText = (params: EditInputBarMessageParameters) => { | ||||
const { message: text, mode } = params; | const { message: text, mode } = params; | ||||
const currentText = this.state.text; | const currentText = this.state.text; | ||||
▲ Show 20 Lines • Show All 351 Lines • ▼ Show 20 Lines | function ConnectedChatInputBarBase(props: ConnectedChatInputBarBaseProps) { | ||||
const editedMessageInfo = messageEditingContext?.editState.editedMessage; | const editedMessageInfo = messageEditingContext?.editState.editedMessage; | ||||
const editedMessagePreview = useMessagePreview( | const editedMessagePreview = useMessagePreview( | ||||
editedMessageInfo, | editedMessageInfo, | ||||
props.threadInfo, | props.threadInfo, | ||||
getDefaultTextMessageRules(chatMentionCandidates).simpleMarkdownRules, | getDefaultTextMessageRules(chatMentionCandidates).simpleMarkdownRules, | ||||
); | ); | ||||
const editMessage = useEditMessage(); | const editMessage = useEditMessage(); | ||||
const [selectionState, setSelectionState] = | |||||
React.useState<SyncedSelectionData>({ | |||||
text: draft, | |||||
selection: { start: 0, end: 0 }, | |||||
}); | |||||
return ( | return ( | ||||
<ChatInputBar | <ChatInputBar | ||||
{...props} | {...props} | ||||
viewerID={viewerID} | viewerID={viewerID} | ||||
draft={draft} | draft={draft} | ||||
joinThreadLoadingStatus={joinThreadLoadingStatus} | joinThreadLoadingStatus={joinThreadLoadingStatus} | ||||
threadCreationInProgress={threadCreationInProgress} | threadCreationInProgress={threadCreationInProgress} | ||||
calendarQuery={calendarQuery} | calendarQuery={calendarQuery} | ||||
Show All 13 Lines | <ChatInputBar | ||||
chatMentionCandidates={chatMentionCandidates} | chatMentionCandidates={chatMentionCandidates} | ||||
parentThreadInfo={parentThreadInfo} | parentThreadInfo={parentThreadInfo} | ||||
editedMessagePreview={editedMessagePreview} | editedMessagePreview={editedMessagePreview} | ||||
editedMessageInfo={editedMessageInfo} | editedMessageInfo={editedMessageInfo} | ||||
editMessage={editMessage} | editMessage={editMessage} | ||||
navigation={props.navigation} | navigation={props.navigation} | ||||
overlayContext={overlayContext} | overlayContext={overlayContext} | ||||
messageEditingContext={messageEditingContext} | messageEditingContext={messageEditingContext} | ||||
selectionState={selectionState} | |||||
setSelectionState={setSelectionState} | |||||
/> | /> | ||||
); | ); | ||||
} | } | ||||
type DummyChatInputBarProps = { | type DummyChatInputBarProps = { | ||||
...BaseProps, | ...BaseProps, | ||||
+onHeightMeasured: (height: number) => mixed, | +onHeightMeasured: (height: number) => mixed, | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 109 Lines • Show Last 20 Lines |