timelines.js 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. import api, { getLinks } from '../api'
  2. import Immutable 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 function refreshTimelineSuccess(timeline, statuses, skipLoading, next) {
  15. return {
  16. type: TIMELINE_REFRESH_SUCCESS,
  17. timeline,
  18. statuses,
  19. skipLoading,
  20. next
  21. };
  22. };
  23. export function updateTimeline(timeline, status) {
  24. return (dispatch, getState) => {
  25. const references = status.reblog ? getState().get('statuses').filter((item, itemId) => (itemId === status.reblog.id || item.get('reblog') === status.reblog.id)).map((_, itemId) => itemId) : [];
  26. dispatch({
  27. type: TIMELINE_UPDATE,
  28. timeline,
  29. status,
  30. references
  31. });
  32. };
  33. };
  34. export function deleteFromTimelines(id) {
  35. return (dispatch, getState) => {
  36. const accountId = getState().getIn(['statuses', id, 'account']);
  37. const references = getState().get('statuses').filter(status => status.get('reblog') === id).map(status => [status.get('id'), status.get('account')]);
  38. const reblogOf = getState().getIn(['statuses', id, 'reblog'], null);
  39. dispatch({
  40. type: TIMELINE_DELETE,
  41. id,
  42. accountId,
  43. references,
  44. reblogOf
  45. });
  46. };
  47. };
  48. export function refreshTimelineRequest(timeline, id, skipLoading) {
  49. return {
  50. type: TIMELINE_REFRESH_REQUEST,
  51. timeline,
  52. id,
  53. skipLoading
  54. };
  55. };
  56. export function refreshTimeline(timeline, id = null) {
  57. return function (dispatch, getState) {
  58. if (getState().getIn(['timelines', timeline, 'isLoading'])) {
  59. return;
  60. }
  61. const ids = getState().getIn(['timelines', timeline, 'items'], Immutable.List());
  62. const newestId = ids.size > 0 ? ids.first() : null;
  63. let params = getState().getIn(['timelines', timeline, 'params'], {});
  64. const path = getState().getIn(['timelines', timeline, 'path'])(id);
  65. let skipLoading = false;
  66. if (newestId !== null && getState().getIn(['timelines', timeline, 'loaded']) && (id === null || getState().getIn(['timelines', timeline, 'id']) === id)) {
  67. if (id === null && getState().getIn(['timelines', timeline, 'online'])) {
  68. // Skip refreshing when timeline is live anyway
  69. return;
  70. }
  71. params = { ...params, since_id: newestId };
  72. skipLoading = true;
  73. }
  74. dispatch(refreshTimelineRequest(timeline, id, skipLoading));
  75. api(getState).get(path, { params }).then(response => {
  76. const next = getLinks(response).refs.find(link => link.rel === 'next');
  77. dispatch(refreshTimelineSuccess(timeline, response.data, skipLoading, next ? next.uri : null));
  78. }).catch(error => {
  79. dispatch(refreshTimelineFail(timeline, error, skipLoading));
  80. });
  81. };
  82. };
  83. export function refreshTimelineFail(timeline, error, skipLoading) {
  84. return {
  85. type: TIMELINE_REFRESH_FAIL,
  86. timeline,
  87. error,
  88. skipLoading
  89. };
  90. };
  91. export function expandTimeline(timeline) {
  92. return (dispatch, getState) => {
  93. if (getState().getIn(['timelines', timeline, 'isLoading'])) {
  94. return;
  95. }
  96. if (getState().getIn(['timelines', timeline, 'items']).size === 0) {
  97. return;
  98. }
  99. const path = getState().getIn(['timelines', timeline, 'path'])(getState().getIn(['timelines', timeline, 'id']));
  100. const params = getState().getIn(['timelines', timeline, 'params'], {});
  101. const lastId = getState().getIn(['timelines', timeline, 'items']).last();
  102. dispatch(expandTimelineRequest(timeline));
  103. api(getState).get(path, {
  104. params: {
  105. ...params,
  106. max_id: lastId,
  107. limit: 10
  108. }
  109. }).then(response => {
  110. const next = getLinks(response).refs.find(link => link.rel === 'next');
  111. dispatch(expandTimelineSuccess(timeline, response.data, next ? next.uri : null));
  112. }).catch(error => {
  113. dispatch(expandTimelineFail(timeline, error));
  114. });
  115. };
  116. };
  117. export function expandTimelineRequest(timeline) {
  118. return {
  119. type: TIMELINE_EXPAND_REQUEST,
  120. timeline
  121. };
  122. };
  123. export function expandTimelineSuccess(timeline, statuses, next) {
  124. return {
  125. type: TIMELINE_EXPAND_SUCCESS,
  126. timeline,
  127. statuses,
  128. next
  129. };
  130. };
  131. export function expandTimelineFail(timeline, error) {
  132. return {
  133. type: TIMELINE_EXPAND_FAIL,
  134. timeline,
  135. error
  136. };
  137. };
  138. export function scrollTopTimeline(timeline, top) {
  139. return {
  140. type: TIMELINE_SCROLL_TOP,
  141. timeline,
  142. top
  143. };
  144. };
  145. export function connectTimeline(timeline) {
  146. return {
  147. type: TIMELINE_CONNECT,
  148. timeline
  149. };
  150. };
  151. export function disconnectTimeline(timeline) {
  152. return {
  153. type: TIMELINE_DISCONNECT,
  154. timeline
  155. };
  156. };