Merge tag 'v3.1.1' into instance_only_statuses
This commit is contained in:
102
app/javascript/mastodon/reducers/announcements.js
Normal file
102
app/javascript/mastodon/reducers/announcements.js
Normal file
@ -0,0 +1,102 @@
|
||||
import {
|
||||
ANNOUNCEMENTS_FETCH_REQUEST,
|
||||
ANNOUNCEMENTS_FETCH_SUCCESS,
|
||||
ANNOUNCEMENTS_FETCH_FAIL,
|
||||
ANNOUNCEMENTS_UPDATE,
|
||||
ANNOUNCEMENTS_REACTION_UPDATE,
|
||||
ANNOUNCEMENTS_REACTION_ADD_REQUEST,
|
||||
ANNOUNCEMENTS_REACTION_ADD_FAIL,
|
||||
ANNOUNCEMENTS_REACTION_REMOVE_REQUEST,
|
||||
ANNOUNCEMENTS_REACTION_REMOVE_FAIL,
|
||||
ANNOUNCEMENTS_TOGGLE_SHOW,
|
||||
ANNOUNCEMENTS_DELETE,
|
||||
ANNOUNCEMENTS_DISMISS_SUCCESS,
|
||||
} from '../actions/announcements';
|
||||
import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
items: ImmutableList(),
|
||||
isLoading: false,
|
||||
show: false,
|
||||
});
|
||||
|
||||
const updateReaction = (state, id, name, updater) => state.update('items', list => list.map(announcement => {
|
||||
if (announcement.get('id') === id) {
|
||||
return announcement.update('reactions', reactions => {
|
||||
const idx = reactions.findIndex(reaction => reaction.get('name') === name);
|
||||
|
||||
if (idx > -1) {
|
||||
return reactions.update(idx, reaction => updater(reaction));
|
||||
}
|
||||
|
||||
return reactions.push(updater(fromJS({ name, count: 0 })));
|
||||
});
|
||||
}
|
||||
|
||||
return announcement;
|
||||
}));
|
||||
|
||||
const updateReactionCount = (state, reaction) => updateReaction(state, reaction.announcement_id, reaction.name, x => x.set('count', reaction.count));
|
||||
|
||||
const addReaction = (state, id, name) => updateReaction(state, id, name, x => x.set('me', true).update('count', y => y + 1));
|
||||
|
||||
const removeReaction = (state, id, name) => updateReaction(state, id, name, x => x.set('me', false).update('count', y => y - 1));
|
||||
|
||||
const sortAnnouncements = list => list.sortBy(x => x.get('starts_at') || x.get('published_at'));
|
||||
|
||||
const updateAnnouncement = (state, announcement) => {
|
||||
const idx = state.get('items').findIndex(x => x.get('id') === announcement.get('id'));
|
||||
|
||||
if (idx > -1) {
|
||||
// Deep merge is used because announcements from the streaming API do not contain
|
||||
// personalized data about which reactions have been selected by the given user,
|
||||
// and that is information we want to preserve
|
||||
return state.update('items', list => sortAnnouncements(list.update(idx, x => x.mergeDeep(announcement))));
|
||||
}
|
||||
|
||||
return state.update('items', list => sortAnnouncements(list.unshift(announcement)));
|
||||
};
|
||||
|
||||
export default function announcementsReducer(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case ANNOUNCEMENTS_TOGGLE_SHOW:
|
||||
return state.withMutations(map => {
|
||||
map.set('show', !map.get('show'));
|
||||
});
|
||||
case ANNOUNCEMENTS_FETCH_REQUEST:
|
||||
return state.set('isLoading', true);
|
||||
case ANNOUNCEMENTS_FETCH_SUCCESS:
|
||||
return state.withMutations(map => {
|
||||
const items = fromJS(action.announcements);
|
||||
|
||||
map.set('items', items);
|
||||
map.set('isLoading', false);
|
||||
});
|
||||
case ANNOUNCEMENTS_FETCH_FAIL:
|
||||
return state.set('isLoading', false);
|
||||
case ANNOUNCEMENTS_UPDATE:
|
||||
return updateAnnouncement(state, fromJS(action.announcement));
|
||||
case ANNOUNCEMENTS_REACTION_UPDATE:
|
||||
return updateReactionCount(state, action.reaction);
|
||||
case ANNOUNCEMENTS_REACTION_ADD_REQUEST:
|
||||
case ANNOUNCEMENTS_REACTION_REMOVE_FAIL:
|
||||
return addReaction(state, action.id, action.name);
|
||||
case ANNOUNCEMENTS_REACTION_REMOVE_REQUEST:
|
||||
case ANNOUNCEMENTS_REACTION_ADD_FAIL:
|
||||
return removeReaction(state, action.id, action.name);
|
||||
case ANNOUNCEMENTS_DISMISS_SUCCESS:
|
||||
return updateAnnouncement(state, fromJS({ 'id': action.id, 'read': true }));
|
||||
case ANNOUNCEMENTS_DELETE:
|
||||
return state.update('items', list => {
|
||||
const idx = list.findIndex(x => x.get('id') === action.id);
|
||||
|
||||
if (idx > -1) {
|
||||
return list.delete(idx);
|
||||
}
|
||||
|
||||
return list;
|
||||
});
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
@ -63,6 +63,7 @@ const initialState = ImmutableMap({
|
||||
is_uploading: false,
|
||||
progress: 0,
|
||||
media_attachments: ImmutableList(),
|
||||
pending_media_attachments: 0,
|
||||
poll: null,
|
||||
suggestion_token: null,
|
||||
suggestions: ImmutableList(),
|
||||
@ -118,6 +119,7 @@ function appendMedia(state, media, file) {
|
||||
map.set('is_uploading', false);
|
||||
map.set('resetFileKey', Math.floor((Math.random() * 0x10000)));
|
||||
map.set('idempotencyKey', uuid());
|
||||
map.update('pending_media_attachments', n => n - 1);
|
||||
|
||||
if (prevSize === 0 && (state.get('default_sensitive') || state.get('spoiler'))) {
|
||||
map.set('sensitive', true);
|
||||
@ -332,11 +334,11 @@ export default function compose(state = initialState, action) {
|
||||
case COMPOSE_UPLOAD_CHANGE_FAIL:
|
||||
return state.set('is_changing_upload', false);
|
||||
case COMPOSE_UPLOAD_REQUEST:
|
||||
return state.set('is_uploading', true);
|
||||
return state.set('is_uploading', true).update('pending_media_attachments', n => n + 1);
|
||||
case COMPOSE_UPLOAD_SUCCESS:
|
||||
return appendMedia(state, fromJS(action.media), action.file);
|
||||
case COMPOSE_UPLOAD_FAIL:
|
||||
return state.set('is_uploading', false);
|
||||
return state.set('is_uploading', false).update('pending_media_attachments', n => n - 1);
|
||||
case COMPOSE_UPLOAD_UNDO:
|
||||
return removeMedia(state, action.media_id);
|
||||
case COMPOSE_UPLOAD_PROGRESS:
|
||||
|
@ -34,8 +34,10 @@ import polls from './polls';
|
||||
import identity_proofs from './identity_proofs';
|
||||
import trends from './trends';
|
||||
import missed_updates from './missed_updates';
|
||||
import announcements from './announcements';
|
||||
|
||||
const reducers = {
|
||||
announcements,
|
||||
dropdown_menu,
|
||||
timelines,
|
||||
meta,
|
||||
|
@ -13,6 +13,8 @@ import {
|
||||
import {
|
||||
ACCOUNT_BLOCK_SUCCESS,
|
||||
ACCOUNT_MUTE_SUCCESS,
|
||||
FOLLOW_REQUEST_AUTHORIZE_SUCCESS,
|
||||
FOLLOW_REQUEST_REJECT_SUCCESS,
|
||||
} from '../actions/accounts';
|
||||
import { DOMAIN_BLOCK_SUCCESS } from 'mastodon/actions/domain_blocks';
|
||||
import { TIMELINE_DELETE, TIMELINE_DISCONNECT } from '../actions/timelines';
|
||||
@ -89,8 +91,8 @@ const expandNormalizedNotifications = (state, notifications, next, isLoadingRece
|
||||
});
|
||||
};
|
||||
|
||||
const filterNotifications = (state, accountIds) => {
|
||||
const helper = list => list.filterNot(item => item !== null && accountIds.includes(item.get('account')));
|
||||
const filterNotifications = (state, accountIds, type) => {
|
||||
const helper = list => list.filterNot(item => item !== null && accountIds.includes(item.get('account')) && (type === undefined || type === item.get('type')));
|
||||
return state.update('items', helper).update('pendingItems', helper);
|
||||
};
|
||||
|
||||
@ -129,6 +131,11 @@ export default function notifications(state = initialState, action) {
|
||||
return action.relationship.muting_notifications ? filterNotifications(state, [action.relationship.id]) : state;
|
||||
case DOMAIN_BLOCK_SUCCESS:
|
||||
return filterNotifications(state, action.accounts);
|
||||
case FOLLOW_REQUEST_AUTHORIZE_SUCCESS:
|
||||
case FOLLOW_REQUEST_REJECT_SUCCESS:
|
||||
return filterNotifications(state, [action.id], 'follow_request');
|
||||
case ACCOUNT_MUTE_SUCCESS:
|
||||
return action.relationship.muting_notifications ? filterNotifications(state, [action.relationship.id]) : state;
|
||||
case NOTIFICATIONS_CLEAR:
|
||||
return state.set('items', ImmutableList()).set('pendingItems', ImmutableList()).set('hasMore', false);
|
||||
case TIMELINE_DELETE:
|
||||
|
@ -6,6 +6,7 @@ const initialState = Immutable.Map({
|
||||
subscription: null,
|
||||
alerts: new Immutable.Map({
|
||||
follow: false,
|
||||
follow_request: false,
|
||||
favourite: false,
|
||||
reblog: false,
|
||||
mention: false,
|
||||
|
@ -30,6 +30,7 @@ const initialState = ImmutableMap({
|
||||
notifications: ImmutableMap({
|
||||
alerts: ImmutableMap({
|
||||
follow: true,
|
||||
follow_request: false,
|
||||
favourite: true,
|
||||
reblog: true,
|
||||
mention: true,
|
||||
@ -44,6 +45,7 @@ const initialState = ImmutableMap({
|
||||
|
||||
shows: ImmutableMap({
|
||||
follow: true,
|
||||
follow_request: false,
|
||||
favourite: true,
|
||||
reblog: true,
|
||||
mention: true,
|
||||
@ -52,6 +54,7 @@ const initialState = ImmutableMap({
|
||||
|
||||
sounds: ImmutableMap({
|
||||
follow: true,
|
||||
follow_request: false,
|
||||
favourite: true,
|
||||
reblog: true,
|
||||
mention: true,
|
||||
|
@ -6,6 +6,14 @@ import {
|
||||
FAVOURITED_STATUSES_EXPAND_SUCCESS,
|
||||
FAVOURITED_STATUSES_EXPAND_FAIL,
|
||||
} from '../actions/favourites';
|
||||
import {
|
||||
BOOKMARKED_STATUSES_FETCH_REQUEST,
|
||||
BOOKMARKED_STATUSES_FETCH_SUCCESS,
|
||||
BOOKMARKED_STATUSES_FETCH_FAIL,
|
||||
BOOKMARKED_STATUSES_EXPAND_REQUEST,
|
||||
BOOKMARKED_STATUSES_EXPAND_SUCCESS,
|
||||
BOOKMARKED_STATUSES_EXPAND_FAIL,
|
||||
} from '../actions/bookmarks';
|
||||
import {
|
||||
PINNED_STATUSES_FETCH_SUCCESS,
|
||||
} from '../actions/pin_statuses';
|
||||
@ -13,6 +21,8 @@ import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
|
||||
import {
|
||||
FAVOURITE_SUCCESS,
|
||||
UNFAVOURITE_SUCCESS,
|
||||
BOOKMARK_SUCCESS,
|
||||
UNBOOKMARK_SUCCESS,
|
||||
PIN_SUCCESS,
|
||||
UNPIN_SUCCESS,
|
||||
} from '../actions/interactions';
|
||||
@ -23,6 +33,11 @@ const initialState = ImmutableMap({
|
||||
loaded: false,
|
||||
items: ImmutableList(),
|
||||
}),
|
||||
bookmarks: ImmutableMap({
|
||||
next: null,
|
||||
loaded: false,
|
||||
items: ImmutableList(),
|
||||
}),
|
||||
pins: ImmutableMap({
|
||||
next: null,
|
||||
loaded: false,
|
||||
@ -71,10 +86,24 @@ export default function statusLists(state = initialState, action) {
|
||||
return normalizeList(state, 'favourites', action.statuses, action.next);
|
||||
case FAVOURITED_STATUSES_EXPAND_SUCCESS:
|
||||
return appendToList(state, 'favourites', action.statuses, action.next);
|
||||
case BOOKMARKED_STATUSES_FETCH_REQUEST:
|
||||
case BOOKMARKED_STATUSES_EXPAND_REQUEST:
|
||||
return state.setIn(['bookmarks', 'isLoading'], true);
|
||||
case BOOKMARKED_STATUSES_FETCH_FAIL:
|
||||
case BOOKMARKED_STATUSES_EXPAND_FAIL:
|
||||
return state.setIn(['bookmarks', 'isLoading'], false);
|
||||
case BOOKMARKED_STATUSES_FETCH_SUCCESS:
|
||||
return normalizeList(state, 'bookmarks', action.statuses, action.next);
|
||||
case BOOKMARKED_STATUSES_EXPAND_SUCCESS:
|
||||
return appendToList(state, 'bookmarks', action.statuses, action.next);
|
||||
case FAVOURITE_SUCCESS:
|
||||
return prependOneToList(state, 'favourites', action.status);
|
||||
case UNFAVOURITE_SUCCESS:
|
||||
return removeOneFromList(state, 'favourites', action.status);
|
||||
case BOOKMARK_SUCCESS:
|
||||
return prependOneToList(state, 'bookmarks', action.status);
|
||||
case UNBOOKMARK_SUCCESS:
|
||||
return removeOneFromList(state, 'bookmarks', action.status);
|
||||
case PINNED_STATUSES_FETCH_SUCCESS:
|
||||
return normalizeList(state, 'pins', action.statuses, action.next);
|
||||
case PIN_SUCCESS:
|
||||
|
@ -3,12 +3,16 @@ import {
|
||||
REBLOG_FAIL,
|
||||
FAVOURITE_REQUEST,
|
||||
FAVOURITE_FAIL,
|
||||
UNFAVOURITE_SUCCESS,
|
||||
BOOKMARK_REQUEST,
|
||||
BOOKMARK_FAIL,
|
||||
} from '../actions/interactions';
|
||||
import {
|
||||
STATUS_MUTE_SUCCESS,
|
||||
STATUS_UNMUTE_SUCCESS,
|
||||
STATUS_REVEAL,
|
||||
STATUS_HIDE,
|
||||
STATUS_COLLAPSE,
|
||||
} from '../actions/statuses';
|
||||
import { TIMELINE_DELETE } from '../actions/timelines';
|
||||
import { STATUS_IMPORT, STATUSES_IMPORT } from '../actions/importer';
|
||||
@ -37,8 +41,14 @@ export default function statuses(state = initialState, action) {
|
||||
return importStatuses(state, action.statuses);
|
||||
case FAVOURITE_REQUEST:
|
||||
return state.setIn([action.status.get('id'), 'favourited'], true);
|
||||
case UNFAVOURITE_SUCCESS:
|
||||
return state.updateIn([action.status.get('id'), 'favourites_count'], x => Math.max(0, x - 1));
|
||||
case FAVOURITE_FAIL:
|
||||
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'favourited'], false);
|
||||
case BOOKMARK_REQUEST:
|
||||
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'bookmarked'], true);
|
||||
case BOOKMARK_FAIL:
|
||||
return state.get(action.status.get('id')) === undefined ? state : state.setIn([action.status.get('id'), 'bookmarked'], false);
|
||||
case REBLOG_REQUEST:
|
||||
return state.setIn([action.status.get('id'), 'reblogged'], true);
|
||||
case REBLOG_FAIL:
|
||||
@ -63,6 +73,8 @@ export default function statuses(state = initialState, action) {
|
||||
}
|
||||
});
|
||||
});
|
||||
case STATUS_COLLAPSE:
|
||||
return state.setIn([action.id, 'collapsed'], action.isCollapsed);
|
||||
case TIMELINE_DELETE:
|
||||
return deleteStatus(state, action.id, action.references);
|
||||
default:
|
||||
|
@ -1,3 +1,6 @@
|
||||
import {
|
||||
NOTIFICATIONS_UPDATE,
|
||||
} from '../actions/notifications';
|
||||
import {
|
||||
FOLLOWERS_FETCH_SUCCESS,
|
||||
FOLLOWERS_EXPAND_SUCCESS,
|
||||
@ -53,6 +56,12 @@ const appendToList = (state, type, id, accounts, next) => {
|
||||
});
|
||||
};
|
||||
|
||||
const normalizeFollowRequest = (state, notification) => {
|
||||
return state.updateIn(['follow_requests', 'items'], list => {
|
||||
return list.filterNot(item => item === notification.account.id).unshift(notification.account.id);
|
||||
});
|
||||
};
|
||||
|
||||
export default function userLists(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case FOLLOWERS_FETCH_SUCCESS:
|
||||
@ -67,6 +76,8 @@ export default function userLists(state = initialState, action) {
|
||||
return state.setIn(['reblogged_by', action.id], ImmutableList(action.accounts.map(item => item.id)));
|
||||
case FAVOURITES_FETCH_SUCCESS:
|
||||
return state.setIn(['favourited_by', action.id], ImmutableList(action.accounts.map(item => item.id)));
|
||||
case NOTIFICATIONS_UPDATE:
|
||||
return action.notification.type === 'follow_request' ? normalizeFollowRequest(state, action.notification) : state;
|
||||
case FOLLOW_REQUESTS_FETCH_SUCCESS:
|
||||
return state.setIn(['follow_requests', 'items'], ImmutableList(action.accounts.map(item => item.id))).setIn(['follow_requests', 'next'], action.next);
|
||||
case FOLLOW_REQUESTS_EXPAND_SUCCESS:
|
||||
|
Reference in New Issue
Block a user