2019-07-02 08:10:25 +01:00
import api from '../api' ;
2020-05-07 00:40:54 +01:00
import { FormattedMessage } from 'react-intl'
2019-07-02 08:10:25 +01:00
import { CancelToken , isCancel } from 'axios' ;
2020-04-08 02:06:59 +01:00
import throttle from 'lodash.throttle'
2020-05-02 07:25:55 +01:00
import moment from 'moment-mini'
2020-05-15 04:17:31 +01:00
import { isMobile } from '../utils/is_mobile'
2019-08-07 06:02:36 +01:00
import { search as emojiSearch } from '../components/emoji/emoji_mart_search_light' ;
2020-04-29 03:24:35 +01:00
import { urlRegex } from '../features/ui/util/url_regex'
2019-07-02 08:10:25 +01:00
import { tagHistory } from '../settings' ;
2020-07-15 04:31:54 +01:00
import { joinGroup } from './groups'
2019-07-02 08:10:25 +01:00
import { useEmoji } from './emojis' ;
import resizeImage from '../utils/resize_image' ;
import { importFetchedAccounts } from './importer' ;
2019-07-11 17:10:46 +01:00
import { updateTimeline , dequeueTimeline } from './timelines' ;
2020-03-14 17:31:29 +00:00
// import { showAlert, showAlertForError } from './alerts';
2019-07-02 08:10:25 +01:00
import { defineMessages } from 'react-intl' ;
import { openModal , closeModal } from './modal' ;
2020-07-25 01:05:31 +01:00
import {
STATUS _EXPIRATION _OPTION _5 _MINUTES ,
STATUS _EXPIRATION _OPTION _60 _MINUTES ,
STATUS _EXPIRATION _OPTION _6 _HOURS ,
STATUS _EXPIRATION _OPTION _24 _HOURS ,
STATUS _EXPIRATION _OPTION _3 _DAYS ,
STATUS _EXPIRATION _OPTION _7 _DAYS ,
} from '../constants'
2020-01-29 16:45:17 +00:00
import { me } from '../initial_state' ;
2020-05-07 00:40:54 +01:00
import { makeGetStatus } from '../selectors'
2019-07-02 08:10:25 +01:00
let cancelFetchComposeSuggestionsAccounts ;
export const COMPOSE _CHANGE = 'COMPOSE_CHANGE' ;
export const COMPOSE _SUBMIT _REQUEST = 'COMPOSE_SUBMIT_REQUEST' ;
export const COMPOSE _SUBMIT _SUCCESS = 'COMPOSE_SUBMIT_SUCCESS' ;
export const COMPOSE _SUBMIT _FAIL = 'COMPOSE_SUBMIT_FAIL' ;
export const COMPOSE _REPLY = 'COMPOSE_REPLY' ;
2019-07-30 19:27:49 +01:00
export const COMPOSE _QUOTE = 'COMPOSE_QUOTE' ;
2019-07-02 08:10:25 +01:00
export const COMPOSE _REPLY _CANCEL = 'COMPOSE_REPLY_CANCEL' ;
export const COMPOSE _MENTION = 'COMPOSE_MENTION' ;
export const COMPOSE _RESET = 'COMPOSE_RESET' ;
export const COMPOSE _UPLOAD _REQUEST = 'COMPOSE_UPLOAD_REQUEST' ;
export const COMPOSE _UPLOAD _SUCCESS = 'COMPOSE_UPLOAD_SUCCESS' ;
export const COMPOSE _UPLOAD _FAIL = 'COMPOSE_UPLOAD_FAIL' ;
export const COMPOSE _UPLOAD _PROGRESS = 'COMPOSE_UPLOAD_PROGRESS' ;
export const COMPOSE _UPLOAD _UNDO = 'COMPOSE_UPLOAD_UNDO' ;
export const COMPOSE _SUGGESTIONS _CLEAR = 'COMPOSE_SUGGESTIONS_CLEAR' ;
export const COMPOSE _SUGGESTIONS _READY = 'COMPOSE_SUGGESTIONS_READY' ;
export const COMPOSE _SUGGESTION _SELECT = 'COMPOSE_SUGGESTION_SELECT' ;
export const COMPOSE _SUGGESTION _TAGS _UPDATE = 'COMPOSE_SUGGESTION_TAGS_UPDATE' ;
export const COMPOSE _TAG _HISTORY _UPDATE = 'COMPOSE_TAG_HISTORY_UPDATE' ;
export const COMPOSE _MOUNT = 'COMPOSE_MOUNT' ;
export const COMPOSE _UNMOUNT = 'COMPOSE_UNMOUNT' ;
export const COMPOSE _SENSITIVITY _CHANGE = 'COMPOSE_SENSITIVITY_CHANGE' ;
export const COMPOSE _SPOILERNESS _CHANGE = 'COMPOSE_SPOILERNESS_CHANGE' ;
export const COMPOSE _SPOILER _TEXT _CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE' ;
export const COMPOSE _VISIBILITY _CHANGE = 'COMPOSE_VISIBILITY_CHANGE' ;
export const COMPOSE _LISTABILITY _CHANGE = 'COMPOSE_LISTABILITY_CHANGE' ;
export const COMPOSE _COMPOSING _CHANGE = 'COMPOSE_COMPOSING_CHANGE' ;
export const COMPOSE _EMOJI _INSERT = 'COMPOSE_EMOJI_INSERT' ;
export const COMPOSE _UPLOAD _CHANGE _REQUEST = 'COMPOSE_UPLOAD_UPDATE_REQUEST' ;
export const COMPOSE _UPLOAD _CHANGE _SUCCESS = 'COMPOSE_UPLOAD_UPDATE_SUCCESS' ;
export const COMPOSE _UPLOAD _CHANGE _FAIL = 'COMPOSE_UPLOAD_UPDATE_FAIL' ;
export const COMPOSE _POLL _ADD = 'COMPOSE_POLL_ADD' ;
export const COMPOSE _POLL _REMOVE = 'COMPOSE_POLL_REMOVE' ;
export const COMPOSE _POLL _OPTION _ADD = 'COMPOSE_POLL_OPTION_ADD' ;
export const COMPOSE _POLL _OPTION _CHANGE = 'COMPOSE_POLL_OPTION_CHANGE' ;
export const COMPOSE _POLL _OPTION _REMOVE = 'COMPOSE_POLL_OPTION_REMOVE' ;
export const COMPOSE _POLL _SETTINGS _CHANGE = 'COMPOSE_POLL_SETTINGS_CHANGE' ;
2019-09-19 01:15:01 +01:00
export const COMPOSE _SCHEDULED _AT _CHANGE = 'COMPOSE_SCHEDULED_AT_CHANGE' ;
2020-07-25 01:05:31 +01:00
export const COMPOSE _EXPIRES _AT _CHANGE = 'COMPOSE_EXPIRES_AT_CHANGE'
2020-03-31 17:04:50 +01:00
export const COMPOSE _RICH _TEXT _EDITOR _CONTROLS _VISIBILITY = 'COMPOSE_RICH_TEXT_EDITOR_CONTROLS_VISIBILITY'
2020-07-14 06:19:02 +01:00
export const COMPOSE _CLEAR = 'COMPOSE_CLEAR'
2019-07-02 08:10:25 +01:00
const messages = defineMessages ( {
uploadErrorLimit : { id : 'upload_error.limit' , defaultMessage : 'File upload limit exceeded.' } ,
uploadErrorPoll : { id : 'upload_error.poll' , defaultMessage : 'File upload not allowed with polls.' } ,
} ) ;
const COMPOSE _PANEL _BREAKPOINT = 600 + ( 285 * 1 ) + ( 10 * 1 ) ;
export const ensureComposeIsVisible = ( getState , routerHistory ) => {
if ( ! getState ( ) . getIn ( [ 'compose' , 'mounted' ] ) && window . innerWidth < COMPOSE _PANEL _BREAKPOINT ) {
routerHistory . push ( '/posts/new' ) ;
}
} ;
2020-06-06 02:43:08 +01:00
export function changeCompose ( text , markdown , replyId , isStandalone , caretPosition ) {
2020-05-07 00:40:54 +01:00
return function ( dispatch , getState ) {
const reduxReplyToId = getState ( ) . getIn ( [ 'compose' , 'in_reply_to' ] )
const existingText = getState ( ) . getIn ( [ 'compose' , 'text' ] ) . trim ( )
2020-05-15 04:36:10 +01:00
const isModalOpen = getState ( ) . getIn ( [ 'modal' , 'modalType' ] ) === 'COMPOSE' || isStandalone
2020-05-07 00:40:54 +01:00
let status
if ( ! ! replyId ) {
status = getState ( ) . getIn ( [ 'statuses' , replyId ] )
status = makeGetStatus ( ) ( getState ( ) , {
id : status . get ( 'id' )
} )
}
if ( ! ! replyId && replyId !== reduxReplyToId && ! isModalOpen ) {
if ( existingText . length === 0 && text . trim ( ) . length > 0 ) {
dispatch ( {
type : COMPOSE _REPLY ,
status : status ,
text : text ,
} )
} else if ( existingText . length > 0 && text . trim ( ) . length > 0 ) {
dispatch ( openModal ( 'CONFIRM' , {
message : < FormattedMessage id = 'confirmations.reply.message' defaultMessage = 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' / > ,
confirm : < FormattedMessage id = 'confirmations.reply.confirm' defaultMessage = 'Reply' / > ,
onConfirm : ( ) => {
dispatch ( {
type : COMPOSE _REPLY ,
status : status ,
} )
dispatch ( {
type : COMPOSE _CHANGE ,
text : text ,
markdown : markdown ,
2020-06-06 02:43:08 +01:00
caretPosition : caretPosition ,
2020-05-07 00:40:54 +01:00
} )
}
} ) )
} else {
dispatch ( {
type : COMPOSE _REPLY _CANCEL ,
} )
}
} else if ( ! replyId && ! ! reduxReplyToId && ! isModalOpen ) {
if ( existingText . length === 0 && text . trim ( ) . length > 0 ) {
dispatch ( {
type : COMPOSE _REPLY _CANCEL ,
} )
dispatch ( {
type : COMPOSE _CHANGE ,
text : text ,
markdown : markdown ,
2020-06-06 02:43:08 +01:00
caretPosition : caretPosition ,
2020-05-07 00:40:54 +01:00
} )
} else if ( existingText . length > 0 && text . trim ( ) . length > 0 ) {
dispatch ( openModal ( 'CONFIRM' , {
message : < FormattedMessage id = 'confirmations.new_compose.message' defaultMessage = 'Composing now will overwrite the reply you are currently writing. Are you sure you want to proceed?' / > ,
confirm : < FormattedMessage id = 'confirmations.new_compose.confirm' defaultMessage = 'Yes' / > ,
onConfirm : ( ) => {
dispatch ( {
type : COMPOSE _REPLY _CANCEL ,
} )
dispatch ( {
type : COMPOSE _CHANGE ,
text : text ,
markdown : markdown ,
2020-06-06 02:43:08 +01:00
caretPosition : caretPosition ,
2020-05-07 00:40:54 +01:00
} )
} ,
} ) )
} else {
//
}
} else {
dispatch ( {
type : COMPOSE _CHANGE ,
text : text ,
markdown : markdown ,
2020-06-06 02:43:08 +01:00
caretPosition : caretPosition ,
2020-05-07 00:40:54 +01:00
} )
}
}
}
2019-07-02 08:10:25 +01:00
2020-05-02 07:25:55 +01:00
export function replyCompose ( status , router , showModal ) {
2020-04-24 04:17:27 +01:00
return ( dispatch ) => {
2019-07-02 08:10:25 +01:00
dispatch ( {
type : COMPOSE _REPLY ,
status : status ,
} ) ;
2020-05-15 04:17:31 +01:00
if ( isMobile ( window . innerWidth ) ) {
router . history . push ( '/compose' )
} else {
if ( showModal ) {
dispatch ( openModal ( 'COMPOSE' ) ) ;
}
2020-05-02 07:25:55 +01:00
}
2019-07-02 08:10:25 +01:00
} ;
} ;
2020-05-15 04:17:31 +01:00
export function quoteCompose ( status , router ) {
2020-04-24 04:17:27 +01:00
return ( dispatch ) => {
2019-07-30 19:27:49 +01:00
dispatch ( {
type : COMPOSE _QUOTE ,
status : status ,
} ) ;
2020-05-15 04:17:31 +01:00
if ( isMobile ( window . innerWidth ) ) {
router . history . push ( '/compose' )
} else {
2020-05-15 06:34:01 +01:00
dispatch ( openModal ( 'COMPOSE' ) ) ;
2020-05-15 04:17:31 +01:00
}
2019-07-30 19:27:49 +01:00
} ;
} ;
2019-07-02 08:10:25 +01:00
export function cancelReplyCompose ( ) {
return {
type : COMPOSE _REPLY _CANCEL ,
} ;
} ;
export function resetCompose ( ) {
return {
type : COMPOSE _RESET ,
} ;
} ;
2020-04-24 04:17:27 +01:00
export function mentionCompose ( account ) {
return ( dispatch ) => {
2019-07-02 08:10:25 +01:00
dispatch ( {
type : COMPOSE _MENTION ,
account : account ,
} ) ;
dispatch ( openModal ( 'COMPOSE' ) ) ;
} ;
} ;
2019-08-28 06:24:06 +01:00
export function handleComposeSubmit ( dispatch , getState , response , status ) {
if ( ! dispatch || ! getState ) return ;
2020-04-08 02:06:59 +01:00
const isScheduledStatus = response . data . scheduled _at !== undefined ;
2019-09-19 01:15:01 +01:00
if ( isScheduledStatus ) {
2020-03-14 17:31:29 +00:00
// dispatch(showAlertForError({
// response: {
// data: {},
// status: 200,
// statusText: 'Successfully scheduled status',
// }
// }));
2019-09-19 01:15:01 +01:00
dispatch ( submitComposeSuccess ( { ... response . data } ) ) ;
return ;
}
2019-08-28 06:24:06 +01:00
dispatch ( insertIntoTagHistory ( response . data . tags , status ) ) ;
dispatch ( submitComposeSuccess ( { ... response . data } ) ) ;
2020-08-12 23:59:23 +01:00
// To make the app more responsive, immediately push the status into the timeline
// : todo : push into comment, reload parent status, etc.
2019-08-28 06:24:06 +01:00
const insertIfOnline = timelineId => {
const timeline = getState ( ) . getIn ( [ 'timelines' , timelineId ] ) ;
if ( timeline && timeline . get ( 'items' ) . size > 0 && timeline . getIn ( [ 'items' , 0 ] ) !== null && timeline . get ( 'online' ) ) {
2020-08-12 23:59:23 +01:00
dispatch ( updateTimelineQueue ( timelineId , response . data ) )
2019-08-28 06:24:06 +01:00
dispatch ( updateTimeline ( timelineId , { ... response . data } ) ) ;
}
} ;
2020-05-04 19:44:37 +01:00
if ( response . data . visibility === 'public' ) {
2019-08-28 06:24:06 +01:00
insertIfOnline ( 'home' ) ;
}
}
2020-07-15 04:31:54 +01:00
export function submitCompose ( groupId , replyToId = null , router , isStandalone , autoJoinGroup ) {
2019-07-02 08:10:25 +01:00
return function ( dispatch , getState ) {
if ( ! me ) return ;
2020-07-15 04:31:54 +01:00
if ( autoJoinGroup ) dispatch ( joinGroup ( groupId ) )
2020-03-31 17:04:50 +01:00
let status = getState ( ) . getIn ( [ 'compose' , 'text' ] , '' ) ;
2020-06-12 17:01:54 +01:00
let markdown = getState ( ) . getIn ( [ 'compose' , 'markdown' ] , '' ) ;
2020-06-20 02:02:13 +01:00
const media = getState ( ) . getIn ( [ 'compose' , 'media_attachments' ] ) ;
2019-07-02 08:10:25 +01:00
2020-06-20 02:02:13 +01:00
const replacer = ( match ) => {
2020-03-31 17:04:50 +01:00
const hasProtocol = match . startsWith ( 'https://' ) || match . startsWith ( 'http://' )
2020-05-05 06:16:01 +01:00
//Make sure not a remote mention like @someone@somewhere.com
if ( ! hasProtocol ) {
if ( status . indexOf ( ` @ ${ match } ` ) > - 1 ) return match
}
2020-03-31 17:04:50 +01:00
return hasProtocol ? match : ` http:// ${ match } `
2020-06-17 18:25:10 +01:00
}
2019-07-02 08:10:25 +01:00
2020-06-20 02:02:13 +01:00
// : hack :
//Prepend http:// to urls in status that don't have protocol
status = ` ${ status } ` . replace ( urlRegex , replacer )
markdown = ! ! markdown ? ` ${ markdown } ` . replace ( urlRegex , replacer ) : undefined
2020-04-23 07:13:29 +01:00
const inReplyToId = getState ( ) . getIn ( [ 'compose' , 'in_reply_to' ] , null ) || replyToId
2019-07-02 08:10:25 +01:00
dispatch ( submitComposeRequest ( ) ) ;
dispatch ( closeModal ( ) ) ;
2019-08-17 12:09:15 +01:00
const id = getState ( ) . getIn ( [ 'compose' , 'id' ] ) ;
const endpoint = id === null
? '/api/v1/statuses'
: ` /api/v1/statuses/ ${ id } ` ;
const method = id === null ? 'post' : 'put' ;
2020-05-15 21:57:21 +01:00
let scheduled _at = getState ( ) . getIn ( [ 'compose' , 'scheduled_at' ] , null ) ;
2020-05-02 07:25:55 +01:00
if ( scheduled _at !== null ) scheduled _at = moment . utc ( scheduled _at ) . toDate ( ) ;
2020-01-14 16:39:44 +00:00
2020-07-25 01:05:31 +01:00
let expires _at = getState ( ) . getIn ( [ 'compose' , 'expires_at' ] , null ) ;
if ( expires _at ) {
if ( expires _at === STATUS _EXPIRATION _OPTION _5 _MINUTES ) {
expires _at = moment . utc ( ) . add ( '5' , 'minute' ) . toDate ( )
} else if ( expires _at === STATUS _EXPIRATION _OPTION _60 _MINUTES ) {
expires _at = moment . utc ( ) . add ( '60' , 'minute' ) . toDate ( )
} else if ( expires _at === STATUS _EXPIRATION _OPTION _6 _HOURS ) {
expires _at = moment . utc ( ) . add ( '6' , 'hour' ) . toDate ( )
} else if ( expires _at === STATUS _EXPIRATION _OPTION _24 _HOURS ) {
expires _at = moment . utc ( ) . add ( '24' , 'hour' ) . toDate ( )
} else if ( expires _at === STATUS _EXPIRATION _OPTION _3 _DAYS ) {
expires _at = moment . utc ( ) . add ( '3' , 'day' ) . toDate ( )
} else if ( expires _at === STATUS _EXPIRATION _OPTION _7 _DAYS ) {
expires _at = moment . utc ( ) . add ( '7' , 'day' ) . toDate ( )
}
}
2020-05-15 04:46:10 +01:00
if ( isMobile ( window . innerWidth ) && router && isStandalone ) {
2020-05-15 04:17:31 +01:00
router . history . goBack ( )
}
2019-08-17 12:09:15 +01:00
api ( getState ) [ method ] ( endpoint , {
2019-07-02 08:10:25 +01:00
status ,
2020-04-22 06:00:11 +01:00
markdown ,
2020-07-25 01:05:31 +01:00
expires _at ,
2020-01-14 16:39:44 +00:00
scheduled _at ,
2020-07-15 04:31:54 +01:00
autoJoinGroup ,
2020-04-23 07:13:29 +01:00
in _reply _to _id : inReplyToId ,
2019-07-30 19:27:49 +01:00
quote _of _id : getState ( ) . getIn ( [ 'compose' , 'quote_of_id' ] , null ) ,
2019-07-02 08:10:25 +01:00
media _ids : media . map ( item => item . get ( 'id' ) ) ,
sensitive : getState ( ) . getIn ( [ 'compose' , 'sensitive' ] ) ,
spoiler _text : getState ( ) . getIn ( [ 'compose' , 'spoiler_text' ] , '' ) ,
visibility : getState ( ) . getIn ( [ 'compose' , 'privacy' ] ) ,
poll : getState ( ) . getIn ( [ 'compose' , 'poll' ] , null ) ,
2020-07-14 06:26:46 +01:00
group _id : groupId || null ,
2019-07-02 08:10:25 +01:00
} , {
headers : {
'Idempotency-Key' : getState ( ) . getIn ( [ 'compose' , 'idempotencyKey' ] ) ,
} ,
} ) . then ( function ( response ) {
2019-08-28 06:24:06 +01:00
handleComposeSubmit ( dispatch , getState , response , status ) ;
2019-07-02 08:10:25 +01:00
} ) . catch ( function ( error ) {
dispatch ( submitComposeFail ( error ) ) ;
} ) ;
} ;
} ;
export function submitComposeRequest ( ) {
return {
type : COMPOSE _SUBMIT _REQUEST ,
} ;
} ;
export function submitComposeSuccess ( status ) {
return {
type : COMPOSE _SUBMIT _SUCCESS ,
status : status ,
} ;
} ;
2020-07-14 06:19:02 +01:00
export function clearCompose ( ) {
return {
type : COMPOSE _CLEAR ,
} ;
} ;
2019-07-02 08:10:25 +01:00
export function submitComposeFail ( error ) {
return {
type : COMPOSE _SUBMIT _FAIL ,
error : error ,
2020-05-01 06:50:27 +01:00
}
}
2019-07-02 08:10:25 +01:00
export function uploadCompose ( files ) {
return function ( dispatch , getState ) {
2020-05-01 06:50:27 +01:00
if ( ! me ) return
2019-07-02 08:10:25 +01:00
2020-05-01 06:50:27 +01:00
const uploadLimit = 4
const media = getState ( ) . getIn ( [ 'compose' , 'media_attachments' ] )
const pending = getState ( ) . getIn ( [ 'compose' , 'pending_media_attachments' ] )
2019-07-02 08:10:25 +01:00
const progress = new Array ( files . length ) . fill ( 0 ) ;
let total = Array . from ( files ) . reduce ( ( a , v ) => a + v . size , 0 ) ;
2020-05-01 06:50:27 +01:00
if ( files . length + media . size + pending > uploadLimit ) {
2020-03-14 17:31:29 +00:00
// dispatch(showAlert(undefined, messages.uploadErrorLimit));
2019-07-02 08:10:25 +01:00
return ;
}
if ( getState ( ) . getIn ( [ 'compose' , 'poll' ] ) ) {
2020-03-14 17:31:29 +00:00
// dispatch(showAlert(undefined, messages.uploadErrorPoll));
2019-07-02 08:10:25 +01:00
return ;
}
dispatch ( uploadComposeRequest ( ) ) ;
for ( const [ i , f ] of Array . from ( files ) . entries ( ) ) {
if ( media . size + i > 3 ) break ;
2020-05-01 06:50:27 +01:00
resizeImage ( f ) . then ( ( file ) => {
2019-07-02 08:10:25 +01:00
const data = new FormData ( ) ;
data . append ( 'file' , file ) ;
// Account for disparity in size of original image and resized data
total += file . size - f . size ;
return api ( getState ) . post ( '/api/v1/media' , data , {
onUploadProgress : function ( { loaded } ) {
progress [ i ] = loaded ;
dispatch ( uploadComposeProgress ( progress . reduce ( ( a , v ) => a + v , 0 ) , total ) ) ;
} ,
} ) . then ( ( { data } ) => dispatch ( uploadComposeSuccess ( data ) ) ) ;
2020-05-01 06:50:27 +01:00
} ) . catch ( error => dispatch ( uploadComposeFail ( error , true ) ) ) ;
2019-07-02 08:10:25 +01:00
} ;
} ;
} ;
export function changeUploadCompose ( id , params ) {
return ( dispatch , getState ) => {
if ( ! me ) return ;
dispatch ( changeUploadComposeRequest ( ) ) ;
api ( getState ) . put ( ` /api/v1/media/ ${ id } ` , params ) . then ( response => {
dispatch ( changeUploadComposeSuccess ( response . data ) ) ;
} ) . catch ( error => {
dispatch ( changeUploadComposeFail ( id , error ) ) ;
} ) ;
} ;
} ;
export function changeUploadComposeRequest ( ) {
return {
type : COMPOSE _UPLOAD _CHANGE _REQUEST ,
skipLoading : true ,
} ;
} ;
export function changeUploadComposeSuccess ( media ) {
return {
type : COMPOSE _UPLOAD _CHANGE _SUCCESS ,
media : media ,
skipLoading : true ,
} ;
} ;
2020-05-01 06:50:27 +01:00
export function changeUploadComposeFail ( error , decrement = false ) {
2019-07-02 08:10:25 +01:00
return {
type : COMPOSE _UPLOAD _CHANGE _FAIL ,
error : error ,
2020-05-01 06:50:27 +01:00
decrement : decrement ,
2019-07-02 08:10:25 +01:00
skipLoading : true ,
} ;
} ;
export function uploadComposeRequest ( ) {
return {
type : COMPOSE _UPLOAD _REQUEST ,
skipLoading : true ,
} ;
} ;
export function uploadComposeProgress ( loaded , total ) {
return {
type : COMPOSE _UPLOAD _PROGRESS ,
loaded : loaded ,
total : total ,
} ;
} ;
export function uploadComposeSuccess ( media ) {
return {
type : COMPOSE _UPLOAD _SUCCESS ,
media : media ,
skipLoading : true ,
} ;
} ;
export function uploadComposeFail ( error ) {
return {
type : COMPOSE _UPLOAD _FAIL ,
error : error ,
skipLoading : true ,
} ;
} ;
export function undoUploadCompose ( media _id ) {
return {
type : COMPOSE _UPLOAD _UNDO ,
media _id : media _id ,
} ;
} ;
export function clearComposeSuggestions ( ) {
if ( cancelFetchComposeSuggestionsAccounts ) {
cancelFetchComposeSuggestionsAccounts ( ) ;
}
return {
type : COMPOSE _SUGGESTIONS _CLEAR ,
} ;
} ;
const fetchComposeSuggestionsAccounts = throttle ( ( dispatch , getState , token ) => {
if ( cancelFetchComposeSuggestionsAccounts ) {
cancelFetchComposeSuggestionsAccounts ( ) ;
}
api ( getState ) . get ( '/api/v1/accounts/search' , {
cancelToken : new CancelToken ( cancel => {
cancelFetchComposeSuggestionsAccounts = cancel ;
} ) ,
params : {
q : token . slice ( 1 ) ,
resolve : false ,
limit : 4 ,
} ,
} ) . then ( response => {
dispatch ( importFetchedAccounts ( response . data ) ) ;
dispatch ( readyComposeSuggestionsAccounts ( token , response . data ) ) ;
} ) . catch ( error => {
if ( ! isCancel ( error ) ) {
2020-03-14 17:31:29 +00:00
// dispatch(showAlertForError(error));
2019-07-02 08:10:25 +01:00
}
} ) ;
} , 200 , { leading : true , trailing : true } ) ;
const fetchComposeSuggestionsEmojis = ( dispatch , getState , token ) => {
const results = emojiSearch ( token . replace ( ':' , '' ) , { maxResults : 5 } ) ;
dispatch ( readyComposeSuggestionsEmojis ( token , results ) ) ;
} ;
const fetchComposeSuggestionsTags = ( dispatch , getState , token ) => {
dispatch ( updateSuggestionTags ( token ) ) ;
} ;
export function fetchComposeSuggestions ( token ) {
return ( dispatch , getState ) => {
switch ( token [ 0 ] ) {
case ':' :
fetchComposeSuggestionsEmojis ( dispatch , getState , token ) ;
break ;
case '#' :
fetchComposeSuggestionsTags ( dispatch , getState , token ) ;
break ;
default :
fetchComposeSuggestionsAccounts ( dispatch , getState , token ) ;
break ;
}
} ;
} ;
export function readyComposeSuggestionsEmojis ( token , emojis ) {
return {
type : COMPOSE _SUGGESTIONS _READY ,
token ,
emojis ,
} ;
} ;
export function readyComposeSuggestionsAccounts ( token , accounts ) {
return {
type : COMPOSE _SUGGESTIONS _READY ,
token ,
accounts ,
} ;
} ;
export function selectComposeSuggestion ( position , token , suggestion , path ) {
return ( dispatch , getState ) => {
let completion , startPosition ;
if ( typeof suggestion === 'object' && suggestion . id ) {
completion = suggestion . native || suggestion . colons ;
startPosition = position - 1 ;
dispatch ( useEmoji ( suggestion ) ) ;
} else if ( suggestion [ 0 ] === '#' ) {
completion = suggestion ;
startPosition = position - 1 ;
} else {
completion = getState ( ) . getIn ( [ 'accounts' , suggestion , 'acct' ] ) ;
startPosition = position ;
}
dispatch ( {
type : COMPOSE _SUGGESTION _SELECT ,
position : startPosition ,
token ,
completion ,
path ,
} ) ;
} ;
} ;
export function updateSuggestionTags ( token ) {
return {
type : COMPOSE _SUGGESTION _TAGS _UPDATE ,
token ,
} ;
}
export function updateTagHistory ( tags ) {
return {
type : COMPOSE _TAG _HISTORY _UPDATE ,
tags ,
} ;
}
export function hydrateCompose ( ) {
return ( dispatch , getState ) => {
const me = getState ( ) . getIn ( [ 'meta' , 'me' ] ) ;
const history = tagHistory . get ( me ) ;
if ( history !== null ) {
dispatch ( updateTagHistory ( history ) ) ;
}
} ;
}
function insertIntoTagHistory ( recognizedTags , text ) {
return ( dispatch , getState ) => {
const state = getState ( ) ;
const oldHistory = state . getIn ( [ 'compose' , 'tagHistory' ] ) ;
const me = state . getIn ( [ 'meta' , 'me' ] ) ;
const names = recognizedTags . map ( tag => text . match ( new RegExp ( ` # ${ tag . name } ` , 'i' ) ) [ 0 ] . slice ( 1 ) ) ;
const intersectedOldHistory = oldHistory . filter ( name => names . findIndex ( newName => newName . toLowerCase ( ) === name . toLowerCase ( ) ) === - 1 ) ;
names . push ( ... intersectedOldHistory . toJS ( ) ) ;
const newHistory = names . slice ( 0 , 1000 ) ;
tagHistory . set ( me , newHistory ) ;
dispatch ( updateTagHistory ( newHistory ) ) ;
} ;
}
export function mountCompose ( ) {
return {
type : COMPOSE _MOUNT ,
} ;
} ;
export function unmountCompose ( ) {
return {
type : COMPOSE _UNMOUNT ,
} ;
} ;
export function changeComposeSensitivity ( ) {
return {
type : COMPOSE _SENSITIVITY _CHANGE ,
} ;
} ;
export function changeComposeSpoilerness ( ) {
return {
type : COMPOSE _SPOILERNESS _CHANGE ,
} ;
} ;
export function changeComposeSpoilerText ( text ) {
return {
type : COMPOSE _SPOILER _TEXT _CHANGE ,
text ,
} ;
} ;
export function changeComposeVisibility ( value ) {
return {
type : COMPOSE _VISIBILITY _CHANGE ,
value ,
} ;
} ;
2020-06-06 02:43:08 +01:00
export function insertEmojiCompose ( emoji , needsSpace ) {
2019-07-02 08:10:25 +01:00
return {
type : COMPOSE _EMOJI _INSERT ,
emoji ,
needsSpace ,
} ;
} ;
export function changeComposing ( value ) {
return {
type : COMPOSE _COMPOSING _CHANGE ,
value ,
} ;
} ;
export function addPoll ( ) {
return {
type : COMPOSE _POLL _ADD ,
} ;
} ;
export function removePoll ( ) {
return {
type : COMPOSE _POLL _REMOVE ,
} ;
} ;
export function addPollOption ( title ) {
return {
type : COMPOSE _POLL _OPTION _ADD ,
title ,
} ;
} ;
export function changePollOption ( index , title ) {
return {
type : COMPOSE _POLL _OPTION _CHANGE ,
index ,
title ,
} ;
} ;
export function removePollOption ( index ) {
return {
type : COMPOSE _POLL _OPTION _REMOVE ,
index ,
} ;
} ;
export function changePollSettings ( expiresIn , isMultiple ) {
return {
type : COMPOSE _POLL _SETTINGS _CHANGE ,
expiresIn ,
isMultiple ,
} ;
} ;
2019-09-19 01:15:01 +01:00
export function changeScheduledAt ( date ) {
return {
type : COMPOSE _SCHEDULED _AT _CHANGE ,
date ,
} ;
2020-03-31 17:04:50 +01:00
} ;
2020-07-25 01:05:31 +01:00
export function changeExpiresAt ( value ) {
return {
type : COMPOSE _EXPIRES _AT _CHANGE ,
value ,
}
}
2020-06-17 18:25:10 +01:00
export function changeRichTextEditorControlsVisibility ( open ) {
2020-03-31 17:04:50 +01:00
return {
type : COMPOSE _RICH _TEXT _EDITOR _CONTROLS _VISIBILITY ,
2020-06-17 18:25:10 +01:00
open ,
2020-03-31 17:04:50 +01:00
}
}