ConversationView: Pull various functions out of getMessageActions
This commit is contained in:
parent
5a98fc2f4c
commit
1e282ee5d0
42 changed files with 440 additions and 570 deletions
|
@ -49,7 +49,7 @@ export default {
|
||||||
queueStoryDownload: {
|
queueStoryDownload: {
|
||||||
action: true,
|
action: true,
|
||||||
},
|
},
|
||||||
retrySend: {
|
retryMessageSend: {
|
||||||
action: true,
|
action: true,
|
||||||
},
|
},
|
||||||
viewStory: { action: true },
|
viewStory: { action: true },
|
||||||
|
|
|
@ -27,7 +27,7 @@ export type PropsType = {
|
||||||
onForward: (storyId: string) => unknown;
|
onForward: (storyId: string) => unknown;
|
||||||
onSave: (story: StoryViewType) => unknown;
|
onSave: (story: StoryViewType) => unknown;
|
||||||
queueStoryDownload: (storyId: string) => unknown;
|
queueStoryDownload: (storyId: string) => unknown;
|
||||||
retrySend: (messageId: string) => unknown;
|
retryMessageSend: (messageId: string) => unknown;
|
||||||
viewStory: ViewStoryActionCreatorType;
|
viewStory: ViewStoryActionCreatorType;
|
||||||
hasViewReceiptSetting: boolean;
|
hasViewReceiptSetting: boolean;
|
||||||
};
|
};
|
||||||
|
@ -40,7 +40,7 @@ export function MyStories({
|
||||||
onForward,
|
onForward,
|
||||||
onSave,
|
onSave,
|
||||||
queueStoryDownload,
|
queueStoryDownload,
|
||||||
retrySend,
|
retryMessageSend,
|
||||||
viewStory,
|
viewStory,
|
||||||
hasViewReceiptSetting,
|
hasViewReceiptSetting,
|
||||||
}: PropsType): JSX.Element {
|
}: PropsType): JSX.Element {
|
||||||
|
@ -95,7 +95,7 @@ export function MyStories({
|
||||||
onForward={onForward}
|
onForward={onForward}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
queueStoryDownload={queueStoryDownload}
|
queueStoryDownload={queueStoryDownload}
|
||||||
retrySend={retrySend}
|
retryMessageSend={retryMessageSend}
|
||||||
setConfirmDeleteStory={setConfirmDeleteStory}
|
setConfirmDeleteStory={setConfirmDeleteStory}
|
||||||
story={story}
|
story={story}
|
||||||
viewStory={viewStory}
|
viewStory={viewStory}
|
||||||
|
@ -120,7 +120,7 @@ type StorySentPropsType = Pick<
|
||||||
| 'onForward'
|
| 'onForward'
|
||||||
| 'onSave'
|
| 'onSave'
|
||||||
| 'queueStoryDownload'
|
| 'queueStoryDownload'
|
||||||
| 'retrySend'
|
| 'retryMessageSend'
|
||||||
| 'viewStory'
|
| 'viewStory'
|
||||||
> & {
|
> & {
|
||||||
setConfirmDeleteStory: (_: StoryViewType | undefined) => unknown;
|
setConfirmDeleteStory: (_: StoryViewType | undefined) => unknown;
|
||||||
|
@ -133,7 +133,7 @@ function StorySent({
|
||||||
onForward,
|
onForward,
|
||||||
onSave,
|
onSave,
|
||||||
queueStoryDownload,
|
queueStoryDownload,
|
||||||
retrySend,
|
retryMessageSend,
|
||||||
setConfirmDeleteStory,
|
setConfirmDeleteStory,
|
||||||
story,
|
story,
|
||||||
viewStory,
|
viewStory,
|
||||||
|
@ -155,7 +155,7 @@ function StorySent({
|
||||||
sendStatus === ResolvedSendStatus.PartiallySent)
|
sendStatus === ResolvedSendStatus.PartiallySent)
|
||||||
) {
|
) {
|
||||||
setWasManuallyRetried(true);
|
setWasManuallyRetried(true);
|
||||||
retrySend(story.messageId);
|
retryMessageSend(story.messageId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ export default {
|
||||||
},
|
},
|
||||||
queueStoryDownload: { action: true },
|
queueStoryDownload: { action: true },
|
||||||
renderStoryCreator: { action: true },
|
renderStoryCreator: { action: true },
|
||||||
retrySend: { action: true },
|
retryMessageSend: { action: true },
|
||||||
showConversation: { action: true },
|
showConversation: { action: true },
|
||||||
showStoriesSettings: { action: true },
|
showStoriesSettings: { action: true },
|
||||||
showToast: { action: true },
|
showToast: { action: true },
|
||||||
|
|
|
@ -42,7 +42,7 @@ export type PropsType = {
|
||||||
preferredWidthFromStorage: number;
|
preferredWidthFromStorage: number;
|
||||||
queueStoryDownload: (storyId: string) => unknown;
|
queueStoryDownload: (storyId: string) => unknown;
|
||||||
renderStoryCreator: () => JSX.Element;
|
renderStoryCreator: () => JSX.Element;
|
||||||
retrySend: (messageId: string) => unknown;
|
retryMessageSend: (messageId: string) => unknown;
|
||||||
setAddStoryData: (data: AddStoryData) => unknown;
|
setAddStoryData: (data: AddStoryData) => unknown;
|
||||||
showConversation: ShowConversationType;
|
showConversation: ShowConversationType;
|
||||||
showStoriesSettings: () => unknown;
|
showStoriesSettings: () => unknown;
|
||||||
|
@ -70,7 +70,7 @@ export function Stories({
|
||||||
preferredWidthFromStorage,
|
preferredWidthFromStorage,
|
||||||
queueStoryDownload,
|
queueStoryDownload,
|
||||||
renderStoryCreator,
|
renderStoryCreator,
|
||||||
retrySend,
|
retryMessageSend,
|
||||||
setAddStoryData,
|
setAddStoryData,
|
||||||
showConversation,
|
showConversation,
|
||||||
showStoriesSettings,
|
showStoriesSettings,
|
||||||
|
@ -111,7 +111,7 @@ export function Stories({
|
||||||
onForward={onForwardStory}
|
onForward={onForwardStory}
|
||||||
onSave={onSaveStory}
|
onSave={onSaveStory}
|
||||||
queueStoryDownload={queueStoryDownload}
|
queueStoryDownload={queueStoryDownload}
|
||||||
retrySend={retrySend}
|
retryMessageSend={retryMessageSend}
|
||||||
viewStory={viewStory}
|
viewStory={viewStory}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
|
|
|
@ -56,7 +56,7 @@ export default {
|
||||||
},
|
},
|
||||||
queueStoryDownload: { action: true },
|
queueStoryDownload: { action: true },
|
||||||
renderEmojiPicker: { action: true },
|
renderEmojiPicker: { action: true },
|
||||||
retrySend: { action: true },
|
retryMessageSend: { action: true },
|
||||||
showToast: { action: true },
|
showToast: { action: true },
|
||||||
skinTone: {
|
skinTone: {
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
|
|
|
@ -101,7 +101,7 @@ export type PropsType = {
|
||||||
recentEmojis?: Array<string>;
|
recentEmojis?: Array<string>;
|
||||||
renderEmojiPicker: (props: RenderEmojiPickerProps) => JSX.Element;
|
renderEmojiPicker: (props: RenderEmojiPickerProps) => JSX.Element;
|
||||||
replyState?: ReplyStateType;
|
replyState?: ReplyStateType;
|
||||||
retrySend: (messageId: string) => unknown;
|
retryMessageSend: (messageId: string) => unknown;
|
||||||
saveAttachment: SaveAttachmentActionCreatorType;
|
saveAttachment: SaveAttachmentActionCreatorType;
|
||||||
setHasAllStoriesUnmuted: (isUnmuted: boolean) => unknown;
|
setHasAllStoriesUnmuted: (isUnmuted: boolean) => unknown;
|
||||||
showToast: ShowToastActionCreatorType;
|
showToast: ShowToastActionCreatorType;
|
||||||
|
@ -153,7 +153,7 @@ export function StoryViewer({
|
||||||
recentEmojis,
|
recentEmojis,
|
||||||
renderEmojiPicker,
|
renderEmojiPicker,
|
||||||
replyState,
|
replyState,
|
||||||
retrySend,
|
retryMessageSend,
|
||||||
saveAttachment,
|
saveAttachment,
|
||||||
setHasAllStoriesUnmuted,
|
setHasAllStoriesUnmuted,
|
||||||
showToast,
|
showToast,
|
||||||
|
@ -555,7 +555,7 @@ export function StoryViewer({
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function doRetrySend() {
|
function doRetryMessageSend() {
|
||||||
if (wasManuallyRetried) {
|
if (wasManuallyRetried) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -568,7 +568,7 @@ export function StoryViewer({
|
||||||
}
|
}
|
||||||
|
|
||||||
setWasManuallyRetried(true);
|
setWasManuallyRetried(true);
|
||||||
retrySend(messageId);
|
retryMessageSend(messageId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -800,7 +800,7 @@ export function StoryViewer({
|
||||||
{sendStatus === ResolvedSendStatus.Failed && !wasManuallyRetried && (
|
{sendStatus === ResolvedSendStatus.Failed && !wasManuallyRetried && (
|
||||||
<button
|
<button
|
||||||
className="StoryViewer__actions__failed"
|
className="StoryViewer__actions__failed"
|
||||||
onClick={doRetrySend}
|
onClick={doRetryMessageSend}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
{i18n('StoryViewer__failed')}
|
{i18n('StoryViewer__failed')}
|
||||||
|
@ -810,7 +810,7 @@ export function StoryViewer({
|
||||||
!wasManuallyRetried && (
|
!wasManuallyRetried && (
|
||||||
<button
|
<button
|
||||||
className="StoryViewer__actions__failed"
|
className="StoryViewer__actions__failed"
|
||||||
onClick={doRetrySend}
|
onClick={doRetryMessageSend}
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
{i18n('StoryViewer__partial-fail')}
|
{i18n('StoryViewer__partial-fail')}
|
||||||
|
|
|
@ -54,7 +54,6 @@ const MESSAGE_DEFAULT_PROPS = {
|
||||||
isMessageRequestAccepted: true,
|
isMessageRequestAccepted: true,
|
||||||
kickOffAttachmentDownload: shouldNeverBeCalled,
|
kickOffAttachmentDownload: shouldNeverBeCalled,
|
||||||
markAttachmentAsCorrupted: shouldNeverBeCalled,
|
markAttachmentAsCorrupted: shouldNeverBeCalled,
|
||||||
markViewed: shouldNeverBeCalled,
|
|
||||||
messageExpanded: shouldNeverBeCalled,
|
messageExpanded: shouldNeverBeCalled,
|
||||||
openGiftBadge: shouldNeverBeCalled,
|
openGiftBadge: shouldNeverBeCalled,
|
||||||
openLink: shouldNeverBeCalled,
|
openLink: shouldNeverBeCalled,
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
// Copyright 2022 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import type { LocalizerType } from '../types/Util';
|
|
||||||
import { Toast } from './Toast';
|
|
||||||
|
|
||||||
export type ToastPropsType = {
|
|
||||||
i18n: LocalizerType;
|
|
||||||
isIncoming: boolean;
|
|
||||||
onClose: () => unknown;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function ToastCannotOpenGiftBadge({
|
|
||||||
i18n,
|
|
||||||
isIncoming,
|
|
||||||
onClose,
|
|
||||||
}: ToastPropsType): JSX.Element {
|
|
||||||
const key = `message--giftBadge--unopened--toast--${
|
|
||||||
isIncoming ? 'incoming' : 'outgoing'
|
|
||||||
}`;
|
|
||||||
|
|
||||||
return <Toast onClose={onClose}>{i18n(key)}</Toast>;
|
|
||||||
}
|
|
|
@ -70,6 +70,20 @@ CannotMixMultiAndNonMultiAttachments.args = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const CannotOpenGiftBadgeIncoming = Template.bind({});
|
||||||
|
CannotOpenGiftBadgeIncoming.args = {
|
||||||
|
toast: {
|
||||||
|
toastType: ToastType.CannotOpenGiftBadgeIncoming,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CannotOpenGiftBadgeOutgoing = Template.bind({});
|
||||||
|
CannotOpenGiftBadgeOutgoing.args = {
|
||||||
|
toast: {
|
||||||
|
toastType: ToastType.CannotOpenGiftBadgeOutgoing,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const CannotStartGroupCall = Template.bind({});
|
export const CannotStartGroupCall = Template.bind({});
|
||||||
CannotStartGroupCall.args = {
|
CannotStartGroupCall.args = {
|
||||||
toast: {
|
toast: {
|
||||||
|
@ -182,6 +196,13 @@ PinnedConversationsFull.args = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ReactionFailed = Template.bind({});
|
||||||
|
ReactionFailed.args = {
|
||||||
|
toast: {
|
||||||
|
toastType: ToastType.ReactionFailed,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const ReportedSpamAndBlocked = Template.bind({});
|
export const ReportedSpamAndBlocked = Template.bind({});
|
||||||
ReportedSpamAndBlocked.args = {
|
ReportedSpamAndBlocked.args = {
|
||||||
toast: {
|
toast: {
|
||||||
|
@ -231,6 +252,20 @@ StoryVideoUnsupported.args = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const TapToViewExpiredIncoming = Template.bind({});
|
||||||
|
TapToViewExpiredIncoming.args = {
|
||||||
|
toast: {
|
||||||
|
toastType: ToastType.TapToViewExpiredIncoming,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TapToViewExpiredOutgoing = Template.bind({});
|
||||||
|
TapToViewExpiredOutgoing.args = {
|
||||||
|
toast: {
|
||||||
|
toastType: ToastType.TapToViewExpiredOutgoing,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const UnableToLoadAttachment = Template.bind({});
|
export const UnableToLoadAttachment = Template.bind({});
|
||||||
UnableToLoadAttachment.args = {
|
UnableToLoadAttachment.args = {
|
||||||
toast: {
|
toast: {
|
||||||
|
|
|
@ -60,6 +60,22 @@ export function ToastManager({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (toastType === ToastType.CannotOpenGiftBadgeIncoming) {
|
||||||
|
return (
|
||||||
|
<Toast onClose={hideToast}>
|
||||||
|
{i18n('message--giftBadge--unopened--toast--incoming')}
|
||||||
|
</Toast>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toastType === ToastType.CannotOpenGiftBadgeOutgoing) {
|
||||||
|
return (
|
||||||
|
<Toast onClose={hideToast}>
|
||||||
|
{i18n('message--giftBadge--unopened--toast--outgoing')}
|
||||||
|
</Toast>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (toastType === ToastType.CannotStartGroupCall) {
|
if (toastType === ToastType.CannotStartGroupCall) {
|
||||||
return (
|
return (
|
||||||
<Toast onClose={hideToast}>
|
<Toast onClose={hideToast}>
|
||||||
|
@ -173,6 +189,10 @@ export function ToastManager({
|
||||||
return <Toast onClose={hideToast}>{i18n('pinnedConversationsFull')}</Toast>;
|
return <Toast onClose={hideToast}>{i18n('pinnedConversationsFull')}</Toast>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (toastType === ToastType.ReactionFailed) {
|
||||||
|
return <Toast onClose={hideToast}>{i18n('Reactions--error')}</Toast>;
|
||||||
|
}
|
||||||
|
|
||||||
if (toastType === ToastType.StoryMuted) {
|
if (toastType === ToastType.StoryMuted) {
|
||||||
return (
|
return (
|
||||||
<Toast onClose={hideToast} timeout={SHORT_TIMEOUT}>
|
<Toast onClose={hideToast} timeout={SHORT_TIMEOUT}>
|
||||||
|
@ -221,6 +241,22 @@ export function ToastManager({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (toastType === ToastType.TapToViewExpiredIncoming) {
|
||||||
|
return (
|
||||||
|
<Toast onClose={hideToast}>
|
||||||
|
{i18n('Message--tap-to-view--incoming--expired-toast')}
|
||||||
|
</Toast>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toastType === ToastType.TapToViewExpiredOutgoing) {
|
||||||
|
return (
|
||||||
|
<Toast onClose={hideToast}>
|
||||||
|
{i18n('Message--tap-to-view--outgoing--expired-toast')}
|
||||||
|
</Toast>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (toastType === ToastType.UnableToLoadAttachment) {
|
if (toastType === ToastType.UnableToLoadAttachment) {
|
||||||
return <Toast onClose={hideToast}>{i18n('unableToLoadAttachment')}</Toast>;
|
return <Toast onClose={hideToast}>{i18n('unableToLoadAttachment')}</Toast>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,28 +0,0 @@
|
||||||
// Copyright 2021 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { action } from '@storybook/addon-actions';
|
|
||||||
import { ToastReactionFailed } from './ToastReactionFailed';
|
|
||||||
|
|
||||||
import { setupI18n } from '../util/setupI18n';
|
|
||||||
import enMessages from '../../_locales/en/messages.json';
|
|
||||||
|
|
||||||
const i18n = setupI18n('en', enMessages);
|
|
||||||
|
|
||||||
const defaultProps = {
|
|
||||||
i18n,
|
|
||||||
onClose: action('onClose'),
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
title: 'Components/ToastReactionFailed',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const _ToastReactionFailed = (): JSX.Element => (
|
|
||||||
<ToastReactionFailed {...defaultProps} />
|
|
||||||
);
|
|
||||||
|
|
||||||
_ToastReactionFailed.story = {
|
|
||||||
name: 'ToastReactionFailed',
|
|
||||||
};
|
|
|
@ -1,15 +0,0 @@
|
||||||
// Copyright 2021 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import type { LocalizerType } from '../types/Util';
|
|
||||||
import { Toast } from './Toast';
|
|
||||||
|
|
||||||
type PropsType = {
|
|
||||||
i18n: LocalizerType;
|
|
||||||
onClose: () => unknown;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function ToastReactionFailed({ i18n, onClose }: PropsType): JSX.Element {
|
|
||||||
return <Toast onClose={onClose}>{i18n('Reactions--error')}</Toast>;
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
// Copyright 2021 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { action } from '@storybook/addon-actions';
|
|
||||||
import { ToastTapToViewExpiredIncoming } from './ToastTapToViewExpiredIncoming';
|
|
||||||
|
|
||||||
import { setupI18n } from '../util/setupI18n';
|
|
||||||
import enMessages from '../../_locales/en/messages.json';
|
|
||||||
|
|
||||||
const i18n = setupI18n('en', enMessages);
|
|
||||||
|
|
||||||
const defaultProps = {
|
|
||||||
i18n,
|
|
||||||
onClose: action('onClose'),
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
title: 'Components/ToastTapToViewExpiredIncoming',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const _ToastTapToViewExpiredIncoming = (): JSX.Element => (
|
|
||||||
<ToastTapToViewExpiredIncoming {...defaultProps} />
|
|
||||||
);
|
|
||||||
|
|
||||||
_ToastTapToViewExpiredIncoming.story = {
|
|
||||||
name: 'ToastTapToViewExpiredIncoming',
|
|
||||||
};
|
|
|
@ -1,22 +0,0 @@
|
||||||
// Copyright 2021 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import type { LocalizerType } from '../types/Util';
|
|
||||||
import { Toast } from './Toast';
|
|
||||||
|
|
||||||
type PropsType = {
|
|
||||||
i18n: LocalizerType;
|
|
||||||
onClose: () => unknown;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function ToastTapToViewExpiredIncoming({
|
|
||||||
i18n,
|
|
||||||
onClose,
|
|
||||||
}: PropsType): JSX.Element {
|
|
||||||
return (
|
|
||||||
<Toast onClose={onClose}>
|
|
||||||
{i18n('Message--tap-to-view--incoming--expired-toast')}
|
|
||||||
</Toast>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
// Copyright 2021 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import { action } from '@storybook/addon-actions';
|
|
||||||
import { ToastTapToViewExpiredOutgoing } from './ToastTapToViewExpiredOutgoing';
|
|
||||||
|
|
||||||
import { setupI18n } from '../util/setupI18n';
|
|
||||||
import enMessages from '../../_locales/en/messages.json';
|
|
||||||
|
|
||||||
const i18n = setupI18n('en', enMessages);
|
|
||||||
|
|
||||||
const defaultProps = {
|
|
||||||
i18n,
|
|
||||||
onClose: action('onClose'),
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
|
||||||
title: 'Components/ToastTapToViewExpiredOutgoing',
|
|
||||||
};
|
|
||||||
|
|
||||||
export const _ToastTapToViewExpiredOutgoing = (): JSX.Element => (
|
|
||||||
<ToastTapToViewExpiredOutgoing {...defaultProps} />
|
|
||||||
);
|
|
||||||
|
|
||||||
_ToastTapToViewExpiredOutgoing.story = {
|
|
||||||
name: 'ToastTapToViewExpiredOutgoing',
|
|
||||||
};
|
|
|
@ -1,22 +0,0 @@
|
||||||
// Copyright 2021 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import type { LocalizerType } from '../types/Util';
|
|
||||||
import { Toast } from './Toast';
|
|
||||||
|
|
||||||
type PropsType = {
|
|
||||||
i18n: LocalizerType;
|
|
||||||
onClose: () => unknown;
|
|
||||||
};
|
|
||||||
|
|
||||||
export function ToastTapToViewExpiredOutgoing({
|
|
||||||
i18n,
|
|
||||||
onClose,
|
|
||||||
}: PropsType): JSX.Element {
|
|
||||||
return (
|
|
||||||
<Toast onClose={onClose}>
|
|
||||||
{i18n('Message--tap-to-view--outgoing--expired-toast')}
|
|
||||||
</Toast>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -91,6 +91,7 @@ import type { AnyPaymentEvent } from '../../types/Payment';
|
||||||
import { Emojify } from './Emojify';
|
import { Emojify } from './Emojify';
|
||||||
import { getPaymentEventDescription } from '../../messages/helpers';
|
import { getPaymentEventDescription } from '../../messages/helpers';
|
||||||
import { PanelType } from '../../types/Panels';
|
import { PanelType } from '../../types/Panels';
|
||||||
|
import { openLinkInWebBrowser } from '../../util/openLinkInWebBrowser';
|
||||||
|
|
||||||
const GUESS_METADATA_WIDTH_TIMESTAMP_SIZE = 16;
|
const GUESS_METADATA_WIDTH_TIMESTAMP_SIZE = 16;
|
||||||
const GUESS_METADATA_WIDTH_EXPIRE_TIMER_SIZE = 18;
|
const GUESS_METADATA_WIDTH_EXPIRE_TIMER_SIZE = 18;
|
||||||
|
@ -317,7 +318,6 @@ export type PropsActions = {
|
||||||
attachment: AttachmentType;
|
attachment: AttachmentType;
|
||||||
messageId: string;
|
messageId: string;
|
||||||
}) => void;
|
}) => void;
|
||||||
markViewed(messageId: string): void;
|
|
||||||
saveAttachment: SaveAttachmentActionCreatorType;
|
saveAttachment: SaveAttachmentActionCreatorType;
|
||||||
showLightbox: (options: {
|
showLightbox: (options: {
|
||||||
attachment: AttachmentType;
|
attachment: AttachmentType;
|
||||||
|
@ -325,7 +325,6 @@ export type PropsActions = {
|
||||||
}) => void;
|
}) => void;
|
||||||
showLightboxForViewOnceMedia: (messageId: string) => unknown;
|
showLightboxForViewOnceMedia: (messageId: string) => unknown;
|
||||||
|
|
||||||
openLink: (url: string) => void;
|
|
||||||
scrollToQuotedMessage: (options: {
|
scrollToQuotedMessage: (options: {
|
||||||
authorId: string;
|
authorId: string;
|
||||||
sentAt: number;
|
sentAt: number;
|
||||||
|
@ -1072,7 +1071,6 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
i18n,
|
i18n,
|
||||||
id,
|
id,
|
||||||
kickOffAttachmentDownload,
|
kickOffAttachmentDownload,
|
||||||
openLink,
|
|
||||||
previews,
|
previews,
|
||||||
quote,
|
quote,
|
||||||
shouldCollapseAbove,
|
shouldCollapseAbove,
|
||||||
|
@ -1123,7 +1121,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
openLink(first.url);
|
openLinkInWebBrowser(first.url);
|
||||||
}
|
}
|
||||||
: noop;
|
: noop;
|
||||||
const contents = (
|
const contents = (
|
||||||
|
@ -1208,14 +1206,14 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
openLink(first.url);
|
openLinkInWebBrowser(first.url);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onClick={(event: React.MouseEvent) => {
|
onClick={(event: React.MouseEvent) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
openLink(first.url);
|
openLinkInWebBrowser(first.url);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{contents}
|
{contents}
|
||||||
|
@ -2277,15 +2275,8 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attachments && !isDownloaded(attachments[0])) {
|
event.preventDefault();
|
||||||
event.preventDefault();
|
event.stopPropagation();
|
||||||
event.stopPropagation();
|
|
||||||
kickOffAttachmentDownload({
|
|
||||||
attachment: attachments[0],
|
|
||||||
messageId: id,
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isTapToViewExpired) {
|
if (isTapToViewExpired) {
|
||||||
const action =
|
const action =
|
||||||
|
@ -2293,13 +2284,21 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
? showExpiredOutgoingTapToViewToast
|
? showExpiredOutgoingTapToViewToast
|
||||||
: showExpiredIncomingTapToViewToast;
|
: showExpiredIncomingTapToViewToast;
|
||||||
action();
|
action();
|
||||||
} else {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
showLightboxForViewOnceMedia(id);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (attachments && !isDownloaded(attachments[0])) {
|
||||||
|
kickOffAttachmentDownload({
|
||||||
|
attachment: attachments[0],
|
||||||
|
messageId: id,
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showLightboxForViewOnceMedia(id);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,10 +77,8 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||||
doubleCheckMissingQuoteReference: action('doubleCheckMissingQuoteReference'),
|
doubleCheckMissingQuoteReference: action('doubleCheckMissingQuoteReference'),
|
||||||
kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
|
kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
|
||||||
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
|
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
|
||||||
markViewed: action('markViewed'),
|
|
||||||
showConversation: action('showConversation'),
|
showConversation: action('showConversation'),
|
||||||
openGiftBadge: action('openGiftBadge'),
|
openGiftBadge: action('openGiftBadge'),
|
||||||
openLink: action('openLink'),
|
|
||||||
renderAudioAttachment: () => <div>*AudioAttachment*</div>,
|
renderAudioAttachment: () => <div>*AudioAttachment*</div>,
|
||||||
saveAttachment: action('saveAttachment'),
|
saveAttachment: action('saveAttachment'),
|
||||||
pushPanelForConversation: action('pushPanelForConversation'),
|
pushPanelForConversation: action('pushPanelForConversation'),
|
||||||
|
|
|
@ -68,7 +68,6 @@ export type PropsData = {
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
theme: ThemeType;
|
theme: ThemeType;
|
||||||
getPreferredBadge: PreferredBadgeSelectorType;
|
getPreferredBadge: PreferredBadgeSelectorType;
|
||||||
markViewed: (messageId: string) => void;
|
|
||||||
} & Pick<
|
} & Pick<
|
||||||
MessagePropsType,
|
MessagePropsType,
|
||||||
| 'getPreferredBadge'
|
| 'getPreferredBadge'
|
||||||
|
@ -79,14 +78,7 @@ export type PropsData = {
|
||||||
|
|
||||||
export type PropsBackboneActions = Pick<
|
export type PropsBackboneActions = Pick<
|
||||||
MessagePropsType,
|
MessagePropsType,
|
||||||
| 'kickOffAttachmentDownload'
|
'renderAudioAttachment' | 'startConversation'
|
||||||
| 'markAttachmentAsCorrupted'
|
|
||||||
| 'openGiftBadge'
|
|
||||||
| 'openLink'
|
|
||||||
| 'renderAudioAttachment'
|
|
||||||
| 'showExpiredIncomingTapToViewToast'
|
|
||||||
| 'showExpiredOutgoingTapToViewToast'
|
|
||||||
| 'startConversation'
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type PropsReduxActions = Pick<
|
export type PropsReduxActions = Pick<
|
||||||
|
@ -94,10 +86,15 @@ export type PropsReduxActions = Pick<
|
||||||
| 'checkForAccount'
|
| 'checkForAccount'
|
||||||
| 'clearSelectedMessage'
|
| 'clearSelectedMessage'
|
||||||
| 'doubleCheckMissingQuoteReference'
|
| 'doubleCheckMissingQuoteReference'
|
||||||
|
| 'kickOffAttachmentDownload'
|
||||||
|
| 'markAttachmentAsCorrupted'
|
||||||
|
| 'openGiftBadge'
|
||||||
| 'pushPanelForConversation'
|
| 'pushPanelForConversation'
|
||||||
| 'saveAttachment'
|
| 'saveAttachment'
|
||||||
| 'showContactModal'
|
| 'showContactModal'
|
||||||
| 'showConversation'
|
| 'showConversation'
|
||||||
|
| 'showExpiredIncomingTapToViewToast'
|
||||||
|
| 'showExpiredOutgoingTapToViewToast'
|
||||||
| 'showLightbox'
|
| 'showLightbox'
|
||||||
| 'showLightboxForViewOnceMedia'
|
| 'showLightboxForViewOnceMedia'
|
||||||
| 'viewStory'
|
| 'viewStory'
|
||||||
|
@ -289,9 +286,7 @@ export class MessageDetail extends React.Component<Props> {
|
||||||
interactionMode,
|
interactionMode,
|
||||||
kickOffAttachmentDownload,
|
kickOffAttachmentDownload,
|
||||||
markAttachmentAsCorrupted,
|
markAttachmentAsCorrupted,
|
||||||
markViewed,
|
|
||||||
openGiftBadge,
|
openGiftBadge,
|
||||||
openLink,
|
|
||||||
pushPanelForConversation,
|
pushPanelForConversation,
|
||||||
renderAudioAttachment,
|
renderAudioAttachment,
|
||||||
saveAttachment,
|
saveAttachment,
|
||||||
|
@ -334,11 +329,9 @@ export class MessageDetail extends React.Component<Props> {
|
||||||
interactionMode={interactionMode}
|
interactionMode={interactionMode}
|
||||||
kickOffAttachmentDownload={kickOffAttachmentDownload}
|
kickOffAttachmentDownload={kickOffAttachmentDownload}
|
||||||
markAttachmentAsCorrupted={markAttachmentAsCorrupted}
|
markAttachmentAsCorrupted={markAttachmentAsCorrupted}
|
||||||
markViewed={markViewed}
|
|
||||||
messageExpanded={noop}
|
messageExpanded={noop}
|
||||||
showConversation={showConversation}
|
showConversation={showConversation}
|
||||||
openGiftBadge={openGiftBadge}
|
openGiftBadge={openGiftBadge}
|
||||||
openLink={openLink}
|
|
||||||
pushPanelForConversation={pushPanelForConversation}
|
pushPanelForConversation={pushPanelForConversation}
|
||||||
renderAudioAttachment={renderAudioAttachment}
|
renderAudioAttachment={renderAudioAttachment}
|
||||||
saveAttachment={saveAttachment}
|
saveAttachment={saveAttachment}
|
||||||
|
|
|
@ -110,11 +110,9 @@ const defaultMessageProps: TimelineMessagesProps = {
|
||||||
isMessageRequestAccepted: true,
|
isMessageRequestAccepted: true,
|
||||||
kickOffAttachmentDownload: action('default--kickOffAttachmentDownload'),
|
kickOffAttachmentDownload: action('default--kickOffAttachmentDownload'),
|
||||||
markAttachmentAsCorrupted: action('default--markAttachmentAsCorrupted'),
|
markAttachmentAsCorrupted: action('default--markAttachmentAsCorrupted'),
|
||||||
markViewed: action('default--markViewed'),
|
|
||||||
messageExpanded: action('default--message-expanded'),
|
messageExpanded: action('default--message-expanded'),
|
||||||
showConversation: action('default--showConversation'),
|
showConversation: action('default--showConversation'),
|
||||||
openGiftBadge: action('openGiftBadge'),
|
openGiftBadge: action('openGiftBadge'),
|
||||||
openLink: action('default--openLink'),
|
|
||||||
previews: [],
|
previews: [],
|
||||||
reactToMessage: action('default--reactToMessage'),
|
reactToMessage: action('default--reactToMessage'),
|
||||||
readStatus: ReadStatus.Read,
|
readStatus: ReadStatus.Read,
|
||||||
|
@ -122,7 +120,7 @@ const defaultMessageProps: TimelineMessagesProps = {
|
||||||
renderReactionPicker: () => <div />,
|
renderReactionPicker: () => <div />,
|
||||||
renderAudioAttachment: () => <div>*AudioAttachment*</div>,
|
renderAudioAttachment: () => <div>*AudioAttachment*</div>,
|
||||||
setQuoteByMessageId: action('default--setQuoteByMessageId'),
|
setQuoteByMessageId: action('default--setQuoteByMessageId'),
|
||||||
retrySend: action('default--retrySend'),
|
retryMessageSend: action('default--retryMessageSend'),
|
||||||
retryDeleteForEveryone: action('default--retryDeleteForEveryone'),
|
retryDeleteForEveryone: action('default--retryDeleteForEveryone'),
|
||||||
saveAttachment: action('saveAttachment'),
|
saveAttachment: action('saveAttachment'),
|
||||||
scrollToQuotedMessage: action('default--scrollToQuotedMessage'),
|
scrollToQuotedMessage: action('default--scrollToQuotedMessage'),
|
||||||
|
|
|
@ -278,23 +278,22 @@ const actions = () => ({
|
||||||
reactToMessage: action('reactToMessage'),
|
reactToMessage: action('reactToMessage'),
|
||||||
setQuoteByMessageId: action('setQuoteByMessageId'),
|
setQuoteByMessageId: action('setQuoteByMessageId'),
|
||||||
retryDeleteForEveryone: action('retryDeleteForEveryone'),
|
retryDeleteForEveryone: action('retryDeleteForEveryone'),
|
||||||
retrySend: action('retrySend'),
|
retryMessageSend: action('retryMessageSend'),
|
||||||
deleteMessage: action('deleteMessage'),
|
deleteMessage: action('deleteMessage'),
|
||||||
deleteMessageForEveryone: action('deleteMessageForEveryone'),
|
deleteMessageForEveryone: action('deleteMessageForEveryone'),
|
||||||
showMessageDetail: action('showMessageDetail'),
|
showMessageDetail: action('showMessageDetail'),
|
||||||
saveAttachment: action('saveAttachment'),
|
saveAttachment: action('saveAttachment'),
|
||||||
pushPanelForConversation: action('pushPanelForConversation'),
|
pushPanelForConversation: action('pushPanelForConversation'),
|
||||||
|
showContactDetail: action('showContactDetail'),
|
||||||
showContactModal: action('showContactModal'),
|
showContactModal: action('showContactModal'),
|
||||||
showConversation: action('showConversation'),
|
showConversation: action('showConversation'),
|
||||||
kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
|
kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
|
||||||
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
|
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
|
||||||
markViewed: action('markViewed'),
|
|
||||||
messageExpanded: action('messageExpanded'),
|
messageExpanded: action('messageExpanded'),
|
||||||
showLightbox: action('showLightbox'),
|
showLightbox: action('showLightbox'),
|
||||||
showLightboxForViewOnceMedia: action('showLightboxForViewOnceMedia'),
|
showLightboxForViewOnceMedia: action('showLightboxForViewOnceMedia'),
|
||||||
doubleCheckMissingQuoteReference: action('doubleCheckMissingQuoteReference'),
|
doubleCheckMissingQuoteReference: action('doubleCheckMissingQuoteReference'),
|
||||||
|
|
||||||
openLink: action('openLink'),
|
|
||||||
openGiftBadge: action('openGiftBadge'),
|
openGiftBadge: action('openGiftBadge'),
|
||||||
scrollToQuotedMessage: action('scrollToQuotedMessage'),
|
scrollToQuotedMessage: action('scrollToQuotedMessage'),
|
||||||
showExpiredIncomingTapToViewToast: action(
|
showExpiredIncomingTapToViewToast: action(
|
||||||
|
@ -307,8 +306,6 @@ const actions = () => ({
|
||||||
|
|
||||||
toggleSafetyNumberModal: action('toggleSafetyNumberModal'),
|
toggleSafetyNumberModal: action('toggleSafetyNumberModal'),
|
||||||
|
|
||||||
downloadNewVersion: action('downloadNewVersion'),
|
|
||||||
|
|
||||||
startCallingLobby: action('startCallingLobby'),
|
startCallingLobby: action('startCallingLobby'),
|
||||||
startConversation: action('startConversation'),
|
startConversation: action('startConversation'),
|
||||||
returnToActiveCall: action('returnToActiveCall'),
|
returnToActiveCall: action('returnToActiveCall'),
|
||||||
|
|
|
@ -19,11 +19,8 @@ import { clearTimeoutIfNecessary } from '../../util/clearTimeoutIfNecessary';
|
||||||
import { WidthBreakpoint } from '../_util';
|
import { WidthBreakpoint } from '../_util';
|
||||||
|
|
||||||
import type { PropsActions as MessageActionsType } from './TimelineMessage';
|
import type { PropsActions as MessageActionsType } from './TimelineMessage';
|
||||||
import type { PropsActions as UnsupportedMessageActionsType } from './UnsupportedMessage';
|
|
||||||
import type { PropsActionsType as ChatSessionRefreshedNotificationActionsType } from './ChatSessionRefreshedNotification';
|
import type { PropsActionsType as ChatSessionRefreshedNotificationActionsType } from './ChatSessionRefreshedNotification';
|
||||||
import type { PropsActionsType as GroupV2ChangeActionsType } from './GroupV2Change';
|
|
||||||
import { ErrorBoundary } from './ErrorBoundary';
|
import { ErrorBoundary } from './ErrorBoundary';
|
||||||
import type { PropsActions as SafetyNumberActionsType } from './SafetyNumberNotification';
|
|
||||||
import { Intl } from '../Intl';
|
import { Intl } from '../Intl';
|
||||||
import { TimelineWarning } from './TimelineWarning';
|
import { TimelineWarning } from './TimelineWarning';
|
||||||
import { TimelineWarnings } from './TimelineWarnings';
|
import { TimelineWarnings } from './TimelineWarnings';
|
||||||
|
@ -47,6 +44,8 @@ import {
|
||||||
} from '../../util/scrollUtil';
|
} from '../../util/scrollUtil';
|
||||||
import { LastSeenIndicator } from './LastSeenIndicator';
|
import { LastSeenIndicator } from './LastSeenIndicator';
|
||||||
import { MINUTE } from '../../util/durations';
|
import { MINUTE } from '../../util/durations';
|
||||||
|
import type { PropsActionsType as DeliveryIssueNotificationActionsType } from './DeliveryIssueNotification';
|
||||||
|
import type { PropsActionsType as GroupV2ChangeActionsType } from './GroupV2Change';
|
||||||
|
|
||||||
const AT_BOTTOM_THRESHOLD = 15;
|
const AT_BOTTOM_THRESHOLD = 15;
|
||||||
const AT_BOTTOM_DETECTOR_STYLE = { height: AT_BOTTOM_THRESHOLD };
|
const AT_BOTTOM_DETECTOR_STYLE = { height: AT_BOTTOM_THRESHOLD };
|
||||||
|
@ -125,7 +124,7 @@ type PropsHousekeepingType = {
|
||||||
theme: ThemeType;
|
theme: ThemeType;
|
||||||
|
|
||||||
renderItem: (props: {
|
renderItem: (props: {
|
||||||
actionProps: PropsActionsType;
|
actionProps: PropsActionsFromBackboneForChildrenType;
|
||||||
containerElementRef: RefObject<HTMLElement>;
|
containerElementRef: RefObject<HTMLElement>;
|
||||||
containerWidthBreakpoint: WidthBreakpoint;
|
containerWidthBreakpoint: WidthBreakpoint;
|
||||||
conversationId: string;
|
conversationId: string;
|
||||||
|
@ -146,41 +145,47 @@ type PropsHousekeepingType = {
|
||||||
) => JSX.Element;
|
) => JSX.Element;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type PropsActionsFromBackboneForChildrenType = Pick<
|
||||||
|
MessageActionsType,
|
||||||
|
'scrollToQuotedMessage' | 'showMessageDetail' | 'startConversation'
|
||||||
|
> &
|
||||||
|
ChatSessionRefreshedNotificationActionsType &
|
||||||
|
DeliveryIssueNotificationActionsType &
|
||||||
|
GroupV2ChangeActionsType;
|
||||||
|
|
||||||
export type PropsActionsType = {
|
export type PropsActionsType = {
|
||||||
|
// From Backbone
|
||||||
acknowledgeGroupMemberNameCollisions: (
|
acknowledgeGroupMemberNameCollisions: (
|
||||||
groupNameCollisions: Readonly<GroupNameCollisionsWithIdsByTitle>
|
groupNameCollisions: Readonly<GroupNameCollisionsWithIdsByTitle>
|
||||||
) => void;
|
) => void;
|
||||||
|
loadOlderMessages: (messageId: string) => unknown;
|
||||||
|
loadNewerMessages: (messageId: string) => unknown;
|
||||||
|
loadNewestMessages: (messageId: string, setFocus?: boolean) => unknown;
|
||||||
|
markMessageRead: (messageId: string) => unknown;
|
||||||
|
removeMember: (conversationId: string) => unknown;
|
||||||
|
unblurAvatar: () => void;
|
||||||
|
updateSharedGroups: () => unknown;
|
||||||
|
|
||||||
|
// From Redux
|
||||||
|
acceptConversation: (conversationId: string) => unknown;
|
||||||
|
blockConversation: (conversationId: string) => unknown;
|
||||||
|
blockAndReportSpam: (conversationId: string) => unknown;
|
||||||
clearInvitedUuidsForNewlyCreatedGroup: () => void;
|
clearInvitedUuidsForNewlyCreatedGroup: () => void;
|
||||||
|
clearSelectedMessage: () => unknown;
|
||||||
closeContactSpoofingReview: () => void;
|
closeContactSpoofingReview: () => void;
|
||||||
|
deleteConversation: (conversationId: string) => unknown;
|
||||||
setIsNearBottom: (conversationId: string, isNearBottom: boolean) => unknown;
|
setIsNearBottom: (conversationId: string, isNearBottom: boolean) => unknown;
|
||||||
|
peekGroupCallForTheFirstTime: (conversationId: string) => unknown;
|
||||||
|
peekGroupCallIfItHasMembers: (conversationId: string) => unknown;
|
||||||
reviewGroupMemberNameCollision: (groupConversationId: string) => void;
|
reviewGroupMemberNameCollision: (groupConversationId: string) => void;
|
||||||
reviewMessageRequestNameCollision: (
|
reviewMessageRequestNameCollision: (
|
||||||
_: Readonly<{
|
_: Readonly<{
|
||||||
safeConversationId: string;
|
safeConversationId: string;
|
||||||
}>
|
}>
|
||||||
) => void;
|
) => void;
|
||||||
|
|
||||||
learnMoreAboutDeliveryIssue: () => unknown;
|
|
||||||
loadOlderMessages: (messageId: string) => unknown;
|
|
||||||
loadNewerMessages: (messageId: string) => unknown;
|
|
||||||
loadNewestMessages: (messageId: string, setFocus?: boolean) => unknown;
|
|
||||||
markMessageRead: (messageId: string) => unknown;
|
|
||||||
blockConversation: (conversationId: string) => unknown;
|
|
||||||
blockAndReportSpam: (conversationId: string) => unknown;
|
|
||||||
deleteConversation: (conversationId: string) => unknown;
|
|
||||||
acceptConversation: (conversationId: string) => unknown;
|
|
||||||
peekGroupCallForTheFirstTime: (conversationId: string) => unknown;
|
|
||||||
peekGroupCallIfItHasMembers: (conversationId: string) => unknown;
|
|
||||||
removeMember: (conversationId: string) => unknown;
|
|
||||||
selectMessage: (messageId: string, conversationId: string) => unknown;
|
selectMessage: (messageId: string, conversationId: string) => unknown;
|
||||||
clearSelectedMessage: () => unknown;
|
showContactModal: (contactId: string, conversationId?: string) => void;
|
||||||
unblurAvatar: () => void;
|
} & PropsActionsFromBackboneForChildrenType;
|
||||||
updateSharedGroups: () => unknown;
|
|
||||||
} & MessageActionsType &
|
|
||||||
SafetyNumberActionsType &
|
|
||||||
UnsupportedMessageActionsType &
|
|
||||||
GroupV2ChangeActionsType &
|
|
||||||
ChatSessionRefreshedNotificationActionsType;
|
|
||||||
|
|
||||||
export type PropsType = PropsDataType &
|
export type PropsType = PropsDataType &
|
||||||
PropsHousekeepingType &
|
PropsHousekeepingType &
|
||||||
|
@ -209,69 +214,29 @@ const getActions = createSelector(
|
||||||
// use `createSelector` to memoize them by the last seen `props` object.
|
// use `createSelector` to memoize them by the last seen `props` object.
|
||||||
(props: PropsType) => props,
|
(props: PropsType) => props,
|
||||||
|
|
||||||
(props: PropsType): PropsActionsType => {
|
(props: PropsType): PropsActionsFromBackboneForChildrenType => {
|
||||||
|
// Note: Because TimelineItem is smart, we only need to include action creators here
|
||||||
|
// which are passed in from backbone and not available via mapDispatchToProps
|
||||||
const unsafe = pick(props, [
|
const unsafe = pick(props, [
|
||||||
'acknowledgeGroupMemberNameCollisions',
|
// MessageActionsType
|
||||||
'blockGroupLinkRequests',
|
|
||||||
'clearInvitedUuidsForNewlyCreatedGroup',
|
|
||||||
'closeContactSpoofingReview',
|
|
||||||
'setIsNearBottom',
|
|
||||||
'reviewGroupMemberNameCollision',
|
|
||||||
'reviewMessageRequestNameCollision',
|
|
||||||
'learnMoreAboutDeliveryIssue',
|
|
||||||
'loadOlderMessages',
|
|
||||||
'loadNewerMessages',
|
|
||||||
'loadNewestMessages',
|
|
||||||
'markMessageRead',
|
|
||||||
'markViewed',
|
|
||||||
'acceptConversation',
|
|
||||||
'blockAndReportSpam',
|
|
||||||
'blockConversation',
|
|
||||||
'deleteConversation',
|
|
||||||
'peekGroupCallForTheFirstTime',
|
|
||||||
'peekGroupCallIfItHasMembers',
|
|
||||||
'removeMember',
|
|
||||||
'selectMessage',
|
|
||||||
'clearSelectedMessage',
|
|
||||||
'unblurAvatar',
|
|
||||||
'updateSharedGroups',
|
|
||||||
|
|
||||||
'doubleCheckMissingQuoteReference',
|
|
||||||
'checkForAccount',
|
|
||||||
'reactToMessage',
|
|
||||||
'retryDeleteForEveryone',
|
|
||||||
'retrySend',
|
|
||||||
'toggleForwardMessageModal',
|
|
||||||
'deleteMessage',
|
|
||||||
'deleteMessageForEveryone',
|
|
||||||
'showConversation',
|
|
||||||
'showMessageDetail',
|
|
||||||
'openGiftBadge',
|
|
||||||
'setQuoteByMessageId',
|
|
||||||
'showContactModal',
|
|
||||||
'kickOffAttachmentDownload',
|
|
||||||
'markAttachmentAsCorrupted',
|
|
||||||
'messageExpanded',
|
|
||||||
'saveAttachment',
|
|
||||||
'showLightbox',
|
|
||||||
'showLightboxForViewOnceMedia',
|
|
||||||
'openLink',
|
|
||||||
'pushPanelForConversation',
|
|
||||||
'scrollToQuotedMessage',
|
'scrollToQuotedMessage',
|
||||||
'showExpiredIncomingTapToViewToast',
|
'showMessageDetail',
|
||||||
'showExpiredOutgoingTapToViewToast',
|
|
||||||
'startConversation',
|
'startConversation',
|
||||||
|
|
||||||
'toggleSafetyNumberModal',
|
// ChatSessionRefreshedNotificationActionsType
|
||||||
|
|
||||||
'downloadNewVersion',
|
|
||||||
|
|
||||||
'contactSupport',
|
'contactSupport',
|
||||||
|
|
||||||
'viewStory',
|
// DeliveryIssueNotificationActionsType
|
||||||
|
'learnMoreAboutDeliveryIssue',
|
||||||
|
|
||||||
|
// GroupV2ChangeActionsType
|
||||||
|
'blockGroupLinkRequests',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const safe: AssertProps<PropsActionsType, typeof unsafe> = unsafe;
|
const safe: AssertProps<
|
||||||
|
PropsActionsFromBackboneForChildrenType,
|
||||||
|
typeof unsafe
|
||||||
|
> = unsafe;
|
||||||
|
|
||||||
return safe;
|
return safe;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,14 +68,13 @@ const getDefaultProps = () => ({
|
||||||
contactSupport: action('contactSupport'),
|
contactSupport: action('contactSupport'),
|
||||||
setQuoteByMessageId: action('setQuoteByMessageId'),
|
setQuoteByMessageId: action('setQuoteByMessageId'),
|
||||||
retryDeleteForEveryone: action('retryDeleteForEveryone'),
|
retryDeleteForEveryone: action('retryDeleteForEveryone'),
|
||||||
retrySend: action('retrySend'),
|
retryMessageSend: action('retryMessageSend'),
|
||||||
blockGroupLinkRequests: action('blockGroupLinkRequests'),
|
blockGroupLinkRequests: action('blockGroupLinkRequests'),
|
||||||
deleteMessage: action('deleteMessage'),
|
deleteMessage: action('deleteMessage'),
|
||||||
deleteMessageForEveryone: action('deleteMessageForEveryone'),
|
deleteMessageForEveryone: action('deleteMessageForEveryone'),
|
||||||
kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
|
kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
|
||||||
learnMoreAboutDeliveryIssue: action('learnMoreAboutDeliveryIssue'),
|
learnMoreAboutDeliveryIssue: action('learnMoreAboutDeliveryIssue'),
|
||||||
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
|
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
|
||||||
markViewed: action('markViewed'),
|
|
||||||
messageExpanded: action('messageExpanded'),
|
messageExpanded: action('messageExpanded'),
|
||||||
showMessageDetail: action('showMessageDetail'),
|
showMessageDetail: action('showMessageDetail'),
|
||||||
showConversation: action('showConversation'),
|
showConversation: action('showConversation'),
|
||||||
|
@ -93,9 +92,7 @@ const getDefaultProps = () => ({
|
||||||
showExpiredOutgoingTapToViewToast: action(
|
showExpiredOutgoingTapToViewToast: action(
|
||||||
'showExpiredIncomingTapToViewToast'
|
'showExpiredIncomingTapToViewToast'
|
||||||
),
|
),
|
||||||
openLink: action('openLink'),
|
|
||||||
scrollToQuotedMessage: action('scrollToQuotedMessage'),
|
scrollToQuotedMessage: action('scrollToQuotedMessage'),
|
||||||
downloadNewVersion: action('downloadNewVersion'),
|
|
||||||
toggleSafetyNumberModal: action('toggleSafetyNumberModal'),
|
toggleSafetyNumberModal: action('toggleSafetyNumberModal'),
|
||||||
startCallingLobby: action('startCallingLobby'),
|
startCallingLobby: action('startCallingLobby'),
|
||||||
startConversation: action('startConversation'),
|
startConversation: action('startConversation'),
|
||||||
|
|
|
@ -26,10 +26,7 @@ import type { PropsData as ChangeNumberNotificationProps } from './ChangeNumberN
|
||||||
import { ChangeNumberNotification } from './ChangeNumberNotification';
|
import { ChangeNumberNotification } from './ChangeNumberNotification';
|
||||||
import type { CallingNotificationType } from '../../util/callingNotification';
|
import type { CallingNotificationType } from '../../util/callingNotification';
|
||||||
import { InlineNotificationWrapper } from './InlineNotificationWrapper';
|
import { InlineNotificationWrapper } from './InlineNotificationWrapper';
|
||||||
import type {
|
import type { PropsData as UnsupportedMessageProps } from './UnsupportedMessage';
|
||||||
PropsActions as UnsupportedMessageActionsType,
|
|
||||||
PropsData as UnsupportedMessageProps,
|
|
||||||
} from './UnsupportedMessage';
|
|
||||||
import { UnsupportedMessage } from './UnsupportedMessage';
|
import { UnsupportedMessage } from './UnsupportedMessage';
|
||||||
import type { PropsData as TimerNotificationProps } from './TimerNotification';
|
import type { PropsData as TimerNotificationProps } from './TimerNotification';
|
||||||
import { TimerNotification } from './TimerNotification';
|
import { TimerNotification } from './TimerNotification';
|
||||||
|
@ -177,7 +174,6 @@ type PropsActionsType = MessageActionsType &
|
||||||
DeliveryIssueActionProps &
|
DeliveryIssueActionProps &
|
||||||
GroupV2ChangeActionsType &
|
GroupV2ChangeActionsType &
|
||||||
PropsChatSessionRefreshedActionsType &
|
PropsChatSessionRefreshedActionsType &
|
||||||
UnsupportedMessageActionsType &
|
|
||||||
SafetyNumberActionsType;
|
SafetyNumberActionsType;
|
||||||
|
|
||||||
export type PropsType = PropsLocalType &
|
export type PropsType = PropsLocalType &
|
||||||
|
|
|
@ -277,11 +277,9 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||||
isTapToViewExpired: overrideProps.isTapToViewExpired,
|
isTapToViewExpired: overrideProps.isTapToViewExpired,
|
||||||
kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
|
kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
|
||||||
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
|
markAttachmentAsCorrupted: action('markAttachmentAsCorrupted'),
|
||||||
markViewed: action('markViewed'),
|
|
||||||
messageExpanded: action('messageExpanded'),
|
messageExpanded: action('messageExpanded'),
|
||||||
showConversation: action('showConversation'),
|
showConversation: action('showConversation'),
|
||||||
openGiftBadge: action('openGiftBadge'),
|
openGiftBadge: action('openGiftBadge'),
|
||||||
openLink: action('openLink'),
|
|
||||||
previews: overrideProps.previews || [],
|
previews: overrideProps.previews || [],
|
||||||
quote: overrideProps.quote || undefined,
|
quote: overrideProps.quote || undefined,
|
||||||
reactions: overrideProps.reactions,
|
reactions: overrideProps.reactions,
|
||||||
|
@ -295,7 +293,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||||
renderAudioAttachment,
|
renderAudioAttachment,
|
||||||
saveAttachment: action('saveAttachment'),
|
saveAttachment: action('saveAttachment'),
|
||||||
setQuoteByMessageId: action('setQuoteByMessageId'),
|
setQuoteByMessageId: action('setQuoteByMessageId'),
|
||||||
retrySend: action('retrySend'),
|
retryMessageSend: action('retryMessageSend'),
|
||||||
retryDeleteForEveryone: action('retryDeleteForEveryone'),
|
retryDeleteForEveryone: action('retryDeleteForEveryone'),
|
||||||
scrollToQuotedMessage: action('scrollToQuotedMessage'),
|
scrollToQuotedMessage: action('scrollToQuotedMessage'),
|
||||||
selectMessage: action('selectMessage'),
|
selectMessage: action('selectMessage'),
|
||||||
|
|
|
@ -49,7 +49,7 @@ export type PropsActions = {
|
||||||
id: string,
|
id: string,
|
||||||
{ emoji, remove }: { emoji: string; remove: boolean }
|
{ emoji, remove }: { emoji: string; remove: boolean }
|
||||||
) => void;
|
) => void;
|
||||||
retrySend: (id: string) => void;
|
retryMessageSend: (id: string) => void;
|
||||||
retryDeleteForEveryone: (id: string) => void;
|
retryDeleteForEveryone: (id: string) => void;
|
||||||
setQuoteByMessageId: (conversationId: string, messageId: string) => void;
|
setQuoteByMessageId: (conversationId: string, messageId: string) => void;
|
||||||
} & MessagePropsActions;
|
} & MessagePropsActions;
|
||||||
|
@ -99,7 +99,7 @@ export function TimelineMessage(props: Props): JSX.Element {
|
||||||
setQuoteByMessageId,
|
setQuoteByMessageId,
|
||||||
renderReactionPicker,
|
renderReactionPicker,
|
||||||
renderEmojiPicker,
|
renderEmojiPicker,
|
||||||
retrySend,
|
retryMessageSend,
|
||||||
retryDeleteForEveryone,
|
retryDeleteForEveryone,
|
||||||
selectedReaction,
|
selectedReaction,
|
||||||
toggleForwardMessageModal,
|
toggleForwardMessageModal,
|
||||||
|
@ -395,7 +395,7 @@ export function TimelineMessage(props: Props): JSX.Element {
|
||||||
onDownload={handleDownload}
|
onDownload={handleDownload}
|
||||||
onReplyToMessage={handleReplyToMessage}
|
onReplyToMessage={handleReplyToMessage}
|
||||||
onReact={handleReact}
|
onReact={handleReact}
|
||||||
onRetrySend={canRetry ? () => retrySend(id) : undefined}
|
onRetryMessageSend={canRetry ? () => retryMessageSend(id) : undefined}
|
||||||
onRetryDeleteForEveryone={
|
onRetryDeleteForEveryone={
|
||||||
canRetryDeleteForEveryone
|
canRetryDeleteForEveryone
|
||||||
? () => retryDeleteForEveryone(id)
|
? () => retryDeleteForEveryone(id)
|
||||||
|
@ -575,7 +575,7 @@ type MessageContextProps = {
|
||||||
onDownload: (() => void) | undefined;
|
onDownload: (() => void) | undefined;
|
||||||
onReplyToMessage: (() => void) | undefined;
|
onReplyToMessage: (() => void) | undefined;
|
||||||
onReact: (() => void) | undefined;
|
onReact: (() => void) | undefined;
|
||||||
onRetrySend: (() => void) | undefined;
|
onRetryMessageSend: (() => void) | undefined;
|
||||||
onRetryDeleteForEveryone: (() => void) | undefined;
|
onRetryDeleteForEveryone: (() => void) | undefined;
|
||||||
onForward: (() => void) | undefined;
|
onForward: (() => void) | undefined;
|
||||||
onDeleteForMe: () => void;
|
onDeleteForMe: () => void;
|
||||||
|
@ -591,7 +591,7 @@ const MessageContextMenu = ({
|
||||||
onReplyToMessage,
|
onReplyToMessage,
|
||||||
onReact,
|
onReact,
|
||||||
onMoreInfo,
|
onMoreInfo,
|
||||||
onRetrySend,
|
onRetryMessageSend,
|
||||||
onRetryDeleteForEveryone,
|
onRetryDeleteForEveryone,
|
||||||
onForward,
|
onForward,
|
||||||
onDeleteForMe,
|
onDeleteForMe,
|
||||||
|
@ -660,7 +660,7 @@ const MessageContextMenu = ({
|
||||||
>
|
>
|
||||||
{i18n('moreInfo')}
|
{i18n('moreInfo')}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
{onRetrySend && (
|
{onRetryMessageSend && (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
attributes={{
|
attributes={{
|
||||||
className:
|
className:
|
||||||
|
@ -670,7 +670,7 @@ const MessageContextMenu = ({
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
onRetrySend();
|
onRetryMessageSend();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{i18n('retrySend')}
|
{i18n('retrySend')}
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { boolean, text } from '@storybook/addon-knobs';
|
import { boolean, text } from '@storybook/addon-knobs';
|
||||||
import { action } from '@storybook/addon-actions';
|
|
||||||
|
|
||||||
import { setupI18n } from '../../util/setupI18n';
|
import { setupI18n } from '../../util/setupI18n';
|
||||||
import enMessages from '../../../_locales/en/messages.json';
|
import enMessages from '../../../_locales/en/messages.json';
|
||||||
|
@ -26,7 +25,6 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||||
i18n,
|
i18n,
|
||||||
canProcessNow: boolean('canProcessNow', overrideProps.canProcessNow || false),
|
canProcessNow: boolean('canProcessNow', overrideProps.canProcessNow || false),
|
||||||
contact: overrideProps.contact || ({} as ContactType),
|
contact: overrideProps.contact || ({} as ContactType),
|
||||||
downloadNewVersion: action('downloadNewVersion'),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export function FromSomeone(): JSX.Element {
|
export function FromSomeone(): JSX.Element {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { Button, ButtonSize, ButtonVariant } from '../Button';
|
||||||
import { ContactName } from './ContactName';
|
import { ContactName } from './ContactName';
|
||||||
import { Intl } from '../Intl';
|
import { Intl } from '../Intl';
|
||||||
import type { LocalizerType } from '../../types/Util';
|
import type { LocalizerType } from '../../types/Util';
|
||||||
|
import { openLinkInWebBrowser } from '../../util/openLinkInWebBrowser';
|
||||||
|
|
||||||
export type ContactType = {
|
export type ContactType = {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -23,21 +24,16 @@ export type PropsData = {
|
||||||
contact: ContactType;
|
contact: ContactType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PropsActions = {
|
|
||||||
downloadNewVersion: () => unknown;
|
|
||||||
};
|
|
||||||
|
|
||||||
type PropsHousekeeping = {
|
type PropsHousekeeping = {
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Props = PropsData & PropsHousekeeping & PropsActions;
|
export type Props = PropsData & PropsHousekeeping;
|
||||||
|
|
||||||
export function UnsupportedMessage({
|
export function UnsupportedMessage({
|
||||||
canProcessNow,
|
canProcessNow,
|
||||||
contact,
|
contact,
|
||||||
i18n,
|
i18n,
|
||||||
downloadNewVersion,
|
|
||||||
}: Props): JSX.Element {
|
}: Props): JSX.Element {
|
||||||
const { isMe } = contact;
|
const { isMe } = contact;
|
||||||
|
|
||||||
|
@ -75,7 +71,7 @@ export function UnsupportedMessage({
|
||||||
<div className="SystemMessage__line">
|
<div className="SystemMessage__line">
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
downloadNewVersion();
|
openLinkInWebBrowser('https://signal.org/download');
|
||||||
}}
|
}}
|
||||||
size={ButtonSize.Small}
|
size={ButtonSize.Small}
|
||||||
variant={ButtonVariant.SystemMessage}
|
variant={ButtonVariant.SystemMessage}
|
||||||
|
|
|
@ -67,6 +67,7 @@ import { writeDraftAttachment } from '../../util/writeDraftAttachment';
|
||||||
import { getMessageById } from '../../messages/getMessageById';
|
import { getMessageById } from '../../messages/getMessageById';
|
||||||
import { canReply } from '../selectors/message';
|
import { canReply } from '../selectors/message';
|
||||||
import { getConversationSelector } from '../selectors/conversations';
|
import { getConversationSelector } from '../selectors/conversations';
|
||||||
|
import { enqueueReactionForSend } from '../../reactions/enqueueReactionForSend';
|
||||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
@ -143,6 +144,7 @@ export const actions = {
|
||||||
addPendingAttachment,
|
addPendingAttachment,
|
||||||
onEditorStateChange,
|
onEditorStateChange,
|
||||||
processAttachments,
|
processAttachments,
|
||||||
|
reactToMessage,
|
||||||
removeAttachment,
|
removeAttachment,
|
||||||
replaceAttachments,
|
replaceAttachments,
|
||||||
resetComposer,
|
resetComposer,
|
||||||
|
@ -810,6 +812,44 @@ function replaceAttachments(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reactToMessage(
|
||||||
|
messageId: string,
|
||||||
|
reaction: { emoji: string; remove: boolean }
|
||||||
|
): ThunkAction<
|
||||||
|
void,
|
||||||
|
RootStateType,
|
||||||
|
unknown,
|
||||||
|
NoopActionType | ShowToastActionType
|
||||||
|
> {
|
||||||
|
return async dispatch => {
|
||||||
|
const { emoji, remove } = reaction;
|
||||||
|
try {
|
||||||
|
await enqueueReactionForSend({
|
||||||
|
messageId,
|
||||||
|
emoji,
|
||||||
|
remove,
|
||||||
|
});
|
||||||
|
dispatch({
|
||||||
|
type: 'NOOP',
|
||||||
|
payload: null,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
log.error(
|
||||||
|
'reactToMessage: Error sending reaction',
|
||||||
|
error,
|
||||||
|
messageId,
|
||||||
|
reaction
|
||||||
|
);
|
||||||
|
dispatch({
|
||||||
|
type: SHOW_TOAST,
|
||||||
|
payload: {
|
||||||
|
toastType: ToastType.ReactionFailed,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function resetComposer(): ResetComposerActionType {
|
function resetComposer(): ResetComposerActionType {
|
||||||
return {
|
return {
|
||||||
type: RESET_COMPOSER,
|
type: RESET_COMPOSER,
|
||||||
|
|
|
@ -90,7 +90,10 @@ import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
|
||||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||||
|
|
||||||
import type { NoopActionType } from './noop';
|
import type { NoopActionType } from './noop';
|
||||||
import { conversationJobQueue } from '../../jobs/conversationJobQueue';
|
import {
|
||||||
|
conversationJobQueue,
|
||||||
|
conversationQueueJobEnum,
|
||||||
|
} from '../../jobs/conversationJobQueue';
|
||||||
import type { TimelineMessageLoadingState } from '../../util/timelineUtil';
|
import type { TimelineMessageLoadingState } from '../../util/timelineUtil';
|
||||||
import {
|
import {
|
||||||
isDirectConversation,
|
isDirectConversation,
|
||||||
|
@ -121,6 +124,9 @@ import {
|
||||||
} from '../../groups';
|
} from '../../groups';
|
||||||
import { getMessageById } from '../../messages/getMessageById';
|
import { getMessageById } from '../../messages/getMessageById';
|
||||||
import type { PanelRenderType } from '../../types/Panels';
|
import type { PanelRenderType } from '../../types/Panels';
|
||||||
|
import type { ConversationQueueJobData } from '../../jobs/conversationJobQueue';
|
||||||
|
import { isOlderThan } from '../../util/timestamp';
|
||||||
|
import { DAY } from '../../util/durations';
|
||||||
import { isNotNil } from '../../util/isNotNil';
|
import { isNotNil } from '../../util/isNotNil';
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
@ -893,14 +899,17 @@ export const actions = {
|
||||||
generateNewGroupLink,
|
generateNewGroupLink,
|
||||||
getProfilesForConversation,
|
getProfilesForConversation,
|
||||||
initiateMigrationToGroupV2,
|
initiateMigrationToGroupV2,
|
||||||
|
kickOffAttachmentDownload,
|
||||||
leaveGroup,
|
leaveGroup,
|
||||||
loadRecentMediaItems,
|
loadRecentMediaItems,
|
||||||
|
markAttachmentAsCorrupted,
|
||||||
messageChanged,
|
messageChanged,
|
||||||
messageDeleted,
|
messageDeleted,
|
||||||
messageExpanded,
|
messageExpanded,
|
||||||
messagesAdded,
|
messagesAdded,
|
||||||
messagesReset,
|
messagesReset,
|
||||||
myProfileChanged,
|
myProfileChanged,
|
||||||
|
openGiftBadge,
|
||||||
popPanelForConversation,
|
popPanelForConversation,
|
||||||
pushPanelForConversation,
|
pushPanelForConversation,
|
||||||
removeAllConversations,
|
removeAllConversations,
|
||||||
|
@ -910,6 +919,8 @@ export const actions = {
|
||||||
repairOldestMessage,
|
repairOldestMessage,
|
||||||
replaceAvatar,
|
replaceAvatar,
|
||||||
resetAllChatColors,
|
resetAllChatColors,
|
||||||
|
retryDeleteForEveryone,
|
||||||
|
retryMessageSend,
|
||||||
reviewGroupMemberNameCollision,
|
reviewGroupMemberNameCollision,
|
||||||
reviewMessageRequestNameCollision,
|
reviewMessageRequestNameCollision,
|
||||||
revokePendingMembershipsFromGroupV2,
|
revokePendingMembershipsFromGroupV2,
|
||||||
|
@ -938,6 +949,8 @@ export const actions = {
|
||||||
showArchivedConversations,
|
showArchivedConversations,
|
||||||
showChooseGroupMembers,
|
showChooseGroupMembers,
|
||||||
showConversation,
|
showConversation,
|
||||||
|
showExpiredIncomingTapToViewToast,
|
||||||
|
showExpiredOutgoingTapToViewToast,
|
||||||
showInbox,
|
showInbox,
|
||||||
startComposing,
|
startComposing,
|
||||||
startSettingGroupMetadata,
|
startSettingGroupMetadata,
|
||||||
|
@ -1561,6 +1574,136 @@ function resetAllChatColors(): ThunkAction<
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function kickOffAttachmentDownload(
|
||||||
|
options: Readonly<{ messageId: string }>
|
||||||
|
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
|
||||||
|
return async dispatch => {
|
||||||
|
const message = await getMessageById(options.messageId);
|
||||||
|
if (!message) {
|
||||||
|
throw new Error(
|
||||||
|
`kickOffAttachmentDownload: Message ${options.messageId} missing!`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await message.queueAttachmentDownloads();
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: 'NOOP',
|
||||||
|
payload: null,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
type AttachmentOptions = {
|
||||||
|
messageId: string;
|
||||||
|
attachment: AttachmentType;
|
||||||
|
};
|
||||||
|
|
||||||
|
function markAttachmentAsCorrupted(
|
||||||
|
options: AttachmentOptions
|
||||||
|
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
|
||||||
|
return async dispatch => {
|
||||||
|
const message = await getMessageById(options.messageId);
|
||||||
|
if (!message) {
|
||||||
|
throw new Error(
|
||||||
|
`markAttachmentAsCorrupted: Message ${options.messageId} missing!`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
message.markAttachmentAsCorrupted(options.attachment);
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: 'NOOP',
|
||||||
|
payload: null,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function openGiftBadge(
|
||||||
|
messageId: string
|
||||||
|
): ThunkAction<void, RootStateType, unknown, ShowToastActionType> {
|
||||||
|
return async dispatch => {
|
||||||
|
const message = await getMessageById(messageId);
|
||||||
|
if (!message) {
|
||||||
|
throw new Error(`openGiftBadge: Message ${messageId} missing!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: SHOW_TOAST,
|
||||||
|
payload: {
|
||||||
|
toastType: isIncoming(message.attributes)
|
||||||
|
? ToastType.CannotOpenGiftBadgeIncoming
|
||||||
|
: ToastType.CannotOpenGiftBadgeOutgoing,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function retryMessageSend(
|
||||||
|
messageId: string
|
||||||
|
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
|
||||||
|
return async dispatch => {
|
||||||
|
const message = await getMessageById(messageId);
|
||||||
|
if (!message) {
|
||||||
|
throw new Error(`retryMessageSend: Message ${messageId} missing!`);
|
||||||
|
}
|
||||||
|
await message.retrySend();
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: 'NOOP',
|
||||||
|
payload: null,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function retryDeleteForEveryone(
|
||||||
|
messageId: string
|
||||||
|
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
|
||||||
|
return async dispatch => {
|
||||||
|
const message = await getMessageById(messageId);
|
||||||
|
if (!message) {
|
||||||
|
throw new Error(`retryDeleteForEveryone: Message ${messageId} missing!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isOlderThan(message.get('sent_at'), DAY)) {
|
||||||
|
throw new Error(
|
||||||
|
'retryDeleteForEveryone: Message too old to retry delete for everyone!'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const conversation = message.getConversation();
|
||||||
|
if (!conversation) {
|
||||||
|
throw new Error(
|
||||||
|
`retryDeleteForEveryone: Conversation for ${messageId} missing!`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const jobData: ConversationQueueJobData = {
|
||||||
|
type: conversationQueueJobEnum.enum.DeleteForEveryone,
|
||||||
|
conversationId: conversation.id,
|
||||||
|
messageId,
|
||||||
|
recipients: conversation.getRecipients(),
|
||||||
|
revision: conversation.get('revision'),
|
||||||
|
targetTimestamp: message.get('sent_at'),
|
||||||
|
};
|
||||||
|
|
||||||
|
log.info(
|
||||||
|
`retryDeleteForEveryone: Adding job for message ${message.idForLogging()}!`
|
||||||
|
);
|
||||||
|
await conversationJobQueue.add(jobData);
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: 'NOOP',
|
||||||
|
payload: null,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
log.error(
|
||||||
|
'retryDeleteForEveryone: Failed to queue delete for everyone',
|
||||||
|
Errors.toLogFormat(error)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// update the conversation voice note playback rate preference for the conversation
|
// update the conversation voice note playback rate preference for the conversation
|
||||||
export function setVoiceNotePlaybackRate({
|
export function setVoiceNotePlaybackRate({
|
||||||
conversationId,
|
conversationId,
|
||||||
|
@ -2990,6 +3133,27 @@ function updateConversationModelSharedGroups(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showExpiredIncomingTapToViewToast(): ShowToastActionType {
|
||||||
|
log.info(
|
||||||
|
'showExpiredIncomingTapToViewToastShowing expired tap-to-view toast for an incoming message'
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
type: SHOW_TOAST,
|
||||||
|
payload: {
|
||||||
|
toastType: ToastType.TapToViewExpiredIncoming,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function showExpiredOutgoingTapToViewToast(): ShowToastActionType {
|
||||||
|
log.info('Showing expired tap-to-view toast for an outgoing message');
|
||||||
|
return {
|
||||||
|
type: SHOW_TOAST,
|
||||||
|
payload: {
|
||||||
|
toastType: ToastType.TapToViewExpiredOutgoing,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function showInbox(): ShowInboxActionType {
|
function showInbox(): ShowInboxActionType {
|
||||||
return {
|
return {
|
||||||
type: 'SHOW_INBOX',
|
type: 'SHOW_INBOX',
|
||||||
|
|
|
@ -24,7 +24,6 @@ import dataInterface from '../../sql/Client';
|
||||||
import { ReadStatus } from '../../messages/MessageReadStatus';
|
import { ReadStatus } from '../../messages/MessageReadStatus';
|
||||||
import { SafetyNumberChangeSource } from '../../components/SafetyNumberChangeDialog';
|
import { SafetyNumberChangeSource } from '../../components/SafetyNumberChangeDialog';
|
||||||
import { StoryViewDirectionType, StoryViewModeType } from '../../types/Stories';
|
import { StoryViewDirectionType, StoryViewModeType } from '../../types/Stories';
|
||||||
import { ToastReactionFailed } from '../../components/ToastReactionFailed';
|
|
||||||
import { assertDev } from '../../util/assert';
|
import { assertDev } from '../../util/assert';
|
||||||
import { blockSendUntilConversationsAreVerified } from '../../util/blockSendUntilConversationsAreVerified';
|
import { blockSendUntilConversationsAreVerified } from '../../util/blockSendUntilConversationsAreVerified';
|
||||||
import { deleteStoryForEveryone as doDeleteStoryForEveryone } from '../../util/deleteStoryForEveryone';
|
import { deleteStoryForEveryone as doDeleteStoryForEveryone } from '../../util/deleteStoryForEveryone';
|
||||||
|
@ -35,7 +34,6 @@ import { markOnboardingStoryAsRead } from '../../util/markOnboardingStoryAsRead'
|
||||||
import { markViewed } from '../../services/MessageUpdater';
|
import { markViewed } from '../../services/MessageUpdater';
|
||||||
import { queueAttachmentDownloads } from '../../util/queueAttachmentDownloads';
|
import { queueAttachmentDownloads } from '../../util/queueAttachmentDownloads';
|
||||||
import { replaceIndex } from '../../util/replaceIndex';
|
import { replaceIndex } from '../../util/replaceIndex';
|
||||||
import { showToast } from '../../util/showToast';
|
|
||||||
import type { DurationInSeconds } from '../../util/durations';
|
import type { DurationInSeconds } from '../../util/durations';
|
||||||
import { hasFailed, isDownloaded, isDownloading } from '../../types/Attachment';
|
import { hasFailed, isDownloaded, isDownloading } from '../../types/Attachment';
|
||||||
import {
|
import {
|
||||||
|
@ -57,6 +55,9 @@ import { verifyStoryListMembers as doVerifyStoryListMembers } from '../../util/v
|
||||||
import { viewSyncJobQueue } from '../../jobs/viewSyncJobQueue';
|
import { viewSyncJobQueue } from '../../jobs/viewSyncJobQueue';
|
||||||
import { viewedReceiptsJobQueue } from '../../jobs/viewedReceiptsJobQueue';
|
import { viewedReceiptsJobQueue } from '../../jobs/viewedReceiptsJobQueue';
|
||||||
import { getOwn } from '../../util/getOwn';
|
import { getOwn } from '../../util/getOwn';
|
||||||
|
import { SHOW_TOAST } from './toast';
|
||||||
|
import { ToastType } from '../../types/Toast';
|
||||||
|
import type { ShowToastActionType } from './toast';
|
||||||
|
|
||||||
export type StoryDataType = {
|
export type StoryDataType = {
|
||||||
attachment?: AttachmentType;
|
attachment?: AttachmentType;
|
||||||
|
@ -492,7 +493,12 @@ function queueStoryDownload(
|
||||||
function reactToStory(
|
function reactToStory(
|
||||||
nextReaction: string,
|
nextReaction: string,
|
||||||
messageId: string
|
messageId: string
|
||||||
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
|
): ThunkAction<
|
||||||
|
void,
|
||||||
|
RootStateType,
|
||||||
|
unknown,
|
||||||
|
ShowToastActionType | NoopActionType
|
||||||
|
> {
|
||||||
return async dispatch => {
|
return async dispatch => {
|
||||||
try {
|
try {
|
||||||
await enqueueReactionForSend({
|
await enqueueReactionForSend({
|
||||||
|
@ -500,15 +506,19 @@ function reactToStory(
|
||||||
emoji: nextReaction,
|
emoji: nextReaction,
|
||||||
remove: false,
|
remove: false,
|
||||||
});
|
});
|
||||||
|
dispatch({
|
||||||
|
type: 'NOOP',
|
||||||
|
payload: null,
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error('Error enqueuing reaction', error, messageId, nextReaction);
|
log.error('Error enqueuing reaction', error, messageId, nextReaction);
|
||||||
showToast(ToastReactionFailed);
|
dispatch({
|
||||||
|
type: SHOW_TOAST,
|
||||||
|
payload: {
|
||||||
|
toastType: ToastType.ReactionFailed,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: 'NOOP',
|
|
||||||
payload: null,
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import type { NoopActionType } from './noop';
|
||||||
import type { ReplacementValuesType } from '../../types/Util';
|
import type { ReplacementValuesType } from '../../types/Util';
|
||||||
import { useBoundActions } from '../../hooks/useBoundActions';
|
import { useBoundActions } from '../../hooks/useBoundActions';
|
||||||
import type { ToastType } from '../../types/Toast';
|
import type { ToastType } from '../../types/Toast';
|
||||||
|
|
||||||
// State
|
// State
|
||||||
|
|
||||||
export type ToastStateType = {
|
export type ToastStateType = {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { SmartMessageDetail } from '../smart/MessageDetail';
|
||||||
|
|
||||||
export const createMessageDetail = (
|
export const createMessageDetail = (
|
||||||
store: Store,
|
store: Store,
|
||||||
props: Omit<OwnProps, 'markViewed'>
|
props: OwnProps
|
||||||
): ReactElement => (
|
): ReactElement => (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<SmartMessageDetail {...props} />
|
<SmartMessageDetail {...props} />
|
||||||
|
|
|
@ -12,7 +12,6 @@ import { getPreferredBadgeSelector } from '../selectors/badges';
|
||||||
import { getIntl, getInteractionMode, getTheme } from '../selectors/user';
|
import { getIntl, getInteractionMode, getTheme } from '../selectors/user';
|
||||||
import { renderAudioAttachment } from './renderAudioAttachment';
|
import { renderAudioAttachment } from './renderAudioAttachment';
|
||||||
import { getContactNameColorSelector } from '../selectors/conversations';
|
import { getContactNameColorSelector } from '../selectors/conversations';
|
||||||
import { markViewed } from '../ducks/conversations';
|
|
||||||
|
|
||||||
export { Contact } from '../../components/conversation/MessageDetail';
|
export { Contact } from '../../components/conversation/MessageDetail';
|
||||||
export type OwnProps = Omit<
|
export type OwnProps = Omit<
|
||||||
|
@ -26,7 +25,6 @@ export type OwnProps = Omit<
|
||||||
| 'theme'
|
| 'theme'
|
||||||
| 'showContactModal'
|
| 'showContactModal'
|
||||||
| 'showConversation'
|
| 'showConversation'
|
||||||
| 'markViewed'
|
|
||||||
>;
|
>;
|
||||||
|
|
||||||
const mapStateToProps = (
|
const mapStateToProps = (
|
||||||
|
@ -40,12 +38,6 @@ const mapStateToProps = (
|
||||||
receivedAt,
|
receivedAt,
|
||||||
sentAt,
|
sentAt,
|
||||||
|
|
||||||
kickOffAttachmentDownload,
|
|
||||||
markAttachmentAsCorrupted,
|
|
||||||
openGiftBadge,
|
|
||||||
openLink,
|
|
||||||
showExpiredIncomingTapToViewToast,
|
|
||||||
showExpiredOutgoingTapToViewToast,
|
|
||||||
startConversation,
|
startConversation,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
@ -72,14 +64,7 @@ const mapStateToProps = (
|
||||||
interactionMode: getInteractionMode(state),
|
interactionMode: getInteractionMode(state),
|
||||||
theme: getTheme(state),
|
theme: getTheme(state),
|
||||||
|
|
||||||
kickOffAttachmentDownload,
|
|
||||||
markAttachmentAsCorrupted,
|
|
||||||
markViewed,
|
|
||||||
openGiftBadge,
|
|
||||||
openLink,
|
|
||||||
renderAudioAttachment,
|
renderAudioAttachment,
|
||||||
showExpiredIncomingTapToViewToast,
|
|
||||||
showExpiredOutgoingTapToViewToast,
|
|
||||||
startConversation,
|
startConversation,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,7 +21,6 @@ import {
|
||||||
getStories,
|
getStories,
|
||||||
shouldShowStoriesView,
|
shouldShowStoriesView,
|
||||||
} from '../selectors/stories';
|
} from '../selectors/stories';
|
||||||
import { retryMessageSend } from '../../util/retryMessageSend';
|
|
||||||
import { useConversationsActions } from '../ducks/conversations';
|
import { useConversationsActions } from '../ducks/conversations';
|
||||||
import { useGlobalModalActions } from '../ducks/globalModals';
|
import { useGlobalModalActions } from '../ducks/globalModals';
|
||||||
import { useStoriesActions } from '../ducks/stories';
|
import { useStoriesActions } from '../ducks/stories';
|
||||||
|
@ -33,8 +32,12 @@ function renderStoryCreator(): JSX.Element {
|
||||||
|
|
||||||
export function SmartStories(): JSX.Element | null {
|
export function SmartStories(): JSX.Element | null {
|
||||||
const storiesActions = useStoriesActions();
|
const storiesActions = useStoriesActions();
|
||||||
const { saveAttachment, showConversation, toggleHideStories } =
|
const {
|
||||||
useConversationsActions();
|
retryMessageSend,
|
||||||
|
saveAttachment,
|
||||||
|
showConversation,
|
||||||
|
toggleHideStories,
|
||||||
|
} = useConversationsActions();
|
||||||
const { showStoriesSettings, toggleForwardMessageModal } =
|
const { showStoriesSettings, toggleForwardMessageModal } =
|
||||||
useGlobalModalActions();
|
useGlobalModalActions();
|
||||||
const { showToast } = useToastActions();
|
const { showToast } = useToastActions();
|
||||||
|
@ -83,7 +86,7 @@ export function SmartStories(): JSX.Element | null {
|
||||||
}}
|
}}
|
||||||
preferredWidthFromStorage={preferredWidthFromStorage}
|
preferredWidthFromStorage={preferredWidthFromStorage}
|
||||||
renderStoryCreator={renderStoryCreator}
|
renderStoryCreator={renderStoryCreator}
|
||||||
retrySend={retryMessageSend}
|
retryMessageSend={retryMessageSend}
|
||||||
showConversation={showConversation}
|
showConversation={showConversation}
|
||||||
showStoriesSettings={showStoriesSettings}
|
showStoriesSettings={showStoriesSettings}
|
||||||
showToast={showToast}
|
showToast={showToast}
|
||||||
|
|
|
@ -29,7 +29,6 @@ import {
|
||||||
import { isInFullScreenCall } from '../selectors/calling';
|
import { isInFullScreenCall } from '../selectors/calling';
|
||||||
import { isSignalConversation } from '../../util/isSignalConversation';
|
import { isSignalConversation } from '../../util/isSignalConversation';
|
||||||
import { renderEmojiPicker } from './renderEmojiPicker';
|
import { renderEmojiPicker } from './renderEmojiPicker';
|
||||||
import { retryMessageSend } from '../../util/retryMessageSend';
|
|
||||||
import { strictAssert } from '../../util/assert';
|
import { strictAssert } from '../../util/assert';
|
||||||
import { asyncShouldNeverBeCalled } from '../../util/shouldNeverBeCalled';
|
import { asyncShouldNeverBeCalled } from '../../util/shouldNeverBeCalled';
|
||||||
import { useActions as useEmojisActions } from '../ducks/emojis';
|
import { useActions as useEmojisActions } from '../ducks/emojis';
|
||||||
|
@ -42,8 +41,12 @@ import { useIsWindowActive } from '../../hooks/useIsWindowActive';
|
||||||
export function SmartStoryViewer(): JSX.Element | null {
|
export function SmartStoryViewer(): JSX.Element | null {
|
||||||
const storiesActions = useStoriesActions();
|
const storiesActions = useStoriesActions();
|
||||||
const { onUseEmoji } = useEmojisActions();
|
const { onUseEmoji } = useEmojisActions();
|
||||||
const { saveAttachment, showConversation, toggleHideStories } =
|
const {
|
||||||
useConversationsActions();
|
retryMessageSend,
|
||||||
|
saveAttachment,
|
||||||
|
showConversation,
|
||||||
|
toggleHideStories,
|
||||||
|
} = useConversationsActions();
|
||||||
const { onSetSkinTone } = useItemsActions();
|
const { onSetSkinTone } = useItemsActions();
|
||||||
const { showToast } = useToastActions();
|
const { showToast } = useToastActions();
|
||||||
|
|
||||||
|
@ -135,7 +138,7 @@ export function SmartStoryViewer(): JSX.Element | null {
|
||||||
recentEmojis={recentEmojis}
|
recentEmojis={recentEmojis}
|
||||||
renderEmojiPicker={renderEmojiPicker}
|
renderEmojiPicker={renderEmojiPicker}
|
||||||
replyState={replyState}
|
replyState={replyState}
|
||||||
retrySend={retryMessageSend}
|
retryMessageSend={retryMessageSend}
|
||||||
showToast={showToast}
|
showToast={showToast}
|
||||||
skinTone={skinTone}
|
skinTone={skinTone}
|
||||||
story={storyView}
|
story={storyView}
|
||||||
|
|
|
@ -8,10 +8,10 @@ import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { mapDispatchToProps } from '../actions';
|
import { mapDispatchToProps } from '../actions';
|
||||||
import type {
|
import type {
|
||||||
PropsActionsType as TimelineActionsType,
|
|
||||||
ContactSpoofingReviewPropType,
|
ContactSpoofingReviewPropType,
|
||||||
WarningType as TimelineWarningType,
|
WarningType as TimelineWarningType,
|
||||||
PropsType as ComponentPropsType,
|
PropsType as ComponentPropsType,
|
||||||
|
PropsActionsFromBackboneForChildrenType,
|
||||||
} from '../../components/conversation/Timeline';
|
} from '../../components/conversation/Timeline';
|
||||||
import { Timeline } from '../../components/conversation/Timeline';
|
import { Timeline } from '../../components/conversation/Timeline';
|
||||||
import type { StateType } from '../reducer';
|
import type { StateType } from '../reducer';
|
||||||
|
@ -62,30 +62,31 @@ type ExternalProps = {
|
||||||
export type TimelinePropsType = ExternalProps &
|
export type TimelinePropsType = ExternalProps &
|
||||||
Pick<
|
Pick<
|
||||||
ComponentPropsType,
|
ComponentPropsType,
|
||||||
|
// All of these are the ones we need from backbone
|
||||||
|
|
||||||
|
// Used by Timeline itself
|
||||||
| 'acknowledgeGroupMemberNameCollisions'
|
| 'acknowledgeGroupMemberNameCollisions'
|
||||||
| 'contactSupport'
|
| 'loadOlderMessages'
|
||||||
| 'blockGroupLinkRequests'
|
|
||||||
| 'downloadNewVersion'
|
|
||||||
| 'kickOffAttachmentDownload'
|
|
||||||
| 'learnMoreAboutDeliveryIssue'
|
|
||||||
| 'loadNewerMessages'
|
| 'loadNewerMessages'
|
||||||
| 'loadNewestMessages'
|
| 'loadNewestMessages'
|
||||||
| 'loadOlderMessages'
|
|
||||||
| 'markAttachmentAsCorrupted'
|
|
||||||
| 'markMessageRead'
|
| 'markMessageRead'
|
||||||
| 'openGiftBadge'
|
|
||||||
| 'openLink'
|
|
||||||
| 'reactToMessage'
|
|
||||||
| 'removeMember'
|
| 'removeMember'
|
||||||
| 'retryDeleteForEveryone'
|
|
||||||
| 'retrySend'
|
|
||||||
| 'scrollToQuotedMessage'
|
|
||||||
| 'showExpiredIncomingTapToViewToast'
|
|
||||||
| 'showExpiredOutgoingTapToViewToast'
|
|
||||||
| 'showMessageDetail'
|
|
||||||
| 'startConversation'
|
|
||||||
| 'unblurAvatar'
|
| 'unblurAvatar'
|
||||||
| 'updateSharedGroups'
|
| 'updateSharedGroups'
|
||||||
|
|
||||||
|
// MessageActionsType
|
||||||
|
| 'scrollToQuotedMessage'
|
||||||
|
| 'showMessageDetail'
|
||||||
|
| 'startConversation'
|
||||||
|
|
||||||
|
// ChatSessionRefreshedNotificationActionsType
|
||||||
|
| 'contactSupport'
|
||||||
|
|
||||||
|
// DeliveryIssueNotificationActionsType
|
||||||
|
| 'learnMoreAboutDeliveryIssue'
|
||||||
|
|
||||||
|
// GroupV2ChangeActionsType
|
||||||
|
| 'blockGroupLinkRequests'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
function renderItem({
|
function renderItem({
|
||||||
|
@ -99,7 +100,7 @@ function renderItem({
|
||||||
previousMessageId,
|
previousMessageId,
|
||||||
unreadIndicatorPlacement,
|
unreadIndicatorPlacement,
|
||||||
}: {
|
}: {
|
||||||
actionProps: TimelineActionsType;
|
actionProps: PropsActionsFromBackboneForChildrenType;
|
||||||
containerElementRef: RefObject<HTMLElement>;
|
containerElementRef: RefObject<HTMLElement>;
|
||||||
containerWidthBreakpoint: WidthBreakpoint;
|
containerWidthBreakpoint: WidthBreakpoint;
|
||||||
conversationId: string;
|
conversationId: string;
|
||||||
|
@ -269,7 +270,7 @@ const getContactSpoofingReview = (
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const mapStateToProps = (state: StateType, props: ExternalProps) => {
|
const mapStateToProps = (state: StateType, props: TimelinePropsType) => {
|
||||||
const { id, ...actions } = props;
|
const { id, ...actions } = props;
|
||||||
|
|
||||||
const conversation = getConversationSelector(state)(id);
|
const conversation = getConversationSelector(state)(id);
|
||||||
|
|
|
@ -6,6 +6,8 @@ export enum ToastType {
|
||||||
Blocked = 'Blocked',
|
Blocked = 'Blocked',
|
||||||
BlockedGroup = 'BlockedGroup',
|
BlockedGroup = 'BlockedGroup',
|
||||||
CannotMixMultiAndNonMultiAttachments = 'CannotMixMultiAndNonMultiAttachments',
|
CannotMixMultiAndNonMultiAttachments = 'CannotMixMultiAndNonMultiAttachments',
|
||||||
|
CannotOpenGiftBadgeIncoming = 'CannotOpenGiftBadgeIncoming',
|
||||||
|
CannotOpenGiftBadgeOutgoing = 'CannotOpenGiftBadgeOutgoing',
|
||||||
CannotStartGroupCall = 'CannotStartGroupCall',
|
CannotStartGroupCall = 'CannotStartGroupCall',
|
||||||
CopiedUsername = 'CopiedUsername',
|
CopiedUsername = 'CopiedUsername',
|
||||||
CopiedUsernameLink = 'CopiedUsernameLink',
|
CopiedUsernameLink = 'CopiedUsernameLink',
|
||||||
|
@ -21,6 +23,7 @@ export enum ToastType {
|
||||||
MaxAttachments = 'MaxAttachments',
|
MaxAttachments = 'MaxAttachments',
|
||||||
MessageBodyTooLong = 'MessageBodyTooLong',
|
MessageBodyTooLong = 'MessageBodyTooLong',
|
||||||
PinnedConversationsFull = 'PinnedConversationsFull',
|
PinnedConversationsFull = 'PinnedConversationsFull',
|
||||||
|
ReactionFailed = 'ReactionFailed',
|
||||||
ReportedSpamAndBlocked = 'ReportedSpamAndBlocked',
|
ReportedSpamAndBlocked = 'ReportedSpamAndBlocked',
|
||||||
StoryMuted = 'StoryMuted',
|
StoryMuted = 'StoryMuted',
|
||||||
StoryReact = 'StoryReact',
|
StoryReact = 'StoryReact',
|
||||||
|
@ -28,6 +31,8 @@ export enum ToastType {
|
||||||
StoryVideoError = 'StoryVideoError',
|
StoryVideoError = 'StoryVideoError',
|
||||||
StoryVideoTooLong = 'StoryVideoTooLong',
|
StoryVideoTooLong = 'StoryVideoTooLong',
|
||||||
StoryVideoUnsupported = 'StoryVideoUnsupported',
|
StoryVideoUnsupported = 'StoryVideoUnsupported',
|
||||||
|
TapToViewExpiredIncoming = 'TapToViewExpiredIncoming',
|
||||||
|
TapToViewExpiredOutgoing = 'TapToViewExpiredOutgoing',
|
||||||
UnableToLoadAttachment = 'UnableToLoadAttachment',
|
UnableToLoadAttachment = 'UnableToLoadAttachment',
|
||||||
UnsupportedMultiAttachment = 'UnsupportedMultiAttachment',
|
UnsupportedMultiAttachment = 'UnsupportedMultiAttachment',
|
||||||
UserAddedToGroup = 'UserAddedToGroup',
|
UserAddedToGroup = 'UserAddedToGroup',
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
// Copyright 2022 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import * as log from '../logging/log';
|
|
||||||
import * as Errors from '../types/errors';
|
|
||||||
|
|
||||||
import type { ConversationQueueJobData } from '../jobs/conversationJobQueue';
|
|
||||||
import {
|
|
||||||
conversationJobQueue,
|
|
||||||
conversationQueueJobEnum,
|
|
||||||
} from '../jobs/conversationJobQueue';
|
|
||||||
import { isOlderThan } from './timestamp';
|
|
||||||
import { DAY } from './durations';
|
|
||||||
|
|
||||||
export async function retryDeleteForEveryone(messageId: string): Promise<void> {
|
|
||||||
const message = window.MessageController.getById(messageId);
|
|
||||||
if (!message) {
|
|
||||||
throw new Error(`retryDeleteForEveryone: Message ${messageId} missing!`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isOlderThan(message.get('sent_at'), DAY)) {
|
|
||||||
throw new Error(
|
|
||||||
'retryDeleteForEveryone: Message too old to retry delete for everyone!'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const conversation = message.getConversation();
|
|
||||||
if (!conversation) {
|
|
||||||
throw new Error(
|
|
||||||
`retryDeleteForEveryone: Conversation for ${messageId} missing!`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const jobData: ConversationQueueJobData = {
|
|
||||||
type: conversationQueueJobEnum.enum.DeleteForEveryone,
|
|
||||||
conversationId: conversation.id,
|
|
||||||
messageId,
|
|
||||||
recipients: conversation.getRecipients(),
|
|
||||||
revision: conversation.get('revision'),
|
|
||||||
targetTimestamp: message.get('sent_at'),
|
|
||||||
};
|
|
||||||
|
|
||||||
log.info(
|
|
||||||
`retryDeleteForEveryone: Adding job for message ${message.idForLogging()}!`
|
|
||||||
);
|
|
||||||
await conversationJobQueue.add(jobData);
|
|
||||||
} catch (error) {
|
|
||||||
log.error(
|
|
||||||
'retryDeleteForEveryone: Failed to queue delete for everyone',
|
|
||||||
Errors.toLogFormat(error)
|
|
||||||
);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +0,0 @@
|
||||||
// Copyright 2021-2022 Signal Messenger, LLC
|
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
|
||||||
|
|
||||||
import { getMessageById } from '../messages/getMessageById';
|
|
||||||
|
|
||||||
export async function retryMessageSend(messageId: string): Promise<void> {
|
|
||||||
const message = await getMessageById(messageId);
|
|
||||||
if (!message) {
|
|
||||||
throw new Error(`retryMessageSend: Message ${messageId} missing!`);
|
|
||||||
}
|
|
||||||
await message.retrySend();
|
|
||||||
}
|
|
|
@ -6,10 +6,6 @@ import { render, unmountComponentAtNode } from 'react-dom';
|
||||||
|
|
||||||
import type { ToastAlreadyGroupMember } from '../components/ToastAlreadyGroupMember';
|
import type { ToastAlreadyGroupMember } from '../components/ToastAlreadyGroupMember';
|
||||||
import type { ToastAlreadyRequestedToJoin } from '../components/ToastAlreadyRequestedToJoin';
|
import type { ToastAlreadyRequestedToJoin } from '../components/ToastAlreadyRequestedToJoin';
|
||||||
import type {
|
|
||||||
ToastCannotOpenGiftBadge,
|
|
||||||
ToastPropsType as ToastCannotOpenGiftBadgePropsType,
|
|
||||||
} from '../components/ToastCannotOpenGiftBadge';
|
|
||||||
import type { ToastCaptchaFailed } from '../components/ToastCaptchaFailed';
|
import type { ToastCaptchaFailed } from '../components/ToastCaptchaFailed';
|
||||||
import type { ToastCaptchaSolved } from '../components/ToastCaptchaSolved';
|
import type { ToastCaptchaSolved } from '../components/ToastCaptchaSolved';
|
||||||
import type {
|
import type {
|
||||||
|
@ -32,19 +28,12 @@ import type { ToastLoadingFullLogs } from '../components/ToastLoadingFullLogs';
|
||||||
import type { ToastMessageBodyTooLong } from '../components/ToastMessageBodyTooLong';
|
import type { ToastMessageBodyTooLong } from '../components/ToastMessageBodyTooLong';
|
||||||
|
|
||||||
import type { ToastOriginalMessageNotFound } from '../components/ToastOriginalMessageNotFound';
|
import type { ToastOriginalMessageNotFound } from '../components/ToastOriginalMessageNotFound';
|
||||||
import type { ToastReactionFailed } from '../components/ToastReactionFailed';
|
|
||||||
import type { ToastStickerPackInstallFailed } from '../components/ToastStickerPackInstallFailed';
|
import type { ToastStickerPackInstallFailed } from '../components/ToastStickerPackInstallFailed';
|
||||||
import type { ToastTapToViewExpiredIncoming } from '../components/ToastTapToViewExpiredIncoming';
|
|
||||||
import type { ToastTapToViewExpiredOutgoing } from '../components/ToastTapToViewExpiredOutgoing';
|
|
||||||
import type { ToastVoiceNoteLimit } from '../components/ToastVoiceNoteLimit';
|
import type { ToastVoiceNoteLimit } from '../components/ToastVoiceNoteLimit';
|
||||||
import type { ToastVoiceNoteMustBeOnlyAttachment } from '../components/ToastVoiceNoteMustBeOnlyAttachment';
|
import type { ToastVoiceNoteMustBeOnlyAttachment } from '../components/ToastVoiceNoteMustBeOnlyAttachment';
|
||||||
|
|
||||||
export function showToast(Toast: typeof ToastAlreadyGroupMember): void;
|
export function showToast(Toast: typeof ToastAlreadyGroupMember): void;
|
||||||
export function showToast(Toast: typeof ToastAlreadyRequestedToJoin): void;
|
export function showToast(Toast: typeof ToastAlreadyRequestedToJoin): void;
|
||||||
export function showToast(
|
|
||||||
Toast: typeof ToastCannotOpenGiftBadge,
|
|
||||||
props: Omit<ToastCannotOpenGiftBadgePropsType, 'i18n' | 'onClose'>
|
|
||||||
): void;
|
|
||||||
export function showToast(Toast: typeof ToastCaptchaFailed): void;
|
export function showToast(Toast: typeof ToastCaptchaFailed): void;
|
||||||
export function showToast(Toast: typeof ToastCaptchaSolved): void;
|
export function showToast(Toast: typeof ToastCaptchaSolved): void;
|
||||||
export function showToast(
|
export function showToast(
|
||||||
|
@ -66,10 +55,7 @@ export function showToast(Toast: typeof ToastLinkCopied): void;
|
||||||
export function showToast(Toast: typeof ToastLoadingFullLogs): void;
|
export function showToast(Toast: typeof ToastLoadingFullLogs): void;
|
||||||
export function showToast(Toast: typeof ToastMessageBodyTooLong): void;
|
export function showToast(Toast: typeof ToastMessageBodyTooLong): void;
|
||||||
export function showToast(Toast: typeof ToastOriginalMessageNotFound): void;
|
export function showToast(Toast: typeof ToastOriginalMessageNotFound): void;
|
||||||
export function showToast(Toast: typeof ToastReactionFailed): void;
|
|
||||||
export function showToast(Toast: typeof ToastStickerPackInstallFailed): void;
|
export function showToast(Toast: typeof ToastStickerPackInstallFailed): void;
|
||||||
export function showToast(Toast: typeof ToastTapToViewExpiredIncoming): void;
|
|
||||||
export function showToast(Toast: typeof ToastTapToViewExpiredOutgoing): void;
|
|
||||||
export function showToast(Toast: typeof ToastVoiceNoteLimit): void;
|
export function showToast(Toast: typeof ToastVoiceNoteLimit): void;
|
||||||
export function showToast(
|
export function showToast(
|
||||||
Toast: typeof ToastVoiceNoteMustBeOnlyAttachment
|
Toast: typeof ToastVoiceNoteMustBeOnlyAttachment
|
||||||
|
|
|
@ -16,10 +16,8 @@ import type { MediaItemType } from '../types/MediaItem';
|
||||||
import { getMessageById } from '../messages/getMessageById';
|
import { getMessageById } from '../messages/getMessageById';
|
||||||
import { getContactId } from '../messages/helpers';
|
import { getContactId } from '../messages/helpers';
|
||||||
import { strictAssert } from '../util/assert';
|
import { strictAssert } from '../util/assert';
|
||||||
import { enqueueReactionForSend } from '../reactions/enqueueReactionForSend';
|
|
||||||
import type { GroupNameCollisionsWithIdsByTitle } from '../util/groupMemberNameCollisions';
|
import type { GroupNameCollisionsWithIdsByTitle } from '../util/groupMemberNameCollisions';
|
||||||
import { isGroup } from '../util/whatTypeOfConversation';
|
import { isGroup } from '../util/whatTypeOfConversation';
|
||||||
import { isIncoming } from '../state/selectors/message';
|
|
||||||
import { getActiveCallState } from '../state/selectors/calling';
|
import { getActiveCallState } from '../state/selectors/calling';
|
||||||
import { ReactWrapperView } from './ReactWrapperView';
|
import { ReactWrapperView } from './ReactWrapperView';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
|
@ -29,17 +27,11 @@ import { ToastConversationMarkedUnread } from '../components/ToastConversationMa
|
||||||
import { ToastConversationUnarchived } from '../components/ToastConversationUnarchived';
|
import { ToastConversationUnarchived } from '../components/ToastConversationUnarchived';
|
||||||
import { ToastMessageBodyTooLong } from '../components/ToastMessageBodyTooLong';
|
import { ToastMessageBodyTooLong } from '../components/ToastMessageBodyTooLong';
|
||||||
import { ToastOriginalMessageNotFound } from '../components/ToastOriginalMessageNotFound';
|
import { ToastOriginalMessageNotFound } from '../components/ToastOriginalMessageNotFound';
|
||||||
import { ToastReactionFailed } from '../components/ToastReactionFailed';
|
|
||||||
import { ToastTapToViewExpiredIncoming } from '../components/ToastTapToViewExpiredIncoming';
|
|
||||||
import { ToastTapToViewExpiredOutgoing } from '../components/ToastTapToViewExpiredOutgoing';
|
|
||||||
import { ToastCannotOpenGiftBadge } from '../components/ToastCannotOpenGiftBadge';
|
|
||||||
import { retryMessageSend } from '../util/retryMessageSend';
|
|
||||||
import { isNotNil } from '../util/isNotNil';
|
import { isNotNil } from '../util/isNotNil';
|
||||||
import { openLinkInWebBrowser } from '../util/openLinkInWebBrowser';
|
import { openLinkInWebBrowser } from '../util/openLinkInWebBrowser';
|
||||||
import { showToast } from '../util/showToast';
|
import { showToast } from '../util/showToast';
|
||||||
import { UUIDKind } from '../types/UUID';
|
import { UUIDKind } from '../types/UUID';
|
||||||
import type { UUIDStringType } from '../types/UUID';
|
import type { UUIDStringType } from '../types/UUID';
|
||||||
import { retryDeleteForEveryone } from '../util/retryDeleteForEveryone';
|
|
||||||
import { MediaGallery } from '../components/conversation/media-gallery/MediaGallery';
|
import { MediaGallery } from '../components/conversation/media-gallery/MediaGallery';
|
||||||
import type { ItemClickEvent } from '../components/conversation/media-gallery/types/ItemClickEvent';
|
import type { ItemClickEvent } from '../components/conversation/media-gallery/types/ItemClickEvent';
|
||||||
import {
|
import {
|
||||||
|
@ -53,11 +45,6 @@ import { clearConversationDraftAttachments } from '../util/clearConversationDraf
|
||||||
import type { BackbonePanelRenderType, PanelRenderType } from '../types/Panels';
|
import type { BackbonePanelRenderType, PanelRenderType } from '../types/Panels';
|
||||||
import { PanelType, isPanelHandledByReact } from '../types/Panels';
|
import { PanelType, isPanelHandledByReact } from '../types/Panels';
|
||||||
|
|
||||||
type AttachmentOptions = {
|
|
||||||
messageId: string;
|
|
||||||
attachment: AttachmentType;
|
|
||||||
};
|
|
||||||
|
|
||||||
const { Message } = window.Signal.Types;
|
const { Message } = window.Signal.Types;
|
||||||
|
|
||||||
type BackbonePanelType = { panelType: PanelType; view: Backbone.View };
|
type BackbonePanelType = { panelType: PanelType; view: Backbone.View };
|
||||||
|
@ -68,21 +55,6 @@ const { getAbsoluteAttachmentPath, upgradeMessageSchema } =
|
||||||
const { getMessagesBySentAt } = window.Signal.Data;
|
const { getMessagesBySentAt } = window.Signal.Data;
|
||||||
|
|
||||||
type MessageActionsType = {
|
type MessageActionsType = {
|
||||||
downloadNewVersion: () => unknown;
|
|
||||||
kickOffAttachmentDownload: (
|
|
||||||
options: Readonly<{ messageId: string }>
|
|
||||||
) => unknown;
|
|
||||||
markAttachmentAsCorrupted: (options: AttachmentOptions) => unknown;
|
|
||||||
openGiftBadge: (messageId: string) => unknown;
|
|
||||||
openLink: (url: string) => unknown;
|
|
||||||
reactToMessage: (
|
|
||||||
messageId: string,
|
|
||||||
reaction: { emoji: string; remove: boolean }
|
|
||||||
) => unknown;
|
|
||||||
retrySend: (messageId: string) => unknown;
|
|
||||||
retryDeleteForEveryone: (messageId: string) => unknown;
|
|
||||||
showExpiredIncomingTapToViewToast: () => unknown;
|
|
||||||
showExpiredOutgoingTapToViewToast: () => unknown;
|
|
||||||
showMessageDetail: (messageId: string) => unknown;
|
showMessageDetail: (messageId: string) => unknown;
|
||||||
startConversation: (e164: string, uuid: UUIDStringType) => unknown;
|
startConversation: (e164: string, uuid: UUIDStringType) => unknown;
|
||||||
};
|
};
|
||||||
|
@ -372,82 +344,11 @@ export class ConversationView extends window.Backbone.View<ConversationModel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
getMessageActions(): MessageActionsType {
|
getMessageActions(): MessageActionsType {
|
||||||
const reactToMessage = async (
|
|
||||||
messageId: string,
|
|
||||||
reaction: { emoji: string; remove: boolean }
|
|
||||||
) => {
|
|
||||||
const { emoji, remove } = reaction;
|
|
||||||
try {
|
|
||||||
await enqueueReactionForSend({
|
|
||||||
messageId,
|
|
||||||
emoji,
|
|
||||||
remove,
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
log.error('Error sending reaction', error, messageId, reaction);
|
|
||||||
showToast(ToastReactionFailed);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const retrySend = retryMessageSend;
|
|
||||||
const showMessageDetail = (messageId: string) => {
|
const showMessageDetail = (messageId: string) => {
|
||||||
this.showMessageDetail(messageId);
|
this.showMessageDetail(messageId);
|
||||||
};
|
};
|
||||||
const kickOffAttachmentDownload = async (
|
|
||||||
options: Readonly<{ messageId: string }>
|
|
||||||
) => {
|
|
||||||
const message = window.MessageController.getById(options.messageId);
|
|
||||||
if (!message) {
|
|
||||||
throw new Error(
|
|
||||||
`kickOffAttachmentDownload: Message ${options.messageId} missing!`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await message.queueAttachmentDownloads();
|
|
||||||
};
|
|
||||||
const markAttachmentAsCorrupted = (options: AttachmentOptions) => {
|
|
||||||
const message = window.MessageController.getById(options.messageId);
|
|
||||||
if (!message) {
|
|
||||||
throw new Error(
|
|
||||||
`markAttachmentAsCorrupted: Message ${options.messageId} missing!`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
message.markAttachmentAsCorrupted(options.attachment);
|
|
||||||
};
|
|
||||||
|
|
||||||
const openGiftBadge = (messageId: string): void => {
|
|
||||||
const message = window.MessageController.getById(messageId);
|
|
||||||
if (!message) {
|
|
||||||
throw new Error(`openGiftBadge: Message ${messageId} missing!`);
|
|
||||||
}
|
|
||||||
|
|
||||||
showToast(ToastCannotOpenGiftBadge, {
|
|
||||||
isIncoming: isIncoming(message.attributes),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const openLink = openLinkInWebBrowser;
|
|
||||||
const downloadNewVersion = () => {
|
|
||||||
openLinkInWebBrowser('https://signal.org/download');
|
|
||||||
};
|
|
||||||
const showExpiredIncomingTapToViewToast = () => {
|
|
||||||
log.info('Showing expired tap-to-view toast for an incoming message');
|
|
||||||
showToast(ToastTapToViewExpiredIncoming);
|
|
||||||
};
|
|
||||||
const showExpiredOutgoingTapToViewToast = () => {
|
|
||||||
log.info('Showing expired tap-to-view toast for an outgoing message');
|
|
||||||
showToast(ToastTapToViewExpiredOutgoing);
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
downloadNewVersion,
|
|
||||||
kickOffAttachmentDownload,
|
|
||||||
markAttachmentAsCorrupted,
|
|
||||||
openGiftBadge,
|
|
||||||
openLink,
|
|
||||||
reactToMessage,
|
|
||||||
retrySend,
|
|
||||||
retryDeleteForEveryone,
|
|
||||||
showExpiredIncomingTapToViewToast,
|
|
||||||
showExpiredOutgoingTapToViewToast,
|
|
||||||
showMessageDetail,
|
showMessageDetail,
|
||||||
startConversation,
|
startConversation,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue