Simplify undownloadable attachment states

This commit is contained in:
trevor-signal
2025-09-05 17:00:28 -04:00
committed by GitHub
parent 265ab4a732
commit ab3dfc2d87
24 changed files with 74 additions and 400 deletions

View File

@@ -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;

View File

@@ -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}
/>
);
}

View File

@@ -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>
);
}

View File

@@ -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}

View File

@@ -62,7 +62,6 @@ const MESSAGE_DEFAULT_PROPS = {
showConversation: noop,
showEditHistoryModal: noop,
showAttachmentDownloadStillInProgressToast: shouldNeverBeCalled,
showAttachmentNotAvailableModal: shouldNeverBeCalled,
showExpiredIncomingTapToViewToast: shouldNeverBeCalled,
showExpiredOutgoingTapToViewToast: shouldNeverBeCalled,
showLightboxForViewOnceMedia: shouldNeverBeCalled,

View File

@@ -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

View File

@@ -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}

View File

@@ -74,7 +74,6 @@ const MESSAGE_DEFAULT_PROPS = {
scrollToQuotedMessage: shouldNeverBeCalled,
showConversation: noop,
showAttachmentDownloadStillInProgressToast: shouldNeverBeCalled,
showAttachmentNotAvailableModal: shouldNeverBeCalled,
showExpiredIncomingTapToViewToast: shouldNeverBeCalled,
showExpiredOutgoingTapToViewToast: shouldNeverBeCalled,
showLightbox: shouldNeverBeCalled,

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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(

View File

@@ -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

View File

@@ -138,7 +138,6 @@ const defaultMessageProps: TimelineMessagesProps = {
showAttachmentDownloadStillInProgressToast: action(
'showAttachmentDownloadStillInProgressToast'
),
showAttachmentNotAvailableModal: action('showAttachmentNotAvailableModal'),
showExpiredIncomingTapToViewToast: action(
'showExpiredIncomingTapToViewToast'
),

View File

@@ -309,7 +309,6 @@ const actions = () => ({
showAttachmentDownloadStillInProgressToast: action(
'showAttachmentDownloadStillInProgressToast'
),
showAttachmentNotAvailableModal: action('showAttachmentNotAvailableModal'),
showExpiredIncomingTapToViewToast: action(
'showExpiredIncomingTapToViewToast'
),

View File

@@ -108,7 +108,6 @@ const getDefaultProps = () => ({
showExpiredOutgoingTapToViewToast: action(
'showExpiredIncomingTapToViewToast'
),
showAttachmentNotAvailableModal: action('showAttachmentNotAvailableModal'),
showMediaNoLongerAvailableToast: action('showMediaNoLongerAvailableToast'),
showTapToViewNotAvailableModal: action('showTapToViewNotAvailableModal'),
scrollToQuotedMessage: action('scrollToQuotedMessage'),

View File

@@ -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} />

View File

@@ -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,

View File

@@ -22,11 +22,6 @@ export const isShowingAnyModal = createSelector(
})
);
export const getAttachmentNotAvailableModalType = createSelector(
getGlobalModalsState,
({ attachmentNotAvailableModalType }) => attachmentNotAvailableModalType
);
export const getCallLinkEditModalRoomId = createSelector(
getGlobalModalsState,
({ callLinkEditModalRoomId }) => callLinkEditModalRoomId

View File

@@ -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}
/>
);
}
);

View File

@@ -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={

View File

@@ -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}

View File

@@ -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}

View File

@@ -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}

View File

@@ -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',
}