Allow stage and send of video, even if we can't get screenshot
This commit is contained in:
parent
117cb074c7
commit
a024ee4b96
21 changed files with 224 additions and 143 deletions
|
@ -13,7 +13,7 @@ import { CompositionArea } from './CompositionArea';
|
|||
import { setupI18n } from '../util/setupI18n';
|
||||
import enMessages from '../../_locales/en/messages.json';
|
||||
|
||||
import { fakeAttachment } from '../test-both/helpers/fakeAttachment';
|
||||
import { fakeDraftAttachment } from '../test-both/helpers/fakeAttachment';
|
||||
import { landscapeGreenUrl } from '../storybook/Fixtures';
|
||||
import { ThemeType } from '../types/Util';
|
||||
import { RecordingState } from '../state/ducks/audioRecorder';
|
||||
|
@ -165,7 +165,7 @@ story.add('SMS-only', () => {
|
|||
story.add('Attachments', () => {
|
||||
const props = createProps({
|
||||
draftAttachments: [
|
||||
fakeAttachment({
|
||||
fakeDraftAttachment({
|
||||
contentType: IMAGE_JPEG,
|
||||
url: landscapeGreenUrl,
|
||||
}),
|
||||
|
|
|
@ -34,7 +34,10 @@ import type { PropsType as GroupV2PendingApprovalActionsPropsType } from './conv
|
|||
import { GroupV2PendingApprovalActions } from './conversation/GroupV2PendingApprovalActions';
|
||||
import { AnnouncementsOnlyGroupBanner } from './AnnouncementsOnlyGroupBanner';
|
||||
import { AttachmentList } from './conversation/AttachmentList';
|
||||
import type { AttachmentType } from '../types/Attachment';
|
||||
import type {
|
||||
AttachmentDraftType,
|
||||
InMemoryAttachmentDraftType,
|
||||
} from '../types/Attachment';
|
||||
import { isImageAttachment } from '../types/Attachment';
|
||||
import { AudioCapture } from './conversation/AudioCapture';
|
||||
import { CompositionUpload } from './CompositionUpload';
|
||||
|
@ -67,11 +70,11 @@ export type OwnProps = Readonly<{
|
|||
acceptedMessageRequest?: boolean;
|
||||
addAttachment: (
|
||||
conversationId: string,
|
||||
attachment: AttachmentType
|
||||
attachment: InMemoryAttachmentDraftType
|
||||
) => unknown;
|
||||
addPendingAttachment: (
|
||||
conversationId: string,
|
||||
pendingAttachment: AttachmentType
|
||||
pendingAttachment: AttachmentDraftType
|
||||
) => unknown;
|
||||
announcementsOnly?: boolean;
|
||||
areWeAdmin?: boolean;
|
||||
|
@ -80,11 +83,11 @@ export type OwnProps = Readonly<{
|
|||
cancelRecording: () => unknown;
|
||||
completeRecording: (
|
||||
conversationId: string,
|
||||
onSendAudioRecording?: (rec: AttachmentType) => unknown
|
||||
onSendAudioRecording?: (rec: InMemoryAttachmentDraftType) => unknown
|
||||
) => unknown;
|
||||
compositionApi?: MutableRefObject<CompositionAPIType>;
|
||||
conversationId: string;
|
||||
draftAttachments: ReadonlyArray<AttachmentType>;
|
||||
draftAttachments: ReadonlyArray<AttachmentDraftType>;
|
||||
errorDialogAudioRecorderType?: ErrorDialogAudioRecorderType;
|
||||
errorRecording: (e: ErrorDialogAudioRecorderType) => unknown;
|
||||
groupAdmins: Array<ConversationType>;
|
||||
|
@ -105,11 +108,11 @@ export type OwnProps = Readonly<{
|
|||
processAttachments: (options: HandleAttachmentsProcessingArgsType) => unknown;
|
||||
onSelectMediaQuality(isHQ: boolean): unknown;
|
||||
onSendMessage(options: {
|
||||
draftAttachments?: ReadonlyArray<AttachmentType>;
|
||||
draftAttachments?: ReadonlyArray<AttachmentDraftType>;
|
||||
mentions?: BodyRangesType;
|
||||
message?: string;
|
||||
timestamp?: number;
|
||||
voiceNoteAttachment?: AttachmentType;
|
||||
voiceNoteAttachment?: InMemoryAttachmentDraftType;
|
||||
}): unknown;
|
||||
openConversation(conversationId: string): unknown;
|
||||
quotedMessageProps?: Omit<
|
||||
|
@ -373,7 +376,9 @@ export const CompositionArea = ({
|
|||
errorRecording={errorRecording}
|
||||
i18n={i18n}
|
||||
recordingState={recordingState}
|
||||
onSendAudioRecording={(voiceNoteAttachment: AttachmentType) => {
|
||||
onSendAudioRecording={(
|
||||
voiceNoteAttachment: InMemoryAttachmentDraftType
|
||||
) => {
|
||||
onSendMessage({ voiceNoteAttachment });
|
||||
}}
|
||||
startRecording={startRecording}
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
import type { ChangeEventHandler } from 'react';
|
||||
import React, { forwardRef, useState } from 'react';
|
||||
|
||||
import type { AttachmentType } from '../types/Attachment';
|
||||
import type {
|
||||
InMemoryAttachmentDraftType,
|
||||
AttachmentDraftType,
|
||||
} from '../types/Attachment';
|
||||
import { AttachmentToastType } from '../types/AttachmentToastType';
|
||||
import type { LocalizerType } from '../types/Util';
|
||||
|
||||
|
@ -19,14 +22,14 @@ import type { HandleAttachmentsProcessingArgsType } from '../util/handleAttachme
|
|||
export type PropsType = {
|
||||
addAttachment: (
|
||||
conversationId: string,
|
||||
attachment: AttachmentType
|
||||
attachment: InMemoryAttachmentDraftType
|
||||
) => unknown;
|
||||
addPendingAttachment: (
|
||||
conversationId: string,
|
||||
pendingAttachment: AttachmentType
|
||||
pendingAttachment: AttachmentDraftType
|
||||
) => unknown;
|
||||
conversationId: string;
|
||||
draftAttachments: ReadonlyArray<AttachmentType>;
|
||||
draftAttachments: ReadonlyArray<AttachmentDraftType>;
|
||||
i18n: LocalizerType;
|
||||
processAttachments: (options: HandleAttachmentsProcessingArgsType) => unknown;
|
||||
removeAttachment: (conversationId: string, filePath: string) => unknown;
|
||||
|
|
|
@ -8,7 +8,7 @@ import { action } from '@storybook/addon-actions';
|
|||
import { text } from '@storybook/addon-knobs';
|
||||
|
||||
import enMessages from '../../_locales/en/messages.json';
|
||||
import type { AttachmentType } from '../types/Attachment';
|
||||
import type { AttachmentDraftType } from '../types/Attachment';
|
||||
import type { PropsType } from './ForwardMessageModal';
|
||||
import { ForwardMessageModal } from './ForwardMessageModal';
|
||||
import { IMAGE_JPEG, VIDEO_MP4, stringToMIMEType } from '../types/MIME';
|
||||
|
@ -16,15 +16,17 @@ import { getDefaultConversation } from '../test-both/helpers/getDefaultConversat
|
|||
import { setupI18n } from '../util/setupI18n';
|
||||
import { StorybookThemeContext } from '../../.storybook/StorybookThemeContext';
|
||||
|
||||
const createAttachment = (
|
||||
props: Partial<AttachmentType> = {}
|
||||
): AttachmentType => ({
|
||||
const createDraftAttachment = (
|
||||
props: Partial<AttachmentDraftType> = {}
|
||||
): AttachmentDraftType => ({
|
||||
pending: false,
|
||||
path: 'fileName.jpg',
|
||||
contentType: stringToMIMEType(
|
||||
text('attachment contentType', props.contentType || '')
|
||||
),
|
||||
fileName: text('attachment fileName', props.fileName || ''),
|
||||
screenshot: props.screenshot,
|
||||
url: text('attachment url', props.url || ''),
|
||||
screenshotPath: props.pending === false ? props.screenshotPath : undefined,
|
||||
url: text('attachment url', props.pending === false ? props.url || '' : ''),
|
||||
size: 3433,
|
||||
});
|
||||
|
||||
|
@ -81,7 +83,7 @@ story.add('link preview', () => {
|
|||
date: Date.now(),
|
||||
domain: 'https://www.signal.org',
|
||||
url: 'signal.org',
|
||||
image: createAttachment({
|
||||
image: createDraftAttachment({
|
||||
url: '/fixtures/kitten-4-112-112.jpg',
|
||||
contentType: IMAGE_JPEG,
|
||||
}),
|
||||
|
@ -99,22 +101,19 @@ story.add('media attachments', () => {
|
|||
<ForwardMessageModal
|
||||
{...useProps({
|
||||
attachments: [
|
||||
createAttachment({
|
||||
createDraftAttachment({
|
||||
pending: true,
|
||||
}),
|
||||
createDraftAttachment({
|
||||
contentType: IMAGE_JPEG,
|
||||
fileName: 'tina-rolf-269345-unsplash.jpg',
|
||||
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
|
||||
}),
|
||||
createAttachment({
|
||||
createDraftAttachment({
|
||||
contentType: VIDEO_MP4,
|
||||
fileName: 'pixabay-Soap-Bubble-7141.mp4',
|
||||
url: '/fixtures/pixabay-Soap-Bubble-7141.mp4',
|
||||
screenshot: {
|
||||
height: 112,
|
||||
width: 112,
|
||||
url: '/fixtures/kitten-4-112-112.jpg',
|
||||
contentType: IMAGE_JPEG,
|
||||
path: 'originalPath',
|
||||
},
|
||||
screenshotPath: '/fixtures/kitten-4-112-112.jpg',
|
||||
}),
|
||||
],
|
||||
messageBody: 'cats',
|
||||
|
|
|
@ -16,7 +16,7 @@ import { animated } from '@react-spring/web';
|
|||
|
||||
import classNames from 'classnames';
|
||||
import { AttachmentList } from './conversation/AttachmentList';
|
||||
import type { AttachmentType } from '../types/Attachment';
|
||||
import type { AttachmentDraftType } from '../types/Attachment';
|
||||
import { Button } from './Button';
|
||||
import type { InputApi } from './CompositionInput';
|
||||
import { CompositionInput } from './CompositionInput';
|
||||
|
@ -38,13 +38,13 @@ import { filterAndSortConversationsByRecent } from '../util/filterAndSortConvers
|
|||
import { useAnimated } from '../hooks/useAnimated';
|
||||
|
||||
export type DataPropsType = {
|
||||
attachments?: Array<AttachmentType>;
|
||||
attachments?: Array<AttachmentDraftType>;
|
||||
candidateConversations: ReadonlyArray<ConversationType>;
|
||||
conversationId: string;
|
||||
doForwardMessage: (
|
||||
selectedContacts: Array<string>,
|
||||
messageBody?: string,
|
||||
attachments?: Array<AttachmentType>,
|
||||
attachments?: Array<AttachmentDraftType>,
|
||||
linkPreview?: LinkPreviewType
|
||||
) => void;
|
||||
i18n: LocalizerType;
|
||||
|
@ -100,7 +100,9 @@ export const ForwardMessageModal: FunctionComponent<PropsType> = ({
|
|||
const [filteredConversations, setFilteredConversations] = useState(
|
||||
filterAndSortConversationsByRecent(candidateConversations, '')
|
||||
);
|
||||
const [attachmentsToForward, setAttachmentsToForward] = useState(attachments);
|
||||
const [attachmentsToForward, setAttachmentsToForward] = useState<
|
||||
Array<AttachmentDraftType>
|
||||
>(attachments || []);
|
||||
const [isEditingMessage, setIsEditingMessage] = useState(false);
|
||||
const [messageBodyText, setMessageBodyText] = useState(messageBody || '');
|
||||
const [cannotMessage, setCannotMessage] = useState(false);
|
||||
|
@ -322,7 +324,7 @@ export const ForwardMessageModal: FunctionComponent<PropsType> = ({
|
|||
<AttachmentList
|
||||
attachments={attachmentsToForward}
|
||||
i18n={i18n}
|
||||
onCloseAttachment={(attachment: AttachmentType) => {
|
||||
onCloseAttachment={(attachment: AttachmentDraftType) => {
|
||||
const newAttachments = attachmentsToForward.filter(
|
||||
currentAttachment => currentAttachment !== attachment
|
||||
);
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
import { setupI18n } from '../../util/setupI18n';
|
||||
import enMessages from '../../../_locales/en/messages.json';
|
||||
|
||||
import { fakeAttachment } from '../../test-both/helpers/fakeAttachment';
|
||||
import { fakeDraftAttachment } from '../../test-both/helpers/fakeAttachment';
|
||||
|
||||
const i18n = setupI18n('en', enMessages);
|
||||
|
||||
|
@ -36,7 +36,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
|||
story.add('One File', () => {
|
||||
const props = createProps({
|
||||
attachments: [
|
||||
fakeAttachment({
|
||||
fakeDraftAttachment({
|
||||
contentType: IMAGE_JPEG,
|
||||
fileName: 'tina-rolf-269345-unsplash.jpg',
|
||||
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
|
||||
|
@ -49,24 +49,18 @@ story.add('One File', () => {
|
|||
story.add('Multiple Visual Attachments', () => {
|
||||
const props = createProps({
|
||||
attachments: [
|
||||
fakeAttachment({
|
||||
fakeDraftAttachment({
|
||||
contentType: IMAGE_JPEG,
|
||||
fileName: 'tina-rolf-269345-unsplash.jpg',
|
||||
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
|
||||
}),
|
||||
fakeAttachment({
|
||||
fakeDraftAttachment({
|
||||
contentType: VIDEO_MP4,
|
||||
fileName: 'pixabay-Soap-Bubble-7141.mp4',
|
||||
url: '/fixtures/pixabay-Soap-Bubble-7141.mp4',
|
||||
screenshot: {
|
||||
height: 112,
|
||||
width: 112,
|
||||
url: '/fixtures/kitten-4-112-112.jpg',
|
||||
contentType: IMAGE_JPEG,
|
||||
path: 'originalpath',
|
||||
},
|
||||
url: '/fixtures/kitten-4-112-112.jpg',
|
||||
screenshotPath: '/fixtures/kitten-4-112-112.jpg',
|
||||
}),
|
||||
fakeAttachment({
|
||||
fakeDraftAttachment({
|
||||
contentType: IMAGE_GIF,
|
||||
fileName: 'giphy-GVNv0UpeYm17e',
|
||||
url: '/fixtures/giphy-GVNvOUpeYmI7e.gif',
|
||||
|
@ -80,34 +74,28 @@ story.add('Multiple Visual Attachments', () => {
|
|||
story.add('Multiple with Non-Visual Types', () => {
|
||||
const props = createProps({
|
||||
attachments: [
|
||||
fakeAttachment({
|
||||
fakeDraftAttachment({
|
||||
contentType: IMAGE_JPEG,
|
||||
fileName: 'tina-rolf-269345-unsplash.jpg',
|
||||
url: '/fixtures/tina-rolf-269345-unsplash.jpg',
|
||||
}),
|
||||
fakeAttachment({
|
||||
fakeDraftAttachment({
|
||||
contentType: stringToMIMEType('text/plain'),
|
||||
fileName: 'lorem-ipsum.txt',
|
||||
url: '/fixtures/lorem-ipsum.txt',
|
||||
}),
|
||||
fakeAttachment({
|
||||
fakeDraftAttachment({
|
||||
contentType: AUDIO_MP3,
|
||||
fileName: 'incompetech-com-Agnus-Dei-X.mp3',
|
||||
url: '/fixtures/incompetech-com-Agnus-Dei-X.mp3',
|
||||
}),
|
||||
fakeAttachment({
|
||||
fakeDraftAttachment({
|
||||
contentType: VIDEO_MP4,
|
||||
fileName: 'pixabay-Soap-Bubble-7141.mp4',
|
||||
url: '/fixtures/pixabay-Soap-Bubble-7141.mp4',
|
||||
screenshot: {
|
||||
height: 112,
|
||||
width: 112,
|
||||
url: '/fixtures/kitten-4-112-112.jpg',
|
||||
contentType: IMAGE_JPEG,
|
||||
path: 'originalpath',
|
||||
},
|
||||
url: '/fixtures/kitten-4-112-112.jpg',
|
||||
screenshotPath: '/fixtures/kitten-4-112-112.jpg',
|
||||
}),
|
||||
fakeAttachment({
|
||||
fakeDraftAttachment({
|
||||
contentType: IMAGE_GIF,
|
||||
fileName: 'giphy-GVNv0UpeYm17e',
|
||||
url: '/fixtures/giphy-GVNvOUpeYmI7e.gif',
|
||||
|
|
|
@ -7,21 +7,20 @@ import { Image } from './Image';
|
|||
import { StagedGenericAttachment } from './StagedGenericAttachment';
|
||||
import { StagedPlaceholderAttachment } from './StagedPlaceholderAttachment';
|
||||
import type { LocalizerType } from '../../types/Util';
|
||||
import type { AttachmentType } from '../../types/Attachment';
|
||||
import type { AttachmentDraftType } from '../../types/Attachment';
|
||||
import {
|
||||
areAllAttachmentsVisual,
|
||||
getUrl,
|
||||
isImageAttachment,
|
||||
isVideoAttachment,
|
||||
} from '../../types/Attachment';
|
||||
|
||||
export type Props = Readonly<{
|
||||
attachments: ReadonlyArray<AttachmentType>;
|
||||
attachments: ReadonlyArray<AttachmentDraftType>;
|
||||
i18n: LocalizerType;
|
||||
onAddAttachment?: () => void;
|
||||
onClickAttachment?: (attachment: AttachmentType) => void;
|
||||
onClickAttachment?: (attachment: AttachmentDraftType) => void;
|
||||
onClose?: () => void;
|
||||
onCloseAttachment: (attachment: AttachmentType) => void;
|
||||
onCloseAttachment: (attachment: AttachmentDraftType) => void;
|
||||
}>;
|
||||
|
||||
const IMAGE_WIDTH = 120;
|
||||
|
@ -31,6 +30,14 @@ const IMAGE_HEIGHT = 120;
|
|||
const BLANK_VIDEO_THUMBNAIL =
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQAAAAA3bvkkAAAACklEQVR42mNiAAAABgADm78GJQAAAABJRU5ErkJggg==';
|
||||
|
||||
function getUrl(attachment: AttachmentDraftType): string | undefined {
|
||||
if (attachment.pending) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return attachment.url;
|
||||
}
|
||||
|
||||
export const AttachmentList = ({
|
||||
attachments,
|
||||
i18n,
|
||||
|
@ -65,11 +72,17 @@ export const AttachmentList = ({
|
|||
|
||||
const isImage = isImageAttachment(attachment);
|
||||
const isVideo = isVideoAttachment(attachment);
|
||||
const closeAttachment = () => onCloseAttachment(attachment);
|
||||
|
||||
if (isImage || isVideo || attachment.pending) {
|
||||
const isDownloaded = !attachment.pending;
|
||||
const imageUrl =
|
||||
url || (isVideo ? BLANK_VIDEO_THUMBNAIL : undefined);
|
||||
|
||||
const clickAttachment = onClickAttachment
|
||||
? () => onClickAttachment(attachment)
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<Image
|
||||
key={key}
|
||||
|
@ -79,17 +92,16 @@ export const AttachmentList = ({
|
|||
className="module-staged-attachment"
|
||||
i18n={i18n}
|
||||
attachment={attachment}
|
||||
isDownloaded={isDownloaded}
|
||||
softCorners
|
||||
playIconOverlay={isVideo}
|
||||
height={IMAGE_HEIGHT}
|
||||
width={IMAGE_WIDTH}
|
||||
url={imageUrl}
|
||||
closeButton
|
||||
onClick={onClickAttachment}
|
||||
onClickClose={onCloseAttachment}
|
||||
onError={() => {
|
||||
onCloseAttachment(attachment);
|
||||
}}
|
||||
onClick={clickAttachment}
|
||||
onClickClose={closeAttachment}
|
||||
onError={closeAttachment}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -99,7 +111,7 @@ export const AttachmentList = ({
|
|||
key={key}
|
||||
attachment={attachment}
|
||||
i18n={i18n}
|
||||
onClose={onCloseAttachment}
|
||||
onClose={closeAttachment}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
|
|
@ -5,7 +5,10 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|||
import * as moment from 'moment';
|
||||
import { noop } from 'lodash';
|
||||
|
||||
import type { AttachmentType } from '../../types/Attachment';
|
||||
import type {
|
||||
AttachmentDraftType,
|
||||
InMemoryAttachmentDraftType,
|
||||
} from '../../types/Attachment';
|
||||
import { ConfirmationDialog } from '../ConfirmationDialog';
|
||||
import type { LocalizerType } from '../../types/Util';
|
||||
import {
|
||||
|
@ -20,7 +23,7 @@ import {
|
|||
useKeyboardShortcuts,
|
||||
} from '../../hooks/useKeyboardShortcuts';
|
||||
|
||||
type OnSendAudioRecordingType = (rec: AttachmentType) => unknown;
|
||||
type OnSendAudioRecordingType = (rec: InMemoryAttachmentDraftType) => unknown;
|
||||
|
||||
export type PropsType = {
|
||||
cancelRecording: () => unknown;
|
||||
|
@ -29,7 +32,7 @@ export type PropsType = {
|
|||
conversationId: string,
|
||||
onSendAudioRecording?: OnSendAudioRecordingType
|
||||
) => unknown;
|
||||
draftAttachments: ReadonlyArray<AttachmentType>;
|
||||
draftAttachments: ReadonlyArray<AttachmentDraftType>;
|
||||
errorDialogAudioRecorderType?: ErrorDialogAudioRecorderType;
|
||||
errorRecording: (e: ErrorDialogAudioRecorderType) => unknown;
|
||||
i18n: LocalizerType;
|
||||
|
|
|
@ -15,6 +15,7 @@ export type Props = {
|
|||
attachment: AttachmentType;
|
||||
url?: string;
|
||||
|
||||
isDownloaded?: boolean;
|
||||
className?: string;
|
||||
height?: number;
|
||||
width?: number;
|
||||
|
@ -145,6 +146,7 @@ export class Image extends React.Component<Props> {
|
|||
curveTopLeft,
|
||||
curveTopRight,
|
||||
darkOverlay,
|
||||
isDownloaded,
|
||||
height = 0,
|
||||
i18n,
|
||||
noBackground,
|
||||
|
@ -165,7 +167,9 @@ export class Image extends React.Component<Props> {
|
|||
|
||||
const { caption, pending } = attachment || { caption: null, pending: true };
|
||||
const canClick = this.canClick();
|
||||
const imgNotDownloaded = hasNotDownloaded(attachment);
|
||||
const imgNotDownloaded = isDownloaded
|
||||
? false
|
||||
: hasNotDownloaded(attachment);
|
||||
|
||||
const resolvedBlurHash = blurHash || defaultBlurHash(theme);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue