akkoma-fe/src/modules/statuses.js

252 lines
7 KiB
JavaScript
Raw Normal View History

import { remove, map, slice, sortBy, toInteger, each, find, flatten, maxBy, last, merge, max } from 'lodash'
2016-10-28 13:59:49 +00:00
import moment from 'moment'
2016-10-30 15:12:35 +00:00
import apiService from '../services/api/api.service.js'
2016-11-15 09:35:16 +00:00
// import parse from '../services/status_parser/status_parser.js'
2016-10-26 17:03:55 +00:00
export const defaultState = {
2016-10-26 17:03:55 +00:00
allStatuses: [],
maxId: 0,
notifications: [],
2016-10-26 17:03:55 +00:00
timelines: {
public: {
statuses: [],
faves: [],
visibleStatuses: [],
newStatusCount: 0,
maxId: 0,
2016-11-06 16:44:05 +00:00
minVisibleId: 0,
loading: false
2016-10-26 17:03:55 +00:00
},
publicAndExternal: {
statuses: [],
faves: [],
visibleStatuses: [],
newStatusCount: 0,
maxId: 0,
2016-11-06 16:44:05 +00:00
minVisibleId: 0,
loading: false
2016-10-26 17:03:55 +00:00
},
friends: {
statuses: [],
faves: [],
visibleStatuses: [],
newStatusCount: 0,
maxId: 0,
2016-11-06 16:44:05 +00:00
minVisibleId: 0,
loading: false
2016-10-26 17:03:55 +00:00
}
}
}
2016-11-15 09:35:16 +00:00
export const prepareStatus = (status) => {
// Parse nsfw tags
if (status.nsfw === undefined) {
const nsfwRegex = /#nsfw/i
status.nsfw = !!status.text.match(nsfwRegex)
}
// Set created_at_parsed to initial value
status.created_at_parsed = status.created_at
return status
}
2016-10-28 13:59:49 +00:00
const updateTimestampsInStatuses = (statuses) => {
2016-10-28 23:38:41 +00:00
return map(statuses, (statusoid) => {
const status = statusoid.retweeted_status || statusoid
2016-10-28 13:59:49 +00:00
// Parse date
status.created_at_parsed = moment(status.created_at).fromNow()
return status
})
}
const statusType = (status) => {
if (status.is_post_verb) {
return 'status'
}
2016-11-13 21:09:27 +00:00
if (status.retweeted_status) {
return 'retweet'
}
2016-11-13 21:09:27 +00:00
if (typeof status.uri === 'string' && status.uri.match(/fave/)) {
return 'favorite'
}
2016-11-13 21:40:33 +00:00
if (status.text.match(/deleted notice {{tag/)) {
return 'deletion'
}
return 'unknown'
}
2016-11-13 21:54:49 +00:00
2016-11-15 09:35:16 +00:00
export const findMaxId = (...args) => {
return (maxBy(flatten(args), 'id') || {}).id
2016-11-13 21:40:33 +00:00
}
const mergeOrAdd = (arr, item) => {
const oldItem = find(arr, {id: item.id})
if (oldItem) {
// We already have this, so only merge the new info.
merge(oldItem, item)
2016-11-19 11:39:10 +00:00
return {item: oldItem, new: false}
} else {
// This is a new item, prepare it
prepareStatus(item)
arr.push(item)
2016-11-19 11:39:10 +00:00
return {item, new: true}
}
}
export const mutations = {
addNewStatuses (state, { statuses, showImmediately = false, timeline, user = {} }) {
const allStatuses = state.allStatuses
2016-11-13 21:09:27 +00:00
const timelineObject = state.timelines[timeline]
// Set the maxId to the new id if it's larger.
const updateMaxId = ({id}) => {
timelineObject.maxId = max([id, timelineObject.maxId])
}
const addStatus = (status, showImmediately, addToTimeline = true) => {
2016-11-19 11:39:10 +00:00
const result = mergeOrAdd(allStatuses, status)
status = result.item
2016-11-15 09:35:16 +00:00
2016-11-19 11:39:10 +00:00
if (result.new) {
updateMaxId(status)
}
// Some statuses should only be added to the global status repository.
if (addToTimeline) {
mergeOrAdd(timelineObject.statuses, status)
}
if (showImmediately) {
// Add it directly to the visibleStatuses, don't change
// newStatusCount
mergeOrAdd(timelineObject.visibleStatuses, status)
2016-11-19 11:39:10 +00:00
} else if (addToTimeline && result.new) {
// Just change newStatuscount
2016-11-19 11:39:10 +00:00
timelineObject.newStatusCount += 1
}
return status
}
2016-11-18 15:05:04 +00:00
2016-11-19 11:39:10 +00:00
const addNotification = ({type, status, action}) => {
state.notifications.push({type, status, action})
}
2016-11-19 11:39:10 +00:00
const favoriteStatus = (favorite) => {
const status = find(allStatuses, { id: toInteger(favorite.in_reply_to_status_id) })
if (status) {
status.fave_num += 1
if (status.user.id === user.id) {
2016-11-19 11:39:10 +00:00
addNotification({type: 'favorite', status, action: favorite})
}
}
return status
}
const processors = {
'status': (status) => {
addStatus(status, showImmediately)
},
'retweet': (status) => {
// RetweetedStatuses are never shown immediately
const retweetedStatus = addStatus(status.retweeted_status, false, false)
let retweet
// If the retweeted status is already there, don't add the retweet
// to the timeline.
if (find(timelineObject.visibleStatuses, {id: retweetedStatus.id})) {
// Already have it visible, don't add to timeline, don't show.
retweet = addStatus(status, false, false)
} else {
retweet = addStatus(status, showImmediately)
}
retweet.retweeted_status = retweetedStatus
},
'favorite': (favorite) => {
updateMaxId(favorite)
2016-11-19 11:39:10 +00:00
favoriteStatus(favorite)
},
2016-11-19 12:08:44 +00:00
'deletion': (deletion) => {
const uri = deletion.uri
updateMaxId(deletion)
remove(allStatuses, { uri })
remove(timelineObject.statuses, { uri })
remove(timelineObject.visibleStatuses, { uri })
},
'default': (unknown) => {
console.log(unknown)
}
}
each(statuses, (status) => {
const type = statusType(status)
const processor = processors[type] || processors['default']
processor(status)
})
// Keep the visible statuses sorted
timelineObject.visibleStatuses = sortBy(timelineObject.visibleStatuses, ({id}) => -id)
timelineObject.statuses = sortBy(timelineObject.statuses, ({id}) => -id)
timelineObject.minVisibleId = (last(timelineObject.statuses) || {}).id
},
showNewStatuses (state, { timeline }) {
const oldTimeline = (state.timelines[timeline])
oldTimeline.newStatusCount = 0
oldTimeline.visibleStatuses = slice(oldTimeline.statuses, 0, 50)
},
updateTimestamps (state) {
updateTimestampsInStatuses(state.allStatuses)
},
setFavorited (state, { status, value }) {
const newStatus = find(state.allStatuses, status)
newStatus.favorited = value
},
2016-11-13 16:09:16 +00:00
setRetweeted (state, { status, value }) {
const newStatus = find(state.allStatuses, status)
newStatus.repeated = value
},
setLoading (state, { timeline, value }) {
state.timelines[timeline].loading = value
},
setNsfw (state, { id, nsfw }) {
2016-11-07 17:47:38 +00:00
const newStatus = find(state.allStatuses, { id })
newStatus.nsfw = nsfw
}
}
2016-10-26 17:03:55 +00:00
const statuses = {
state: defaultState,
2016-10-30 15:12:35 +00:00
actions: {
addNewStatuses ({ rootState, commit }, { statuses, showImmediately = false, timeline }) {
commit('addNewStatuses', { statuses, showImmediately, timeline, user: rootState.users.currentUser })
},
2016-10-30 15:12:35 +00:00
favorite ({ rootState, commit }, status) {
// Optimistic favoriting...
commit('setFavorited', { status, value: true })
apiService.favorite({ id: status.id, credentials: rootState.users.currentUser.credentials })
},
unfavorite ({ rootState, commit }, status) {
// Optimistic favoriting...
commit('setFavorited', { status, value: false })
apiService.unfavorite({ id: status.id, credentials: rootState.users.currentUser.credentials })
2016-11-13 16:09:16 +00:00
},
retweet ({ rootState, commit }, status) {
// Optimistic retweeting...
commit('setRetweeted', { status, value: true })
apiService.retweet({ id: status.id, credentials: rootState.users.currentUser.credentials })
2016-10-30 15:12:35 +00:00
}
},
mutations
2016-10-26 17:03:55 +00:00
}
export default statuses