You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

219 lines
7.6 KiB

7 years ago
7 years ago
  1. import { importFetchedStatus, importFetchedStatuses } from './importer';
  2. import api, { getLinks } from '../api';
  3. import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
  4. export const TIMELINE_UPDATE = 'TIMELINE_UPDATE';
  5. export const TIMELINE_DELETE = 'TIMELINE_DELETE';
  6. export const TIMELINE_REFRESH_REQUEST = 'TIMELINE_REFRESH_REQUEST';
  7. export const TIMELINE_REFRESH_SUCCESS = 'TIMELINE_REFRESH_SUCCESS';
  8. export const TIMELINE_REFRESH_FAIL = 'TIMELINE_REFRESH_FAIL';
  9. export const TIMELINE_EXPAND_REQUEST = 'TIMELINE_EXPAND_REQUEST';
  10. export const TIMELINE_EXPAND_SUCCESS = 'TIMELINE_EXPAND_SUCCESS';
  11. export const TIMELINE_EXPAND_FAIL = 'TIMELINE_EXPAND_FAIL';
  12. export const TIMELINE_SCROLL_TOP = 'TIMELINE_SCROLL_TOP';
  13. export const TIMELINE_CONNECT = 'TIMELINE_CONNECT';
  14. export const TIMELINE_DISCONNECT = 'TIMELINE_DISCONNECT';
  15. export const TIMELINE_CONTEXT_UPDATE = 'CONTEXT_UPDATE';
  16. export function refreshTimelineSuccess(timeline, statuses, skipLoading, next, partial) {
  17. return {
  18. type: TIMELINE_REFRESH_SUCCESS,
  19. timeline,
  20. statuses,
  21. skipLoading,
  22. next,
  23. partial,
  24. };
  25. };
  26. export function updateTimeline(timeline, status) {
  27. return (dispatch, getState) => {
  28. const references = status.reblog ? getState().get('statuses').filter((item, itemId) => (itemId === status.reblog.id || item.get('reblog') === status.reblog.id)).map((_, itemId) => itemId) : [];
  29. const parents = [];
  30. if (status.in_reply_to_id) {
  31. let parent = getState().getIn(['statuses', status.in_reply_to_id]);
  32. while (parent && parent.get('in_reply_to_id')) {
  33. parents.push(parent.get('id'));
  34. parent = getState().getIn(['statuses', parent.get('in_reply_to_id')]);
  35. }
  36. }
  37. dispatch(importFetchedStatus(status));
  38. dispatch({
  39. type: TIMELINE_UPDATE,
  40. timeline,
  41. status,
  42. references,
  43. });
  44. if (parents.length > 0) {
  45. dispatch({
  46. type: TIMELINE_CONTEXT_UPDATE,
  47. status,
  48. references: parents,
  49. });
  50. }
  51. };
  52. };
  53. export function deleteFromTimelines(id) {
  54. return (dispatch, getState) => {
  55. const accountId = getState().getIn(['statuses', id, 'account']);
  56. const references = getState().get('statuses').filter(status => status.get('reblog') === id).map(status => [status.get('id'), status.get('account')]);
  57. const reblogOf = getState().getIn(['statuses', id, 'reblog'], null);
  58. dispatch({
  59. type: TIMELINE_DELETE,
  60. id,
  61. accountId,
  62. references,
  63. reblogOf,
  64. });
  65. };
  66. };
  67. export function refreshTimelineRequest(timeline, skipLoading) {
  68. return {
  69. type: TIMELINE_REFRESH_REQUEST,
  70. timeline,
  71. skipLoading,
  72. };
  73. };
  74. export function refreshTimeline(timelineId, path, params = {}) {
  75. return function (dispatch, getState) {
  76. const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());
  77. if (timeline.get('isLoading') || (timeline.get('online') && !timeline.get('isPartial'))) {
  78. return;
  79. }
  80. const ids = timeline.get('items', ImmutableList());
  81. const newestId = ids.size > 0 ? ids.first() : null;
  82. let skipLoading = timeline.get('loaded');
  83. if (newestId !== null) {
  84. params.since_id = newestId;
  85. }
  86. dispatch(refreshTimelineRequest(timelineId, skipLoading));
  87. api(getState).get(path, { params }).then(response => {
  88. if (response.status === 206) {
  89. dispatch(refreshTimelineSuccess(timelineId, [], skipLoading, null, true));
  90. } else {
  91. const next = getLinks(response).refs.find(link => link.rel === 'next');
  92. dispatch(importFetchedStatuses(response.data));
  93. dispatch(refreshTimelineSuccess(timelineId, response.data, skipLoading, next ? next.uri : null, false));
  94. }
  95. }).catch(error => {
  96. dispatch(refreshTimelineFail(timelineId, error, skipLoading));
  97. });
  98. };
  99. };
  100. export const refreshHomeTimeline = () => refreshTimeline('home', '/api/v1/timelines/home');
  101. export const refreshPublicTimeline = () => refreshTimeline('public', '/api/v1/timelines/public');
  102. export const refreshCommunityTimeline = () => refreshTimeline('community', '/api/v1/timelines/public', { local: true });
  103. export const refreshAccountTimeline = (accountId, withReplies) => refreshTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies });
  104. export const refreshAccountFeaturedTimeline = accountId => refreshTimeline(`account:${accountId}:pinned`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true });
  105. export const refreshAccountMediaTimeline = accountId => refreshTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { only_media: true });
  106. export const refreshHashtagTimeline = hashtag => refreshTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`);
  107. export const refreshListTimeline = id => refreshTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`);
  108. export function refreshTimelineFail(timeline, error, skipLoading) {
  109. return {
  110. type: TIMELINE_REFRESH_FAIL,
  111. timeline,
  112. error,
  113. skipLoading,
  114. skipAlert: error.response && error.response.status === 404,
  115. };
  116. };
  117. export function expandTimeline(timelineId, path, params = {}) {
  118. return (dispatch, getState) => {
  119. const timeline = getState().getIn(['timelines', timelineId], ImmutableMap());
  120. const ids = timeline.get('items', ImmutableList());
  121. if (timeline.get('isLoading') || ids.size === 0) {
  122. return;
  123. }
  124. params.max_id = ids.last();
  125. params.limit = 10;
  126. dispatch(expandTimelineRequest(timelineId));
  127. api(getState).get(path, { params }).then(response => {
  128. const next = getLinks(response).refs.find(link => link.rel === 'next');
  129. dispatch(importFetchedStatuses(response.data));
  130. dispatch(expandTimelineSuccess(timelineId, response.data, next ? next.uri : null));
  131. }).catch(error => {
  132. dispatch(expandTimelineFail(timelineId, error));
  133. });
  134. };
  135. };
  136. export const expandHomeTimeline = () => expandTimeline('home', '/api/v1/timelines/home');
  137. export const expandPublicTimeline = () => expandTimeline('public', '/api/v1/timelines/public');
  138. export const expandCommunityTimeline = () => expandTimeline('community', '/api/v1/timelines/public', { local: true });
  139. export const expandAccountTimeline = (accountId, withReplies) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies });
  140. export const expandAccountMediaTimeline = accountId => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { only_media: true });
  141. export const expandHashtagTimeline = hashtag => expandTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`);
  142. export const expandListTimeline = id => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`);
  143. export function expandTimelineRequest(timeline) {
  144. return {
  145. type: TIMELINE_EXPAND_REQUEST,
  146. timeline,
  147. };
  148. };
  149. export function expandTimelineSuccess(timeline, statuses, next) {
  150. return {
  151. type: TIMELINE_EXPAND_SUCCESS,
  152. timeline,
  153. statuses,
  154. next,
  155. };
  156. };
  157. export function expandTimelineFail(timeline, error) {
  158. return {
  159. type: TIMELINE_EXPAND_FAIL,
  160. timeline,
  161. error,
  162. };
  163. };
  164. export function scrollTopTimeline(timeline, top) {
  165. return {
  166. type: TIMELINE_SCROLL_TOP,
  167. timeline,
  168. top,
  169. };
  170. };
  171. export function connectTimeline(timeline) {
  172. return {
  173. type: TIMELINE_CONNECT,
  174. timeline,
  175. };
  176. };
  177. export function disconnectTimeline(timeline) {
  178. return {
  179. type: TIMELINE_DISCONNECT,
  180. timeline,
  181. };
  182. };