Page MenuHomePhabricator

D7344.id25032.diff
No OneTemporary

D7344.id25032.diff

diff --git a/lib/shared/edit-messages-utils.js b/lib/shared/edit-messages-utils.js
--- a/lib/shared/edit-messages-utils.js
+++ b/lib/shared/edit-messages-utils.js
@@ -8,10 +8,12 @@
sendEditMessageActionTypes,
sendEditMessage,
} from '../actions/message-actions.js';
+import { messageInfoSelector } from '../selectors/chat-selectors.js';
import type {
SendEditMessageResult,
RobotextMessageInfo,
ComposableMessageInfo,
+ MessageInfo,
} from '../types/message-types';
import { messageTypes } from '../types/message-types.js';
import { threadPermissions, type ThreadInfo } from '../types/thread-types.js';
@@ -76,6 +78,42 @@
return hasPermission;
}
+function useGetEditedMessage(targetMessageID: ?string): ?MessageInfo {
+ const messageInfos = useSelector(messageInfoSelector);
+ const targetMessageInfo = targetMessageID && messageInfos[targetMessageID];
+ const threadInfo = useSelector(state => {
+ if (!targetMessageInfo) {
+ return null;
+ }
+ return state.messageStore.threads[targetMessageInfo.threadID];
+ });
+
+ return React.useMemo(() => {
+ if (!targetMessageInfo || targetMessageInfo.type !== messageTypes.TEXT) {
+ return null;
+ }
+ const threadMessageInfos = (threadInfo?.messageIDs ?? [])
+ .map((messageID: string) => messageInfos[messageID])
+ .filter(Boolean)
+ .filter(
+ message =>
+ message.type === messageTypes.EDIT_MESSAGE &&
+ message.targetMessageID === targetMessageID,
+ );
+ if (threadMessageInfos.length === 0) {
+ return targetMessageInfo;
+ }
+ invariant(
+ threadMessageInfos[0].type === messageTypes.EDIT_MESSAGE,
+ 'message should be edit message',
+ );
+ return {
+ ...targetMessageInfo,
+ text: threadMessageInfos[0].text,
+ };
+ }, [messageInfos, targetMessageID, targetMessageInfo, threadInfo]);
+}
+
function getMessageLabel(
hasBeenEdited: ?boolean,
threadInfo: ThreadInfo,
@@ -87,4 +125,9 @@
return null;
}
-export { useCanEditMessage, useEditMessage, getMessageLabel };
+export {
+ useCanEditMessage,
+ useGetEditedMessage,
+ getMessageLabel,
+ useEditMessage,
+};
diff --git a/lib/shared/message-utils.js b/lib/shared/message-utils.js
--- a/lib/shared/message-utils.js
+++ b/lib/shared/message-utils.js
@@ -468,7 +468,7 @@
// unread has highest contrast, followed by primary, followed by secondary
+style: 'unread' | 'primary' | 'secondary',
};
-type MessagePreviewResult = {
+export type MessagePreviewResult = {
+message: MessagePreviewPart,
+username: ?MessagePreviewPart,
};
diff --git a/native/chat/chat-input-bar.react.js b/native/chat/chat-input-bar.react.js
--- a/native/chat/chat-input-bar.react.js
+++ b/native/chat/chat-input-bar.react.js
@@ -31,13 +31,19 @@
import { threadInfoSelector } from 'lib/selectors/thread-selectors.js';
import { userStoreSearchIndex } from 'lib/selectors/user-selectors.js';
import { colorIsDark } from 'lib/shared/color-utils.js';
+import { useGetEditedMessage } from 'lib/shared/edit-messages-utils.js';
import {
getTypeaheadUserSuggestions,
getTypeaheadRegexMatches,
type Selection,
getMentionsCandidates,
} from 'lib/shared/mention-utils.js';
-import { localIDPrefix, trimMessage } from 'lib/shared/message-utils.js';
+import {
+ localIDPrefix,
+ trimMessage,
+ useMessagePreview,
+} from 'lib/shared/message-utils.js';
+import type { MessagePreviewResult } from 'lib/shared/message-utils.js';
import SearchIndex from 'lib/shared/search-index.js';
import {
threadHasPermission,
@@ -75,6 +81,7 @@
import type { SyncedSelectionData } from '../components/selectable-text-input.js';
// eslint-disable-next-line import/extensions
import SelectableTextInput from '../components/selectable-text-input.react';
+import { SingleLine } from '../components/single-line.react.js';
import SWMansionIcon from '../components/swmansion-icon.react.js';
import { type InputState, InputStateContext } from '../input/input-state.js';
import KeyboardInputHost from '../keyboard/keyboard-input-host.react.js';
@@ -83,6 +90,7 @@
KeyboardContext,
} from '../keyboard/keyboard-state.js';
import { getKeyboardHeight } from '../keyboard/keyboard.js';
+import { getDefaultTextMessageRules } from '../markdown/rules.react.js';
import {
nonThreadCalendarQuery,
activeThreadSelector,
@@ -139,6 +147,7 @@
+userSearchIndex: SearchIndex,
+mentionsCandidates: $ReadOnlyArray<RelativeMemberInfo>,
+parentThreadInfo: ?ThreadInfo,
+ +messagePreviewResult: ?MessagePreviewResult,
};
type State = {
+text: string,
@@ -422,6 +431,7 @@
threadPermissions.JOIN_THREAD,
);
let joinButton = null;
+ const threadColor = `#${this.props.threadInfo.color}`;
if (!isMember && canJoin && !this.props.threadCreationInProgress) {
let buttonContent;
if (this.props.joinThreadLoadingStatus === 'loading') {
@@ -450,7 +460,7 @@
iosActiveOpacity={0.85}
style={[
this.props.styles.joinButton,
- { backgroundColor: `#${this.props.threadInfo.color}` },
+ { backgroundColor: threadColor },
]}
>
{buttonContent}
@@ -532,6 +542,33 @@
<KeyboardInputHost textInputRef={this.textInput} />
);
+ let editMode;
+ const isEditMode = this.isEditMode();
+ if (isEditMode && this.props.messagePreviewResult) {
+ const { message } = this.props.messagePreviewResult;
+ editMode = (
+ <AnimatedView style={this.props.styles.editView}>
+ <View style={this.props.styles.editViewContent}>
+ <Text
+ style={[{ color: threadColor }, this.props.styles.editingLabel]}
+ >
+ Editing message
+ </Text>
+ <SingleLine style={this.props.styles.editingMessagePreview}>
+ {message.text}
+ </SingleLine>
+ </View>
+ <SWMansionIcon
+ style={this.props.styles.exitEditButton}
+ name="cross"
+ size={22}
+ color={threadColor}
+ onPress={this.onPressExitEditMode}
+ />
+ </AnimatedView>
+ );
+ }
+
return (
<View
style={this.props.styles.container}
@@ -539,6 +576,7 @@
>
{typeaheadTooltip}
{joinButton}
+ {editMode}
{content}
{keyboardInputHost}
</View>
@@ -736,6 +774,15 @@
);
};
+ isEditMode = () => {
+ const editState = this.props.inputState?.editState;
+ return editState && editState.editedMessageID !== null;
+ };
+
+ onPressExitEditMode = () => {
+ this.props.inputState?.setEditedMessageID(null);
+ };
+
onPressJoin = () => {
this.props.dispatchActionPromise(joinThreadActionTypes, this.joinAction());
};
@@ -844,6 +891,26 @@
height: 48,
marginBottom: 8,
},
+ editView: {
+ marginLeft: 20,
+ marginRight: 20,
+ padding: 10,
+ flexDirection: 'row',
+ justifyContent: 'space-between',
+ },
+ editViewContent: {
+ flex: 1,
+ paddingRight: 6,
+ },
+ exitEditButton: {
+ marginTop: 6,
+ },
+ editingLabel: {
+ paddingBottom: 4,
+ },
+ editingMessagePreview: {
+ color: 'listForegroundLabel',
+ },
joinButtonContent: {
flexDirection: 'row',
justifyContent: 'center',
@@ -948,6 +1015,15 @@
parentThreadInfo,
);
+ const editedMessageID = inputState?.editState.editedMessageID;
+ const editedMessageInfo = useGetEditedMessage(editedMessageID);
+
+ const messagePreviewResult = useMessagePreview(
+ editedMessageInfo,
+ props.threadInfo,
+ getDefaultTextMessageRules().simpleMarkdownRules,
+ );
+
return (
<ChatInputBar
{...props}
@@ -969,6 +1045,7 @@
userSearchIndex={userSearchIndex}
mentionsCandidates={mentionsCandidates}
parentThreadInfo={parentThreadInfo}
+ messagePreviewResult={messagePreviewResult}
/>
);
}

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 9, 10:01 AM (21 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2451372
Default Alt Text
D7344.id25032.diff (7 KB)

Event Timeline