Import/export additional message flags
Co-authored-by: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com>
This commit is contained in:
parent
eb619350b3
commit
5b3509e34c
14 changed files with 85 additions and 2 deletions
10
images/icons/v2/lock-unlock-outline-12.svg
Normal file
10
images/icons/v2/lock-unlock-outline-12.svg
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<g clip-path="url(#clip0_1619_1707)">
|
||||||
|
<path d="M9 0C7.34 0 6 1.34 6 3V4.5H2C0.9 4.5 0 5.4 0 6.5V10C0 11.1 0.9 12 2 12H7C8.1 12 9 11.1 9 10V6.5C9 5.4 8.1 4.5 7 4.5V3C7 1.9 7.9 1 9 1C10.1 1 11 1.9 11 3V5H12V3C12 1.34 10.66 0 9 0ZM8 6.5V10C8 10.55 7.55 11 7 11H2C1.45 11 1 10.55 1 10V6.5C1 5.95 1.45 5.5 2 5.5H7C7.55 5.5 8 5.95 8 6.5ZM5 8.35V10H4V8.35C3.71 8.18 3.5 7.87 3.5 7.5C3.5 6.95 3.95 6.5 4.5 6.5C5.05 6.5 5.5 6.95 5.5 7.5C5.5 7.87 5.29 8.17 5 8.35Z" fill="black" fill-opacity="0.72"/>
|
||||||
|
</g>
|
||||||
|
<defs>
|
||||||
|
<clipPath id="clip0_1619_1707">
|
||||||
|
<rect width="12" height="12" fill="white"/>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 702 B |
|
@ -1205,6 +1205,29 @@ $message-padding-horizontal: 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.module-message__metadata__sms {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
display: inline-block;
|
||||||
|
margin-inline-start: 6px;
|
||||||
|
// High margin to leave space for the increase when we go to two checks
|
||||||
|
margin-bottom: 2px;
|
||||||
|
|
||||||
|
@include color-svg(
|
||||||
|
'../images/icons/v2/lock-unlock-outline-12.svg',
|
||||||
|
$color-white
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.module-message__metadata__sms--incoming {
|
||||||
|
@include light-theme {
|
||||||
|
background-color: $color-gray-60;
|
||||||
|
}
|
||||||
|
@include dark-theme {
|
||||||
|
background-color: $color-gray-25;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.module-message__container--outgoing .module-message__metadata__edited {
|
.module-message__container--outgoing .module-message__metadata__edited {
|
||||||
color: $color-white-alpha-80;
|
color: $color-white-alpha-80;
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ const MESSAGE_DEFAULT_PROPS = {
|
||||||
isMessageRequestAccepted: true,
|
isMessageRequestAccepted: true,
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
isSelectMode: false,
|
isSelectMode: false,
|
||||||
|
isSMS: false,
|
||||||
onToggleSelect: shouldNeverBeCalled,
|
onToggleSelect: shouldNeverBeCalled,
|
||||||
onReplyToMessage: shouldNeverBeCalled,
|
onReplyToMessage: shouldNeverBeCalled,
|
||||||
kickOffAttachmentDownload: shouldNeverBeCalled,
|
kickOffAttachmentDownload: shouldNeverBeCalled,
|
||||||
|
|
|
@ -99,6 +99,7 @@ import { UserText } from '../UserText';
|
||||||
|
|
||||||
const GUESS_METADATA_WIDTH_TIMESTAMP_SIZE = 16;
|
const GUESS_METADATA_WIDTH_TIMESTAMP_SIZE = 16;
|
||||||
const GUESS_METADATA_WIDTH_EXPIRE_TIMER_SIZE = 18;
|
const GUESS_METADATA_WIDTH_EXPIRE_TIMER_SIZE = 18;
|
||||||
|
const GUESS_METADATA_WIDTH_SMS_SIZE = 18;
|
||||||
const GUESS_METADATA_WIDTH_EDITED_SIZE = 40;
|
const GUESS_METADATA_WIDTH_EDITED_SIZE = 40;
|
||||||
const GUESS_METADATA_WIDTH_OUTGOING_SIZE: Record<MessageStatusType, number> = {
|
const GUESS_METADATA_WIDTH_OUTGOING_SIZE: Record<MessageStatusType, number> = {
|
||||||
delivered: 24,
|
delivered: 24,
|
||||||
|
@ -218,6 +219,7 @@ export type PropsData = {
|
||||||
isTargetedCounter?: number;
|
isTargetedCounter?: number;
|
||||||
isSelected: boolean;
|
isSelected: boolean;
|
||||||
isSelectMode: boolean;
|
isSelectMode: boolean;
|
||||||
|
isSMS: boolean;
|
||||||
isSpoilerExpanded?: Record<number, boolean>;
|
isSpoilerExpanded?: Record<number, boolean>;
|
||||||
direction: DirectionType;
|
direction: DirectionType;
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
|
@ -628,7 +630,8 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
* because it can reduce layout jumpiness.
|
* because it can reduce layout jumpiness.
|
||||||
*/
|
*/
|
||||||
private guessMetadataWidth(): number {
|
private guessMetadataWidth(): number {
|
||||||
const { direction, expirationLength, status, isEditedMessage } = this.props;
|
const { direction, expirationLength, isSMS, status, isEditedMessage } =
|
||||||
|
this.props;
|
||||||
|
|
||||||
let result = GUESS_METADATA_WIDTH_TIMESTAMP_SIZE;
|
let result = GUESS_METADATA_WIDTH_TIMESTAMP_SIZE;
|
||||||
|
|
||||||
|
@ -641,6 +644,10 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
result += GUESS_METADATA_WIDTH_EXPIRE_TIMER_SIZE;
|
result += GUESS_METADATA_WIDTH_EXPIRE_TIMER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isSMS) {
|
||||||
|
result += GUESS_METADATA_WIDTH_SMS_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
if (direction === 'outgoing' && status) {
|
if (direction === 'outgoing' && status) {
|
||||||
result += GUESS_METADATA_WIDTH_OUTGOING_SIZE[status];
|
result += GUESS_METADATA_WIDTH_OUTGOING_SIZE[status];
|
||||||
}
|
}
|
||||||
|
@ -811,6 +818,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
i18n,
|
i18n,
|
||||||
id,
|
id,
|
||||||
isEditedMessage,
|
isEditedMessage,
|
||||||
|
isSMS,
|
||||||
isSticker,
|
isSticker,
|
||||||
isTapToViewExpired,
|
isTapToViewExpired,
|
||||||
retryMessageSend,
|
retryMessageSend,
|
||||||
|
@ -834,6 +842,7 @@ export class Message extends React.PureComponent<Props, State> {
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
id={id}
|
id={id}
|
||||||
isEditedMessage={isEditedMessage}
|
isEditedMessage={isEditedMessage}
|
||||||
|
isSMS={isSMS}
|
||||||
isInline={isInline}
|
isInline={isInline}
|
||||||
isOutlineOnlyBubble={
|
isOutlineOnlyBubble={
|
||||||
deletedForEveryone || (attachmentDroppedDueToSize && !text)
|
deletedForEveryone || (attachmentDroppedDueToSize && !text)
|
||||||
|
|
|
@ -36,6 +36,7 @@ const defaultMessage: MessageDataPropsType = {
|
||||||
isMessageRequestAccepted: true,
|
isMessageRequestAccepted: true,
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
isSelectMode: false,
|
isSelectMode: false,
|
||||||
|
isSMS: false,
|
||||||
isSpoilerExpanded: {},
|
isSpoilerExpanded: {},
|
||||||
previews: [],
|
previews: [],
|
||||||
readStatus: ReadStatus.Read,
|
readStatus: ReadStatus.Read,
|
||||||
|
|
|
@ -27,6 +27,7 @@ type PropsType = {
|
||||||
i18n: LocalizerType;
|
i18n: LocalizerType;
|
||||||
id: string;
|
id: string;
|
||||||
isEditedMessage?: boolean;
|
isEditedMessage?: boolean;
|
||||||
|
isSMS?: boolean;
|
||||||
isInline?: boolean;
|
isInline?: boolean;
|
||||||
isOutlineOnlyBubble?: boolean;
|
isOutlineOnlyBubble?: boolean;
|
||||||
isShowingImage: boolean;
|
isShowingImage: boolean;
|
||||||
|
@ -56,6 +57,7 @@ export const MessageMetadata = forwardRef<HTMLDivElement, Readonly<PropsType>>(
|
||||||
i18n,
|
i18n,
|
||||||
id,
|
id,
|
||||||
isEditedMessage,
|
isEditedMessage,
|
||||||
|
isSMS,
|
||||||
isOutlineOnlyBubble,
|
isOutlineOnlyBubble,
|
||||||
isInline,
|
isInline,
|
||||||
isShowingImage,
|
isShowingImage,
|
||||||
|
@ -211,6 +213,11 @@ export const MessageMetadata = forwardRef<HTMLDivElement, Readonly<PropsType>>(
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{timestampNode}
|
{timestampNode}
|
||||||
|
{isSMS ? (
|
||||||
|
<div
|
||||||
|
className={`module-message__metadata__sms module-message__metadata__sms--${direction}`}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
{expirationLength ? (
|
{expirationLength ? (
|
||||||
<ExpireTimer
|
<ExpireTimer
|
||||||
direction={metadataDirection}
|
direction={metadataDirection}
|
||||||
|
|
|
@ -105,6 +105,7 @@ const defaultMessageProps: TimelineMessagesProps = {
|
||||||
isMessageRequestAccepted: true,
|
isMessageRequestAccepted: true,
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
isSelectMode: false,
|
isSelectMode: false,
|
||||||
|
isSMS: false,
|
||||||
isSpoilerExpanded: {},
|
isSpoilerExpanded: {},
|
||||||
toggleSelectMessage: action('toggleSelectMessage'),
|
toggleSelectMessage: action('toggleSelectMessage'),
|
||||||
kickOffAttachmentDownload: action('default--kickOffAttachmentDownload'),
|
kickOffAttachmentDownload: action('default--kickOffAttachmentDownload'),
|
||||||
|
|
|
@ -67,6 +67,7 @@ function mockMessageTimelineItem(
|
||||||
isMessageRequestAccepted: true,
|
isMessageRequestAccepted: true,
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
isSelectMode: false,
|
isSelectMode: false,
|
||||||
|
isSMS: false,
|
||||||
isSpoilerExpanded: {},
|
isSpoilerExpanded: {},
|
||||||
previews: [],
|
previews: [],
|
||||||
readStatus: ReadStatus.Read,
|
readStatus: ReadStatus.Read,
|
||||||
|
|
|
@ -295,6 +295,7 @@ const createProps = (overrideProps: Partial<Props> = {}): Props => ({
|
||||||
isSelectMode: isBoolean(overrideProps.isSelectMode)
|
isSelectMode: isBoolean(overrideProps.isSelectMode)
|
||||||
? overrideProps.isSelectMode
|
? overrideProps.isSelectMode
|
||||||
: false,
|
: false,
|
||||||
|
isSMS: isBoolean(overrideProps.isSMS) ? overrideProps.isSMS : false,
|
||||||
isSpoilerExpanded: overrideProps.isSpoilerExpanded || {},
|
isSpoilerExpanded: overrideProps.isSpoilerExpanded || {},
|
||||||
isTapToView: overrideProps.isTapToView,
|
isTapToView: overrideProps.isTapToView,
|
||||||
isTapToViewError: overrideProps.isTapToViewError,
|
isTapToViewError: overrideProps.isTapToViewError,
|
||||||
|
@ -2060,6 +2061,12 @@ PaymentNotification.args = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const SMS = Template.bind({});
|
||||||
|
SMS.args = {
|
||||||
|
isSMS: true,
|
||||||
|
text: 'hello',
|
||||||
|
};
|
||||||
|
|
||||||
function MultiSelectMessage() {
|
function MultiSelectMessage() {
|
||||||
const [selected, setSelected] = React.useState(false);
|
const [selected, setSelected] = React.useState(false);
|
||||||
|
|
||||||
|
|
1
ts/model-types.d.ts
vendored
1
ts/model-types.d.ts
vendored
|
@ -198,6 +198,7 @@ export type MessageAttributesType = {
|
||||||
quote?: QuotedMessageType;
|
quote?: QuotedMessageType;
|
||||||
reactions?: ReadonlyArray<MessageReactionType>;
|
reactions?: ReadonlyArray<MessageReactionType>;
|
||||||
requiredProtocolVersion?: number;
|
requiredProtocolVersion?: number;
|
||||||
|
sms?: boolean;
|
||||||
sourceDevice?: number;
|
sourceDevice?: number;
|
||||||
storyDistributionListId?: StoryDistributionIdString;
|
storyDistributionListId?: StoryDistributionIdString;
|
||||||
storyId?: string;
|
storyId?: string;
|
||||||
|
|
|
@ -747,7 +747,7 @@ export class BackupExportStream extends Readable {
|
||||||
expireStartDate,
|
expireStartDate,
|
||||||
expiresInMs,
|
expiresInMs,
|
||||||
revisions: [],
|
revisions: [],
|
||||||
sms: false,
|
sms: message.sms === true,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isNormalBubble(message)) {
|
if (!isNormalBubble(message)) {
|
||||||
|
|
|
@ -881,6 +881,7 @@ export class BackupImportStream extends Writable {
|
||||||
item.expiresInMs && !item.expiresInMs.isZero()
|
item.expiresInMs && !item.expiresInMs.isZero()
|
||||||
? DurationInSeconds.fromMillis(item.expiresInMs.toNumber())
|
? DurationInSeconds.fromMillis(item.expiresInMs.toNumber())
|
||||||
: undefined,
|
: undefined,
|
||||||
|
sms: item.sms === true ? true : undefined,
|
||||||
...directionDetails,
|
...directionDetails,
|
||||||
};
|
};
|
||||||
const additionalMessages: Array<MessageAttributesType> = [];
|
const additionalMessages: Array<MessageAttributesType> = [];
|
||||||
|
|
|
@ -761,6 +761,7 @@ export const getPropsForMessage = (
|
||||||
isMessageRequestAccepted: conversation?.acceptedMessageRequest ?? true,
|
isMessageRequestAccepted: conversation?.acceptedMessageRequest ?? true,
|
||||||
isSelected,
|
isSelected,
|
||||||
isSelectMode,
|
isSelectMode,
|
||||||
|
isSMS: message.sms === true,
|
||||||
isSpoilerExpanded: message.isSpoilerExpanded,
|
isSpoilerExpanded: message.isSpoilerExpanded,
|
||||||
isSticker: Boolean(sticker),
|
isSticker: Boolean(sticker),
|
||||||
isTargeted,
|
isTargeted,
|
||||||
|
|
|
@ -363,4 +363,24 @@ describe('backup/bubble messages', () => {
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('roundtrips sms messages', async () => {
|
||||||
|
await symmetricRoundtripHarness([
|
||||||
|
{
|
||||||
|
conversationId: contactA.id,
|
||||||
|
id: generateGuid(),
|
||||||
|
type: 'incoming',
|
||||||
|
received_at: 3,
|
||||||
|
received_at_ms: 3,
|
||||||
|
sent_at: 3,
|
||||||
|
timestamp: 3,
|
||||||
|
sourceServiceId: CONTACT_A,
|
||||||
|
body: 'd',
|
||||||
|
readStatus: ReadStatus.Unread,
|
||||||
|
seenStatus: SeenStatus.Unseen,
|
||||||
|
unidentifiedDeliveryReceived: true,
|
||||||
|
sms: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue