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.

216 lines
7.6 KiB

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