mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-02-15 07:28:59 +00:00
Simplify undownloadable attachment states
This commit is contained in:
@@ -647,11 +647,6 @@ $message-padding-horizontal: 12px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.module-message__undownloadable-attachment--no-text
|
||||
+ .module-message__metadata {
|
||||
margin-block-start: -25px;
|
||||
}
|
||||
|
||||
.module-message__sticker-container {
|
||||
// To ensure that images are centered if they aren't full width of bubble
|
||||
text-align: center;
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
// Copyright 2025 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React from 'react';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import type { PropsType } from './AttachmentNotAvailableModal';
|
||||
import {
|
||||
AttachmentNotAvailableModal,
|
||||
AttachmentNotAvailableModalType,
|
||||
} from './AttachmentNotAvailableModal';
|
||||
import type { ComponentMeta } from '../storybook/types';
|
||||
|
||||
const { i18n } = window.SignalContext;
|
||||
|
||||
export default {
|
||||
title: 'Components/AttachmentNotAvailableModal',
|
||||
component: AttachmentNotAvailableModal,
|
||||
args: {
|
||||
modalType: AttachmentNotAvailableModalType.VisualMedia,
|
||||
i18n,
|
||||
onClose: action('onClose'),
|
||||
},
|
||||
} satisfies ComponentMeta<PropsType>;
|
||||
|
||||
export function File(args: PropsType): JSX.Element {
|
||||
return (
|
||||
<AttachmentNotAvailableModal
|
||||
{...args}
|
||||
modalType={AttachmentNotAvailableModalType.File}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function LongText(args: PropsType): JSX.Element {
|
||||
return (
|
||||
<AttachmentNotAvailableModal
|
||||
{...args}
|
||||
modalType={AttachmentNotAvailableModalType.LongText}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function Sticker(args: PropsType): JSX.Element {
|
||||
return (
|
||||
<AttachmentNotAvailableModal
|
||||
{...args}
|
||||
modalType={AttachmentNotAvailableModalType.Sticker}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function VisualMedia(args: PropsType): JSX.Element {
|
||||
return (
|
||||
<AttachmentNotAvailableModal
|
||||
{...args}
|
||||
modalType={AttachmentNotAvailableModalType.VisualMedia}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export function VoiceMessage(args: PropsType): JSX.Element {
|
||||
return (
|
||||
<AttachmentNotAvailableModal
|
||||
{...args}
|
||||
modalType={AttachmentNotAvailableModalType.VoiceMessage}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
// Copyright 2025 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import * as React from 'react';
|
||||
|
||||
import type { LocalizerType } from '../types/Util';
|
||||
import { Modal } from './Modal';
|
||||
import { Button, ButtonVariant } from './Button';
|
||||
|
||||
export type PropsType = {
|
||||
i18n: LocalizerType;
|
||||
modalType: AttachmentNotAvailableModalType;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
export enum AttachmentNotAvailableModalType {
|
||||
File = 'File',
|
||||
LongText = 'LongText',
|
||||
Sticker = 'Sticker',
|
||||
VisualMedia = 'VisualMedia',
|
||||
VoiceMessage = 'VoiceMessage',
|
||||
}
|
||||
|
||||
function focusRef(el: HTMLElement | null) {
|
||||
if (el) {
|
||||
el.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function getTitle(
|
||||
i18n: LocalizerType,
|
||||
modalType: AttachmentNotAvailableModalType
|
||||
): string {
|
||||
switch (modalType) {
|
||||
case AttachmentNotAvailableModalType.LongText:
|
||||
return i18n('icu:AttachmentNotAvailableModal__title--long-text');
|
||||
case AttachmentNotAvailableModalType.Sticker:
|
||||
return i18n('icu:AttachmentNotAvailableModal__title--sticker');
|
||||
case AttachmentNotAvailableModalType.VisualMedia:
|
||||
return i18n('icu:AttachmentNotAvailableModal__title--media');
|
||||
case AttachmentNotAvailableModalType.VoiceMessage:
|
||||
return i18n('icu:AttachmentNotAvailableModal__title--voice-message');
|
||||
case AttachmentNotAvailableModalType.File:
|
||||
default:
|
||||
return i18n('icu:AttachmentNotAvailableModal__title--file');
|
||||
}
|
||||
}
|
||||
|
||||
function getBody(
|
||||
i18n: LocalizerType,
|
||||
modalType: AttachmentNotAvailableModalType
|
||||
): string {
|
||||
switch (modalType) {
|
||||
case AttachmentNotAvailableModalType.LongText:
|
||||
return i18n('icu:AttachmentNotAvailableModal__body--long-text');
|
||||
case AttachmentNotAvailableModalType.Sticker:
|
||||
return i18n('icu:AttachmentNotAvailableModal__body--sticker');
|
||||
case AttachmentNotAvailableModalType.VisualMedia:
|
||||
return i18n('icu:AttachmentNotAvailableModal__body--media');
|
||||
case AttachmentNotAvailableModalType.VoiceMessage:
|
||||
return i18n('icu:AttachmentNotAvailableModal__body--voice-message');
|
||||
case AttachmentNotAvailableModalType.File:
|
||||
default:
|
||||
return i18n('icu:AttachmentNotAvailableModal__body--file');
|
||||
}
|
||||
}
|
||||
|
||||
export function AttachmentNotAvailableModal(props: PropsType): JSX.Element {
|
||||
const { i18n, modalType, onClose } = props;
|
||||
|
||||
const footer = (
|
||||
<Button onClick={onClose} ref={focusRef} variant={ButtonVariant.Primary}>
|
||||
{i18n('icu:Confirmation--confirm')}
|
||||
</Button>
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
modalName="AttachmentNotAvailableModal"
|
||||
moduleClassName="AttachmentNotAvailableModal"
|
||||
i18n={i18n}
|
||||
onClose={onClose}
|
||||
title={getTitle(i18n, modalType)}
|
||||
modalFooter={footer}
|
||||
padded={false}
|
||||
>
|
||||
<div className="module-error-modal__description">
|
||||
{getBody(i18n, modalType)}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -159,7 +159,6 @@ export function DebugLogWindow({
|
||||
onUndoArchive={shouldNeverBeCalled}
|
||||
openFileInFolder={shouldNeverBeCalled}
|
||||
setDidResumeDonation={shouldNeverBeCalled}
|
||||
showAttachmentNotAvailableModal={shouldNeverBeCalled}
|
||||
toast={toast}
|
||||
containerWidthBreakpoint={null}
|
||||
isInFullScreenCall={false}
|
||||
@@ -219,7 +218,6 @@ export function DebugLogWindow({
|
||||
onUndoArchive={shouldNeverBeCalled}
|
||||
openFileInFolder={shouldNeverBeCalled}
|
||||
setDidResumeDonation={shouldNeverBeCalled}
|
||||
showAttachmentNotAvailableModal={shouldNeverBeCalled}
|
||||
toast={toast}
|
||||
containerWidthBreakpoint={null}
|
||||
isInFullScreenCall={false}
|
||||
|
||||
@@ -62,7 +62,6 @@ const MESSAGE_DEFAULT_PROPS = {
|
||||
showConversation: noop,
|
||||
showEditHistoryModal: noop,
|
||||
showAttachmentDownloadStillInProgressToast: shouldNeverBeCalled,
|
||||
showAttachmentNotAvailableModal: shouldNeverBeCalled,
|
||||
showExpiredIncomingTapToViewToast: shouldNeverBeCalled,
|
||||
showExpiredOutgoingTapToViewToast: shouldNeverBeCalled,
|
||||
showLightboxForViewOnceMedia: shouldNeverBeCalled,
|
||||
|
||||
@@ -22,7 +22,6 @@ import { SignalConnectionsModal } from './SignalConnectionsModal';
|
||||
import { WhatsNewModal } from './WhatsNewModal';
|
||||
import { MediaPermissionsModal } from './MediaPermissionsModal';
|
||||
import type { StartCallData } from './ConfirmLeaveCallModal';
|
||||
import type { AttachmentNotAvailableModalType } from './AttachmentNotAvailableModal';
|
||||
import {
|
||||
TapToViewNotAvailableModal,
|
||||
type DataPropsType as TapToViewNotAvailablePropsType,
|
||||
@@ -43,9 +42,6 @@ export type PropsType = {
|
||||
// AddUserToAnotherGroupModal
|
||||
addUserToAnotherGroupModalContactId: string | undefined;
|
||||
renderAddUserToAnotherGroup: () => JSX.Element;
|
||||
// AttachmentNotAvailableModal
|
||||
attachmentNotAvailableModalType: AttachmentNotAvailableModalType | undefined;
|
||||
renderAttachmentNotAvailableModal: () => JSX.Element;
|
||||
// CallLinkAddNameModal
|
||||
callLinkAddNameModalRoomId: string | null;
|
||||
renderCallLinkAddNameModal: () => JSX.Element;
|
||||
@@ -163,9 +159,6 @@ export type PropsType = {
|
||||
|
||||
export function GlobalModalContainer({
|
||||
i18n,
|
||||
// AttachmentNotAvailableModal
|
||||
attachmentNotAvailableModalType,
|
||||
renderAttachmentNotAvailableModal,
|
||||
// AddUserToAnotherGroupModal
|
||||
addUserToAnotherGroupModalContactId,
|
||||
renderAddUserToAnotherGroup,
|
||||
@@ -420,10 +413,6 @@ export function GlobalModalContainer({
|
||||
);
|
||||
}
|
||||
|
||||
if (attachmentNotAvailableModalType) {
|
||||
return renderAttachmentNotAvailableModal();
|
||||
}
|
||||
|
||||
if (tapToViewNotAvailableModalProps) {
|
||||
return (
|
||||
<TapToViewNotAvailableModal
|
||||
|
||||
@@ -292,9 +292,6 @@ const useProps = (overrideProps: OverridePropsType = {}): PropsType => {
|
||||
onUndoArchive={action('onUndoArchive')}
|
||||
openFileInFolder={action('openFileInFolder')}
|
||||
setDidResumeDonation={action('setDidResumeDonation')}
|
||||
showAttachmentNotAvailableModal={action(
|
||||
'showAttachmentNotAvailableModal'
|
||||
)}
|
||||
toast={undefined}
|
||||
megaphone={undefined}
|
||||
containerWidthBreakpoint={containerWidthBreakpoint}
|
||||
|
||||
@@ -74,7 +74,6 @@ const MESSAGE_DEFAULT_PROPS = {
|
||||
scrollToQuotedMessage: shouldNeverBeCalled,
|
||||
showConversation: noop,
|
||||
showAttachmentDownloadStillInProgressToast: shouldNeverBeCalled,
|
||||
showAttachmentNotAvailableModal: shouldNeverBeCalled,
|
||||
showExpiredIncomingTapToViewToast: shouldNeverBeCalled,
|
||||
showExpiredOutgoingTapToViewToast: shouldNeverBeCalled,
|
||||
showLightbox: shouldNeverBeCalled,
|
||||
|
||||
@@ -273,7 +273,6 @@ export default {
|
||||
openFileInFolder: action('openFileInFolder'),
|
||||
onShowDebugLog: action('onShowDebugLog'),
|
||||
onUndoArchive: action('onUndoArchive'),
|
||||
showAttachmentNotAvailableModal: action('showAttachmentNotAvailableModal'),
|
||||
i18n,
|
||||
toastType: ToastType.AddingUserToGroup,
|
||||
megaphoneType: MegaphoneType.UsernameOnboarding,
|
||||
|
||||
@@ -13,7 +13,6 @@ import { assertDev } from '../util/assert';
|
||||
import { missingCaseError } from '../util/missingCaseError';
|
||||
import { ToastType } from '../types/Toast';
|
||||
import { MegaphoneType } from '../types/Megaphone';
|
||||
import { AttachmentNotAvailableModalType } from './AttachmentNotAvailableModal';
|
||||
import { NavTab, SettingsPage } from '../types/Nav';
|
||||
|
||||
import type { LocalizerType } from '../types/Util';
|
||||
@@ -33,9 +32,6 @@ export type PropsType = {
|
||||
options?: { wasPinned?: boolean }
|
||||
) => unknown;
|
||||
setDidResumeDonation: (didResume: boolean) => unknown;
|
||||
showAttachmentNotAvailableModal: (
|
||||
type: AttachmentNotAvailableModalType
|
||||
) => void;
|
||||
toast?: AnyToast;
|
||||
megaphone?: AnyActionableMegaphone;
|
||||
centerToast?: boolean;
|
||||
@@ -54,7 +50,6 @@ export function renderToast({
|
||||
onShowDebugLog,
|
||||
onUndoArchive,
|
||||
setDidResumeDonation,
|
||||
showAttachmentNotAvailableModal,
|
||||
OS,
|
||||
toast,
|
||||
}: PropsType): JSX.Element | null {
|
||||
@@ -549,20 +544,7 @@ export function renderToast({
|
||||
}
|
||||
|
||||
if (toastType === ToastType.MediaNoLongerAvailable) {
|
||||
return (
|
||||
<Toast
|
||||
onClose={hideToast}
|
||||
toastAction={{
|
||||
label: i18n('icu:attachmentNoLongerAvailable__learnMore'),
|
||||
onClick: () =>
|
||||
showAttachmentNotAvailableModal(
|
||||
AttachmentNotAvailableModalType.VisualMedia
|
||||
),
|
||||
}}
|
||||
>
|
||||
{i18n('icu:mediaNotAvailable')}
|
||||
</Toast>
|
||||
);
|
||||
return <Toast onClose={hideToast}>{i18n('icu:mediaNotAvailable')}</Toast>;
|
||||
}
|
||||
|
||||
if (toastType === ToastType.MessageBodyTooLong) {
|
||||
|
||||
@@ -103,7 +103,6 @@ import { getColorForCallLink } from '../../util/getColorForCallLink';
|
||||
import { getKeyFromCallLink } from '../../util/callLinks';
|
||||
import { InAnotherCallTooltip } from './InAnotherCallTooltip';
|
||||
import { formatFileSize } from '../../util/formatFileSize';
|
||||
import { AttachmentNotAvailableModalType } from '../AttachmentNotAvailableModal';
|
||||
import { assertDev, strictAssert } from '../../util/assert';
|
||||
import { AttachmentStatusIcon } from './AttachmentStatusIcon';
|
||||
import { TapToViewNotAvailableType } from '../TapToViewNotAvailableModal';
|
||||
@@ -412,9 +411,6 @@ export type PropsActions = {
|
||||
|
||||
showEditHistoryModal?: (id: string) => unknown;
|
||||
showAttachmentDownloadStillInProgressToast: (count: number) => unknown;
|
||||
showAttachmentNotAvailableModal: (
|
||||
modalType: AttachmentNotAvailableModalType
|
||||
) => void;
|
||||
showExpiredIncomingTapToViewToast: () => unknown;
|
||||
showExpiredOutgoingTapToViewToast: () => unknown;
|
||||
showMediaNoLongerAvailableToast: () => unknown;
|
||||
@@ -1323,6 +1319,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const isAttachmentAudio = isAudio(attachments);
|
||||
|
||||
if (isAttachmentNotAvailable && (isAttachmentAudio || isSticker)) {
|
||||
@@ -1498,7 +1495,6 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
isTapToViewError,
|
||||
isTapToViewExpired,
|
||||
readStatus,
|
||||
showAttachmentNotAvailableModal,
|
||||
showTapToViewNotAvailableModal,
|
||||
text,
|
||||
quote,
|
||||
@@ -1511,16 +1507,13 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
|
||||
let attachmentType: string;
|
||||
let info: string;
|
||||
let attachmentModalType: AttachmentNotAvailableModalType | undefined;
|
||||
let tapToViewModalType: TapToViewNotAvailableType | undefined;
|
||||
if (isAttachmentAudio) {
|
||||
attachmentType = 'audio';
|
||||
info = i18n('icu:attachmentNotAvailable__voice');
|
||||
attachmentModalType = AttachmentNotAvailableModalType.VoiceMessage;
|
||||
} else if (isSticker) {
|
||||
attachmentType = 'sticker';
|
||||
info = i18n('icu:attachmentNotAvailable__sticker');
|
||||
attachmentModalType = AttachmentNotAvailableModalType.Sticker;
|
||||
} else if (isTapToView && !isViewed && isTapToViewExpired) {
|
||||
attachmentType = 'tap-to-view';
|
||||
info = i18n('icu:attachmentNotAvailable__tapToView');
|
||||
@@ -1561,56 +1554,38 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
<div className="module-message__undownloadable-attachment-info">
|
||||
{info}
|
||||
</div>
|
||||
<div className="module-message__undownloadable-attachment-learn-more-container">
|
||||
<button
|
||||
className="module-message__undownloadable-attachment-learn-more"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
if (attachmentModalType) {
|
||||
showAttachmentNotAvailableModal(attachmentModalType);
|
||||
} else if (tapToViewModalType) {
|
||||
{tapToViewModalType ? (
|
||||
<div className="module-message__undownloadable-attachment-learn-more-container">
|
||||
<button
|
||||
className="module-message__undownloadable-attachment-learn-more"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
showTapToViewNotAvailableModal({
|
||||
type: tapToViewModalType,
|
||||
parameters: {
|
||||
name: author.firstName || author.title,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
throw new Error(
|
||||
'renderSimpleAttachmentNotAvailable: No type set!'
|
||||
);
|
||||
}
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
{i18n('icu:attachmentNoLongerAvailable__learnMore')}
|
||||
</button>
|
||||
</div>
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
{i18n('icu:attachmentNoLongerAvailable__learnMore')}
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
public renderUndownloadableTextAttachment(): JSX.Element | null {
|
||||
const { i18n, textAttachment, showAttachmentNotAvailableModal } =
|
||||
this.props;
|
||||
const { i18n, textAttachment } = this.props;
|
||||
if (!textAttachment || !textAttachment.isPermanentlyUndownloadable) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="module-message__simple-attachment module-message__undownloadable-attachment-text"
|
||||
tabIndex={-1}
|
||||
onClick={event => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
showAttachmentNotAvailableModal(
|
||||
AttachmentNotAvailableModalType.LongText
|
||||
);
|
||||
}}
|
||||
>
|
||||
<div className="module-message__simple-attachment module-message__undownloadable-attachment-text">
|
||||
<div className="module-message__undownloadable-attachment-text__icon-container">
|
||||
<div className="module-message__undownloadable-attachment__icon module-message__undownloadable-attachment__icon--file" />
|
||||
</div>
|
||||
@@ -1618,13 +1593,8 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
<div className="module-message__undownloadable-attachment-info">
|
||||
{i18n('icu:attachmentNotAvailable__longMessage')}
|
||||
</div>
|
||||
<div className="module-message__undownloadable-attachment-learn-more-container">
|
||||
<div className="module-message__undownloadable-attachment-learn-more">
|
||||
{i18n('icu:attachmentNoLongerAvailable__learnMore')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3024,7 +2994,6 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
direction,
|
||||
giftBadge,
|
||||
id,
|
||||
isSticker,
|
||||
isTapToView,
|
||||
isTapToViewError,
|
||||
isTapToViewExpired,
|
||||
@@ -3032,12 +3001,10 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
openGiftBadge,
|
||||
pushPanelForConversation,
|
||||
readStatus,
|
||||
showAttachmentNotAvailableModal,
|
||||
showExpiredIncomingTapToViewToast,
|
||||
showExpiredOutgoingTapToViewToast,
|
||||
showLightbox,
|
||||
showLightboxForViewOnceMedia,
|
||||
showMediaNoLongerAvailableToast,
|
||||
startConversation,
|
||||
} = this.props;
|
||||
const { imageBroken } = this.state;
|
||||
@@ -3082,24 +3049,6 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
}
|
||||
|
||||
if (attachments?.[0]?.isPermanentlyUndownloadable) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
// This needs to be the first check because canDisplayImage is true for stickers
|
||||
if (isSticker) {
|
||||
showAttachmentNotAvailableModal(
|
||||
AttachmentNotAvailableModalType.Sticker
|
||||
);
|
||||
} else if (canDisplayImage(attachments)) {
|
||||
showMediaNoLongerAvailableToast();
|
||||
} else if (isAudio(attachments)) {
|
||||
showAttachmentNotAvailableModal(
|
||||
AttachmentNotAvailableModalType.VoiceMessage
|
||||
);
|
||||
} else {
|
||||
showAttachmentNotAvailableModal(AttachmentNotAvailableModalType.File);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3181,7 +3130,6 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
timestamp,
|
||||
kickOffAttachmentDownload,
|
||||
attachmentDroppedDueToSize,
|
||||
showAttachmentNotAvailableModal,
|
||||
cancelAttachmentDownload,
|
||||
} = this.props;
|
||||
|
||||
@@ -3199,8 +3147,10 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
!attachmentDroppedDueToSize;
|
||||
|
||||
if (isAttachmentNotAvailable) {
|
||||
showAttachmentNotAvailableModal(AttachmentNotAvailableModalType.File);
|
||||
} else if (firstAttachment.pending) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstAttachment.pending) {
|
||||
cancelAttachmentDownload({
|
||||
messageId: id,
|
||||
});
|
||||
@@ -3278,7 +3228,9 @@ export class Message extends React.PureComponent<Props, State> {
|
||||
(text || (!isVideo(attachments) && !isImage(attachments)));
|
||||
const isClickable =
|
||||
isTapToView ||
|
||||
(this.isGenericAttachment(attachments, imageBroken) && !text) ||
|
||||
(this.isGenericAttachment(attachments, imageBroken) &&
|
||||
!text &&
|
||||
!attachments?.[0]?.isPermanentlyUndownloadable) ||
|
||||
contact;
|
||||
|
||||
const containerClassnames = classNames(
|
||||
|
||||
@@ -102,7 +102,6 @@ export type PropsReduxActions = Pick<
|
||||
| 'showConversation'
|
||||
| 'showEditHistoryModal'
|
||||
| 'showAttachmentDownloadStillInProgressToast'
|
||||
| 'showAttachmentNotAvailableModal'
|
||||
| 'showExpiredIncomingTapToViewToast'
|
||||
| 'showExpiredOutgoingTapToViewToast'
|
||||
| 'showLightbox'
|
||||
@@ -152,7 +151,6 @@ export function MessageDetail({
|
||||
showConversation,
|
||||
showEditHistoryModal,
|
||||
showAttachmentDownloadStillInProgressToast,
|
||||
showAttachmentNotAvailableModal,
|
||||
showExpiredIncomingTapToViewToast,
|
||||
showExpiredOutgoingTapToViewToast,
|
||||
showLightbox,
|
||||
@@ -369,7 +367,6 @@ export function MessageDetail({
|
||||
showAttachmentDownloadStillInProgressToast={
|
||||
showAttachmentDownloadStillInProgressToast
|
||||
}
|
||||
showAttachmentNotAvailableModal={showAttachmentNotAvailableModal}
|
||||
showTapToViewNotAvailableModal={showTapToViewNotAvailableModal}
|
||||
showExpiredIncomingTapToViewToast={
|
||||
showExpiredIncomingTapToViewToast
|
||||
|
||||
@@ -138,7 +138,6 @@ const defaultMessageProps: TimelineMessagesProps = {
|
||||
showAttachmentDownloadStillInProgressToast: action(
|
||||
'showAttachmentDownloadStillInProgressToast'
|
||||
),
|
||||
showAttachmentNotAvailableModal: action('showAttachmentNotAvailableModal'),
|
||||
showExpiredIncomingTapToViewToast: action(
|
||||
'showExpiredIncomingTapToViewToast'
|
||||
),
|
||||
|
||||
@@ -309,7 +309,6 @@ const actions = () => ({
|
||||
showAttachmentDownloadStillInProgressToast: action(
|
||||
'showAttachmentDownloadStillInProgressToast'
|
||||
),
|
||||
showAttachmentNotAvailableModal: action('showAttachmentNotAvailableModal'),
|
||||
showExpiredIncomingTapToViewToast: action(
|
||||
'showExpiredIncomingTapToViewToast'
|
||||
),
|
||||
|
||||
@@ -108,7 +108,6 @@ const getDefaultProps = () => ({
|
||||
showExpiredOutgoingTapToViewToast: action(
|
||||
'showExpiredIncomingTapToViewToast'
|
||||
),
|
||||
showAttachmentNotAvailableModal: action('showAttachmentNotAvailableModal'),
|
||||
showMediaNoLongerAvailableToast: action('showMediaNoLongerAvailableToast'),
|
||||
showTapToViewNotAvailableModal: action('showTapToViewNotAvailableModal'),
|
||||
scrollToQuotedMessage: action('scrollToQuotedMessage'),
|
||||
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
LONG_MESSAGE,
|
||||
stringToMIMEType,
|
||||
IMAGE_GIF,
|
||||
VIDEO_QUICKTIME,
|
||||
} from '../../types/MIME';
|
||||
import { ReadStatus } from '../../messages/MessageReadStatus';
|
||||
import { MessageAudio } from './MessageAudio';
|
||||
@@ -346,7 +347,6 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||
showAttachmentDownloadStillInProgressToast: action(
|
||||
'showAttachmentDownloadStillInProgressToast'
|
||||
),
|
||||
showAttachmentNotAvailableModal: action('showAttachmentNotAvailableModal'),
|
||||
showExpiredIncomingTapToViewToast: action(
|
||||
'showExpiredIncomingTapToViewToast'
|
||||
),
|
||||
@@ -2809,6 +2809,24 @@ export function PermanentlyUndownloadableAttachments(): JSX.Element {
|
||||
],
|
||||
status: 'sent',
|
||||
});
|
||||
const undisplayableVideo = createProps({
|
||||
attachments: [
|
||||
fakeAttachment({
|
||||
contentType: VIDEO_QUICKTIME,
|
||||
fileName: 'bird.mov',
|
||||
blurHash: 'LDA,FDBnm+I=p{tkIUI;~UkpELV]',
|
||||
width: 296,
|
||||
height: 394,
|
||||
path: undefined,
|
||||
key: undefined,
|
||||
id: undefined,
|
||||
error: true,
|
||||
isPermanentlyUndownloadable: true,
|
||||
}),
|
||||
],
|
||||
status: 'sent',
|
||||
});
|
||||
|
||||
const multipleImagesProps = createProps({
|
||||
attachments: [
|
||||
fakeAttachment({
|
||||
@@ -2838,6 +2856,32 @@ export function PermanentlyUndownloadableAttachments(): JSX.Element {
|
||||
],
|
||||
status: 'sent',
|
||||
});
|
||||
const multipleImagesSomeUndownloadableProps = createProps({
|
||||
attachments: [
|
||||
fakeAttachment({
|
||||
contentType: IMAGE_JPEG,
|
||||
fileName: 'bird.jpg',
|
||||
blurHash: 'LDA,FDBnm+I=p{tkIUI;~UkpELV]',
|
||||
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
|
||||
width: 296,
|
||||
height: 394,
|
||||
isPermanentlyUndownloadable: false,
|
||||
}),
|
||||
fakeAttachment({
|
||||
contentType: IMAGE_JPEG,
|
||||
fileName: 'bird.jpg',
|
||||
blurHash: 'LDA,FDBnm+I=p{tkIUI;~UkpELV]',
|
||||
width: 296,
|
||||
height: 394,
|
||||
path: undefined,
|
||||
key: undefined,
|
||||
id: undefined,
|
||||
error: true,
|
||||
isPermanentlyUndownloadable: true,
|
||||
}),
|
||||
],
|
||||
status: 'sent',
|
||||
});
|
||||
const gifProps = createProps({
|
||||
attachments: [
|
||||
fakeAttachment({
|
||||
@@ -2947,9 +2991,11 @@ export function PermanentlyUndownloadableAttachments(): JSX.Element {
|
||||
return (
|
||||
<>
|
||||
<TimelineMessage {...imageProps} shouldCollapseAbove />
|
||||
<TimelineMessage {...undisplayableVideo} />
|
||||
<TimelineMessage {...gifProps} />
|
||||
<TimelineMessage {...videoProps} />
|
||||
<TimelineMessage {...multipleImagesProps} />
|
||||
<TimelineMessage {...multipleImagesSomeUndownloadableProps} />
|
||||
<TimelineMessage {...stickerProps} />
|
||||
<TimelineMessage {...textFileProps} />
|
||||
<TimelineMessage {...textFileWithCaptionProps} />
|
||||
|
||||
@@ -56,7 +56,6 @@ import type { LocalizerType } from '../../types/I18N';
|
||||
import { linkCallRoute } from '../../util/signalRoutes';
|
||||
import type { StartCallData } from '../../components/ConfirmLeaveCallModal';
|
||||
import { getMessageById } from '../../messages/getMessageById';
|
||||
import type { AttachmentNotAvailableModalType } from '../../components/AttachmentNotAvailableModal';
|
||||
import type { DataPropsType as TapToViewNotAvailablePropsType } from '../../components/TapToViewNotAvailableModal';
|
||||
import type { DataPropsType as BackfillFailureModalPropsType } from '../../components/BackfillFailureModal';
|
||||
import type { SmartDraftGifMessageSendModalProps } from '../smart/DraftGifMessageSendModal';
|
||||
@@ -106,7 +105,6 @@ type MigrateToGV2PropsType = ReadonlyDeep<{
|
||||
export type GlobalModalsStateType = ReadonlyDeep<{
|
||||
addUserToAnotherGroupModalContactId?: string;
|
||||
aboutContactModalContactId?: string;
|
||||
attachmentNotAvailableModalType: AttachmentNotAvailableModalType | undefined;
|
||||
backfillFailureModalProps: BackfillFailureModalPropsType | undefined;
|
||||
callLinkAddNameModalRoomId: string | null;
|
||||
callLinkEditModalRoomId: string | null;
|
||||
@@ -155,10 +153,6 @@ export type GlobalModalsStateType = ReadonlyDeep<{
|
||||
|
||||
// Actions
|
||||
|
||||
const SHOW_ATTACHMENT_NOT_AVAILABLE_MODAL =
|
||||
'globalModals/SHOW_ATTACHMENT_NOT_AVAILABLE_MODAL';
|
||||
const HIDE_ATTACHMENT_NOT_AVAILABLE_MODAL =
|
||||
'globalModals/HIDE_ATTACHMENT_NOT_AVAILABLE_MODAL';
|
||||
const SHOW_TAP_TO_VIEW_NOT_AVAILABLE_MODAL =
|
||||
'globalModals/SHOW_TAP_TO_VIEW_NOT_AVAILABLE_MODAL';
|
||||
const HIDE_TAP_TO_VIEW_NOT_AVAILABLE_MODAL =
|
||||
@@ -246,15 +240,6 @@ export type UserNotFoundModalStateType = ReadonlyDeep<
|
||||
}
|
||||
>;
|
||||
|
||||
type HideAttachmentNotAvailableModalActionType = ReadonlyDeep<{
|
||||
type: typeof HIDE_ATTACHMENT_NOT_AVAILABLE_MODAL;
|
||||
}>;
|
||||
|
||||
type ShowAttachmentNotAvailableModalActionType = ReadonlyDeep<{
|
||||
type: typeof SHOW_ATTACHMENT_NOT_AVAILABLE_MODAL;
|
||||
payload: AttachmentNotAvailableModalType;
|
||||
}>;
|
||||
|
||||
type HideTapToViewNotAvailableModalActionType = ReadonlyDeep<{
|
||||
type: typeof HIDE_TAP_TO_VIEW_NOT_AVAILABLE_MODAL;
|
||||
}>;
|
||||
@@ -504,7 +489,6 @@ export type GlobalModalsActionType = ReadonlyDeep<
|
||||
| CloseGV2MigrationDialogActionType
|
||||
| CloseShortcutGuideModalActionType
|
||||
| CloseStickerPackPreviewActionType
|
||||
| HideAttachmentNotAvailableModalActionType
|
||||
| HideBackfillFailureModalActionType
|
||||
| HideContactModalActionType
|
||||
| HideCriticalIdlePrimaryDeviceModalActionType
|
||||
@@ -517,7 +501,6 @@ export type GlobalModalsActionType = ReadonlyDeep<
|
||||
| MessageChangedActionType
|
||||
| MessageDeletedActionType
|
||||
| MessageExpiredActionType
|
||||
| ShowAttachmentNotAvailableModalActionType
|
||||
| ShowBackfillFailureModalActionType
|
||||
| ShowCriticalIdlePrimaryDeviceModalActionType
|
||||
| ShowContactModalActionType
|
||||
@@ -564,7 +547,6 @@ export const actions = {
|
||||
closeStickerPackPreview,
|
||||
closeMediaPermissionsModal,
|
||||
ensureSystemMediaPermissions,
|
||||
hideAttachmentNotAvailableModal,
|
||||
hideBackfillFailureModal,
|
||||
hideBlockingSafetyNumberChangeDialog,
|
||||
hideContactModal,
|
||||
@@ -574,7 +556,6 @@ export const actions = {
|
||||
hideTapToViewNotAvailableModal,
|
||||
hideUserNotFoundModal,
|
||||
hideWhatsNewModal,
|
||||
showAttachmentNotAvailableModal,
|
||||
showBackfillFailureModal,
|
||||
showBlockingSafetyNumberChangeDialog,
|
||||
showContactModal,
|
||||
@@ -614,21 +595,6 @@ export const useGlobalModalActions = (): BoundActionCreatorsMapObject<
|
||||
typeof actions
|
||||
> => useBoundActions(actions);
|
||||
|
||||
function hideAttachmentNotAvailableModal(): HideAttachmentNotAvailableModalActionType {
|
||||
return {
|
||||
type: HIDE_ATTACHMENT_NOT_AVAILABLE_MODAL,
|
||||
};
|
||||
}
|
||||
|
||||
function showAttachmentNotAvailableModal(
|
||||
payload: AttachmentNotAvailableModalType
|
||||
): ShowAttachmentNotAvailableModalActionType {
|
||||
return {
|
||||
type: SHOW_ATTACHMENT_NOT_AVAILABLE_MODAL,
|
||||
payload,
|
||||
};
|
||||
}
|
||||
|
||||
function hideTapToViewNotAvailableModal(): HideTapToViewNotAvailableModalActionType {
|
||||
return {
|
||||
type: HIDE_TAP_TO_VIEW_NOT_AVAILABLE_MODAL,
|
||||
@@ -1335,7 +1301,6 @@ function copyOverMessageAttributesIntoForwardMessages(
|
||||
|
||||
export function getEmptyState(): GlobalModalsStateType {
|
||||
return {
|
||||
attachmentNotAvailableModalType: undefined,
|
||||
backfillFailureModalProps: undefined,
|
||||
hasConfirmationModal: false,
|
||||
callLinkAddNameModalRoomId: null,
|
||||
@@ -1425,20 +1390,6 @@ export function reducer(
|
||||
};
|
||||
}
|
||||
|
||||
if (action.type === HIDE_ATTACHMENT_NOT_AVAILABLE_MODAL) {
|
||||
return {
|
||||
...state,
|
||||
attachmentNotAvailableModalType: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
if (action.type === SHOW_ATTACHMENT_NOT_AVAILABLE_MODAL) {
|
||||
return {
|
||||
...state,
|
||||
attachmentNotAvailableModalType: action.payload,
|
||||
};
|
||||
}
|
||||
|
||||
if (action.type === HIDE_TAP_TO_VIEW_NOT_AVAILABLE_MODAL) {
|
||||
return {
|
||||
...state,
|
||||
|
||||
@@ -22,11 +22,6 @@ export const isShowingAnyModal = createSelector(
|
||||
})
|
||||
);
|
||||
|
||||
export const getAttachmentNotAvailableModalType = createSelector(
|
||||
getGlobalModalsState,
|
||||
({ attachmentNotAvailableModalType }) => attachmentNotAvailableModalType
|
||||
);
|
||||
|
||||
export const getCallLinkEditModalRoomId = createSelector(
|
||||
getGlobalModalsState,
|
||||
({ callLinkEditModalRoomId }) => callLinkEditModalRoomId
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright 2025 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import React, { memo, useCallback } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AttachmentNotAvailableModal } from '../../components/AttachmentNotAvailableModal';
|
||||
import { strictAssert } from '../../util/assert';
|
||||
import { getAttachmentNotAvailableModalType } from '../selectors/globalModals';
|
||||
import { getIntl } from '../selectors/user';
|
||||
import { useGlobalModalActions } from '../ducks/globalModals';
|
||||
|
||||
export const SmartAttachmentNotAvailableModal = memo(
|
||||
function SmartAttachmentNotAvailableModal() {
|
||||
const i18n = useSelector(getIntl);
|
||||
const attachmentNotAvailableModalType = useSelector(
|
||||
getAttachmentNotAvailableModalType
|
||||
);
|
||||
|
||||
strictAssert(
|
||||
attachmentNotAvailableModalType != null,
|
||||
'attachmentNotAvailableModalType is required'
|
||||
);
|
||||
|
||||
const { hideAttachmentNotAvailableModal } = useGlobalModalActions();
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
hideAttachmentNotAvailableModal();
|
||||
}, [hideAttachmentNotAvailableModal]);
|
||||
|
||||
return (
|
||||
<AttachmentNotAvailableModal
|
||||
i18n={i18n}
|
||||
modalType={attachmentNotAvailableModalType}
|
||||
onClose={handleClose}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
@@ -29,7 +29,6 @@ import { SmartCallLinkEditModal } from './CallLinkEditModal';
|
||||
import { SmartCallLinkAddNameModal } from './CallLinkAddNameModal';
|
||||
import { SmartConfirmLeaveCallModal } from './ConfirmLeaveCallModal';
|
||||
import { SmartCallLinkPendingParticipantModal } from './CallLinkPendingParticipantModal';
|
||||
import { SmartAttachmentNotAvailableModal } from './AttachmentNotAvailableModal';
|
||||
import { SmartProfileNameWarningModal } from './ProfileNameWarningModal';
|
||||
import { SmartDraftGifMessageSendModal } from './DraftGifMessageSendModal';
|
||||
import { DebugLogErrorModal } from '../../components/DebugLogErrorModal';
|
||||
@@ -106,10 +105,6 @@ function renderAboutContactModal(): JSX.Element {
|
||||
return <SmartAboutContactModal />;
|
||||
}
|
||||
|
||||
function renderAttachmentNotAvailableModal(): JSX.Element {
|
||||
return <SmartAttachmentNotAvailableModal />;
|
||||
}
|
||||
|
||||
export const SmartGlobalModalContainer = memo(
|
||||
function SmartGlobalModalContainer() {
|
||||
const conversationsStoppingSend = useSelector(getConversationsStoppingSend);
|
||||
@@ -121,7 +116,6 @@ export const SmartGlobalModalContainer = memo(
|
||||
const {
|
||||
aboutContactModalContactId,
|
||||
addUserToAnotherGroupModalContactId,
|
||||
attachmentNotAvailableModalType,
|
||||
backfillFailureModalProps,
|
||||
callLinkAddNameModalRoomId,
|
||||
callLinkEditModalRoomId,
|
||||
@@ -227,7 +221,6 @@ export const SmartGlobalModalContainer = memo(
|
||||
|
||||
return (
|
||||
<GlobalModalContainer
|
||||
attachmentNotAvailableModalType={attachmentNotAvailableModalType}
|
||||
addUserToAnotherGroupModalContactId={
|
||||
addUserToAnotherGroupModalContactId
|
||||
}
|
||||
@@ -271,7 +264,6 @@ export const SmartGlobalModalContainer = memo(
|
||||
isWhatsNewVisible={isWhatsNewVisible}
|
||||
renderAboutContactModal={renderAboutContactModal}
|
||||
renderAddUserToAnotherGroup={renderAddUserToAnotherGroup}
|
||||
renderAttachmentNotAvailableModal={renderAttachmentNotAvailableModal}
|
||||
renderCallLinkAddNameModal={renderCallLinkAddNameModal}
|
||||
renderCallLinkEditModal={renderCallLinkEditModal}
|
||||
renderCallLinkPendingParticipantModal={
|
||||
|
||||
@@ -60,7 +60,6 @@ export const SmartMessageDetail = memo(
|
||||
startConversation,
|
||||
} = useConversationsActions();
|
||||
const {
|
||||
showAttachmentNotAvailableModal,
|
||||
showContactModal,
|
||||
showEditHistoryModal,
|
||||
showTapToViewNotAvailableModal,
|
||||
@@ -117,7 +116,6 @@ export const SmartMessageDetail = memo(
|
||||
showAttachmentDownloadStillInProgressToast={
|
||||
showAttachmentDownloadStillInProgressToast
|
||||
}
|
||||
showAttachmentNotAvailableModal={showAttachmentNotAvailableModal}
|
||||
showExpiredIncomingTapToViewToast={showExpiredIncomingTapToViewToast}
|
||||
showExpiredOutgoingTapToViewToast={showExpiredOutgoingTapToViewToast}
|
||||
showLightbox={showLightbox}
|
||||
|
||||
@@ -144,7 +144,6 @@ export const SmartTimelineItem = memo(function SmartTimelineItem(
|
||||
useComposerActions();
|
||||
|
||||
const {
|
||||
showAttachmentNotAvailableModal,
|
||||
showContactModal,
|
||||
showEditHistoryModal,
|
||||
showTapToViewNotAvailableModal,
|
||||
@@ -235,7 +234,6 @@ export const SmartTimelineItem = memo(function SmartTimelineItem(
|
||||
showAttachmentDownloadStillInProgressToast={
|
||||
showAttachmentDownloadStillInProgressToast
|
||||
}
|
||||
showAttachmentNotAvailableModal={showAttachmentNotAvailableModal}
|
||||
showExpiredIncomingTapToViewToast={showExpiredIncomingTapToViewToast}
|
||||
showExpiredOutgoingTapToViewToast={showExpiredOutgoingTapToViewToast}
|
||||
showLightbox={showLightbox}
|
||||
|
||||
@@ -60,8 +60,7 @@ export const SmartToastManager = memo(function SmartToastManager({
|
||||
|
||||
const { onUndoArchive } = useConversationsActions();
|
||||
const { openFileInFolder, hideToast } = useToastActions();
|
||||
const { showAttachmentNotAvailableModal, toggleUsernameOnboarding } =
|
||||
useGlobalModalActions();
|
||||
const { toggleUsernameOnboarding } = useGlobalModalActions();
|
||||
|
||||
let megaphone: AnyActionableMegaphone | undefined;
|
||||
|
||||
@@ -100,7 +99,6 @@ export const SmartToastManager = memo(function SmartToastManager({
|
||||
openFileInFolder={openFileInFolder}
|
||||
hideToast={hideToast}
|
||||
setDidResumeDonation={setDidResume}
|
||||
showAttachmentNotAvailableModal={showAttachmentNotAvailableModal}
|
||||
centerToast={centerToast}
|
||||
containerWidthBreakpoint={containerWidthBreakpoint}
|
||||
isCompositionAreaVisible={isCompositionAreaVisible}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright 2025 Signal Messenger, LLC
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
export enum AttachmentNotAvailableModalType {
|
||||
File = 'File',
|
||||
LongText = 'LongText',
|
||||
Sticker = 'Sticker',
|
||||
VisualMedia = 'VisualMedia',
|
||||
VoiceMessage = 'VoiceMessage',
|
||||
}
|
||||
Reference in New Issue
Block a user