2020-11-15 18:48:32 +00:00
import api from '../api'
2020-05-07 00:40:54 +01:00
import { FormattedMessage } from 'react-intl'
2020-11-15 18:48:32 +00: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'
2020-11-15 18:48:32 +00: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'
2020-11-15 18:48:32 +00:00
import { tagHistory } from '../settings'
2020-07-15 04:31:54 +01:00
import { joinGroup } from './groups'
2020-11-15 18:48:32 +00:00
import { useEmoji } from './emojis'
import resizeImage from '../utils/resize_image'
import { importFetchedAccounts } from './importer'
2020-09-24 21:41:59 +01:00
import {
updateTimelineQueue ,
updateTimeline ,
} from './timelines'
2020-11-15 18:48:32 +00:00
// import { showAlert, showAlertForError } from './alerts'
import { defineMessages } from 'react-intl'
import { openModal , closeModal } from './modal'
2020-07-25 01:05:31 +01:00
import {
2020-11-25 21:22:37 +00:00
MODAL _COMPOSE ,
2020-12-16 00:31:30 +00:00
EXPIRATION _OPTION _5 _MINUTES ,
2020-12-19 06:33:33 +00:00
EXPIRATION _OPTION _1 _HOUR ,
2020-12-16 00:31:30 +00:00
EXPIRATION _OPTION _6 _HOURS ,
2020-12-19 06:33:33 +00:00
EXPIRATION _OPTION _1 _DAY ,
2020-12-16 00:31:30 +00:00
EXPIRATION _OPTION _3 _DAYS ,
EXPIRATION _OPTION _7 _DAYS ,
2020-07-25 01:05:31 +01:00
} from '../constants'
2020-11-15 18:48:32 +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
2020-11-15 18:48:32 +00: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'
export const COMPOSE _QUOTE = 'COMPOSE_QUOTE'
export const COMPOSE _REPLY _CANCEL = 'COMPOSE_REPLY_CANCEL'
export const COMPOSE _MENTION = 'COMPOSE_MENTION'
export const COMPOSE _RESET = 'COMPOSE_RESET'
2020-12-16 22:29:06 +00:00
export const COMPOSE _GROUP _SET = 'COMPOSE_GROUP_SET'
2020-11-15 18:48:32 +00:00
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'
2020-11-25 21:22:37 +00:00
export const COMPOSE _SENSITIVITY _CHANGE = 'COMPOSE_SENSITIVITY_CHANGE'
export const COMPOSE _SPOILERNESS _CHANGE = 'COMPOSE_SPOILERNESS_CHANGE'
2020-11-15 18:48:32 +00:00
export const COMPOSE _SPOILER _TEXT _CHANGE = 'COMPOSE_SPOILER_TEXT_CHANGE'
2020-11-25 21:22:37 +00:00
export const COMPOSE _VISIBILITY _CHANGE = 'COMPOSE_VISIBILITY_CHANGE'
export const COMPOSE _LISTABILITY _CHANGE = 'COMPOSE_LISTABILITY_CHANGE'
export const COMPOSE _COMPOSING _CHANGE = 'COMPOSE_COMPOSING_CHANGE'
2020-11-15 18:48:32 +00:00
export const COMPOSE _EMOJI _INSERT = 'COMPOSE_EMOJI_INSERT'
2020-11-25 21:22:37 +00:00
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'
2020-11-15 18:48:32 +00:00
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'
export const COMPOSE _SCHEDULED _AT _CHANGE = 'COMPOSE_SCHEDULED_AT_CHANGE'
2019-09-19 01:15:01 +01:00
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.' } ,
2020-11-15 18:48:32 +00:00
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const hydrateCompose = ( ) => ( dispatch , getState ) => {
const me = getState ( ) . getIn ( [ 'meta' , 'me' ] )
const history = tagHistory . get ( me )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
if ( history !== null ) {
dispatch ( updateTagHistory ( history ) )
2019-07-02 08:10:25 +01:00
}
2020-11-15 18:48:32 +00:00
}
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
const insertIntoTagHistory = ( recognizedTags , text ) => ( 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 const changeCompose = ( text , markdown , replyId , isStandalone , caretPosition ) => ( dispatch , getState ) => {
const reduxReplyToId = getState ( ) . getIn ( [ 'compose' , 'in_reply_to' ] )
const existingText = getState ( ) . getIn ( [ 'compose' , 'text' ] ) . trim ( )
const isModalOpen = getState ( ) . getIn ( [ 'modal' , 'modalType' ] ) === MODAL _COMPOSE || isStandalone
let status
if ( ! ! replyId ) {
status = getState ( ) . getIn ( [ 'statuses' , replyId ] )
status = makeGetStatus ( ) ( getState ( ) , {
id : status . get ( 'id' )
} )
}
2020-05-07 00:40:54 +01:00
2020-11-25 21:22:37 +00:00
if ( ! ! replyId && replyId !== reduxReplyToId && ! isModalOpen ) {
if ( existingText . length === 0 && text . trim ( ) . length > 0 ) {
dispatch ( {
type : COMPOSE _REPLY ,
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 ,
} )
dispatch ( {
type : COMPOSE _CHANGE ,
text : text ,
markdown : markdown ,
caretPosition : caretPosition ,
} )
}
} ) )
2020-05-07 00:40:54 +01:00
} else {
2020-11-25 21:22:37 +00:00
dispatch ( {
type : COMPOSE _REPLY _CANCEL ,
} )
}
} else if ( ! replyId && ! ! reduxReplyToId && ! isModalOpen ) {
if ( existingText . length === 0 && text . trim ( ) . length > 0 ) {
dispatch ( {
type : COMPOSE _REPLY _CANCEL ,
} )
2020-05-07 00:40:54 +01:00
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
} )
2020-11-25 21:22:37 +00: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 ,
caretPosition : caretPosition ,
} )
} ,
} ) )
} else {
//
2020-05-07 00:40:54 +01:00
}
2020-11-25 21:22:37 +00:00
} else {
dispatch ( {
type : COMPOSE _CHANGE ,
text : text ,
markdown : markdown ,
caretPosition : caretPosition ,
} )
2020-05-07 00:40:54 +01:00
}
}
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const replyCompose = ( status , router , showModal ) => ( dispatch ) => {
dispatch ( {
type : COMPOSE _REPLY ,
status ,
} )
if ( isMobile ( window . innerWidth ) ) {
router . history . push ( '/compose' )
} else {
if ( showModal ) {
dispatch ( openModal ( MODAL _COMPOSE ) )
2020-05-02 07:25:55 +01:00
}
2020-11-25 21:22:37 +00:00
}
}
2019-07-30 19:27:49 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const quoteCompose = ( status , router ) => ( dispatch ) => {
dispatch ( {
type : COMPOSE _QUOTE ,
status ,
} )
if ( isMobile ( window . innerWidth ) ) {
router . history . push ( '/compose' )
} else {
dispatch ( openModal ( MODAL _COMPOSE ) )
}
}
2019-07-30 19:27:49 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const cancelReplyCompose = ( ) => ( {
type : COMPOSE _REPLY _CANCEL ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const resetCompose = ( ) => ( {
type : COMPOSE _RESET ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const mentionCompose = ( account ) => ( dispatch ) => {
dispatch ( {
type : COMPOSE _MENTION ,
account : account ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
dispatch ( openModal ( MODAL _COMPOSE ) )
}
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const handleComposeSubmit = ( dispatch , getState , response , status ) => {
if ( ! dispatch || ! getState ) return
2019-08-28 06:24:06 +01:00
2020-11-25 21:22:37 +00: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',
// }
2020-11-25 21:22:37 +00:00
// }))
dispatch ( submitComposeSuccess ( { ... response . data } ) )
return
2019-09-19 01:15:01 +01:00
}
2020-11-25 21:22:37 +00:00
dispatch ( insertIntoTagHistory ( response . data . tags , status ) )
dispatch ( submitComposeSuccess ( { ... response . data } ) )
2019-08-28 06:24:06 +01:00
2021-01-01 02:46:31 +00:00
// If is group, reset composer to be in group
if ( response . data . group ) {
dispatch ( changeComposeGroupId ( response . data . group . id ) )
}
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.
2020-11-25 21:22:37 +00:00
const insertIfOnline = ( timelineId ) => {
const timeline = getState ( ) . getIn ( [ 'timelines' , timelineId ] )
2019-08-28 06:24:06 +01:00
if ( timeline && timeline . get ( 'items' ) . size > 0 && timeline . getIn ( [ 'items' , 0 ] ) !== null && timeline . get ( 'online' ) ) {
2020-11-25 21:22:37 +00:00
dispatch ( updateTimeline ( timelineId , { ... response . data } ) )
2019-08-28 06:24:06 +01:00
}
2020-11-25 21:22:37 +00:00
}
2019-08-28 06:24:06 +01:00
2020-05-04 19:44:37 +01:00
if ( response . data . visibility === 'public' ) {
2020-11-25 21:22:37 +00:00
insertIfOnline ( 'home' )
2019-08-28 06:24:06 +01:00
}
}
2020-11-25 21:22:37 +00:00
/ * *
*
* /
2020-12-21 01:37:53 +00:00
export const submitCompose = ( options = { } ) => ( dispatch , getState ) => {
2020-11-25 21:22:37 +00:00
if ( ! me ) return
2019-07-02 08:10:25 +01:00
2020-12-21 01:37:53 +00:00
if ( options . autoJoinGroup ) dispatch ( joinGroup ( groupId ) )
2020-07-15 04:31:54 +01:00
2020-11-25 21:22:37 +00:00
let status = getState ( ) . getIn ( [ 'compose' , 'text' ] , '' )
let markdown = getState ( ) . getIn ( [ 'compose' , 'markdown' ] , '' )
2020-12-21 01:37:53 +00:00
2020-11-25 21:22:37 +00:00
const replacer = ( match ) => {
const hasProtocol = match . startsWith ( 'https://' ) || match . startsWith ( 'http://' )
//Make sure not a remote mention like @someone@somewhere.com
if ( ! hasProtocol ) {
if ( status . indexOf ( ` @ ${ match } ` ) > - 1 ) return match
2020-06-17 18:25:10 +01:00
}
2020-11-25 21:22:37 +00:00
return hasProtocol ? match : ` http:// ${ match } `
}
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00: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-12-21 01:37:53 +00:00
const inReplyToId = getState ( ) . getIn ( [ 'compose' , 'in_reply_to' ] , null )
const groupId = getState ( ) . getIn ( [ 'compose' , 'group_id' ] , null )
const media = getState ( ) . getIn ( [ 'compose' , 'media_attachments' ] )
const isPrivateGroup = ! ! groupId ? getState ( ) . getIn ( [ 'groups' , groupId , 'is_private' ] , false ) : false
const expires _at = getState ( ) . getIn ( [ 'compose' , 'expires_at' ] , null )
2020-11-25 21:22:37 +00:00
2020-12-21 01:37:53 +00:00
let scheduled _at = getState ( ) . getIn ( [ 'compose' , 'scheduled_at' ] , null )
if ( scheduled _at !== null ) scheduled _at = moment . utc ( scheduled _at ) . toDate ( )
//
2020-11-25 21:22:37 +00:00
const id = getState ( ) . getIn ( [ 'compose' , 'id' ] )
2020-12-21 01:37:53 +00:00
const endpoint = id === null ? '/api/v1/statuses' : ` /api/v1/statuses/ ${ id } `
2020-11-25 21:22:37 +00:00
const method = id === null ? 'post' : 'put'
2020-12-21 01:37:53 +00:00
dispatch ( submitComposeRequest ( ) )
dispatch ( closeModal ( ) )
2020-07-25 01:05:31 +01:00
2020-12-21 01:37:53 +00:00
if ( isMobile ( window . innerWidth ) && options . router && options . isStandalone ) {
options . router . history . goBack ( )
2020-11-25 21:22:37 +00:00
}
2020-05-15 04:17:31 +01:00
2020-11-25 21:22:37 +00:00
api ( getState ) [ method ] ( endpoint , {
status ,
markdown ,
expires _at ,
scheduled _at ,
2020-12-21 01:37:53 +00:00
autoJoinGroup : options . autoJoinGroup ,
2020-11-25 21:22:37 +00:00
isPrivateGroup ,
in _reply _to _id : inReplyToId ,
quote _of _id : getState ( ) . getIn ( [ 'compose' , 'quote_of_id' ] , null ) ,
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 ) ,
group _id : groupId || null ,
} , {
headers : {
'Idempotency-Key' : getState ( ) . getIn ( [ 'compose' , 'idempotencyKey' ] ) ,
} ,
} ) . then ( ( response ) => {
handleComposeSubmit ( dispatch , getState , response , status )
} ) . catch ( ( error ) => {
dispatch ( submitComposeFail ( error ) )
} )
}
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
const submitComposeRequest = ( ) => ( {
type : COMPOSE _SUBMIT _REQUEST ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
const submitComposeSuccess = ( status ) => ( {
type : COMPOSE _SUBMIT _SUCCESS ,
2020-12-08 04:39:13 +00:00
showToast : true ,
2020-11-25 21:22:37 +00:00
status ,
} )
2020-07-14 06:19:02 +01:00
2020-11-25 21:22:37 +00:00
const submitComposeFail = ( error ) => ( {
type : COMPOSE _SUBMIT _FAIL ,
2020-12-08 04:39:13 +00:00
showToast : true ,
2020-11-25 21:22:37 +00:00
error ,
} )
/ * *
*
* /
export const uploadCompose = ( files ) => ( dispatch , getState ) => {
if ( ! me ) return
const uploadLimit = 4
const media = getState ( ) . getIn ( [ 'compose' , 'media_attachments' ] )
const pending = getState ( ) . getIn ( [ 'compose' , 'pending_media_attachments' ] )
const progress = new Array ( files . length ) . fill ( 0 )
let total = Array . from ( files ) . reduce ( ( a , v ) => a + v . size , 0 )
if ( files . length + media . size + pending > uploadLimit ) {
// dispatch(showAlert(undefined, messages.uploadErrorLimit))
return
}
if ( getState ( ) . getIn ( [ 'compose' , 'poll' ] ) ) {
// dispatch(showAlert(undefined, messages.uploadErrorPoll))
return
}
dispatch ( uploadComposeRequest ( ) )
for ( const [ i , f ] of Array . from ( files ) . entries ( ) ) {
if ( media . size + i > 3 ) break
resizeImage ( f ) . then ( ( file ) => {
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 : ( { loaded } ) => {
progress [ i ] = loaded
dispatch ( uploadComposeProgress ( progress . reduce ( ( a , v ) => a + v , 0 ) , total ) )
} ,
} ) . then ( ( { data } ) => dispatch ( uploadComposeSuccess ( data ) ) )
} ) . catch ( ( error ) => dispatch ( uploadComposeFail ( error , true ) ) )
2020-05-01 06:50:27 +01:00
}
}
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
const uploadComposeRequest = ( ) => ( {
type : COMPOSE _UPLOAD _REQUEST ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
const uploadComposeProgress = ( loaded , total ) => ( {
type : COMPOSE _UPLOAD _PROGRESS ,
loaded : loaded ,
total : total ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
const uploadComposeSuccess = ( media ) => ( {
type : COMPOSE _UPLOAD _SUCCESS ,
media : media ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
const uploadComposeFail = ( error ) => ( {
type : COMPOSE _UPLOAD _FAIL ,
2020-12-08 04:39:13 +00:00
showToast : true ,
2020-11-25 21:22:37 +00:00
error ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const changeUploadCompose = ( id , params ) => ( dispatch , getState ) => {
if ( ! me ) return
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
dispatch ( changeUploadComposeRequest ( ) )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
api ( getState ) . put ( ` /api/v1/media/ ${ id } ` , params ) . then ( ( response ) => {
dispatch ( changeUploadComposeSuccess ( response . data ) )
} ) . catch ( ( error ) => {
dispatch ( changeUploadComposeFail ( id , error ) )
} )
}
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
const changeUploadComposeRequest = ( ) => ( {
type : COMPOSE _UPLOAD _CHANGE _REQUEST ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
const changeUploadComposeSuccess = ( media ) => ( {
type : COMPOSE _UPLOAD _CHANGE _SUCCESS ,
media : media ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
const changeUploadComposeFail = ( error , decrement = false ) => ( {
type : COMPOSE _UPLOAD _CHANGE _FAIL ,
error ,
2020-12-08 04:39:13 +00:00
showToast : true ,
2020-11-25 21:22:37 +00:00
decrement : decrement ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const undoUploadCompose = ( media _id ) => ( {
type : COMPOSE _UPLOAD _UNDO ,
media _id : media _id ,
} )
/ * *
*
* /
export const clearComposeSuggestions = ( ) => {
2019-07-02 08:10:25 +01:00
if ( cancelFetchComposeSuggestionsAccounts ) {
2020-11-25 21:22:37 +00:00
cancelFetchComposeSuggestionsAccounts ( )
2019-07-02 08:10:25 +01:00
}
2020-11-25 21:22:37 +00:00
2019-07-02 08:10:25 +01:00
return {
type : COMPOSE _SUGGESTIONS _CLEAR ,
2020-11-25 21:22:37 +00:00
}
}
/ * *
*
* /
export const fetchComposeSuggestions = ( token ) => ( dispatch , getState ) => {
switch ( token [ 0 ] ) {
case ':' :
fetchComposeSuggestionsEmojis ( dispatch , getState , token )
break
case '#' :
fetchComposeSuggestionsTags ( dispatch , getState , token )
break
default :
fetchComposeSuggestionsAccounts ( dispatch , getState , token )
break
}
}
2019-07-02 08:10:25 +01:00
const fetchComposeSuggestionsAccounts = throttle ( ( dispatch , getState , token ) => {
if ( cancelFetchComposeSuggestionsAccounts ) {
2020-11-25 21:22:37 +00:00
cancelFetchComposeSuggestionsAccounts ( )
2019-07-02 08:10:25 +01:00
}
2020-11-25 21:22:37 +00:00
2019-07-02 08:10:25 +01:00
api ( getState ) . get ( '/api/v1/accounts/search' , {
cancelToken : new CancelToken ( cancel => {
2020-11-25 21:22:37 +00:00
cancelFetchComposeSuggestionsAccounts = cancel
2019-07-02 08:10:25 +01:00
} ) ,
params : {
q : token . slice ( 1 ) ,
resolve : false ,
limit : 4 ,
} ,
2020-11-25 21:22:37 +00:00
} ) . then ( ( response ) => {
dispatch ( importFetchedAccounts ( response . data ) )
dispatch ( readyComposeSuggestionsAccounts ( token , response . data ) )
} ) . catch ( ( error ) => {
2019-07-02 08:10:25 +01:00
if ( ! isCancel ( error ) ) {
2020-11-25 21:22:37 +00:00
// dispatch(showAlertForError(error))
2019-07-02 08:10:25 +01:00
}
2020-11-25 21:22:37 +00:00
} )
2021-02-10 18:29:48 +00:00
} , 1000 , { leading : true , trailing : true } )
2019-07-02 08:10:25 +01:00
const fetchComposeSuggestionsEmojis = ( dispatch , getState , token ) => {
2020-11-25 21:22:37 +00:00
const results = emojiSearch ( token . replace ( ':' , '' ) , { maxResults : 5 } )
dispatch ( readyComposeSuggestionsEmojis ( token , results ) )
}
2019-07-02 08:10:25 +01:00
const fetchComposeSuggestionsTags = ( dispatch , getState , token ) => {
2020-11-25 21:22:37 +00:00
dispatch ( updateSuggestionTags ( token ) )
}
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
const readyComposeSuggestionsEmojis = ( token , emojis ) => ( {
type : COMPOSE _SUGGESTIONS _READY ,
token ,
emojis ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
const readyComposeSuggestionsAccounts = ( token , accounts ) => ( {
2020-11-15 18:48:32 +00:00
type : COMPOSE _SUGGESTIONS _READY ,
token ,
accounts ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const selectComposeSuggestion = ( position , token , suggestion , path ) => ( 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
}
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
dispatch ( {
type : COMPOSE _SUGGESTION _SELECT ,
position : startPosition ,
2019-07-02 08:10:25 +01:00
token ,
2020-11-25 21:22:37 +00:00
completion ,
path ,
} )
2019-07-02 08:10:25 +01:00
}
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const updateSuggestionTags = ( token ) => ( {
type : COMPOSE _SUGGESTION _TAGS _UPDATE ,
token ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const updateTagHistory = ( tags ) => ( {
type : COMPOSE _TAG _HISTORY _UPDATE ,
tags ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const mountCompose = ( ) => ( {
type : COMPOSE _MOUNT ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const unmountCompose = ( ) => ( {
type : COMPOSE _UNMOUNT ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const clearCompose = ( ) => ( {
type : COMPOSE _CLEAR ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const changeComposeSensitivity = ( ) => ( {
type : COMPOSE _SENSITIVITY _CHANGE ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const changeComposeSpoilerness = ( ) => ( {
type : COMPOSE _SPOILERNESS _CHANGE ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const changeComposeSpoilerText = ( text ) => ( {
type : COMPOSE _SPOILER _TEXT _CHANGE ,
text ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const changeComposeVisibility = ( value ) => ( {
type : COMPOSE _VISIBILITY _CHANGE ,
value ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
2020-12-31 23:48:35 +00:00
export const insertEmojiCompose = ( emoji ) => ( {
2020-11-25 21:22:37 +00:00
type : COMPOSE _EMOJI _INSERT ,
emoji ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const changeComposing = ( value ) => ( {
type : COMPOSE _COMPOSING _CHANGE ,
value ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const addPoll = ( ) => ( {
type : COMPOSE _POLL _ADD ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const removePoll = ( ) => ( {
type : COMPOSE _POLL _REMOVE ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const addPollOption = ( title ) => ( {
type : COMPOSE _POLL _OPTION _ADD ,
title ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const changePollOption = ( index , title ) => ( {
type : COMPOSE _POLL _OPTION _CHANGE ,
index ,
title ,
} )
2019-07-02 08:10:25 +01:00
2020-11-25 21:22:37 +00:00
/ * *
*
* /
export const removePollOption = ( index ) => ( {
type : COMPOSE _POLL _OPTION _REMOVE ,
index ,
} )
2019-07-02 08:10:25 +01:00
2020-11-15 18:48:32 +00:00
/ * *
*
* /
export const changePollSettings = ( expiresIn , isMultiple ) => ( {
type : COMPOSE _POLL _SETTINGS _CHANGE ,
expiresIn ,
isMultiple ,
} )
/ * *
*
* /
export const changeScheduledAt = ( date ) => ( {
type : COMPOSE _SCHEDULED _AT _CHANGE ,
date ,
} )
/ * *
*
* /
export const changeExpiresAt = ( value ) => ( {
type : COMPOSE _EXPIRES _AT _CHANGE ,
value ,
} )
2020-12-16 22:29:06 +00:00
/ * *
*
* /
export const changeComposeGroupId = ( groupId ) => ( {
type : COMPOSE _GROUP _SET ,
groupId ,
} )
2020-11-15 18:48:32 +00:00
/ * *
*
* /
export const changeRichTextEditorControlsVisibility = ( open ) => ( {
type : COMPOSE _RICH _TEXT _EDITOR _CONTROLS _VISIBILITY ,
open ,
} )