Send edited messages support

Co-authored-by: Fedor Indutnyy <indutny@signal.org>
This commit is contained in:
Josh Perez
2023-04-20 12:31:59 -04:00
committed by GitHub
parent d380817a44
commit 1f2cde6d04
79 changed files with 2507 additions and 1175 deletions

View File

@@ -27,7 +27,8 @@ import { ThemeType } from './Util';
import * as GoogleChrome from '../util/GoogleChrome';
import { ReadStatus } from '../messages/MessageReadStatus';
import type { MessageStatusType } from '../components/conversation/Message';
import { softAssert } from '../util/assert';
import { strictAssert } from '../util/assert';
import type { SignalService as Proto } from '../protobuf';
const MAX_WIDTH = 300;
const MAX_HEIGHT = MAX_WIDTH * 1.5;
@@ -84,6 +85,16 @@ export type AttachmentType = {
key?: string;
};
export type UploadedAttachmentType = Proto.IAttachmentPointer &
Readonly<{
// Required fields
cdnId: Long;
key: Uint8Array;
size: number;
digest: Uint8Array;
contentType: string;
}>;
export type AttachmentWithHydratedData = AttachmentType & {
data: Uint8Array;
};
@@ -1006,6 +1017,6 @@ export const canBeDownloaded = (
};
export function getAttachmentSignature(attachment: AttachmentType): string {
softAssert(attachment.digest, 'attachment missing digest');
return attachment.digest || String(attachment.blurHash);
strictAssert(attachment.digest, 'attachment missing digest');
return attachment.digest;
}

View File

@@ -11,17 +11,22 @@ import {
format as formatPhoneNumber,
parse as parsePhoneNumber,
} from './PhoneNumber';
import type { AttachmentType, migrateDataToFileSystem } from './Attachment';
import type {
AttachmentType,
AttachmentWithHydratedData,
UploadedAttachmentType,
migrateDataToFileSystem,
} from './Attachment';
import { toLogFormat } from './errors';
import type { LoggerType } from './Logging';
import type { UUIDStringType } from './UUID';
export type EmbeddedContactType = {
type GenericEmbeddedContactType<AvatarType> = {
name?: Name;
number?: Array<Phone>;
email?: Array<Email>;
address?: Array<PostalAddress>;
avatar?: Avatar;
avatar?: AvatarType;
organization?: string;
// Populated by selector
@@ -29,6 +34,12 @@ export type EmbeddedContactType = {
uuid?: UUIDStringType;
};
export type EmbeddedContactType = GenericEmbeddedContactType<Avatar>;
export type EmbeddedContactWithHydratedAvatar =
GenericEmbeddedContactType<AvatarWithHydratedData>;
export type EmbeddedContactWithUploadedAvatar =
GenericEmbeddedContactType<UploadedAvatar>;
type Name = {
givenName?: string;
familyName?: string;
@@ -75,11 +86,15 @@ export type PostalAddress = {
country?: string;
};
export type Avatar = {
avatar: AttachmentType;
type GenericAvatar<Attachment> = {
avatar: Attachment;
isProfile: boolean;
};
export type Avatar = GenericAvatar<AttachmentType>;
export type AvatarWithHydratedData = GenericAvatar<AttachmentWithHydratedData>;
export type UploadedAvatar = GenericAvatar<UploadedAttachmentType>;
const DEFAULT_PHONE_TYPE = Proto.DataMessage.Contact.Phone.Type.HOME;
const DEFAULT_EMAIL_TYPE = Proto.DataMessage.Contact.Email.Type.HOME;
const DEFAULT_ADDRESS_TYPE = Proto.DataMessage.Contact.PostalAddress.Type.HOME;

View File

@@ -0,0 +1,13 @@
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { ToastType } from './Toast';
export class ErrorWithToast extends Error {
public toastType: ToastType;
constructor(message: string, toastType: ToastType) {
super(message);
this.toastType = toastType;
}
}

View File

@@ -8,11 +8,9 @@ import LinkifyIt from 'linkify-it';
import { maybeParseUrl } from '../util/url';
import { replaceEmojiWithSpaces } from '../util/emoji';
import type { AttachmentType } from './Attachment';
import type { AttachmentWithHydratedData } from './Attachment';
export type LinkPreviewImage = AttachmentType & {
data: Uint8Array;
};
export type LinkPreviewImage = AttachmentWithHydratedData;
export type LinkPreviewResult = {
title: string | null;

View File

@@ -20,13 +20,19 @@ import { initializeAttachmentMetadata } from './message/initializeAttachmentMeta
import type * as MIME from './MIME';
import type { LoggerType } from './Logging';
import type { EmbeddedContactType } from './EmbeddedContact';
import type {
EmbeddedContactType,
EmbeddedContactWithHydratedAvatar,
} from './EmbeddedContact';
import type {
MessageAttributesType,
QuotedMessageType,
} from '../model-types.d';
import type { LinkPreviewType } from './message/LinkPreviews';
import type {
LinkPreviewType,
LinkPreviewWithHydratedData,
} from './message/LinkPreviews';
import type { StickerType, StickerWithHydratedData } from './Stickers';
export { hasExpiration } from './Message';
@@ -714,28 +720,33 @@ export const loadContactData = (
loadAttachmentData: LoadAttachmentType
): ((
contact: Array<EmbeddedContactType> | undefined
) => Promise<Array<EmbeddedContactType> | undefined>) => {
) => Promise<Array<EmbeddedContactWithHydratedAvatar> | undefined>) => {
if (!isFunction(loadAttachmentData)) {
throw new TypeError('loadContactData: loadAttachmentData is required');
}
return async (
contact: Array<EmbeddedContactType> | undefined
): Promise<Array<EmbeddedContactType> | undefined> => {
): Promise<Array<EmbeddedContactWithHydratedAvatar> | undefined> => {
if (!contact) {
return undefined;
}
return Promise.all(
contact.map(
async (item: EmbeddedContactType): Promise<EmbeddedContactType> => {
async (
item: EmbeddedContactType
): Promise<EmbeddedContactWithHydratedAvatar> => {
if (
!item ||
!item.avatar ||
!item.avatar.avatar ||
!item.avatar.avatar.path
) {
return item;
return {
...item,
avatar: undefined,
};
}
return {
@@ -758,7 +769,7 @@ export const loadPreviewData = (
loadAttachmentData: LoadAttachmentType
): ((
preview: Array<LinkPreviewType> | undefined
) => Promise<Array<LinkPreviewType>>) => {
) => Promise<Array<LinkPreviewWithHydratedData>>) => {
if (!isFunction(loadAttachmentData)) {
throw new TypeError('loadPreviewData: loadAttachmentData is required');
}
@@ -769,16 +780,22 @@ export const loadPreviewData = (
}
return Promise.all(
preview.map(async item => {
if (!item.image) {
return item;
}
preview.map(
async (item: LinkPreviewType): Promise<LinkPreviewWithHydratedData> => {
if (!item.image) {
return {
...item,
// Pacify typescript
image: undefined,
};
}
return {
...item,
image: await loadAttachmentData(item.image),
};
})
return {
...item,
image: await loadAttachmentData(item.image),
};
}
)
);
};
};

View File

@@ -7,6 +7,7 @@ export enum ToastType {
AlreadyRequestedToJoin = 'AlreadyRequestedToJoin',
Blocked = 'Blocked',
BlockedGroup = 'BlockedGroup',
CannotEditMessage = 'CannotEditMessage',
CannotForwardEmptyMessage = 'CannotForwardEmptyMessage',
CannotMixMultiAndNonMultiAttachments = 'CannotMixMultiAndNonMultiAttachments',
CannotOpenGiftBadgeIncoming = 'CannotOpenGiftBadgeIncoming',
@@ -54,6 +55,7 @@ export type AnyToast =
| { toastType: ToastType.AlreadyRequestedToJoin }
| { toastType: ToastType.Blocked }
| { toastType: ToastType.BlockedGroup }
| { toastType: ToastType.CannotEditMessage }
| { toastType: ToastType.CannotForwardEmptyMessage }
| { toastType: ToastType.CannotMixMultiAndNonMultiAttachments }
| { toastType: ToastType.CannotOpenGiftBadgeIncoming }

View File

@@ -1,14 +1,18 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { AttachmentType } from '../Attachment';
import type { AttachmentType, AttachmentWithHydratedData } from '../Attachment';
export type LinkPreviewType = {
type GenericLinkPreviewType<Image> = {
title?: string;
description?: string;
domain?: string;
url: string;
isStickerPack?: boolean;
image?: Readonly<AttachmentType>;
image?: Readonly<Image>;
date?: number;
};
export type LinkPreviewType = GenericLinkPreviewType<AttachmentType>;
export type LinkPreviewWithHydratedData =
GenericLinkPreviewType<AttachmentWithHydratedData>;