|
|
|
@ -1,4 +1,5 @@
|
|
|
|
|
import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet, Record as ImmutableRecord, fromJS } from 'immutable';
|
|
|
|
|
import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable';
|
|
|
|
|
import { create } from 'mutative';
|
|
|
|
|
import { Instance, PLEROMA, type CredentialAccount, type MediaAttachment, type Tag } from 'pl-api';
|
|
|
|
|
|
|
|
|
|
import { INSTANCE_FETCH_SUCCESS, InstanceAction } from 'pl-fe/actions/instance';
|
|
|
|
@ -59,7 +60,8 @@ import {
|
|
|
|
|
COMPOSE_CHANGE_MEDIA_ORDER,
|
|
|
|
|
COMPOSE_ADD_SUGGESTED_QUOTE,
|
|
|
|
|
COMPOSE_FEDERATED_CHANGE,
|
|
|
|
|
ComposeAction,
|
|
|
|
|
type ComposeAction,
|
|
|
|
|
type ComposeSuggestionSelectAction,
|
|
|
|
|
} from '../actions/compose';
|
|
|
|
|
import { EVENT_COMPOSE_CANCEL, EVENT_FORM_SET, type EventsAction } from '../actions/events';
|
|
|
|
|
import { ME_FETCH_SUCCESS, ME_PATCH_SUCCESS, MeAction } from '../actions/me';
|
|
|
|
@ -75,57 +77,108 @@ import type { APIEntity } from 'pl-fe/types/entities';
|
|
|
|
|
|
|
|
|
|
const getResetFileKey = () => Math.floor((Math.random() * 0x10000));
|
|
|
|
|
|
|
|
|
|
const PollRecord = ImmutableRecord({
|
|
|
|
|
interface ComposePoll {
|
|
|
|
|
options: ImmutableList<string>;
|
|
|
|
|
options_map: ImmutableList<ImmutableMap<Language, string>>;
|
|
|
|
|
expires_in: number;
|
|
|
|
|
multiple: boolean;
|
|
|
|
|
hide_totals: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const newPoll = (params: Partial<ComposePoll> = {}): ComposePoll => ({
|
|
|
|
|
options: ImmutableList(['', '']),
|
|
|
|
|
options_map: ImmutableList<ImmutableMap<Language, string>>([ImmutableMap(), ImmutableMap()]),
|
|
|
|
|
options_map: ImmutableList([ImmutableMap(), ImmutableMap()]),
|
|
|
|
|
expires_in: 24 * 3600,
|
|
|
|
|
multiple: false,
|
|
|
|
|
hide_totals: false,
|
|
|
|
|
...params,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const ReducerCompose = ImmutableRecord({
|
|
|
|
|
caretPosition: null as number | null,
|
|
|
|
|
interface Compose {
|
|
|
|
|
caretPosition: number | null;
|
|
|
|
|
content_type: string;
|
|
|
|
|
draft_id: string | null;
|
|
|
|
|
editorState: string | null;
|
|
|
|
|
editorStateMap: ImmutableMap<Language, string | null>;
|
|
|
|
|
focusDate: Date | null;
|
|
|
|
|
group_id: string | null;
|
|
|
|
|
idempotencyKey: string;
|
|
|
|
|
id: string | null;
|
|
|
|
|
in_reply_to: string | null;
|
|
|
|
|
is_changing_upload: boolean;
|
|
|
|
|
is_composing: boolean;
|
|
|
|
|
is_submitting: boolean;
|
|
|
|
|
is_uploading: boolean;
|
|
|
|
|
media_attachments: ImmutableList<MediaAttachment>;
|
|
|
|
|
poll: ComposePoll | null;
|
|
|
|
|
privacy: string;
|
|
|
|
|
progress: number;
|
|
|
|
|
quote: string | null;
|
|
|
|
|
resetFileKey: number | null;
|
|
|
|
|
schedule: Date | null;
|
|
|
|
|
sensitive: boolean;
|
|
|
|
|
spoiler_text: string;
|
|
|
|
|
spoilerTextMap: ImmutableMap<Language, string>;
|
|
|
|
|
suggestions: ImmutableList<string>;
|
|
|
|
|
suggestion_token: string | null;
|
|
|
|
|
tagHistory: ImmutableList<string>;
|
|
|
|
|
text: string;
|
|
|
|
|
textMap: ImmutableMap<Language, string>;
|
|
|
|
|
to: ImmutableOrderedSet<string>;
|
|
|
|
|
parent_reblogged_by: string | null;
|
|
|
|
|
dismissed_quotes: ImmutableOrderedSet<string>;
|
|
|
|
|
language: Language | null;
|
|
|
|
|
modified_language: Language | null;
|
|
|
|
|
suggested_language: string | null;
|
|
|
|
|
federated: boolean;
|
|
|
|
|
approvalRequired: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const newCompose = (params: Partial<Compose> = {}): Compose => ({
|
|
|
|
|
caretPosition: null,
|
|
|
|
|
content_type: 'text/plain',
|
|
|
|
|
draft_id: null as string | null,
|
|
|
|
|
editorState: null as string | null,
|
|
|
|
|
draft_id: null,
|
|
|
|
|
editorState: null,
|
|
|
|
|
editorStateMap: ImmutableMap<Language, string | null>(),
|
|
|
|
|
focusDate: null as Date | null,
|
|
|
|
|
group_id: null as string | null,
|
|
|
|
|
focusDate: null,
|
|
|
|
|
group_id: null,
|
|
|
|
|
idempotencyKey: '',
|
|
|
|
|
id: null as string | null,
|
|
|
|
|
in_reply_to: null as string | null,
|
|
|
|
|
id: null,
|
|
|
|
|
in_reply_to: null,
|
|
|
|
|
is_changing_upload: false,
|
|
|
|
|
is_composing: false,
|
|
|
|
|
is_submitting: false,
|
|
|
|
|
is_uploading: false,
|
|
|
|
|
media_attachments: ImmutableList<MediaAttachment>(),
|
|
|
|
|
poll: null as Poll | null,
|
|
|
|
|
poll: null,
|
|
|
|
|
privacy: 'public',
|
|
|
|
|
progress: 0,
|
|
|
|
|
quote: null as string | null,
|
|
|
|
|
resetFileKey: null as number | null,
|
|
|
|
|
schedule: null as Date | null,
|
|
|
|
|
quote: null,
|
|
|
|
|
resetFileKey: null,
|
|
|
|
|
schedule: null,
|
|
|
|
|
sensitive: false,
|
|
|
|
|
spoiler_text: '',
|
|
|
|
|
spoilerTextMap: ImmutableMap<Language, string>(),
|
|
|
|
|
suggestions: ImmutableList<string>(),
|
|
|
|
|
suggestion_token: null as string | null,
|
|
|
|
|
suggestion_token: null,
|
|
|
|
|
tagHistory: ImmutableList<string>(),
|
|
|
|
|
text: '',
|
|
|
|
|
textMap: ImmutableMap<Language, string>(),
|
|
|
|
|
to: ImmutableOrderedSet<string>(),
|
|
|
|
|
parent_reblogged_by: null as string | null,
|
|
|
|
|
parent_reblogged_by: null,
|
|
|
|
|
dismissed_quotes: ImmutableOrderedSet<string>(),
|
|
|
|
|
language: null as Language | null,
|
|
|
|
|
modified_language: null as Language | null,
|
|
|
|
|
suggested_language: null as string | null,
|
|
|
|
|
language: null,
|
|
|
|
|
modified_language: null,
|
|
|
|
|
suggested_language: null,
|
|
|
|
|
federated: true,
|
|
|
|
|
approvalRequired: false,
|
|
|
|
|
...params,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
type State = ImmutableMap<string, Compose>;
|
|
|
|
|
type Compose = ReturnType<typeof ReducerCompose>;
|
|
|
|
|
type Poll = ReturnType<typeof PollRecord>;
|
|
|
|
|
type State = {
|
|
|
|
|
default: Compose;
|
|
|
|
|
[key: string]: Compose;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const statusToTextMentions = (status: Pick<Status, 'account' | 'mentions'>, account: Pick<Account, 'acct'>) => {
|
|
|
|
|
const author = status.account.acct;
|
|
|
|
@ -160,53 +213,47 @@ const statusToMentionsAccountIdsArray = (status: Pick<Status, 'mentions' | 'acco
|
|
|
|
|
const appendMedia = (compose: Compose, media: MediaAttachment, defaultSensitive?: boolean) => {
|
|
|
|
|
const prevSize = compose.media_attachments.size;
|
|
|
|
|
|
|
|
|
|
return compose.withMutations(map => {
|
|
|
|
|
map.update('media_attachments', list => list.push(media));
|
|
|
|
|
map.set('is_uploading', false);
|
|
|
|
|
map.set('resetFileKey', Math.floor((Math.random() * 0x10000)));
|
|
|
|
|
map.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
compose.media_attachments.push(media);
|
|
|
|
|
compose.is_uploading = false;
|
|
|
|
|
compose.resetFileKey = Math.floor((Math.random() * 0x10000));
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
|
|
|
|
|
if (prevSize === 0 && (defaultSensitive || compose.sensitive)) {
|
|
|
|
|
map.set('sensitive', true);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
if (prevSize === 0 && (defaultSensitive || compose.sensitive)) {
|
|
|
|
|
compose.sensitive = true;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const removeMedia = (compose: Compose, mediaId: string) => {
|
|
|
|
|
const prevSize = compose.media_attachments.size;
|
|
|
|
|
|
|
|
|
|
return compose.withMutations(map => {
|
|
|
|
|
map.update('media_attachments', list => list.filterNot(item => item.id === mediaId));
|
|
|
|
|
map.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
compose.media_attachments = compose.media_attachments.filter(item => item.id !== mediaId);
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
|
|
|
|
|
if (prevSize === 1) {
|
|
|
|
|
map.set('sensitive', false);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
if (prevSize === 1) {
|
|
|
|
|
compose.sensitive = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const insertSuggestion = (compose: Compose, position: number, token: string | null, completion: string, path: Array<string | number>) =>
|
|
|
|
|
compose.withMutations(map => {
|
|
|
|
|
map.updateIn(path, oldText => `${(oldText as string).slice(0, position)}${completion} ${(oldText as string).slice(position + (token?.length ?? 0))}`);
|
|
|
|
|
map.set('suggestion_token', null);
|
|
|
|
|
map.set('suggestions', ImmutableList());
|
|
|
|
|
if (path.length === 1 && path[0] === 'text') {
|
|
|
|
|
map.set('focusDate', new Date());
|
|
|
|
|
map.set('caretPosition', position + completion.length + 1);
|
|
|
|
|
}
|
|
|
|
|
map.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
});
|
|
|
|
|
const insertSuggestion = (compose: Compose, position: number, token: string | null, completion: string, path: ComposeSuggestionSelectAction['path']) => {
|
|
|
|
|
const updateText = (oldText?: string) => `${oldText?.slice(0, position)}${completion} ${oldText?.slice(position + (token?.length ?? 0))}`;
|
|
|
|
|
if (path[0] === 'spoiler_text') {
|
|
|
|
|
compose.spoiler_text = updateText(compose.spoiler_text);
|
|
|
|
|
} else if (compose.poll) {
|
|
|
|
|
compose.poll.options = compose.poll.options.update(path[2], updateText);
|
|
|
|
|
}
|
|
|
|
|
compose.suggestion_token = null;
|
|
|
|
|
compose.suggestions = ImmutableList();
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const updateSuggestionTags = (compose: Compose, token: string, tags: Tag[]) => {
|
|
|
|
|
const prefix = token.slice(1);
|
|
|
|
|
|
|
|
|
|
return compose.merge({
|
|
|
|
|
suggestions: ImmutableList(tags
|
|
|
|
|
.filter((tag) => tag.name.toLowerCase().startsWith(prefix.toLowerCase()))
|
|
|
|
|
.slice(0, 4)
|
|
|
|
|
.map((tag) => '#' + tag.name)),
|
|
|
|
|
suggestion_token: token,
|
|
|
|
|
});
|
|
|
|
|
compose.suggestions = ImmutableList(tags
|
|
|
|
|
.filter((tag) => tag.name.toLowerCase().startsWith(prefix.toLowerCase()))
|
|
|
|
|
.slice(0, 4)
|
|
|
|
|
.map((tag) => '#' + tag.name));
|
|
|
|
|
compose.suggestion_token = token;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const insertEmoji = (compose: Compose, position: number, emojiData: Emoji, needsSpace: boolean) => {
|
|
|
|
@ -214,12 +261,10 @@ const insertEmoji = (compose: Compose, position: number, emojiData: Emoji, needs
|
|
|
|
|
const emojiText = isNativeEmoji(emojiData) ? emojiData.native : emojiData.colons;
|
|
|
|
|
const emoji = needsSpace ? ' ' + emojiText : emojiText;
|
|
|
|
|
|
|
|
|
|
return compose.merge({
|
|
|
|
|
text: `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`,
|
|
|
|
|
focusDate: new Date(),
|
|
|
|
|
caretPosition: position + emoji.length + 1,
|
|
|
|
|
idempotencyKey: crypto.randomUUID(),
|
|
|
|
|
});
|
|
|
|
|
compose.text = `${oldText.slice(0, position)}${emoji} ${oldText.slice(position)}`;
|
|
|
|
|
compose.focusDate = new Date();
|
|
|
|
|
compose.caretPosition = position + emoji.length + 1;
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const privacyPreference = (a: string, b: string) => {
|
|
|
|
@ -257,13 +302,11 @@ const getExplicitMentions = (me: string, status: Pick<Status, 'content' | 'menti
|
|
|
|
|
const importAccount = (compose: Compose, account: CredentialAccount) => {
|
|
|
|
|
const settings = account.settings_store?.[FE_NAME];
|
|
|
|
|
|
|
|
|
|
if (!settings) return compose;
|
|
|
|
|
if (!settings) return;
|
|
|
|
|
|
|
|
|
|
return compose.withMutations(compose => {
|
|
|
|
|
if (settings.defaultPrivacy) compose.set('privacy', settings.defaultPrivacy);
|
|
|
|
|
if (settings.defaultContentType) compose.set('content_type', settings.defaultContentType);
|
|
|
|
|
compose.set('tagHistory', ImmutableList(tagHistory.get(account.id)));
|
|
|
|
|
});
|
|
|
|
|
if (settings.defaultPrivacy) compose.privacy = settings.defaultPrivacy;
|
|
|
|
|
if (settings.defaultContentType) compose.content_type = settings.defaultContentType;
|
|
|
|
|
compose.tagHistory = ImmutableList(tagHistory.get(account.id));
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// const updateSetting = (compose: Compose, path: string[], value: string) => {
|
|
|
|
@ -281,323 +324,385 @@ const importAccount = (compose: Compose, account: CredentialAccount) => {
|
|
|
|
|
const updateDefaultContentType = (compose: Compose, instance: Instance) => {
|
|
|
|
|
const postFormats = instance.pleroma.metadata.post_formats;
|
|
|
|
|
|
|
|
|
|
return compose.update('content_type', type => postFormats.includes(type) ? type : postFormats.includes('text/markdown') ? 'text/markdown' : postFormats[0]);
|
|
|
|
|
compose.content_type = postFormats.includes(compose.content_type) ? compose.content_type : postFormats.includes('text/markdown') ? 'text/markdown' : postFormats[0];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const updateCompose = (state: State, key: string, updater: (compose: Compose) => Compose) =>
|
|
|
|
|
state.update(key, state.get('default')!, updater);
|
|
|
|
|
const updateCompose = (state: State, key: string, updater: (compose: Compose) => void) =>
|
|
|
|
|
create(state, draft => {
|
|
|
|
|
draft[key] = draft[key] || create(draft.default, () => {});
|
|
|
|
|
updater(draft[key]);
|
|
|
|
|
});
|
|
|
|
|
// state.update(key, state.get('default')!, updater);
|
|
|
|
|
|
|
|
|
|
const initialState: State = ImmutableMap({
|
|
|
|
|
default: ReducerCompose({ idempotencyKey: crypto.randomUUID(), resetFileKey: getResetFileKey() }),
|
|
|
|
|
});
|
|
|
|
|
const initialState: State = {
|
|
|
|
|
default: newCompose({ idempotencyKey: crypto.randomUUID(), resetFileKey: getResetFileKey() }),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const compose = (state = initialState, action: ComposeAction | EventsAction | InstanceAction | MeAction | TimelineAction) => {
|
|
|
|
|
const compose = (state = initialState, action: ComposeAction | EventsAction | InstanceAction | MeAction | TimelineAction): State => {
|
|
|
|
|
switch (action.type) {
|
|
|
|
|
case COMPOSE_TYPE_CHANGE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.withMutations(map => {
|
|
|
|
|
map.set('content_type', action.value);
|
|
|
|
|
map.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
}));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.content_type = action.value;
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_SPOILERNESS_CHANGE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.withMutations(map => {
|
|
|
|
|
map.set('sensitive', !compose.sensitive);
|
|
|
|
|
map.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
}));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.sensitive = !compose.sensitive;
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_SPOILER_TEXT_CHANGE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
return compose
|
|
|
|
|
.setIn(compose.modified_language === compose.language ? ['spoiler_text'] : ['spoilerTextMap', compose.modified_language], action.text)
|
|
|
|
|
.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
if (compose.modified_language === compose.language) {
|
|
|
|
|
compose.spoiler_text = action.text;
|
|
|
|
|
} else {
|
|
|
|
|
compose.spoilerTextMap = compose.spoilerTextMap.set(compose.modified_language!, action.text);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_VISIBILITY_CHANGE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose
|
|
|
|
|
.set('privacy', action.value)
|
|
|
|
|
.set('idempotencyKey', crypto.randomUUID()));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.privacy = action.value;
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_LANGUAGE_CHANGE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.withMutations(map => {
|
|
|
|
|
map.set('language', action.value);
|
|
|
|
|
map.set('modified_language', action.value);
|
|
|
|
|
map.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
}));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.language = action.value;
|
|
|
|
|
compose.modified_language = action.value;
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_MODIFIED_LANGUAGE_CHANGE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.withMutations(map => {
|
|
|
|
|
map.set('modified_language', action.value);
|
|
|
|
|
map.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
}));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.modified_language = action.value;
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_CHANGE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose
|
|
|
|
|
.set('text', action.text)
|
|
|
|
|
.set('idempotencyKey', crypto.randomUUID()));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.text = action.text;
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_REPLY:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.withMutations(map => {
|
|
|
|
|
const defaultCompose = state.get('default')!;
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
const defaultCompose = state.default!;
|
|
|
|
|
|
|
|
|
|
const to = action.explicitAddressing
|
|
|
|
|
? statusToMentionsArray(action.status, action.account, action.rebloggedBy)
|
|
|
|
|
: ImmutableOrderedSet<string>();
|
|
|
|
|
|
|
|
|
|
map.set('group_id', action.status.group_id);
|
|
|
|
|
map.set('in_reply_to', action.status.id);
|
|
|
|
|
map.set('to', to);
|
|
|
|
|
map.set('parent_reblogged_by', action.rebloggedBy?.id || null);
|
|
|
|
|
map.set('text', !action.explicitAddressing ? statusToTextMentions(action.status, action.account) : '');
|
|
|
|
|
map.set('privacy', privacyPreference(action.status.visibility, defaultCompose.privacy));
|
|
|
|
|
map.set('focusDate', new Date());
|
|
|
|
|
map.set('caretPosition', null);
|
|
|
|
|
map.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
map.set('content_type', defaultCompose.content_type);
|
|
|
|
|
map.set('approvalRequired', action.approvalRequired || false);
|
|
|
|
|
compose.group_id = action.status.group_id;
|
|
|
|
|
compose.in_reply_to = action.status.id;
|
|
|
|
|
compose.to = to;
|
|
|
|
|
compose.parent_reblogged_by = action.rebloggedBy?.id || null;
|
|
|
|
|
compose.text = !action.explicitAddressing ? statusToTextMentions(action.status, action.account) : '';
|
|
|
|
|
compose.privacy = privacyPreference(action.status.visibility, defaultCompose.privacy);
|
|
|
|
|
compose.focusDate = new Date();
|
|
|
|
|
compose.caretPosition = null;
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
compose.content_type = defaultCompose.content_type;
|
|
|
|
|
compose.approvalRequired = action.approvalRequired || false;
|
|
|
|
|
if (action.preserveSpoilers && action.status.spoiler_text) {
|
|
|
|
|
map.set('sensitive', true);
|
|
|
|
|
map.set('spoiler_text', action.status.spoiler_text);
|
|
|
|
|
compose.sensitive = true;
|
|
|
|
|
compose.spoiler_text = action.status.spoiler_text;
|
|
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_EVENT_REPLY:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.withMutations(map => {
|
|
|
|
|
map.set('in_reply_to', action.status.id);
|
|
|
|
|
map.set('to', statusToMentionsArray(action.status, action.account));
|
|
|
|
|
map.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
}));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.in_reply_to = action.status.id;
|
|
|
|
|
compose.to = statusToMentionsArray(action.status, action.account);
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_QUOTE:
|
|
|
|
|
return updateCompose(state, 'compose-modal', compose => compose.withMutations(map => {
|
|
|
|
|
return updateCompose(state, 'compose-modal', compose => {
|
|
|
|
|
const author = action.status.account.acct;
|
|
|
|
|
const defaultCompose = state.get('default')!;
|
|
|
|
|
const defaultCompose = state.default;
|
|
|
|
|
|
|
|
|
|
map.set('quote', action.status.id);
|
|
|
|
|
map.set('to', ImmutableOrderedSet<string>([author]));
|
|
|
|
|
map.set('parent_reblogged_by', null);
|
|
|
|
|
map.set('text', '');
|
|
|
|
|
map.set('privacy', privacyPreference(action.status.visibility, defaultCompose.privacy));
|
|
|
|
|
map.set('focusDate', new Date());
|
|
|
|
|
map.set('caretPosition', null);
|
|
|
|
|
map.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
map.set('content_type', defaultCompose.content_type);
|
|
|
|
|
map.set('spoiler_text', '');
|
|
|
|
|
compose.quote = action.status.id;
|
|
|
|
|
compose.to = ImmutableOrderedSet<string>([author]);
|
|
|
|
|
compose.parent_reblogged_by = null;
|
|
|
|
|
compose.text = '';
|
|
|
|
|
compose.privacy = privacyPreference(action.status.visibility, defaultCompose.privacy);
|
|
|
|
|
compose.focusDate = new Date();
|
|
|
|
|
compose.caretPosition = null;
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
compose.content_type = defaultCompose.content_type;
|
|
|
|
|
compose.spoiler_text = '';
|
|
|
|
|
|
|
|
|
|
if (action.status.visibility === 'group') {
|
|
|
|
|
map.set('group_id', action.status.group_id);
|
|
|
|
|
map.set('privacy', 'group');
|
|
|
|
|
compose.group_id = action.status.group_id;
|
|
|
|
|
compose.privacy = 'group';
|
|
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_SUBMIT_REQUEST:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('is_submitting', true));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.is_submitting = true;
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_UPLOAD_CHANGE_REQUEST:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('is_changing_upload', true));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.is_changing_upload = true;
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_REPLY_CANCEL:
|
|
|
|
|
case COMPOSE_RESET:
|
|
|
|
|
case COMPOSE_SUBMIT_SUCCESS:
|
|
|
|
|
return updateCompose(state, action.composeId, () => state.get('default')!.withMutations(map => {
|
|
|
|
|
map.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
map.set('in_reply_to', action.composeId.startsWith('reply:') ? action.composeId.slice(6) : null);
|
|
|
|
|
if (action.composeId.startsWith('group:')) {
|
|
|
|
|
map.set('privacy', 'group');
|
|
|
|
|
map.set('group_id', action.composeId.slice(6));
|
|
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
return create(state, (draft) => {
|
|
|
|
|
draft[action.composeId] = newCompose({
|
|
|
|
|
idempotencyKey: crypto.randomUUID(),
|
|
|
|
|
in_reply_to: action.composeId.startsWith('reply:') ? action.composeId.slice(6) : null,
|
|
|
|
|
...(action.composeId.startsWith('group:') ? {
|
|
|
|
|
privacy: 'group',
|
|
|
|
|
group_id: action.composeId.slice(6),
|
|
|
|
|
} : undefined),
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_SUBMIT_FAIL:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('is_submitting', false));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.is_submitting = false;
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_UPLOAD_CHANGE_FAIL:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('is_changing_upload', false));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.is_changing_upload = false;
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_UPLOAD_REQUEST:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('is_uploading', true));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.is_uploading = true;
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_UPLOAD_SUCCESS:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => appendMedia(compose, action.media, state.get('default')!.sensitive));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => appendMedia(compose, action.media, state.default.sensitive));
|
|
|
|
|
case COMPOSE_UPLOAD_FAIL:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('is_uploading', false));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.is_uploading = false;
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_UPLOAD_UNDO:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => removeMedia(compose, action.mediaId));
|
|
|
|
|
case COMPOSE_UPLOAD_PROGRESS:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('progress', Math.round((action.loaded / action.total) * 100)));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.progress = Math.round((action.loaded / action.total) * 100);
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_MENTION:
|
|
|
|
|
return updateCompose(state, 'compose-modal', compose => compose.withMutations(map => {
|
|
|
|
|
map.update('text', text => [text.trim(), `@${action.account.acct} `].filter((str) => str.length !== 0).join(' '));
|
|
|
|
|
map.set('focusDate', new Date());
|
|
|
|
|
map.set('caretPosition', null);
|
|
|
|
|
map.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
}));
|
|
|
|
|
return updateCompose(state, 'compose-modal', compose => {
|
|
|
|
|
compose.text = [compose.text.trim(), `@${action.account.acct} `].filter((str) => str.length !== 0).join(' ');
|
|
|
|
|
compose.focusDate = new Date();
|
|
|
|
|
compose.caretPosition = null;
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_DIRECT:
|
|
|
|
|
return updateCompose(state, 'compose-modal', compose => compose.withMutations(map => {
|
|
|
|
|
map.update('text', text => [text.trim(), `@${action.account.acct} `].filter((str) => str.length !== 0).join(' '));
|
|
|
|
|
map.set('privacy', 'direct');
|
|
|
|
|
map.set('focusDate', new Date());
|
|
|
|
|
map.set('caretPosition', null);
|
|
|
|
|
map.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
}));
|
|
|
|
|
return updateCompose(state, 'compose-modal', compose => {
|
|
|
|
|
compose.text = [compose.text.trim(), `@${action.account.acct} `].filter((str) => str.length !== 0).join(' ');
|
|
|
|
|
compose.privacy = 'direct';
|
|
|
|
|
compose.focusDate = new Date();
|
|
|
|
|
compose.caretPosition = null;
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_GROUP_POST:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.withMutations(map => {
|
|
|
|
|
map.set('privacy', 'group');
|
|
|
|
|
map.set('group_id', action.groupId);
|
|
|
|
|
map.set('focusDate', new Date());
|
|
|
|
|
map.set('caretPosition', null);
|
|
|
|
|
map.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
}));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.privacy = 'group';
|
|
|
|
|
compose.group_id = action.groupId;
|
|
|
|
|
compose.focusDate = new Date();
|
|
|
|
|
compose.caretPosition = null;
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_SUGGESTIONS_CLEAR:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.update('suggestions', list => list?.clear()).set('suggestion_token', null));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.suggestions = compose.suggestions.clear();
|
|
|
|
|
compose.suggestion_token = null;
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_SUGGESTIONS_READY:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('suggestions', ImmutableList(action.accounts ? action.accounts.map((item: APIEntity) => item.id) : action.emojis)).set('suggestion_token', action.token));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.suggestions = ImmutableList(action.accounts ? action.accounts.map((item: APIEntity) => item.id) : action.emojis);
|
|
|
|
|
compose.suggestion_token = action.token;
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_SUGGESTION_SELECT:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => insertSuggestion(compose, action.position, action.token, action.completion, action.path));
|
|
|
|
|
case COMPOSE_SUGGESTION_TAGS_UPDATE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => updateSuggestionTags(compose, action.token, action.tags));
|
|
|
|
|
case COMPOSE_TAG_HISTORY_UPDATE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('tagHistory', ImmutableList(fromJS(action.tags)) as ImmutableList<string>));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.tagHistory = ImmutableList(fromJS(action.tags)) as ImmutableList<string>;
|
|
|
|
|
});
|
|
|
|
|
case TIMELINE_DELETE:
|
|
|
|
|
return updateCompose(state, 'compose-modal', compose => {
|
|
|
|
|
if (action.statusId === compose.in_reply_to) {
|
|
|
|
|
return compose.set('in_reply_to', null);
|
|
|
|
|
compose.in_reply_to = null;
|
|
|
|
|
} if (action.statusId === compose.quote) {
|
|
|
|
|
return compose.set('quote', null);
|
|
|
|
|
} else {
|
|
|
|
|
return compose;
|
|
|
|
|
compose.quote = null;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_EMOJI_INSERT:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => insertEmoji(compose, action.position, action.emoji, action.needsSpace));
|
|
|
|
|
case COMPOSE_UPLOAD_CHANGE_SUCCESS:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose
|
|
|
|
|
.set('is_changing_upload', false)
|
|
|
|
|
.update('media_attachments', list => list.map(item => {
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.is_changing_upload = false;
|
|
|
|
|
|
|
|
|
|
compose.media_attachments = compose.media_attachments.map(item => {
|
|
|
|
|
if (item.id === action.media.id) {
|
|
|
|
|
return action.media;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return item;
|
|
|
|
|
})));
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_SET_STATUS:
|
|
|
|
|
return updateCompose(state, 'compose-modal', compose => compose.withMutations(map => {
|
|
|
|
|
return updateCompose(state, 'compose-modal', compose => {
|
|
|
|
|
const to = action.explicitAddressing ? getExplicitMentions(action.status.account.id, action.status) : ImmutableOrderedSet<string>();
|
|
|
|
|
if (!action.withRedraft && !action.draftId) {
|
|
|
|
|
map.set('id', action.status.id);
|
|
|
|
|
compose.id = action.status.id;
|
|
|
|
|
}
|
|
|
|
|
map.set('text', action.rawText || unescapeHTML(expandMentions(action.status)));
|
|
|
|
|
map.set('to', to);
|
|
|
|
|
map.set('parent_reblogged_by', null);
|
|
|
|
|
map.set('in_reply_to', action.status.in_reply_to_id);
|
|
|
|
|
map.set('privacy', action.status.visibility);
|
|
|
|
|
map.set('focusDate', new Date());
|
|
|
|
|
map.set('caretPosition', null);
|
|
|
|
|
map.set('idempotencyKey', crypto.randomUUID());
|
|
|
|
|
map.set('content_type', action.contentType || 'text/plain');
|
|
|
|
|
map.set('quote', action.status.quote_id);
|
|
|
|
|
map.set('group_id', action.status.group_id);
|
|
|
|
|
compose.text = action.rawText || unescapeHTML(expandMentions(action.status));
|
|
|
|
|
compose.to = to;
|
|
|
|
|
compose.parent_reblogged_by = null;
|
|
|
|
|
compose.in_reply_to = action.status.in_reply_to_id;
|
|
|
|
|
compose.privacy = action.status.visibility;
|
|
|
|
|
compose.focusDate = new Date();
|
|
|
|
|
compose.caretPosition = null;
|
|
|
|
|
compose.idempotencyKey = crypto.randomUUID();
|
|
|
|
|
compose.content_type = action.contentType || 'text/plain';
|
|
|
|
|
compose.quote = action.status.quote_id;
|
|
|
|
|
compose.group_id = action.status.group_id;
|
|
|
|
|
|
|
|
|
|
if (action.v?.software === PLEROMA && action.withRedraft && hasIntegerMediaIds(action.status)) {
|
|
|
|
|
map.set('media_attachments', ImmutableList());
|
|
|
|
|
compose.media_attachments = ImmutableList();
|
|
|
|
|
} else {
|
|
|
|
|
map.set('media_attachments', ImmutableList(action.status.media_attachments));
|
|
|
|
|
compose.media_attachments = ImmutableList(action.status.media_attachments);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (action.status.spoiler_text.length > 0) {
|
|
|
|
|
map.set('spoiler_text', action.status.spoiler_text);
|
|
|
|
|
compose.spoiler_text = action.status.spoiler_text;
|
|
|
|
|
} else {
|
|
|
|
|
map.set('spoiler_text', '');
|
|
|
|
|
compose.spoiler_text = '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (action.poll) {
|
|
|
|
|
map.set('poll', PollRecord({
|
|
|
|
|
compose.poll = newPoll({
|
|
|
|
|
options: ImmutableList(action.poll.options.map(({ title }) => title)),
|
|
|
|
|
multiple: action.poll.multiple,
|
|
|
|
|
expires_in: 24 * 3600,
|
|
|
|
|
}));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (action.draftId) {
|
|
|
|
|
map.set('draft_id', action.draftId);
|
|
|
|
|
compose.draft_id = action.draftId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (action.editorState) {
|
|
|
|
|
map.set('editorState', action.editorState);
|
|
|
|
|
compose.editorState = action.editorState;
|
|
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_POLL_ADD:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('poll', PollRecord()));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.poll = newPoll();
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_POLL_REMOVE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('poll', null));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.poll = null;
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_SCHEDULE_ADD:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('schedule', new Date(Date.now() + 10 * 60 * 1000)));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.schedule = new Date(Date.now() + 10 * 60 * 1000);
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_SCHEDULE_SET:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('schedule', action.date));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.schedule = action.date;
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_SCHEDULE_REMOVE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('schedule', null));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.schedule = null;
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_POLL_OPTION_ADD:
|
|
|
|
|
return updateCompose(state, action.composeId, compose =>
|
|
|
|
|
compose
|
|
|
|
|
.updateIn(['poll', 'options'], options => (options as ImmutableList<string>).push(action.title))
|
|
|
|
|
.updateIn(['poll', 'options_map'], options_map => (options_map as ImmutableList<ImmutableMap<Language, string>>).push(ImmutableMap(compose.textMap.map(_ => action.title)))),
|
|
|
|
|
);
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
if (!compose.poll) return;
|
|
|
|
|
compose.poll.options = compose.poll.options.push(action.title);
|
|
|
|
|
compose.poll.options_map = compose.poll.options_map.push(ImmutableMap(compose.textMap.map(_ => action.title)));
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_POLL_OPTION_CHANGE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose =>
|
|
|
|
|
compose.setIn(!compose.modified_language || compose.modified_language === compose.language ? ['poll', 'options', action.index] : ['poll', 'options_map', action.index, compose.modified_language], action.title),
|
|
|
|
|
);
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
if (!compose.poll) return;
|
|
|
|
|
if (!compose.modified_language || compose.modified_language === compose.language) {
|
|
|
|
|
compose.poll.options = compose.poll.options.set(action.index, action.title);
|
|
|
|
|
compose.poll.options_map = compose.poll.options_map.setIn([action.index, compose.modified_language], action.title);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_POLL_OPTION_REMOVE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose =>
|
|
|
|
|
compose
|
|
|
|
|
.updateIn(['poll', 'options'], options => (options as ImmutableList<string>).delete(action.index))
|
|
|
|
|
.updateIn(['poll', 'options_map'], options_map => (options_map as ImmutableList<ImmutableMap<Language, string>>).delete(action.index)),
|
|
|
|
|
);
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
if (!compose.poll) return;
|
|
|
|
|
compose.poll.options = compose.poll.options.delete(action.index);
|
|
|
|
|
compose.poll.options_map = compose.poll.options_map.delete(action.index);
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_POLL_SETTINGS_CHANGE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.update('poll', poll => {
|
|
|
|
|
if (!poll) return null;
|
|
|
|
|
return poll.withMutations((poll) => {
|
|
|
|
|
if (action.expiresIn) {
|
|
|
|
|
poll.set('expires_in', action.expiresIn);
|
|
|
|
|
}
|
|
|
|
|
if (typeof action.isMultiple === 'boolean') {
|
|
|
|
|
poll.set('multiple', action.isMultiple);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
if (!compose.poll) return null;
|
|
|
|
|
if (action.expiresIn) {
|
|
|
|
|
compose.poll.expires_in = action.expiresIn;
|
|
|
|
|
}
|
|
|
|
|
if (typeof action.isMultiple === 'boolean') {
|
|
|
|
|
compose.poll.multiple = action.isMultiple;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_ADD_TO_MENTIONS:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.update('to', mentions => mentions!.add(action.account)));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.to = compose.to.add(action.account);
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_REMOVE_FROM_MENTIONS:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.update('to', mentions => mentions!.delete(action.account)));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.to = compose.to.delete(action.account);
|
|
|
|
|
});
|
|
|
|
|
case ME_FETCH_SUCCESS:
|
|
|
|
|
case ME_PATCH_SUCCESS:
|
|
|
|
|
return updateCompose(state, 'default', compose => importAccount(compose, action.me));
|
|
|
|
|
// case SETTING_CHANGE:
|
|
|
|
|
// return updateCompose(state, 'default', compose => updateSetting(compose, action.path, action.value));
|
|
|
|
|
case COMPOSE_EDITOR_STATE_SET:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose
|
|
|
|
|
.setIn(!compose.modified_language || compose.modified_language === compose.language ? ['editorState'] : ['editorStateMap', compose.modified_language], action.editorState as string)
|
|
|
|
|
.setIn(!compose.modified_language || compose.modified_language === compose.language ? ['text'] : ['textMap', compose.modified_language], action.text as string));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
if (!compose.modified_language || compose.modified_language) {
|
|
|
|
|
compose.editorState = action.editorState as string;
|
|
|
|
|
compose.text = action.text as string;
|
|
|
|
|
} else {
|
|
|
|
|
compose.editorStateMap = compose.editorStateMap.set(compose.modified_language, action.editorState as string);
|
|
|
|
|
compose.textMap = compose.textMap.set(compose.modified_language, action.text as string);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
case EVENT_COMPOSE_CANCEL:
|
|
|
|
|
return updateCompose(state, 'event-compose-modal', compose => compose.set('text', ''));
|
|
|
|
|
return updateCompose(state, 'event-compose-modal', compose => {
|
|
|
|
|
compose.text = '';
|
|
|
|
|
});
|
|
|
|
|
case EVENT_FORM_SET:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('text', action.text));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.text = action.text;
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_CHANGE_MEDIA_ORDER:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.update('media_attachments', list => {
|
|
|
|
|
const indexA = list.findIndex(x => x.id === action.a);
|
|
|
|
|
const moveItem = list.get(indexA)!;
|
|
|
|
|
const indexB = list.findIndex(x => x.id === action.b);
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
const indexA = compose.media_attachments.findIndex(x => x.id === action.a);
|
|
|
|
|
const moveItem = compose.media_attachments.get(indexA)!;
|
|
|
|
|
const indexB = compose.media_attachments.findIndex(x => x.id === action.b);
|
|
|
|
|
|
|
|
|
|
return list.splice(indexA, 1).splice(indexB, 0, moveItem);
|
|
|
|
|
}));
|
|
|
|
|
return compose.media_attachments.splice(indexA, 1).splice(indexB, 0, moveItem);
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_ADD_SUGGESTED_QUOTE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('quote', action.quoteId));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.quote = action.quoteId;
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_ADD_SUGGESTED_LANGUAGE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.set('suggested_language', action.language));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.suggested_language = action.language;
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_LANGUAGE_ADD:
|
|
|
|
|
return updateCompose(state, action.composeId, compose =>
|
|
|
|
|
compose
|
|
|
|
|
.setIn(['editorStateMap', action.value], compose.editorState)
|
|
|
|
|
.setIn(['textMap', action.value], compose.text)
|
|
|
|
|
.setIn(['spoilerTextMap', action.value], compose.spoiler_text)
|
|
|
|
|
.update('poll', poll => {
|
|
|
|
|
if (!poll) return poll;
|
|
|
|
|
return poll.update('options_map', optionsMap => optionsMap.map((option, key) => option.set(action.value, poll.options.get(key)!)));
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.editorStateMap = compose.editorStateMap.set(action.value, compose.editorState);
|
|
|
|
|
compose.textMap = compose.textMap.set(action.value, compose.text);
|
|
|
|
|
compose.spoilerTextMap = compose.spoilerTextMap.set(action.value, compose.spoiler_text);
|
|
|
|
|
if (compose.poll) compose.poll.options_map = compose.poll.options_map.map((option, key) => option.set(action.value, compose.poll!.options.get(key)!));
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_LANGUAGE_DELETE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose
|
|
|
|
|
.removeIn(['editorStateMap', action.value])
|
|
|
|
|
.removeIn(['textMap', action.value])
|
|
|
|
|
.removeIn(['spoilerTextMap', action.value]));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.editorStateMap = compose.editorStateMap.delete(action.value);
|
|
|
|
|
compose.textMap = compose.textMap.delete(action.value);
|
|
|
|
|
compose.spoilerTextMap = compose.spoilerTextMap.delete(action.value);
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_QUOTE_CANCEL:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose
|
|
|
|
|
.update('dismissed_quotes', quotes => compose.quote ? quotes.add(compose.quote) : quotes)
|
|
|
|
|
.set('quote', null));
|
|
|
|
|
return updateCompose(state, action.composeId, (compose) => {
|
|
|
|
|
if (compose.quote) compose.dismissed_quotes = compose.dismissed_quotes.add(compose.quote);
|
|
|
|
|
compose.quote = null;
|
|
|
|
|
});
|
|
|
|
|
case COMPOSE_FEDERATED_CHANGE:
|
|
|
|
|
return updateCompose(state, action.composeId, compose => compose.update('federated', value => !value));
|
|
|
|
|
return updateCompose(state, action.composeId, compose => {
|
|
|
|
|
compose.federated = !compose.federated;
|
|
|
|
|
});
|
|
|
|
|
case INSTANCE_FETCH_SUCCESS:
|
|
|
|
|
return updateCompose(state, 'default', (compose) => updateDefaultContentType(compose, action.instance));
|
|
|
|
|
default:
|
|
|
|
@ -606,7 +711,7 @@ const compose = (state = initialState, action: ComposeAction | EventsAction | In
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export {
|
|
|
|
|
ReducerCompose,
|
|
|
|
|
type Compose,
|
|
|
|
|
statusToMentionsAccountIdsArray,
|
|
|
|
|
initialState,
|
|
|
|
|
compose as default,
|
|
|
|
|