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