@@ -1,4 +1,6 @@ | |||||
import api, { getLinks } from '../api'; | import api, { getLinks } from '../api'; | ||||
import asyncDB from '../db/async'; | |||||
import { importAccount, importFetchedAccount, importFetchedAccounts } from './importer'; | |||||
export const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST'; | export const ACCOUNT_FETCH_REQUEST = 'ACCOUNT_FETCH_REQUEST'; | ||||
export const ACCOUNT_FETCH_SUCCESS = 'ACCOUNT_FETCH_SUCCESS'; | export const ACCOUNT_FETCH_SUCCESS = 'ACCOUNT_FETCH_SUCCESS'; | ||||
@@ -64,6 +66,24 @@ export const FOLLOW_REQUEST_REJECT_REQUEST = 'FOLLOW_REQUEST_REJECT_REQUEST'; | |||||
export const FOLLOW_REQUEST_REJECT_SUCCESS = 'FOLLOW_REQUEST_REJECT_SUCCESS'; | export const FOLLOW_REQUEST_REJECT_SUCCESS = 'FOLLOW_REQUEST_REJECT_SUCCESS'; | ||||
export const FOLLOW_REQUEST_REJECT_FAIL = 'FOLLOW_REQUEST_REJECT_FAIL'; | export const FOLLOW_REQUEST_REJECT_FAIL = 'FOLLOW_REQUEST_REJECT_FAIL'; | ||||
function getFromDB(dispatch, getState, index, id) { | |||||
return new Promise((resolve, reject) => { | |||||
const request = index.get(id); | |||||
request.onerror = reject; | |||||
request.onsuccess = () => { | |||||
if (!request.result) { | |||||
reject(); | |||||
return; | |||||
} | |||||
dispatch(importAccount(request.result)); | |||||
resolve(request.result.moved && getFromDB(dispatch, getState, index, request.result.moved)); | |||||
}; | |||||
}); | |||||
} | |||||
export function fetchAccount(id) { | export function fetchAccount(id) { | ||||
return (dispatch, getState) => { | return (dispatch, getState) => { | ||||
dispatch(fetchRelationships([id])); | dispatch(fetchRelationships([id])); | ||||
@@ -74,9 +94,16 @@ export function fetchAccount(id) { | |||||
dispatch(fetchAccountRequest(id)); | dispatch(fetchAccountRequest(id)); | ||||
api(getState).get(`/api/v1/accounts/${id}`).then(response => { | |||||
dispatch(fetchAccountSuccess(response.data)); | |||||
}).catch(error => { | |||||
asyncDB.then(db => getFromDB( | |||||
dispatch, | |||||
getState, | |||||
db.transaction('accounts', 'read').objectStore('accounts').index('id'), | |||||
id | |||||
)).catch(() => api(getState).get(`/api/v1/accounts/${id}`).then(response => { | |||||
dispatch(importFetchedAccount(response.data)); | |||||
})).then(() => { | |||||
dispatch(fetchAccountSuccess()); | |||||
}, error => { | |||||
dispatch(fetchAccountFail(id, error)); | dispatch(fetchAccountFail(id, error)); | ||||
}); | }); | ||||
}; | }; | ||||
@@ -89,10 +116,9 @@ export function fetchAccountRequest(id) { | |||||
}; | }; | ||||
}; | }; | ||||
export function fetchAccountSuccess(account) { | |||||
export function fetchAccountSuccess() { | |||||
return { | return { | ||||
type: ACCOUNT_FETCH_SUCCESS, | type: ACCOUNT_FETCH_SUCCESS, | ||||
account, | |||||
}; | }; | ||||
}; | }; | ||||
@@ -319,6 +345,7 @@ export function fetchFollowers(id) { | |||||
api(getState).get(`/api/v1/accounts/${id}/followers`).then(response => { | api(getState).get(`/api/v1/accounts/${id}/followers`).then(response => { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedAccounts(response.data)); | |||||
dispatch(fetchFollowersSuccess(id, response.data, next ? next.uri : null)); | dispatch(fetchFollowersSuccess(id, response.data, next ? next.uri : null)); | ||||
dispatch(fetchRelationships(response.data.map(item => item.id))); | dispatch(fetchRelationships(response.data.map(item => item.id))); | ||||
}).catch(error => { | }).catch(error => { | ||||
@@ -364,6 +391,7 @@ export function expandFollowers(id) { | |||||
api(getState).get(url).then(response => { | api(getState).get(url).then(response => { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedAccounts(response.data)); | |||||
dispatch(expandFollowersSuccess(id, response.data, next ? next.uri : null)); | dispatch(expandFollowersSuccess(id, response.data, next ? next.uri : null)); | ||||
dispatch(fetchRelationships(response.data.map(item => item.id))); | dispatch(fetchRelationships(response.data.map(item => item.id))); | ||||
}).catch(error => { | }).catch(error => { | ||||
@@ -403,6 +431,7 @@ export function fetchFollowing(id) { | |||||
api(getState).get(`/api/v1/accounts/${id}/following`).then(response => { | api(getState).get(`/api/v1/accounts/${id}/following`).then(response => { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedAccounts(response.data)); | |||||
dispatch(fetchFollowingSuccess(id, response.data, next ? next.uri : null)); | dispatch(fetchFollowingSuccess(id, response.data, next ? next.uri : null)); | ||||
dispatch(fetchRelationships(response.data.map(item => item.id))); | dispatch(fetchRelationships(response.data.map(item => item.id))); | ||||
}).catch(error => { | }).catch(error => { | ||||
@@ -448,6 +477,7 @@ export function expandFollowing(id) { | |||||
api(getState).get(url).then(response => { | api(getState).get(url).then(response => { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedAccounts(response.data)); | |||||
dispatch(expandFollowingSuccess(id, response.data, next ? next.uri : null)); | dispatch(expandFollowingSuccess(id, response.data, next ? next.uri : null)); | ||||
dispatch(fetchRelationships(response.data.map(item => item.id))); | dispatch(fetchRelationships(response.data.map(item => item.id))); | ||||
}).catch(error => { | }).catch(error => { | ||||
@@ -529,6 +559,7 @@ export function fetchFollowRequests() { | |||||
api(getState).get('/api/v1/follow_requests').then(response => { | api(getState).get('/api/v1/follow_requests').then(response => { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedAccounts(response.data)); | |||||
dispatch(fetchFollowRequestsSuccess(response.data, next ? next.uri : null)); | dispatch(fetchFollowRequestsSuccess(response.data, next ? next.uri : null)); | ||||
}).catch(error => dispatch(fetchFollowRequestsFail(error))); | }).catch(error => dispatch(fetchFollowRequestsFail(error))); | ||||
}; | }; | ||||
@@ -567,6 +598,7 @@ export function expandFollowRequests() { | |||||
api(getState).get(url).then(response => { | api(getState).get(url).then(response => { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedAccounts(response.data)); | |||||
dispatch(expandFollowRequestsSuccess(response.data, next ? next.uri : null)); | dispatch(expandFollowRequestsSuccess(response.data, next ? next.uri : null)); | ||||
}).catch(error => dispatch(expandFollowRequestsFail(error))); | }).catch(error => dispatch(expandFollowRequestsFail(error))); | ||||
}; | }; | ||||
@@ -1,5 +1,6 @@ | |||||
import api, { getLinks } from '../api'; | import api, { getLinks } from '../api'; | ||||
import { fetchRelationships } from './accounts'; | import { fetchRelationships } from './accounts'; | ||||
import { importFetchedAccounts } from './importer'; | |||||
export const BLOCKS_FETCH_REQUEST = 'BLOCKS_FETCH_REQUEST'; | export const BLOCKS_FETCH_REQUEST = 'BLOCKS_FETCH_REQUEST'; | ||||
export const BLOCKS_FETCH_SUCCESS = 'BLOCKS_FETCH_SUCCESS'; | export const BLOCKS_FETCH_SUCCESS = 'BLOCKS_FETCH_SUCCESS'; | ||||
@@ -15,6 +16,7 @@ export function fetchBlocks() { | |||||
api(getState).get('/api/v1/blocks').then(response => { | api(getState).get('/api/v1/blocks').then(response => { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedAccounts(response.data)); | |||||
dispatch(fetchBlocksSuccess(response.data, next ? next.uri : null)); | dispatch(fetchBlocksSuccess(response.data, next ? next.uri : null)); | ||||
dispatch(fetchRelationships(response.data.map(item => item.id))); | dispatch(fetchRelationships(response.data.map(item => item.id))); | ||||
}).catch(error => dispatch(fetchBlocksFail(error))); | }).catch(error => dispatch(fetchBlocksFail(error))); | ||||
@@ -54,6 +56,7 @@ export function expandBlocks() { | |||||
api(getState).get(url).then(response => { | api(getState).get(url).then(response => { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedAccounts(response.data)); | |||||
dispatch(expandBlocksSuccess(response.data, next ? next.uri : null)); | dispatch(expandBlocksSuccess(response.data, next ? next.uri : null)); | ||||
dispatch(fetchRelationships(response.data.map(item => item.id))); | dispatch(fetchRelationships(response.data.map(item => item.id))); | ||||
}).catch(error => dispatch(expandBlocksFail(error))); | }).catch(error => dispatch(expandBlocksFail(error))); | ||||
@@ -4,6 +4,7 @@ import { throttle } from 'lodash'; | |||||
import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light'; | import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light'; | ||||
import { tagHistory } from '../settings'; | import { tagHistory } from '../settings'; | ||||
import { useEmoji } from './emojis'; | import { useEmoji } from './emojis'; | ||||
import { importFetchedAccounts } from './importer'; | |||||
import { | import { | ||||
updateTimeline, | updateTimeline, | ||||
@@ -282,6 +283,7 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) => | |||||
limit: 4, | limit: 4, | ||||
}, | }, | ||||
}).then(response => { | }).then(response => { | ||||
dispatch(importFetchedAccounts(response.data)); | |||||
dispatch(readyComposeSuggestionsAccounts(token, response.data)); | dispatch(readyComposeSuggestionsAccounts(token, response.data)); | ||||
}); | }); | ||||
}, 200, { leading: true, trailing: true }); | }, 200, { leading: true, trailing: true }); | ||||
@@ -1,4 +1,5 @@ | |||||
import api, { getLinks } from '../api'; | import api, { getLinks } from '../api'; | ||||
import { importFetchedStatuses } from './importer'; | |||||
export const FAVOURITED_STATUSES_FETCH_REQUEST = 'FAVOURITED_STATUSES_FETCH_REQUEST'; | export const FAVOURITED_STATUSES_FETCH_REQUEST = 'FAVOURITED_STATUSES_FETCH_REQUEST'; | ||||
export const FAVOURITED_STATUSES_FETCH_SUCCESS = 'FAVOURITED_STATUSES_FETCH_SUCCESS'; | export const FAVOURITED_STATUSES_FETCH_SUCCESS = 'FAVOURITED_STATUSES_FETCH_SUCCESS'; | ||||
@@ -18,6 +19,7 @@ export function fetchFavouritedStatuses() { | |||||
api(getState).get('/api/v1/favourites').then(response => { | api(getState).get('/api/v1/favourites').then(response => { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedStatuses(response.data)); | |||||
dispatch(fetchFavouritedStatusesSuccess(response.data, next ? next.uri : null)); | dispatch(fetchFavouritedStatusesSuccess(response.data, next ? next.uri : null)); | ||||
}).catch(error => { | }).catch(error => { | ||||
dispatch(fetchFavouritedStatusesFail(error)); | dispatch(fetchFavouritedStatusesFail(error)); | ||||
@@ -58,6 +60,7 @@ export function expandFavouritedStatuses() { | |||||
api(getState).get(url).then(response => { | api(getState).get(url).then(response => { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedStatuses(response.data)); | |||||
dispatch(expandFavouritedStatusesSuccess(response.data, next ? next.uri : null)); | dispatch(expandFavouritedStatusesSuccess(response.data, next ? next.uri : null)); | ||||
}).catch(error => { | }).catch(error => { | ||||
dispatch(expandFavouritedStatusesFail(error)); | dispatch(expandFavouritedStatusesFail(error)); | ||||
@@ -0,0 +1,76 @@ | |||||
import { putAccounts, putStatuses } from '../../db/modifier'; | |||||
import { normalizeAccount, normalizeStatus } from './normalizer'; | |||||
export const ACCOUNT_IMPORT = 'ACCOUNT_IMPORT'; | |||||
export const ACCOUNTS_IMPORT = 'ACCOUNTS_IMPORT'; | |||||
export const STATUS_IMPORT = 'STATUS_IMPORT'; | |||||
export const STATUSES_IMPORT = 'STATUSES_IMPORT'; | |||||
function pushUnique(array, object) { | |||||
if (array.every(element => element.id !== object.id)) { | |||||
array.push(object); | |||||
} | |||||
} | |||||
export function importAccount(account) { | |||||
return { type: ACCOUNT_IMPORT, account }; | |||||
} | |||||
export function importAccounts(accounts) { | |||||
return { type: ACCOUNTS_IMPORT, accounts }; | |||||
} | |||||
export function importStatus(status) { | |||||
return { type: STATUS_IMPORT, status }; | |||||
} | |||||
export function importStatuses(statuses) { | |||||
return { type: STATUSES_IMPORT, statuses }; | |||||
} | |||||
export function importFetchedAccount(account) { | |||||
return importFetchedAccounts([account]); | |||||
} | |||||
export function importFetchedAccounts(accounts) { | |||||
const normalAccounts = []; | |||||
function processAccount(account) { | |||||
pushUnique(normalAccounts, normalizeAccount(account)); | |||||
if (account.moved) { | |||||
processAccount(account); | |||||
} | |||||
} | |||||
accounts.forEach(processAccount); | |||||
putAccounts(normalAccounts); | |||||
return importAccounts(normalAccounts); | |||||
} | |||||
export function importFetchedStatus(status) { | |||||
return importFetchedStatuses([status]); | |||||
} | |||||
export function importFetchedStatuses(statuses) { | |||||
return (dispatch, getState) => { | |||||
const accounts = []; | |||||
const normalStatuses = []; | |||||
function processStatus(status) { | |||||
pushUnique(normalStatuses, normalizeStatus(status, getState().getIn(['statuses', status.id]))); | |||||
pushUnique(accounts, status.account); | |||||
if (status.reblog && status.reblog.id) { | |||||
processStatus(status.reblog); | |||||
} | |||||
} | |||||
statuses.forEach(processStatus); | |||||
putStatuses(normalStatuses); | |||||
dispatch(importFetchedAccounts(accounts)); | |||||
dispatch(importStatuses(normalStatuses)); | |||||
}; | |||||
} |
@@ -0,0 +1,46 @@ | |||||
import escapeTextContentForBrowser from 'escape-html'; | |||||
import emojify from '../../features/emoji/emoji'; | |||||
const domParser = new DOMParser(); | |||||
export function normalizeAccount(account) { | |||||
account = { ...account }; | |||||
const displayName = account.display_name.length === 0 ? account.username : account.display_name; | |||||
account.display_name_html = emojify(escapeTextContentForBrowser(displayName)); | |||||
account.note_emojified = emojify(account.note); | |||||
return account; | |||||
} | |||||
export function normalizeStatus(status, normalOldStatus) { | |||||
const normalStatus = { ...status }; | |||||
normalStatus.account = status.account.id; | |||||
if (status.reblog && status.reblog.id) { | |||||
normalStatus.reblog = status.reblog.id; | |||||
} | |||||
// Only calculate these values when status first encountered | |||||
// Otherwise keep the ones already in the reducer | |||||
if (normalOldStatus) { | |||||
normalStatus.search_index = normalOldStatus.get('search_index'); | |||||
normalStatus.contentHtml = normalOldStatus.get('contentHtml'); | |||||
normalStatus.spoilerHtml = normalOldStatus.get('spoilerHtml'); | |||||
normalStatus.hidden = normalOldStatus.get('hidden'); | |||||
} else { | |||||
const searchContent = [status.spoiler_text, status.content].join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n'); | |||||
const emojiMap = normalStatus.emojis.reduce((obj, emoji) => { | |||||
obj[`:${emoji.shortcode}:`] = emoji; | |||||
return obj; | |||||
}, {}); | |||||
normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent; | |||||
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap); | |||||
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(normalStatus.spoiler_text || ''), emojiMap); | |||||
normalStatus.hidden = normalStatus.sensitive; | |||||
} | |||||
return normalStatus; | |||||
} |
@@ -1,4 +1,5 @@ | |||||
import api from '../api'; | import api from '../api'; | ||||
import { importFetchedAccounts, importFetchedStatus } from './importer'; | |||||
export const REBLOG_REQUEST = 'REBLOG_REQUEST'; | export const REBLOG_REQUEST = 'REBLOG_REQUEST'; | ||||
export const REBLOG_SUCCESS = 'REBLOG_SUCCESS'; | export const REBLOG_SUCCESS = 'REBLOG_SUCCESS'; | ||||
@@ -39,7 +40,8 @@ export function reblog(status) { | |||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`).then(function (response) { | api(getState).post(`/api/v1/statuses/${status.get('id')}/reblog`).then(function (response) { | ||||
// The reblog API method returns a new status wrapped around the original. In this case we are only | // The reblog API method returns a new status wrapped around the original. In this case we are only | ||||
// interested in how the original is modified, hence passing it skipping the wrapper | // interested in how the original is modified, hence passing it skipping the wrapper | ||||
dispatch(reblogSuccess(status, response.data.reblog)); | |||||
dispatch(importFetchedStatus(response.data.reblog)); | |||||
dispatch(reblogSuccess(status)); | |||||
}).catch(function (error) { | }).catch(function (error) { | ||||
dispatch(reblogFail(status, error)); | dispatch(reblogFail(status, error)); | ||||
}); | }); | ||||
@@ -51,7 +53,8 @@ export function unreblog(status) { | |||||
dispatch(unreblogRequest(status)); | dispatch(unreblogRequest(status)); | ||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => { | api(getState).post(`/api/v1/statuses/${status.get('id')}/unreblog`).then(response => { | ||||
dispatch(unreblogSuccess(status, response.data)); | |||||
dispatch(importFetchedStatus(response.data)); | |||||
dispatch(unreblogSuccess(status)); | |||||
}).catch(error => { | }).catch(error => { | ||||
dispatch(unreblogFail(status, error)); | dispatch(unreblogFail(status, error)); | ||||
}); | }); | ||||
@@ -66,11 +69,10 @@ export function reblogRequest(status) { | |||||
}; | }; | ||||
}; | }; | ||||
export function reblogSuccess(status, response) { | |||||
export function reblogSuccess(status) { | |||||
return { | return { | ||||
type: REBLOG_SUCCESS, | type: REBLOG_SUCCESS, | ||||
status: status, | status: status, | ||||
response: response, | |||||
skipLoading: true, | skipLoading: true, | ||||
}; | }; | ||||
}; | }; | ||||
@@ -92,11 +94,10 @@ export function unreblogRequest(status) { | |||||
}; | }; | ||||
}; | }; | ||||
export function unreblogSuccess(status, response) { | |||||
export function unreblogSuccess(status) { | |||||
return { | return { | ||||
type: UNREBLOG_SUCCESS, | type: UNREBLOG_SUCCESS, | ||||
status: status, | status: status, | ||||
response: response, | |||||
skipLoading: true, | skipLoading: true, | ||||
}; | }; | ||||
}; | }; | ||||
@@ -115,7 +116,8 @@ export function favourite(status) { | |||||
dispatch(favouriteRequest(status)); | dispatch(favouriteRequest(status)); | ||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/favourite`).then(function (response) { | api(getState).post(`/api/v1/statuses/${status.get('id')}/favourite`).then(function (response) { | ||||
dispatch(favouriteSuccess(status, response.data)); | |||||
dispatch(importFetchedStatus(response.data)); | |||||
dispatch(favouriteSuccess(status)); | |||||
}).catch(function (error) { | }).catch(function (error) { | ||||
dispatch(favouriteFail(status, error)); | dispatch(favouriteFail(status, error)); | ||||
}); | }); | ||||
@@ -127,7 +129,8 @@ export function unfavourite(status) { | |||||
dispatch(unfavouriteRequest(status)); | dispatch(unfavouriteRequest(status)); | ||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then(response => { | api(getState).post(`/api/v1/statuses/${status.get('id')}/unfavourite`).then(response => { | ||||
dispatch(unfavouriteSuccess(status, response.data)); | |||||
dispatch(importFetchedStatus(response.data)); | |||||
dispatch(unfavouriteSuccess(status)); | |||||
}).catch(error => { | }).catch(error => { | ||||
dispatch(unfavouriteFail(status, error)); | dispatch(unfavouriteFail(status, error)); | ||||
}); | }); | ||||
@@ -142,11 +145,10 @@ export function favouriteRequest(status) { | |||||
}; | }; | ||||
}; | }; | ||||
export function favouriteSuccess(status, response) { | |||||
export function favouriteSuccess(status) { | |||||
return { | return { | ||||
type: FAVOURITE_SUCCESS, | type: FAVOURITE_SUCCESS, | ||||
status: status, | status: status, | ||||
response: response, | |||||
skipLoading: true, | skipLoading: true, | ||||
}; | }; | ||||
}; | }; | ||||
@@ -168,11 +170,10 @@ export function unfavouriteRequest(status) { | |||||
}; | }; | ||||
}; | }; | ||||
export function unfavouriteSuccess(status, response) { | |||||
export function unfavouriteSuccess(status) { | |||||
return { | return { | ||||
type: UNFAVOURITE_SUCCESS, | type: UNFAVOURITE_SUCCESS, | ||||
status: status, | status: status, | ||||
response: response, | |||||
skipLoading: true, | skipLoading: true, | ||||
}; | }; | ||||
}; | }; | ||||
@@ -191,6 +192,7 @@ export function fetchReblogs(id) { | |||||
dispatch(fetchReblogsRequest(id)); | dispatch(fetchReblogsRequest(id)); | ||||
api(getState).get(`/api/v1/statuses/${id}/reblogged_by`).then(response => { | api(getState).get(`/api/v1/statuses/${id}/reblogged_by`).then(response => { | ||||
dispatch(importFetchedAccounts(response.data)); | |||||
dispatch(fetchReblogsSuccess(id, response.data)); | dispatch(fetchReblogsSuccess(id, response.data)); | ||||
}).catch(error => { | }).catch(error => { | ||||
dispatch(fetchReblogsFail(id, error)); | dispatch(fetchReblogsFail(id, error)); | ||||
@@ -225,6 +227,7 @@ export function fetchFavourites(id) { | |||||
dispatch(fetchFavouritesRequest(id)); | dispatch(fetchFavouritesRequest(id)); | ||||
api(getState).get(`/api/v1/statuses/${id}/favourited_by`).then(response => { | api(getState).get(`/api/v1/statuses/${id}/favourited_by`).then(response => { | ||||
dispatch(importFetchedAccounts(response.data)); | |||||
dispatch(fetchFavouritesSuccess(id, response.data)); | dispatch(fetchFavouritesSuccess(id, response.data)); | ||||
}).catch(error => { | }).catch(error => { | ||||
dispatch(fetchFavouritesFail(id, error)); | dispatch(fetchFavouritesFail(id, error)); | ||||
@@ -259,7 +262,8 @@ export function pin(status) { | |||||
dispatch(pinRequest(status)); | dispatch(pinRequest(status)); | ||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/pin`).then(response => { | api(getState).post(`/api/v1/statuses/${status.get('id')}/pin`).then(response => { | ||||
dispatch(pinSuccess(status, response.data)); | |||||
dispatch(importFetchedStatus(response.data)); | |||||
dispatch(pinSuccess(status)); | |||||
}).catch(error => { | }).catch(error => { | ||||
dispatch(pinFail(status, error)); | dispatch(pinFail(status, error)); | ||||
}); | }); | ||||
@@ -274,11 +278,10 @@ export function pinRequest(status) { | |||||
}; | }; | ||||
}; | }; | ||||
export function pinSuccess(status, response) { | |||||
export function pinSuccess(status) { | |||||
return { | return { | ||||
type: PIN_SUCCESS, | type: PIN_SUCCESS, | ||||
status, | status, | ||||
response, | |||||
skipLoading: true, | skipLoading: true, | ||||
}; | }; | ||||
}; | }; | ||||
@@ -297,7 +300,8 @@ export function unpin (status) { | |||||
dispatch(unpinRequest(status)); | dispatch(unpinRequest(status)); | ||||
api(getState).post(`/api/v1/statuses/${status.get('id')}/unpin`).then(response => { | api(getState).post(`/api/v1/statuses/${status.get('id')}/unpin`).then(response => { | ||||
dispatch(unpinSuccess(status, response.data)); | |||||
dispatch(importFetchedStatus(response.data)); | |||||
dispatch(unpinSuccess(status)); | |||||
}).catch(error => { | }).catch(error => { | ||||
dispatch(unpinFail(status, error)); | dispatch(unpinFail(status, error)); | ||||
}); | }); | ||||
@@ -312,11 +316,10 @@ export function unpinRequest(status) { | |||||
}; | }; | ||||
}; | }; | ||||
export function unpinSuccess(status, response) { | |||||
export function unpinSuccess(status) { | |||||
return { | return { | ||||
type: UNPIN_SUCCESS, | type: UNPIN_SUCCESS, | ||||
status, | status, | ||||
response, | |||||
skipLoading: true, | skipLoading: true, | ||||
}; | }; | ||||
}; | }; | ||||
@@ -1,4 +1,5 @@ | |||||
import api from '../api'; | import api from '../api'; | ||||
import { importFetchedAccounts } from './importer'; | |||||
export const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST'; | export const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST'; | ||||
export const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS'; | export const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS'; | ||||
@@ -200,9 +201,10 @@ export const deleteListFail = (id, error) => ({ | |||||
export const fetchListAccounts = listId => (dispatch, getState) => { | export const fetchListAccounts = listId => (dispatch, getState) => { | ||||
dispatch(fetchListAccountsRequest(listId)); | dispatch(fetchListAccountsRequest(listId)); | ||||
api(getState).get(`/api/v1/lists/${listId}/accounts`, { params: { limit: 0 } }) | |||||
.then(({ data }) => dispatch(fetchListAccountsSuccess(listId, data))) | |||||
.catch(err => dispatch(fetchListAccountsFail(listId, err))); | |||||
api(getState).get(`/api/v1/lists/${listId}/accounts`, { params: { limit: 0 } }).then(({ data }) => { | |||||
dispatch(importFetchedAccounts(data)); | |||||
dispatch(fetchListAccountsSuccess(listId, data)); | |||||
}).catch(err => dispatch(fetchListAccountsFail(listId, err))); | |||||
}; | }; | ||||
export const fetchListAccountsRequest = id => ({ | export const fetchListAccountsRequest = id => ({ | ||||
@@ -231,8 +233,10 @@ export const fetchListSuggestions = q => (dispatch, getState) => { | |||||
following: true, | following: true, | ||||
}; | }; | ||||
api(getState).get('/api/v1/accounts/search', { params }) | |||||
.then(({ data }) => dispatch(fetchListSuggestionsReady(q, data))); | |||||
api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => { | |||||
dispatch(importFetchedAccounts(data)); | |||||
dispatch(fetchListSuggestionsReady(q, data)); | |||||
}); | |||||
}; | }; | ||||
export const fetchListSuggestionsReady = (query, accounts) => ({ | export const fetchListSuggestionsReady = (query, accounts) => ({ | ||||
@@ -1,5 +1,6 @@ | |||||
import api, { getLinks } from '../api'; | import api, { getLinks } from '../api'; | ||||
import { fetchRelationships } from './accounts'; | import { fetchRelationships } from './accounts'; | ||||
import { importFetchedAccounts } from './importer'; | |||||
import { openModal } from './modal'; | import { openModal } from './modal'; | ||||
export const MUTES_FETCH_REQUEST = 'MUTES_FETCH_REQUEST'; | export const MUTES_FETCH_REQUEST = 'MUTES_FETCH_REQUEST'; | ||||
@@ -19,6 +20,7 @@ export function fetchMutes() { | |||||
api(getState).get('/api/v1/mutes').then(response => { | api(getState).get('/api/v1/mutes').then(response => { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedAccounts(response.data)); | |||||
dispatch(fetchMutesSuccess(response.data, next ? next.uri : null)); | dispatch(fetchMutesSuccess(response.data, next ? next.uri : null)); | ||||
dispatch(fetchRelationships(response.data.map(item => item.id))); | dispatch(fetchRelationships(response.data.map(item => item.id))); | ||||
}).catch(error => dispatch(fetchMutesFail(error))); | }).catch(error => dispatch(fetchMutesFail(error))); | ||||
@@ -58,6 +60,7 @@ export function expandMutes() { | |||||
api(getState).get(url).then(response => { | api(getState).get(url).then(response => { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedAccounts(response.data)); | |||||
dispatch(expandMutesSuccess(response.data, next ? next.uri : null)); | dispatch(expandMutesSuccess(response.data, next ? next.uri : null)); | ||||
dispatch(fetchRelationships(response.data.map(item => item.id))); | dispatch(fetchRelationships(response.data.map(item => item.id))); | ||||
}).catch(error => dispatch(expandMutesFail(error))); | }).catch(error => dispatch(expandMutesFail(error))); | ||||
@@ -2,6 +2,12 @@ import api, { getLinks } from '../api'; | |||||
import { List as ImmutableList } from 'immutable'; | import { List as ImmutableList } from 'immutable'; | ||||
import IntlMessageFormat from 'intl-messageformat'; | import IntlMessageFormat from 'intl-messageformat'; | ||||
import { fetchRelationships } from './accounts'; | import { fetchRelationships } from './accounts'; | ||||
import { | |||||
importFetchedAccount, | |||||
importFetchedAccounts, | |||||
importFetchedStatus, | |||||
importFetchedStatuses, | |||||
} from './importer'; | |||||
import { defineMessages } from 'react-intl'; | import { defineMessages } from 'react-intl'; | ||||
export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE'; | export const NOTIFICATIONS_UPDATE = 'NOTIFICATIONS_UPDATE'; | ||||
@@ -41,11 +47,12 @@ export function updateNotifications(notification, intlMessages, intlLocale) { | |||||
const showAlert = getState().getIn(['settings', 'notifications', 'alerts', notification.type], true); | const showAlert = getState().getIn(['settings', 'notifications', 'alerts', notification.type], true); | ||||
const playSound = getState().getIn(['settings', 'notifications', 'sounds', notification.type], true); | const playSound = getState().getIn(['settings', 'notifications', 'sounds', notification.type], true); | ||||
dispatch(importFetchedAccount(notification.account)); | |||||
dispatch(importFetchedStatus(notification.status)); | |||||
dispatch({ | dispatch({ | ||||
type: NOTIFICATIONS_UPDATE, | type: NOTIFICATIONS_UPDATE, | ||||
notification, | notification, | ||||
account: notification.account, | |||||
status: notification.status, | |||||
meta: playSound ? { sound: 'boop' } : undefined, | meta: playSound ? { sound: 'boop' } : undefined, | ||||
}); | }); | ||||
@@ -89,6 +96,9 @@ export function refreshNotifications() { | |||||
api(getState).get('/api/v1/notifications', { params }).then(response => { | api(getState).get('/api/v1/notifications', { params }).then(response => { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedAccounts(response.data.map(item => item.account))); | |||||
dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status))); | |||||
dispatch(refreshNotificationsSuccess(response.data, skipLoading, next ? next.uri : null)); | dispatch(refreshNotificationsSuccess(response.data, skipLoading, next ? next.uri : null)); | ||||
fetchRelatedRelationships(dispatch, response.data); | fetchRelatedRelationships(dispatch, response.data); | ||||
}).catch(error => { | }).catch(error => { | ||||
@@ -108,8 +118,6 @@ export function refreshNotificationsSuccess(notifications, skipLoading, next) { | |||||
return { | return { | ||||
type: NOTIFICATIONS_REFRESH_SUCCESS, | type: NOTIFICATIONS_REFRESH_SUCCESS, | ||||
notifications, | notifications, | ||||
accounts: notifications.map(item => item.account), | |||||
statuses: notifications.map(item => item.status).filter(status => !!status), | |||||
skipLoading, | skipLoading, | ||||
next, | next, | ||||
}; | }; | ||||
@@ -141,6 +149,10 @@ export function expandNotifications() { | |||||
api(getState).get('/api/v1/notifications', { params }).then(response => { | api(getState).get('/api/v1/notifications', { params }).then(response => { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedAccounts(response.data.map(item => item.account))); | |||||
dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status))); | |||||
dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null)); | dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null)); | ||||
fetchRelatedRelationships(dispatch, response.data); | fetchRelatedRelationships(dispatch, response.data); | ||||
}).catch(error => { | }).catch(error => { | ||||
@@ -159,8 +171,6 @@ export function expandNotificationsSuccess(notifications, next) { | |||||
return { | return { | ||||
type: NOTIFICATIONS_EXPAND_SUCCESS, | type: NOTIFICATIONS_EXPAND_SUCCESS, | ||||
notifications, | notifications, | ||||
accounts: notifications.map(item => item.account), | |||||
statuses: notifications.map(item => item.status).filter(status => !!status), | |||||
next, | next, | ||||
}; | }; | ||||
}; | }; | ||||
@@ -1,4 +1,5 @@ | |||||
import api from '../api'; | import api from '../api'; | ||||
import { importFetchedStatuses } from './importer'; | |||||
export const PINNED_STATUSES_FETCH_REQUEST = 'PINNED_STATUSES_FETCH_REQUEST'; | export const PINNED_STATUSES_FETCH_REQUEST = 'PINNED_STATUSES_FETCH_REQUEST'; | ||||
export const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS'; | export const PINNED_STATUSES_FETCH_SUCCESS = 'PINNED_STATUSES_FETCH_SUCCESS'; | ||||
@@ -11,6 +12,7 @@ export function fetchPinnedStatuses() { | |||||
dispatch(fetchPinnedStatusesRequest()); | dispatch(fetchPinnedStatusesRequest()); | ||||
api(getState).get(`/api/v1/accounts/${me}/statuses`, { params: { pinned: true } }).then(response => { | api(getState).get(`/api/v1/accounts/${me}/statuses`, { params: { pinned: true } }).then(response => { | ||||
dispatch(importFetchedStatuses(response.data)); | |||||
dispatch(fetchPinnedStatusesSuccess(response.data, null)); | dispatch(fetchPinnedStatusesSuccess(response.data, null)); | ||||
}).catch(error => { | }).catch(error => { | ||||
dispatch(fetchPinnedStatusesFail(error)); | dispatch(fetchPinnedStatusesFail(error)); | ||||
@@ -1,5 +1,6 @@ | |||||
import api from '../api'; | import api from '../api'; | ||||
import { fetchRelationships } from './accounts'; | import { fetchRelationships } from './accounts'; | ||||
import { importFetchedAccounts, importFetchedStatuses } from './importer'; | |||||
export const SEARCH_CHANGE = 'SEARCH_CHANGE'; | export const SEARCH_CHANGE = 'SEARCH_CHANGE'; | ||||
export const SEARCH_CLEAR = 'SEARCH_CLEAR'; | export const SEARCH_CLEAR = 'SEARCH_CLEAR'; | ||||
@@ -38,6 +39,14 @@ export function submitSearch() { | |||||
resolve: true, | resolve: true, | ||||
}, | }, | ||||
}).then(response => { | }).then(response => { | ||||
if (response.data.accounts) { | |||||
dispatch(importFetchedAccounts(response.data.accounts)); | |||||
} | |||||
if (response.data.statuses) { | |||||
dispatch(importFetchedStatuses(response.data.statuses)); | |||||
} | |||||
dispatch(fetchSearchSuccess(response.data)); | dispatch(fetchSearchSuccess(response.data)); | ||||
dispatch(fetchRelationships(response.data.accounts.map(item => item.id))); | dispatch(fetchRelationships(response.data.accounts.map(item => item.id))); | ||||
}).catch(error => { | }).catch(error => { | ||||
@@ -56,8 +65,6 @@ export function fetchSearchSuccess(results) { | |||||
return { | return { | ||||
type: SEARCH_FETCH_SUCCESS, | type: SEARCH_FETCH_SUCCESS, | ||||
results, | results, | ||||
accounts: results.accounts, | |||||
statuses: results.statuses, | |||||
}; | }; | ||||
}; | }; | ||||
@@ -1,7 +1,10 @@ | |||||
import api from '../api'; | import api from '../api'; | ||||
import asyncDB from '../db/async'; | |||||
import { evictStatus } from '../db/modifier'; | |||||
import { deleteFromTimelines } from './timelines'; | import { deleteFromTimelines } from './timelines'; | ||||
import { fetchStatusCard } from './cards'; | import { fetchStatusCard } from './cards'; | ||||
import { importFetchedStatus, importFetchedStatuses, importAccount, importStatus } from './importer'; | |||||
export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST'; | export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST'; | ||||
export const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS'; | export const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS'; | ||||
@@ -34,6 +37,48 @@ export function fetchStatusRequest(id, skipLoading) { | |||||
}; | }; | ||||
}; | }; | ||||
function getFromDB(dispatch, getState, accountIndex, index, id) { | |||||
return new Promise((resolve, reject) => { | |||||
const request = index.get(id); | |||||
request.onerror = reject; | |||||
request.onsuccess = () => { | |||||
const promises = []; | |||||
if (!request.result) { | |||||
reject(); | |||||
return; | |||||
} | |||||
dispatch(importStatus(request.result)); | |||||
if (getState().getIn(['accounts', request.result.account], null) === null) { | |||||
promises.push(new Promise((accountResolve, accountReject) => { | |||||
const accountRequest = accountIndex.get(request.result.account); | |||||
accountRequest.onerror = accountReject; | |||||
accountRequest.onsuccess = () => { | |||||
if (!request.result) { | |||||
accountReject(); | |||||
return; | |||||
} | |||||
dispatch(importAccount(accountRequest.result)); | |||||
accountResolve(); | |||||
}; | |||||
})); | |||||
} | |||||
if (request.result.reblog && getState().getIn(['statuses', request.result.reblog], null) === null) { | |||||
promises.push(getFromDB(dispatch, getState, accountIndex, index, request.result.reblog)); | |||||
} | |||||
resolve(Promise.all(promises)); | |||||
}; | |||||
}); | |||||
} | |||||
export function fetchStatus(id) { | export function fetchStatus(id) { | ||||
return (dispatch, getState) => { | return (dispatch, getState) => { | ||||
const skipLoading = getState().getIn(['statuses', id], null) !== null; | const skipLoading = getState().getIn(['statuses', id], null) !== null; | ||||
@@ -47,18 +92,26 @@ export function fetchStatus(id) { | |||||
dispatch(fetchStatusRequest(id, skipLoading)); | dispatch(fetchStatusRequest(id, skipLoading)); | ||||
api(getState).get(`/api/v1/statuses/${id}`).then(response => { | |||||
dispatch(fetchStatusSuccess(response.data, skipLoading)); | |||||
}).catch(error => { | |||||
asyncDB.then(db => { | |||||
const transaction = db.transaction(['accounts', 'statuses'], 'read'); | |||||
const accountIndex = transaction.objectStore('accounts').index('id'); | |||||
const index = transaction.objectStore('statuses').index('id'); | |||||
return getFromDB(dispatch, getState, accountIndex, index, id); | |||||
}).then(() => { | |||||
dispatch(fetchStatusSuccess(skipLoading)); | |||||
}, () => api(getState).get(`/api/v1/statuses/${id}`).then(response => { | |||||
dispatch(importFetchedStatus(response.data)); | |||||
dispatch(fetchStatusSuccess(skipLoading)); | |||||
})).catch(error => { | |||||
dispatch(fetchStatusFail(id, error, skipLoading)); | dispatch(fetchStatusFail(id, error, skipLoading)); | ||||
}); | }); | ||||
}; | }; | ||||
}; | }; | ||||
export function fetchStatusSuccess(status, skipLoading) { | |||||
export function fetchStatusSuccess(skipLoading) { | |||||
return { | return { | ||||
type: STATUS_FETCH_SUCCESS, | type: STATUS_FETCH_SUCCESS, | ||||
status, | |||||
skipLoading, | skipLoading, | ||||
}; | }; | ||||
}; | }; | ||||
@@ -78,6 +131,7 @@ export function deleteStatus(id) { | |||||
dispatch(deleteStatusRequest(id)); | dispatch(deleteStatusRequest(id)); | ||||
api(getState).delete(`/api/v1/statuses/${id}`).then(() => { | api(getState).delete(`/api/v1/statuses/${id}`).then(() => { | ||||
evictStatus(id); | |||||
dispatch(deleteStatusSuccess(id)); | dispatch(deleteStatusSuccess(id)); | ||||
dispatch(deleteFromTimelines(id)); | dispatch(deleteFromTimelines(id)); | ||||
}).catch(error => { | }).catch(error => { | ||||
@@ -113,6 +167,7 @@ export function fetchContext(id) { | |||||
dispatch(fetchContextRequest(id)); | dispatch(fetchContextRequest(id)); | ||||
api(getState).get(`/api/v1/statuses/${id}/context`).then(response => { | api(getState).get(`/api/v1/statuses/${id}/context`).then(response => { | ||||
dispatch(importFetchedStatuses(response.data.ancestors.concat(response.data.descendants))); | |||||
dispatch(fetchContextSuccess(id, response.data.ancestors, response.data.descendants)); | dispatch(fetchContextSuccess(id, response.data.ancestors, response.data.descendants)); | ||||
}).catch(error => { | }).catch(error => { | ||||
@@ -1,5 +1,6 @@ | |||||
import { Iterable, fromJS } from 'immutable'; | import { Iterable, fromJS } from 'immutable'; | ||||
import { hydrateCompose } from './compose'; | import { hydrateCompose } from './compose'; | ||||
import { importFetchedAccounts } from './importer'; | |||||
export const STORE_HYDRATE = 'STORE_HYDRATE'; | export const STORE_HYDRATE = 'STORE_HYDRATE'; | ||||
export const STORE_HYDRATE_LAZY = 'STORE_HYDRATE_LAZY'; | export const STORE_HYDRATE_LAZY = 'STORE_HYDRATE_LAZY'; | ||||
@@ -18,5 +19,6 @@ export function hydrateStore(rawState) { | |||||
}); | }); | ||||
dispatch(hydrateCompose()); | dispatch(hydrateCompose()); | ||||
dispatch(importFetchedAccounts(Object.values(rawState.accounts))); | |||||
}; | }; | ||||
}; | }; |
@@ -1,3 +1,4 @@ | |||||
import { importFetchedStatus, importFetchedStatuses } from './importer'; | |||||
import api, { getLinks } from '../api'; | import api, { getLinks } from '../api'; | ||||
import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; | import { Map as ImmutableMap, List as ImmutableList } from 'immutable'; | ||||
@@ -44,6 +45,8 @@ export function updateTimeline(timeline, status) { | |||||
} | } | ||||
} | } | ||||
dispatch(importFetchedStatus(status)); | |||||
dispatch({ | dispatch({ | ||||
type: TIMELINE_UPDATE, | type: TIMELINE_UPDATE, | ||||
timeline, | timeline, | ||||
@@ -109,6 +112,7 @@ export function refreshTimeline(timelineId, path, params = {}) { | |||||
dispatch(refreshTimelineSuccess(timelineId, [], skipLoading, null, true)); | dispatch(refreshTimelineSuccess(timelineId, [], skipLoading, null, true)); | ||||
} else { | } else { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedStatuses(response.data)); | |||||
dispatch(refreshTimelineSuccess(timelineId, response.data, skipLoading, next ? next.uri : null, false)); | dispatch(refreshTimelineSuccess(timelineId, response.data, skipLoading, next ? next.uri : null, false)); | ||||
} | } | ||||
}).catch(error => { | }).catch(error => { | ||||
@@ -152,6 +156,7 @@ export function expandTimeline(timelineId, path, params = {}) { | |||||
api(getState).get(path, { params }).then(response => { | api(getState).get(path, { params }).then(response => { | ||||
const next = getLinks(response).refs.find(link => link.rel === 'next'); | const next = getLinks(response).refs.find(link => link.rel === 'next'); | ||||
dispatch(importFetchedStatuses(response.data)); | |||||
dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null)); | dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null)); | ||||
}).catch(error => { | }).catch(error => { | ||||
dispatch(expandTimelineFail(timelineId, error)); | dispatch(expandTimelineFail(timelineId, error)); | ||||
@@ -0,0 +1,28 @@ | |||||
import { me } from '../initial_state'; | |||||
export default new Promise((resolve, reject) => { | |||||
// Microsoft Edge 17 does not support getAll according to: | |||||
// Catalog of standard and vendor APIs across browsers - Microsoft Edge Development | |||||
// https://developer.microsoft.com/en-us/microsoft-edge/platform/catalog/?q=specName%3Aindexeddb | |||||
if (!me || !('getAll' in IDBObjectStore.prototype)) { | |||||
reject(); | |||||
return; | |||||
} | |||||
const request = indexedDB.open('mastodon:' + me); | |||||
request.onerror = reject; | |||||
request.onsuccess = ({ target }) => resolve(target.result); | |||||
request.onupgradeneeded = ({ target }) => { | |||||
const accounts = target.result.createObjectStore('accounts', { autoIncrement: true }); | |||||
const statuses = target.result.createObjectStore('statuses', { autoIncrement: true }); | |||||
accounts.createIndex('id', 'id', { unique: true }); | |||||
accounts.createIndex('moved', 'moved'); | |||||
statuses.createIndex('id', 'id', { unique: true }); | |||||
statuses.createIndex('account', 'account'); | |||||
statuses.createIndex('reblog', 'reblog'); | |||||
}; | |||||
}); |
@@ -0,0 +1,93 @@ | |||||
import asyncDB from './async'; | |||||
const limit = 1024; | |||||
function put(name, objects, callback) { | |||||
asyncDB.then(db => { | |||||
const putTransaction = db.transaction(name, 'readwrite'); | |||||
const putStore = putTransaction.objectStore(name); | |||||
const putIndex = putStore.index('id'); | |||||
objects.forEach(object => { | |||||
function add() { | |||||
putStore.add(object); | |||||
} | |||||
putIndex.getKey(object.id).onsuccess = retrieval => { | |||||
if (retrieval.target.result) { | |||||
putStore.delete(retrieval.target.result).onsuccess = add; | |||||
} else { | |||||
add(); | |||||
} | |||||
}; | |||||
}); | |||||
putTransaction.oncomplete = () => { | |||||
const readTransaction = db.transaction(name, 'readonly'); | |||||
const readStore = readTransaction.objectStore(name); | |||||
readStore.count().onsuccess = count => { | |||||
const excess = count.target.result - limit; | |||||
if (excess > 0) { | |||||
readStore.getAll(null, excess).onsuccess = | |||||
retrieval => callback(retrieval.target.result.map(({ id }) => id)); | |||||
} | |||||
}; | |||||
}; | |||||
}); | |||||
} | |||||
export function evictAccounts(ids) { | |||||
asyncDB.then(db => { | |||||
const transaction = db.transaction(['accounts', 'statuses'], 'readwrite'); | |||||
const accounts = transaction.objectStore('accounts'); | |||||
const accountsIdIndex = accounts.index('id'); | |||||
const accountsMovedIndex = accounts.index('moved'); | |||||
const statuses = transaction.objectStore('statuses'); | |||||
const statusesIndex = statuses.index('account'); | |||||
function evict(toEvict) { | |||||
toEvict.forEach(id => { | |||||
accountsMovedIndex.getAllKeys(id).onsuccess = | |||||
({ target }) => evict(target.result); | |||||
statusesIndex.getAll(id).onsuccess = | |||||
({ target }) => evictStatuses(target.result.map(({ id }) => id)); | |||||
accountsIdIndex.getKey(id).onsuccess = | |||||
({ target }) => target.result && accounts.delete(target.result); | |||||
}); | |||||
} | |||||
evict(ids); | |||||
}); | |||||
} | |||||
export function evictStatus(id) { | |||||
return evictStatuses([id]); | |||||
} | |||||
export function evictStatuses(ids) { | |||||
asyncDB.then(db => { | |||||
const store = db.transaction('statuses', 'readwrite').objectStore('statuses'); | |||||
const idIndex = store.index('id'); | |||||
const reblogIndex = store.index('reblog'); | |||||
ids.forEach(id => { | |||||
reblogIndex.getAllKeys(id).onsuccess = | |||||
({ target }) => target.result.forEach(reblogKey => store.delete(reblogKey)); | |||||
idIndex.getKey(id).onsuccess = | |||||
({ target }) => target.result && store.delete(target.result); | |||||
}); | |||||
}); | |||||
} | |||||
export function putAccounts(records) { | |||||
put('accounts', records, evictAccounts); | |||||
} | |||||
export function putStatuses(records) { | |||||
put('statuses', records, evictStatuses); | |||||
} |
@@ -1,56 +1,7 @@ | |||||
import { | |||||
ACCOUNT_FETCH_SUCCESS, | |||||
FOLLOWERS_FETCH_SUCCESS, | |||||
FOLLOWERS_EXPAND_SUCCESS, | |||||
FOLLOWING_FETCH_SUCCESS, | |||||
FOLLOWING_EXPAND_SUCCESS, | |||||
FOLLOW_REQUESTS_FETCH_SUCCESS, | |||||
FOLLOW_REQUESTS_EXPAND_SUCCESS, | |||||
} from '../actions/accounts'; | |||||
import { | |||||
BLOCKS_FETCH_SUCCESS, | |||||
BLOCKS_EXPAND_SUCCESS, | |||||
} from '../actions/blocks'; | |||||
import { | |||||
MUTES_FETCH_SUCCESS, | |||||
MUTES_EXPAND_SUCCESS, | |||||
} from '../actions/mutes'; | |||||
import { COMPOSE_SUGGESTIONS_READY } from '../actions/compose'; | |||||
import { | |||||
REBLOG_SUCCESS, | |||||
UNREBLOG_SUCCESS, | |||||
FAVOURITE_SUCCESS, | |||||
UNFAVOURITE_SUCCESS, | |||||
REBLOGS_FETCH_SUCCESS, | |||||
FAVOURITES_FETCH_SUCCESS, | |||||
} from '../actions/interactions'; | |||||
import { | |||||
TIMELINE_REFRESH_SUCCESS, | |||||
TIMELINE_UPDATE, | |||||
TIMELINE_EXPAND_SUCCESS, | |||||
} from '../actions/timelines'; | |||||
import { | |||||
STATUS_FETCH_SUCCESS, | |||||
CONTEXT_FETCH_SUCCESS, | |||||
} from '../actions/statuses'; | |||||
import { SEARCH_FETCH_SUCCESS } from '../actions/search'; | |||||
import { | |||||
NOTIFICATIONS_UPDATE, | |||||
NOTIFICATIONS_REFRESH_SUCCESS, | |||||
NOTIFICATIONS_EXPAND_SUCCESS, | |||||
} from '../actions/notifications'; | |||||
import { | |||||
FAVOURITED_STATUSES_FETCH_SUCCESS, | |||||
FAVOURITED_STATUSES_EXPAND_SUCCESS, | |||||
} from '../actions/favourites'; | |||||
import { | |||||
LIST_ACCOUNTS_FETCH_SUCCESS, | |||||
LIST_EDITOR_SUGGESTIONS_READY, | |||||
} from '../actions/lists'; | |||||
import { STORE_HYDRATE } from '../actions/store'; | |||||
import emojify from '../features/emoji/emoji'; | |||||
import { ACCOUNT_IMPORT, ACCOUNTS_IMPORT } from '../actions/importer'; | |||||
import { Map as ImmutableMap, fromJS } from 'immutable'; | import { Map as ImmutableMap, fromJS } from 'immutable'; | ||||
import escapeTextContentForBrowser from 'escape-html'; | |||||
const initialState = ImmutableMap(); | |||||
const normalizeAccount = (state, account) => { | const normalizeAccount = (state, account) => { | ||||
account = { ...account }; | account = { ...account }; | ||||
@@ -59,15 +10,6 @@ const normalizeAccount = (state, account) => { | |||||
delete account.following_count; | delete account.following_count; | ||||
delete account.statuses_count; | delete account.statuses_count; | ||||
const displayName = account.display_name.length === 0 ? account.username : account.display_name; | |||||
account.display_name_html = emojify(escapeTextContentForBrowser(displayName)); | |||||
account.note_emojified = emojify(account.note); | |||||
if (account.moved) { | |||||
state = normalizeAccount(state, account.moved); | |||||
account.moved = account.moved.id; | |||||
} | |||||
return state.set(account.id, fromJS(account)); | return state.set(account.id, fromJS(account)); | ||||
}; | }; | ||||
@@ -79,67 +21,12 @@ const normalizeAccounts = (state, accounts) => { | |||||
return state; | return state; | ||||
}; | }; | ||||
const normalizeAccountFromStatus = (state, status) => { | |||||
state = normalizeAccount(state, status.account); | |||||
if (status.reblog && status.reblog.account) { | |||||
state = normalizeAccount(state, status.reblog.account); | |||||
} | |||||
return state; | |||||
}; | |||||
const normalizeAccountsFromStatuses = (state, statuses) => { | |||||
statuses.forEach(status => { | |||||
state = normalizeAccountFromStatus(state, status); | |||||
}); | |||||
return state; | |||||
}; | |||||
const initialState = ImmutableMap(); | |||||
export default function accounts(state = initialState, action) { | export default function accounts(state = initialState, action) { | ||||
switch(action.type) { | switch(action.type) { | ||||
case STORE_HYDRATE: | |||||
return normalizeAccounts(state, Object.values(action.state.get('accounts').toJS())); | |||||
case ACCOUNT_FETCH_SUCCESS: | |||||
case NOTIFICATIONS_UPDATE: | |||||
case ACCOUNT_IMPORT: | |||||
return normalizeAccount(state, action.account); | return normalizeAccount(state, action.account); | ||||
case FOLLOWERS_FETCH_SUCCESS: | |||||
case FOLLOWERS_EXPAND_SUCCESS: | |||||
case FOLLOWING_FETCH_SUCCESS: | |||||
case FOLLOWING_EXPAND_SUCCESS: | |||||
case REBLOGS_FETCH_SUCCESS: | |||||
case FAVOURITES_FETCH_SUCCESS: | |||||
case COMPOSE_SUGGESTIONS_READY: | |||||
case FOLLOW_REQUESTS_FETCH_SUCCESS: | |||||
case FOLLOW_REQUESTS_EXPAND_SUCCESS: | |||||
case BLOCKS_FETCH_SUCCESS: | |||||
case BLOCKS_EXPAND_SUCCESS: | |||||
case MUTES_FETCH_SUCCESS: | |||||
case MUTES_EXPAND_SUCCESS: | |||||
case LIST_ACCOUNTS_FETCH_SUCCESS: | |||||
case LIST_EDITOR_SUGGESTIONS_READY: | |||||
return action.accounts ? normalizeAccounts(state, action.accounts) : state; | |||||
case NOTIFICATIONS_REFRESH_SUCCESS: | |||||
case NOTIFICATIONS_EXPAND_SUCCESS: | |||||
case SEARCH_FETCH_SUCCESS: | |||||
return normalizeAccountsFromStatuses(normalizeAccounts(state, action.accounts), action.statuses); | |||||
case TIMELINE_REFRESH_SUCCESS: | |||||
case TIMELINE_EXPAND_SUCCESS: | |||||
case CONTEXT_FETCH_SUCCESS: | |||||
case FAVOURITED_STATUSES_FETCH_SUCCESS: | |||||
case FAVOURITED_STATUSES_EXPAND_SUCCESS: | |||||
return normalizeAccountsFromStatuses(state, action.statuses); | |||||
case REBLOG_SUCCESS: | |||||
case FAVOURITE_SUCCESS: | |||||
case UNREBLOG_SUCCESS: | |||||
case UNFAVOURITE_SUCCESS: | |||||
return normalizeAccountFromStatus(state, action.response); | |||||
case TIMELINE_UPDATE: | |||||
case STATUS_FETCH_SUCCESS: | |||||
return normalizeAccountFromStatus(state, action.status); | |||||
case ACCOUNTS_IMPORT: | |||||
return normalizeAccounts(state, action.accounts); | |||||
default: | default: | ||||
return state; | return state; | ||||
} | } | ||||
@@ -1,55 +1,8 @@ | |||||
import { | import { | ||||
ACCOUNT_FETCH_SUCCESS, | |||||
FOLLOWERS_FETCH_SUCCESS, | |||||
FOLLOWERS_EXPAND_SUCCESS, | |||||
FOLLOWING_FETCH_SUCCESS, | |||||
FOLLOWING_EXPAND_SUCCESS, | |||||
FOLLOW_REQUESTS_FETCH_SUCCESS, | |||||
FOLLOW_REQUESTS_EXPAND_SUCCESS, | |||||
ACCOUNT_FOLLOW_SUCCESS, | ACCOUNT_FOLLOW_SUCCESS, | ||||
ACCOUNT_UNFOLLOW_SUCCESS, | ACCOUNT_UNFOLLOW_SUCCESS, | ||||
} from '../actions/accounts'; | } from '../actions/accounts'; | ||||
import { | |||||
BLOCKS_FETCH_SUCCESS, | |||||
BLOCKS_EXPAND_SUCCESS, | |||||
} from '../actions/blocks'; | |||||
import { | |||||
MUTES_FETCH_SUCCESS, | |||||
MUTES_EXPAND_SUCCESS, | |||||
} from '../actions/mutes'; | |||||
import { COMPOSE_SUGGESTIONS_READY } from '../actions/compose'; | |||||
import { | |||||
REBLOG_SUCCESS, | |||||
UNREBLOG_SUCCESS, | |||||
FAVOURITE_SUCCESS, | |||||
UNFAVOURITE_SUCCESS, | |||||
REBLOGS_FETCH_SUCCESS, | |||||
FAVOURITES_FETCH_SUCCESS, | |||||
} from '../actions/interactions'; | |||||
import { | |||||
TIMELINE_REFRESH_SUCCESS, | |||||
TIMELINE_UPDATE, | |||||
TIMELINE_EXPAND_SUCCESS, | |||||
} from '../actions/timelines'; | |||||
import { | |||||
STATUS_FETCH_SUCCESS, | |||||
CONTEXT_FETCH_SUCCESS, | |||||
} from '../actions/statuses'; | |||||
import { SEARCH_FETCH_SUCCESS } from '../actions/search'; | |||||
import { | |||||
NOTIFICATIONS_UPDATE, | |||||
NOTIFICATIONS_REFRESH_SUCCESS, | |||||
NOTIFICATIONS_EXPAND_SUCCESS, | |||||
} from '../actions/notifications'; | |||||
import { | |||||
FAVOURITED_STATUSES_FETCH_SUCCESS, | |||||
FAVOURITED_STATUSES_EXPAND_SUCCESS, | |||||
} from '../actions/favourites'; | |||||
import { | |||||
LIST_ACCOUNTS_FETCH_SUCCESS, | |||||
LIST_EDITOR_SUGGESTIONS_READY, | |||||
} from '../actions/lists'; | |||||
import { STORE_HYDRATE } from '../actions/store'; | |||||
import { ACCOUNT_IMPORT, ACCOUNTS_IMPORT } from '../actions/importer'; | |||||
import { Map as ImmutableMap, fromJS } from 'immutable'; | import { Map as ImmutableMap, fromJS } from 'immutable'; | ||||
const normalizeAccount = (state, account) => state.set(account.id, fromJS({ | const normalizeAccount = (state, account) => state.set(account.id, fromJS({ | ||||
@@ -66,71 +19,14 @@ const normalizeAccounts = (state, accounts) => { | |||||
return state; | return state; | ||||
}; | }; | ||||
const normalizeAccountFromStatus = (state, status) => { | |||||
state = normalizeAccount(state, status.account); | |||||
if (status.reblog && status.reblog.account) { | |||||
state = normalizeAccount(state, status.reblog.account); | |||||
} | |||||
return state; | |||||
}; | |||||
const normalizeAccountsFromStatuses = (state, statuses) => { | |||||
statuses.forEach(status => { | |||||
state = normalizeAccountFromStatus(state, status); | |||||
}); | |||||
return state; | |||||
}; | |||||
const initialState = ImmutableMap(); | const initialState = ImmutableMap(); | ||||
export default function accountsCounters(state = initialState, action) { | export default function accountsCounters(state = initialState, action) { | ||||
switch(action.type) { | switch(action.type) { | ||||
case STORE_HYDRATE: | |||||
return state.merge(action.state.get('accounts').map(item => fromJS({ | |||||
followers_count: item.get('followers_count'), | |||||
following_count: item.get('following_count'), | |||||
statuses_count: item.get('statuses_count'), | |||||
}))); | |||||
case ACCOUNT_FETCH_SUCCESS: | |||||
case NOTIFICATIONS_UPDATE: | |||||
case ACCOUNT_IMPORT: | |||||
return normalizeAccount(state, action.account); | return normalizeAccount(state, action.account); | ||||
case FOLLOWERS_FETCH_SUCCESS: | |||||
case FOLLOWERS_EXPAND_SUCCESS: | |||||
case FOLLOWING_FETCH_SUCCESS: | |||||
case FOLLOWING_EXPAND_SUCCESS: | |||||
case REBLOGS_FETCH_SUCCESS: | |||||
case FAVOURITES_FETCH_SUCCESS: | |||||
case COMPOSE_SUGGESTIONS_READY: | |||||
case FOLLOW_REQUESTS_FETCH_SUCCESS: | |||||
case FOLLOW_REQUESTS_EXPAND_SUCCESS: | |||||
case BLOCKS_FETCH_SUCCESS: | |||||
case BLOCKS_EXPAND_SUCCESS: | |||||
case MUTES_FETCH_SUCCESS: | |||||
case MUTES_EXPAND_SUCCESS: | |||||
case LIST_ACCOUNTS_FETCH_SUCCESS: | |||||
case LIST_EDITOR_SUGGESTIONS_READY: | |||||
return action.accounts ? normalizeAccounts(state, action.accounts) : state; | |||||
case NOTIFICATIONS_REFRESH_SUCCESS: | |||||
case NOTIFICATIONS_EXPAND_SUCCESS: | |||||
case SEARCH_FETCH_SUCCESS: | |||||
return normalizeAccountsFromStatuses(normalizeAccounts(state, action.accounts), action.statuses); | |||||
case TIMELINE_REFRESH_SUCCESS: | |||||
case TIMELINE_EXPAND_SUCCESS: | |||||
case CONTEXT_FETCH_SUCCESS: | |||||
case FAVOURITED_STATUSES_FETCH_SUCCESS: | |||||
case FAVOURITED_STATUSES_EXPAND_SUCCESS: | |||||
return normalizeAccountsFromStatuses(state, action.statuses); | |||||
case REBLOG_SUCCESS: | |||||
case FAVOURITE_SUCCESS: | |||||
case UNREBLOG_SUCCESS: | |||||
case UNFAVOURITE_SUCCESS: | |||||
return normalizeAccountFromStatus(state, action.response); | |||||
case TIMELINE_UPDATE: | |||||
case STATUS_FETCH_SUCCESS: | |||||
return normalizeAccountFromStatus(state, action.status); | |||||
case ACCOUNTS_IMPORT: | |||||
return normalizeAccounts(state, action.accounts); | |||||
case ACCOUNT_FOLLOW_SUCCESS: | case ACCOUNT_FOLLOW_SUCCESS: | ||||
return action.alreadyFollowing ? state : | return action.alreadyFollowing ? state : | ||||
state.updateIn([action.relationship.id, 'followers_count'], num => num + 1); | state.updateIn([action.relationship.id, 'followers_count'], num => num + 1); | ||||
@@ -1,87 +1,25 @@ | |||||
import { | import { | ||||
REBLOG_REQUEST, | REBLOG_REQUEST, | ||||
REBLOG_SUCCESS, | |||||
REBLOG_FAIL, | REBLOG_FAIL, | ||||
UNREBLOG_SUCCESS, | |||||
FAVOURITE_REQUEST, | FAVOURITE_REQUEST, | ||||
FAVOURITE_SUCCESS, | |||||
FAVOURITE_FAIL, | FAVOURITE_FAIL, | ||||
UNFAVOURITE_SUCCESS, | |||||
PIN_SUCCESS, | |||||
UNPIN_SUCCESS, | |||||
} from '../actions/interactions'; | } from '../actions/interactions'; | ||||
import { | import { | ||||
STATUS_FETCH_SUCCESS, | |||||
CONTEXT_FETCH_SUCCESS, | |||||
STATUS_MUTE_SUCCESS, | STATUS_MUTE_SUCCESS, | ||||
STATUS_UNMUTE_SUCCESS, | STATUS_UNMUTE_SUCCESS, | ||||
STATUS_REVEAL, | STATUS_REVEAL, | ||||
STATUS_HIDE, | STATUS_HIDE, | ||||
} from '../actions/statuses'; | } from '../actions/statuses'; | ||||
import { | import { | ||||
TIMELINE_REFRESH_SUCCESS, | |||||
TIMELINE_UPDATE, | |||||
TIMELINE_DELETE, | TIMELINE_DELETE, | ||||
TIMELINE_EXPAND_SUCCESS, | |||||
} from '../actions/timelines'; | } from '../actions/timelines'; | ||||
import { | |||||
NOTIFICATIONS_UPDATE, | |||||
NOTIFICATIONS_REFRESH_SUCCESS, | |||||
NOTIFICATIONS_EXPAND_SUCCESS, | |||||
} from '../actions/notifications'; | |||||
import { | |||||
FAVOURITED_STATUSES_FETCH_SUCCESS, | |||||
FAVOURITED_STATUSES_EXPAND_SUCCESS, | |||||
} from '../actions/favourites'; | |||||
import { | |||||
PINNED_STATUSES_FETCH_SUCCESS, | |||||
} from '../actions/pin_statuses'; | |||||
import { SEARCH_FETCH_SUCCESS } from '../actions/search'; | |||||
import emojify from '../features/emoji/emoji'; | |||||
import { STATUS_IMPORT, STATUSES_IMPORT } from '../actions/importer'; | |||||
import { Map as ImmutableMap, fromJS } from 'immutable'; | import { Map as ImmutableMap, fromJS } from 'immutable'; | ||||
import escapeTextContentForBrowser from 'escape-html'; | |||||
const domParser = new DOMParser(); | |||||
const normalizeStatus = (state, status) => { | |||||
if (!status) { | |||||
return state; | |||||
} | |||||
const normalStatus = { ...status }; | |||||
normalStatus.account = status.account.id; | |||||
if (status.reblog && status.reblog.id) { | |||||
state = normalizeStatus(state, status.reblog); | |||||
normalStatus.reblog = status.reblog.id; | |||||
} | |||||
// Only calculate these values when status first encountered | |||||
// Otherwise keep the ones already in the reducer | |||||
if (!state.has(status.id)) { | |||||
const searchContent = [status.spoiler_text, status.content].join('\n\n').replace(/<br\s*\/?>/g, '\n').replace(/<\/p><p>/g, '\n\n'); | |||||
const emojiMap = normalStatus.emojis.reduce((obj, emoji) => { | |||||
obj[`:${emoji.shortcode}:`] = emoji; | |||||
return obj; | |||||
}, {}); | |||||
const importStatus = (state, status) => state.set(status.id, fromJS(status)); | |||||
normalStatus.search_index = domParser.parseFromString(searchContent, 'text/html').documentElement.textContent; | |||||
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap); | |||||
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(normalStatus.spoiler_text || ''), emojiMap); | |||||
normalStatus.hidden = normalStatus.sensitive; | |||||
} | |||||
return state.update(status.id, ImmutableMap(), map => map.mergeDeep(fromJS(normalStatus))); | |||||
}; | |||||
const normalizeStatuses = (state, statuses) => { | |||||
statuses.forEach(status => { | |||||
state = normalizeStatus(state, status); | |||||
}); | |||||
return state; | |||||
}; | |||||
const importStatuses = (state, statuses) => | |||||
state.withMutations(mutable => statuses.forEach(status => importStatus(mutable, status))); | |||||
const deleteStatus = (state, id, references) => { | const deleteStatus = (state, id, references) => { | ||||
references.forEach(ref => { | references.forEach(ref => { | ||||
@@ -95,17 +33,10 @@ const initialState = ImmutableMap(); | |||||
export default function statuses(state = initialState, action) { | export default function statuses(state = initialState, action) { | ||||
switch(action.type) { | switch(action.type) { | ||||
case TIMELINE_UPDATE: | |||||
case STATUS_FETCH_SUCCESS: | |||||
case NOTIFICATIONS_UPDATE: | |||||
return normalizeStatus(state, action.status); | |||||
case REBLOG_SUCCESS: | |||||
case UNREBLOG_SUCCESS: | |||||
case FAVOURITE_SUCCESS: | |||||
case UNFAVOURITE_SUCCESS: | |||||
case PIN_SUCCESS: | |||||
case UNPIN_SUCCESS: | |||||
return normalizeStatus(state, action.response); | |||||
case STATUS_IMPORT: | |||||
return importStatus(state, action.status); | |||||
case STATUSES_IMPORT: | |||||
return importStatuses(state, action.statuses); | |||||
case FAVOURITE_REQUEST: | case FAVOURITE_REQUEST: | ||||
return state.setIn([action.status.get('id'), 'favourited'], true); | return state.setIn([action.status.get('id'), 'favourited'], true); | ||||
case FAVOURITE_FAIL: | case FAVOURITE_FAIL: | ||||
@@ -126,16 +57,6 @@ export default function statuses(state = initialState, action) { | |||||
return state.withMutations(map => { | return state.withMutations(map => { | ||||
action.ids.forEach(id => map.setIn([id, 'hidden'], true)); | action.ids.forEach(id => map.setIn([id, 'hidden'], true)); | ||||
}); | }); | ||||
case TIMELINE_REFRESH_SUCCESS: | |||||
case TIMELINE_EXPAND_SUCCESS: | |||||
case CONTEXT_FETCH_SUCCESS: | |||||
case NOTIFICATIONS_REFRESH_SUCCESS: | |||||
case NOTIFICATIONS_EXPAND_SUCCESS: | |||||
case FAVOURITED_STATUSES_FETCH_SUCCESS: | |||||
case FAVOURITED_STATUSES_EXPAND_SUCCESS: | |||||
case PINNED_STATUSES_FETCH_SUCCESS: | |||||
case SEARCH_FETCH_SUCCESS: | |||||
return normalizeStatuses(state, action.statuses); | |||||
case TIMELINE_DELETE: | case TIMELINE_DELETE: | ||||
return deleteStatus(state, action.id, action.references); | return deleteStatus(state, action.id, action.references); | ||||
default: | default: | ||||