Merge remote-tracking branch 'parent/main' into upstream-20240123

This commit is contained in:
KMY 2025-01-23 18:10:34 +09:00
commit 50ae2d9439
320 changed files with 2587 additions and 2817 deletions

View file

@ -1,5 +1,6 @@
import { Map as ImmutableMap, List as ImmutableList, OrderedSet as ImmutableOrderedSet, fromJS } from 'immutable';
import { changeUploadCompose } from 'mastodon/actions/compose_typed';
import { timelineDelete } from 'mastodon/actions/timelines_typed';
import {
@ -40,18 +41,12 @@ import {
COMPOSE_EXPIRATION_INSERT,
COMPOSE_FEATURED_TAG_INSERT,
COMPOSE_REFERENCE_INSERT,
COMPOSE_UPLOAD_CHANGE_REQUEST,
COMPOSE_UPLOAD_CHANGE_SUCCESS,
COMPOSE_UPLOAD_CHANGE_FAIL,
COMPOSE_RESET,
COMPOSE_POLL_ADD,
COMPOSE_POLL_REMOVE,
COMPOSE_POLL_OPTION_CHANGE,
COMPOSE_POLL_SETTINGS_CHANGE,
COMPOSE_CIRCLE_CHANGE,
INIT_MEDIA_EDIT_MODAL,
COMPOSE_CHANGE_MEDIA_DESCRIPTION,
COMPOSE_CHANGE_MEDIA_FOCUS,
COMPOSE_CHANGE_MEDIA_ORDER,
COMPOSE_SET_STATUS,
COMPOSE_SEARCHABILITY_CHANGE,
@ -99,13 +94,6 @@ const initialState = ImmutableMap({
resetFileKey: Math.floor((Math.random() * 0x10000)),
idempotencyKey: null,
tagHistory: ImmutableList(),
media_modal: ImmutableMap({
id: null,
description: '',
focusX: 0,
focusY: 0,
dirty: false,
}),
posted_on_this_session: false,
});
@ -394,7 +382,24 @@ const updatePoll = (state, index, value, maxOptions) => state.updateIn(['poll',
return tmp;
});
export default function compose(state = initialState, action) {
/** @type {import('@reduxjs/toolkit').Reducer<typeof initialState>} */
export const composeReducer = (state = initialState, action) => {
if (changeUploadCompose.fulfilled.match(action)) {
return state
.set('is_changing_upload', false)
.update('media_attachments', list => list.map(item => {
if (item.get('id') === action.payload.media.id) {
return fromJS(action.payload.media).set('unattached', !action.payload.attached);
}
return item;
}));
} else if (changeUploadCompose.pending.match(action)) {
return state.set('is_changing_upload', true);
} else if (changeUploadCompose.rejected.match(action)) {
return state.set('is_changing_upload', false);
}
switch(action.type) {
case STORE_HYDRATE:
return hydrate(state, action.state.get('compose'));
@ -487,16 +492,13 @@ export default function compose(state = initialState, action) {
});
case COMPOSE_SUBMIT_REQUEST:
return state.set('is_submitting', true);
case COMPOSE_UPLOAD_CHANGE_REQUEST:
return state.set('is_changing_upload', true);
case COMPOSE_REPLY_CANCEL:
case COMPOSE_RESET:
case COMPOSE_SUBMIT_SUCCESS:
return clearAll(state);
case COMPOSE_SUBMIT_FAIL:
return state.set('is_submitting', false);
case COMPOSE_UPLOAD_CHANGE_FAIL:
return state.set('is_changing_upload', false);
case COMPOSE_UPLOAD_REQUEST:
return state.set('is_uploading', true).update('pending_media_attachments', n => n + 1);
case COMPOSE_UPLOAD_PROCESSING:
@ -525,20 +527,6 @@ export default function compose(state = initialState, action) {
return item;
}));
case INIT_MEDIA_EDIT_MODAL: {
const media = state.get('media_attachments').find(item => item.get('id') === action.id);
return state.set('media_modal', ImmutableMap({
id: action.id,
description: media.get('description') || '',
focusX: media.getIn(['meta', 'focus', 'x'], 0),
focusY: media.getIn(['meta', 'focus', 'y'], 0),
dirty: false,
}));
}
case COMPOSE_CHANGE_MEDIA_DESCRIPTION:
return state.setIn(['media_modal', 'description'], action.description).setIn(['media_modal', 'dirty'], true);
case COMPOSE_CHANGE_MEDIA_FOCUS:
return state.setIn(['media_modal', 'focusX'], action.focusX).setIn(['media_modal', 'focusY'], action.focusY).setIn(['media_modal', 'dirty'], true);
case COMPOSE_MENTION:
return state.withMutations(map => {
map.update('text', text => [text.trim(), `@${action.account.get('acct')} `].filter((str) => str.length !== 0).join(' '));
@ -587,17 +575,6 @@ export default function compose(state = initialState, action) {
return insertFeaturedTag(state, action.position, action.data);
case COMPOSE_REFERENCE_INSERT:
return insertReference(state, action.url, action.attributeType);
case COMPOSE_UPLOAD_CHANGE_SUCCESS:
return state
.set('is_changing_upload', false)
.setIn(['media_modal', 'dirty'], false)
.update('media_attachments', list => list.map(item => {
if (item.get('id') === action.media.id) {
return fromJS(action.media).set('unattached', !action.attached);
}
return item;
}));
case REDRAFT:
return state.withMutations(map => {
map.set('text', action.raw_text || unescapeHTML(expandMentions(action.status)));
@ -692,4 +669,4 @@ export default function compose(state = initialState, action) {
default:
return state;
}
}
};

View file

@ -10,7 +10,7 @@ import announcements from './announcements';
import { antennasReducer } from './antennas';
import { bookmarkCategoriesReducer } from './bookmark_categories';
import { circlesReducer } from './circles';
import compose from './compose';
import { composeReducer } from './compose';
import contexts from './contexts';
import conversations from './conversations';
import custom_emojis from './custom_emojis';
@ -63,7 +63,7 @@ const reducers = {
push_notifications,
server,
contexts,
compose,
compose: composeReducer,
search: searchReducer,
media_attachments,
notifications,

View file

@ -3,7 +3,6 @@ import { Record as ImmutableRecord, Stack } from 'immutable';
import { timelineDelete } from 'mastodon/actions/timelines_typed';
import { COMPOSE_UPLOAD_CHANGE_SUCCESS } from '../actions/compose';
import type { ModalType } from '../actions/modal';
import { openModal, closeModal } from '../actions/modal';
@ -53,12 +52,36 @@ const pushModal = (
state: State,
modalType: ModalType,
modalProps: ModalProps,
previousModalProps?: ModalProps,
): State => {
return state.withMutations((record) => {
record.set('ignoreFocus', false);
record.update('stack', (stack) =>
stack.unshift(Modal({ modalType, modalProps })),
);
record.update('stack', (stack) => {
let tmp = stack;
// With this option, we update the previously opened modal, so that when the
// current (new) modal is closed, the previous modal is re-opened with different
// props. Specifically, this is useful for the confirmation modal.
if (previousModalProps) {
const previousModal = tmp.first() as Modal | undefined;
if (previousModal) {
tmp = tmp.shift().unshift(
Modal({
modalType: previousModal.modalType,
modalProps: {
...previousModal.modalProps,
...previousModalProps,
},
}),
);
}
}
tmp = tmp.unshift(Modal({ modalType, modalProps }));
return tmp;
});
});
};
@ -68,11 +91,10 @@ export const modalReducer: Reducer<State> = (state = initialState, action) => {
state,
action.payload.modalType,
action.payload.modalProps,
action.payload.previousModalProps,
);
else if (closeModal.match(action)) return popModal(state, action.payload);
// TODO: type those actions
else if (action.type === COMPOSE_UPLOAD_CHANGE_SUCCESS)
return popModal(state, { modalType: 'FOCAL_POINT', ignoreFocus: false });
else if (timelineDelete.match(action))
return state.update('stack', (stack) =>
stack.filterNot(