Moves saveAttachment to a redux action
This commit is contained in:
parent
c8068cd501
commit
b138774454
34 changed files with 190 additions and 216 deletions
|
@ -41,6 +41,7 @@ type PropsType = {
|
|||
isMaximized: boolean;
|
||||
isFullScreen: boolean;
|
||||
menuOptions: MenuOptionsType;
|
||||
openFileInFolder: (target: string) => unknown;
|
||||
hasCustomTitleBar: boolean;
|
||||
hideMenuBar: boolean;
|
||||
|
||||
|
@ -73,6 +74,7 @@ export function App({
|
|||
hasCustomTitleBar,
|
||||
menuOptions,
|
||||
openInbox,
|
||||
openFileInFolder,
|
||||
registerSingleDevice,
|
||||
renderCallManager,
|
||||
renderCustomizingPreferredReactionsModal,
|
||||
|
@ -178,7 +180,12 @@ export function App({
|
|||
'dark-theme': theme === ThemeType.dark,
|
||||
})}
|
||||
>
|
||||
<ToastManager hideToast={hideToast} i18n={i18n} toast={toast} />
|
||||
<ToastManager
|
||||
hideToast={hideToast}
|
||||
i18n={i18n}
|
||||
openFileInFolder={openFileInFolder}
|
||||
toast={toast}
|
||||
/>
|
||||
{renderGlobalModalContainer()}
|
||||
{renderCallManager()}
|
||||
{renderLightbox()}
|
||||
|
|
|
@ -30,8 +30,9 @@ export function AvatarLightbox({
|
|||
<Lightbox
|
||||
closeLightbox={onClose}
|
||||
i18n={i18n}
|
||||
media={[]}
|
||||
isViewOnce
|
||||
media={[]}
|
||||
saveAttachment={noop}
|
||||
toggleForwardMessageModal={noop}
|
||||
>
|
||||
<AvatarPreview
|
||||
|
|
|
@ -59,6 +59,7 @@ const createProps = (overrideProps: Partial<PropsType> = {}): PropsType => ({
|
|||
i18n,
|
||||
isViewOnce: Boolean(overrideProps.isViewOnce),
|
||||
media: overrideProps.media || [],
|
||||
saveAttachment: action('saveAttachment'),
|
||||
selectedIndex: number('selectedIndex', overrideProps.selectedIndex || 0),
|
||||
toggleForwardMessageModal: action('toggleForwardMessageModal'),
|
||||
});
|
||||
|
|
|
@ -9,7 +9,10 @@ import { createPortal } from 'react-dom';
|
|||
import { noop } from 'lodash';
|
||||
import { useSpring, animated, to } from '@react-spring/web';
|
||||
|
||||
import type { ConversationType } from '../state/ducks/conversations';
|
||||
import type {
|
||||
ConversationType,
|
||||
SaveAttachmentActionCreatorType,
|
||||
} from '../state/ducks/conversations';
|
||||
import type { LocalizerType } from '../types/Util';
|
||||
import type { MediaItemType, MediaItemMessageType } from '../types/MediaItem';
|
||||
import * as GoogleChrome from '../util/GoogleChrome';
|
||||
|
@ -18,7 +21,6 @@ import { Avatar, AvatarSize } from './Avatar';
|
|||
import { IMAGE_PNG, isImage, isVideo } from '../types/MIME';
|
||||
import { formatDuration } from '../util/formatDuration';
|
||||
import { isGIF } from '../types/Attachment';
|
||||
import { saveAttachment } from '../util/saveAttachment';
|
||||
import { useRestoreFocus } from '../hooks/useRestoreFocus';
|
||||
|
||||
export type PropsType = {
|
||||
|
@ -28,6 +30,7 @@ export type PropsType = {
|
|||
i18n: LocalizerType;
|
||||
isViewOnce?: boolean;
|
||||
media: Array<MediaItemType>;
|
||||
saveAttachment: SaveAttachmentActionCreatorType;
|
||||
selectedIndex?: number;
|
||||
toggleForwardMessageModal: (messageId: string) => unknown;
|
||||
};
|
||||
|
@ -53,6 +56,7 @@ export function Lightbox({
|
|||
media,
|
||||
i18n,
|
||||
isViewOnce = false,
|
||||
saveAttachment,
|
||||
selectedIndex: initialSelectedIndex = 0,
|
||||
toggleForwardMessageModal,
|
||||
}: PropsType): JSX.Element | null {
|
||||
|
|
|
@ -15,7 +15,7 @@ import { SendStatus } from '../messages/MessageSendState';
|
|||
import { Theme } from '../util/theme';
|
||||
import { formatDateTimeLong } from '../util/timestamp';
|
||||
import { DurationInSeconds } from '../util/durations';
|
||||
import type { saveAttachment } from '../util/saveAttachment';
|
||||
import type { SaveAttachmentActionCreatorType } from '../state/ducks/conversations';
|
||||
import type { AttachmentType } from '../types/Attachment';
|
||||
import { ThemeType } from '../types/Util';
|
||||
import { Time } from './Time';
|
||||
|
@ -27,7 +27,7 @@ export type PropsType = {
|
|||
i18n: LocalizerType;
|
||||
isInternalUser?: boolean;
|
||||
onClose: () => unknown;
|
||||
saveAttachment: typeof saveAttachment;
|
||||
saveAttachment: SaveAttachmentActionCreatorType;
|
||||
sender: StoryViewType['sender'];
|
||||
sendState?: Array<StorySendStateType>;
|
||||
attachment?: AttachmentType;
|
||||
|
|
|
@ -12,7 +12,10 @@ import React, {
|
|||
import classNames from 'classnames';
|
||||
import type { DraftBodyRangesType, LocalizerType } from '../types/Util';
|
||||
import type { ContextMenuOptionType } from './ContextMenu';
|
||||
import type { ConversationType } from '../state/ducks/conversations';
|
||||
import type {
|
||||
ConversationType,
|
||||
SaveAttachmentActionCreatorType,
|
||||
} from '../state/ducks/conversations';
|
||||
import type { EmojiPickDataType } from './emoji/EmojiPicker';
|
||||
import type { PreferredBadgeSelectorType } from '../state/selectors/badges';
|
||||
import type { RenderEmojiPickerProps } from './conversation/ReactionPicker';
|
||||
|
@ -44,7 +47,6 @@ import { ToastType } from '../state/ducks/toast';
|
|||
import { getAvatarColor } from '../types/Colors';
|
||||
import { getStoryBackground } from '../util/getStoryBackground';
|
||||
import { getStoryDuration } from '../util/getStoryDuration';
|
||||
import type { saveAttachment } from '../util/saveAttachment';
|
||||
import { isVideoAttachment } from '../types/Attachment';
|
||||
import { graphemeAndLinkAwareSlice } from '../util/graphemeAndLinkAwareSlice';
|
||||
import { useEscapeHandling } from '../hooks/useEscapeHandling';
|
||||
|
@ -100,7 +102,7 @@ export type PropsType = {
|
|||
renderEmojiPicker: (props: RenderEmojiPickerProps) => JSX.Element;
|
||||
replyState?: ReplyStateType;
|
||||
retrySend: (messageId: string) => unknown;
|
||||
saveAttachment: typeof saveAttachment;
|
||||
saveAttachment: SaveAttachmentActionCreatorType;
|
||||
setHasAllStoriesUnmuted: (isUnmuted: boolean) => unknown;
|
||||
showToast: ShowToastActionCreatorType;
|
||||
skinTone?: number;
|
||||
|
|
|
@ -62,6 +62,7 @@ const MESSAGE_DEFAULT_PROPS = {
|
|||
openLink: shouldNeverBeCalled,
|
||||
previews: [],
|
||||
renderAudioAttachment: () => <div />,
|
||||
saveAttachment: shouldNeverBeCalled,
|
||||
scrollToQuotedMessage: shouldNeverBeCalled,
|
||||
showContactDetail: shouldNeverBeCalled,
|
||||
showContactModal: shouldNeverBeCalled,
|
||||
|
|
|
@ -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 { ToastDangerousFileType } from './ToastDangerousFileType';
|
||||
|
||||
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/ToastDangerousFileType',
|
||||
};
|
||||
|
||||
export const _ToastDangerousFileType = (): JSX.Element => (
|
||||
<ToastDangerousFileType {...defaultProps} />
|
||||
);
|
||||
|
||||
_ToastDangerousFileType.story = {
|
||||
name: 'ToastDangerousFileType',
|
||||
};
|
|
@ -1,18 +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 ToastDangerousFileType({
|
||||
i18n,
|
||||
onClose,
|
||||
}: PropsType): JSX.Element {
|
||||
return <Toast onClose={onClose}>{i18n('dangerousFileType')}</Toast>;
|
||||
}
|
|
@ -1,29 +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 { ToastFileSaved } from './ToastFileSaved';
|
||||
|
||||
import { setupI18n } from '../util/setupI18n';
|
||||
import enMessages from '../../_locales/en/messages.json';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
const defaultProps = {
|
||||
i18n,
|
||||
onClose: action('onClose'),
|
||||
onOpenFile: action('onOpenFile'),
|
||||
};
|
||||
|
||||
export default {
|
||||
title: 'Components/ToastFileSaved',
|
||||
};
|
||||
|
||||
export const _ToastFileSaved = (): JSX.Element => (
|
||||
<ToastFileSaved {...defaultProps} />
|
||||
);
|
||||
|
||||
_ToastFileSaved.story = {
|
||||
name: 'ToastFileSaved',
|
||||
};
|
|
@ -1,33 +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';
|
||||
|
||||
export type ToastPropsType = {
|
||||
onOpenFile: () => unknown;
|
||||
};
|
||||
|
||||
type PropsType = {
|
||||
i18n: LocalizerType;
|
||||
onClose: () => unknown;
|
||||
} & ToastPropsType;
|
||||
|
||||
export function ToastFileSaved({
|
||||
i18n,
|
||||
onClose,
|
||||
onOpenFile,
|
||||
}: PropsType): JSX.Element {
|
||||
return (
|
||||
<Toast
|
||||
onClose={onClose}
|
||||
toastAction={{
|
||||
label: i18n('attachmentSavedShow'),
|
||||
onClick: onOpenFile,
|
||||
}}
|
||||
>
|
||||
{i18n('attachmentSaved')}
|
||||
</Toast>
|
||||
);
|
||||
}
|
|
@ -126,6 +126,16 @@ FailedToDeleteUsername.args = {
|
|||
},
|
||||
};
|
||||
|
||||
export const FileSaved = Template.bind({});
|
||||
FileSaved.args = {
|
||||
toast: {
|
||||
toastType: ToastType.FileSaved,
|
||||
parameters: {
|
||||
fullPath: '/image.png',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const FileSize = Template.bind({});
|
||||
FileSize.args = {
|
||||
toast: {
|
||||
|
|
|
@ -12,6 +12,7 @@ import { missingCaseError } from '../util/missingCaseError';
|
|||
export type PropsType = {
|
||||
hideToast: () => unknown;
|
||||
i18n: LocalizerType;
|
||||
openFileInFolder: (target: string) => unknown;
|
||||
toast?: {
|
||||
toastType: ToastType;
|
||||
parameters?: ReplacementValuesType;
|
||||
|
@ -23,6 +24,7 @@ const SHORT_TIMEOUT = 3 * SECOND;
|
|||
export function ToastManager({
|
||||
hideToast,
|
||||
i18n,
|
||||
openFileInFolder,
|
||||
toast,
|
||||
}: PropsType): JSX.Element | null {
|
||||
if (toast === undefined) {
|
||||
|
@ -117,6 +119,24 @@ export function ToastManager({
|
|||
);
|
||||
}
|
||||
|
||||
if (toastType === ToastType.FileSaved) {
|
||||
return (
|
||||
<Toast
|
||||
onClose={hideToast}
|
||||
toastAction={{
|
||||
label: i18n('attachmentSavedShow'),
|
||||
onClick: () => {
|
||||
if (toast.parameters && 'fullPath' in toast.parameters) {
|
||||
openFileInFolder(String(toast.parameters.fullPath));
|
||||
}
|
||||
},
|
||||
}}
|
||||
>
|
||||
{i18n('attachmentSaved')}
|
||||
</Toast>
|
||||
);
|
||||
}
|
||||
|
||||
if (toastType === ToastType.FileSize) {
|
||||
return (
|
||||
<Toast onClose={hideToast}>
|
||||
|
|
|
@ -14,6 +14,7 @@ import type {
|
|||
ConversationType,
|
||||
ConversationTypeType,
|
||||
InteractionModeType,
|
||||
SaveAttachmentActionCreatorType,
|
||||
} from '../../state/ducks/conversations';
|
||||
import type { ViewStoryActionCreatorType } from '../../state/ducks/stories';
|
||||
import type { ReadStatus } from '../../messages/MessageReadStatus';
|
||||
|
@ -87,7 +88,6 @@ import { PaymentEventKind } from '../../types/Payment';
|
|||
import type { AnyPaymentEvent } from '../../types/Payment';
|
||||
import { Emojify } from './Emojify';
|
||||
import { getPaymentEventDescription } from '../../messages/helpers';
|
||||
import { saveAttachment } from '../../util/saveAttachment';
|
||||
|
||||
const GUESS_METADATA_WIDTH_TIMESTAMP_SIZE = 10;
|
||||
const GUESS_METADATA_WIDTH_EXPIRE_TIMER_SIZE = 18;
|
||||
|
@ -319,6 +319,7 @@ export type PropsActions = {
|
|||
messageId: string;
|
||||
}) => void;
|
||||
markViewed(messageId: string): void;
|
||||
saveAttachment: SaveAttachmentActionCreatorType;
|
||||
showLightbox: (options: {
|
||||
attachment: AttachmentType;
|
||||
messageId: string;
|
||||
|
@ -2380,8 +2381,13 @@ export class Message extends React.PureComponent<Props, State> {
|
|||
};
|
||||
|
||||
public openGenericAttachment = (event?: React.MouseEvent): void => {
|
||||
const { id, attachments, timestamp, kickOffAttachmentDownload } =
|
||||
this.props;
|
||||
const {
|
||||
id,
|
||||
attachments,
|
||||
saveAttachment,
|
||||
timestamp,
|
||||
kickOffAttachmentDownload,
|
||||
} = this.props;
|
||||
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
|
|
|
@ -82,6 +82,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
|||
openGiftBadge: action('openGiftBadge'),
|
||||
openLink: action('openLink'),
|
||||
renderAudioAttachment: () => <div>*AudioAttachment*</div>,
|
||||
saveAttachment: action('saveAttachment'),
|
||||
showContactDetail: action('showContactDetail'),
|
||||
showContactModal: action('showContactModal'),
|
||||
showExpiredIncomingTapToViewToast: action(
|
||||
|
|
|
@ -96,6 +96,7 @@ export type PropsReduxActions = Pick<
|
|||
| 'checkForAccount'
|
||||
| 'clearSelectedMessage'
|
||||
| 'doubleCheckMissingQuoteReference'
|
||||
| 'saveAttachment'
|
||||
| 'showContactModal'
|
||||
| 'showLightbox'
|
||||
| 'showLightboxForViewOnceMedia'
|
||||
|
@ -293,6 +294,7 @@ export class MessageDetail extends React.Component<Props> {
|
|||
openGiftBadge,
|
||||
openLink,
|
||||
renderAudioAttachment,
|
||||
saveAttachment,
|
||||
showContactDetail,
|
||||
showContactModal,
|
||||
showExpiredIncomingTapToViewToast,
|
||||
|
@ -338,6 +340,7 @@ export class MessageDetail extends React.Component<Props> {
|
|||
openGiftBadge={openGiftBadge}
|
||||
openLink={openLink}
|
||||
renderAudioAttachment={renderAudioAttachment}
|
||||
saveAttachment={saveAttachment}
|
||||
shouldCollapseAbove={false}
|
||||
shouldCollapseBelow={false}
|
||||
shouldHideMetadata={false}
|
||||
|
|
|
@ -124,6 +124,7 @@ const defaultMessageProps: TimelineMessagesProps = {
|
|||
setQuoteByMessageId: action('default--setQuoteByMessageId'),
|
||||
retrySend: action('default--retrySend'),
|
||||
retryDeleteForEveryone: action('default--retryDeleteForEveryone'),
|
||||
saveAttachment: action('saveAttachment'),
|
||||
scrollToQuotedMessage: action('default--scrollToQuotedMessage'),
|
||||
selectMessage: action('default--selectMessage'),
|
||||
shouldCollapseAbove: false,
|
||||
|
|
|
@ -283,6 +283,7 @@ const actions = () => ({
|
|||
deleteMessageForEveryone: action('deleteMessageForEveryone'),
|
||||
showMessageDetail: action('showMessageDetail'),
|
||||
openConversation: action('openConversation'),
|
||||
saveAttachment: action('saveAttachment'),
|
||||
showContactDetail: action('showContactDetail'),
|
||||
showContactModal: action('showContactModal'),
|
||||
kickOffAttachmentDownload: action('kickOffAttachmentDownload'),
|
||||
|
|
|
@ -253,6 +253,7 @@ const getActions = createSelector(
|
|||
'kickOffAttachmentDownload',
|
||||
'markAttachmentAsCorrupted',
|
||||
'messageExpanded',
|
||||
'saveAttachment',
|
||||
'showLightbox',
|
||||
'showLightboxForViewOnceMedia',
|
||||
'openLink',
|
||||
|
|
|
@ -80,6 +80,7 @@ const getDefaultProps = () => ({
|
|||
showMessageDetail: action('showMessageDetail'),
|
||||
openConversation: action('openConversation'),
|
||||
openGiftBadge: action('openGiftBadge'),
|
||||
saveAttachment: action('saveAttachment'),
|
||||
showContactDetail: action('showContactDetail'),
|
||||
showContactModal: action('showContactModal'),
|
||||
showLightbox: action('showLightbox'),
|
||||
|
|
|
@ -293,6 +293,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
|||
renderEmojiPicker,
|
||||
renderReactionPicker,
|
||||
renderAudioAttachment,
|
||||
saveAttachment: action('saveAttachment'),
|
||||
setQuoteByMessageId: action('setQuoteByMessageId'),
|
||||
retrySend: action('retrySend'),
|
||||
retryDeleteForEveryone: action('retryDeleteForEveryone'),
|
||||
|
|
|
@ -27,7 +27,6 @@ import { doesMessageBodyOverflow } from './MessageBodyReadMore';
|
|||
import type { Props as ReactionPickerProps } from './ReactionPicker';
|
||||
import { ConfirmationDialog } from '../ConfirmationDialog';
|
||||
import { useToggleReactionPicker } from '../../hooks/useKeyboardShortcuts';
|
||||
import { saveAttachment } from '../../util/saveAttachment';
|
||||
|
||||
export type PropsData = {
|
||||
canDownload: boolean;
|
||||
|
@ -172,7 +171,7 @@ export function TimelineMessage(props: Props): JSX.Element {
|
|||
});
|
||||
|
||||
const openGenericAttachment = (event?: React.MouseEvent): void => {
|
||||
const { kickOffAttachmentDownload } = props;
|
||||
const { kickOffAttachmentDownload, saveAttachment } = props;
|
||||
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue