The code powering m.abunchtell.com https://m.abunchtell.com
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.
 
 
 
 

359 lines
8.9 KiB

  1. import api from '../api';
  2. import { emojiIndex } from 'emoji-mart';
  3. import {
  4. updateTimeline,
  5. refreshHomeTimeline,
  6. refreshCommunityTimeline,
  7. refreshPublicTimeline,
  8. } from './timelines';
  9. export const COMPOSE_CHANGE = 'COMPOSE_CHANGE';
  10. export const COMPOSE_SUBMIT_REQUEST = 'COMPOSE_SUBMIT_REQUEST';
  11. export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS';
  12. export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL';
  13. export const COMPOSE_REPLY = 'COMPOSE_REPLY';
  14. export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL';
  15. export const COMPOSE_MENTION = 'COMPOSE_MENTION';
  16. export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST';
  17. export const COMPOSE_UPLOAD_SUCCESS = 'COMPOSE_UPLOAD_SUCCESS';
  18. export const COMPOSE_UPLOAD_FAIL = 'COMPOSE_UPLOAD_FAIL';
  19. export const COMPOSE_UPLOAD_PROGRESS = 'COMPOSE_UPLOAD_PROGRESS';
  20. export const COMPOSE_UPLOAD_UNDO = 'COMPOSE_UPLOAD_UNDO';
  21. export const COMPOSE_SUGGESTIONS_CLEAR = 'COMPOSE_SUGGESTIONS_CLEAR';
  22. export const COMPOSE_SUGGESTIONS_READY = 'COMPOSE_SUGGESTIONS_READY';
  23. export const COMPOSE_SUGGESTION_SELECT = 'COMPOSE_SUGGESTION_SELECT';
  24. export const COMPOSE_MOUNT = 'COMPOSE_MOUNT';
  25. export const COMPOSE_UNMOUNT = 'COMPOSE_UNMOUNT';
  26. export const COMPOSE_SENSITIVITY_CHANGE = 'COMPOSE_SENSITIVITY_CHANGE';
  27. export const COMPOSE_SPOILERNESS_CHANGE = 'COMPOSE_SPOILERNESS_CHANGE';
  28. export const COMPOSE_SPOILER_TEXT_CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE';
  29. export const COMPOSE_VISIBILITY_CHANGE = 'COMPOSE_VISIBILITY_CHANGE';
  30. export const COMPOSE_LISTABILITY_CHANGE = 'COMPOSE_LISTABILITY_CHANGE';
  31. export const COMPOSE_COMPOSING_CHANGE = 'COMPOSE_COMPOSING_CHANGE';
  32. export const COMPOSE_EMOJI_INSERT = 'COMPOSE_EMOJI_INSERT';
  33. export const COMPOSE_UPLOAD_CHANGE_REQUEST = 'COMPOSE_UPLOAD_UPDATE_REQUEST';
  34. export const COMPOSE_UPLOAD_CHANGE_SUCCESS = 'COMPOSE_UPLOAD_UPDATE_SUCCESS';
  35. export const COMPOSE_UPLOAD_CHANGE_FAIL = 'COMPOSE_UPLOAD_UPDATE_FAIL';
  36. export function changeCompose(text) {
  37. return {
  38. type: COMPOSE_CHANGE,
  39. text: text,
  40. };
  41. };
  42. export function replyCompose(status, router) {
  43. return (dispatch, getState) => {
  44. dispatch({
  45. type: COMPOSE_REPLY,
  46. status: status,
  47. });
  48. if (!getState().getIn(['compose', 'mounted'])) {
  49. router.push('/statuses/new');
  50. }
  51. };
  52. };
  53. export function cancelReplyCompose() {
  54. return {
  55. type: COMPOSE_REPLY_CANCEL,
  56. };
  57. };
  58. export function mentionCompose(account, router) {
  59. return (dispatch, getState) => {
  60. dispatch({
  61. type: COMPOSE_MENTION,
  62. account: account,
  63. });
  64. if (!getState().getIn(['compose', 'mounted'])) {
  65. router.push('/statuses/new');
  66. }
  67. };
  68. };
  69. export function submitCompose() {
  70. return function (dispatch, getState) {
  71. const status = getState().getIn(['compose', 'text'], '');
  72. if (!status || !status.length) {
  73. return;
  74. }
  75. dispatch(submitComposeRequest());
  76. api(getState).post('/api/v1/statuses', {
  77. status,
  78. in_reply_to_id: getState().getIn(['compose', 'in_reply_to'], null),
  79. media_ids: getState().getIn(['compose', 'media_attachments']).map(item => item.get('id')),
  80. sensitive: getState().getIn(['compose', 'sensitive']),
  81. spoiler_text: getState().getIn(['compose', 'spoiler_text'], ''),
  82. visibility: getState().getIn(['compose', 'privacy']),
  83. }, {
  84. headers: {
  85. 'Idempotency-Key': getState().getIn(['compose', 'idempotencyKey']),
  86. },
  87. }).then(function (response) {
  88. dispatch(submitComposeSuccess({ ...response.data }));
  89. // To make the app more responsive, immediately get the status into the columns
  90. const insertOrRefresh = (timelineId, refreshAction) => {
  91. if (getState().getIn(['timelines', timelineId, 'online'])) {
  92. dispatch(updateTimeline(timelineId, { ...response.data }));
  93. } else if (getState().getIn(['timelines', timelineId, 'loaded'])) {
  94. dispatch(refreshAction());
  95. }
  96. };
  97. insertOrRefresh('home', refreshHomeTimeline);
  98. if (response.data.in_reply_to_id === null && response.data.visibility === 'public') {
  99. insertOrRefresh('community', refreshCommunityTimeline);
  100. insertOrRefresh('public', refreshPublicTimeline);
  101. }
  102. }).catch(function (error) {
  103. dispatch(submitComposeFail(error));
  104. });
  105. };
  106. };
  107. export function submitComposeRequest() {
  108. return {
  109. type: COMPOSE_SUBMIT_REQUEST,
  110. };
  111. };
  112. export function submitComposeSuccess(status) {
  113. return {
  114. type: COMPOSE_SUBMIT_SUCCESS,
  115. status: status,
  116. };
  117. };
  118. export function submitComposeFail(error) {
  119. return {
  120. type: COMPOSE_SUBMIT_FAIL,
  121. error: error,
  122. };
  123. };
  124. export function uploadCompose(files) {
  125. return function (dispatch, getState) {
  126. if (getState().getIn(['compose', 'media_attachments']).size > 3) {
  127. return;
  128. }
  129. dispatch(uploadComposeRequest());
  130. let data = new FormData();
  131. data.append('file', files[0]);
  132. api(getState).post('/api/v1/media', data, {
  133. onUploadProgress: function (e) {
  134. dispatch(uploadComposeProgress(e.loaded, e.total));
  135. },
  136. }).then(function (response) {
  137. dispatch(uploadComposeSuccess(response.data));
  138. }).catch(function (error) {
  139. dispatch(uploadComposeFail(error));
  140. });
  141. };
  142. };
  143. export function changeUploadCompose(id, description) {
  144. return (dispatch, getState) => {
  145. dispatch(changeUploadComposeRequest());
  146. api(getState).put(`/api/v1/media/${id}`, { description }).then(response => {
  147. dispatch(changeUploadComposeSuccess(response.data));
  148. }).catch(error => {
  149. dispatch(changeUploadComposeFail(id, error));
  150. });
  151. };
  152. };
  153. export function changeUploadComposeRequest() {
  154. return {
  155. type: COMPOSE_UPLOAD_CHANGE_REQUEST,
  156. skipLoading: true,
  157. };
  158. };
  159. export function changeUploadComposeSuccess(media) {
  160. return {
  161. type: COMPOSE_UPLOAD_CHANGE_SUCCESS,
  162. media: media,
  163. skipLoading: true,
  164. };
  165. };
  166. export function changeUploadComposeFail(error) {
  167. return {
  168. type: COMPOSE_UPLOAD_CHANGE_FAIL,
  169. error: error,
  170. skipLoading: true,
  171. };
  172. };
  173. export function uploadComposeRequest() {
  174. return {
  175. type: COMPOSE_UPLOAD_REQUEST,
  176. skipLoading: true,
  177. };
  178. };
  179. export function uploadComposeProgress(loaded, total) {
  180. return {
  181. type: COMPOSE_UPLOAD_PROGRESS,
  182. loaded: loaded,
  183. total: total,
  184. };
  185. };
  186. export function uploadComposeSuccess(media) {
  187. return {
  188. type: COMPOSE_UPLOAD_SUCCESS,
  189. media: media,
  190. skipLoading: true,
  191. };
  192. };
  193. export function uploadComposeFail(error) {
  194. return {
  195. type: COMPOSE_UPLOAD_FAIL,
  196. error: error,
  197. skipLoading: true,
  198. };
  199. };
  200. export function undoUploadCompose(media_id) {
  201. return {
  202. type: COMPOSE_UPLOAD_UNDO,
  203. media_id: media_id,
  204. };
  205. };
  206. export function clearComposeSuggestions() {
  207. return {
  208. type: COMPOSE_SUGGESTIONS_CLEAR,
  209. };
  210. };
  211. export function fetchComposeSuggestions(token) {
  212. return (dispatch, getState) => {
  213. if (token[0] === ':') {
  214. const results = emojiIndex.search(token.replace(':', ''), { maxResults: 3 });
  215. dispatch(readyComposeSuggestionsEmojis(token, results));
  216. return;
  217. }
  218. api(getState).get('/api/v1/accounts/search', {
  219. params: {
  220. q: token.slice(1),
  221. resolve: false,
  222. limit: 4,
  223. },
  224. }).then(response => {
  225. dispatch(readyComposeSuggestionsAccounts(token, response.data));
  226. });
  227. };
  228. };
  229. export function readyComposeSuggestionsEmojis(token, emojis) {
  230. return {
  231. type: COMPOSE_SUGGESTIONS_READY,
  232. token,
  233. emojis,
  234. };
  235. };
  236. export function readyComposeSuggestionsAccounts(token, accounts) {
  237. return {
  238. type: COMPOSE_SUGGESTIONS_READY,
  239. token,
  240. accounts,
  241. };
  242. };
  243. export function selectComposeSuggestion(position, token, suggestion) {
  244. return (dispatch, getState) => {
  245. let completion, startPosition;
  246. if (typeof suggestion === 'object' && suggestion.id) {
  247. completion = suggestion.native || suggestion.colons;
  248. startPosition = position - 1;
  249. } else {
  250. completion = getState().getIn(['accounts', suggestion, 'acct']);
  251. startPosition = position;
  252. }
  253. dispatch({
  254. type: COMPOSE_SUGGESTION_SELECT,
  255. position: startPosition,
  256. token,
  257. completion,
  258. });
  259. };
  260. };
  261. export function mountCompose() {
  262. return {
  263. type: COMPOSE_MOUNT,
  264. };
  265. };
  266. export function unmountCompose() {
  267. return {
  268. type: COMPOSE_UNMOUNT,
  269. };
  270. };
  271. export function changeComposeSensitivity() {
  272. return {
  273. type: COMPOSE_SENSITIVITY_CHANGE,
  274. };
  275. };
  276. export function changeComposeSpoilerness() {
  277. return {
  278. type: COMPOSE_SPOILERNESS_CHANGE,
  279. };
  280. };
  281. export function changeComposeSpoilerText(text) {
  282. return {
  283. type: COMPOSE_SPOILER_TEXT_CHANGE,
  284. text,
  285. };
  286. };
  287. export function changeComposeVisibility(value) {
  288. return {
  289. type: COMPOSE_VISIBILITY_CHANGE,
  290. value,
  291. };
  292. };
  293. export function insertEmojiCompose(position, emoji) {
  294. return {
  295. type: COMPOSE_EMOJI_INSERT,
  296. position,
  297. emoji,
  298. };
  299. };
  300. export function changeComposing(value) {
  301. return {
  302. type: COMPOSE_COMPOSING_CHANGE,
  303. value,
  304. };
  305. }