Render replies to 1:1 text stories
This commit is contained in:
parent
7b1b1584f1
commit
78e3120d1a
5 changed files with 47 additions and 22 deletions
|
@ -105,6 +105,7 @@ export type PropsType = {
|
|||
retryMessageSend: (messageId: string) => unknown;
|
||||
saveAttachment: SaveAttachmentActionCreatorType;
|
||||
setHasAllStoriesUnmuted: (isUnmuted: boolean) => unknown;
|
||||
showContactModal: (contactId: string, conversationId?: string) => void;
|
||||
showToast: ShowToastActionCreatorType;
|
||||
skinTone?: number;
|
||||
story: StoryViewType;
|
||||
|
@ -158,6 +159,7 @@ export function StoryViewer({
|
|||
retryMessageSend,
|
||||
saveAttachment,
|
||||
setHasAllStoriesUnmuted,
|
||||
showContactModal,
|
||||
showToast,
|
||||
skinTone,
|
||||
story,
|
||||
|
@ -948,6 +950,7 @@ export function StoryViewer({
|
|||
recentEmojis={recentEmojis}
|
||||
renderEmojiPicker={renderEmojiPicker}
|
||||
replies={replies}
|
||||
showContactModal={showContactModal}
|
||||
skinTone={skinTone}
|
||||
sortedGroupMembers={group?.sortedGroupMembers}
|
||||
views={views}
|
||||
|
|
|
@ -58,7 +58,6 @@ const MESSAGE_DEFAULT_PROPS = {
|
|||
renderAudioAttachment: () => <div />,
|
||||
saveAttachment: shouldNeverBeCalled,
|
||||
scrollToQuotedMessage: shouldNeverBeCalled,
|
||||
showContactModal: shouldNeverBeCalled,
|
||||
showConversation: noop,
|
||||
showExpiredIncomingTapToViewToast: shouldNeverBeCalled,
|
||||
showExpiredOutgoingTapToViewToast: shouldNeverBeCalled,
|
||||
|
@ -77,12 +76,15 @@ export enum StoryViewsNRepliesTab {
|
|||
export type PropsType = {
|
||||
authorTitle: string;
|
||||
canReply: boolean;
|
||||
deleteGroupStoryReply: (id: string) => void;
|
||||
deleteGroupStoryReplyForEveryone: (id: string) => void;
|
||||
getPreferredBadge: PreferredBadgeSelectorType;
|
||||
group: Pick<ConversationType, 'left'> | undefined;
|
||||
hasViewReceiptSetting: boolean;
|
||||
hasViewsCapability: boolean;
|
||||
i18n: LocalizerType;
|
||||
isInternalUser?: boolean;
|
||||
group: Pick<ConversationType, 'left'> | undefined;
|
||||
onChangeViewTarget: (target: StoryViewTargetType) => unknown;
|
||||
onClose: () => unknown;
|
||||
onReact: (emoji: string) => unknown;
|
||||
onReply: (
|
||||
|
@ -97,24 +99,25 @@ export type PropsType = {
|
|||
recentEmojis?: ReadonlyArray<string>;
|
||||
renderEmojiPicker: (props: RenderEmojiPickerProps) => JSX.Element;
|
||||
replies: ReadonlyArray<ReplyType>;
|
||||
showContactModal: (contactId: string, conversationId?: string) => void;
|
||||
skinTone?: number;
|
||||
sortedGroupMembers?: ReadonlyArray<ConversationType>;
|
||||
views: ReadonlyArray<StorySendStateType>;
|
||||
viewTarget: StoryViewTargetType;
|
||||
onChangeViewTarget: (target: StoryViewTargetType) => unknown;
|
||||
deleteGroupStoryReply: (id: string) => void;
|
||||
deleteGroupStoryReplyForEveryone: (id: string) => void;
|
||||
};
|
||||
|
||||
export function StoryViewsNRepliesModal({
|
||||
authorTitle,
|
||||
canReply,
|
||||
deleteGroupStoryReply,
|
||||
deleteGroupStoryReplyForEveryone,
|
||||
getPreferredBadge,
|
||||
group,
|
||||
hasViewReceiptSetting,
|
||||
hasViewsCapability,
|
||||
i18n,
|
||||
isInternalUser,
|
||||
group,
|
||||
onChangeViewTarget,
|
||||
onClose,
|
||||
onReact,
|
||||
onReply,
|
||||
|
@ -125,13 +128,11 @@ export function StoryViewsNRepliesModal({
|
|||
recentEmojis,
|
||||
renderEmojiPicker,
|
||||
replies,
|
||||
showContactModal,
|
||||
skinTone,
|
||||
sortedGroupMembers,
|
||||
views,
|
||||
viewTarget,
|
||||
onChangeViewTarget,
|
||||
deleteGroupStoryReply,
|
||||
deleteGroupStoryReplyForEveryone,
|
||||
views,
|
||||
}: PropsType): JSX.Element | null {
|
||||
const [deleteReplyId, setDeleteReplyId] = useState<string | undefined>(
|
||||
undefined
|
||||
|
@ -274,18 +275,19 @@ export function StoryViewsNRepliesModal({
|
|||
return (
|
||||
<ReplyOrReactionMessage
|
||||
key={reply.id}
|
||||
id={reply.id}
|
||||
i18n={i18n}
|
||||
isInternalUser={isInternalUser}
|
||||
reply={reply}
|
||||
containerElementRef={containerElementRef}
|
||||
deleteGroupStoryReply={() => setDeleteReplyId(reply.id)}
|
||||
deleteGroupStoryReplyForEveryone={() =>
|
||||
setDeleteForEveryoneReplyId(reply.id)
|
||||
}
|
||||
getPreferredBadge={getPreferredBadge}
|
||||
i18n={i18n}
|
||||
id={reply.id}
|
||||
isInternalUser={isInternalUser}
|
||||
reply={reply}
|
||||
shouldCollapseAbove={shouldCollapse(reply, replies[index - 1])}
|
||||
shouldCollapseBelow={shouldCollapse(reply, replies[index + 1])}
|
||||
containerElementRef={containerElementRef}
|
||||
showContactModal={showContactModal}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@ -452,17 +454,18 @@ export function StoryViewsNRepliesModal({
|
|||
}
|
||||
|
||||
type ReplyOrReactionMessageProps = {
|
||||
i18n: LocalizerType;
|
||||
id: string;
|
||||
isInternalUser?: boolean;
|
||||
reply: ReplyType;
|
||||
containerElementRef: React.RefObject<HTMLElement>;
|
||||
deleteGroupStoryReply: (replyId: string) => void;
|
||||
deleteGroupStoryReplyForEveryone: (replyId: string) => void;
|
||||
getPreferredBadge: PreferredBadgeSelectorType;
|
||||
i18n: LocalizerType;
|
||||
id: string;
|
||||
isInternalUser?: boolean;
|
||||
onContextMenu?: (ev: React.MouseEvent) => void;
|
||||
reply: ReplyType;
|
||||
shouldCollapseAbove: boolean;
|
||||
shouldCollapseBelow: boolean;
|
||||
containerElementRef: React.RefObject<HTMLElement>;
|
||||
onContextMenu?: (ev: React.MouseEvent) => void;
|
||||
showContactModal: (contactId: string, conversationId?: string) => void;
|
||||
};
|
||||
|
||||
function ReplyOrReactionMessage({
|
||||
|
@ -476,6 +479,7 @@ function ReplyOrReactionMessage({
|
|||
getPreferredBadge,
|
||||
shouldCollapseAbove,
|
||||
shouldCollapseBelow,
|
||||
showContactModal,
|
||||
}: ReplyOrReactionMessageProps) {
|
||||
const renderContent = (onContextMenu?: (ev: React.MouseEvent) => void) => {
|
||||
if (reply.reactionEmoji && !reply.deletedForEveryone) {
|
||||
|
@ -546,6 +550,7 @@ function ReplyOrReactionMessage({
|
|||
shouldCollapseAbove={shouldCollapseAbove}
|
||||
shouldCollapseBelow={shouldCollapseBelow}
|
||||
shouldHideMetadata={false}
|
||||
showContactModal={showContactModal}
|
||||
text={reply.body}
|
||||
textDirection={TextDirection.Default}
|
||||
timestamp={reply.timestamp}
|
||||
|
|
|
@ -464,7 +464,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
|
|||
|
||||
const attachments = getAttachmentsForMessage({ ...message });
|
||||
let attachment: AttachmentType | undefined = attachments?.[0];
|
||||
if (attachment && !attachment.url) {
|
||||
if (attachment && !attachment.url && !attachment.textAttachment) {
|
||||
attachment = undefined;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import type {
|
|||
MessageChangedActionType,
|
||||
MessageDeletedActionType,
|
||||
MessagesAddedActionType,
|
||||
SelectedConversationChangedActionType,
|
||||
} from './conversations';
|
||||
import type { NoopActionType } from './noop';
|
||||
import type { StateType as RootStateType } from '../reducer';
|
||||
|
@ -20,6 +21,7 @@ import type { StoryViewTargetType, StoryViewType } from '../../types/Stories';
|
|||
import type { SyncType } from '../../jobs/helpers/syncHelpers';
|
||||
import type { UUIDStringType } from '../../types/UUID';
|
||||
import * as log from '../../logging/log';
|
||||
import { SELECTED_CONVERSATION_CHANGED } from './conversations';
|
||||
import { SIGNAL_ACI } from '../../types/SignalConversation';
|
||||
import dataInterface from '../../sql/Client';
|
||||
import { ReadStatus } from '../../messages/MessageReadStatus';
|
||||
|
@ -263,6 +265,7 @@ export type StoriesActionType =
|
|||
| ViewStoryActionType
|
||||
| StoryReplyDeletedActionType
|
||||
| RemoveAllStoriesActionType
|
||||
| SelectedConversationChangedActionType
|
||||
| SetAddStoryDataType
|
||||
| SetStorySendingType
|
||||
| SetHasAllStoriesUnmutedType;
|
||||
|
@ -1775,5 +1778,16 @@ export function reducer(
|
|||
};
|
||||
}
|
||||
|
||||
if (action.type === SELECTED_CONVERSATION_CHANGED) {
|
||||
return {
|
||||
...state,
|
||||
lastOpenedAtTimestamp: state.openedAtTimestamp || Date.now(),
|
||||
openedAtTimestamp: undefined,
|
||||
replyState: undefined,
|
||||
sendStoryModalData: undefined,
|
||||
selectedStoryData: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ import { useConversationsActions } from '../ducks/conversations';
|
|||
import { useRecentEmojis } from '../selectors/emojis';
|
||||
import { useActions as useItemsActions } from '../ducks/items';
|
||||
import { useAudioPlayerActions } from '../ducks/audioPlayer';
|
||||
import { useGlobalModalActions } from '../ducks/globalModals';
|
||||
import { useStoriesActions } from '../ducks/stories';
|
||||
import { useIsWindowActive } from '../../hooks/useIsWindowActive';
|
||||
|
||||
|
@ -50,6 +51,7 @@ export function SmartStoryViewer(): JSX.Element | null {
|
|||
} = useConversationsActions();
|
||||
const { onSetSkinTone } = useItemsActions();
|
||||
const { showToast } = useToastActions();
|
||||
const { showContactModal } = useGlobalModalActions();
|
||||
|
||||
const isWindowActive = useIsWindowActive();
|
||||
|
||||
|
@ -143,6 +145,7 @@ export function SmartStoryViewer(): JSX.Element | null {
|
|||
renderEmojiPicker={renderEmojiPicker}
|
||||
replyState={replyState}
|
||||
retryMessageSend={retryMessageSend}
|
||||
showContactModal={showContactModal}
|
||||
showToast={showToast}
|
||||
skinTone={skinTone}
|
||||
story={storyView}
|
||||
|
|
Loading…
Add table
Reference in a new issue