Use ReadonlyArrays in conversation model and redux

This commit is contained in:
Fedor Indutny 2022-12-21 16:07:02 -08:00 committed by GitHub
parent ecbf84638d
commit dec23725e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
55 changed files with 173 additions and 162 deletions

View file

@ -1105,7 +1105,7 @@ export class SignalProtocolStore extends EventEmitter {
async getOpenDevices( async getOpenDevices(
ourUuid: UUID, ourUuid: UUID,
identifiers: Array<string>, identifiers: ReadonlyArray<string>,
{ zone = GLOBAL_ZONE }: SessionTransactionOptions = {} { zone = GLOBAL_ZONE }: SessionTransactionOptions = {}
): Promise<{ ): Promise<{
devices: Array<DeviceType>; devices: Array<DeviceType>;

View file

@ -49,7 +49,7 @@ export type Props = {
noteToSelf?: boolean; noteToSelf?: boolean;
phoneNumber?: string; phoneNumber?: string;
profileName?: string; profileName?: string;
sharedGroupNames: Array<string>; sharedGroupNames: ReadonlyArray<string>;
size: AvatarSize; size: AvatarSize;
title: string; title: string;
unblurredAvatarPath?: string; unblurredAvatarPath?: string;

View file

@ -79,7 +79,7 @@ export type Props = Readonly<{
moduleClassName?: string; moduleClassName?: string;
theme: ThemeType; theme: ThemeType;
placeholder?: string; placeholder?: string;
sortedGroupMembers?: Array<ConversationType>; sortedGroupMembers?: ReadonlyArray<ConversationType>;
scrollerRef?: React.RefObject<HTMLDivElement>; scrollerRef?: React.RefObject<HTMLDivElement>;
onDirtyChange?(dirty: boolean): unknown; onDirtyChange?(dirty: boolean): unknown;
onEditorStateChange?( onEditorStateChange?(
@ -488,7 +488,9 @@ export function CompositionInput(props: Props): React.ReactElement {
[] []
); );
const removeStaleMentions = (currentMembers: Array<ConversationType>) => { const removeStaleMentions = (
currentMembers: ReadonlyArray<ConversationType>
) => {
const quill = quillRef.current; const quill = quillRef.current;
if (quill === undefined) { if (quill === undefined) {

View file

@ -20,12 +20,12 @@ import { offsetDistanceModifier } from '../util/popperUtil';
import { handleOutsideClick } from '../util/handleOutsideClick'; import { handleOutsideClick } from '../util/handleOutsideClick';
type PropsType = { type PropsType = {
draftPreferredReactions: Array<string>; draftPreferredReactions: ReadonlyArray<string>;
hadSaveError: boolean; hadSaveError: boolean;
i18n: LocalizerType; i18n: LocalizerType;
isSaving: boolean; isSaving: boolean;
originalPreferredReactions: Array<string>; originalPreferredReactions: ReadonlyArray<string>;
recentEmojis: Array<string>; recentEmojis: ReadonlyArray<string>;
selectedDraftEmojiIndex: undefined | number; selectedDraftEmojiIndex: undefined | number;
skinTone: number; skinTone: number;

View file

@ -40,12 +40,12 @@ import {
} from '../util/shouldNeverBeCalled'; } from '../util/shouldNeverBeCalled';
export type DataPropsType = { export type DataPropsType = {
attachments?: Array<AttachmentType>; attachments?: ReadonlyArray<AttachmentType>;
candidateConversations: ReadonlyArray<ConversationType>; candidateConversations: ReadonlyArray<ConversationType>;
doForwardMessage: ( doForwardMessage: (
selectedContacts: Array<string>, selectedContacts: Array<string>,
messageBody?: string, messageBody?: string,
attachments?: Array<AttachmentType>, attachments?: ReadonlyArray<AttachmentType>,
linkPreview?: LinkPreviewType linkPreview?: LinkPreviewType
) => void; ) => void;
getPreferredBadge: PreferredBadgeSelectorType; getPreferredBadge: PreferredBadgeSelectorType;
@ -102,7 +102,7 @@ export function ForwardMessageModal({
filterAndSortConversationsByRecent(candidateConversations, '', regionCode) filterAndSortConversationsByRecent(candidateConversations, '', regionCode)
); );
const [attachmentsToForward, setAttachmentsToForward] = useState< const [attachmentsToForward, setAttachmentsToForward] = useState<
Array<AttachmentType> ReadonlyArray<AttachmentType>
>(attachments || []); >(attachments || []);
const [isEditingMessage, setIsEditingMessage] = useState(false); const [isEditingMessage, setIsEditingMessage] = useState(false);
const [messageBodyText, setMessageBodyText] = useState(messageBody || ''); const [messageBodyText, setMessageBodyText] = useState(messageBody || '');

View file

@ -29,7 +29,7 @@ export type PropsType = {
getConversation?: (id: string) => ConversationType; getConversation?: (id: string) => ConversationType;
i18n: LocalizerType; i18n: LocalizerType;
isViewOnce?: boolean; isViewOnce?: boolean;
media: Array<MediaItemType>; media: ReadonlyArray<MediaItemType>;
saveAttachment: SaveAttachmentActionCreatorType; saveAttachment: SaveAttachmentActionCreatorType;
selectedIndex?: number; selectedIndex?: number;
toggleForwardMessageModal: (messageId: string) => unknown; toggleForwardMessageModal: (messageId: string) => unknown;

View file

@ -69,7 +69,7 @@ export type PropsDataType = {
firstName: string; firstName: string;
i18n: LocalizerType; i18n: LocalizerType;
isUsernameFlagEnabled: boolean; isUsernameFlagEnabled: boolean;
userAvatarData: Array<AvatarDataType>; userAvatarData: ReadonlyArray<AvatarDataType>;
username?: string; username?: string;
usernameEditState: UsernameEditState; usernameEditState: UsernameEditState;
} & Pick<EmojiButtonProps, 'recentEmojis' | 'skinTone'>; } & Pick<EmojiButtonProps, 'recentEmojis' | 'skinTone'>;

View file

@ -11,7 +11,7 @@ import type { LocalizerType } from '../types/Util';
type PropsType = { type PropsType = {
i18n: LocalizerType; i18n: LocalizerType;
nameClassName?: string; nameClassName?: string;
sharedGroupNames: Array<string>; sharedGroupNames: ReadonlyArray<string>;
}; };
export function SharedGroupNames({ export function SharedGroupNames({

View file

@ -96,9 +96,9 @@ export type PropsType = {
story: StoryViewType story: StoryViewType
) => unknown; ) => unknown;
onUseEmoji: (_: EmojiPickDataType) => unknown; onUseEmoji: (_: EmojiPickDataType) => unknown;
preferredReactionEmoji: Array<string>; preferredReactionEmoji: ReadonlyArray<string>;
queueStoryDownload: (storyId: string) => unknown; queueStoryDownload: (storyId: string) => unknown;
recentEmojis?: Array<string>; recentEmojis?: ReadonlyArray<string>;
renderEmojiPicker: (props: RenderEmojiPickerProps) => JSX.Element; renderEmojiPicker: (props: RenderEmojiPickerProps) => JSX.Element;
replyState?: ReplyStateType; replyState?: ReplyStateType;
retryMessageSend: (messageId: string) => unknown; retryMessageSend: (messageId: string) => unknown;

View file

@ -98,14 +98,14 @@ export type PropsType = {
onSetSkinTone: (tone: number) => unknown; onSetSkinTone: (tone: number) => unknown;
onTextTooLong: () => unknown; onTextTooLong: () => unknown;
onUseEmoji: (_: EmojiPickDataType) => unknown; onUseEmoji: (_: EmojiPickDataType) => unknown;
preferredReactionEmoji: Array<string>; preferredReactionEmoji: ReadonlyArray<string>;
recentEmojis?: Array<string>; recentEmojis?: ReadonlyArray<string>;
renderEmojiPicker: (props: RenderEmojiPickerProps) => JSX.Element; renderEmojiPicker: (props: RenderEmojiPickerProps) => JSX.Element;
replies: ReadonlyArray<ReplyType>; replies: ReadonlyArray<ReplyType>;
skinTone?: number; skinTone?: number;
sortedGroupMembers?: Array<ConversationType>; sortedGroupMembers?: ReadonlyArray<ConversationType>;
storyPreviewAttachment?: AttachmentType; storyPreviewAttachment?: AttachmentType;
views: Array<StorySendStateType>; views: ReadonlyArray<StorySendStateType>;
viewTarget: StoryViewTargetType; viewTarget: StoryViewTargetType;
onChangeViewTarget: (target: StoryViewTargetType) => unknown; onChangeViewTarget: (target: StoryViewTargetType) => unknown;
deleteGroupStoryReply: (id: string) => void; deleteGroupStoryReply: (id: string) => void;

View file

@ -29,7 +29,7 @@ export type Props = {
membersCount?: number; membersCount?: number;
name?: string; name?: string;
phoneNumber?: string; phoneNumber?: string;
sharedGroupNames?: Array<string>; sharedGroupNames?: ReadonlyArray<string>;
unblurAvatar: (conversationId: string) => void; unblurAvatar: (conversationId: string) => void;
unblurredAvatarPath?: string; unblurredAvatarPath?: string;
updateSharedGroups: (conversationId: string) => unknown; updateSharedGroups: (conversationId: string) => unknown;

View file

@ -43,11 +43,11 @@ const renderChange = (
groupName, groupName,
areWeAdmin = true, areWeAdmin = true,
}: { }: {
groupMemberships?: Array<{ groupMemberships?: ReadonlyArray<{
uuid: UUIDStringType; uuid: UUIDStringType;
isAdmin: boolean; isAdmin: boolean;
}>; }>;
groupBannedMemberships?: Array<UUIDStringType>; groupBannedMemberships?: ReadonlyArray<UUIDStringType>;
groupName?: string; groupName?: string;
areWeAdmin?: boolean; areWeAdmin?: boolean;
} = {} } = {}

View file

@ -25,11 +25,11 @@ import { ConfirmationDialog } from '../ConfirmationDialog';
export type PropsDataType = { export type PropsDataType = {
areWeAdmin: boolean; areWeAdmin: boolean;
conversationId: string; conversationId: string;
groupMemberships?: Array<{ groupMemberships?: ReadonlyArray<{
uuid: UUIDStringType; uuid: UUIDStringType;
isAdmin: boolean; isAdmin: boolean;
}>; }>;
groupBannedMemberships?: Array<UUIDStringType>; groupBannedMemberships?: ReadonlyArray<UUIDStringType>;
groupName?: string; groupName?: string;
ourACI?: UUIDStringType; ourACI?: UUIDStringType;
ourPNI?: UUIDStringType; ourPNI?: UUIDStringType;
@ -155,11 +155,11 @@ function GroupV2Detail({
conversationId: string; conversationId: string;
detail: GroupV2ChangeDetailType; detail: GroupV2ChangeDetailType;
isLastText: boolean; isLastText: boolean;
groupMemberships?: Array<{ groupMemberships?: ReadonlyArray<{
uuid: UUIDStringType; uuid: UUIDStringType;
isAdmin: boolean; isAdmin: boolean;
}>; }>;
groupBannedMemberships?: Array<UUIDStringType>; groupBannedMemberships?: ReadonlyArray<UUIDStringType>;
groupName?: string; groupName?: string;
i18n: LocalizerType; i18n: LocalizerType;
fromId?: UUIDStringType; fromId?: UUIDStringType;

View file

@ -21,7 +21,7 @@ import type { LocalizerType, ThemeType } from '../../types/Util';
export type DirectionType = 'incoming' | 'outgoing'; export type DirectionType = 'incoming' | 'outgoing';
export type Props = { export type Props = {
attachments: Array<AttachmentType>; attachments: ReadonlyArray<AttachmentType>;
bottomOverlay?: boolean; bottomOverlay?: boolean;
direction: DirectionType; direction: DirectionType;
isSticker?: boolean; isSticker?: boolean;

View file

@ -223,7 +223,7 @@ export type PropsData = {
>; >;
reducedMotion?: boolean; reducedMotion?: boolean;
conversationType: ConversationTypeType; conversationType: ConversationTypeType;
attachments?: Array<AttachmentType>; attachments?: ReadonlyArray<AttachmentType>;
giftBadge?: GiftBadgeType; giftBadge?: GiftBadgeType;
payment?: AnyPaymentEvent; payment?: AnyPaymentEvent;
quote?: { quote?: {
@ -255,7 +255,7 @@ export type PropsData = {
storyId?: string; storyId?: string;
text: string; text: string;
}; };
previews: Array<LinkPreviewType>; previews: ReadonlyArray<LinkPreviewType>;
isTapToView?: boolean; isTapToView?: boolean;
isTapToViewExpired?: boolean; isTapToViewExpired?: boolean;

View file

@ -28,7 +28,7 @@ export type OwnProps = {
onPick: (emoji: string) => unknown; onPick: (emoji: string) => unknown;
onSetSkinTone: (tone: number) => unknown; onSetSkinTone: (tone: number) => unknown;
openCustomizePreferredReactionsModal?: () => unknown; openCustomizePreferredReactionsModal?: () => unknown;
preferredReactionEmoji: Array<string>; preferredReactionEmoji: ReadonlyArray<string>;
renderEmojiPicker: (props: RenderEmojiPickerProps) => React.ReactElement; renderEmojiPicker: (props: RenderEmojiPickerProps) => React.ReactElement;
}; };

View file

@ -48,7 +48,7 @@ type StateType = {
maximumGroupSizeModalState: OneTimeModalState; maximumGroupSizeModalState: OneTimeModalState;
recommendedGroupSizeModalState: OneTimeModalState; recommendedGroupSizeModalState: OneTimeModalState;
searchTerm: string; searchTerm: string;
selectedConversationIds: Array<string>; selectedConversationIds: ReadonlyArray<string>;
stage: Stage; stage: Stage;
}; };

View file

@ -74,14 +74,14 @@ export type StateProps = {
i18n: LocalizerType; i18n: LocalizerType;
isAdmin: boolean; isAdmin: boolean;
isGroup: boolean; isGroup: boolean;
groupsInCommon: Array<ConversationType>; groupsInCommon: ReadonlyArray<ConversationType>;
maxGroupSize: number; maxGroupSize: number;
maxRecommendedGroupSize: number; maxRecommendedGroupSize: number;
memberships: Array<GroupV2Membership>; memberships: ReadonlyArray<GroupV2Membership>;
pendingApprovalMemberships: ReadonlyArray<GroupV2RequestingMembership>; pendingApprovalMemberships: ReadonlyArray<GroupV2RequestingMembership>;
pendingMemberships: ReadonlyArray<GroupV2PendingMembership>; pendingMemberships: ReadonlyArray<GroupV2PendingMembership>;
theme: ThemeType; theme: ThemeType;
userAvatarData: Array<AvatarDataType>; userAvatarData: ReadonlyArray<AvatarDataType>;
renderChooseGroupMembersModal: ( renderChooseGroupMembersModal: (
props: SmartChooseGroupMembersModalPropsType props: SmartChooseGroupMembersModalPropsType
) => JSX.Element; ) => JSX.Element;

View file

@ -15,7 +15,7 @@ import { PanelSection } from './PanelSection';
type Props = { type Props = {
contactId: string; contactId: string;
i18n: LocalizerType; i18n: LocalizerType;
groupsInCommon: Array<ConversationType>; groupsInCommon: ReadonlyArray<ConversationType>;
toggleAddUserToAnotherGroupModal: (contactId?: string) => void; toggleAddUserToAnotherGroupModal: (contactId?: string) => void;
showConversation: ShowConversationType; showConversation: ShowConversationType;
}; };

View file

@ -24,7 +24,7 @@ export type Props = {
i18n: LocalizerType; i18n: LocalizerType;
isGroup: boolean; isGroup: boolean;
isMe: boolean; isMe: boolean;
memberships: Array<GroupV2Membership>; memberships: ReadonlyArray<GroupV2Membership>;
startEditing: (isGroupTitle: boolean) => void; startEditing: (isGroupTitle: boolean) => void;
theme: ThemeType; theme: ThemeType;
}; };

View file

@ -19,7 +19,7 @@ export type Props = {
showAllMedia: () => void; showAllMedia: () => void;
showLightboxWithMedia: ( showLightboxWithMedia: (
selectedAttachmentPath: string | undefined, selectedAttachmentPath: string | undefined,
media: Array<MediaItemType> media: ReadonlyArray<MediaItemType>
) => void; ) => void;
}; };

View file

@ -25,7 +25,7 @@ export type Props = {
getPreferredBadge: PreferredBadgeSelectorType; getPreferredBadge: PreferredBadgeSelectorType;
i18n: LocalizerType; i18n: LocalizerType;
maxShownMemberCount?: number; maxShownMemberCount?: number;
memberships: Array<GroupV2Membership>; memberships: ReadonlyArray<GroupV2Membership>;
showContactModal: (contactId: string, conversationId?: string) => void; showContactModal: (contactId: string, conversationId?: string) => void;
startAddingNewMembers?: () => void; startAddingNewMembers?: () => void;
theme: ThemeType; theme: ThemeType;

View file

@ -41,7 +41,7 @@ type PropsType = {
deleteAvatarFromDisk: DeleteAvatarFromDiskActionType; deleteAvatarFromDisk: DeleteAvatarFromDiskActionType;
replaceAvatar: ReplaceAvatarActionType; replaceAvatar: ReplaceAvatarActionType;
saveAvatarToDisk: SaveAvatarToDiskActionType; saveAvatarToDisk: SaveAvatarToDiskActionType;
userAvatarData: Array<AvatarDataType>; userAvatarData: ReadonlyArray<AvatarDataType>;
}; };
export function EditConversationAttributesModal({ export function EditConversationAttributesModal({

View file

@ -34,7 +34,7 @@ type PropsActionType = {
) => void; ) => void;
readonly revokePendingMembershipsFromGroupV2: ( readonly revokePendingMembershipsFromGroupV2: (
conversationId: string, conversationId: string,
memberIds: Array<string> memberIds: ReadonlyArray<string>
) => void; ) => void;
}; };
@ -193,14 +193,14 @@ function MembershipActionConfirmation({
) => void; ) => void;
conversation: ConversationType; conversation: ConversationType;
i18n: LocalizerType; i18n: LocalizerType;
members: Array<ConversationType>; members: ReadonlyArray<ConversationType>;
onClose: () => void; onClose: () => void;
ourUuid: string; ourUuid: string;
revokePendingMembershipsFromGroupV2: ( revokePendingMembershipsFromGroupV2: (
conversationId: string, conversationId: string,
memberIds: Array<string> memberIds: ReadonlyArray<string>
) => void; ) => void;
stagedMemberships: Array<StagedMembershipType>; stagedMemberships: ReadonlyArray<StagedMembershipType>;
}) { }) {
const revokeStagedMemberships = () => { const revokeStagedMemberships = () => {
if (!stagedMemberships) { if (!stagedMemberships) {
@ -424,7 +424,7 @@ function MembersPendingProfileKey({
conversation: ConversationType; conversation: ConversationType;
getPreferredBadge: PreferredBadgeSelectorType; getPreferredBadge: PreferredBadgeSelectorType;
i18n: LocalizerType; i18n: LocalizerType;
members: Array<ConversationType>; members: ReadonlyArray<ConversationType>;
memberships: ReadonlyArray<GroupV2PendingMembership>; memberships: ReadonlyArray<GroupV2PendingMembership>;
ourUuid: string; ourUuid: string;
setStagedMemberships: (stagedMembership: Array<StagedMembershipType>) => void; setStagedMemberships: (stagedMembership: Array<StagedMembershipType>) => void;

View file

@ -14,7 +14,7 @@ import { missingCaseError } from '../../../util/missingCaseError';
export type Props = { export type Props = {
header?: string; header?: string;
i18n: LocalizerType; i18n: LocalizerType;
mediaItems: Array<MediaItemType>; mediaItems: ReadonlyArray<MediaItemType>;
onItemClick: (event: ItemClickEvent) => unknown; onItemClick: (event: ItemClickEvent) => unknown;
type: 'media' | 'documents'; type: 'media' | 'documents';
}; };

View file

@ -15,7 +15,7 @@ type YearMonthSectionType = 'yearMonth';
type GenericSection<T> = { type GenericSection<T> = {
type: T; type: T;
mediaItems: Array<MediaItemType>; mediaItems: ReadonlyArray<MediaItemType>;
}; };
type StaticSection = GenericSection<StaticSectionType>; type StaticSection = GenericSection<StaticSectionType>;
type YearMonthSection = GenericSection<YearMonthSectionType> & { type YearMonthSection = GenericSection<YearMonthSectionType> & {
@ -25,7 +25,7 @@ type YearMonthSection = GenericSection<YearMonthSectionType> & {
export type Section = StaticSection | YearMonthSection; export type Section = StaticSection | YearMonthSection;
export const groupMediaItemsByDate = ( export const groupMediaItemsByDate = (
timestamp: number, timestamp: number,
mediaItems: Array<MediaItemType> mediaItems: ReadonlyArray<MediaItemType>
): Array<Section> => { ): Array<Section> => {
const referenceDateTime = moment.utc(timestamp); const referenceDateTime = moment.utc(timestamp);

View file

@ -19,7 +19,7 @@ export type GroupListItemConversationType = Pick<
> & { > & {
disabledReason: DisabledReason | undefined; disabledReason: DisabledReason | undefined;
membersCount: number; membersCount: number;
memberships: Array<{ memberships: ReadonlyArray<{
uuid: UUIDStringType; uuid: UUIDStringType;
isAdmin: boolean; isAdmin: boolean;
}>; }>;

View file

@ -36,7 +36,7 @@ export type OwnProps = {
readonly doSend?: () => unknown; readonly doSend?: () => unknown;
readonly skinTone?: number; readonly skinTone?: number;
readonly onSetSkinTone?: (tone: number) => unknown; readonly onSetSkinTone?: (tone: number) => unknown;
readonly recentEmojis?: Array<string>; readonly recentEmojis?: ReadonlyArray<string>;
readonly onClickSettings?: () => unknown; readonly onClickSettings?: () => unknown;
readonly onClose?: () => unknown; readonly onClose?: () => unknown;
}; };

View file

@ -1193,7 +1193,7 @@ export function buildDeletePendingMemberChange({
uuids, uuids,
group, group,
}: { }: {
uuids: Array<UUID>; uuids: ReadonlyArray<UUID>;
group: ConversationAttributesType; group: ConversationAttributesType;
}): Proto.GroupChange.Actions { }): Proto.GroupChange.Actions {
const actions = new Proto.GroupChange.Actions(); const actions = new Proto.GroupChange.Actions();
@ -1452,7 +1452,7 @@ export async function modifyGroupV2({
conversation: ConversationModel; conversation: ConversationModel;
usingCredentialsFrom: ReadonlyArray<ConversationModel>; usingCredentialsFrom: ReadonlyArray<ConversationModel>;
createGroupChange: () => Promise<Proto.GroupChange.Actions | undefined>; createGroupChange: () => Promise<Proto.GroupChange.Actions | undefined>;
extraConversationsForSend?: Array<string>; extraConversationsForSend?: ReadonlyArray<string>;
inviteLinkPassword?: string; inviteLinkPassword?: string;
name: string; name: string;
}): Promise<void> { }): Promise<void> {
@ -1554,7 +1554,7 @@ export async function modifyGroupV2({
type: conversationQueueJobEnum.enum.GroupUpdate, type: conversationQueueJobEnum.enum.GroupUpdate,
conversationId: conversation.id, conversationId: conversation.id,
groupChangeBase64, groupChangeBase64,
recipients: groupV2Info.members, recipients: groupV2Info.members.slice(),
revision: groupV2Info.revision, revision: groupV2Info.revision,
}); });
}); });
@ -1733,8 +1733,8 @@ export async function createGroupV2(
name: string; name: string;
avatar: undefined | Uint8Array; avatar: undefined | Uint8Array;
expireTimer: undefined | DurationInSeconds; expireTimer: undefined | DurationInSeconds;
conversationIds: Array<string>; conversationIds: ReadonlyArray<string>;
avatars?: Array<AvatarDataType>; avatars?: ReadonlyArray<AvatarDataType>;
refreshedCredentials?: boolean; refreshedCredentials?: boolean;
}> }>
): Promise<ConversationModel> { ): Promise<ConversationModel> {
@ -1953,7 +1953,7 @@ export async function createGroupV2(
await conversationJobQueue.add({ await conversationJobQueue.add({
type: conversationQueueJobEnum.enum.GroupUpdate, type: conversationQueueJobEnum.enum.GroupUpdate,
conversationId: conversation.id, conversationId: conversation.id,
recipients: groupV2Info.members, recipients: groupV2Info.members.slice(),
revision: groupV2Info.revision, revision: groupV2Info.revision,
}); });
@ -2438,7 +2438,7 @@ export async function initiateMigrationToGroupV2(
await conversationJobQueue.add({ await conversationJobQueue.add({
type: conversationQueueJobEnum.enum.GroupUpdate, type: conversationQueueJobEnum.enum.GroupUpdate,
conversationId: conversation.id, conversationId: conversation.id,
recipients: groupV2Info.members, recipients: groupV2Info.members.slice(),
revision: groupV2Info.revision, revision: groupV2Info.revision,
}); });
} }
@ -2466,7 +2466,7 @@ export async function waitThenRespondToGroupV2Migration(
} }
export function buildMigrationBubble( export function buildMigrationBubble(
previousGroupV1MembersIds: Array<string>, previousGroupV1MembersIds: ReadonlyArray<string>,
newAttributes: ConversationAttributesType newAttributes: ConversationAttributesType
): GroupChangeMessageType { ): GroupChangeMessageType {
const ourACI = window.storage.user.getCheckedUuid(UUIDKind.ACI); const ourACI = window.storage.user.getCheckedUuid(UUIDKind.ACI);
@ -3880,7 +3880,7 @@ async function integrateGroupChanges({
}: { }: {
group: ConversationAttributesType; group: ConversationAttributesType;
newRevision: number | undefined; newRevision: number | undefined;
changes: Array<Proto.IGroupChanges>; changes: ReadonlyArray<Proto.IGroupChanges>;
}): Promise<UpdatesResultType> { }): Promise<UpdatesResultType> {
const logId = idForLogging(group.groupId); const logId = idForLogging(group.groupId);
let attributes = group; let attributes = group;
@ -4715,7 +4715,7 @@ function extractDiffs({
return result; return result;
} }
function profileKeysToMembers(items: Array<GroupChangeMemberType>) { function profileKeysToMembers(items: ReadonlyArray<GroupChangeMemberType>) {
return items.map(item => ({ return items.map(item => ({
profileKey: Bytes.toBase64(item.profileKey), profileKey: Bytes.toBase64(item.profileKey),
uuid: item.uuid, uuid: item.uuid,

View file

@ -17,12 +17,12 @@ export function toggleSelectedContactForGroupAddition(
maximumGroupSizeModalState: OneTimeModalState; maximumGroupSizeModalState: OneTimeModalState;
numberOfContactsAlreadyInGroup: number; numberOfContactsAlreadyInGroup: number;
recommendedGroupSizeModalState: OneTimeModalState; recommendedGroupSizeModalState: OneTimeModalState;
selectedConversationIds: Array<string>; selectedConversationIds: ReadonlyArray<string>;
}> }>
): { ): {
maximumGroupSizeModalState: OneTimeModalState; maximumGroupSizeModalState: OneTimeModalState;
recommendedGroupSizeModalState: OneTimeModalState; recommendedGroupSizeModalState: OneTimeModalState;
selectedConversationIds: Array<string>; selectedConversationIds: ReadonlyArray<string>;
} { } {
const { const {
maxGroupSize, maxGroupSize,

View file

@ -741,7 +741,7 @@ export class ConversationModel extends window.Backbone
}: { }: {
usingCredentialsFrom: ReadonlyArray<ConversationModel>; usingCredentialsFrom: ReadonlyArray<ConversationModel>;
createGroupChange: () => Promise<Proto.GroupChange.Actions | undefined>; createGroupChange: () => Promise<Proto.GroupChange.Actions | undefined>;
extraConversationsForSend?: Array<string>; extraConversationsForSend?: ReadonlyArray<string>;
inviteLinkPassword?: string; inviteLinkPassword?: string;
name: string; name: string;
}): Promise<void> { }): Promise<void> {
@ -1159,9 +1159,9 @@ export class ConversationModel extends window.Backbone
{ groupChange?: Uint8Array } & ( { groupChange?: Uint8Array } & (
| { | {
includePendingMembers?: boolean; includePendingMembers?: boolean;
extraConversationsForSend?: Array<string>; extraConversationsForSend?: ReadonlyArray<string>;
} }
| { members: Array<string> } | { members: ReadonlyArray<string> }
) )
> = {} > = {}
): GroupV2InfoType | undefined { ): GroupV2InfoType | undefined {
@ -3712,7 +3712,7 @@ export class ConversationModel extends window.Backbone
isStoryReply = false, isStoryReply = false,
}: { }: {
includePendingMembers?: boolean; includePendingMembers?: boolean;
extraConversationsForSend?: Array<string>; extraConversationsForSend?: ReadonlyArray<string>;
isStoryReply?: boolean; isStoryReply?: boolean;
} = {}): Array<string> { } = {}): Array<string> {
return getRecipients(this.attributes, { return getRecipients(this.attributes, {

View file

@ -45,14 +45,14 @@ export class MemberRepository {
FUSE_OPTIONS FUSE_OPTIONS
); );
constructor(private members: Array<ConversationType> = []) {} constructor(private members: ReadonlyArray<ConversationType> = []) {}
updateMembers(members: Array<ConversationType>): void { updateMembers(members: ReadonlyArray<ConversationType>): void {
this.members = members; this.members = members;
this.isFuseReady = false; this.isFuseReady = false;
} }
getMembers(omit?: ConversationType): Array<ConversationType> { getMembers(omit?: ConversationType): ReadonlyArray<ConversationType> {
if (omit) { if (omit) {
return this.members.filter(({ id }) => id !== omit.id); return this.members.filter(({ id }) => id !== omit.id);
} }
@ -72,7 +72,10 @@ export class MemberRepository {
: undefined; : undefined;
} }
search(pattern: string, omit?: ConversationType): Array<ConversationType> { search(
pattern: string,
omit?: ConversationType
): ReadonlyArray<ConversationType> {
if (!this.isFuseReady) { if (!this.isFuseReady) {
this.fuse.setCollection(this.members); this.fuse.setCollection(this.members);
this.isFuseReady = true; this.isFuseReady = true;

View file

@ -31,7 +31,7 @@ export type MentionCompletionOptions = {
const MENTION_REGEX = /(?:^|\W)@([-+\w]*)$/; const MENTION_REGEX = /(?:^|\W)@([-+\w]*)$/;
export class MentionCompletion { export class MentionCompletion {
results: Array<ConversationType>; results: ReadonlyArray<ConversationType>;
index: number; index: number;
@ -105,7 +105,7 @@ export class MentionCompletion {
this.clearResults(); this.clearResults();
} }
possiblyShowMemberResults(): Array<ConversationType> { possiblyShowMemberResults(): ReadonlyArray<ConversationType> {
const range = this.quill.getSelection(); const range = this.quill.getSelection();
if (range) { if (range) {
@ -120,7 +120,7 @@ export class MentionCompletion {
if (leftTokenTextMatch) { if (leftTokenTextMatch) {
const [, leftTokenText] = leftTokenTextMatch; const [, leftTokenText] = leftTokenTextMatch;
let results: Array<ConversationType> = []; let results: ReadonlyArray<ConversationType> = [];
const memberRepository = this.options.memberRepositoryRef.current; const memberRepository = this.options.memberRepositoryRef.current;

View file

@ -471,7 +471,7 @@ export type DataInterface = {
options: { forceSave?: boolean; ourUuid: UUIDStringType } options: { forceSave?: boolean; ourUuid: UUIDStringType }
) => Promise<void>; ) => Promise<void>;
removeMessage: (id: string) => Promise<void>; removeMessage: (id: string) => Promise<void>;
removeMessages: (ids: Array<string>) => Promise<void>; removeMessages: (ids: ReadonlyArray<string>) => Promise<void>;
getTotalUnreadForConversation: ( getTotalUnreadForConversation: (
conversationId: string, conversationId: string,
options: { options: {

View file

@ -1509,7 +1509,7 @@ async function updateConversations(
})(); })();
} }
function removeConversationsSync(ids: Array<string>): void { function removeConversationsSync(ids: ReadonlyArray<string>): void {
const db = getInstance(); const db = getInstance();
// Our node interface doesn't seem to allow you to replace one single ? with an array // Our node interface doesn't seem to allow you to replace one single ? with an array
@ -2046,7 +2046,7 @@ async function removeMessage(id: string): Promise<void> {
db.prepare<Query>('DELETE FROM messages WHERE id = $id;').run({ id }); db.prepare<Query>('DELETE FROM messages WHERE id = $id;').run({ id });
} }
function removeMessagesSync(ids: Array<string>): void { function removeMessagesSync(ids: ReadonlyArray<string>): void {
const db = getInstance(); const db = getInstance();
db.prepare<ArrayQuery>( db.prepare<ArrayQuery>(
@ -2057,7 +2057,7 @@ function removeMessagesSync(ids: Array<string>): void {
).run(ids); ).run(ids);
} }
async function removeMessages(ids: Array<string>): Promise<void> { async function removeMessages(ids: ReadonlyArray<string>): Promise<void> {
batchMultiVarQuery(getInstance(), ids, removeMessagesSync); batchMultiVarQuery(getInstance(), ids, removeMessagesSync);
} }
@ -2091,7 +2091,7 @@ async function getMessagesById(
return batchMultiVarQuery( return batchMultiVarQuery(
db, db,
messageIds, messageIds,
(batch: Array<string>): Array<MessageType> => { (batch: ReadonlyArray<string>): Array<MessageType> => {
const query = db.prepare<ArrayQuery>( const query = db.prepare<ArrayQuery>(
`SELECT json FROM messages WHERE id IN (${Array(batch.length) `SELECT json FROM messages WHERE id IN (${Array(batch.length)
.fill('?') .fill('?')
@ -2325,7 +2325,7 @@ async function getUnreadReactionsAndMarkRead({
}); });
const idsToUpdate = unreadMessages.map(item => item.rowid); const idsToUpdate = unreadMessages.map(item => item.rowid);
batchMultiVarQuery(db, idsToUpdate, (ids: Array<number>): void => { batchMultiVarQuery(db, idsToUpdate, (ids: ReadonlyArray<number>): void => {
db.prepare<ArrayQuery>( db.prepare<ArrayQuery>(
` `
UPDATE reactions SET UPDATE reactions SET
@ -3408,7 +3408,7 @@ async function getAllUnprocessedAndIncrementAttempts(): Promise<
})(); })();
} }
function removeUnprocessedsSync(ids: Array<string>): void { function removeUnprocessedsSync(ids: ReadonlyArray<string>): void {
const db = getInstance(); const db = getInstance();
db.prepare<ArrayQuery>( db.prepare<ArrayQuery>(
@ -4680,7 +4680,7 @@ function modifyStoryDistributionMembersSync(
}); });
} }
batchMultiVarQuery(db, toRemove, (uuids: Array<UUIDStringType>) => { batchMultiVarQuery(db, toRemove, (uuids: ReadonlyArray<UUIDStringType>) => {
db.prepare<ArrayQuery>( db.prepare<ArrayQuery>(
` `
DELETE FROM storyDistributionMembers DELETE FROM storyDistributionMembers
@ -5166,7 +5166,7 @@ async function getKnownMessageAttachments(
const messages = batchMultiVarQuery( const messages = batchMultiVarQuery(
db, db,
rowids, rowids,
(batch: Array<number>): Array<MessageType> => { (batch: ReadonlyArray<number>): Array<MessageType> => {
const query = db.prepare<ArrayQuery>( const query = db.prepare<ArrayQuery>(
`SELECT json FROM messages WHERE rowid IN (${Array(batch.length) `SELECT json FROM messages WHERE rowid IN (${Array(batch.length)
.fill('?') .fill('?')

View file

@ -57,7 +57,7 @@ export default function updateToSchemaVersion42(
} }
}); });
function deleteReactions(rowids: Array<number>) { function deleteReactions(rowids: ReadonlyArray<number>) {
db.prepare<ArrayQuery>( db.prepare<ArrayQuery>(
` `
DELETE FROM reactions DELETE FROM reactions

View file

@ -5,7 +5,7 @@ import type { Database } from '@signalapp/better-sqlite3';
import { isNumber, last } from 'lodash'; import { isNumber, last } from 'lodash';
export type EmptyQuery = []; export type EmptyQuery = [];
export type ArrayQuery = Array<Array<null | number | bigint | string>>; export type ArrayQuery = Array<ReadonlyArray<null | number | bigint | string>>;
export type Query = { export type Query = {
[key: string]: null | number | bigint | string | Uint8Array; [key: string]: null | number | bigint | string | Uint8Array;
}; };
@ -72,21 +72,21 @@ export function getSQLCipherVersion(db: Database): string | undefined {
export function batchMultiVarQuery<ValueT>( export function batchMultiVarQuery<ValueT>(
db: Database, db: Database,
values: Array<ValueT>, values: ReadonlyArray<ValueT>,
query: (batch: Array<ValueT>) => void query: (batch: ReadonlyArray<ValueT>) => void
): []; ): [];
export function batchMultiVarQuery<ValueT, ResultT>( export function batchMultiVarQuery<ValueT, ResultT>(
db: Database, db: Database,
values: Array<ValueT>, values: ReadonlyArray<ValueT>,
query: (batch: Array<ValueT>) => Array<ResultT> query: (batch: ReadonlyArray<ValueT>) => Array<ResultT>
): Array<ResultT>; ): Array<ResultT>;
export function batchMultiVarQuery<ValueT, ResultT>( export function batchMultiVarQuery<ValueT, ResultT>(
db: Database, db: Database,
values: Array<ValueT>, values: ReadonlyArray<ValueT>,
query: query:
| ((batch: Array<ValueT>) => void) | ((batch: ReadonlyArray<ValueT>) => void)
| ((batch: Array<ValueT>) => Array<ResultT>) | ((batch: ReadonlyArray<ValueT>) => Array<ResultT>)
): Array<ResultT> { ): Array<ResultT> {
if (values.length > MAX_VARIABLE_COUNT) { if (values.length > MAX_VARIABLE_COUNT) {
const result: Array<ResultT> = []; const result: Array<ResultT> = [];
@ -187,7 +187,7 @@ export function removeById<Key extends string | number>(
throw new Error('removeById: No ids to delete!'); throw new Error('removeById: No ids to delete!');
} }
const removeByIdsSync = (ids: Array<string | number>): void => { const removeByIdsSync = (ids: ReadonlyArray<string | number>): void => {
db.prepare<ArrayQuery>( db.prepare<ArrayQuery>(
` `
DELETE FROM ${table} DELETE FROM ${table}

View file

@ -170,7 +170,7 @@ export type ConversationType = {
about?: string; about?: string;
aboutText?: string; aboutText?: string;
aboutEmoji?: string; aboutEmoji?: string;
avatars?: Array<AvatarDataType>; avatars?: ReadonlyArray<AvatarDataType>;
avatarPath?: string; avatarPath?: string;
avatarHash?: string; avatarHash?: string;
profileAvatarPath?: string; profileAvatarPath?: string;
@ -215,24 +215,24 @@ export type ConversationType = {
announcementsOnly?: boolean; announcementsOnly?: boolean;
announcementsOnlyReady?: boolean; announcementsOnlyReady?: boolean;
expireTimer?: DurationInSeconds; expireTimer?: DurationInSeconds;
memberships?: Array<{ memberships?: ReadonlyArray<{
uuid: UUIDStringType; uuid: UUIDStringType;
isAdmin: boolean; isAdmin: boolean;
}>; }>;
pendingMemberships?: Array<{ pendingMemberships?: ReadonlyArray<{
uuid: UUIDStringType; uuid: UUIDStringType;
addedByUserId?: UUIDStringType; addedByUserId?: UUIDStringType;
}>; }>;
pendingApprovalMemberships?: Array<{ pendingApprovalMemberships?: ReadonlyArray<{
uuid: UUIDStringType; uuid: UUIDStringType;
}>; }>;
bannedMemberships?: Array<UUIDStringType>; bannedMemberships?: ReadonlyArray<UUIDStringType>;
muteExpiresAt?: number; muteExpiresAt?: number;
dontNotifyForMentionsIfMuted?: boolean; dontNotifyForMentionsIfMuted?: boolean;
isMe: boolean; isMe: boolean;
lastUpdated?: number; lastUpdated?: number;
// This is used by the CompositionInput for @mentions // This is used by the CompositionInput for @mentions
sortedGroupMembers?: Array<ConversationType>; sortedGroupMembers?: ReadonlyArray<ConversationType>;
title: string; title: string;
titleNoDefault?: string; titleNoDefault?: string;
searchableTitle?: string; searchableTitle?: string;
@ -240,7 +240,7 @@ export type ConversationType = {
isSelected?: boolean; isSelected?: boolean;
isFetchingUUID?: boolean; isFetchingUUID?: boolean;
typingContactId?: string; typingContactId?: string;
recentMediaItems?: Array<MediaItemType>; recentMediaItems?: ReadonlyArray<MediaItemType>;
profileSharing?: boolean; profileSharing?: boolean;
shouldShowDraft?: boolean; shouldShowDraft?: boolean;
@ -248,7 +248,7 @@ export type ConversationType = {
draftBodyRanges?: DraftBodyRangesType; draftBodyRanges?: DraftBodyRangesType;
draftPreview?: string; draftPreview?: string;
sharedGroupNames: Array<string>; sharedGroupNames: ReadonlyArray<string>;
groupDescription?: string; groupDescription?: string;
groupVersion?: 1 | 2; groupVersion?: 1 | 2;
groupId?: string; groupId?: string;
@ -260,7 +260,7 @@ export type ConversationType = {
profileKey?: string; profileKey?: string;
voiceNotePlaybackRate?: number; voiceNotePlaybackRate?: number;
badges: Array< badges: ReadonlyArray<
| { | {
id: string; id: string;
} }
@ -312,7 +312,7 @@ export type MessageLookupType = {
export type ConversationMessageType = { export type ConversationMessageType = {
isNearBottom?: boolean; isNearBottom?: boolean;
messageChangeCounter: number; messageChangeCounter: number;
messageIds: Array<string>; messageIds: ReadonlyArray<string>;
messageLoadingState?: undefined | TimelineMessageLoadingState; messageLoadingState?: undefined | TimelineMessageLoadingState;
metrics: MessageMetricsType; metrics: MessageMetricsType;
scrollToMessageId?: string; scrollToMessageId?: string;
@ -340,8 +340,8 @@ type ComposerGroupCreationState = {
groupExpireTimer: DurationInSeconds; groupExpireTimer: DurationInSeconds;
maximumGroupSizeModalState: OneTimeModalState; maximumGroupSizeModalState: OneTimeModalState;
recommendedGroupSizeModalState: OneTimeModalState; recommendedGroupSizeModalState: OneTimeModalState;
selectedConversationIds: Array<string>; selectedConversationIds: ReadonlyArray<string>;
userAvatarData: Array<AvatarDataType>; userAvatarData: ReadonlyArray<AvatarDataType>;
}; };
type DistributionVerificationData = { type DistributionVerificationData = {
@ -397,7 +397,7 @@ type ContactSpoofingReviewStateType =
export type ConversationsStateType = { export type ConversationsStateType = {
preJoinConversation?: PreJoinConversationType; preJoinConversation?: PreJoinConversationType;
invitedUuidsForNewlyCreatedGroup?: Array<string>; invitedUuidsForNewlyCreatedGroup?: ReadonlyArray<string>;
conversationLookup: ConversationLookupType; conversationLookup: ConversationLookupType;
conversationsByE164: ConversationLookupType; conversationsByE164: ConversationLookupType;
conversationsByUuid: ConversationLookupType; conversationsByUuid: ConversationLookupType;
@ -407,8 +407,9 @@ export type ConversationsStateType = {
selectedMessage: string | undefined; selectedMessage: string | undefined;
selectedMessageCounter: number; selectedMessageCounter: number;
selectedMessageSource: SelectedMessageSource | undefined; selectedMessageSource: SelectedMessageSource | undefined;
selectedConversationPanels: Array<PanelRenderType>; selectedConversationPanels: ReadonlyArray<PanelRenderType>;
selectedMessageForDetails?: MessageAttributesType; selectedMessageForDetails?: MessageAttributesType;
showArchived: boolean; showArchived: boolean;
composer?: ComposerStateType; composer?: ComposerStateType;
contactSpoofingReview?: ContactSpoofingReviewStateType; contactSpoofingReview?: ContactSpoofingReviewStateType;
@ -600,7 +601,7 @@ type CreateGroupPendingActionType = {
type CreateGroupFulfilledActionType = { type CreateGroupFulfilledActionType = {
type: 'CREATE_GROUP_FULFILLED'; type: 'CREATE_GROUP_FULFILLED';
payload: { payload: {
invitedUuids: Array<UUIDStringType>; invitedUuids: ReadonlyArray<UUIDStringType>;
}; };
}; };
type CreateGroupRejectedActionType = { type CreateGroupRejectedActionType = {
@ -655,7 +656,7 @@ export type MessagesAddedActionType = {
isActive: boolean; isActive: boolean;
isJustSent: boolean; isJustSent: boolean;
isNewMessage: boolean; isNewMessage: boolean;
messages: Array<MessageAttributesType>; messages: ReadonlyArray<MessageAttributesType>;
}; };
}; };
@ -682,7 +683,7 @@ export type MessagesResetActionType = {
type: 'MESSAGES_RESET'; type: 'MESSAGES_RESET';
payload: { payload: {
conversationId: string; conversationId: string;
messages: Array<MessageAttributesType>; messages: ReadonlyArray<MessageAttributesType>;
metrics: MessageMetricsType; metrics: MessageMetricsType;
scrollToMessageId?: string; scrollToMessageId?: string;
// The set of provided messages should be trusted, even if it conflicts with metrics, // The set of provided messages should be trusted, even if it conflicts with metrics,
@ -776,7 +777,7 @@ type SetRecentMediaItemsActionType = {
type: 'SET_RECENT_MEDIA_ITEMS'; type: 'SET_RECENT_MEDIA_ITEMS';
payload: { payload: {
id: string; id: string;
recentMediaItems: Array<MediaItemType>; recentMediaItems: ReadonlyArray<MediaItemType>;
}; };
}; };
type ToggleComposeEditingAvatarActionType = { type ToggleComposeEditingAvatarActionType = {
@ -812,7 +813,7 @@ type ReplaceAvatarsActionType = {
type: typeof REPLACE_AVATARS; type: typeof REPLACE_AVATARS;
payload: { payload: {
conversationId: string; conversationId: string;
avatars: Array<AvatarDataType>; avatars: ReadonlyArray<AvatarDataType>;
}; };
}; };
@ -1230,7 +1231,7 @@ function filterAvatarData(
return avatars.filter(avatarData => !isSameAvatarData(data, avatarData)); return avatars.filter(avatarData => !isSameAvatarData(data, avatarData));
} }
function getNextAvatarId(avatars: Array<AvatarDataType>): number { function getNextAvatarId(avatars: ReadonlyArray<AvatarDataType>): number {
return Math.max(...avatars.map(x => Number(x.id))) + 1; return Math.max(...avatars.map(x => Number(x.id))) + 1;
} }
@ -1238,10 +1239,10 @@ async function getAvatarsAndUpdateConversation(
conversations: ConversationsStateType, conversations: ConversationsStateType,
conversationId: string, conversationId: string,
getNextAvatarsData: ( getNextAvatarsData: (
avatars: Array<AvatarDataType>, avatars: ReadonlyArray<AvatarDataType>,
nextId: number nextId: number
) => Array<AvatarDataType> ) => ReadonlyArray<AvatarDataType>
): Promise<Array<AvatarDataType>> { ): Promise<ReadonlyArray<AvatarDataType>> {
const conversation = window.ConversationController.get(conversationId); const conversation = window.ConversationController.get(conversationId);
if (!conversation) { if (!conversation) {
throw new Error('getAvatarsAndUpdateConversation: No conversation found'); throw new Error('getAvatarsAndUpdateConversation: No conversation found');
@ -2415,7 +2416,7 @@ function messagesAdded({
isActive: boolean; isActive: boolean;
isJustSent: boolean; isJustSent: boolean;
isNewMessage: boolean; isNewMessage: boolean;
messages: Array<MessageAttributesType>; messages: ReadonlyArray<MessageAttributesType>;
}): MessagesAddedActionType { }): MessagesAddedActionType {
return { return {
type: 'MESSAGES_ADDED', type: 'MESSAGES_ADDED',
@ -2469,7 +2470,7 @@ function reviewMessageRequestNameCollision(
export type MessageResetOptionsType = Readonly<{ export type MessageResetOptionsType = Readonly<{
conversationId: string; conversationId: string;
messages: Array<MessageAttributesType>; messages: ReadonlyArray<MessageAttributesType>;
metrics: MessageMetricsType; metrics: MessageMetricsType;
scrollToMessageId?: string; scrollToMessageId?: string;
unboundedFetch?: boolean; unboundedFetch?: boolean;
@ -2705,7 +2706,7 @@ function approvePendingMembershipFromGroupV2(
function revokePendingMembershipsFromGroupV2( function revokePendingMembershipsFromGroupV2(
conversationId: string, conversationId: string,
memberIds: Array<string> memberIds: ReadonlyArray<string>
): ThunkAction<void, RootStateType, unknown, NoopActionType> { ): ThunkAction<void, RootStateType, unknown, NoopActionType> {
return async dispatch => { return async dispatch => {
const conversation = window.ConversationController.get(conversationId); const conversation = window.ConversationController.get(conversationId);
@ -3340,7 +3341,7 @@ function leaveGroup(
} }
function toggleGroupsForStorySend( function toggleGroupsForStorySend(
conversationIds: Array<string> conversationIds: ReadonlyArray<string>
): ThunkAction<Promise<void>, RootStateType, unknown, NoopActionType> { ): ThunkAction<Promise<void>, RootStateType, unknown, NoopActionType> {
return async dispatch => { return async dispatch => {
await Promise.all( await Promise.all(
@ -4018,7 +4019,7 @@ export function reducer(
...omit(state, 'contactSpoofingReview'), ...omit(state, 'contactSpoofingReview'),
selectedConversationId, selectedConversationId,
selectedConversationPanels: [], selectedConversationPanels: [],
messagesLookup: omit(state.messagesLookup, messageIds), messagesLookup: omit(state.messagesLookup, [...messageIds]),
messagesByConversation: omit(state.messagesByConversation, [id]), messagesByConversation: omit(state.messagesByConversation, [id]),
}; };
} }
@ -4930,7 +4931,7 @@ export function reducer(
} }
if (action.type === 'SHOW_CHOOSE_GROUP_MEMBERS') { if (action.type === 'SHOW_CHOOSE_GROUP_MEMBERS') {
let selectedConversationIds: Array<string>; let selectedConversationIds: ReadonlyArray<string>;
let recommendedGroupSizeModalState: OneTimeModalState; let recommendedGroupSizeModalState: OneTimeModalState;
let maximumGroupSizeModalState: OneTimeModalState; let maximumGroupSizeModalState: OneTimeModalState;
let groupName: string; let groupName: string;

View file

@ -37,7 +37,7 @@ export type ItemsStateType = {
readonly preferredLeftPaneWidth?: number; readonly preferredLeftPaneWidth?: number;
readonly preferredReactionEmoji?: Array<string>; readonly preferredReactionEmoji?: ReadonlyArray<string>;
readonly areWeASubscriber?: boolean; readonly areWeASubscriber?: boolean;
}; };

View file

@ -32,7 +32,7 @@ export type LightboxStateType =
| { | {
isShowingLightbox: true; isShowingLightbox: true;
isViewOnce: boolean; isViewOnce: boolean;
media: Array<MediaItemType>; media: ReadonlyArray<MediaItemType>;
selectedAttachmentPath: string | undefined; selectedAttachmentPath: string | undefined;
}; };
@ -47,7 +47,7 @@ type ShowLightboxActionType = {
type: typeof SHOW_LIGHTBOX; type: typeof SHOW_LIGHTBOX;
payload: { payload: {
isViewOnce: boolean; isViewOnce: boolean;
media: Array<MediaItemType>; media: ReadonlyArray<MediaItemType>;
selectedAttachmentPath: string | undefined; selectedAttachmentPath: string | undefined;
}; };
}; };
@ -89,7 +89,7 @@ function closeLightbox(): ThunkAction<
function showLightboxWithMedia( function showLightboxWithMedia(
selectedAttachmentPath: string | undefined, selectedAttachmentPath: string | undefined,
media: Array<MediaItemType> media: ReadonlyArray<MediaItemType>
): ShowLightboxActionType { ): ShowLightboxActionType {
return { return {
type: SHOW_LIGHTBOX, type: SHOW_LIGHTBOX,

View file

@ -279,7 +279,7 @@ export const _getLeftPaneLists = (
lookup: ConversationLookupType, lookup: ConversationLookupType,
comparator: (left: ConversationType, right: ConversationType) => number, comparator: (left: ConversationType, right: ConversationType) => number,
selectedConversation?: string, selectedConversation?: string,
pinnedConversationIds?: Array<string> pinnedConversationIds?: ReadonlyArray<string>
): { ): {
conversations: Array<ConversationType>; conversations: Array<ConversationType>;
archivedConversations: Array<ConversationType>; archivedConversations: Array<ConversationType>;
@ -603,7 +603,7 @@ export const getFilteredComposeContacts = createSelector(
getRegionCode, getRegionCode,
( (
searchTerm: string, searchTerm: string,
contacts: Array<ConversationType>, contacts: ReadonlyArray<ConversationType>,
regionCode: string | undefined regionCode: string | undefined
): Array<ConversationType> => { ): Array<ConversationType> => {
return filterAndSortConversationsByRecent(contacts, searchTerm, regionCode); return filterAndSortConversationsByRecent(contacts, searchTerm, regionCode);
@ -616,7 +616,7 @@ export const getFilteredComposeGroups = createSelector(
getRegionCode, getRegionCode,
( (
searchTerm: string, searchTerm: string,
groups: Array<ConversationType>, groups: ReadonlyArray<ConversationType>,
regionCode: string | undefined regionCode: string | undefined
): Array<ConversationType> => { ): Array<ConversationType> => {
return filterAndSortConversationsByRecent(groups, searchTerm, regionCode); return filterAndSortConversationsByRecent(groups, searchTerm, regionCode);
@ -638,7 +638,7 @@ const getGroupCreationComposerState = createSelector(
groupName: string; groupName: string;
groupAvatar: undefined | Uint8Array; groupAvatar: undefined | Uint8Array;
groupExpireTimer: DurationInSeconds; groupExpireTimer: DurationInSeconds;
selectedConversationIds: Array<string>; selectedConversationIds: ReadonlyArray<string>;
} => { } => {
switch (composerState?.step) { switch (composerState?.step) {
case ComposerStep.ChooseGroupMembers: case ComposerStep.ChooseGroupMembers:

View file

@ -36,5 +36,6 @@ export const getSelectedIndex = createSelector(
export const getMedia = createSelector( export const getMedia = createSelector(
getLightboxState, getLightboxState,
(state): Array<MediaItemType> => (state.isShowingLightbox ? state.media : []) (state): ReadonlyArray<MediaItemType> =>
state.isShowingLightbox ? state.media : []
); );

View file

@ -33,7 +33,7 @@ export function SmartLightbox(): JSX.Element | null {
const isShowingLightbox = useSelector<StateType, boolean>(shouldShowLightbox); const isShowingLightbox = useSelector<StateType, boolean>(shouldShowLightbox);
const isViewOnce = useSelector<StateType, boolean>(getIsViewOnce); const isViewOnce = useSelector<StateType, boolean>(getIsViewOnce);
const media = useSelector<StateType, Array<MediaItemType>>(getMedia); const media = useSelector<StateType, ReadonlyArray<MediaItemType>>(getMedia);
const selectedIndex = useSelector<StateType, number>(getSelectedIndex); const selectedIndex = useSelector<StateType, number>(getSelectedIndex);
if (!isShowingLightbox) { if (!isShowingLightbox) {

View file

@ -34,7 +34,7 @@ export const SmartReactionPicker = React.forwardRef<
const i18n = useSelector<StateType, LocalizerType>(getIntl); const i18n = useSelector<StateType, LocalizerType>(getIntl);
const preferredReactionEmoji = useSelector<StateType, Array<string>>( const preferredReactionEmoji = useSelector<StateType, ReadonlyArray<string>>(
getPreferredReactionEmoji getPreferredReactionEmoji
); );

View file

@ -54,7 +54,7 @@ export function SmartStoryViewer(): JSX.Element | null {
const i18n = useSelector<StateType, LocalizerType>(getIntl); const i18n = useSelector<StateType, LocalizerType>(getIntl);
const getPreferredBadge = useSelector(getPreferredBadgeSelector); const getPreferredBadge = useSelector(getPreferredBadgeSelector);
const preferredReactionEmoji = useSelector<StateType, Array<string>>( const preferredReactionEmoji = useSelector<StateType, ReadonlyArray<string>>(
getPreferredReactionEmoji getPreferredReactionEmoji
); );

View file

@ -99,7 +99,7 @@ describe('MentionCompletion', () => {
describe('onTextChange', () => { describe('onTextChange', () => {
let possiblyShowMemberResultsStub: sinon.SinonStub< let possiblyShowMemberResultsStub: sinon.SinonStub<
[], [],
Array<ConversationType> ReadonlyArray<ConversationType>
>; >;
beforeEach(() => { beforeEach(() => {

View file

@ -97,11 +97,11 @@ export type GroupV2InfoType = {
groupChange?: Uint8Array; groupChange?: Uint8Array;
masterKey: Uint8Array; masterKey: Uint8Array;
revision: number; revision: number;
members: Array<string>; members: ReadonlyArray<string>;
}; };
export type GroupV1InfoType = { export type GroupV1InfoType = {
id: string; id: string;
members: Array<string>; members: ReadonlyArray<string>;
}; };
type GroupCallUpdateType = { type GroupCallUpdateType = {

View file

@ -726,14 +726,16 @@ export function hasFailed(attachment?: AttachmentType): boolean {
return Boolean(resolved && resolved.error); return Boolean(resolved && resolved.error);
} }
export function hasVideoBlurHash(attachments?: Array<AttachmentType>): boolean { export function hasVideoBlurHash(
attachments?: ReadonlyArray<AttachmentType>
): boolean {
const firstAttachment = attachments ? attachments[0] : null; const firstAttachment = attachments ? attachments[0] : null;
return Boolean(firstAttachment && firstAttachment.blurHash); return Boolean(firstAttachment && firstAttachment.blurHash);
} }
export function hasVideoScreenshot( export function hasVideoScreenshot(
attachments?: Array<AttachmentType> attachments?: ReadonlyArray<AttachmentType>
): string | null | undefined { ): string | null | undefined {
const firstAttachment = attachments ? attachments[0] : null; const firstAttachment = attachments ? attachments[0] : null;

View file

@ -118,7 +118,9 @@ const personalDefaultAvatars = PersonalAvatarIcons.map((icon, index) => ({
icon, icon,
})); }));
export function getDefaultAvatars(isGroup?: boolean): Array<AvatarDataType> { export function getDefaultAvatars(
isGroup?: boolean
): ReadonlyArray<AvatarDataType> {
if (isGroup) { if (isGroup) {
return groupDefaultAvatars; return groupDefaultAvatars;
} }

22
ts/types/Storage.d.ts vendored
View file

@ -49,8 +49,8 @@ export type StorageAccessType = {
'audio-notification': boolean; 'audio-notification': boolean;
'auto-download-update': boolean; 'auto-download-update': boolean;
'badge-count-muted-conversations': boolean; 'badge-count-muted-conversations': boolean;
'blocked-groups': Array<string>; 'blocked-groups': ReadonlyArray<string>;
'blocked-uuids': Array<string>; 'blocked-uuids': ReadonlyArray<string>;
'call-ringtone-notification': boolean; 'call-ringtone-notification': boolean;
'call-system-notification': boolean; 'call-system-notification': boolean;
'hide-menu-bar': boolean; 'hide-menu-bar': boolean;
@ -64,11 +64,11 @@ export type StorageAccessType = {
'theme-setting': ThemeSettingType; 'theme-setting': ThemeSettingType;
attachmentMigration_isComplete: boolean; attachmentMigration_isComplete: boolean;
attachmentMigration_lastProcessedIndex: number; attachmentMigration_lastProcessedIndex: number;
blocked: Array<string>; blocked: ReadonlyArray<string>;
defaultConversationColor: DefaultConversationColorType; defaultConversationColor: DefaultConversationColorType;
customColors: CustomColorsItemType; customColors: CustomColorsItemType;
device_name: string; device_name: string;
existingOnboardingStoryMessageIds: Array<string> | undefined; existingOnboardingStoryMessageIds: ReadonlyArray<string> | undefined;
hasRegisterSupportForUnauthenticatedDelivery: boolean; hasRegisterSupportForUnauthenticatedDelivery: boolean;
hasSetMyStoriesPrivacy: boolean; hasSetMyStoriesPrivacy: boolean;
hasViewedOnboardingStory: boolean; hasViewedOnboardingStory: boolean;
@ -98,12 +98,12 @@ export type StorageAccessType = {
version: string; version: string;
linkPreviews: boolean; linkPreviews: boolean;
universalExpireTimer: number; universalExpireTimer: number;
retryPlaceholders: Array<RetryItemType>; retryPlaceholders: ReadonlyArray<RetryItemType>;
chromiumRegistrationDoneEver: ''; chromiumRegistrationDoneEver: '';
chromiumRegistrationDone: ''; chromiumRegistrationDone: '';
phoneNumberSharingMode: PhoneNumberSharingMode; phoneNumberSharingMode: PhoneNumberSharingMode;
phoneNumberDiscoverability: PhoneNumberDiscoverability; phoneNumberDiscoverability: PhoneNumberDiscoverability;
pinnedConversationIds: Array<string>; pinnedConversationIds: ReadonlyArray<string>;
preferContactAvatars: boolean; preferContactAvatars: boolean;
primarySendsSms: boolean; primarySendsSms: boolean;
// Unlike `number_id` (which also includes device id) this field is only // Unlike `number_id` (which also includes device id) this field is only
@ -115,18 +115,18 @@ export type StorageAccessType = {
avatarUrl: string | undefined; avatarUrl: string | undefined;
manifestVersion: number; manifestVersion: number;
storageCredentials: StorageServiceCredentials; storageCredentials: StorageServiceCredentials;
'storage-service-error-records': Array<UnknownRecord>; 'storage-service-error-records': ReadonlyArray<UnknownRecord>;
'storage-service-unknown-records': Array<UnknownRecord>; 'storage-service-unknown-records': ReadonlyArray<UnknownRecord>;
'storage-service-pending-deletes': Array<ExtendedStorageID>; 'storage-service-pending-deletes': ReadonlyArray<ExtendedStorageID>;
'preferred-video-input-device': string; 'preferred-video-input-device': string;
'preferred-audio-input-device': AudioDevice; 'preferred-audio-input-device': AudioDevice;
'preferred-audio-output-device': AudioDevice; 'preferred-audio-output-device': AudioDevice;
previousAudioDeviceModule: AudioDeviceModule; previousAudioDeviceModule: AudioDeviceModule;
remoteConfig: RemoteConfigType; remoteConfig: RemoteConfigType;
unidentifiedDeliveryIndicators: boolean; unidentifiedDeliveryIndicators: boolean;
groupCredentials: Array<GroupCredentialType>; groupCredentials: ReadonlyArray<GroupCredentialType>;
lastReceivedAtCounter: number; lastReceivedAtCounter: number;
preferredReactionEmoji: Array<string>; preferredReactionEmoji: ReadonlyArray<string>;
skinTone: number; skinTone: number;
unreadCount: number; unreadCount: number;
'challenge:conversations': ReadonlyArray<RegisteredChallengeType>; 'challenge:conversations': ReadonlyArray<RegisteredChallengeType>;

View file

@ -8,7 +8,7 @@ import type { ConversationAttributesType } from '../model-types.d';
export function getAvatarData( export function getAvatarData(
conversationAttrs: Pick<ConversationAttributesType, 'avatars' | 'type'> conversationAttrs: Pick<ConversationAttributesType, 'avatars' | 'type'>
): Array<AvatarDataType> { ): ReadonlyArray<AvatarDataType> {
const { avatars } = conversationAttrs; const { avatars } = conversationAttrs;
if (avatars && avatars.length) { if (avatars && avatars.length) {

View file

@ -11,9 +11,9 @@ import type { UUIDStringType } from '../types/UUID';
import { isConversationUnregistered } from './isConversationUnregistered'; import { isConversationUnregistered } from './isConversationUnregistered';
export type GroupMemberships = { export type GroupMemberships = {
memberships: Array<GroupV2Membership>; memberships: ReadonlyArray<GroupV2Membership>;
pendingApprovalMemberships: Array<GroupV2RequestingMembership>; pendingApprovalMemberships: ReadonlyArray<GroupV2RequestingMembership>;
pendingMemberships: Array<GroupV2PendingMembership>; pendingMemberships: ReadonlyArray<GroupV2PendingMembership>;
}; };
export const getGroupMemberships = ( export const getGroupMemberships = (
@ -30,7 +30,7 @@ export const getGroupMemberships = (
getConversationByUuid: (uuid: UUIDStringType) => undefined | ConversationType getConversationByUuid: (uuid: UUIDStringType) => undefined | ConversationType
): GroupMemberships => ({ ): GroupMemberships => ({
memberships: memberships.reduce( memberships: memberships.reduce(
(result: Array<GroupV2Membership>, membership) => { (result: ReadonlyArray<GroupV2Membership>, membership) => {
const member = getConversationByUuid(membership.uuid); const member = getConversationByUuid(membership.uuid);
if (!member) { if (!member) {
return result; return result;
@ -40,7 +40,7 @@ export const getGroupMemberships = (
[] []
), ),
pendingApprovalMemberships: pendingApprovalMemberships.reduce( pendingApprovalMemberships: pendingApprovalMemberships.reduce(
(result: Array<GroupV2RequestingMembership>, membership) => { (result: ReadonlyArray<GroupV2RequestingMembership>, membership) => {
const member = getConversationByUuid(membership.uuid); const member = getConversationByUuid(membership.uuid);
if (!member || isConversationUnregistered(member)) { if (!member || isConversationUnregistered(member)) {
return result; return result;
@ -50,7 +50,7 @@ export const getGroupMemberships = (
[] []
), ),
pendingMemberships: pendingMemberships.reduce( pendingMemberships: pendingMemberships.reduce(
(result: Array<GroupV2PendingMembership>, membership) => { (result: ReadonlyArray<GroupV2PendingMembership>, membership) => {
const member = getConversationByUuid(membership.uuid); const member = getConversationByUuid(membership.uuid);
if (!member || isConversationUnregistered(member)) { if (!member || isConversationUnregistered(member)) {
return result; return result;

View file

@ -18,7 +18,7 @@ export function getRecipients(
isStoryReply = false, isStoryReply = false,
}: { }: {
includePendingMembers?: boolean; includePendingMembers?: boolean;
extraConversationsForSend?: Array<string>; extraConversationsForSend?: ReadonlyArray<string>;
isStoryReply?: boolean; isStoryReply?: boolean;
} = {} } = {}
): Array<string> { ): Array<string> {

View file

@ -14,9 +14,9 @@ import { getRecipientsByConversation } from './getRecipientsByConversation';
export async function maybeForwardMessage( export async function maybeForwardMessage(
messageAttributes: MessageAttributesType, messageAttributes: MessageAttributesType,
conversationIds: Array<string>, conversationIds: ReadonlyArray<string>,
messageBody?: string, messageBody?: string,
attachments?: Array<AttachmentType>, attachments?: ReadonlyArray<AttachmentType>,
linkPreview?: LinkPreviewType linkPreview?: LinkPreviewType
): Promise<boolean> { ): Promise<boolean> {
const idForLogging = getMessageIdForLogging(messageAttributes); const idForLogging = getMessageIdForLogging(messageAttributes);

View file

@ -167,7 +167,7 @@ export async function sendContentMessageToGroup({
isPartialSend?: boolean; isPartialSend?: boolean;
messageId: string | undefined; messageId: string | undefined;
online?: boolean; online?: boolean;
recipients: Array<string>; recipients: ReadonlyArray<string>;
sendOptions?: SendOptionsType; sendOptions?: SendOptionsType;
sendTarget: SenderKeyTargetType; sendTarget: SenderKeyTargetType;
sendType: SendTypesType; sendType: SendTypesType;
@ -254,7 +254,7 @@ export async function sendToGroupViaSenderKey(options: {
isPartialSend?: boolean; isPartialSend?: boolean;
messageId: string | undefined; messageId: string | undefined;
online?: boolean; online?: boolean;
recipients: Array<string>; recipients: ReadonlyArray<string>;
recursionCount: number; recursionCount: number;
sendOptions?: SendOptionsType; sendOptions?: SendOptionsType;
sendTarget: SenderKeyTargetType; sendTarget: SenderKeyTargetType;
@ -836,7 +836,7 @@ export function _shouldFailSend(error: unknown, logId: string): boolean {
return false; return false;
} }
function getRecipients(options: GroupSendOptionsType): Array<string> { function getRecipients(options: GroupSendOptionsType): ReadonlyArray<string> {
if (options.groupV2) { if (options.groupV2) {
return options.groupV2.members; return options.groupV2.members;
} }