Add type-alias-readonlydeep rule and make ducks mostly immutable

This commit is contained in:
Jamie Kyle 2023-01-13 12:07:26 -08:00 committed by GitHub
parent 11ce3c3d59
commit c58a723f45
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 1164 additions and 871 deletions

View file

@ -3,6 +3,7 @@
import type { ThunkAction } from 'redux-thunk';
import type { ReadonlyDeep } from 'type-fest';
import * as Errors from '../../types/errors';
import * as log from '../../logging/log';
@ -16,21 +17,21 @@ import type { NoopActionType } from './noop';
// State
export type AccountsStateType = {
export type AccountsStateType = ReadonlyDeep<{
accounts: Record<string, UUIDStringType | undefined>;
};
}>;
// Actions
type AccountUpdateActionType = {
type AccountUpdateActionType = ReadonlyDeep<{
type: 'accounts/UPDATE';
payload: {
phoneNumber: string;
uuid?: UUIDStringType;
};
};
}>;
export type AccountsActionType = AccountUpdateActionType;
export type AccountsActionType = ReadonlyDeep<AccountUpdateActionType>;
// Action Creators

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import type { ThunkAction } from 'redux-thunk';
import type { ReadonlyDeep } from 'type-fest';
import type { StateType as RootStateType } from '../reducer';
import * as log from '../../logging/log';
@ -14,10 +15,10 @@ export enum AppViewType {
Standalone = 'Standalone',
}
export type AppStateType = {
export type AppStateType = ReadonlyDeep<{
appView: AppViewType;
hasInitialLoadCompleted: boolean;
};
}>;
// Actions
@ -26,27 +27,28 @@ const OPEN_INBOX = 'app/OPEN_INBOX';
const OPEN_INSTALLER = 'app/OPEN_INSTALLER';
const OPEN_STANDALONE = 'app/OPEN_STANDALONE';
type InitialLoadCompleteActionType = {
type InitialLoadCompleteActionType = ReadonlyDeep<{
type: typeof INITIAL_LOAD_COMPLETE;
};
}>;
type OpenInboxActionType = {
type OpenInboxActionType = ReadonlyDeep<{
type: typeof OPEN_INBOX;
};
}>;
type OpenInstallerActionType = {
type OpenInstallerActionType = ReadonlyDeep<{
type: typeof OPEN_INSTALLER;
};
}>;
type OpenStandaloneActionType = {
type OpenStandaloneActionType = ReadonlyDeep<{
type: typeof OPEN_STANDALONE;
};
}>;
export type AppActionType =
export type AppActionType = ReadonlyDeep<
| InitialLoadCompleteActionType
| OpenInboxActionType
| OpenInstallerActionType
| OpenStandaloneActionType;
| OpenStandaloneActionType
>;
export const actions = {
initialLoadComplete,

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import type { ThunkAction } from 'redux-thunk';
import type { ReadonlyDeep } from 'type-fest';
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
import { useBoundActions } from '../../hooks/useBoundActions';
import { Sound } from '../../util/Sound';
@ -35,25 +36,25 @@ import { getMessagePropStatus } from '../selectors/message';
// State
export type ActiveAudioPlayerStateType = {
readonly playing: boolean;
readonly currentTime: number;
readonly playbackRate: number;
readonly duration: number;
};
export type ActiveAudioPlayerStateType = ReadonlyDeep<{
playing: boolean;
currentTime: number;
playbackRate: number;
duration: number;
}>;
export type AudioPlayerStateType = {
readonly active:
export type AudioPlayerStateType = ReadonlyDeep<{
active:
| (ActiveAudioPlayerStateType & { id: string; context: string })
| undefined;
};
}>;
// Actions
/**
* Sets the current "active" message audio for a particular rendering "context"
*/
export type SetMessageAudioAction = {
export type SetMessageAudioAction = ReadonlyDeep<{
type: 'audioPlayer/SET_MESSAGE_AUDIO';
payload:
| {
@ -63,39 +64,40 @@ export type SetMessageAudioAction = {
duration: number;
}
| undefined;
};
}>;
type SetPlaybackRate = {
type SetPlaybackRate = ReadonlyDeep<{
type: 'audioPlayer/SET_PLAYBACK_RATE';
payload: number;
};
}>;
type SetIsPlayingAction = {
type SetIsPlayingAction = ReadonlyDeep<{
type: 'audioPlayer/SET_IS_PLAYING';
payload: boolean;
};
}>;
type CurrentTimeUpdated = {
type CurrentTimeUpdated = ReadonlyDeep<{
type: 'audioPlayer/CURRENT_TIME_UPDATED';
payload: number;
};
}>;
type MessageAudioEnded = {
type MessageAudioEnded = ReadonlyDeep<{
type: 'audioPlayer/MESSAGE_AUDIO_ENDED';
};
}>;
type DurationChanged = {
type DurationChanged = ReadonlyDeep<{
type: 'audioPlayer/DURATION_CHANGED';
payload: number;
};
}>;
type AudioPlayerActionType =
type AudioPlayerActionType = ReadonlyDeep<
| SetMessageAudioAction
| SetIsPlayingAction
| SetPlaybackRate
| MessageAudioEnded
| CurrentTimeUpdated
| DurationChanged;
| DurationChanged
>;
// Action Creators

View file

@ -3,6 +3,7 @@
import type { ThunkAction } from 'redux-thunk';
import type { ReadonlyDeep } from 'type-fest';
import * as log from '../../logging/log';
import type { InMemoryAttachmentDraftType } from '../../types/Attachment';
import { SignalService as Proto } from '../../protobuf';
@ -28,10 +29,10 @@ export enum RecordingState {
Idle = 'idle',
}
export type AudioPlayerStateType = {
readonly recordingState: RecordingState;
readonly errorDialogAudioRecorderType?: ErrorDialogAudioRecorderType;
};
export type AudioPlayerStateType = ReadonlyDeep<{
recordingState: RecordingState;
errorDialogAudioRecorderType?: ErrorDialogAudioRecorderType;
}>;
// Actions
@ -41,33 +42,34 @@ const ERROR_RECORDING = 'audioRecorder/ERROR_RECORDING';
const NOW_RECORDING = 'audioRecorder/NOW_RECORDING';
const START_RECORDING = 'audioRecorder/START_RECORDING';
type CancelRecordingAction = {
type CancelRecordingAction = ReadonlyDeep<{
type: typeof CANCEL_RECORDING;
payload: undefined;
};
type CompleteRecordingAction = {
}>;
type CompleteRecordingAction = ReadonlyDeep<{
type: typeof COMPLETE_RECORDING;
payload: undefined;
};
type ErrorRecordingAction = {
}>;
type ErrorRecordingAction = ReadonlyDeep<{
type: typeof ERROR_RECORDING;
payload: ErrorDialogAudioRecorderType;
};
type StartRecordingAction = {
}>;
type StartRecordingAction = ReadonlyDeep<{
type: typeof START_RECORDING;
payload: undefined;
};
type NowRecordingAction = {
}>;
type NowRecordingAction = ReadonlyDeep<{
type: typeof NOW_RECORDING;
payload: undefined;
};
}>;
type AudioPlayerActionType =
type AudioPlayerActionType = ReadonlyDeep<
| CancelRecordingAction
| CompleteRecordingAction
| ErrorRecordingAction
| NowRecordingAction
| StartRecordingAction;
| StartRecordingAction
>;
// Action Creators

View file

@ -3,6 +3,7 @@
import type { ThunkAction } from 'redux-thunk';
import { mapValues } from 'lodash';
import type { ReadonlyDeep } from 'type-fest';
import type { StateType as RootStateType } from '../reducer';
import type { BadgeType, BadgeImageType } from '../../badges/types';
import { getOwn } from '../../util/getOwn';
@ -22,27 +23,27 @@ import { badgeImageFileDownloader } from '../../badges/badgeImageFileDownloader'
// State
export type BadgesStateType = {
export type BadgesStateType = ReadonlyDeep<{
byId: Record<string, BadgeType>;
};
}>;
// Actions
const IMAGE_FILE_DOWNLOADED = 'badges/IMAGE_FILE_DOWNLOADED';
const UPDATE_OR_CREATE = 'badges/UPDATE_OR_CREATE';
type ImageFileDownloadedActionType = {
type ImageFileDownloadedActionType = ReadonlyDeep<{
type: typeof IMAGE_FILE_DOWNLOADED;
payload: {
url: string;
localPath: string;
};
};
}>;
type UpdateOrCreateActionType = {
type UpdateOrCreateActionType = ReadonlyDeep<{
type: typeof UPDATE_OR_CREATE;
payload: ReadonlyArray<BadgeType>;
};
payload: Array<BadgeType>;
}>;
// Action creators

View file

@ -9,6 +9,7 @@ import {
openSystemPreferences,
} from 'mac-screen-capture-permissions';
import { has, omit } from 'lodash';
import type { ReadonlyDeep } from 'type-fest';
import { getOwn } from '../../util/getOwn';
import * as Errors from '../../types/errors';
import { getPlatform } from '../selectors/user';
@ -57,14 +58,15 @@ import MessageSender from '../../textsecure/SendMessage';
// State
export type GroupCallPeekInfoType = {
export type GroupCallPeekInfoType = ReadonlyDeep<{
uuids: Array<UUIDStringType>;
creatorUuid?: UUIDStringType;
eraId?: string;
maxDevices: number;
deviceCount: number;
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type GroupCallParticipantInfoType = {
uuid: UUIDStringType;
demuxId: number;
@ -76,6 +78,7 @@ export type GroupCallParticipantInfoType = {
videoAspectRatio: number;
};
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type DirectCallStateType = {
callMode: CallMode.Direct;
conversationId: string;
@ -87,7 +90,7 @@ export type DirectCallStateType = {
hasRemoteVideo?: boolean;
};
type GroupCallRingStateType =
type GroupCallRingStateType = ReadonlyDeep<
| {
ringId?: undefined;
ringerUuid?: undefined;
@ -95,8 +98,10 @@ type GroupCallRingStateType =
| {
ringId: bigint;
ringerUuid: UUIDStringType;
};
}
>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type GroupCallStateType = {
callMode: CallMode.Group;
conversationId: string;
@ -107,6 +112,7 @@ export type GroupCallStateType = {
remoteAudioLevels?: Map<number, number>;
} & GroupCallRingStateType;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type ActiveCallStateType = {
conversationId: string;
hasLocalAudio: boolean;
@ -124,21 +130,23 @@ export type ActiveCallStateType = {
showParticipantsList: boolean;
};
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type CallsByConversationType = {
[conversationId: string]: DirectCallStateType | GroupCallStateType;
};
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type CallingStateType = MediaDeviceSettings & {
callsByConversation: CallsByConversationType;
activeCallState?: ActiveCallStateType;
};
export type AcceptCallType = {
export type AcceptCallType = ReadonlyDeep<{
conversationId: string;
asVideoCall: boolean;
};
}>;
export type CallStateChangeType = {
export type CallStateChangeType = ReadonlyDeep<{
remoteUserId: string; // TODO: Remove
callId: string; // TODO: Remove
conversationId: string;
@ -148,21 +156,22 @@ export type CallStateChangeType = {
isIncoming: boolean;
isVideoCall: boolean;
title: string;
};
}>;
export type CancelCallType = {
export type CancelCallType = ReadonlyDeep<{
conversationId: string;
};
}>;
type CancelIncomingGroupCallRingType = {
type CancelIncomingGroupCallRingType = ReadonlyDeep<{
conversationId: string;
ringId: bigint;
};
}>;
export type DeclineCallType = {
export type DeclineCallType = ReadonlyDeep<{
conversationId: string;
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
type GroupCallStateChangeArgumentType = {
connectionState: GroupCallConnectionState;
conversationId: string;
@ -173,77 +182,81 @@ type GroupCallStateChangeArgumentType = {
remoteParticipants: Array<GroupCallParticipantInfoType>;
};
// eslint-disable-next-line local-rules/type-alias-readonlydeep
type GroupCallStateChangeActionPayloadType =
GroupCallStateChangeArgumentType & {
ourUuid: UUIDStringType;
};
type HangUpActionPayloadType = {
type HangUpActionPayloadType = ReadonlyDeep<{
conversationId: string;
};
}>;
type KeyChangedType = {
type KeyChangedType = ReadonlyDeep<{
uuid: UUIDStringType;
};
}>;
export type KeyChangeOkType = {
export type KeyChangeOkType = ReadonlyDeep<{
conversationId: string;
};
}>;
export type IncomingDirectCallType = {
export type IncomingDirectCallType = ReadonlyDeep<{
conversationId: string;
isVideoCall: boolean;
};
}>;
type IncomingGroupCallType = {
type IncomingGroupCallType = ReadonlyDeep<{
conversationId: string;
ringId: bigint;
ringerUuid: UUIDStringType;
};
}>;
type PeekNotConnectedGroupCallType = {
type PeekNotConnectedGroupCallType = ReadonlyDeep<{
conversationId: string;
};
}>;
type StartDirectCallType = {
type StartDirectCallType = ReadonlyDeep<{
conversationId: string;
hasLocalAudio: boolean;
hasLocalVideo: boolean;
};
}>;
export type StartCallType = StartDirectCallType & {
callMode: CallMode.Direct | CallMode.Group;
};
export type StartCallType = ReadonlyDeep<
StartDirectCallType & {
callMode: CallMode.Direct | CallMode.Group;
}
>;
export type RemoteVideoChangeType = {
export type RemoteVideoChangeType = ReadonlyDeep<{
conversationId: string;
hasVideo: boolean;
};
}>;
type RemoteSharingScreenChangeType = {
type RemoteSharingScreenChangeType = ReadonlyDeep<{
conversationId: string;
isSharingScreen: boolean;
};
}>;
export type SetLocalAudioType = {
export type SetLocalAudioType = ReadonlyDeep<{
enabled: boolean;
};
}>;
export type SetLocalVideoType = {
export type SetLocalVideoType = ReadonlyDeep<{
enabled: boolean;
};
}>;
export type SetGroupCallVideoRequestType = {
export type SetGroupCallVideoRequestType = ReadonlyDeep<{
conversationId: string;
resolutions: Array<GroupCallVideoRequest>;
speakerHeight: number;
};
}>;
export type StartCallingLobbyType = {
export type StartCallingLobbyType = ReadonlyDeep<{
conversationId: string;
isVideoCall: boolean;
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
type StartCallingLobbyPayloadType =
| {
callMode: CallMode.Direct;
@ -263,10 +276,12 @@ type StartCallingLobbyPayloadType =
remoteParticipants: Array<GroupCallParticipantInfoType>;
};
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type SetLocalPreviewType = {
element: React.RefObject<HTMLVideoElement> | undefined;
};
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type SetRendererCanvasType = {
element: React.RefObject<HTMLCanvasElement> | undefined;
};
@ -441,76 +456,79 @@ const TOGGLE_SPEAKER_VIEW = 'calling/TOGGLE_SPEAKER_VIEW';
const SWITCH_TO_PRESENTATION_VIEW = 'calling/SWITCH_TO_PRESENTATION_VIEW';
const SWITCH_FROM_PRESENTATION_VIEW = 'calling/SWITCH_FROM_PRESENTATION_VIEW';
type AcceptCallPendingActionType = {
type AcceptCallPendingActionType = ReadonlyDeep<{
type: 'calling/ACCEPT_CALL_PENDING';
payload: AcceptCallType;
};
}>;
type CancelCallActionType = {
type CancelCallActionType = ReadonlyDeep<{
type: 'calling/CANCEL_CALL';
};
}>;
type CancelIncomingGroupCallRingActionType = {
type CancelIncomingGroupCallRingActionType = ReadonlyDeep<{
type: 'calling/CANCEL_INCOMING_GROUP_CALL_RING';
payload: CancelIncomingGroupCallRingType;
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
type StartCallingLobbyActionType = {
type: 'calling/START_CALLING_LOBBY';
payload: StartCallingLobbyPayloadType;
};
type CallStateChangeFulfilledActionType = {
type CallStateChangeFulfilledActionType = ReadonlyDeep<{
type: 'calling/CALL_STATE_CHANGE_FULFILLED';
payload: CallStateChangeType;
};
}>;
type ChangeIODeviceFulfilledActionType = {
type ChangeIODeviceFulfilledActionType = ReadonlyDeep<{
type: 'calling/CHANGE_IO_DEVICE_FULFILLED';
payload: ChangeIODevicePayloadType;
};
}>;
type CloseNeedPermissionScreenActionType = {
type CloseNeedPermissionScreenActionType = ReadonlyDeep<{
type: 'calling/CLOSE_NEED_PERMISSION_SCREEN';
payload: null;
};
}>;
type DeclineCallActionType = {
type DeclineCallActionType = ReadonlyDeep<{
type: 'calling/DECLINE_DIRECT_CALL';
payload: DeclineCallType;
};
}>;
type GroupCallAudioLevelsChangeActionPayloadType = Readonly<{
type GroupCallAudioLevelsChangeActionPayloadType = ReadonlyDeep<{
conversationId: string;
localAudioLevel: number;
remoteDeviceStates: ReadonlyArray<{ audioLevel: number; demuxId: number }>;
}>;
type GroupCallAudioLevelsChangeActionType = {
type GroupCallAudioLevelsChangeActionType = ReadonlyDeep<{
type: 'calling/GROUP_CALL_AUDIO_LEVELS_CHANGE';
payload: GroupCallAudioLevelsChangeActionPayloadType;
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type GroupCallStateChangeActionType = {
type: 'calling/GROUP_CALL_STATE_CHANGE';
payload: GroupCallStateChangeActionPayloadType;
};
type HangUpActionType = {
type HangUpActionType = ReadonlyDeep<{
type: 'calling/HANG_UP';
payload: HangUpActionPayloadType;
};
}>;
type IncomingDirectCallActionType = {
type IncomingDirectCallActionType = ReadonlyDeep<{
type: 'calling/INCOMING_DIRECT_CALL';
payload: IncomingDirectCallType;
};
}>;
type IncomingGroupCallActionType = {
type IncomingGroupCallActionType = ReadonlyDeep<{
type: 'calling/INCOMING_GROUP_CALL';
payload: IncomingGroupCallType;
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
type KeyChangedActionType = {
type: 'calling/MARK_CALL_UNTRUSTED';
payload: {
@ -518,101 +536,104 @@ type KeyChangedActionType = {
};
};
type KeyChangeOkActionType = {
type KeyChangeOkActionType = ReadonlyDeep<{
type: 'calling/MARK_CALL_TRUSTED';
payload: null;
};
}>;
type OutgoingCallActionType = {
type OutgoingCallActionType = ReadonlyDeep<{
type: 'calling/OUTGOING_CALL';
payload: StartDirectCallType;
};
}>;
export type PeekGroupCallFulfilledActionType = {
export type PeekGroupCallFulfilledActionType = ReadonlyDeep<{
type: 'calling/PEEK_GROUP_CALL_FULFILLED';
payload: {
conversationId: string;
peekInfo: GroupCallPeekInfoType;
};
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
type RefreshIODevicesActionType = {
type: 'calling/REFRESH_IO_DEVICES';
payload: MediaDeviceSettings;
};
type RemoteSharingScreenChangeActionType = {
type RemoteSharingScreenChangeActionType = ReadonlyDeep<{
type: 'calling/REMOTE_SHARING_SCREEN_CHANGE';
payload: RemoteSharingScreenChangeType;
};
}>;
type RemoteVideoChangeActionType = {
type RemoteVideoChangeActionType = ReadonlyDeep<{
type: 'calling/REMOTE_VIDEO_CHANGE';
payload: RemoteVideoChangeType;
};
}>;
type ReturnToActiveCallActionType = {
type ReturnToActiveCallActionType = ReadonlyDeep<{
type: 'calling/RETURN_TO_ACTIVE_CALL';
};
}>;
type SetLocalAudioActionType = {
type SetLocalAudioActionType = ReadonlyDeep<{
type: 'calling/SET_LOCAL_AUDIO_FULFILLED';
payload: SetLocalAudioType;
};
}>;
type SetLocalVideoFulfilledActionType = {
type SetLocalVideoFulfilledActionType = ReadonlyDeep<{
type: 'calling/SET_LOCAL_VIDEO_FULFILLED';
payload: SetLocalVideoType;
};
}>;
type SetPresentingFulfilledActionType = {
type SetPresentingFulfilledActionType = ReadonlyDeep<{
type: 'calling/SET_PRESENTING';
payload?: PresentedSource;
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
type SetPresentingSourcesActionType = {
type: 'calling/SET_PRESENTING_SOURCES';
payload: Array<PresentableSource>;
};
type SetOutgoingRingActionType = {
type SetOutgoingRingActionType = ReadonlyDeep<{
type: 'calling/SET_OUTGOING_RING';
payload: boolean;
};
}>;
type StartDirectCallActionType = {
type StartDirectCallActionType = ReadonlyDeep<{
type: 'calling/START_DIRECT_CALL';
payload: StartDirectCallType;
};
}>;
type ToggleNeedsScreenRecordingPermissionsActionType = {
type ToggleNeedsScreenRecordingPermissionsActionType = ReadonlyDeep<{
type: 'calling/TOGGLE_NEEDS_SCREEN_RECORDING_PERMISSIONS';
};
}>;
type ToggleParticipantsActionType = {
type ToggleParticipantsActionType = ReadonlyDeep<{
type: 'calling/TOGGLE_PARTICIPANTS';
};
}>;
type TogglePipActionType = {
type TogglePipActionType = ReadonlyDeep<{
type: 'calling/TOGGLE_PIP';
};
}>;
type ToggleSettingsActionType = {
type ToggleSettingsActionType = ReadonlyDeep<{
type: 'calling/TOGGLE_SETTINGS';
};
}>;
type ToggleSpeakerViewActionType = {
type ToggleSpeakerViewActionType = ReadonlyDeep<{
type: 'calling/TOGGLE_SPEAKER_VIEW';
};
}>;
type SwitchToPresentationViewActionType = {
type SwitchToPresentationViewActionType = ReadonlyDeep<{
type: 'calling/SWITCH_TO_PRESENTATION_VIEW';
};
}>;
type SwitchFromPresentationViewActionType = {
type SwitchFromPresentationViewActionType = ReadonlyDeep<{
type: 'calling/SWITCH_FROM_PRESENTATION_VIEW';
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type CallingActionType =
| AcceptCallPendingActionType
| CancelCallActionType
@ -1545,7 +1566,7 @@ export const actions = {
toggleSpeakerView,
};
export type ActionsType = typeof actions;
export type ActionsType = ReadonlyDeep<typeof actions>;
// Reducer

View file

@ -6,6 +6,7 @@ import path from 'path';
import { debounce } from 'lodash';
import type { ThunkAction } from 'redux-thunk';
import type { ReadonlyDeep } from 'type-fest';
import type {
AddLinkPreviewActionType,
RemoveLinkPreviewActionType,
@ -86,7 +87,7 @@ import { drop } from '../../util/drop';
import { strictAssert } from '../../util/assert';
// State
// eslint-disable-next-line local-rules/type-alias-readonlydeep
type ComposerStateByConversationType = {
attachments: ReadonlyArray<AttachmentDraftType>;
focusCounter: number;
@ -98,11 +99,13 @@ type ComposerStateByConversationType = {
shouldSendHighQualityAttachments?: boolean;
};
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type QuotedMessageType = Pick<
MessageAttributesType,
'conversationId' | 'quote'
>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type ComposerStateType = {
conversations: Record<string, ComposerStateByConversationType>;
};
@ -134,14 +137,15 @@ const SET_HIGH_QUALITY_SETTING = 'composer/SET_HIGH_QUALITY_SETTING';
const SET_QUOTED_MESSAGE = 'composer/SET_QUOTED_MESSAGE';
const SET_COMPOSER_DISABLED = 'composer/SET_COMPOSER_DISABLED';
type AddPendingAttachmentActionType = {
type AddPendingAttachmentActionType = ReadonlyDeep<{
type: typeof ADD_PENDING_ATTACHMENT;
payload: {
conversationId: string;
attachment: AttachmentDraftType;
};
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type ReplaceAttachmentsActionType = {
type: typeof REPLACE_ATTACHMENTS;
payload: {
@ -150,36 +154,37 @@ export type ReplaceAttachmentsActionType = {
};
};
export type ResetComposerActionType = {
export type ResetComposerActionType = ReadonlyDeep<{
type: typeof RESET_COMPOSER;
payload: {
conversationId: string;
};
};
}>;
type SetComposerDisabledStateActionType = {
type SetComposerDisabledStateActionType = ReadonlyDeep<{
type: typeof SET_COMPOSER_DISABLED;
payload: {
conversationId: string;
value: boolean;
};
};
}>;
export type SetFocusActionType = {
export type SetFocusActionType = ReadonlyDeep<{
type: typeof SET_FOCUS;
payload: {
conversationId: string;
};
};
}>;
type SetHighQualitySettingActionType = {
type SetHighQualitySettingActionType = ReadonlyDeep<{
type: typeof SET_HIGH_QUALITY_SETTING;
payload: {
conversationId: string;
value: boolean;
};
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type SetQuotedMessageActionType = {
type: typeof SET_QUOTED_MESSAGE;
payload: {
@ -188,6 +193,7 @@ export type SetQuotedMessageActionType = {
};
};
// eslint-disable-next-line local-rules/type-alias-readonlydeep
type ComposerActionType =
| AddLinkPreviewActionType
| AddPendingAttachmentActionType

View file

@ -12,6 +12,7 @@ import {
without,
} from 'lodash';
import type { ReadonlyDeep } from 'type-fest';
import type { AttachmentType } from '../../types/Attachment';
import type { StateType as RootStateType } from '../reducer';
import * as groups from '../../groups';
@ -152,27 +153,31 @@ import {
// State
export type DBConversationType = {
export type DBConversationType = ReadonlyDeep<{
id: string;
activeAt?: number;
lastMessage?: string | null;
type: string;
};
}>;
export const InteractionModes = ['mouse', 'keyboard'] as const;
export type InteractionModeType = typeof InteractionModes[number];
export type InteractionModeType = ReadonlyDeep<typeof InteractionModes[number]>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type MessageType = MessageAttributesType & {
interactionType?: InteractionModeType;
};
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type MessageWithUIFieldsType = MessageAttributesType & {
displayLimit?: number;
};
export const ConversationTypes = ['direct', 'group'] as const;
export type ConversationTypeType = typeof ConversationTypes[number];
export type ConversationTypeType = ReadonlyDeep<
typeof ConversationTypes[number]
>;
export type LastMessageType = Readonly<
export type LastMessageType = ReadonlyDeep<
| {
status?: LastMessageStatus;
text: string;
@ -182,154 +187,161 @@ export type LastMessageType = Readonly<
| { deletedForEveryone: true }
>;
export type ConversationType = {
id: string;
uuid?: UUIDStringType;
pni?: UUIDStringType;
e164?: string;
name?: string;
systemGivenName?: string;
systemFamilyName?: string;
familyName?: string;
firstName?: string;
profileName?: string;
username?: string;
about?: string;
aboutText?: string;
aboutEmoji?: string;
avatars?: ReadonlyArray<AvatarDataType>;
avatarPath?: string;
avatarHash?: string;
profileAvatarPath?: string;
unblurredAvatarPath?: string;
areWeAdmin?: boolean;
areWePending?: boolean;
areWePendingApproval?: boolean;
canChangeTimer?: boolean;
canEditGroupInfo?: boolean;
canAddNewMembers?: boolean;
color?: AvatarColorType;
conversationColor?: ConversationColorType;
customColor?: CustomColorType;
customColorId?: string;
discoveredUnregisteredAt?: number;
hideStory?: boolean;
isArchived?: boolean;
isBlocked?: boolean;
isGroupV1AndDisabled?: boolean;
isPinned?: boolean;
isUntrusted?: boolean;
isVerified?: boolean;
activeAt?: number;
timestamp?: number;
inboxPosition?: number;
left?: boolean;
lastMessage?: LastMessageType;
markedUnread?: boolean;
phoneNumber?: string;
membersCount?: number;
hasMessages?: boolean;
accessControlAddFromInviteLink?: number;
accessControlAttributes?: number;
accessControlMembers?: number;
announcementsOnly?: boolean;
announcementsOnlyReady?: boolean;
expireTimer?: DurationInSeconds;
memberships?: ReadonlyArray<{
uuid: UUIDStringType;
isAdmin: boolean;
}>;
pendingMemberships?: ReadonlyArray<{
uuid: UUIDStringType;
addedByUserId?: UUIDStringType;
}>;
pendingApprovalMemberships?: ReadonlyArray<{
uuid: UUIDStringType;
}>;
bannedMemberships?: ReadonlyArray<UUIDStringType>;
muteExpiresAt?: number;
dontNotifyForMentionsIfMuted?: boolean;
isMe: boolean;
lastUpdated?: number;
// This is used by the CompositionInput for @mentions
sortedGroupMembers?: ReadonlyArray<ConversationType>;
title: string;
titleNoDefault?: string;
searchableTitle?: string;
unreadCount?: number;
isSelected?: boolean;
isFetchingUUID?: boolean;
typingContactId?: string;
recentMediaItems?: ReadonlyArray<MediaItemType>;
profileSharing?: boolean;
export type ConversationType = ReadonlyDeep<
{
id: string;
uuid?: UUIDStringType;
pni?: UUIDStringType;
e164?: string;
name?: string;
systemGivenName?: string;
systemFamilyName?: string;
familyName?: string;
firstName?: string;
profileName?: string;
username?: string;
about?: string;
aboutText?: string;
aboutEmoji?: string;
avatars?: ReadonlyArray<AvatarDataType>;
avatarPath?: string;
avatarHash?: string;
profileAvatarPath?: string;
unblurredAvatarPath?: string;
areWeAdmin?: boolean;
areWePending?: boolean;
areWePendingApproval?: boolean;
canChangeTimer?: boolean;
canEditGroupInfo?: boolean;
canAddNewMembers?: boolean;
color?: AvatarColorType;
conversationColor?: ConversationColorType;
customColor?: CustomColorType;
customColorId?: string;
discoveredUnregisteredAt?: number;
hideStory?: boolean;
isArchived?: boolean;
isBlocked?: boolean;
isGroupV1AndDisabled?: boolean;
isPinned?: boolean;
isUntrusted?: boolean;
isVerified?: boolean;
activeAt?: number;
timestamp?: number;
inboxPosition?: number;
left?: boolean;
lastMessage?: LastMessageType;
markedUnread?: boolean;
phoneNumber?: string;
membersCount?: number;
hasMessages?: boolean;
accessControlAddFromInviteLink?: number;
accessControlAttributes?: number;
accessControlMembers?: number;
announcementsOnly?: boolean;
announcementsOnlyReady?: boolean;
expireTimer?: DurationInSeconds;
memberships?: ReadonlyArray<{
uuid: UUIDStringType;
isAdmin: boolean;
}>;
pendingMemberships?: ReadonlyArray<{
uuid: UUIDStringType;
addedByUserId?: UUIDStringType;
}>;
pendingApprovalMemberships?: ReadonlyArray<{
uuid: UUIDStringType;
}>;
bannedMemberships?: ReadonlyArray<UUIDStringType>;
muteExpiresAt?: number;
dontNotifyForMentionsIfMuted?: boolean;
isMe: boolean;
lastUpdated?: number;
// This is used by the CompositionInput for @mentions
sortedGroupMembers?: ReadonlyArray<ConversationType>;
title: string;
titleNoDefault?: string;
searchableTitle?: string;
unreadCount?: number;
isSelected?: boolean;
isFetchingUUID?: boolean;
typingContactId?: string;
recentMediaItems?: ReadonlyArray<MediaItemType>;
profileSharing?: boolean;
shouldShowDraft?: boolean;
draftText?: string;
draftBodyRanges?: DraftBodyRangesType;
draftPreview?: string;
shouldShowDraft?: boolean;
draftText?: string;
draftBodyRanges?: DraftBodyRangesType;
draftPreview?: string;
sharedGroupNames: ReadonlyArray<string>;
groupDescription?: string;
groupVersion?: 1 | 2;
groupId?: string;
groupLink?: string;
messageRequestsEnabled?: boolean;
acceptedMessageRequest: boolean;
secretParams?: string;
publicParams?: string;
profileKey?: string;
voiceNotePlaybackRate?: number;
sharedGroupNames: ReadonlyArray<string>;
groupDescription?: string;
groupVersion?: 1 | 2;
groupId?: string;
groupLink?: string;
messageRequestsEnabled?: boolean;
acceptedMessageRequest: boolean;
secretParams?: string;
publicParams?: string;
profileKey?: string;
voiceNotePlaybackRate?: number;
badges: ReadonlyArray<
badges: ReadonlyArray<
| {
id: string;
}
| {
id: string;
expiresAt: number;
isVisible: boolean;
}
>;
} & (
| {
id: string;
type: 'direct';
storySendMode?: undefined;
acknowledgedGroupNameCollisions?: undefined;
}
| {
id: string;
expiresAt: number;
isVisible: boolean;
type: 'group';
storySendMode: StorySendMode;
acknowledgedGroupNameCollisions: GroupNameCollisionsWithIdsByTitle;
}
>;
} & (
| {
type: 'direct';
storySendMode?: undefined;
acknowledgedGroupNameCollisions?: undefined;
}
| {
type: 'group';
storySendMode: StorySendMode;
acknowledgedGroupNameCollisions: GroupNameCollisionsWithIdsByTitle;
}
);
export type ProfileDataType = {
firstName: string;
} & Pick<ConversationType, 'aboutEmoji' | 'aboutText' | 'familyName'>;
)
>;
export type ProfileDataType = ReadonlyDeep<
{
firstName: string;
} & Pick<ConversationType, 'aboutEmoji' | 'aboutText' | 'familyName'>
>;
export type ConversationLookupType = {
export type ConversationLookupType = ReadonlyDeep<{
[key: string]: ConversationType;
};
export type CustomError = Error & {
identifier?: string;
number?: string;
};
}>;
export type CustomError = ReadonlyDeep<
Error & {
identifier?: string;
number?: string;
}
>;
type MessagePointerType = {
type MessagePointerType = ReadonlyDeep<{
id: string;
received_at: number;
sent_at?: number;
};
type MessageMetricsType = {
}>;
type MessageMetricsType = ReadonlyDeep<{
newest?: MessagePointerType;
oldest?: MessagePointerType;
oldestUnseen?: MessagePointerType;
totalUnseen: number;
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type MessageLookupType = {
[key: string]: MessageWithUIFieldsType;
};
export type ConversationMessageType = {
export type ConversationMessageType = ReadonlyDeep<{
isNearBottom?: boolean;
messageChangeCounter: number;
messageIds: ReadonlyArray<string>;
@ -337,13 +349,13 @@ export type ConversationMessageType = {
metrics: MessageMetricsType;
scrollToMessageId?: string;
scrollToMessageCounter: number;
};
}>;
export type MessagesByConversationType = {
export type MessagesByConversationType = ReadonlyDeep<{
[key: string]: ConversationMessageType | undefined;
};
}>;
export type PreJoinConversationType = {
export type PreJoinConversationType = ReadonlyDeep<{
avatar?: {
loading?: boolean;
url?: string;
@ -352,9 +364,9 @@ export type PreJoinConversationType = {
memberCount: number;
title: string;
approvalRequired: boolean;
};
}>;
type ComposerGroupCreationState = {
type ComposerGroupCreationState = ReadonlyDeep<{
groupAvatar: undefined | Uint8Array;
groupName: string;
groupExpireTimer: DurationInSeconds;
@ -362,13 +374,13 @@ type ComposerGroupCreationState = {
recommendedGroupSizeModalState: OneTimeModalState;
selectedConversationIds: ReadonlyArray<string>;
userAvatarData: ReadonlyArray<AvatarDataType>;
};
}>;
type DistributionVerificationData = {
uuidsNeedingVerification: ReadonlyArray<UUIDStringType>;
};
type DistributionVerificationData = ReadonlyDeep<{
uuidsNeedingVerification: Array<UUIDStringType>;
}>;
export type ConversationVerificationData =
export type ConversationVerificationData = ReadonlyDeep<
| {
type: ConversationVerificationState.PendingVerification;
uuidsNeedingVerification: ReadonlyArray<UUIDStringType>;
@ -378,14 +390,14 @@ export type ConversationVerificationData =
| {
type: ConversationVerificationState.VerificationCancelled;
canceledAt: number;
};
type VerificationDataByConversation = Record<
string,
ConversationVerificationData
}
>;
type ComposerStateType =
type VerificationDataByConversation = ReadonlyDeep<
Record<string, ConversationVerificationData>
>;
type ComposerStateType = ReadonlyDeep<
| {
step: ComposerStep.StartDirectConversation;
searchTerm: string;
@ -403,9 +415,10 @@ type ComposerStateType =
(
| { isCreating: false; hasError: boolean }
| { isCreating: true; hasError: false }
));
))
>;
type ContactSpoofingReviewStateType =
type ContactSpoofingReviewStateType = ReadonlyDeep<
| {
type: ContactSpoofingType.DirectConversationWithSameTitle;
safeConversationId: string;
@ -413,9 +426,11 @@ type ContactSpoofingReviewStateType =
| {
type: ContactSpoofingType.MultipleGroupMembersWithSameTitle;
groupConversationId: string;
};
}
>;
export type ConversationsStateType = {
// eslint-disable-next-line local-rules/type-alias-readonlydeep -- FIXME
export type ConversationsStateType = Readonly<{
preJoinConversation?: PreJoinConversationType;
invitedUuidsForNewlyCreatedGroup?: ReadonlyArray<string>;
conversationLookup: ConversationLookupType;
@ -444,7 +459,7 @@ export type ConversationsStateType = {
// Note: it's very important that both of these locations are always kept up to date
messagesLookup: MessageLookupType;
messagesByConversation: MessagesByConversationType;
};
}>;
// Helpers
@ -502,35 +517,37 @@ export const SET_VOICE_NOTE_PLAYBACK_RATE =
'conversations/SET_VOICE_NOTE_PLAYBACK_RATE';
export const CONVERSATION_UNLOADED = 'CONVERSATION_UNLOADED';
export type CancelVerificationDataByConversationActionType = {
export type CancelVerificationDataByConversationActionType = ReadonlyDeep<{
type: typeof CANCEL_CONVERSATION_PENDING_VERIFICATION;
payload: {
canceledAt: number;
};
};
type ClearGroupCreationErrorActionType = { type: 'CLEAR_GROUP_CREATION_ERROR' };
type ClearInvitedUuidsForNewlyCreatedGroupActionType = {
}>;
type ClearGroupCreationErrorActionType = ReadonlyDeep<{
type: 'CLEAR_GROUP_CREATION_ERROR';
}>;
type ClearInvitedUuidsForNewlyCreatedGroupActionType = ReadonlyDeep<{
type: 'CLEAR_INVITED_UUIDS_FOR_NEWLY_CREATED_GROUP';
};
type ClearVerificationDataByConversationActionType = {
}>;
type ClearVerificationDataByConversationActionType = ReadonlyDeep<{
type: typeof CLEAR_CONVERSATIONS_PENDING_VERIFICATION;
};
type ClearCancelledVerificationActionType = {
}>;
type ClearCancelledVerificationActionType = ReadonlyDeep<{
type: typeof CLEAR_CANCELLED_VERIFICATION;
payload: {
conversationId: string;
};
};
type CloseContactSpoofingReviewActionType = {
}>;
type CloseContactSpoofingReviewActionType = ReadonlyDeep<{
type: 'CLOSE_CONTACT_SPOOFING_REVIEW';
};
type CloseMaximumGroupSizeModalActionType = {
}>;
type CloseMaximumGroupSizeModalActionType = ReadonlyDeep<{
type: 'CLOSE_MAXIMUM_GROUP_SIZE_MODAL';
};
type CloseRecommendedGroupSizeModalActionType = {
}>;
type CloseRecommendedGroupSizeModalActionType = ReadonlyDeep<{
type: 'CLOSE_RECOMMENDED_GROUP_SIZE_MODAL';
};
type ColorsChangedActionType = {
}>;
type ColorsChangedActionType = ReadonlyDeep<{
type: typeof COLORS_CHANGED;
payload: {
conversationColor?: ConversationColorType;
@ -539,41 +556,41 @@ type ColorsChangedActionType = {
value: CustomColorType;
};
};
};
type ColorSelectedPayloadType = {
}>;
type ColorSelectedPayloadType = ReadonlyDeep<{
conversationId: string;
conversationColor?: ConversationColorType;
customColorData?: {
id: string;
value: CustomColorType;
};
};
export type ColorSelectedActionType = {
}>;
export type ColorSelectedActionType = ReadonlyDeep<{
type: typeof COLOR_SELECTED;
payload: ColorSelectedPayloadType;
};
type ComposeDeleteAvatarActionType = {
}>;
type ComposeDeleteAvatarActionType = ReadonlyDeep<{
type: typeof COMPOSE_REMOVE_AVATAR;
payload: AvatarDataType;
};
type ComposeReplaceAvatarsActionType = {
}>;
type ComposeReplaceAvatarsActionType = ReadonlyDeep<{
type: typeof COMPOSE_REPLACE_AVATAR;
payload: {
curr: AvatarDataType;
prev?: AvatarDataType;
};
};
type ComposeSaveAvatarActionType = {
}>;
type ComposeSaveAvatarActionType = ReadonlyDeep<{
type: typeof COMPOSE_ADD_AVATAR;
payload: AvatarDataType;
};
type CustomColorRemovedActionType = {
}>;
type CustomColorRemovedActionType = ReadonlyDeep<{
type: typeof CUSTOM_COLOR_REMOVED;
payload: {
colorId: string;
};
};
type DiscardMessagesActionType = {
}>;
type DiscardMessagesActionType = ReadonlyDeep<{
type: typeof DISCARD_MESSAGES;
payload: Readonly<
| {
@ -582,71 +599,72 @@ type DiscardMessagesActionType = {
}
| { conversationId: string; numberToKeepAtTop: number }
>;
};
type SetPreJoinConversationActionType = {
}>;
type SetPreJoinConversationActionType = ReadonlyDeep<{
type: 'SET_PRE_JOIN_CONVERSATION';
payload: {
data: PreJoinConversationType | undefined;
};
};
}>;
type ConversationAddedActionType = {
type ConversationAddedActionType = ReadonlyDeep<{
type: 'CONVERSATION_ADDED';
payload: {
id: string;
data: ConversationType;
};
};
export type ConversationChangedActionType = {
}>;
export type ConversationChangedActionType = ReadonlyDeep<{
type: 'CONVERSATION_CHANGED';
payload: {
id: string;
data: ConversationType;
};
};
export type ConversationRemovedActionType = {
}>;
export type ConversationRemovedActionType = ReadonlyDeep<{
type: 'CONVERSATION_REMOVED';
payload: {
id: string;
};
};
export type ConversationUnloadedActionType = {
}>;
export type ConversationUnloadedActionType = ReadonlyDeep<{
type: typeof CONVERSATION_UNLOADED;
payload: {
conversationId: string;
};
};
type CreateGroupPendingActionType = {
}>;
type CreateGroupPendingActionType = ReadonlyDeep<{
type: 'CREATE_GROUP_PENDING';
};
type CreateGroupFulfilledActionType = {
}>;
type CreateGroupFulfilledActionType = ReadonlyDeep<{
type: 'CREATE_GROUP_FULFILLED';
payload: {
invitedUuids: ReadonlyArray<UUIDStringType>;
};
};
type CreateGroupRejectedActionType = {
}>;
type CreateGroupRejectedActionType = ReadonlyDeep<{
type: 'CREATE_GROUP_REJECTED';
};
export type RemoveAllConversationsActionType = {
}>;
export type RemoveAllConversationsActionType = ReadonlyDeep<{
type: 'CONVERSATIONS_REMOVE_ALL';
payload: null;
};
export type MessageSelectedActionType = {
}>;
export type MessageSelectedActionType = ReadonlyDeep<{
type: 'MESSAGE_SELECTED';
payload: {
messageId: string;
conversationId: string;
};
};
type ConversationStoppedByMissingVerificationActionType = {
}>;
type ConversationStoppedByMissingVerificationActionType = ReadonlyDeep<{
type: typeof CONVERSATION_STOPPED_BY_MISSING_VERIFICATION;
payload: {
conversationId: string;
distributionId?: string;
untrustedUuids: ReadonlyArray<UUIDStringType>;
};
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep -- FIXME
export type MessageChangedActionType = {
type: typeof MESSAGE_CHANGED;
payload: {
@ -655,22 +673,23 @@ export type MessageChangedActionType = {
data: MessageAttributesType;
};
};
export type MessageDeletedActionType = {
export type MessageDeletedActionType = ReadonlyDeep<{
type: typeof MESSAGE_DELETED;
payload: {
id: string;
conversationId: string;
};
};
export type MessageExpandedActionType = {
}>;
export type MessageExpandedActionType = ReadonlyDeep<{
type: 'MESSAGE_EXPANDED';
payload: {
id: string;
displayLimit: number;
};
};
}>;
export type MessagesAddedActionType = {
// eslint-disable-next-line local-rules/type-alias-readonlydeep -- FIXME
export type MessagesAddedActionType = Readonly<{
type: 'MESSAGES_ADDED';
payload: {
conversationId: string;
@ -679,27 +698,28 @@ export type MessagesAddedActionType = {
isNewMessage: boolean;
messages: ReadonlyArray<MessageAttributesType>;
};
};
}>;
export type MessageExpiredActionType = {
export type MessageExpiredActionType = ReadonlyDeep<{
type: typeof MESSAGE_EXPIRED;
payload: {
id: string;
};
};
}>;
export type RepairNewestMessageActionType = {
export type RepairNewestMessageActionType = ReadonlyDeep<{
type: 'REPAIR_NEWEST_MESSAGE';
payload: {
conversationId: string;
};
};
export type RepairOldestMessageActionType = {
}>;
export type RepairOldestMessageActionType = ReadonlyDeep<{
type: 'REPAIR_OLDEST_MESSAGE';
payload: {
conversationId: string;
};
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type MessagesResetActionType = {
type: 'MESSAGES_RESET';
payload: {
@ -712,132 +732,135 @@ export type MessagesResetActionType = {
unboundedFetch: boolean;
};
};
export type SetMessageLoadingStateActionType = {
export type SetMessageLoadingStateActionType = ReadonlyDeep<{
type: 'SET_MESSAGE_LOADING_STATE';
payload: {
conversationId: string;
messageLoadingState: undefined | TimelineMessageLoadingState;
};
};
export type SetIsNearBottomActionType = {
}>;
export type SetIsNearBottomActionType = ReadonlyDeep<{
type: 'SET_NEAR_BOTTOM';
payload: {
conversationId: string;
isNearBottom: boolean;
};
};
export type ScrollToMessageActionType = {
}>;
export type ScrollToMessageActionType = ReadonlyDeep<{
type: 'SCROLL_TO_MESSAGE';
payload: {
conversationId: string;
messageId: string;
};
};
export type ClearSelectedMessageActionType = {
}>;
export type ClearSelectedMessageActionType = ReadonlyDeep<{
type: 'CLEAR_SELECTED_MESSAGE';
payload: null;
};
export type ClearUnreadMetricsActionType = {
}>;
export type ClearUnreadMetricsActionType = ReadonlyDeep<{
type: 'CLEAR_UNREAD_METRICS';
payload: {
conversationId: string;
};
};
export type SelectedConversationChangedActionType = {
}>;
export type SelectedConversationChangedActionType = ReadonlyDeep<{
type: typeof SELECTED_CONVERSATION_CHANGED;
payload: {
conversationId?: string;
messageId?: string;
switchToAssociatedView?: boolean;
};
};
type ReviewGroupMemberNameCollisionActionType = {
}>;
type ReviewGroupMemberNameCollisionActionType = ReadonlyDeep<{
type: 'REVIEW_GROUP_MEMBER_NAME_COLLISION';
payload: {
groupConversationId: string;
};
};
type ReviewMessageRequestNameCollisionActionType = {
}>;
type ReviewMessageRequestNameCollisionActionType = ReadonlyDeep<{
type: 'REVIEW_MESSAGE_REQUEST_NAME_COLLISION';
payload: {
safeConversationId: string;
};
};
type ShowInboxActionType = {
}>;
type ShowInboxActionType = ReadonlyDeep<{
type: 'SHOW_INBOX';
payload: null;
};
export type ShowArchivedConversationsActionType = {
}>;
export type ShowArchivedConversationsActionType = ReadonlyDeep<{
type: 'SHOW_ARCHIVED_CONVERSATIONS';
payload: null;
};
type SetComposeGroupAvatarActionType = {
}>;
type SetComposeGroupAvatarActionType = ReadonlyDeep<{
type: 'SET_COMPOSE_GROUP_AVATAR';
payload: { groupAvatar: undefined | Uint8Array };
};
type SetComposeGroupNameActionType = {
}>;
type SetComposeGroupNameActionType = ReadonlyDeep<{
type: 'SET_COMPOSE_GROUP_NAME';
payload: { groupName: string };
};
type SetComposeGroupExpireTimerActionType = {
}>;
type SetComposeGroupExpireTimerActionType = ReadonlyDeep<{
type: 'SET_COMPOSE_GROUP_EXPIRE_TIMER';
payload: { groupExpireTimer: DurationInSeconds };
};
type SetComposeSearchTermActionType = {
}>;
type SetComposeSearchTermActionType = ReadonlyDeep<{
type: 'SET_COMPOSE_SEARCH_TERM';
payload: { searchTerm: string };
};
type SetIsFetchingUUIDActionType = {
}>;
type SetIsFetchingUUIDActionType = ReadonlyDeep<{
type: 'SET_IS_FETCHING_UUID';
payload: {
identifier: UUIDFetchStateKeyType;
isFetching: boolean;
};
};
type SetRecentMediaItemsActionType = {
}>;
type SetRecentMediaItemsActionType = ReadonlyDeep<{
type: 'SET_RECENT_MEDIA_ITEMS';
payload: {
id: string;
recentMediaItems: ReadonlyArray<MediaItemType>;
};
};
type ToggleComposeEditingAvatarActionType = {
}>;
type ToggleComposeEditingAvatarActionType = ReadonlyDeep<{
type: typeof COMPOSE_TOGGLE_EDITING_AVATAR;
};
type StartComposingActionType = {
}>;
type StartComposingActionType = ReadonlyDeep<{
type: 'START_COMPOSING';
};
type ShowChooseGroupMembersActionType = {
}>;
type ShowChooseGroupMembersActionType = ReadonlyDeep<{
type: 'SHOW_CHOOSE_GROUP_MEMBERS';
};
type StartSettingGroupMetadataActionType = {
}>;
type StartSettingGroupMetadataActionType = ReadonlyDeep<{
type: 'START_SETTING_GROUP_METADATA';
};
export type ToggleConversationInChooseMembersActionType = {
}>;
export type ToggleConversationInChooseMembersActionType = ReadonlyDeep<{
type: 'TOGGLE_CONVERSATION_IN_CHOOSE_MEMBERS';
payload: {
conversationId: string;
maxRecommendedGroupSize: number;
maxGroupSize: number;
};
};
type PushPanelActionType = {
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep -- FIXME
type PushPanelActionType = Readonly<{
type: typeof PUSH_PANEL;
payload: PanelRenderType;
};
type PopPanelActionType = {
}>;
type PopPanelActionType = ReadonlyDeep<{
type: typeof POP_PANEL;
payload: null;
};
}>;
type ReplaceAvatarsActionType = {
type ReplaceAvatarsActionType = ReadonlyDeep<{
type: typeof REPLACE_AVATARS;
payload: {
conversationId: string;
avatars: ReadonlyArray<AvatarDataType>;
};
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep -- FIXME
export type ConversationActionType =
| CancelVerificationDataByConversationActionType
| ClearCancelledVerificationActionType
@ -1109,7 +1132,7 @@ function onMoveToInbox(conversationId: string): ShowToastActionType {
function acknowledgeGroupMemberNameCollisions(
conversationId: string,
groupNameCollisions: Readonly<GroupNameCollisionsWithIdsByTitle>
groupNameCollisions: ReadonlyDeep<GroupNameCollisionsWithIdsByTitle>
): NoopActionType {
const conversation = window.ConversationController.get(conversationId);
if (!conversation) {
@ -1907,10 +1930,10 @@ function kickOffAttachmentDownload(
};
}
type AttachmentOptions = {
type AttachmentOptions = ReadonlyDeep<{
messageId: string;
attachment: AttachmentType;
};
}>;
function markAttachmentAsCorrupted(
options: AttachmentOptions
@ -2512,13 +2535,14 @@ function reviewMessageRequestNameCollision(
return { type: 'REVIEW_MESSAGE_REQUEST_NAME_COLLISION', payload };
}
export type MessageResetOptionsType = Readonly<{
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type MessageResetOptionsType = {
conversationId: string;
messages: ReadonlyArray<MessageAttributesType>;
metrics: MessageMetricsType;
scrollToMessageId?: string;
unboundedFetch?: boolean;
}>;
};
function messagesReset({
conversationId,
@ -2583,9 +2607,9 @@ function setIsFetchingUUID(
};
}
export type PushPanelForConversationActionType = (
panel: PanelRequestType
) => unknown;
export type PushPanelForConversationActionType = ReadonlyDeep<
(panel: PanelRequestType) => unknown
>;
function pushPanelForConversation(
panel: PanelRequestType
@ -2619,7 +2643,7 @@ function pushPanelForConversation(
};
}
export type PopPanelForConversationActionType = () => unknown;
export type PopPanelForConversationActionType = ReadonlyDeep<() => unknown>;
function popPanelForConversation(): ThunkAction<
void,
@ -3016,11 +3040,9 @@ function loadRecentMediaItems(
};
}
export type SaveAttachmentActionCreatorType = (
attachment: AttachmentType,
timestamp?: number,
index?: number
) => unknown;
export type SaveAttachmentActionCreatorType = ReadonlyDeep<
(attachment: AttachmentType, timestamp?: number, index?: number) => unknown
>;
function saveAttachment(
attachment: AttachmentType,
@ -3475,14 +3497,14 @@ function showInbox(): ShowInboxActionType {
};
}
type ShowConversationArgsType = {
type ShowConversationArgsType = ReadonlyDeep<{
conversationId?: string;
messageId?: string;
switchToAssociatedView?: boolean;
};
export type ShowConversationType = (
options: ShowConversationArgsType
) => unknown;
}>;
export type ShowConversationType = ReadonlyDeep<
(options: ShowConversationArgsType) => unknown
>;
function showConversation({
conversationId,
@ -3858,10 +3880,12 @@ function getVerificationDataForConversation({
}
// Return same data, and we do nothing. Return undefined, and we'll delete the list.
type DistributionVisitor = (
id: string,
data: DistributionVerificationData
) => DistributionVerificationData | undefined;
type DistributionVisitor = ReadonlyDeep<
(
id: string,
data: DistributionVerificationData
) => DistributionVerificationData | undefined
>;
function visitListsInVerificationData(
existing: VerificationDataByConversation,

View file

@ -1,6 +1,7 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { ReadonlyDeep } from 'type-fest';
import * as log from '../../logging/log';
import { showToast } from '../../util/showToast';
import * as Errors from '../../types/errors';
@ -10,10 +11,10 @@ import type { PromiseAction } from '../util';
// State
export type CrashReportsStateType = {
export type CrashReportsStateType = ReadonlyDeep<{
count: number;
isPending: boolean;
};
}>;
// Actions
@ -21,15 +22,16 @@ const SET_COUNT = 'crashReports/SET_COUNT';
const UPLOAD = 'crashReports/UPLOAD';
const ERASE = 'crashReports/ERASE';
type SetCrashReportCountActionType = {
type SetCrashReportCountActionType = ReadonlyDeep<{
type: typeof SET_COUNT;
payload: number;
};
}>;
type CrashReportsActionType =
type CrashReportsActionType = ReadonlyDeep<
| SetCrashReportCountActionType
| PromiseAction<typeof UPLOAD>
| PromiseAction<typeof ERASE>;
| PromiseAction<typeof ERASE>
>;
// Action Creators

View file

@ -3,6 +3,7 @@
import { take, uniq } from 'lodash';
import type { ThunkAction } from 'redux-thunk';
import type { ReadonlyDeep } from 'type-fest';
import type { EmojiPickDataType } from '../../components/emoji/EmojiPicker';
import dataInterface from '../../sql/Client';
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
@ -12,18 +13,18 @@ const { updateEmojiUsage } = dataInterface;
// State
export type EmojisStateType = {
readonly recents: Array<string>;
};
export type EmojisStateType = ReadonlyDeep<{
recents: Array<string>;
}>;
// Actions
type UseEmojiAction = {
type UseEmojiAction = ReadonlyDeep<{
type: 'emojis/USE_EMOJI';
payload: string;
};
}>;
type EmojisActionType = UseEmojiAction;
type EmojisActionType = ReadonlyDeep<UseEmojiAction>;
// Action Creators
@ -64,8 +65,8 @@ function getEmptyState(): EmojisStateType {
}
export function reducer(
state: Readonly<EmojisStateType> = getEmptyState(),
action: Readonly<EmojisActionType>
state: EmojisStateType = getEmptyState(),
action: EmojisActionType
): EmojisStateType {
if (action.type === 'emojis/USE_EMOJI') {
const { payload } = action;

View file

@ -1,22 +1,25 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { ReadonlyDeep } from 'type-fest';
// State
export type ExpirationStateType = {
export type ExpirationStateType = ReadonlyDeep<{
hasExpired: boolean;
};
}>;
// Actions
const HYDRATE_EXPIRATION_STATUS = 'expiration/HYDRATE_EXPIRATION_STATUS';
type HyrdateExpirationStatusActionType = {
type HyrdateExpirationStatusActionType = ReadonlyDeep<{
type: 'expiration/HYDRATE_EXPIRATION_STATUS';
payload: boolean;
};
}>;
export type ExpirationActionType = HyrdateExpirationStatusActionType;
export type ExpirationActionType =
ReadonlyDeep<HyrdateExpirationStatusActionType>;
// Action Creators

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import type { ThunkAction } from 'redux-thunk';
import type { ReadonlyDeep } from 'type-fest';
import type { ExplodePromiseResultType } from '../../util/explodePromise';
import type { GroupV2PendingMemberType } from '../../model-types.d';
import type { PropsForMessage } from '../selectors/message';
@ -21,24 +22,23 @@ import { getGroupMigrationMembers } from '../../groups';
// State
export type ForwardMessagePropsType = Omit<
PropsForMessage,
'renderingContext' | 'menu' | 'contextMenu'
export type ForwardMessagePropsType = ReadonlyDeep<
Omit<PropsForMessage, 'renderingContext' | 'menu' | 'contextMenu'>
>;
export type SafetyNumberChangedBlockingDataType = Readonly<{
export type SafetyNumberChangedBlockingDataType = ReadonlyDeep<{
promiseUuid: UUIDStringType;
source?: SafetyNumberChangeSource;
}>;
type MigrateToGV2PropsType = {
type MigrateToGV2PropsType = ReadonlyDeep<{
areWeInvited: boolean;
conversationId: string;
droppedMemberIds: ReadonlyArray<string>;
droppedMemberIds: Array<string>;
hasMigrated: boolean;
invitedMemberIds: ReadonlyArray<string>;
};
invitedMemberIds: Array<string>;
}>;
export type GlobalModalsStateType = Readonly<{
export type GlobalModalsStateType = ReadonlyDeep<{
addUserToAnotherGroupModalContactId?: string;
contactModalState?: ContactModalStateType;
errorModalProps?: {
@ -90,12 +90,12 @@ const SHOW_ERROR_MODAL = 'globalModals/SHOW_ERROR_MODAL';
const CLOSE_SHORTCUT_GUIDE_MODAL = 'globalModals/CLOSE_SHORTCUT_GUIDE_MODAL';
const SHOW_SHORTCUT_GUIDE_MODAL = 'globalModals/SHOW_SHORTCUT_GUIDE_MODAL';
export type ContactModalStateType = {
export type ContactModalStateType = ReadonlyDeep<{
contactId: string;
conversationId?: string;
};
}>;
export type UserNotFoundModalStateType =
export type UserNotFoundModalStateType = ReadonlyDeep<
| {
type: 'phoneNumber';
phoneNumber: string;
@ -103,119 +103,120 @@ export type UserNotFoundModalStateType =
| {
type: 'username';
username: string;
};
}
>;
type HideContactModalActionType = {
type HideContactModalActionType = ReadonlyDeep<{
type: typeof HIDE_CONTACT_MODAL;
};
}>;
type ShowContactModalActionType = {
type ShowContactModalActionType = ReadonlyDeep<{
type: typeof SHOW_CONTACT_MODAL;
payload: ContactModalStateType;
};
}>;
type HideWhatsNewModalActionType = {
type HideWhatsNewModalActionType = ReadonlyDeep<{
type: typeof HIDE_WHATS_NEW_MODAL;
};
}>;
type ShowWhatsNewModalActionType = {
type ShowWhatsNewModalActionType = ReadonlyDeep<{
type: typeof SHOW_WHATS_NEW_MODAL;
};
}>;
type HideUserNotFoundModalActionType = {
type HideUserNotFoundModalActionType = ReadonlyDeep<{
type: typeof HIDE_UUID_NOT_FOUND_MODAL;
};
}>;
export type ShowUserNotFoundModalActionType = {
export type ShowUserNotFoundModalActionType = ReadonlyDeep<{
type: typeof SHOW_UUID_NOT_FOUND_MODAL;
payload: UserNotFoundModalStateType;
};
}>;
type ToggleForwardMessageModalActionType = {
type ToggleForwardMessageModalActionType = ReadonlyDeep<{
type: typeof TOGGLE_FORWARD_MESSAGE_MODAL;
payload: ForwardMessagePropsType | undefined;
};
}>;
type ToggleProfileEditorActionType = {
type ToggleProfileEditorActionType = ReadonlyDeep<{
type: typeof TOGGLE_PROFILE_EDITOR;
};
}>;
export type ToggleProfileEditorErrorActionType = {
export type ToggleProfileEditorErrorActionType = ReadonlyDeep<{
type: typeof TOGGLE_PROFILE_EDITOR_ERROR;
};
}>;
type ToggleSafetyNumberModalActionType = {
type ToggleSafetyNumberModalActionType = ReadonlyDeep<{
type: typeof TOGGLE_SAFETY_NUMBER_MODAL;
payload: string | undefined;
};
}>;
type ToggleAddUserToAnotherGroupModalActionType = {
type ToggleAddUserToAnotherGroupModalActionType = ReadonlyDeep<{
type: typeof TOGGLE_ADD_USER_TO_ANOTHER_GROUP_MODAL;
payload: string | undefined;
};
}>;
type ToggleSignalConnectionsModalActionType = {
type ToggleSignalConnectionsModalActionType = ReadonlyDeep<{
type: typeof TOGGLE_SIGNAL_CONNECTIONS_MODAL;
};
}>;
type ShowStoriesSettingsActionType = {
type ShowStoriesSettingsActionType = ReadonlyDeep<{
type: typeof SHOW_STORIES_SETTINGS;
};
}>;
type HideStoriesSettingsActionType = {
type HideStoriesSettingsActionType = ReadonlyDeep<{
type: typeof HIDE_STORIES_SETTINGS;
};
}>;
type StartMigrationToGV2ActionType = {
type StartMigrationToGV2ActionType = ReadonlyDeep<{
type: typeof SHOW_GV2_MIGRATION_DIALOG;
payload: MigrateToGV2PropsType;
};
}>;
type CloseGV2MigrationDialogActionType = {
type CloseGV2MigrationDialogActionType = ReadonlyDeep<{
type: typeof CLOSE_GV2_MIGRATION_DIALOG;
};
}>;
export type ShowSendAnywayDialogActionType = {
export type ShowSendAnywayDialogActionType = ReadonlyDeep<{
type: typeof SHOW_SEND_ANYWAY_DIALOG;
payload: SafetyNumberChangedBlockingDataType & {
untrustedByConversation: RecipientsByConversation;
};
};
}>;
type HideSendAnywayDialogActiontype = {
type HideSendAnywayDialogActiontype = ReadonlyDeep<{
type: typeof HIDE_SEND_ANYWAY_DIALOG;
};
}>;
export type ShowStickerPackPreviewActionType = {
export type ShowStickerPackPreviewActionType = ReadonlyDeep<{
type: typeof SHOW_STICKER_PACK_PREVIEW;
payload: string;
};
}>;
type CloseStickerPackPreviewActionType = {
type CloseStickerPackPreviewActionType = ReadonlyDeep<{
type: typeof CLOSE_STICKER_PACK_PREVIEW;
};
}>;
type CloseErrorModalActionType = {
type CloseErrorModalActionType = ReadonlyDeep<{
type: typeof CLOSE_ERROR_MODAL;
};
}>;
type ShowErrorModalActionType = {
type ShowErrorModalActionType = ReadonlyDeep<{
type: typeof SHOW_ERROR_MODAL;
payload: {
description?: string;
title?: string;
};
};
}>;
type CloseShortcutGuideModalActionType = {
type CloseShortcutGuideModalActionType = ReadonlyDeep<{
type: typeof CLOSE_SHORTCUT_GUIDE_MODAL;
};
}>;
type ShowShortcutGuideModalActionType = {
type ShowShortcutGuideModalActionType = ReadonlyDeep<{
type: typeof SHOW_SHORTCUT_GUIDE_MODAL;
};
}>;
export type GlobalModalsActionType =
export type GlobalModalsActionType = ReadonlyDeep<
| StartMigrationToGV2ActionType
| CloseGV2MigrationDialogActionType
| HideContactModalActionType
@ -239,7 +240,8 @@ export type GlobalModalsActionType =
| ToggleProfileEditorErrorActionType
| ToggleSafetyNumberModalActionType
| ToggleAddUserToAnotherGroupModalActionType
| ToggleSignalConnectionsModalActionType;
| ToggleSignalConnectionsModalActionType
>;
// Action Creators

View file

@ -4,6 +4,7 @@
import { omit } from 'lodash';
import { v4 as getGuid } from 'uuid';
import type { ThunkAction } from 'redux-thunk';
import type { ReadonlyDeep } from 'type-fest';
import type { StateType as RootStateType } from '../reducer';
import * as storageShim from '../../shims/storage';
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
@ -23,60 +24,61 @@ import type { ConfigMapType as RemoteConfigType } from '../../RemoteConfig';
// State
export type ItemsStateType = {
readonly universalExpireTimer?: number;
export type ItemsStateType = ReadonlyDeep<{
universalExpireTimer?: number;
readonly [key: string]: unknown;
[key: string]: unknown;
readonly remoteConfig?: RemoteConfigType;
remoteConfig?: RemoteConfigType;
// This property should always be set and this is ensured in background.ts
readonly defaultConversationColor?: DefaultConversationColorType;
defaultConversationColor?: DefaultConversationColorType;
readonly customColors?: CustomColorsItemType;
customColors?: CustomColorsItemType;
readonly preferredLeftPaneWidth?: number;
preferredLeftPaneWidth?: number;
readonly preferredReactionEmoji?: ReadonlyArray<string>;
preferredReactionEmoji?: Array<string>;
readonly areWeASubscriber?: boolean;
};
areWeASubscriber?: boolean;
}>;
// Actions
type ItemPutAction = {
type ItemPutAction = ReadonlyDeep<{
type: 'items/PUT';
payload: null;
};
}>;
type ItemPutExternalAction = {
type ItemPutExternalAction = ReadonlyDeep<{
type: 'items/PUT_EXTERNAL';
payload: {
key: string;
value: unknown;
};
};
}>;
type ItemRemoveAction = {
type ItemRemoveAction = ReadonlyDeep<{
type: 'items/REMOVE';
payload: null;
};
}>;
type ItemRemoveExternalAction = {
type ItemRemoveExternalAction = ReadonlyDeep<{
type: 'items/REMOVE_EXTERNAL';
payload: string;
};
}>;
type ItemsResetAction = {
type ItemsResetAction = ReadonlyDeep<{
type: 'items/RESET';
};
}>;
export type ItemsActionType =
export type ItemsActionType = ReadonlyDeep<
| ItemPutAction
| ItemPutExternalAction
| ItemRemoveAction
| ItemRemoveExternalAction
| ItemsResetAction;
| ItemsResetAction
>;
// Action Creators

View file

@ -3,6 +3,7 @@
import type { ThunkAction } from 'redux-thunk';
import type { ReadonlyDeep } from 'type-fest';
import type { AttachmentType } from '../../types/Attachment';
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
import type { MediaItemType } from '../../types/MediaItem';
@ -34,6 +35,7 @@ import {
import { showStickerPackPreview } from './globalModals';
import { useBoundActions } from '../../hooks/useBoundActions';
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type LightboxStateType =
| {
isShowingLightbox: false;
@ -41,26 +43,28 @@ export type LightboxStateType =
| {
isShowingLightbox: true;
isViewOnce: boolean;
media: ReadonlyArray<MediaItemType>;
media: ReadonlyArray<ReadonlyDeep<MediaItemType>>;
selectedAttachmentPath: string | undefined;
};
const CLOSE_LIGHTBOX = 'lightbox/CLOSE';
const SHOW_LIGHTBOX = 'lightbox/SHOW';
type CloseLightboxActionType = {
type CloseLightboxActionType = ReadonlyDeep<{
type: typeof CLOSE_LIGHTBOX;
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
type ShowLightboxActionType = {
type: typeof SHOW_LIGHTBOX;
payload: {
isViewOnce: boolean;
media: ReadonlyArray<MediaItemType>;
media: ReadonlyArray<ReadonlyDeep<MediaItemType>>;
selectedAttachmentPath: string | undefined;
};
};
// eslint-disable-next-line local-rules/type-alias-readonlydeep
type LightboxActionType =
| CloseLightboxActionType
| MessageChangedActionType
@ -100,7 +104,7 @@ function closeLightbox(): ThunkAction<
function showLightboxWithMedia(
selectedAttachmentPath: string | undefined,
media: ReadonlyArray<MediaItemType>
media: ReadonlyArray<ReadonlyDeep<MediaItemType>>
): ShowLightboxActionType {
return {
type: SHOW_LIGHTBOX,

View file

@ -3,6 +3,7 @@
import type { ThunkAction } from 'redux-thunk';
import type { ReadonlyDeep } from 'type-fest';
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
import type { LinkPreviewType } from '../../types/message/LinkPreviews';
import type { MaybeGrabLinkPreviewOptionsType } from '../../types/LinkPreview';
@ -16,35 +17,35 @@ import { useBoundActions } from '../../hooks/useBoundActions';
// State
export type LinkPreviewsStateType = {
readonly linkPreview?: LinkPreviewType;
readonly source?: LinkPreviewSourceType;
};
export type LinkPreviewsStateType = ReadonlyDeep<{
linkPreview?: LinkPreviewType;
source?: LinkPreviewSourceType;
}>;
// Actions
export const ADD_PREVIEW = 'linkPreviews/ADD_PREVIEW';
export const REMOVE_PREVIEW = 'linkPreviews/REMOVE_PREVIEW';
export type AddLinkPreviewActionType = {
export type AddLinkPreviewActionType = ReadonlyDeep<{
type: 'linkPreviews/ADD_PREVIEW';
payload: {
conversationId?: string;
linkPreview: LinkPreviewType;
source: LinkPreviewSourceType;
};
};
}>;
export type RemoveLinkPreviewActionType = {
export type RemoveLinkPreviewActionType = ReadonlyDeep<{
type: 'linkPreviews/REMOVE_PREVIEW';
payload: {
conversationId?: string;
};
};
}>;
type LinkPreviewsActionType =
| AddLinkPreviewActionType
| RemoveLinkPreviewActionType;
type LinkPreviewsActionType = ReadonlyDeep<
AddLinkPreviewActionType | RemoveLinkPreviewActionType
>;
// Action Creators

View file

@ -27,6 +27,7 @@ import { isDownloading, hasFailed } from '../../types/Attachment';
import { isNotNil } from '../../util/isNotNil';
import { useBoundActions } from '../../hooks/useBoundActions';
// eslint-disable-next-line local-rules/type-alias-readonlydeep
type MediaType = {
path: string;
objectURL: string;
@ -44,6 +45,7 @@ type MediaType = {
};
};
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type MediaGalleryStateType = {
documents: Array<MediaItemType>;
media: Array<MediaType>;
@ -51,6 +53,7 @@ export type MediaGalleryStateType = {
const LOAD_MEDIA_ITEMS = 'mediaGallery/LOAD_MEDIA_ITEMS';
// eslint-disable-next-line local-rules/type-alias-readonlydeep
type LoadMediaItemslActionType = {
type: typeof LOAD_MEDIA_ITEMS;
payload: {
@ -59,6 +62,7 @@ type LoadMediaItemslActionType = {
};
};
// eslint-disable-next-line local-rules/type-alias-readonlydeep
type MediaGalleryActionType =
| ConversationUnloadedActionType
| LoadMediaItemslActionType

View file

@ -1,18 +1,19 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { ReadonlyDeep } from 'type-fest';
import { SocketStatus } from '../../types/SocketStatus';
import { trigger } from '../../shims/events';
import { assignWithNoUnnecessaryAllocation } from '../../util/assignWithNoUnnecessaryAllocation';
// State
export type NetworkStateType = {
export type NetworkStateType = ReadonlyDeep<{
isOnline: boolean;
socketStatus: SocketStatus;
withinConnectingGracePeriod: boolean;
challengeStatus: 'required' | 'pending' | 'idle';
};
}>;
// Actions
@ -21,36 +22,37 @@ const CLOSE_CONNECTING_GRACE_PERIOD = 'network/CLOSE_CONNECTING_GRACE_PERIOD';
const RELINK_DEVICE = 'network/RELINK_DEVICE';
const SET_CHALLENGE_STATUS = 'network/SET_CHALLENGE_STATUS';
export type CheckNetworkStatusPayloadType = {
export type CheckNetworkStatusPayloadType = ReadonlyDeep<{
isOnline: boolean;
socketStatus: SocketStatus;
};
}>;
type CheckNetworkStatusAction = {
type CheckNetworkStatusAction = ReadonlyDeep<{
type: 'network/CHECK_NETWORK_STATUS';
payload: CheckNetworkStatusPayloadType;
};
}>;
type CloseConnectingGracePeriodActionType = {
type CloseConnectingGracePeriodActionType = ReadonlyDeep<{
type: 'network/CLOSE_CONNECTING_GRACE_PERIOD';
};
}>;
type RelinkDeviceActionType = {
type RelinkDeviceActionType = ReadonlyDeep<{
type: 'network/RELINK_DEVICE';
};
}>;
type SetChallengeStatusActionType = {
type SetChallengeStatusActionType = ReadonlyDeep<{
type: 'network/SET_CHALLENGE_STATUS';
payload: {
challengeStatus: NetworkStateType['challengeStatus'];
};
};
}>;
export type NetworkActionType =
export type NetworkActionType = ReadonlyDeep<
| CheckNetworkStatusAction
| CloseConnectingGracePeriodActionType
| RelinkDeviceActionType
| SetChallengeStatusActionType;
| SetChallengeStatusActionType
>;
// Action Creators

View file

@ -1,10 +1,12 @@
// Copyright 2019 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
export type NoopActionType = {
import type { ReadonlyDeep } from 'type-fest';
export type NoopActionType = ReadonlyDeep<{
type: 'NOOP';
payload: null;
};
}>;
export function noopAction(): NoopActionType {
return {

View file

@ -3,6 +3,7 @@
import type { ThunkAction } from 'redux-thunk';
import { omit } from 'lodash';
import type { ReadonlyDeep } from 'type-fest';
import * as log from '../../logging/log';
import * as Errors from '../../types/errors';
import { replaceIndex } from '../../util/replaceIndex';
@ -16,7 +17,7 @@ import { convertShortName } from '../../components/emoji/lib';
// State
export type PreferredReactionsStateType = {
export type PreferredReactionsStateType = ReadonlyDeep<{
customizePreferredReactionsModal?: {
draftPreferredReactions: Array<string>;
originalPreferredReactions: Array<string>;
@ -25,7 +26,7 @@ export type PreferredReactionsStateType = {
| { isSaving: true; hadSaveError: false }
| { isSaving: false; hadSaveError: boolean }
);
};
}>;
// Actions
@ -46,45 +47,47 @@ const SAVE_PREFERRED_REACTIONS_REJECTED =
const SELECT_DRAFT_EMOJI_TO_BE_REPLACED =
'preferredReactions/SELECT_DRAFT_EMOJI_TO_BE_REPLACED';
type CancelCustomizePreferredReactionsModalActionType = {
type CancelCustomizePreferredReactionsModalActionType = ReadonlyDeep<{
type: typeof CANCEL_CUSTOMIZE_PREFERRED_REACTIONS_MODAL;
};
}>;
type DeselectDraftEmojiActionType = { type: typeof DESELECT_DRAFT_EMOJI };
type DeselectDraftEmojiActionType = ReadonlyDeep<{
type: typeof DESELECT_DRAFT_EMOJI;
}>;
type OpenCustomizePreferredReactionsModalActionType = {
type OpenCustomizePreferredReactionsModalActionType = ReadonlyDeep<{
type: typeof OPEN_CUSTOMIZE_PREFERRED_REACTIONS_MODAL;
payload: {
originalPreferredReactions: Array<string>;
};
};
}>;
type ReplaceSelectedDraftEmojiActionType = {
type ReplaceSelectedDraftEmojiActionType = ReadonlyDeep<{
type: typeof REPLACE_SELECTED_DRAFT_EMOJI;
payload: string;
};
}>;
type ResetDraftEmojiActionType = {
type ResetDraftEmojiActionType = ReadonlyDeep<{
type: typeof RESET_DRAFT_EMOJI;
payload: { skinTone: number };
};
}>;
type SavePreferredReactionsFulfilledActionType = {
type SavePreferredReactionsFulfilledActionType = ReadonlyDeep<{
type: typeof SAVE_PREFERRED_REACTIONS_FULFILLED;
};
}>;
type SavePreferredReactionsPendingActionType = {
type SavePreferredReactionsPendingActionType = ReadonlyDeep<{
type: typeof SAVE_PREFERRED_REACTIONS_PENDING;
};
}>;
type SavePreferredReactionsRejectedActionType = {
type SavePreferredReactionsRejectedActionType = ReadonlyDeep<{
type: typeof SAVE_PREFERRED_REACTIONS_REJECTED;
};
}>;
type SelectDraftEmojiToBeReplacedActionType = {
type SelectDraftEmojiToBeReplacedActionType = ReadonlyDeep<{
type: typeof SELECT_DRAFT_EMOJI_TO_BE_REPLACED;
payload: number;
};
}>;
// Action creators

View file

@ -1,6 +1,7 @@
// Copyright 2020 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { ReadonlyDeep } from 'type-fest';
import { generateSecurityNumberBlock } from '../../util/safetyNumber';
import type { ConversationType } from './conversations';
import {
@ -10,17 +11,17 @@ import {
import * as log from '../../logging/log';
import * as Errors from '../../types/errors';
export type SafetyNumberContactType = {
export type SafetyNumberContactType = ReadonlyDeep<{
safetyNumber: string;
safetyNumberChanged?: boolean;
verificationDisabled: boolean;
};
}>;
export type SafetyNumberStateType = {
export type SafetyNumberStateType = ReadonlyDeep<{
contacts: {
[key: string]: SafetyNumberContactType;
};
};
}>;
const GENERATE = 'safetyNumber/GENERATE';
const GENERATE_FULFILLED = 'safetyNumber/GENERATE_FULFILLED';
@ -28,51 +29,52 @@ const TOGGLE_VERIFIED = 'safetyNumber/TOGGLE_VERIFIED';
const TOGGLE_VERIFIED_FULFILLED = 'safetyNumber/TOGGLE_VERIFIED_FULFILLED';
const TOGGLE_VERIFIED_PENDING = 'safetyNumber/TOGGLE_VERIFIED_PENDING';
type GenerateAsyncActionType = {
type GenerateAsyncActionType = ReadonlyDeep<{
contact: ConversationType;
safetyNumber: string;
};
}>;
type GenerateActionType = {
type GenerateActionType = ReadonlyDeep<{
type: 'safetyNumber/GENERATE';
payload: Promise<GenerateAsyncActionType>;
};
}>;
type GenerateFulfilledActionType = {
type GenerateFulfilledActionType = ReadonlyDeep<{
type: 'safetyNumber/GENERATE_FULFILLED';
payload: GenerateAsyncActionType;
};
}>;
type ToggleVerifiedAsyncActionType = {
type ToggleVerifiedAsyncActionType = ReadonlyDeep<{
contact: ConversationType;
safetyNumber?: string;
safetyNumberChanged?: boolean;
};
}>;
type ToggleVerifiedActionType = {
type ToggleVerifiedActionType = ReadonlyDeep<{
type: 'safetyNumber/TOGGLE_VERIFIED';
payload: {
data: { contact: ConversationType };
promise: Promise<ToggleVerifiedAsyncActionType>;
};
};
}>;
type ToggleVerifiedPendingActionType = {
type ToggleVerifiedPendingActionType = ReadonlyDeep<{
type: 'safetyNumber/TOGGLE_VERIFIED_PENDING';
payload: ToggleVerifiedAsyncActionType;
};
}>;
type ToggleVerifiedFulfilledActionType = {
type ToggleVerifiedFulfilledActionType = ReadonlyDeep<{
type: 'safetyNumber/TOGGLE_VERIFIED_FULFILLED';
payload: ToggleVerifiedAsyncActionType;
};
}>;
export type SafetyNumberActionType =
export type SafetyNumberActionType = ReadonlyDeep<
| GenerateActionType
| GenerateFulfilledActionType
| ToggleVerifiedActionType
| ToggleVerifiedPendingActionType
| ToggleVerifiedFulfilledActionType;
| ToggleVerifiedFulfilledActionType
>;
function generate(contact: ConversationType): GenerateActionType {
return {

View file

@ -4,6 +4,7 @@
import type { ThunkAction, ThunkDispatch } from 'redux-thunk';
import { debounce, omit, reject } from 'lodash';
import type { ReadonlyDeep } from 'type-fest';
import type { StateType as RootStateType } from '../reducer';
import { cleanSearchTerm } from '../../util/cleanSearchTerm';
import { filterAndSortConversationsByRecent } from '../../util/filterAndSortConversations';
@ -43,15 +44,17 @@ const {
// State
export type MessageSearchResultType = MessageType & {
snippet?: string;
};
export type MessageSearchResultType = ReadonlyDeep<
MessageType & {
snippet?: string;
}
>;
export type MessageSearchResultLookupType = {
export type MessageSearchResultLookupType = ReadonlyDeep<{
[id: string]: MessageSearchResultType;
};
}>;
export type SearchStateType = {
export type SearchStateType = ReadonlyDeep<{
startSearchCounter: number;
searchConversationId?: string;
contactIds: Array<string>;
@ -64,49 +67,49 @@ export type SearchStateType = {
// Loading state
discussionsLoading: boolean;
messagesLoading: boolean;
};
}>;
// Actions
type SearchMessagesResultsFulfilledActionType = {
type SearchMessagesResultsFulfilledActionType = ReadonlyDeep<{
type: 'SEARCH_MESSAGES_RESULTS_FULFILLED';
payload: {
messages: Array<MessageSearchResultType>;
query: string;
};
};
type SearchDiscussionsResultsFulfilledActionType = {
}>;
type SearchDiscussionsResultsFulfilledActionType = ReadonlyDeep<{
type: 'SEARCH_DISCUSSIONS_RESULTS_FULFILLED';
payload: {
conversationIds: Array<string>;
contactIds: Array<string>;
query: string;
};
};
type UpdateSearchTermActionType = {
}>;
type UpdateSearchTermActionType = ReadonlyDeep<{
type: 'SEARCH_UPDATE';
payload: {
query: string;
};
};
type StartSearchActionType = {
}>;
type StartSearchActionType = ReadonlyDeep<{
type: 'SEARCH_START';
payload: null;
};
type ClearSearchActionType = {
}>;
type ClearSearchActionType = ReadonlyDeep<{
type: 'SEARCH_CLEAR';
payload: null;
};
type ClearConversationSearchActionType = {
}>;
type ClearConversationSearchActionType = ReadonlyDeep<{
type: 'CLEAR_CONVERSATION_SEARCH';
payload: null;
};
type SearchInConversationActionType = {
}>;
type SearchInConversationActionType = ReadonlyDeep<{
type: 'SEARCH_IN_CONVERSATION';
payload: { searchConversationId: string };
};
}>;
export type SearchActionType =
export type SearchActionType = ReadonlyDeep<
| SearchMessagesResultsFulfilledActionType
| SearchDiscussionsResultsFulfilledActionType
| UpdateSearchTermActionType
@ -118,7 +121,8 @@ export type SearchActionType =
| RemoveAllConversationsActionType
| SelectedConversationChangedActionType
| ShowArchivedConversationsActionType
| ConversationUnloadedActionType;
| ConversationUnloadedActionType
>;
// Action Creators

View file

@ -3,6 +3,7 @@
import type { Dictionary } from 'lodash';
import { omit, reject } from 'lodash';
import type { ReadonlyDeep } from 'type-fest';
import type {
StickerPackStatusType,
StickerType as StickerDBType,
@ -24,23 +25,23 @@ const { getRecentStickers, updateStickerLastUsed } = dataInterface;
// State
export type StickersStateType = {
readonly installedPack: string | null;
readonly packs: Dictionary<StickerPackDBType>;
readonly recentStickers: Array<RecentStickerType>;
readonly blessedPacks: Dictionary<boolean>;
};
export type StickersStateType = ReadonlyDeep<{
installedPack: string | null;
packs: Dictionary<StickerPackDBType>;
recentStickers: Array<RecentStickerType>;
blessedPacks: Dictionary<boolean>;
}>;
// These are for the React components
export type StickerType = {
readonly id: number;
readonly packId: string;
readonly emoji?: string;
readonly url: string;
};
export type StickerType = ReadonlyDeep<{
id: number;
packId: string;
emoji?: string;
url: string;
}>;
export type StickerPackType = Readonly<{
export type StickerPackType = ReadonlyDeep<{
id: string;
key: string;
title: string;
@ -56,76 +57,76 @@ export type StickerPackType = Readonly<{
// Actions
type StickerPackAddedAction = {
type StickerPackAddedAction = ReadonlyDeep<{
type: 'stickers/STICKER_PACK_ADDED';
payload: StickerPackDBType;
};
}>;
type StickerAddedAction = {
type StickerAddedAction = ReadonlyDeep<{
type: 'stickers/STICKER_ADDED';
payload: StickerDBType;
};
}>;
type InstallStickerPackPayloadType = {
type InstallStickerPackPayloadType = ReadonlyDeep<{
packId: string;
fromSync: boolean;
status: 'installed';
installedAt: number;
recentStickers: Array<RecentStickerType>;
};
type InstallStickerPackAction = {
}>;
type InstallStickerPackAction = ReadonlyDeep<{
type: 'stickers/INSTALL_STICKER_PACK';
payload: Promise<InstallStickerPackPayloadType>;
};
type InstallStickerPackFulfilledAction = {
}>;
type InstallStickerPackFulfilledAction = ReadonlyDeep<{
type: 'stickers/INSTALL_STICKER_PACK_FULFILLED';
payload: InstallStickerPackPayloadType;
};
type ClearInstalledStickerPackAction = {
}>;
type ClearInstalledStickerPackAction = ReadonlyDeep<{
type: 'stickers/CLEAR_INSTALLED_STICKER_PACK';
};
}>;
type UninstallStickerPackPayloadType = {
type UninstallStickerPackPayloadType = ReadonlyDeep<{
packId: string;
fromSync: boolean;
status: 'downloaded';
installedAt?: undefined;
recentStickers: Array<RecentStickerType>;
};
type UninstallStickerPackAction = {
}>;
type UninstallStickerPackAction = ReadonlyDeep<{
type: 'stickers/UNINSTALL_STICKER_PACK';
payload: Promise<UninstallStickerPackPayloadType>;
};
type UninstallStickerPackFulfilledAction = {
}>;
type UninstallStickerPackFulfilledAction = ReadonlyDeep<{
type: 'stickers/UNINSTALL_STICKER_PACK_FULFILLED';
payload: UninstallStickerPackPayloadType;
};
}>;
type StickerPackUpdatedAction = {
type StickerPackUpdatedAction = ReadonlyDeep<{
type: 'stickers/STICKER_PACK_UPDATED';
payload: { packId: string; patch: Partial<StickerPackDBType> };
};
}>;
type StickerPackRemovedAction = {
type StickerPackRemovedAction = ReadonlyDeep<{
type: 'stickers/REMOVE_STICKER_PACK';
payload: string;
};
}>;
type UseStickerPayloadType = {
type UseStickerPayloadType = ReadonlyDeep<{
packId: string;
stickerId: number;
time: number;
};
type UseStickerAction = {
}>;
type UseStickerAction = ReadonlyDeep<{
type: 'stickers/USE_STICKER';
payload: Promise<UseStickerPayloadType>;
};
type UseStickerFulfilledAction = {
}>;
type UseStickerFulfilledAction = ReadonlyDeep<{
type: 'stickers/USE_STICKER_FULFILLED';
payload: UseStickerPayloadType;
};
}>;
export type StickersActionType =
export type StickersActionType = ReadonlyDeep<
| ClearInstalledStickerPackAction
| StickerAddedAction
| StickerPackAddedAction
@ -134,7 +135,8 @@ export type StickersActionType =
| StickerPackUpdatedAction
| StickerPackRemovedAction
| UseStickerFulfilledAction
| NoopActionType;
| NoopActionType
>;
// Action Creators

View file

@ -4,6 +4,7 @@
import type { ThunkAction, ThunkDispatch } from 'redux-thunk';
import { isEqual, pick } from 'lodash';
import type { ReadonlyDeep } from 'type-fest';
import * as Errors from '../../types/errors';
import type { AttachmentType } from '../../types/Attachment';
import type { DraftBodyRangesType } from '../../types/Util';
@ -60,44 +61,46 @@ import { SHOW_TOAST } from './toast';
import { ToastType } from '../../types/Toast';
import type { ShowToastActionType } from './toast';
export type StoryDataType = {
attachment?: AttachmentType;
hasReplies?: boolean;
hasRepliesFromSelf?: boolean;
messageId: string;
startedDownload?: boolean;
} & Pick<
MessageAttributesType,
| 'canReplyToStory'
| 'conversationId'
| 'deletedForEveryone'
| 'reactions'
| 'readAt'
| 'readStatus'
| 'sendStateByConversationId'
| 'source'
| 'sourceUuid'
| 'storyDistributionListId'
| 'timestamp'
| 'type'
| 'storyRecipientsVersion'
> & {
// don't want the fields to be optional as in MessageAttributesType
expireTimer: DurationInSeconds | undefined;
expirationStartTimestamp: number | undefined;
sourceDevice: number;
};
export type StoryDataType = ReadonlyDeep<
{
attachment?: AttachmentType;
hasReplies?: boolean;
hasRepliesFromSelf?: boolean;
messageId: string;
startedDownload?: boolean;
} & Pick<
MessageAttributesType,
| 'canReplyToStory'
| 'conversationId'
| 'deletedForEveryone'
| 'reactions'
| 'readAt'
| 'readStatus'
| 'sendStateByConversationId'
| 'source'
| 'sourceUuid'
| 'storyDistributionListId'
| 'timestamp'
| 'type'
| 'storyRecipientsVersion'
> & {
// don't want the fields to be optional as in MessageAttributesType
expireTimer: DurationInSeconds | undefined;
expirationStartTimestamp: number | undefined;
sourceDevice: number;
}
>;
export type SelectedStoryDataType = {
export type SelectedStoryDataType = ReadonlyDeep<{
currentIndex: number;
messageId: string;
numStories: number;
storyViewMode: StoryViewModeType;
unviewedStoryConversationIdsSorted: Array<string>;
viewTarget?: StoryViewTargetType;
};
}>;
export type AddStoryData =
export type AddStoryData = ReadonlyDeep<
| {
type: 'Media';
file: File;
@ -107,8 +110,10 @@ export type AddStoryData =
type: 'Text';
sending?: boolean;
}
| undefined;
| undefined
>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type RecipientsByConversation = Record<
string, // conversationId
{
@ -125,6 +130,7 @@ export type RecipientsByConversation = Record<
// State
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type StoriesStateType = Readonly<{
addStoryData: AddStoryData;
hasAllStoriesUnmuted: boolean;
@ -157,20 +163,21 @@ const SET_ADD_STORY_DATA = 'stories/SET_ADD_STORY_DATA';
const SET_STORY_SENDING = 'stories/SET_STORY_SENDING';
const SET_HAS_ALL_STORIES_UNMUTED = 'stories/SET_HAS_ALL_STORIES_UNMUTED';
type DOEStoryActionType = {
type DOEStoryActionType = ReadonlyDeep<{
type: typeof DOE_STORY;
payload: string;
};
}>;
type ListMembersVerified = {
type ListMembersVerified = ReadonlyDeep<{
type: typeof LIST_MEMBERS_VERIFIED;
payload: {
conversationId: string;
distributionId: string | undefined;
uuids: Array<UUIDStringType>;
};
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
type LoadStoryRepliesActionType = {
type: typeof LOAD_STORY_REPLIES;
payload: {
@ -179,62 +186,63 @@ type LoadStoryRepliesActionType = {
};
};
type MarkStoryReadActionType = {
type MarkStoryReadActionType = ReadonlyDeep<{
type: typeof MARK_STORY_READ;
payload: {
messageId: string;
readAt: number;
};
};
}>;
type QueueStoryDownloadActionType = {
type QueueStoryDownloadActionType = ReadonlyDeep<{
type: typeof QUEUE_STORY_DOWNLOAD;
payload: string;
};
}>;
type SendStoryModalOpenStateChanged = {
type SendStoryModalOpenStateChanged = ReadonlyDeep<{
type: typeof SEND_STORY_MODAL_OPEN_STATE_CHANGED;
payload: number | undefined;
};
}>;
type StoryChangedActionType = {
type StoryChangedActionType = ReadonlyDeep<{
type: typeof STORY_CHANGED;
payload: StoryDataType;
};
}>;
type ToggleViewActionType = {
type ToggleViewActionType = ReadonlyDeep<{
type: typeof TOGGLE_VIEW;
};
}>;
type ViewStoryActionType = {
type ViewStoryActionType = ReadonlyDeep<{
type: typeof VIEW_STORY;
payload: SelectedStoryDataType | undefined;
};
}>;
type StoryReplyDeletedActionType = {
type StoryReplyDeletedActionType = ReadonlyDeep<{
type: typeof STORY_REPLY_DELETED;
payload: string;
};
}>;
type RemoveAllStoriesActionType = {
type RemoveAllStoriesActionType = ReadonlyDeep<{
type: typeof REMOVE_ALL_STORIES;
};
}>;
type SetAddStoryDataType = {
type SetAddStoryDataType = ReadonlyDeep<{
type: typeof SET_ADD_STORY_DATA;
payload: AddStoryData;
};
}>;
type SetStorySendingType = {
type SetStorySendingType = ReadonlyDeep<{
type: typeof SET_STORY_SENDING;
payload: boolean;
};
}>;
type SetHasAllStoriesUnmutedType = {
type SetHasAllStoriesUnmutedType = ReadonlyDeep<{
type: typeof SET_HAS_ALL_STORIES_UNMUTED;
payload: boolean;
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type StoriesActionType =
| DOEStoryActionType
| ListMembersVerified
@ -817,11 +825,13 @@ const getSelectedStoryDataForConversationId = (
};
};
export type ViewUserStoriesActionCreatorType = (opts: {
conversationId: string;
storyViewMode?: StoryViewModeType;
viewTarget?: StoryViewTargetType;
}) => unknown;
export type ViewUserStoriesActionCreatorType = ReadonlyDeep<
(opts: {
conversationId: string;
storyViewMode?: StoryViewModeType;
viewTarget?: StoryViewTargetType;
}) => unknown
>;
const viewUserStories: ViewUserStoriesActionCreatorType = ({
conversationId,
@ -886,7 +896,7 @@ function removeAllStories(): RemoveAllStoriesActionType {
};
}
type ViewStoryOptionsType =
type ViewStoryOptionsType = ReadonlyDeep<
| {
closeViewer: true;
}
@ -895,15 +905,18 @@ type ViewStoryOptionsType =
storyViewMode: StoryViewModeType;
viewDirection?: StoryViewDirectionType;
viewTarget?: StoryViewTargetType;
};
}
>;
export type ViewStoryActionCreatorType = (
opts: ViewStoryOptionsType
) => unknown;
export type ViewStoryActionCreatorType = ReadonlyDeep<
(opts: ViewStoryOptionsType) => unknown
>;
export type DispatchableViewStoryType = (
opts: ViewStoryOptionsType
) => ThunkAction<void, RootStateType, unknown, ViewStoryActionType>;
export type DispatchableViewStoryType = ReadonlyDeep<
(
opts: ViewStoryOptionsType
) => ThunkAction<void, RootStateType, unknown, ViewStoryActionType>
>;
const viewStory: ViewStoryActionCreatorType = (
opts

View file

@ -4,6 +4,7 @@
import { omit } from 'lodash';
import type { ThunkAction } from 'redux-thunk';
import type { ReadonlyDeep } from 'type-fest';
import type { StateType as RootStateType } from '../reducer';
import type { StoryDistributionWithMembersType } from '../../sql/Interface';
import type { UUIDStringType } from '../../types/UUID';
@ -19,18 +20,18 @@ import { useBoundActions } from '../../hooks/useBoundActions';
// State
export type StoryDistributionListDataType = {
export type StoryDistributionListDataType = ReadonlyDeep<{
id: UUIDStringType;
deletedAtTimestamp?: number;
name: string;
allowsReplies: boolean;
isBlockList: boolean;
memberUuids: Array<UUIDStringType>;
};
}>;
export type StoryDistributionListStateType = {
export type StoryDistributionListStateType = ReadonlyDeep<{
distributionLists: Array<StoryDistributionListDataType>;
};
}>;
// Actions
@ -43,65 +44,65 @@ export const MODIFY_LIST = 'storyDistributionLists/MODIFY_LIST';
const RESET_MY_STORIES = 'storyDistributionLists/RESET_MY_STORIES';
export const VIEWERS_CHANGED = 'storyDistributionLists/VIEWERS_CHANGED';
type AllowRepliesChangedActionType = {
type AllowRepliesChangedActionType = ReadonlyDeep<{
type: typeof ALLOW_REPLIES_CHANGED;
payload: {
listId: string;
allowsReplies: boolean;
};
};
}>;
type CreateListActionType = {
type CreateListActionType = ReadonlyDeep<{
type: typeof CREATE_LIST;
payload: StoryDistributionListDataType;
};
}>;
type DeleteListActionType = {
type DeleteListActionType = ReadonlyDeep<{
type: typeof DELETE_LIST;
payload: {
listId: string;
deletedAtTimestamp: number;
};
};
}>;
type HideMyStoriesFromActionType = {
type HideMyStoriesFromActionType = ReadonlyDeep<{
type: typeof HIDE_MY_STORIES_FROM;
payload: Array<UUIDStringType>;
};
}>;
type ModifyDistributionListType = Omit<
StoryDistributionListDataType,
'memberUuids'
> & {
membersToAdd: Array<UUIDStringType>;
membersToRemove: Array<UUIDStringType>;
};
type ModifyDistributionListType = ReadonlyDeep<
Omit<StoryDistributionListDataType, 'memberUuids'> & {
membersToAdd: Array<UUIDStringType>;
membersToRemove: Array<UUIDStringType>;
}
>;
export type ModifyListActionType = {
export type ModifyListActionType = ReadonlyDeep<{
type: typeof MODIFY_LIST;
payload: ModifyDistributionListType;
};
}>;
type ResetMyStoriesActionType = {
type ResetMyStoriesActionType = ReadonlyDeep<{
type: typeof RESET_MY_STORIES;
};
}>;
type ViewersChangedActionType = {
type ViewersChangedActionType = ReadonlyDeep<{
type: typeof VIEWERS_CHANGED;
payload: {
listId: string;
memberUuids: Array<UUIDStringType>;
};
};
}>;
export type StoryDistributionListsActionType =
export type StoryDistributionListsActionType = ReadonlyDeep<
| AllowRepliesChangedActionType
| CreateListActionType
| DeleteListActionType
| HideMyStoriesFromActionType
| ModifyListActionType
| ResetMyStoriesActionType
| ViewersChangedActionType;
| ViewersChangedActionType
>;
// Action Creators
@ -503,7 +504,7 @@ export function getEmptyState(): StoryDistributionListStateType {
}
function replaceDistributionListData(
distributionLists: Array<StoryDistributionListDataType>,
distributionLists: ReadonlyArray<StoryDistributionListDataType>,
listId: string,
getNextDistributionListData: (
list: StoryDistributionListDataType

View file

@ -3,6 +3,7 @@
import { ipcRenderer } from 'electron';
import type { ReadonlyDeep } from 'type-fest';
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
import type { NoopActionType } from './noop';
import type { ReplacementValuesType } from '../../types/Util';
@ -11,6 +12,7 @@ import type { ToastType } from '../../types/Toast';
// State
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type ToastStateType = {
toast?: {
toastType: ToastType;
@ -23,10 +25,11 @@ export type ToastStateType = {
const HIDE_TOAST = 'toast/HIDE_TOAST';
export const SHOW_TOAST = 'toast/SHOW_TOAST';
type HideToastActionType = {
type HideToastActionType = ReadonlyDeep<{
type: typeof HIDE_TOAST;
};
}>;
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type ShowToastActionType = {
type: typeof SHOW_TOAST;
payload: {
@ -35,6 +38,7 @@ export type ShowToastActionType = {
};
};
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type ToastActionType = HideToastActionType | ShowToastActionType;
// Action Creators
@ -53,10 +57,12 @@ function openFileInFolder(target: string): NoopActionType {
};
}
export type ShowToastActionCreatorType = (
toastType: ToastType,
parameters?: ReplacementValuesType
) => ShowToastActionType;
export type ShowToastActionCreatorType = ReadonlyDeep<
(
toastType: ToastType,
parameters?: ReplacementValuesType
) => ShowToastActionType
>;
export const showToast: ShowToastActionCreatorType = (
toastType,

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import type { ThunkAction } from 'redux-thunk';
import type { ReadonlyDeep } from 'type-fest';
import * as updateIpc from '../../shims/updateIpc';
import { DialogType } from '../../types/Dialogs';
import { DAY } from '../../util/durations';
@ -9,14 +10,14 @@ import type { StateType as RootStateType } from '../reducer';
// State
export type UpdatesStateType = {
export type UpdatesStateType = ReadonlyDeep<{
dialogType: DialogType;
didSnooze: boolean;
downloadSize?: number;
downloadedSize?: number;
showEventsCount: number;
version?: string;
};
}>;
// Actions
@ -26,43 +27,44 @@ const SNOOZE_UPDATE = 'updates/SNOOZE_UPDATE';
const START_UPDATE = 'updates/START_UPDATE';
const UNSNOOZE_UPDATE = 'updates/UNSNOOZE_UPDATE';
export type UpdateDialogOptionsType = {
export type UpdateDialogOptionsType = ReadonlyDeep<{
downloadSize?: number;
downloadedSize?: number;
version?: string;
};
}>;
type DismissDialogActionType = {
type DismissDialogActionType = ReadonlyDeep<{
type: typeof DISMISS_DIALOG;
};
}>;
export type ShowUpdateDialogActionType = {
export type ShowUpdateDialogActionType = ReadonlyDeep<{
type: typeof SHOW_UPDATE_DIALOG;
payload: {
dialogType: DialogType;
otherState: UpdateDialogOptionsType;
};
};
}>;
type SnoozeUpdateActionType = {
type SnoozeUpdateActionType = ReadonlyDeep<{
type: typeof SNOOZE_UPDATE;
};
}>;
type StartUpdateActionType = {
type StartUpdateActionType = ReadonlyDeep<{
type: typeof START_UPDATE;
};
}>;
type UnsnoozeUpdateActionType = {
type UnsnoozeUpdateActionType = ReadonlyDeep<{
type: typeof UNSNOOZE_UPDATE;
payload: DialogType;
};
}>;
export type UpdatesActionType =
export type UpdatesActionType = ReadonlyDeep<
| DismissDialogActionType
| ShowUpdateDialogActionType
| SnoozeUpdateActionType
| StartUpdateActionType
| UnsnoozeUpdateActionType;
| UnsnoozeUpdateActionType
>;
// Action Creators

View file

@ -1,6 +1,7 @@
// Copyright 2019 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { ReadonlyDeep } from 'type-fest';
import { trigger } from '../../shims/events';
import type { LocaleMessagesType } from '../../types/I18N';
@ -13,7 +14,8 @@ import { ThemeType } from '../../types/Util';
// State
export type UserStateType = {
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type UserStateType = Readonly<{
attachmentsPath: string;
i18n: LocalizerType;
interactionMode: 'mouse' | 'keyboard';
@ -33,11 +35,11 @@ export type UserStateType = {
tempPath: string;
theme: ThemeType;
version: string;
};
}>;
// Actions
type UserChangedActionType = {
type UserChangedActionType = ReadonlyDeep<{
type: 'USER_CHANGED';
payload: {
ourConversationId?: string;
@ -52,9 +54,9 @@ type UserChangedActionType = {
isMainWindowFullScreen?: boolean;
menuOptions?: MenuOptionsType;
};
};
}>;
export type UserActionType = UserChangedActionType;
export type UserActionType = ReadonlyDeep<UserChangedActionType>;
// Action Creators

View file

@ -3,6 +3,7 @@
import type { ThunkAction } from 'redux-thunk';
import type { ReadonlyDeep } from 'type-fest';
import type { UsernameReservationType } from '../../types/Username';
import { ReserveUsernameError } from '../../types/Username';
import * as usernameServices from '../../services/username';
@ -27,14 +28,14 @@ import { showToast } from './toast';
import { ToastType } from '../../types/Toast';
import type { ToastActionType } from './toast';
export type UsernameReservationStateType = Readonly<{
export type UsernameReservationStateType = ReadonlyDeep<{
state: UsernameReservationState;
reservation?: UsernameReservationType;
error?: UsernameReservationError;
abortController?: AbortController;
}>;
export type UsernameStateType = Readonly<{
export type UsernameStateType = ReadonlyDeep<{
// ProfileEditor
editState: UsernameEditState;
@ -52,44 +53,51 @@ const RESERVE_USERNAME = 'username/RESERVE_USERNAME';
const CONFIRM_USERNAME = 'username/CONFIRM_USERNAME';
const DELETE_USERNAME = 'username/DELETE_USERNAME';
type SetUsernameEditStateActionType = {
type SetUsernameEditStateActionType = ReadonlyDeep<{
type: typeof SET_USERNAME_EDIT_STATE;
payload: {
editState: UsernameEditState;
};
};
}>;
type OpenUsernameReservationModalActionType = {
type OpenUsernameReservationModalActionType = ReadonlyDeep<{
type: typeof OPEN_USERNAME_RESERVATION_MODAL;
};
}>;
type CloseUsernameReservationModalActionType = {
type CloseUsernameReservationModalActionType = ReadonlyDeep<{
type: typeof CLOSE_USERNAME_RESERVATION_MODAL;
};
}>;
type SetUsernameReservationErrorActionType = {
type SetUsernameReservationErrorActionType = ReadonlyDeep<{
type: typeof SET_USERNAME_RESERVATION_ERROR;
payload: {
error: UsernameReservationError | undefined;
};
};
}>;
type ReserveUsernameActionType = PromiseAction<
typeof RESERVE_USERNAME,
ReserveUsernameResultType | undefined,
{ abortController: AbortController }
type ReserveUsernameActionType = ReadonlyDeep<
PromiseAction<
typeof RESERVE_USERNAME,
ReserveUsernameResultType | undefined,
{ abortController: AbortController }
>
>;
type ConfirmUsernameActionType = ReadonlyDeep<
PromiseAction<typeof CONFIRM_USERNAME, void>
>;
type DeleteUsernameActionType = ReadonlyDeep<
PromiseAction<typeof DELETE_USERNAME, void>
>;
type ConfirmUsernameActionType = PromiseAction<typeof CONFIRM_USERNAME, void>;
type DeleteUsernameActionType = PromiseAction<typeof DELETE_USERNAME, void>;
export type UsernameActionType =
export type UsernameActionType = ReadonlyDeep<
| SetUsernameEditStateActionType
| OpenUsernameReservationModalActionType
| CloseUsernameReservationModalActionType
| SetUsernameReservationErrorActionType
| ReserveUsernameActionType
| ConfirmUsernameActionType
| DeleteUsernameActionType;
| DeleteUsernameActionType
>;
export const actions = {
setUsernameEditState,
@ -133,7 +141,7 @@ export function setUsernameReservationError(
const INPUT_DELAY_MS = 500;
export type ReserveUsernameOptionsType = Readonly<{
export type ReserveUsernameOptionsType = ReadonlyDeep<{
doReserveUsername?: typeof usernameServices.reserveUsername;
delay?: number;
}>;
@ -194,7 +202,7 @@ export function reserveUsername(
};
}
export type ConfirmUsernameOptionsType = Readonly<{
export type ConfirmUsernameOptionsType = ReadonlyDeep<{
doConfirmUsername?: typeof usernameServices.confirmUsername;
}>;
@ -221,7 +229,7 @@ export function confirmUsername({
};
}
export type DeleteUsernameOptionsType = Readonly<{
export type DeleteUsernameOptionsType = ReadonlyDeep<{
doDeleteUsername?: typeof usernameServices.deleteUsername;
// Only for testing

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { createSelector } from 'reselect';
import type { ReadonlyDeep } from 'type-fest';
import type { MediaItemType } from '../../types/MediaItem';
import type { StateType } from '../reducer';
import type { LightboxStateType } from '../ducks/lightbox';
@ -36,6 +37,6 @@ export const getSelectedIndex = createSelector(
export const getMedia = createSelector(
getLightboxState,
(state): ReadonlyArray<MediaItemType> =>
(state): ReadonlyArray<ReadonlyDeep<MediaItemType>> =>
state.isShowingLightbox ? state.media : []
);

View file

@ -125,7 +125,7 @@ export const getRecentStickers = createSelector(
getStickersPath,
getTempPath,
(
recents: Array<RecentStickerType>,
recents: ReadonlyArray<RecentStickerType>,
packs: Dictionary<StickerPackDBType>,
stickersPath: string,
tempPath: string

View file

@ -8,6 +8,7 @@ import { MediaGallery } from '../../components/conversation/media-gallery/MediaG
import { getMediaGalleryState } from '../selectors/mediaGallery';
import { useConversationsActions } from '../ducks/conversations';
import { useLightboxActions } from '../ducks/lightbox';
import { useMediaGalleryActions } from '../ducks/mediaGallery';
export type PropsType = {

View file

@ -4,6 +4,7 @@
import React from 'react';
import { useSelector } from 'react-redux';
import type { ReadonlyDeep } from 'type-fest';
import type { GetConversationByIdType } from '../selectors/conversations';
import type { LocalizerType } from '../../types/Util';
import type { MediaItemType } from '../../types/MediaItem';
@ -33,7 +34,10 @@ export function SmartLightbox(): JSX.Element | null {
const isShowingLightbox = useSelector<StateType, boolean>(shouldShowLightbox);
const isViewOnce = useSelector<StateType, boolean>(getIsViewOnce);
const media = useSelector<StateType, ReadonlyArray<MediaItemType>>(getMedia);
const media = useSelector<
StateType,
ReadonlyArray<ReadonlyDeep<MediaItemType>>
>(getMedia);
const selectedIndex = useSelector<StateType, number>(getSelectedIndex);
if (!isShowingLightbox) {

View file

@ -6,6 +6,7 @@ import type { RefObject } from 'react';
import React from 'react';
import { connect } from 'react-redux';
import type { ReadonlyDeep } from 'type-fest';
import { mapDispatchToProps } from '../actions';
import type {
ContactSpoofingReviewPropType,
@ -103,7 +104,7 @@ function renderTypingBubble(id: string): JSX.Element {
}
const getWarning = (
conversation: Readonly<ConversationType>,
conversation: ReadonlyDeep<ConversationType>,
state: Readonly<StateType>
): undefined | TimelineWarningType => {
switch (conversation.type) {