Improve layout of various message bubbles
This commit is contained in:
parent
933c07c9ce
commit
b50c96c0b5
|
@ -443,6 +443,22 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.module-message__container--deleted-for-everyone {
|
||||||
|
@include light-theme {
|
||||||
|
color: $color-gray-90;
|
||||||
|
border: 1px solid $color-gray-25;
|
||||||
|
background-color: $color-white;
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@include dark-theme {
|
||||||
|
color: $color-gray-05;
|
||||||
|
border: 1px solid $color-gray-75;
|
||||||
|
background-color: $color-gray-95;
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.module-message__tap-to-view {
|
.module-message__tap-to-view {
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -992,6 +1008,14 @@
|
||||||
.module-message__text--error {
|
.module-message__text--error {
|
||||||
@include font-body-1-italic;
|
@include font-body-1-italic;
|
||||||
}
|
}
|
||||||
|
.module-message__text--delete-for-everyone {
|
||||||
|
@include light-theme {
|
||||||
|
color: $color-gray-90;
|
||||||
|
}
|
||||||
|
@include dark-theme {
|
||||||
|
color: $color-gray-05;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.module-message__metadata {
|
.module-message__metadata {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -999,6 +1023,7 @@
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
margin-top: 3px;
|
margin-top: 3px;
|
||||||
|
font-style: normal;
|
||||||
|
|
||||||
&--inline {
|
&--inline {
|
||||||
float: right;
|
float: right;
|
||||||
|
@ -1021,6 +1046,15 @@
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.module-message__metadata--deleted-for-everyone {
|
||||||
|
@include light-theme {
|
||||||
|
color: $color-gray-60;
|
||||||
|
}
|
||||||
|
@include dark-theme {
|
||||||
|
color: $color-gray-25;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.module-message__metadata__date {
|
.module-message__metadata__date {
|
||||||
@include font-caption;
|
@include font-caption;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
@ -1054,6 +1088,14 @@
|
||||||
color: $color-white-alpha-80;
|
color: $color-white-alpha-80;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.module-message__metadata__date--deleted-for-everyone {
|
||||||
|
@include light-theme {
|
||||||
|
color: $color-gray-60;
|
||||||
|
}
|
||||||
|
@include dark-theme {
|
||||||
|
color: $color-gray-25;
|
||||||
|
}
|
||||||
|
}
|
||||||
.module-message__metadata__date.module-message__metadata__date--incoming-with-tap-to-view-expired {
|
.module-message__metadata__date.module-message__metadata__date--incoming-with-tap-to-view-expired {
|
||||||
color: $color-gray-75;
|
color: $color-gray-75;
|
||||||
|
|
||||||
|
@ -1076,6 +1118,8 @@
|
||||||
height: 12px;
|
height: 12px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
|
// High margin to leave space for the increase when we go to two checks
|
||||||
|
margin-right: 6px;
|
||||||
margin-bottom: 2px;
|
margin-bottom: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1102,6 +1146,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.module-message__metadata__status-icon--delivered {
|
.module-message__metadata__status-icon--delivered {
|
||||||
|
// We reduce the margin size to keep the overall width the same
|
||||||
|
margin-right: 0px;
|
||||||
width: 18px;
|
width: 18px;
|
||||||
|
|
||||||
@include light-theme {
|
@include light-theme {
|
||||||
|
@ -1113,6 +1159,8 @@
|
||||||
}
|
}
|
||||||
.module-message__metadata__status-icon--read,
|
.module-message__metadata__status-icon--read,
|
||||||
.module-message__metadata__status-icon--viewed {
|
.module-message__metadata__status-icon--viewed {
|
||||||
|
// We reduce the margin size to keep the overall width the same
|
||||||
|
margin-right: 0px;
|
||||||
width: 18px;
|
width: 18px;
|
||||||
|
|
||||||
@include light-theme {
|
@include light-theme {
|
||||||
|
@ -1138,6 +1186,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.module-message__metadata__status-icon--deleted-for-everyone {
|
||||||
|
@include light-theme {
|
||||||
|
background-color: $color-gray-60;
|
||||||
|
}
|
||||||
|
@include dark-theme {
|
||||||
|
background-color: $color-gray-25;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.module-message__metadata__spinner-container {
|
.module-message__metadata__spinner-container {
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
}
|
}
|
||||||
|
@ -1367,6 +1424,15 @@ $timer-icons: '55', '50', '45', '40', '35', '30', '25', '20', '15', '10', '05',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.module-expire-timer--deleted-for-everyone {
|
||||||
|
@include light-theme {
|
||||||
|
background-color: $color-gray-60;
|
||||||
|
}
|
||||||
|
@include dark-theme {
|
||||||
|
background-color: $color-gray-25;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.module-about {
|
.module-about {
|
||||||
&__container {
|
&__container {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
@ -7845,6 +7911,8 @@ button.module-image__border-overlay:focus {
|
||||||
|
|
||||||
// To limit messages with things forcing them wider, like long attachment names
|
// To limit messages with things forcing them wider, like long attachment names
|
||||||
.module-message__container {
|
.module-message__container {
|
||||||
|
max-width: 100%;
|
||||||
|
|
||||||
&--incoming {
|
&--incoming {
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { StorybookThemeContext } from '../../.storybook/StorybookThemeContext';
|
||||||
import { fakeDraftAttachment } from '../test-both/helpers/fakeAttachment';
|
import { fakeDraftAttachment } from '../test-both/helpers/fakeAttachment';
|
||||||
import { landscapeGreenUrl } from '../storybook/Fixtures';
|
import { landscapeGreenUrl } from '../storybook/Fixtures';
|
||||||
import { RecordingState } from '../state/ducks/audioRecorder';
|
import { RecordingState } from '../state/ducks/audioRecorder';
|
||||||
|
import { ConversationColors } from '../types/Colors';
|
||||||
|
|
||||||
const i18n = setupI18n('en', enMessages);
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
|
||||||
|
@ -183,3 +184,18 @@ story.add('Announcements Only group', () => (
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
|
||||||
|
story.add('Quote', () => (
|
||||||
|
<CompositionArea
|
||||||
|
{...useProps({
|
||||||
|
quotedMessageProps: {
|
||||||
|
text: 'something',
|
||||||
|
conversationColor: ConversationColors[10],
|
||||||
|
isViewOnce: false,
|
||||||
|
referencedMessageNotFound: false,
|
||||||
|
authorTitle: 'Someone',
|
||||||
|
isFromMe: false,
|
||||||
|
},
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
|
@ -8,12 +8,13 @@ import { getIncrement, getTimerBucket } from '../../util/timer';
|
||||||
import { clearTimeoutIfNecessary } from '../../util/clearTimeoutIfNecessary';
|
import { clearTimeoutIfNecessary } from '../../util/clearTimeoutIfNecessary';
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
|
deletedForEveryone?: boolean;
|
||||||
|
direction?: 'incoming' | 'outgoing';
|
||||||
|
expirationLength: number;
|
||||||
|
expirationTimestamp?: number;
|
||||||
withImageNoCaption?: boolean;
|
withImageNoCaption?: boolean;
|
||||||
withSticker?: boolean;
|
withSticker?: boolean;
|
||||||
withTapToViewExpired?: boolean;
|
withTapToViewExpired?: boolean;
|
||||||
expirationLength: number;
|
|
||||||
expirationTimestamp: number;
|
|
||||||
direction?: 'incoming' | 'outgoing';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ExpireTimer extends React.Component<Props> {
|
export class ExpireTimer extends React.Component<Props> {
|
||||||
|
@ -46,6 +47,7 @@ export class ExpireTimer extends React.Component<Props> {
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public override render(): JSX.Element {
|
||||||
const {
|
const {
|
||||||
|
deletedForEveryone,
|
||||||
direction,
|
direction,
|
||||||
expirationLength,
|
expirationLength,
|
||||||
expirationTimestamp,
|
expirationTimestamp,
|
||||||
|
@ -62,6 +64,9 @@ export class ExpireTimer extends React.Component<Props> {
|
||||||
'module-expire-timer',
|
'module-expire-timer',
|
||||||
`module-expire-timer--${bucket}`,
|
`module-expire-timer--${bucket}`,
|
||||||
direction ? `module-expire-timer--${direction}` : null,
|
direction ? `module-expire-timer--${direction}` : null,
|
||||||
|
deletedForEveryone
|
||||||
|
? 'module-expire-timer--deleted-for-everyone'
|
||||||
|
: null,
|
||||||
withTapToViewExpired
|
withTapToViewExpired
|
||||||
? `module-expire-timer--${direction}-with-tap-to-view-expired`
|
? `module-expire-timer--${direction}-with-tap-to-view-expired`
|
||||||
: null,
|
: null,
|
||||||
|
|
|
@ -381,6 +381,16 @@ story.add('Expiring', () => {
|
||||||
return renderBothDirections(props);
|
return renderBothDirections(props);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
story.add('Will expire but still sending', () => {
|
||||||
|
const props = createProps({
|
||||||
|
status: 'sending',
|
||||||
|
expirationLength: 30 * 1000,
|
||||||
|
text: 'For outgoing messages, we show timer immediately. Incoming, we wait until expirationStartTimestamp is present.',
|
||||||
|
});
|
||||||
|
|
||||||
|
return renderBothDirections(props);
|
||||||
|
});
|
||||||
|
|
||||||
story.add('Pending', () => {
|
story.add('Pending', () => {
|
||||||
const props = createProps({
|
const props = createProps({
|
||||||
text: 'Hello there from a pal! I am sending a long message so that it will wrap a bit, since I like that look.',
|
text: 'Hello there from a pal! I am sending a long message so that it will wrap a bit, since I like that look.',
|
||||||
|
@ -607,12 +617,12 @@ story.add('Sticker', () => {
|
||||||
|
|
||||||
story.add('Deleted', () => {
|
story.add('Deleted', () => {
|
||||||
const propsSent = createProps({
|
const propsSent = createProps({
|
||||||
conversationType: 'group',
|
conversationType: 'direct',
|
||||||
deletedForEveryone: true,
|
deletedForEveryone: true,
|
||||||
status: 'sent',
|
status: 'sent',
|
||||||
});
|
});
|
||||||
const propsSending = createProps({
|
const propsSending = createProps({
|
||||||
conversationType: 'group',
|
conversationType: 'direct',
|
||||||
deletedForEveryone: true,
|
deletedForEveryone: true,
|
||||||
status: 'sending',
|
status: 'sending',
|
||||||
});
|
});
|
||||||
|
@ -645,6 +655,7 @@ story.add('Deleted with error', () => {
|
||||||
conversationType: 'group',
|
conversationType: 'group',
|
||||||
deletedForEveryone: true,
|
deletedForEveryone: true,
|
||||||
status: 'partial-sent',
|
status: 'partial-sent',
|
||||||
|
direction: 'outgoing',
|
||||||
});
|
});
|
||||||
const propsError = createProps({
|
const propsError = createProps({
|
||||||
timestamp: Date.now() - 60 * 1000,
|
timestamp: Date.now() - 60 * 1000,
|
||||||
|
@ -652,12 +663,13 @@ story.add('Deleted with error', () => {
|
||||||
conversationType: 'group',
|
conversationType: 'group',
|
||||||
deletedForEveryone: true,
|
deletedForEveryone: true,
|
||||||
status: 'error',
|
status: 'error',
|
||||||
|
direction: 'outgoing',
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{renderBothDirections(propsPartialError)}
|
<Message {...propsPartialError} />
|
||||||
{renderBothDirections(propsError)}
|
<Message {...propsError} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -548,6 +548,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
private getMetadataPlacement(
|
private getMetadataPlacement(
|
||||||
{
|
{
|
||||||
attachments,
|
attachments,
|
||||||
|
deletedForEveryone,
|
||||||
expirationLength,
|
expirationLength,
|
||||||
expirationTimestamp,
|
expirationTimestamp,
|
||||||
shouldHideMetadata,
|
shouldHideMetadata,
|
||||||
|
@ -567,7 +568,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
return MetadataPlacement.NotRendered;
|
return MetadataPlacement.NotRendered;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!text) {
|
if (!text && !deletedForEveryone) {
|
||||||
return isAudio(attachments)
|
return isAudio(attachments)
|
||||||
? MetadataPlacement.RenderedByMessageAudioComponent
|
? MetadataPlacement.RenderedByMessageAudioComponent
|
||||||
: MetadataPlacement.Bottom;
|
: MetadataPlacement.Bottom;
|
||||||
|
@ -598,7 +599,9 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
|
|
||||||
let result = GUESS_METADATA_WIDTH_TIMESTAMP_SIZE;
|
let result = GUESS_METADATA_WIDTH_TIMESTAMP_SIZE;
|
||||||
|
|
||||||
const hasExpireTimer = Boolean(expirationLength && expirationTimestamp);
|
const hasExpireTimer = Boolean(
|
||||||
|
expirationLength && (expirationTimestamp || direction === 'outgoing')
|
||||||
|
);
|
||||||
if (hasExpireTimer) {
|
if (hasExpireTimer) {
|
||||||
result += GUESS_METADATA_WIDTH_EXPIRE_TIMER_SIZE;
|
result += GUESS_METADATA_WIDTH_EXPIRE_TIMER_SIZE;
|
||||||
}
|
}
|
||||||
|
@ -1464,6 +1467,9 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
`module-message__text--${direction}`,
|
`module-message__text--${direction}`,
|
||||||
status === 'error' && direction === 'incoming'
|
status === 'error' && direction === 'incoming'
|
||||||
? 'module-message__text--error'
|
? 'module-message__text--error'
|
||||||
|
: null,
|
||||||
|
deletedForEveryone
|
||||||
|
? 'module-message__text--delete-for-everyone'
|
||||||
: null
|
: null
|
||||||
)}
|
)}
|
||||||
dir={isRTL ? 'rtl' : undefined}
|
dir={isRTL ? 'rtl' : undefined}
|
||||||
|
|
|
@ -91,6 +91,8 @@ export const MessageMetadata = ({
|
||||||
className={classNames({
|
className={classNames({
|
||||||
'module-message__metadata__date': true,
|
'module-message__metadata__date': true,
|
||||||
'module-message__metadata__date--with-sticker': isSticker,
|
'module-message__metadata__date--with-sticker': isSticker,
|
||||||
|
'module-message__metadata__date--deleted-for-everyone':
|
||||||
|
deletedForEveryone,
|
||||||
[`module-message__metadata__date--${direction}`]: !isSticker,
|
[`module-message__metadata__date--${direction}`]: !isSticker,
|
||||||
'module-message__metadata__date--with-image-no-caption':
|
'module-message__metadata__date--with-image-no-caption':
|
||||||
withImageNoCaption,
|
withImageNoCaption,
|
||||||
|
@ -105,6 +107,7 @@ export const MessageMetadata = ({
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
timestamp={timestamp}
|
timestamp={timestamp}
|
||||||
direction={metadataDirection}
|
direction={metadataDirection}
|
||||||
|
deletedForEveryone={deletedForEveryone}
|
||||||
withImageNoCaption={withImageNoCaption}
|
withImageNoCaption={withImageNoCaption}
|
||||||
withSticker={isSticker}
|
withSticker={isSticker}
|
||||||
withTapToViewExpired={isTapToViewExpired}
|
withTapToViewExpired={isTapToViewExpired}
|
||||||
|
@ -117,14 +120,16 @@ export const MessageMetadata = ({
|
||||||
const className = classNames(
|
const className = classNames(
|
||||||
'module-message__metadata',
|
'module-message__metadata',
|
||||||
isInline && 'module-message__metadata--inline',
|
isInline && 'module-message__metadata--inline',
|
||||||
withImageNoCaption && 'module-message__metadata--with-image-no-caption'
|
withImageNoCaption && 'module-message__metadata--with-image-no-caption',
|
||||||
|
deletedForEveryone && 'module-message__metadata--deleted-for-everyone'
|
||||||
);
|
);
|
||||||
const children = (
|
const children = (
|
||||||
<>
|
<>
|
||||||
{timestampNode}
|
{timestampNode}
|
||||||
{expirationLength && expirationTimestamp ? (
|
{expirationLength && (expirationTimestamp || direction === 'outgoing') ? (
|
||||||
<ExpireTimer
|
<ExpireTimer
|
||||||
direction={metadataDirection}
|
direction={metadataDirection}
|
||||||
|
deletedForEveryone={deletedForEveryone}
|
||||||
expirationLength={expirationLength}
|
expirationLength={expirationLength}
|
||||||
expirationTimestamp={expirationTimestamp}
|
expirationTimestamp={expirationTimestamp}
|
||||||
withImageNoCaption={withImageNoCaption}
|
withImageNoCaption={withImageNoCaption}
|
||||||
|
@ -152,6 +157,9 @@ export const MessageMetadata = ({
|
||||||
withImageNoCaption
|
withImageNoCaption
|
||||||
? 'module-message__metadata__status-icon--with-image-no-caption'
|
? 'module-message__metadata__status-icon--with-image-no-caption'
|
||||||
: null,
|
: null,
|
||||||
|
deletedForEveryone
|
||||||
|
? 'module-message__metadata__status-icon--deleted-for-everyone'
|
||||||
|
: null,
|
||||||
isTapToViewExpired
|
isTapToViewExpired
|
||||||
? 'module-message__metadata__status-icon--with-tap-to-view-expired'
|
? 'module-message__metadata__status-icon--with-tap-to-view-expired'
|
||||||
: null
|
: null
|
||||||
|
|
|
@ -12,16 +12,18 @@ import { Time } from '../Time';
|
||||||
import { useNowThatUpdatesEveryMinute } from '../../hooks/useNowThatUpdatesEveryMinute';
|
import { useNowThatUpdatesEveryMinute } from '../../hooks/useNowThatUpdatesEveryMinute';
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
timestamp: number;
|
deletedForEveryone?: boolean;
|
||||||
|
direction?: 'incoming' | 'outgoing';
|
||||||
|
i18n: LocalizerType;
|
||||||
module?: string;
|
module?: string;
|
||||||
|
timestamp: number;
|
||||||
withImageNoCaption?: boolean;
|
withImageNoCaption?: boolean;
|
||||||
withSticker?: boolean;
|
withSticker?: boolean;
|
||||||
withTapToViewExpired?: boolean;
|
withTapToViewExpired?: boolean;
|
||||||
direction?: 'incoming' | 'outgoing';
|
|
||||||
i18n: LocalizerType;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function MessageTimestamp({
|
export function MessageTimestamp({
|
||||||
|
deletedForEveryone,
|
||||||
direction,
|
direction,
|
||||||
i18n,
|
i18n,
|
||||||
module,
|
module,
|
||||||
|
@ -42,7 +44,8 @@ export function MessageTimestamp({
|
||||||
? `${moduleName}--${direction}-with-tap-to-view-expired`
|
? `${moduleName}--${direction}-with-tap-to-view-expired`
|
||||||
: null,
|
: null,
|
||||||
withImageNoCaption ? `${moduleName}--with-image-no-caption` : null,
|
withImageNoCaption ? `${moduleName}--with-image-no-caption` : null,
|
||||||
withSticker ? `${moduleName}--with-sticker` : null
|
withSticker ? `${moduleName}--with-sticker` : null,
|
||||||
|
deletedForEveryone ? `${moduleName}--deleted-for-everyone` : null
|
||||||
)}
|
)}
|
||||||
timestamp={timestamp}
|
timestamp={timestamp}
|
||||||
>
|
>
|
||||||
|
|
|
@ -3669,16 +3669,22 @@ export class ConversationModel extends window.Backbone
|
||||||
sticker?: WhatIsThis
|
sticker?: WhatIsThis
|
||||||
): Promise<WhatIsThis> {
|
): Promise<WhatIsThis> {
|
||||||
if (attachments && attachments.length) {
|
if (attachments && attachments.length) {
|
||||||
const validAttachments = filter(
|
const attachmentsToUse = Array.from(take(attachments, 1));
|
||||||
attachments,
|
|
||||||
attachment => attachment && !attachment.pending && !attachment.error
|
|
||||||
);
|
|
||||||
const attachmentsToUse = Array.from(take(validAttachments, 1));
|
|
||||||
const isGIFQuote = isGIF(attachmentsToUse);
|
const isGIFQuote = isGIF(attachmentsToUse);
|
||||||
|
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
map(attachmentsToUse, async attachment => {
|
map(attachmentsToUse, async attachment => {
|
||||||
const { fileName, thumbnail, contentType } = attachment;
|
const { path, fileName, thumbnail, contentType } = attachment;
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
|
return {
|
||||||
|
contentType: isGIFQuote ? IMAGE_GIF : contentType,
|
||||||
|
// Our protos library complains about this field being undefined, so we
|
||||||
|
// force it to null
|
||||||
|
fileName: fileName || null,
|
||||||
|
thumbnail: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
contentType: isGIFQuote ? IMAGE_GIF : contentType,
|
contentType: isGIFQuote ? IMAGE_GIF : contentType,
|
||||||
|
@ -3697,12 +3703,22 @@ export class ConversationModel extends window.Backbone
|
||||||
}
|
}
|
||||||
|
|
||||||
if (preview && preview.length) {
|
if (preview && preview.length) {
|
||||||
const validPreviews = filter(preview, item => item && item.image);
|
const previewsToUse = take(preview, 1);
|
||||||
const previewsToUse = take(validPreviews, 1);
|
|
||||||
|
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
map(previewsToUse, async attachment => {
|
map(previewsToUse, async attachment => {
|
||||||
const { image } = attachment;
|
const { image } = attachment;
|
||||||
|
|
||||||
|
if (!image) {
|
||||||
|
return {
|
||||||
|
contentType: IMAGE_JPEG,
|
||||||
|
// Our protos library complains about these fields being undefined, so we
|
||||||
|
// force them to null
|
||||||
|
fileName: null,
|
||||||
|
thumbnail: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const { contentType } = image;
|
const { contentType } = image;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -4428,7 +4444,7 @@ export class ConversationModel extends window.Backbone
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isGroupV1AndDisabled()) {
|
if (!isSetByOther && this.isGroupV1AndDisabled()) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'updateExpirationTimer: GroupV1 is deprecated; cannot update expiration timer'
|
'updateExpirationTimer: GroupV1 is deprecated; cannot update expiration timer'
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,7 +11,14 @@ export function getIncrement(length: number): number {
|
||||||
return Math.ceil(length / 12);
|
return Math.ceil(length / 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTimerBucket(expiration: number, length: number): string {
|
export function getTimerBucket(
|
||||||
|
expiration: number | undefined,
|
||||||
|
length: number
|
||||||
|
): string {
|
||||||
|
if (!expiration) {
|
||||||
|
return '60';
|
||||||
|
}
|
||||||
|
|
||||||
const delta = expiration - Date.now();
|
const delta = expiration - Date.now();
|
||||||
if (delta < 0) {
|
if (delta < 0) {
|
||||||
return '00';
|
return '00';
|
||||||
|
|
Loading…
Reference in New Issue