Merge tag 'v2.8.0' into instance_only_statuses
This commit is contained in:
@ -30,6 +30,12 @@ import {
|
||||
COMPOSE_UPLOAD_CHANGE_SUCCESS,
|
||||
COMPOSE_UPLOAD_CHANGE_FAIL,
|
||||
COMPOSE_RESET,
|
||||
COMPOSE_POLL_ADD,
|
||||
COMPOSE_POLL_REMOVE,
|
||||
COMPOSE_POLL_OPTION_ADD,
|
||||
COMPOSE_POLL_OPTION_CHANGE,
|
||||
COMPOSE_POLL_OPTION_REMOVE,
|
||||
COMPOSE_POLL_SETTINGS_CHANGE,
|
||||
} from '../actions/compose';
|
||||
import { TIMELINE_DELETE } from '../actions/timelines';
|
||||
import { STORE_HYDRATE } from '../actions/store';
|
||||
@ -57,6 +63,7 @@ const initialState = ImmutableMap({
|
||||
is_uploading: false,
|
||||
progress: 0,
|
||||
media_attachments: ImmutableList(),
|
||||
poll: null,
|
||||
suggestion_token: null,
|
||||
suggestions: ImmutableList(),
|
||||
default_privacy: 'public',
|
||||
@ -67,6 +74,12 @@ const initialState = ImmutableMap({
|
||||
tagHistory: ImmutableList(),
|
||||
});
|
||||
|
||||
const initialPoll = ImmutableMap({
|
||||
options: ImmutableList(['', '']),
|
||||
expires_in: 24 * 3600,
|
||||
multiple: false,
|
||||
});
|
||||
|
||||
function statusToTextMentions(state, status) {
|
||||
let set = ImmutableOrderedSet([]);
|
||||
|
||||
@ -89,6 +102,7 @@ function clearAll(state) {
|
||||
map.set('federation', state.get('default_federation'));
|
||||
map.set('sensitive', false);
|
||||
map.update('media_attachments', list => list.clear());
|
||||
map.set('poll', null);
|
||||
map.set('idempotencyKey', uuid());
|
||||
});
|
||||
};
|
||||
@ -256,6 +270,7 @@ export default function compose(state = initialState, action) {
|
||||
map.set('spoiler', false);
|
||||
map.set('spoiler_text', '');
|
||||
map.set('privacy', state.get('default_privacy'));
|
||||
map.set('poll', null);
|
||||
map.set('federation', state.get('default_federation'));
|
||||
map.set('idempotencyKey', uuid());
|
||||
});
|
||||
@ -340,7 +355,27 @@ export default function compose(state = initialState, action) {
|
||||
map.set('spoiler', false);
|
||||
map.set('spoiler_text', '');
|
||||
}
|
||||
|
||||
if (action.status.get('poll')) {
|
||||
map.set('poll', ImmutableMap({
|
||||
options: action.status.getIn(['poll', 'options']).map(x => x.get('title')),
|
||||
multiple: action.status.getIn(['poll', 'multiple']),
|
||||
expires_in: 24 * 3600,
|
||||
}));
|
||||
}
|
||||
});
|
||||
case COMPOSE_POLL_ADD:
|
||||
return state.set('poll', initialPoll);
|
||||
case COMPOSE_POLL_REMOVE:
|
||||
return state.set('poll', null);
|
||||
case COMPOSE_POLL_OPTION_ADD:
|
||||
return state.updateIn(['poll', 'options'], options => options.push(action.title));
|
||||
case COMPOSE_POLL_OPTION_CHANGE:
|
||||
return state.setIn(['poll', 'options', action.index], action.title);
|
||||
case COMPOSE_POLL_OPTION_REMOVE:
|
||||
return state.updateIn(['poll', 'options'], options => options.delete(action.index));
|
||||
case COMPOSE_POLL_SETTINGS_CHANGE:
|
||||
return state.update('poll', poll => poll.set('expires_in', action.expiresIn).set('multiple', action.isMultiple));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ const updateConversation = (state, item) => state.update('items', list => {
|
||||
}
|
||||
});
|
||||
|
||||
const expandNormalizedConversations = (state, conversations, next) => {
|
||||
const expandNormalizedConversations = (state, conversations, next, isLoadingRecent) => {
|
||||
let items = ImmutableList(conversations.map(conversationToMap));
|
||||
|
||||
return state.withMutations(mutable => {
|
||||
@ -66,7 +66,7 @@ const expandNormalizedConversations = (state, conversations, next) => {
|
||||
});
|
||||
}
|
||||
|
||||
if (!next) {
|
||||
if (!next && !isLoadingRecent) {
|
||||
mutable.set('hasMore', false);
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ export default function conversations(state = initialState, action) {
|
||||
case CONVERSATIONS_FETCH_FAIL:
|
||||
return state.set('isLoading', false);
|
||||
case CONVERSATIONS_FETCH_SUCCESS:
|
||||
return expandNormalizedConversations(state, action.conversations, action.next);
|
||||
return expandNormalizedConversations(state, action.conversations, action.next, action.isLoadingRecent);
|
||||
case CONVERSATIONS_UPDATE:
|
||||
return updateConversation(state, action.conversation);
|
||||
case CONVERSATIONS_MOUNT:
|
||||
|
25
app/javascript/mastodon/reducers/identity_proofs.js
Normal file
25
app/javascript/mastodon/reducers/identity_proofs.js
Normal file
@ -0,0 +1,25 @@
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
import {
|
||||
IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST,
|
||||
IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS,
|
||||
IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL,
|
||||
} from '../actions/identity_proofs';
|
||||
|
||||
const initialState = ImmutableMap();
|
||||
|
||||
export default function identityProofsReducer(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case IDENTITY_PROOFS_ACCOUNT_FETCH_REQUEST:
|
||||
return state.set('isLoading', true);
|
||||
case IDENTITY_PROOFS_ACCOUNT_FETCH_FAIL:
|
||||
return state.set('isLoading', false);
|
||||
case IDENTITY_PROOFS_ACCOUNT_FETCH_SUCCESS:
|
||||
return state.update(identity_proofs => identity_proofs.withMutations(map => {
|
||||
map.set('isLoading', false);
|
||||
map.set('loaded', true);
|
||||
map.set(action.accountId, fromJS(action.identity_proofs));
|
||||
}));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
@ -29,6 +29,8 @@ import listAdder from './list_adder';
|
||||
import filters from './filters';
|
||||
import conversations from './conversations';
|
||||
import suggestions from './suggestions';
|
||||
import polls from './polls';
|
||||
import identity_proofs from './identity_proofs';
|
||||
|
||||
const reducers = {
|
||||
dropdown_menu,
|
||||
@ -55,12 +57,14 @@ const reducers = {
|
||||
notifications,
|
||||
height_cache,
|
||||
custom_emojis,
|
||||
identity_proofs,
|
||||
lists,
|
||||
listEditor,
|
||||
listAdder,
|
||||
filters,
|
||||
conversations,
|
||||
suggestions,
|
||||
polls,
|
||||
};
|
||||
|
||||
export default combineReducers(reducers);
|
||||
|
@ -22,6 +22,7 @@ import {
|
||||
const initialState = ImmutableMap({
|
||||
listId: null,
|
||||
isSubmitting: false,
|
||||
isChanged: false,
|
||||
title: '',
|
||||
|
||||
accounts: ImmutableMap({
|
||||
@ -47,10 +48,16 @@ export default function listEditorReducer(state = initialState, action) {
|
||||
map.set('isSubmitting', false);
|
||||
});
|
||||
case LIST_EDITOR_TITLE_CHANGE:
|
||||
return state.set('title', action.value);
|
||||
return state.withMutations(map => {
|
||||
map.set('title', action.value);
|
||||
map.set('isChanged', true);
|
||||
});
|
||||
case LIST_CREATE_REQUEST:
|
||||
case LIST_UPDATE_REQUEST:
|
||||
return state.set('isSubmitting', true);
|
||||
return state.withMutations(map => {
|
||||
map.set('isSubmitting', true);
|
||||
map.set('isChanged', false);
|
||||
});
|
||||
case LIST_CREATE_FAIL:
|
||||
case LIST_UPDATE_FAIL:
|
||||
return state.set('isSubmitting', false);
|
||||
|
@ -108,6 +108,7 @@ export default function notifications(state = initialState, action) {
|
||||
case NOTIFICATIONS_EXPAND_SUCCESS:
|
||||
return expandNormalizedNotifications(state, action.notifications, action.next);
|
||||
case ACCOUNT_BLOCK_SUCCESS:
|
||||
return filterNotifications(state, action.relationship);
|
||||
case ACCOUNT_MUTE_SUCCESS:
|
||||
return action.relationship.muting_notifications ? filterNotifications(state, action.relationship) : state;
|
||||
case NOTIFICATIONS_CLEAR:
|
||||
|
15
app/javascript/mastodon/reducers/polls.js
Normal file
15
app/javascript/mastodon/reducers/polls.js
Normal file
@ -0,0 +1,15 @@
|
||||
import { POLLS_IMPORT } from 'mastodon/actions/importer';
|
||||
import { Map as ImmutableMap, fromJS } from 'immutable';
|
||||
|
||||
const importPolls = (state, polls) => state.withMutations(map => polls.forEach(poll => map.set(poll.id, fromJS(poll))));
|
||||
|
||||
const initialState = ImmutableMap();
|
||||
|
||||
export default function polls(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case POLLS_IMPORT:
|
||||
return importPolls(state, action.polls);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ const initialState = Immutable.Map({
|
||||
favourite: false,
|
||||
reblog: false,
|
||||
mention: false,
|
||||
poll: false,
|
||||
}),
|
||||
isSubscribed: false,
|
||||
browserSupport: false,
|
||||
|
@ -31,6 +31,7 @@ const initialState = ImmutableMap({
|
||||
favourite: true,
|
||||
reblog: true,
|
||||
mention: true,
|
||||
poll: true,
|
||||
}),
|
||||
|
||||
quickFilter: ImmutableMap({
|
||||
@ -44,6 +45,7 @@ const initialState = ImmutableMap({
|
||||
favourite: true,
|
||||
reblog: true,
|
||||
mention: true,
|
||||
poll: true,
|
||||
}),
|
||||
|
||||
sounds: ImmutableMap({
|
||||
@ -51,6 +53,7 @@ const initialState = ImmutableMap({
|
||||
favourite: true,
|
||||
reblog: true,
|
||||
mention: true,
|
||||
poll: true,
|
||||
}),
|
||||
}),
|
||||
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
TIMELINE_EXPAND_REQUEST,
|
||||
TIMELINE_EXPAND_FAIL,
|
||||
TIMELINE_SCROLL_TOP,
|
||||
TIMELINE_CONNECT,
|
||||
TIMELINE_DISCONNECT,
|
||||
} from '../actions/timelines';
|
||||
import {
|
||||
@ -20,6 +21,7 @@ const initialState = ImmutableMap();
|
||||
|
||||
const initialTimeline = ImmutableMap({
|
||||
unread: 0,
|
||||
online: false,
|
||||
top: true,
|
||||
isLoading: false,
|
||||
hasMore: true,
|
||||
@ -29,6 +31,8 @@ const initialTimeline = ImmutableMap({
|
||||
const expandNormalizedTimeline = (state, timeline, statuses, next, isPartial, isLoadingRecent) => {
|
||||
return state.update(timeline, initialTimeline, map => map.withMutations(mMap => {
|
||||
mMap.set('isLoading', false);
|
||||
mMap.set('isPartial', isPartial);
|
||||
|
||||
if (!next && !isLoadingRecent) mMap.set('hasMore', false);
|
||||
|
||||
if (!statuses.isEmpty()) {
|
||||
@ -74,14 +78,15 @@ const updateTimeline = (state, timeline, status) => {
|
||||
}));
|
||||
};
|
||||
|
||||
const deleteStatus = (state, id, accountId, references) => {
|
||||
const deleteStatus = (state, id, accountId, references, exclude_account = null) => {
|
||||
state.keySeq().forEach(timeline => {
|
||||
state = state.updateIn([timeline, 'items'], list => list.filterNot(item => item === id));
|
||||
if (exclude_account === null || (timeline !== `account:${exclude_account}` && !timeline.startsWith(`account:${exclude_account}:`)))
|
||||
state = state.updateIn([timeline, 'items'], list => list.filterNot(item => item === id));
|
||||
});
|
||||
|
||||
// Remove reblogs of deleted status
|
||||
references.forEach(ref => {
|
||||
state = deleteStatus(state, ref[0], ref[1], []);
|
||||
state = deleteStatus(state, ref[0], ref[1], [], exclude_account);
|
||||
});
|
||||
|
||||
return state;
|
||||
@ -100,7 +105,7 @@ const filterTimelines = (state, relationship, statuses) => {
|
||||
}
|
||||
|
||||
references = statuses.filter(item => item.get('reblog') === status.get('id')).map(item => [item.get('id'), item.get('account')]);
|
||||
state = deleteStatus(state, status.get('id'), status.get('account'), references);
|
||||
state = deleteStatus(state, status.get('id'), status.get('account'), references, relationship.id);
|
||||
});
|
||||
|
||||
return state;
|
||||
@ -140,14 +145,13 @@ export default function timelines(state = initialState, action) {
|
||||
return filterTimeline('home', state, action.relationship, action.statuses);
|
||||
case TIMELINE_SCROLL_TOP:
|
||||
return updateTop(state, action.timeline, action.top);
|
||||
case TIMELINE_CONNECT:
|
||||
return state.update(action.timeline, initialTimeline, map => map.set('online', true));
|
||||
case TIMELINE_DISCONNECT:
|
||||
return state.update(
|
||||
action.timeline,
|
||||
initialTimeline,
|
||||
map => map.update(
|
||||
'items',
|
||||
items => items.first() ? items.unshift(null) : items
|
||||
)
|
||||
map => map.set('online', false).update('items', items => items.first() ? items.unshift(null) : items)
|
||||
);
|
||||
default:
|
||||
return state;
|
||||
|
Reference in New Issue
Block a user