biome format --write
This commit is contained in:
parent
8372348148
commit
9262e803ec
415 changed files with 54076 additions and 17419 deletions
|
|
@ -8,24 +8,24 @@ export const defaultState = {
|
|||
modifiedPaths: null,
|
||||
descriptions: null,
|
||||
draft: null,
|
||||
dbConfigEnabled: null
|
||||
dbConfigEnabled: null,
|
||||
}
|
||||
|
||||
export const newUserFlags = {
|
||||
...defaultState.flagStorage
|
||||
...defaultState.flagStorage,
|
||||
}
|
||||
|
||||
const adminSettingsStorage = {
|
||||
state: {
|
||||
...cloneDeep(defaultState)
|
||||
...cloneDeep(defaultState),
|
||||
},
|
||||
mutations: {
|
||||
setInstanceAdminNoDbConfig (state) {
|
||||
setInstanceAdminNoDbConfig(state) {
|
||||
state.loaded = false
|
||||
state.dbConfigEnabled = false
|
||||
},
|
||||
setAvailableFrontends (state, { frontends }) {
|
||||
state.frontends = frontends.map(f => {
|
||||
setAvailableFrontends(state, { frontends }) {
|
||||
state.frontends = frontends.map((f) => {
|
||||
f.installedRefs = f.installed_refs
|
||||
if (f.name === 'pleroma-fe') {
|
||||
f.refs = ['master', 'develop']
|
||||
|
|
@ -35,16 +35,16 @@ const adminSettingsStorage = {
|
|||
return f
|
||||
})
|
||||
},
|
||||
updateAdminSettings (state, { config, modifiedPaths }) {
|
||||
updateAdminSettings(state, { config, modifiedPaths }) {
|
||||
state.loaded = true
|
||||
state.dbConfigEnabled = true
|
||||
state.config = config
|
||||
state.modifiedPaths = modifiedPaths
|
||||
},
|
||||
updateAdminDescriptions (state, { descriptions }) {
|
||||
updateAdminDescriptions(state, { descriptions }) {
|
||||
state.descriptions = descriptions
|
||||
},
|
||||
updateAdminDraft (state, { path, value }) {
|
||||
updateAdminDraft(state, { path, value }) {
|
||||
const [group, key, subkey] = path
|
||||
const parent = [group, key, subkey]
|
||||
|
||||
|
|
@ -55,21 +55,23 @@ const adminSettingsStorage = {
|
|||
set(state.draft, parent, cloneDeep(get(state.draft, parent)))
|
||||
}
|
||||
},
|
||||
resetAdminDraft (state) {
|
||||
resetAdminDraft(state) {
|
||||
state.draft = cloneDeep(state.config)
|
||||
}
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
loadFrontendsStuff ({ rootState, commit }) {
|
||||
rootState.api.backendInteractor.fetchAvailableFrontends()
|
||||
.then(frontends => commit('setAvailableFrontends', { frontends }))
|
||||
loadFrontendsStuff({ rootState, commit }) {
|
||||
rootState.api.backendInteractor
|
||||
.fetchAvailableFrontends()
|
||||
.then((frontends) => commit('setAvailableFrontends', { frontends }))
|
||||
},
|
||||
loadAdminStuff ({ state, rootState, dispatch, commit }) {
|
||||
rootState.api.backendInteractor.fetchInstanceDBConfig()
|
||||
.then(backendDbConfig => {
|
||||
loadAdminStuff({ state, rootState, dispatch, commit }) {
|
||||
rootState.api.backendInteractor
|
||||
.fetchInstanceDBConfig()
|
||||
.then((backendDbConfig) => {
|
||||
if (backendDbConfig.error) {
|
||||
if (backendDbConfig.error.status === 400) {
|
||||
backendDbConfig.error.json().then(errorJson => {
|
||||
backendDbConfig.error.json().then((errorJson) => {
|
||||
if (/configurable_from_database/.test(errorJson.error)) {
|
||||
commit('setInstanceAdminNoDbConfig')
|
||||
}
|
||||
|
|
@ -80,20 +82,23 @@ const adminSettingsStorage = {
|
|||
}
|
||||
})
|
||||
if (state.descriptions === null) {
|
||||
rootState.api.backendInteractor.fetchInstanceConfigDescriptions()
|
||||
.then(backendDescriptions => dispatch('setInstanceAdminDescriptions', { backendDescriptions }))
|
||||
rootState.api.backendInteractor
|
||||
.fetchInstanceConfigDescriptions()
|
||||
.then((backendDescriptions) =>
|
||||
dispatch('setInstanceAdminDescriptions', { backendDescriptions }),
|
||||
)
|
||||
}
|
||||
},
|
||||
setInstanceAdminSettings ({ state, commit }, { backendDbConfig }) {
|
||||
setInstanceAdminSettings({ state, commit }, { backendDbConfig }) {
|
||||
const config = state.config || {}
|
||||
const modifiedPaths = new Set()
|
||||
|
||||
backendDbConfig.configs.forEach(c => {
|
||||
backendDbConfig.configs.forEach((c) => {
|
||||
const path = [c.group, c.key]
|
||||
if (c.db) {
|
||||
// Path elements can contain dot, therefore we use ' -> ' as a separator instead
|
||||
// Using strings for modified paths for easier searching
|
||||
c.db.forEach(x => modifiedPaths.add([...path, x].join(' -> ')))
|
||||
c.db.forEach((x) => modifiedPaths.add([...path, x].join(' -> ')))
|
||||
}
|
||||
|
||||
// we need to preserve tuples on second level only, possibly third
|
||||
|
|
@ -102,10 +107,13 @@ const adminSettingsStorage = {
|
|||
if (Array.isArray(value) && value.length > 0 && value[0].tuple) {
|
||||
if (!preserveTuples) {
|
||||
return value.reduce((acc, c) => {
|
||||
return { ...acc, [c.tuple[0]]: convert(c.tuple[1], preserveTuplesLv2) }
|
||||
return {
|
||||
...acc,
|
||||
[c.tuple[0]]: convert(c.tuple[1], preserveTuplesLv2),
|
||||
}
|
||||
}, {})
|
||||
} else {
|
||||
return value.map(x => x.tuple)
|
||||
return value.map((x) => x.tuple)
|
||||
}
|
||||
} else {
|
||||
if (!preserveTuples) {
|
||||
|
|
@ -120,7 +128,7 @@ const adminSettingsStorage = {
|
|||
// so for those cases we want to preserve tuples as-is
|
||||
// right now it's made exclusively for :pleroma.:rate_limit
|
||||
// so it might not work properly elsewhere
|
||||
const preserveTuples = path.find(x => x === ':rate_limit')
|
||||
const preserveTuples = path.find((x) => x === ':rate_limit')
|
||||
set(config, path, convert(c.value, false, preserveTuples))
|
||||
})
|
||||
// patching http adapter config to be easier to handle
|
||||
|
|
@ -128,19 +136,23 @@ const adminSettingsStorage = {
|
|||
if (Array.isArray(adapter)) {
|
||||
config[':pleroma'][':http'][':adapter'] = {
|
||||
[':ssl_options']: {
|
||||
[':versions']: []
|
||||
}
|
||||
[':versions']: [],
|
||||
},
|
||||
}
|
||||
}
|
||||
commit('updateAdminSettings', { config, modifiedPaths })
|
||||
commit('resetAdminDraft')
|
||||
},
|
||||
setInstanceAdminDescriptions ({ commit }, { backendDescriptions }) {
|
||||
const convert = ({ children, description, label, key = '<ROOT>', group, suggestions }, path, acc) => {
|
||||
setInstanceAdminDescriptions({ commit }, { backendDescriptions }) {
|
||||
const convert = (
|
||||
{ children, description, label, key = '<ROOT>', group, suggestions },
|
||||
path,
|
||||
acc,
|
||||
) => {
|
||||
const newPath = group ? [group, key] : [key]
|
||||
const obj = { description, label, suggestions }
|
||||
if (Array.isArray(children)) {
|
||||
children.forEach(c => {
|
||||
children.forEach((c) => {
|
||||
convert(c, newPath, obj)
|
||||
})
|
||||
}
|
||||
|
|
@ -149,13 +161,13 @@ const adminSettingsStorage = {
|
|||
|
||||
const descriptions = {}
|
||||
|
||||
backendDescriptions.forEach(d => convert(d, '', descriptions))
|
||||
backendDescriptions.forEach((d) => convert(d, '', descriptions))
|
||||
commit('updateAdminDescriptions', { descriptions })
|
||||
},
|
||||
|
||||
// This action takes draft state, diffs it with live config state and then pushes
|
||||
// only differences between the two. Difference detection only work up to subkey (third) level.
|
||||
pushAdminDraft ({ rootState, state, dispatch }) {
|
||||
pushAdminDraft({ rootState, state, dispatch }) {
|
||||
// TODO cleanup paths in modifiedPaths
|
||||
const convert = (value) => {
|
||||
if (typeof value !== 'object') {
|
||||
|
|
@ -169,13 +181,9 @@ const adminSettingsStorage = {
|
|||
|
||||
// Getting all group-keys used in config
|
||||
const allGroupKeys = flatten(
|
||||
Object
|
||||
.entries(state.config)
|
||||
.map(
|
||||
([group, lv1data]) => Object
|
||||
.keys(lv1data)
|
||||
.map((key) => ({ group, key }))
|
||||
)
|
||||
Object.entries(state.config).map(([group, lv1data]) =>
|
||||
Object.keys(lv1data).map((key) => ({ group, key })),
|
||||
),
|
||||
)
|
||||
|
||||
// Only using group-keys where there are changes detected
|
||||
|
|
@ -194,19 +202,30 @@ const adminSettingsStorage = {
|
|||
|
||||
// Then those entries array we diff so only changed subkey entries remain
|
||||
// We use the diffed array to reconstruct the object and then shove it into convert()
|
||||
return ({ group, key, value: convert(Object.fromEntries(differenceWith(eDraft, eConfig, isEqual))) })
|
||||
})
|
||||
|
||||
rootState.api.backendInteractor.pushInstanceDBConfig({
|
||||
payload: {
|
||||
configs: changed
|
||||
return {
|
||||
group,
|
||||
key,
|
||||
value: convert(
|
||||
Object.fromEntries(differenceWith(eDraft, eConfig, isEqual)),
|
||||
),
|
||||
}
|
||||
})
|
||||
|
||||
rootState.api.backendInteractor
|
||||
.pushInstanceDBConfig({
|
||||
payload: {
|
||||
configs: changed,
|
||||
},
|
||||
})
|
||||
.then(() => rootState.api.backendInteractor.fetchInstanceDBConfig())
|
||||
.then(backendDbConfig => dispatch('setInstanceAdminSettings', { backendDbConfig }))
|
||||
.then((backendDbConfig) =>
|
||||
dispatch('setInstanceAdminSettings', { backendDbConfig }),
|
||||
)
|
||||
},
|
||||
pushAdminSetting ({ rootState, dispatch }, { path, value }) {
|
||||
const [group, key, ...rest] = Array.isArray(path) ? path : path.split(/\./g)
|
||||
pushAdminSetting({ rootState, dispatch }, { path, value }) {
|
||||
const [group, key, ...rest] = Array.isArray(path)
|
||||
? path
|
||||
: path.split(/\./g)
|
||||
const clone = {} // not actually cloning the entire thing to avoid excessive writes
|
||||
set(clone, rest, value)
|
||||
|
||||
|
|
@ -221,37 +240,49 @@ const adminSettingsStorage = {
|
|||
}
|
||||
}
|
||||
|
||||
rootState.api.backendInteractor.pushInstanceDBConfig({
|
||||
payload: {
|
||||
configs: [{
|
||||
group,
|
||||
key,
|
||||
value: convert(clone)
|
||||
}]
|
||||
}
|
||||
})
|
||||
rootState.api.backendInteractor
|
||||
.pushInstanceDBConfig({
|
||||
payload: {
|
||||
configs: [
|
||||
{
|
||||
group,
|
||||
key,
|
||||
value: convert(clone),
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
.then(() => rootState.api.backendInteractor.fetchInstanceDBConfig())
|
||||
.then(backendDbConfig => dispatch('setInstanceAdminSettings', { backendDbConfig }))
|
||||
.then((backendDbConfig) =>
|
||||
dispatch('setInstanceAdminSettings', { backendDbConfig }),
|
||||
)
|
||||
},
|
||||
resetAdminSetting ({ rootState, state, dispatch }, { path }) {
|
||||
const [group, key, subkey] = Array.isArray(path) ? path : path.split(/\./g)
|
||||
resetAdminSetting({ rootState, state, dispatch }, { path }) {
|
||||
const [group, key, subkey] = Array.isArray(path)
|
||||
? path
|
||||
: path.split(/\./g)
|
||||
|
||||
state.modifiedPaths.delete(path)
|
||||
|
||||
return rootState.api.backendInteractor.pushInstanceDBConfig({
|
||||
payload: {
|
||||
configs: [{
|
||||
group,
|
||||
key,
|
||||
delete: true,
|
||||
subkeys: [subkey]
|
||||
}]
|
||||
}
|
||||
})
|
||||
return rootState.api.backendInteractor
|
||||
.pushInstanceDBConfig({
|
||||
payload: {
|
||||
configs: [
|
||||
{
|
||||
group,
|
||||
key,
|
||||
delete: true,
|
||||
subkeys: [subkey],
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
.then(() => rootState.api.backendInteractor.fetchInstanceDBConfig())
|
||||
.then(backendDbConfig => dispatch('setInstanceAdminSettings', { backendDbConfig }))
|
||||
}
|
||||
}
|
||||
.then((backendDbConfig) =>
|
||||
dispatch('setInstanceAdminSettings', { backendDbConfig }),
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default adminSettingsStorage
|
||||
|
|
|
|||
|
|
@ -15,40 +15,40 @@ const api = {
|
|||
socket: null,
|
||||
mastoUserSocket: null,
|
||||
mastoUserSocketStatus: null,
|
||||
followRequests: []
|
||||
followRequests: [],
|
||||
},
|
||||
getters: {
|
||||
followRequestCount: state => state.followRequests.length
|
||||
followRequestCount: (state) => state.followRequests.length,
|
||||
},
|
||||
mutations: {
|
||||
setBackendInteractor (state, backendInteractor) {
|
||||
setBackendInteractor(state, backendInteractor) {
|
||||
state.backendInteractor = backendInteractor
|
||||
},
|
||||
addFetcher (state, { fetcherName, fetcher }) {
|
||||
addFetcher(state, { fetcherName, fetcher }) {
|
||||
state.fetchers[fetcherName] = fetcher
|
||||
},
|
||||
removeFetcher (state, { fetcherName }) {
|
||||
removeFetcher(state, { fetcherName }) {
|
||||
state.fetchers[fetcherName].stop()
|
||||
delete state.fetchers[fetcherName]
|
||||
},
|
||||
setWsToken (state, token) {
|
||||
setWsToken(state, token) {
|
||||
state.wsToken = token
|
||||
},
|
||||
setSocket (state, socket) {
|
||||
setSocket(state, socket) {
|
||||
state.socket = socket
|
||||
},
|
||||
setFollowRequests (state, value) {
|
||||
setFollowRequests(state, value) {
|
||||
state.followRequests = value
|
||||
},
|
||||
setMastoUserSocketStatus (state, value) {
|
||||
setMastoUserSocketStatus(state, value) {
|
||||
state.mastoUserSocketStatus = value
|
||||
},
|
||||
incrementRetryMultiplier (state) {
|
||||
incrementRetryMultiplier(state) {
|
||||
state.retryMultiplier = Math.max(++state.retryMultiplier, 3)
|
||||
},
|
||||
resetRetryMultiplier (state) {
|
||||
resetRetryMultiplier(state) {
|
||||
state.retryMultiplier = 1
|
||||
}
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
/**
|
||||
|
|
@ -56,15 +56,14 @@ const api = {
|
|||
*
|
||||
* @param {Boolean} [initial] - whether this enabling happened at boot time or not
|
||||
*/
|
||||
enableMastoSockets (store, initial) {
|
||||
enableMastoSockets(store, initial) {
|
||||
const { state, dispatch, commit } = store
|
||||
// Do not initialize unless nonexistent or closed
|
||||
if (
|
||||
state.mastoUserSocket &&
|
||||
![
|
||||
WebSocket.CLOSED,
|
||||
WebSocket.CLOSING
|
||||
].includes(state.mastoUserSocket.getState())
|
||||
![WebSocket.CLOSED, WebSocket.CLOSING].includes(
|
||||
state.mastoUserSocket.getState(),
|
||||
)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
|
@ -75,7 +74,7 @@ const api = {
|
|||
}
|
||||
return dispatch('startMastoUserSocket')
|
||||
},
|
||||
disableMastoSockets (store) {
|
||||
disableMastoSockets(store) {
|
||||
const { state, dispatch, commit } = store
|
||||
if (!state.mastoUserSocket) return
|
||||
commit('setMastoUserSocketStatus', WSConnectionStatus.DISABLED)
|
||||
|
|
@ -83,15 +82,20 @@ const api = {
|
|||
},
|
||||
|
||||
// MastoAPI 'User' sockets
|
||||
startMastoUserSocket (store) {
|
||||
startMastoUserSocket(store) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const { state, commit, dispatch, rootState } = store
|
||||
const timelineData = rootState.statuses.timelines.friends
|
||||
state.mastoUserSocket = state.backendInteractor.startUserSocket({ store })
|
||||
state.mastoUserSocket.addEventListener('pleroma:authenticated', () => {
|
||||
state.mastoUserSocket.subscribe('user')
|
||||
state.mastoUserSocket = state.backendInteractor.startUserSocket({
|
||||
store,
|
||||
})
|
||||
state.mastoUserSocket.addEventListener(
|
||||
'pleroma:authenticated',
|
||||
() => {
|
||||
state.mastoUserSocket.subscribe('user')
|
||||
},
|
||||
)
|
||||
state.mastoUserSocket.addEventListener(
|
||||
'message',
|
||||
({ detail: message }) => {
|
||||
|
|
@ -99,21 +103,22 @@ const api = {
|
|||
if (message.event === 'notification') {
|
||||
dispatch('addNewNotifications', {
|
||||
notifications: [message.notification],
|
||||
older: false
|
||||
older: false,
|
||||
})
|
||||
} else if (message.event === 'update') {
|
||||
dispatch('addNewStatuses', {
|
||||
statuses: [message.status],
|
||||
userId: false,
|
||||
showImmediately: timelineData.visibleStatuses.length === 0,
|
||||
timeline: 'friends'
|
||||
timeline: 'friends',
|
||||
})
|
||||
} else if (message.event === 'status.update') {
|
||||
dispatch('addNewStatuses', {
|
||||
statuses: [message.status],
|
||||
userId: false,
|
||||
showImmediately: message.status.id in timelineData.visibleStatusesObject,
|
||||
timeline: 'friends'
|
||||
showImmediately:
|
||||
message.status.id in timelineData.visibleStatusesObject,
|
||||
timeline: 'friends',
|
||||
})
|
||||
} else if (message.event === 'delete') {
|
||||
dispatch('deleteStatusById', message.id)
|
||||
|
|
@ -125,28 +130,33 @@ const api = {
|
|||
setTimeout(() => {
|
||||
dispatch('addChatMessages', {
|
||||
chatId: message.chatUpdate.id,
|
||||
messages: [message.chatUpdate.lastMessage]
|
||||
messages: [message.chatUpdate.lastMessage],
|
||||
})
|
||||
dispatch('updateChat', { chat: message.chatUpdate })
|
||||
maybeShowChatNotification(store, message.chatUpdate)
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
state.mastoUserSocket.addEventListener('open', () => {
|
||||
// Do not show notification when we just opened up the page
|
||||
if (state.mastoUserSocketStatus !== WSConnectionStatus.STARTING_INITIAL) {
|
||||
if (
|
||||
state.mastoUserSocketStatus !==
|
||||
WSConnectionStatus.STARTING_INITIAL
|
||||
) {
|
||||
useInterfaceStore().pushGlobalNotice({
|
||||
level: 'success',
|
||||
messageKey: 'timeline.socket_reconnected',
|
||||
timeout: 5000
|
||||
timeout: 5000,
|
||||
})
|
||||
}
|
||||
// Stop polling if we were errored or disabled
|
||||
if (new Set([
|
||||
WSConnectionStatus.ERROR,
|
||||
WSConnectionStatus.DISABLED
|
||||
]).has(state.mastoUserSocketStatus)) {
|
||||
if (
|
||||
new Set([
|
||||
WSConnectionStatus.ERROR,
|
||||
WSConnectionStatus.DISABLED,
|
||||
]).has(state.mastoUserSocketStatus)
|
||||
) {
|
||||
dispatch('stopFetchingTimeline', { timeline: 'friends' })
|
||||
dispatch('stopFetchingNotifications')
|
||||
dispatch('stopFetchingChats')
|
||||
|
|
@ -154,48 +164,58 @@ const api = {
|
|||
commit('resetRetryMultiplier')
|
||||
commit('setMastoUserSocketStatus', WSConnectionStatus.JOINED)
|
||||
})
|
||||
state.mastoUserSocket.addEventListener('error', ({ detail: error }) => {
|
||||
console.error('Error in MastoAPI websocket:', error)
|
||||
// TODO is this needed?
|
||||
dispatch('clearOpenedChats')
|
||||
})
|
||||
state.mastoUserSocket.addEventListener('close', ({ detail: closeEvent }) => {
|
||||
const ignoreCodes = new Set([
|
||||
1000, // Normal (intended) closure
|
||||
1001 // Going away
|
||||
])
|
||||
const { code } = closeEvent
|
||||
if (ignoreCodes.has(code)) {
|
||||
console.debug(`Not restarting socket becasue of closure code ${code} is in ignore list`)
|
||||
commit('setMastoUserSocketStatus', WSConnectionStatus.CLOSED)
|
||||
} else {
|
||||
console.warn(`MastoAPI websocket disconnected, restarting. CloseEvent code: ${code}`)
|
||||
setTimeout(() => {
|
||||
dispatch('startMastoUserSocket')
|
||||
}, retryTimeout(state.retryMultiplier))
|
||||
commit('incrementRetryMultiplier')
|
||||
if (state.mastoUserSocketStatus !== WSConnectionStatus.ERROR) {
|
||||
dispatch('startFetchingTimeline', { timeline: 'friends' })
|
||||
dispatch('startFetchingNotifications')
|
||||
dispatch('startFetchingChats')
|
||||
useInterfaceStore().pushGlobalNotice({
|
||||
level: 'error',
|
||||
messageKey: 'timeline.socket_broke',
|
||||
messageArgs: [code],
|
||||
timeout: 5000
|
||||
})
|
||||
state.mastoUserSocket.addEventListener(
|
||||
'error',
|
||||
({ detail: error }) => {
|
||||
console.error('Error in MastoAPI websocket:', error)
|
||||
// TODO is this needed?
|
||||
dispatch('clearOpenedChats')
|
||||
},
|
||||
)
|
||||
state.mastoUserSocket.addEventListener(
|
||||
'close',
|
||||
({ detail: closeEvent }) => {
|
||||
const ignoreCodes = new Set([
|
||||
1000, // Normal (intended) closure
|
||||
1001, // Going away
|
||||
])
|
||||
const { code } = closeEvent
|
||||
if (ignoreCodes.has(code)) {
|
||||
console.debug(
|
||||
`Not restarting socket becasue of closure code ${code} is in ignore list`,
|
||||
)
|
||||
commit('setMastoUserSocketStatus', WSConnectionStatus.CLOSED)
|
||||
} else {
|
||||
console.warn(
|
||||
`MastoAPI websocket disconnected, restarting. CloseEvent code: ${code}`,
|
||||
)
|
||||
setTimeout(() => {
|
||||
dispatch('startMastoUserSocket')
|
||||
}, retryTimeout(state.retryMultiplier))
|
||||
commit('incrementRetryMultiplier')
|
||||
if (state.mastoUserSocketStatus !== WSConnectionStatus.ERROR) {
|
||||
dispatch('startFetchingTimeline', { timeline: 'friends' })
|
||||
dispatch('startFetchingNotifications')
|
||||
dispatch('startFetchingChats')
|
||||
useInterfaceStore().pushGlobalNotice({
|
||||
level: 'error',
|
||||
messageKey: 'timeline.socket_broke',
|
||||
messageArgs: [code],
|
||||
timeout: 5000,
|
||||
})
|
||||
}
|
||||
commit('setMastoUserSocketStatus', WSConnectionStatus.ERROR)
|
||||
}
|
||||
commit('setMastoUserSocketStatus', WSConnectionStatus.ERROR)
|
||||
}
|
||||
dispatch('clearOpenedChats')
|
||||
})
|
||||
dispatch('clearOpenedChats')
|
||||
},
|
||||
)
|
||||
resolve()
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
})
|
||||
},
|
||||
stopMastoUserSocket ({ state, dispatch }) {
|
||||
stopMastoUserSocket({ state, dispatch }) {
|
||||
dispatch('startFetchingTimeline', { timeline: 'friends' })
|
||||
dispatch('startFetchingNotifications')
|
||||
dispatch('startFetchingChats')
|
||||
|
|
@ -203,103 +223,127 @@ const api = {
|
|||
},
|
||||
|
||||
// Timelines
|
||||
startFetchingTimeline (store, {
|
||||
timeline = 'friends',
|
||||
tag = false,
|
||||
userId = false,
|
||||
listId = false,
|
||||
statusId = false,
|
||||
bookmarkFolderId = false
|
||||
}) {
|
||||
if (timeline === 'favourites' && !store.rootState.instance.pleromaPublicFavouritesAvailable) return
|
||||
startFetchingTimeline(
|
||||
store,
|
||||
{
|
||||
timeline = 'friends',
|
||||
tag = false,
|
||||
userId = false,
|
||||
listId = false,
|
||||
statusId = false,
|
||||
bookmarkFolderId = false,
|
||||
},
|
||||
) {
|
||||
if (
|
||||
timeline === 'favourites' &&
|
||||
!store.rootState.instance.pleromaPublicFavouritesAvailable
|
||||
)
|
||||
return
|
||||
if (store.state.fetchers[timeline]) return
|
||||
|
||||
const fetcher = store.state.backendInteractor.startFetchingTimeline({
|
||||
timeline, store, userId, listId, statusId, bookmarkFolderId, tag
|
||||
timeline,
|
||||
store,
|
||||
userId,
|
||||
listId,
|
||||
statusId,
|
||||
bookmarkFolderId,
|
||||
tag,
|
||||
})
|
||||
store.commit('addFetcher', { fetcherName: timeline, fetcher })
|
||||
},
|
||||
stopFetchingTimeline (store, timeline) {
|
||||
stopFetchingTimeline(store, timeline) {
|
||||
const fetcher = store.state.fetchers[timeline]
|
||||
if (!fetcher) return
|
||||
store.commit('removeFetcher', { fetcherName: timeline, fetcher })
|
||||
},
|
||||
fetchTimeline (store, { timeline, ...rest }) {
|
||||
fetchTimeline(store, { timeline, ...rest }) {
|
||||
store.state.backendInteractor.fetchTimeline({
|
||||
store,
|
||||
timeline,
|
||||
...rest
|
||||
...rest,
|
||||
})
|
||||
},
|
||||
|
||||
// Notifications
|
||||
startFetchingNotifications (store) {
|
||||
startFetchingNotifications(store) {
|
||||
if (store.state.fetchers.notifications) return
|
||||
const fetcher = store.state.backendInteractor.startFetchingNotifications({ store })
|
||||
const fetcher = store.state.backendInteractor.startFetchingNotifications({
|
||||
store,
|
||||
})
|
||||
store.commit('addFetcher', { fetcherName: 'notifications', fetcher })
|
||||
},
|
||||
stopFetchingNotifications (store) {
|
||||
stopFetchingNotifications(store) {
|
||||
const fetcher = store.state.fetchers.notifications
|
||||
if (!fetcher) return
|
||||
store.commit('removeFetcher', { fetcherName: 'notifications', fetcher })
|
||||
},
|
||||
fetchNotifications (store, { ...rest }) {
|
||||
fetchNotifications(store, { ...rest }) {
|
||||
store.state.backendInteractor.fetchNotifications({
|
||||
store,
|
||||
...rest
|
||||
...rest,
|
||||
})
|
||||
},
|
||||
|
||||
// Follow requests
|
||||
startFetchingFollowRequests (store) {
|
||||
startFetchingFollowRequests(store) {
|
||||
if (store.state.fetchers.followRequests) return
|
||||
const fetcher = store.state.backendInteractor.startFetchingFollowRequests({ store })
|
||||
const fetcher = store.state.backendInteractor.startFetchingFollowRequests(
|
||||
{ store },
|
||||
)
|
||||
|
||||
store.commit('addFetcher', { fetcherName: 'followRequests', fetcher })
|
||||
},
|
||||
stopFetchingFollowRequests (store) {
|
||||
stopFetchingFollowRequests(store) {
|
||||
const fetcher = store.state.fetchers.followRequests
|
||||
if (!fetcher) return
|
||||
store.commit('removeFetcher', { fetcherName: 'followRequests', fetcher })
|
||||
},
|
||||
removeFollowRequest (store, request) {
|
||||
removeFollowRequest(store, request) {
|
||||
const requests = store.state.followRequests.filter((it) => it !== request)
|
||||
store.commit('setFollowRequests', requests)
|
||||
},
|
||||
|
||||
// Lists
|
||||
startFetchingLists (store) {
|
||||
startFetchingLists(store) {
|
||||
if (store.state.fetchers.lists) return
|
||||
const fetcher = store.state.backendInteractor.startFetchingLists({ store })
|
||||
const fetcher = store.state.backendInteractor.startFetchingLists({
|
||||
store,
|
||||
})
|
||||
store.commit('addFetcher', { fetcherName: 'lists', fetcher })
|
||||
},
|
||||
stopFetchingLists (store) {
|
||||
stopFetchingLists(store) {
|
||||
const fetcher = store.state.fetchers.lists
|
||||
if (!fetcher) return
|
||||
store.commit('removeFetcher', { fetcherName: 'lists', fetcher })
|
||||
},
|
||||
|
||||
// Bookmark folders
|
||||
startFetchingBookmarkFolders (store) {
|
||||
startFetchingBookmarkFolders(store) {
|
||||
if (store.state.fetchers.bookmarkFolders) return
|
||||
if (!store.rootState.instance.pleromaBookmarkFoldersAvailable) return
|
||||
const fetcher = store.state.backendInteractor.startFetchingBookmarkFolders({ store })
|
||||
const fetcher =
|
||||
store.state.backendInteractor.startFetchingBookmarkFolders({ store })
|
||||
store.commit('addFetcher', { fetcherName: 'bookmarkFolders', fetcher })
|
||||
},
|
||||
stopFetchingBookmarkFolders (store) {
|
||||
stopFetchingBookmarkFolders(store) {
|
||||
const fetcher = store.state.fetchers.bookmarkFolders
|
||||
if (!fetcher) return
|
||||
store.commit('removeFetcher', { fetcherName: 'bookmarkFolders', fetcher })
|
||||
},
|
||||
|
||||
// Pleroma websocket
|
||||
setWsToken (store, token) {
|
||||
setWsToken(store, token) {
|
||||
store.commit('setWsToken', token)
|
||||
},
|
||||
initializeSocket ({ commit, state, rootState }) {
|
||||
initializeSocket({ commit, state, rootState }) {
|
||||
// Set up websocket connection
|
||||
const token = state.wsToken
|
||||
if (rootState.instance.shoutAvailable && typeof token !== 'undefined' && state.socket === null) {
|
||||
if (
|
||||
rootState.instance.shoutAvailable &&
|
||||
typeof token !== 'undefined' &&
|
||||
state.socket === null
|
||||
) {
|
||||
const socket = new Socket('/socket', { params: { token } })
|
||||
socket.connect()
|
||||
|
||||
|
|
@ -307,11 +351,11 @@ const api = {
|
|||
useShoutStore().initializeShout(socket)
|
||||
}
|
||||
},
|
||||
disconnectFromSocket ({ commit, state }) {
|
||||
disconnectFromSocket({ commit, state }) {
|
||||
state.socket && state.socket.disconnect()
|
||||
commit('setSocket', null)
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default api
|
||||
|
|
|
|||
|
|
@ -1,13 +1,16 @@
|
|||
import { reactive } from 'vue'
|
||||
import { find, omitBy, orderBy, sumBy } from 'lodash'
|
||||
import chatService from '../services/chat_service/chat_service.js'
|
||||
import { parseChat, parseChatMessage } from '../services/entity_normalizer/entity_normalizer.service.js'
|
||||
import {
|
||||
parseChat,
|
||||
parseChatMessage,
|
||||
} from '../services/entity_normalizer/entity_normalizer.service.js'
|
||||
import { maybeShowChatNotification } from '../services/chat_utils/chat_utils.js'
|
||||
import { promiseInterval } from '../services/promise_interval/promise_interval.js'
|
||||
|
||||
const emptyChatList = () => ({
|
||||
data: [],
|
||||
idStore: {}
|
||||
idStore: {},
|
||||
})
|
||||
|
||||
const defaultState = {
|
||||
|
|
@ -17,7 +20,7 @@ const defaultState = {
|
|||
openedChatMessageServices: reactive({}),
|
||||
fetcher: undefined,
|
||||
currentChatId: null,
|
||||
lastReadMessageId: null
|
||||
lastReadMessageId: null,
|
||||
}
|
||||
|
||||
const getChatById = (state, id) => {
|
||||
|
|
@ -35,65 +38,74 @@ const unreadChatCount = (state) => {
|
|||
const chats = {
|
||||
state: { ...defaultState },
|
||||
getters: {
|
||||
currentChat: state => state.openedChats[state.currentChatId],
|
||||
currentChatMessageService: state => state.openedChatMessageServices[state.currentChatId],
|
||||
findOpenedChatByRecipientId: state => recipientId => find(state.openedChats, c => c.account.id === recipientId),
|
||||
currentChat: (state) => state.openedChats[state.currentChatId],
|
||||
currentChatMessageService: (state) =>
|
||||
state.openedChatMessageServices[state.currentChatId],
|
||||
findOpenedChatByRecipientId: (state) => (recipientId) =>
|
||||
find(state.openedChats, (c) => c.account.id === recipientId),
|
||||
sortedChatList,
|
||||
unreadChatCount
|
||||
unreadChatCount,
|
||||
},
|
||||
actions: {
|
||||
// Chat list
|
||||
startFetchingChats ({ dispatch, commit }) {
|
||||
startFetchingChats({ dispatch, commit }) {
|
||||
const fetcher = () => dispatch('fetchChats', { latest: true })
|
||||
fetcher()
|
||||
commit('setChatListFetcher', {
|
||||
fetcher: () => promiseInterval(fetcher, 5000)
|
||||
fetcher: () => promiseInterval(fetcher, 5000),
|
||||
})
|
||||
},
|
||||
stopFetchingChats ({ commit }) {
|
||||
stopFetchingChats({ commit }) {
|
||||
commit('setChatListFetcher', { fetcher: undefined })
|
||||
},
|
||||
fetchChats ({ dispatch, rootState }) {
|
||||
return rootState.api.backendInteractor.chats()
|
||||
.then(({ chats }) => {
|
||||
dispatch('addNewChats', { chats })
|
||||
return chats
|
||||
})
|
||||
fetchChats({ dispatch, rootState }) {
|
||||
return rootState.api.backendInteractor.chats().then(({ chats }) => {
|
||||
dispatch('addNewChats', { chats })
|
||||
return chats
|
||||
})
|
||||
},
|
||||
addNewChats (store, { chats }) {
|
||||
addNewChats(store, { chats }) {
|
||||
const { commit, dispatch, rootGetters } = store
|
||||
const newChatMessageSideEffects = (chat) => {
|
||||
maybeShowChatNotification(store, chat)
|
||||
}
|
||||
commit('addNewUsers', chats.map(k => k.account).filter(k => k))
|
||||
commit('addNewChats', { dispatch, chats, rootGetters, newChatMessageSideEffects })
|
||||
commit(
|
||||
'addNewUsers',
|
||||
chats.map((k) => k.account).filter((k) => k),
|
||||
)
|
||||
commit('addNewChats', {
|
||||
dispatch,
|
||||
chats,
|
||||
rootGetters,
|
||||
newChatMessageSideEffects,
|
||||
})
|
||||
},
|
||||
updateChat ({ commit }, { chat }) {
|
||||
updateChat({ commit }, { chat }) {
|
||||
commit('updateChat', { chat })
|
||||
},
|
||||
|
||||
// Opened Chats
|
||||
startFetchingCurrentChat ({ dispatch }, { fetcher }) {
|
||||
startFetchingCurrentChat({ dispatch }, { fetcher }) {
|
||||
dispatch('setCurrentChatFetcher', { fetcher })
|
||||
},
|
||||
setCurrentChatFetcher ({ commit }, { fetcher }) {
|
||||
setCurrentChatFetcher({ commit }, { fetcher }) {
|
||||
commit('setCurrentChatFetcher', { fetcher })
|
||||
},
|
||||
addOpenedChat ({ commit, dispatch }, { chat }) {
|
||||
addOpenedChat({ commit, dispatch }, { chat }) {
|
||||
commit('addOpenedChat', { dispatch, chat: parseChat(chat) })
|
||||
dispatch('addNewUsers', [chat.account])
|
||||
},
|
||||
addChatMessages ({ commit }, value) {
|
||||
addChatMessages({ commit }, value) {
|
||||
commit('addChatMessages', { commit, ...value })
|
||||
},
|
||||
resetChatNewMessageCount ({ commit }, value) {
|
||||
resetChatNewMessageCount({ commit }, value) {
|
||||
commit('resetChatNewMessageCount', value)
|
||||
},
|
||||
clearCurrentChat ({ commit }) {
|
||||
clearCurrentChat({ commit }) {
|
||||
commit('setCurrentChatId', { chatId: undefined })
|
||||
commit('setCurrentChatFetcher', { fetcher: undefined })
|
||||
},
|
||||
readChat ({ rootState, commit, dispatch }, { id, lastReadId }) {
|
||||
readChat({ rootState, commit, dispatch }, { id, lastReadId }) {
|
||||
const isNewMessage = rootState.chats.lastReadMessageId !== lastReadId
|
||||
|
||||
dispatch('resetChatNewMessageCount')
|
||||
|
|
@ -103,40 +115,40 @@ const chats = {
|
|||
rootState.api.backendInteractor.readChat({ id, lastReadId })
|
||||
}
|
||||
},
|
||||
deleteChatMessage ({ rootState, commit }, value) {
|
||||
deleteChatMessage({ rootState, commit }, value) {
|
||||
rootState.api.backendInteractor.deleteChatMessage(value)
|
||||
commit('deleteChatMessage', { commit, ...value })
|
||||
},
|
||||
resetChats ({ commit, dispatch }) {
|
||||
resetChats({ commit, dispatch }) {
|
||||
dispatch('clearCurrentChat')
|
||||
commit('resetChats', { commit })
|
||||
},
|
||||
clearOpenedChats ({ commit }) {
|
||||
clearOpenedChats({ commit }) {
|
||||
commit('clearOpenedChats', { commit })
|
||||
},
|
||||
handleMessageError ({ commit }, value) {
|
||||
handleMessageError({ commit }, value) {
|
||||
commit('handleMessageError', { commit, ...value })
|
||||
},
|
||||
cullOlderMessages ({ commit }, chatId) {
|
||||
cullOlderMessages({ commit }, chatId) {
|
||||
commit('cullOlderMessages', chatId)
|
||||
}
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
setChatListFetcher (state, { fetcher }) {
|
||||
setChatListFetcher(state, { fetcher }) {
|
||||
const prevFetcher = state.chatListFetcher
|
||||
if (prevFetcher) {
|
||||
prevFetcher.stop()
|
||||
}
|
||||
state.chatListFetcher = fetcher && fetcher()
|
||||
},
|
||||
setCurrentChatFetcher (state, { fetcher }) {
|
||||
setCurrentChatFetcher(state, { fetcher }) {
|
||||
const prevFetcher = state.fetcher
|
||||
if (prevFetcher) {
|
||||
prevFetcher.stop()
|
||||
}
|
||||
state.fetcher = fetcher && fetcher()
|
||||
},
|
||||
addOpenedChat (state, { chat }) {
|
||||
addOpenedChat(state, { chat }) {
|
||||
state.currentChatId = chat.id
|
||||
state.openedChats[chat.id] = chat
|
||||
|
||||
|
|
@ -144,15 +156,17 @@ const chats = {
|
|||
state.openedChatMessageServices[chat.id] = chatService.empty(chat.id)
|
||||
}
|
||||
},
|
||||
setCurrentChatId (state, { chatId }) {
|
||||
setCurrentChatId(state, { chatId }) {
|
||||
state.currentChatId = chatId
|
||||
},
|
||||
addNewChats (state, { chats, newChatMessageSideEffects }) {
|
||||
addNewChats(state, { chats, newChatMessageSideEffects }) {
|
||||
chats.forEach((updatedChat) => {
|
||||
const chat = getChatById(state, updatedChat.id)
|
||||
|
||||
if (chat) {
|
||||
const isNewMessage = (chat.lastMessage && chat.lastMessage.id) !== (updatedChat.lastMessage && updatedChat.lastMessage.id)
|
||||
const isNewMessage =
|
||||
(chat.lastMessage && chat.lastMessage.id) !==
|
||||
(updatedChat.lastMessage && updatedChat.lastMessage.id)
|
||||
chat.lastMessage = updatedChat.lastMessage
|
||||
chat.unread = updatedChat.unread
|
||||
chat.updated_at = updatedChat.updated_at
|
||||
|
|
@ -165,23 +179,28 @@ const chats = {
|
|||
}
|
||||
})
|
||||
},
|
||||
updateChat (state, { chat: updatedChat }) {
|
||||
updateChat(state, { chat: updatedChat }) {
|
||||
const chat = getChatById(state, updatedChat.id)
|
||||
if (chat) {
|
||||
chat.lastMessage = updatedChat.lastMessage
|
||||
chat.unread = updatedChat.unread
|
||||
chat.updated_at = updatedChat.updated_at
|
||||
}
|
||||
if (!chat) { state.chatList.data.unshift(updatedChat) }
|
||||
if (!chat) {
|
||||
state.chatList.data.unshift(updatedChat)
|
||||
}
|
||||
state.chatList.idStore[updatedChat.id] = updatedChat
|
||||
},
|
||||
deleteChat (state, { id }) {
|
||||
state.chats.data = state.chats.data.filter(conversation =>
|
||||
conversation.last_status.id !== id
|
||||
deleteChat(state, { id }) {
|
||||
state.chats.data = state.chats.data.filter(
|
||||
(conversation) => conversation.last_status.id !== id,
|
||||
)
|
||||
state.chats.idStore = omitBy(
|
||||
state.chats.idStore,
|
||||
(conversation) => conversation.last_status.id === id,
|
||||
)
|
||||
state.chats.idStore = omitBy(state.chats.idStore, conversation => conversation.last_status.id === id)
|
||||
},
|
||||
resetChats (state, { commit }) {
|
||||
resetChats(state, { commit }) {
|
||||
state.chatList = emptyChatList()
|
||||
state.currentChatId = null
|
||||
commit('setChatListFetcher', { fetcher: undefined })
|
||||
|
|
@ -191,27 +210,31 @@ const chats = {
|
|||
delete state.openedChatMessageServices[chatId]
|
||||
}
|
||||
},
|
||||
setChatsLoading (state, { value }) {
|
||||
setChatsLoading(state, { value }) {
|
||||
state.chats.loading = value
|
||||
},
|
||||
addChatMessages (state, { chatId, messages, updateMaxId }) {
|
||||
addChatMessages(state, { chatId, messages, updateMaxId }) {
|
||||
const chatMessageService = state.openedChatMessageServices[chatId]
|
||||
if (chatMessageService) {
|
||||
chatService.add(chatMessageService, { messages: messages.map(parseChatMessage), updateMaxId })
|
||||
chatService.add(chatMessageService, {
|
||||
messages: messages.map(parseChatMessage),
|
||||
updateMaxId,
|
||||
})
|
||||
}
|
||||
},
|
||||
deleteChatMessage (state, { chatId, messageId }) {
|
||||
deleteChatMessage(state, { chatId, messageId }) {
|
||||
const chatMessageService = state.openedChatMessageServices[chatId]
|
||||
if (chatMessageService) {
|
||||
chatService.deleteMessage(chatMessageService, messageId)
|
||||
}
|
||||
},
|
||||
resetChatNewMessageCount (state) {
|
||||
const chatMessageService = state.openedChatMessageServices[state.currentChatId]
|
||||
resetChatNewMessageCount(state) {
|
||||
const chatMessageService =
|
||||
state.openedChatMessageServices[state.currentChatId]
|
||||
chatService.resetNewMessageCount(chatMessageService)
|
||||
},
|
||||
// Used when a connection loss occurs
|
||||
clearOpenedChats (state) {
|
||||
clearOpenedChats(state) {
|
||||
const currentChatId = state.currentChatId
|
||||
for (const chatId in state.openedChats) {
|
||||
if (currentChatId !== chatId) {
|
||||
|
|
@ -221,21 +244,21 @@ const chats = {
|
|||
}
|
||||
}
|
||||
},
|
||||
readChat (state, { id, lastReadId }) {
|
||||
readChat(state, { id, lastReadId }) {
|
||||
state.lastReadMessageId = lastReadId
|
||||
const chat = getChatById(state, id)
|
||||
if (chat) {
|
||||
chat.unread = 0
|
||||
}
|
||||
},
|
||||
handleMessageError (state, { chatId, fakeId, isRetry }) {
|
||||
handleMessageError(state, { chatId, fakeId, isRetry }) {
|
||||
const chatMessageService = state.openedChatMessageServices[chatId]
|
||||
chatService.handleMessageError(chatMessageService, fakeId, isRetry)
|
||||
},
|
||||
cullOlderMessages (state, chatId) {
|
||||
cullOlderMessages(state, chatId) {
|
||||
chatService.cullOlderMessages(state.openedChatMessageServices[chatId])
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default chats
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ const APPEARANCE_SETTINGS_KEYS = new Set([
|
|||
'panelHeaderSize',
|
||||
'forcedRoundness',
|
||||
'emojiSize',
|
||||
'emojiReactionsScale'
|
||||
'emojiReactionsScale',
|
||||
])
|
||||
|
||||
/* TODO this is a bit messy.
|
||||
|
|
@ -34,7 +34,7 @@ export const multiChoiceProperties = [
|
|||
'conversationOtherRepliesButton', // below | inside
|
||||
'mentionLinkDisplay', // short | full_for_remote | full
|
||||
'userPopoverAvatarAction', // close | zoom | open
|
||||
'unsavedPostAction' // save | discard | confirm
|
||||
'unsavedPostAction', // save | discard | confirm
|
||||
]
|
||||
|
||||
// caching the instance default properties
|
||||
|
|
@ -43,43 +43,48 @@ export const instanceDefaultProperties = Object.keys(instanceDefaultConfig)
|
|||
const config = {
|
||||
state: { ...defaultState },
|
||||
getters: {
|
||||
defaultConfig (state, getters, rootState) {
|
||||
defaultConfig(state, getters, rootState) {
|
||||
const { instance } = rootState
|
||||
return {
|
||||
...defaultState,
|
||||
...Object.fromEntries(
|
||||
instanceDefaultProperties.map(key => [key, instance[key]])
|
||||
)
|
||||
instanceDefaultProperties.map((key) => [key, instance[key]]),
|
||||
),
|
||||
}
|
||||
},
|
||||
mergedConfig (state, getters, rootState, rootGetters) {
|
||||
mergedConfig(state, getters, rootState, rootGetters) {
|
||||
const { defaultConfig } = rootGetters
|
||||
return {
|
||||
...defaultConfig,
|
||||
// Do not override with undefined
|
||||
...Object.fromEntries(Object.entries(state).filter(([, v]) => v !== undefined))
|
||||
...Object.fromEntries(
|
||||
Object.entries(state).filter(([, v]) => v !== undefined),
|
||||
),
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
mutations: {
|
||||
setOptionTemporarily (state, { name, value }) {
|
||||
setOptionTemporarily(state, { name, value }) {
|
||||
set(state, name, value)
|
||||
applyConfig(state)
|
||||
},
|
||||
setOption (state, { name, value }) {
|
||||
setOption(state, { name, value }) {
|
||||
set(state, name, value)
|
||||
},
|
||||
setHighlight (state, { user, color, type }) {
|
||||
setHighlight(state, { user, color, type }) {
|
||||
const data = this.state.config.highlight[user]
|
||||
if (color || type) {
|
||||
state.highlight[user] = { color: color || data.color, type: type || data.type }
|
||||
state.highlight[user] = {
|
||||
color: color || data.color,
|
||||
type: type || data.type,
|
||||
}
|
||||
} else {
|
||||
delete state.highlight[user]
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
loadSettings ({ dispatch }, data) {
|
||||
loadSettings({ dispatch }, data) {
|
||||
const knownKeys = new Set(Object.keys(defaultState))
|
||||
const presentKeys = new Set(Object.keys(data))
|
||||
const intersection = new Set()
|
||||
|
|
@ -89,16 +94,16 @@ const config = {
|
|||
}
|
||||
}
|
||||
|
||||
intersection.forEach(
|
||||
name => dispatch('setOption', { name, value: data[name] })
|
||||
intersection.forEach((name) =>
|
||||
dispatch('setOption', { name, value: data[name] }),
|
||||
)
|
||||
},
|
||||
setHighlight ({ commit }, { user, color, type }) {
|
||||
setHighlight({ commit }, { user, color, type }) {
|
||||
commit('setHighlight', { user, color, type })
|
||||
},
|
||||
setOptionTemporarily ({ commit, dispatch, state }, { name, value }) {
|
||||
setOptionTemporarily({ commit, dispatch, state }, { name, value }) {
|
||||
if (useInterfaceStore().temporaryChangesTimeoutId !== null) {
|
||||
console.warn('Can\'t track more than one temporary change')
|
||||
console.warn("Can't track more than one temporary change")
|
||||
return
|
||||
}
|
||||
const oldValue = state[name]
|
||||
|
|
@ -117,32 +122,35 @@ const config = {
|
|||
|
||||
useInterfaceStore().setTemporaryChanges({
|
||||
confirm,
|
||||
revert
|
||||
revert,
|
||||
})
|
||||
},
|
||||
setThemeV2 ({ commit, dispatch }, { customTheme, customThemeSource }) {
|
||||
setThemeV2({ commit, dispatch }, { customTheme, customThemeSource }) {
|
||||
commit('setOption', { name: 'theme', value: 'custom' })
|
||||
commit('setOption', { name: 'customTheme', value: customTheme })
|
||||
commit('setOption', { name: 'customThemeSource', value: customThemeSource })
|
||||
commit('setOption', {
|
||||
name: 'customThemeSource',
|
||||
value: customThemeSource,
|
||||
})
|
||||
dispatch('setTheme', { themeData: customThemeSource, recompile: true })
|
||||
},
|
||||
setOption ({ commit, dispatch, state }, { name, value }) {
|
||||
const exceptions = new Set([
|
||||
'useStreamingApi'
|
||||
])
|
||||
setOption({ commit, dispatch, state }, { name, value }) {
|
||||
const exceptions = new Set(['useStreamingApi'])
|
||||
|
||||
if (exceptions.has(name)) {
|
||||
switch (name) {
|
||||
case 'useStreamingApi': {
|
||||
const action = value ? 'enableMastoSockets' : 'disableMastoSockets'
|
||||
|
||||
dispatch(action).then(() => {
|
||||
commit('setOption', { name: 'useStreamingApi', value })
|
||||
}).catch((e) => {
|
||||
console.error('Failed starting MastoAPI Streaming socket', e)
|
||||
dispatch('disableMastoSockets')
|
||||
dispatch('setOption', { name: 'useStreamingApi', value: false })
|
||||
})
|
||||
dispatch(action)
|
||||
.then(() => {
|
||||
commit('setOption', { name: 'useStreamingApi', value })
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('Failed starting MastoAPI Streaming socket', e)
|
||||
dispatch('disableMastoSockets')
|
||||
dispatch('setOption', { name: 'useStreamingApi', value: false })
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
@ -157,7 +165,11 @@ const config = {
|
|||
switch (name) {
|
||||
case 'theme':
|
||||
if (value === 'custom') break
|
||||
dispatch('setTheme', { themeName: value, recompile: true, saveData: true })
|
||||
dispatch('setTheme', {
|
||||
themeName: value,
|
||||
recompile: true,
|
||||
saveData: true,
|
||||
})
|
||||
break
|
||||
case 'themeDebug': {
|
||||
dispatch('setTheme', { recompile: true })
|
||||
|
|
@ -168,7 +180,7 @@ const config = {
|
|||
dispatch('loadUnicodeEmojiData', value)
|
||||
Cookies.set(
|
||||
BACKEND_LANGUAGE_COOKIE_NAME,
|
||||
localeService.internalToBackendLocaleMulti(value)
|
||||
localeService.internalToBackendLocaleMulti(value),
|
||||
)
|
||||
break
|
||||
case 'thirdColumnMode':
|
||||
|
|
@ -176,8 +188,8 @@ const config = {
|
|||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default config
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
export const CONFIG_MIGRATION = 1
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
// for future use
|
||||
/*
|
||||
|
|
@ -20,7 +20,7 @@ export const declarations = [
|
|||
migrationNum: 1,
|
||||
description: 'Mute filters, wordfilter/regexp/etc',
|
||||
valueType: 'complex',
|
||||
migration (serverside, rootState) {
|
||||
migration(serverside, rootState) {
|
||||
rootState.config.muteWords.forEach((word, order) => {
|
||||
const uniqueId = uuidv4()
|
||||
|
||||
|
|
@ -33,10 +33,10 @@ export const declarations = [
|
|||
enabled: true,
|
||||
expires: null,
|
||||
hide: false,
|
||||
order
|
||||
}
|
||||
order,
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
]
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export const instanceDefaultConfig = {
|
|||
followRequest: true,
|
||||
reports: true,
|
||||
chatMention: true,
|
||||
polls: true
|
||||
polls: true,
|
||||
},
|
||||
notificationNative: {
|
||||
follows: true,
|
||||
|
|
@ -83,7 +83,7 @@ export const instanceDefaultConfig = {
|
|||
followRequest: true,
|
||||
reports: true,
|
||||
chatMention: true,
|
||||
polls: true
|
||||
polls: true,
|
||||
},
|
||||
webPushNotifications: false,
|
||||
webPushAlwaysShowNotifications: false,
|
||||
|
|
@ -170,10 +170,11 @@ export const instanceDefaultConfig = {
|
|||
absoluteTimeFormatMinAge: '0d',
|
||||
absoluteTime12h: '24h',
|
||||
imageCompression: true,
|
||||
alwaysUseJpeg: false
|
||||
alwaysUseJpeg: false,
|
||||
}
|
||||
|
||||
export const makeUndefined = c => Object.fromEntries(Object.keys(c).map(key => [key, undefined]))
|
||||
export const makeUndefined = (c) =>
|
||||
Object.fromEntries(Object.keys(c).map((key) => [key, undefined]))
|
||||
|
||||
/// For properties with special processing or properties that does not
|
||||
/// make sense to be overriden on a instance-wide level.
|
||||
|
|
@ -199,14 +200,15 @@ export const defaultState = {
|
|||
paletteCustomData: null,
|
||||
themeDebug: false, // debug mode that uses computed backgrounds instead of real ones to debug contrast functions
|
||||
forceThemeRecompilation: false, // flag that forces recompilation on boot even if cache exists
|
||||
theme3hacks: { // Hacks, user overrides that are independent of theme used
|
||||
theme3hacks: {
|
||||
// Hacks, user overrides that are independent of theme used
|
||||
underlay: 'none',
|
||||
fonts: {
|
||||
interface: undefined,
|
||||
input: undefined,
|
||||
post: undefined,
|
||||
monospace: undefined
|
||||
}
|
||||
monospace: undefined,
|
||||
},
|
||||
},
|
||||
|
||||
// Special handling: These fields are not of a primitive type, and
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
import { storage } from 'src/lib/storage.js'
|
||||
|
||||
export const defaultState = {
|
||||
drafts: {}
|
||||
drafts: {},
|
||||
}
|
||||
|
||||
export const mutations = {
|
||||
addOrSaveDraft (state, { draft }) {
|
||||
addOrSaveDraft(state, { draft }) {
|
||||
state.drafts[draft.id] = draft
|
||||
},
|
||||
abandonDraft (state, { id }) {
|
||||
abandonDraft(state, { id }) {
|
||||
delete state.drafts[id]
|
||||
},
|
||||
loadDrafts (state, data) {
|
||||
loadDrafts(state, data) {
|
||||
state.drafts = data
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const storageKey = 'pleroma-fe-drafts'
|
||||
|
|
@ -30,7 +30,7 @@ const storageKey = 'pleroma-fe-drafts'
|
|||
* different keys, which will just pollute the whole storage.
|
||||
* It is indeed best to have backend support for this.
|
||||
*/
|
||||
const getStorageData = async () => ((await storage.getItem(storageKey)) || {})
|
||||
const getStorageData = async () => (await storage.getItem(storageKey)) || {}
|
||||
|
||||
const saveDraftToStorage = async (draft) => {
|
||||
const currentData = await getStorageData()
|
||||
|
|
@ -45,42 +45,44 @@ const deleteDraftFromStorage = async (id) => {
|
|||
}
|
||||
|
||||
export const actions = {
|
||||
async addOrSaveDraft (store, { draft }) {
|
||||
const id = draft.id || (new Date().getTime()).toString()
|
||||
async addOrSaveDraft(store, { draft }) {
|
||||
const id = draft.id || new Date().getTime().toString()
|
||||
const draftWithId = { ...draft, id }
|
||||
store.commit('addOrSaveDraft', { draft: draftWithId })
|
||||
await saveDraftToStorage(draftWithId)
|
||||
return id
|
||||
},
|
||||
async abandonDraft (store, { id }) {
|
||||
async abandonDraft(store, { id }) {
|
||||
store.commit('abandonDraft', { id })
|
||||
await deleteDraftFromStorage(id)
|
||||
},
|
||||
async loadDrafts (store) {
|
||||
async loadDrafts(store) {
|
||||
const currentData = await getStorageData()
|
||||
store.commit('loadDrafts', currentData)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const getters = {
|
||||
draftsByTypeAndRefId (state) {
|
||||
draftsByTypeAndRefId(state) {
|
||||
return (type, refId) => {
|
||||
return Object.values(state.drafts).filter(draft => draft.type === type && draft.refId === refId)
|
||||
return Object.values(state.drafts).filter(
|
||||
(draft) => draft.type === type && draft.refId === refId,
|
||||
)
|
||||
}
|
||||
},
|
||||
draftsArray (state) {
|
||||
draftsArray(state) {
|
||||
return Object.values(state.drafts)
|
||||
},
|
||||
draftCount (state) {
|
||||
draftCount(state) {
|
||||
return Object.values(state.drafts).length
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const drafts = {
|
||||
state: defaultState,
|
||||
mutations,
|
||||
getters,
|
||||
actions
|
||||
actions,
|
||||
}
|
||||
|
||||
export default drafts
|
||||
|
|
|
|||
|
|
@ -19,5 +19,5 @@ export default {
|
|||
profileConfig,
|
||||
adminSettings,
|
||||
drafts,
|
||||
chats
|
||||
chats,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@ import { ensureFinalFallback } from '../i18n/languages.js'
|
|||
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||
// See build/emojis_plugin for more details
|
||||
import { annotationsLoader } from 'virtual:pleroma-fe/emoji-annotations'
|
||||
import { staticOrApiConfigDefault, instanceDefaultConfig } from './default_config_state.js';
|
||||
import {
|
||||
staticOrApiConfigDefault,
|
||||
instanceDefaultConfig,
|
||||
} from './default_config_state.js'
|
||||
|
||||
const SORTED_EMOJI_GROUP_IDS = [
|
||||
'smileys-and-emotion',
|
||||
|
|
@ -15,12 +18,12 @@ const SORTED_EMOJI_GROUP_IDS = [
|
|||
'activities',
|
||||
'objects',
|
||||
'symbols',
|
||||
'flags'
|
||||
'flags',
|
||||
]
|
||||
|
||||
const REGIONAL_INDICATORS = (() => {
|
||||
const start = 0x1F1E6
|
||||
const end = 0x1F1FF
|
||||
const start = 0x1f1e6
|
||||
const end = 0x1f1ff
|
||||
const A = 'A'.codePointAt(0)
|
||||
const res = new Array(end - start + 1)
|
||||
for (let i = start; i <= end; ++i) {
|
||||
|
|
@ -31,8 +34,8 @@ const REGIONAL_INDICATORS = (() => {
|
|||
displayText: 'regional_indicator_' + letter,
|
||||
displayTextI18n: {
|
||||
key: 'emoji.regional_indicator',
|
||||
args: { letter }
|
||||
}
|
||||
args: { letter },
|
||||
},
|
||||
}
|
||||
}
|
||||
return res
|
||||
|
|
@ -107,13 +110,12 @@ const defaultState = {
|
|||
max_options: 4,
|
||||
max_option_chars: 255,
|
||||
min_expiration: 60,
|
||||
max_expiration: 60 * 60 * 24
|
||||
}
|
||||
max_expiration: 60 * 60 * 24,
|
||||
},
|
||||
}
|
||||
|
||||
const loadAnnotations = (lang) => {
|
||||
return annotationsLoader[lang]()
|
||||
.then(k => k.default)
|
||||
return annotationsLoader[lang]().then((k) => k.default)
|
||||
}
|
||||
|
||||
const injectAnnotations = (emoji, annotations) => {
|
||||
|
|
@ -124,11 +126,11 @@ const injectAnnotations = (emoji, annotations) => {
|
|||
annotations: availableLangs.reduce((acc, cur) => {
|
||||
acc[cur] = annotations[cur][emoji.replacement]
|
||||
return acc
|
||||
}, {})
|
||||
}, {}),
|
||||
}
|
||||
}
|
||||
|
||||
const injectRegionalIndicators = groups => {
|
||||
const injectRegionalIndicators = (groups) => {
|
||||
groups.symbols.push(...REGIONAL_INDICATORS)
|
||||
return groups
|
||||
}
|
||||
|
|
@ -136,77 +138,84 @@ const injectRegionalIndicators = groups => {
|
|||
const instance = {
|
||||
state: defaultState,
|
||||
mutations: {
|
||||
setInstanceOption (state, { name, value }) {
|
||||
setInstanceOption(state, { name, value }) {
|
||||
if (typeof value !== 'undefined') {
|
||||
state[name] = value
|
||||
}
|
||||
},
|
||||
setKnownDomains (state, domains) {
|
||||
setKnownDomains(state, domains) {
|
||||
state.knownDomains = domains
|
||||
},
|
||||
setUnicodeEmojiAnnotations (state, { lang, annotations }) {
|
||||
setUnicodeEmojiAnnotations(state, { lang, annotations }) {
|
||||
state.unicodeEmojiAnnotations[lang] = annotations
|
||||
}
|
||||
},
|
||||
},
|
||||
getters: {
|
||||
instanceDefaultConfig (state) {
|
||||
instanceDefaultConfig(state) {
|
||||
return instanceDefaultProperties
|
||||
.map(key => [key, state[key]])
|
||||
.map((key) => [key, state[key]])
|
||||
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {})
|
||||
},
|
||||
groupedCustomEmojis (state) {
|
||||
const packsOf = emoji => {
|
||||
groupedCustomEmojis(state) {
|
||||
const packsOf = (emoji) => {
|
||||
const packs = emoji.tags
|
||||
.filter(k => k.startsWith('pack:'))
|
||||
.map(k => {
|
||||
.filter((k) => k.startsWith('pack:'))
|
||||
.map((k) => {
|
||||
const packName = k.slice(5) // remove 'pack:' prefix
|
||||
return {
|
||||
id: `custom-${packName}`,
|
||||
text: packName
|
||||
text: packName,
|
||||
}
|
||||
})
|
||||
|
||||
if (!packs.length) {
|
||||
return [{
|
||||
id: 'unpacked'
|
||||
}]
|
||||
return [
|
||||
{
|
||||
id: 'unpacked',
|
||||
},
|
||||
]
|
||||
} else {
|
||||
return packs
|
||||
}
|
||||
}
|
||||
|
||||
return state.customEmoji
|
||||
.reduce((res, emoji) => {
|
||||
packsOf(emoji).forEach(({ id: packId, text: packName }) => {
|
||||
if (!res[packId]) {
|
||||
res[packId] = ({
|
||||
id: packId,
|
||||
text: packName,
|
||||
image: emoji.imageUrl,
|
||||
emojis: []
|
||||
})
|
||||
return state.customEmoji.reduce((res, emoji) => {
|
||||
packsOf(emoji).forEach(({ id: packId, text: packName }) => {
|
||||
if (!res[packId]) {
|
||||
res[packId] = {
|
||||
id: packId,
|
||||
text: packName,
|
||||
image: emoji.imageUrl,
|
||||
emojis: [],
|
||||
}
|
||||
res[packId].emojis.push(emoji)
|
||||
})
|
||||
return res
|
||||
}, {})
|
||||
}
|
||||
res[packId].emojis.push(emoji)
|
||||
})
|
||||
return res
|
||||
}, {})
|
||||
},
|
||||
standardEmojiList (state) {
|
||||
return SORTED_EMOJI_GROUP_IDS
|
||||
.map(groupId => (state.emoji[groupId] || []).map(k => injectAnnotations(k, state.unicodeEmojiAnnotations)))
|
||||
.reduce((a, b) => a.concat(b), [])
|
||||
standardEmojiList(state) {
|
||||
return SORTED_EMOJI_GROUP_IDS.map((groupId) =>
|
||||
(state.emoji[groupId] || []).map((k) =>
|
||||
injectAnnotations(k, state.unicodeEmojiAnnotations),
|
||||
),
|
||||
).reduce((a, b) => a.concat(b), [])
|
||||
},
|
||||
standardEmojiGroupList (state) {
|
||||
return SORTED_EMOJI_GROUP_IDS.map(groupId => ({
|
||||
standardEmojiGroupList(state) {
|
||||
return SORTED_EMOJI_GROUP_IDS.map((groupId) => ({
|
||||
id: groupId,
|
||||
emojis: (state.emoji[groupId] || []).map(k => injectAnnotations(k, state.unicodeEmojiAnnotations))
|
||||
emojis: (state.emoji[groupId] || []).map((k) =>
|
||||
injectAnnotations(k, state.unicodeEmojiAnnotations),
|
||||
),
|
||||
}))
|
||||
},
|
||||
instanceDomain (state) {
|
||||
instanceDomain(state) {
|
||||
return new URL(state.server).hostname
|
||||
},
|
||||
remoteInteractionLink (state) {
|
||||
const server = state.server.endsWith('/') ? state.server.slice(0, -1) : state.server
|
||||
remoteInteractionLink(state) {
|
||||
const server = state.server.endsWith('/')
|
||||
? state.server.slice(0, -1)
|
||||
: state.server
|
||||
const link = server + REMOTE_INTERACTION_URL
|
||||
|
||||
return ({ statusId, nickname }) => {
|
||||
|
|
@ -216,10 +225,10 @@ const instance = {
|
|||
return `${link}?nickname=${nickname}`
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
setInstanceOption ({ commit, dispatch }, { name, value }) {
|
||||
setInstanceOption({ commit, dispatch }, { name, value }) {
|
||||
commit('setInstanceOption', { name, value })
|
||||
switch (name) {
|
||||
case 'name':
|
||||
|
|
@ -232,43 +241,49 @@ const instance = {
|
|||
break
|
||||
}
|
||||
},
|
||||
async getStaticEmoji ({ commit }) {
|
||||
async getStaticEmoji({ commit }) {
|
||||
try {
|
||||
const values = (await import('/src/assets/emoji.json')).default
|
||||
|
||||
const emoji = Object.keys(values).reduce((res, groupId) => {
|
||||
res[groupId] = values[groupId].map(e => ({
|
||||
res[groupId] = values[groupId].map((e) => ({
|
||||
displayText: e.slug,
|
||||
imageUrl: false,
|
||||
replacement: e.emoji
|
||||
replacement: e.emoji,
|
||||
}))
|
||||
return res
|
||||
}, {})
|
||||
commit('setInstanceOption', { name: 'emoji', value: injectRegionalIndicators(emoji) })
|
||||
commit('setInstanceOption', {
|
||||
name: 'emoji',
|
||||
value: injectRegionalIndicators(emoji),
|
||||
})
|
||||
} catch (e) {
|
||||
console.warn("Can't load static emoji\n", e)
|
||||
}
|
||||
},
|
||||
|
||||
loadUnicodeEmojiData ({ commit, state }, language) {
|
||||
loadUnicodeEmojiData({ commit, state }, language) {
|
||||
const langList = ensureFinalFallback(language)
|
||||
|
||||
return Promise.all(
|
||||
langList
|
||||
.map(async lang => {
|
||||
if (!state.unicodeEmojiAnnotations[lang]) {
|
||||
try {
|
||||
const annotations = await loadAnnotations(lang)
|
||||
commit('setUnicodeEmojiAnnotations', { lang, annotations })
|
||||
} catch (e) {
|
||||
console.warn(`Error loading unicode emoji annotations for ${lang}: `, e)
|
||||
// ignore
|
||||
}
|
||||
langList.map(async (lang) => {
|
||||
if (!state.unicodeEmojiAnnotations[lang]) {
|
||||
try {
|
||||
const annotations = await loadAnnotations(lang)
|
||||
commit('setUnicodeEmojiAnnotations', { lang, annotations })
|
||||
} catch (e) {
|
||||
console.warn(
|
||||
`Error loading unicode emoji annotations for ${lang}: `,
|
||||
e,
|
||||
)
|
||||
// ignore
|
||||
}
|
||||
}))
|
||||
}
|
||||
}),
|
||||
)
|
||||
},
|
||||
|
||||
async getCustomEmoji ({ commit, state }) {
|
||||
async getCustomEmoji({ commit, state }) {
|
||||
try {
|
||||
let res = await window.fetch('/api/v1/pleroma/emoji')
|
||||
if (!res.ok) {
|
||||
|
|
@ -276,11 +291,13 @@ const instance = {
|
|||
}
|
||||
if (res.ok) {
|
||||
const result = await res.json()
|
||||
const values = Array.isArray(result) ? Object.assign({}, ...result) : result
|
||||
const values = Array.isArray(result)
|
||||
? Object.assign({}, ...result)
|
||||
: result
|
||||
const caseInsensitiveStrCmp = (a, b) => {
|
||||
const la = a.toLowerCase()
|
||||
const lb = b.toLowerCase()
|
||||
return la > lb ? 1 : (la < lb ? -1 : 0)
|
||||
return la > lb ? 1 : la < lb ? -1 : 0
|
||||
}
|
||||
const noPackLast = (a, b) => {
|
||||
const aNull = a === ''
|
||||
|
|
@ -294,32 +311,43 @@ const instance = {
|
|||
}
|
||||
}
|
||||
const byPackThenByName = (a, b) => {
|
||||
const packOf = emoji => (emoji.tags.filter(k => k.startsWith('pack:'))[0] || '').slice(5)
|
||||
const packOf = (emoji) =>
|
||||
(emoji.tags.filter((k) => k.startsWith('pack:'))[0] || '').slice(
|
||||
5,
|
||||
)
|
||||
const packOfA = packOf(a)
|
||||
const packOfB = packOf(b)
|
||||
return noPackLast(packOfA, packOfB) || caseInsensitiveStrCmp(packOfA, packOfB) || caseInsensitiveStrCmp(a.displayText, b.displayText)
|
||||
return (
|
||||
noPackLast(packOfA, packOfB) ||
|
||||
caseInsensitiveStrCmp(packOfA, packOfB) ||
|
||||
caseInsensitiveStrCmp(a.displayText, b.displayText)
|
||||
)
|
||||
}
|
||||
|
||||
const emoji = Object.entries(values).map(([key, value]) => {
|
||||
const imageUrl = value.image_url
|
||||
return {
|
||||
displayText: key,
|
||||
imageUrl: imageUrl ? state.server + imageUrl : value,
|
||||
tags: imageUrl ? value.tags.sort((a, b) => a > b ? 1 : 0) : ['utf'],
|
||||
replacement: `:${key}: `
|
||||
}
|
||||
// Technically could use tags but those are kinda useless right now,
|
||||
// should have been "pack" field, that would be more useful
|
||||
}).sort(byPackThenByName)
|
||||
const emoji = Object.entries(values)
|
||||
.map(([key, value]) => {
|
||||
const imageUrl = value.image_url
|
||||
return {
|
||||
displayText: key,
|
||||
imageUrl: imageUrl ? state.server + imageUrl : value,
|
||||
tags: imageUrl
|
||||
? value.tags.sort((a, b) => (a > b ? 1 : 0))
|
||||
: ['utf'],
|
||||
replacement: `:${key}: `,
|
||||
}
|
||||
// Technically could use tags but those are kinda useless right now,
|
||||
// should have been "pack" field, that would be more useful
|
||||
})
|
||||
.sort(byPackThenByName)
|
||||
commit('setInstanceOption', { name: 'customEmoji', value: emoji })
|
||||
} else {
|
||||
throw (res)
|
||||
throw res
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Can't load custom emojis\n", e)
|
||||
}
|
||||
},
|
||||
fetchEmoji ({ dispatch, state }) {
|
||||
fetchEmoji({ dispatch, state }) {
|
||||
if (!state.customEmojiFetched) {
|
||||
state.customEmojiFetched = true
|
||||
dispatch('getCustomEmoji')
|
||||
|
|
@ -330,17 +358,17 @@ const instance = {
|
|||
}
|
||||
},
|
||||
|
||||
async getKnownDomains ({ commit, rootState }) {
|
||||
async getKnownDomains({ commit, rootState }) {
|
||||
try {
|
||||
const result = await apiService.fetchKnownDomains({
|
||||
credentials: rootState.users.currentUser.credentials
|
||||
credentials: rootState.users.currentUser.credentials,
|
||||
})
|
||||
commit('setKnownDomains', result)
|
||||
} catch (e) {
|
||||
console.warn("Can't load known domains\n", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default instance
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ import { useServerSideStorageStore } from 'src/stores/serverSideStorage'
|
|||
import {
|
||||
isStatusNotification,
|
||||
isValidNotification,
|
||||
maybeShowNotification
|
||||
maybeShowNotification,
|
||||
} from '../services/notification_utils/notification_utils.js'
|
||||
|
||||
import {
|
||||
closeDesktopNotification,
|
||||
closeAllDesktopNotifications
|
||||
closeAllDesktopNotifications,
|
||||
} from '../services/desktop_notification_utils/desktop_notification_utils.js'
|
||||
|
||||
import { useReportsStore } from 'src/stores/reports.js'
|
||||
|
|
@ -20,58 +20,58 @@ const emptyNotifications = () => ({
|
|||
minId: Number.POSITIVE_INFINITY,
|
||||
data: [],
|
||||
idStore: {},
|
||||
loading: false
|
||||
loading: false,
|
||||
})
|
||||
|
||||
export const defaultState = () => ({
|
||||
...emptyNotifications()
|
||||
...emptyNotifications(),
|
||||
})
|
||||
|
||||
export const notifications = {
|
||||
state: defaultState(),
|
||||
mutations: {
|
||||
addNewNotifications (state, { notifications }) {
|
||||
notifications.forEach(notification => {
|
||||
addNewNotifications(state, { notifications }) {
|
||||
notifications.forEach((notification) => {
|
||||
state.data.push(notification)
|
||||
state.idStore[notification.id] = notification
|
||||
})
|
||||
},
|
||||
clearNotifications (state) {
|
||||
clearNotifications(state) {
|
||||
const blankState = defaultState()
|
||||
Object.keys(state).forEach(k => {
|
||||
Object.keys(state).forEach((k) => {
|
||||
state[k] = blankState[k]
|
||||
})
|
||||
},
|
||||
updateNotificationsMinMaxId (state, id) {
|
||||
updateNotificationsMinMaxId(state, id) {
|
||||
state.maxId = id > state.maxId ? id : state.maxId
|
||||
state.minId = id < state.minId ? id : state.minId
|
||||
},
|
||||
setNotificationsLoading (state, { value }) {
|
||||
setNotificationsLoading(state, { value }) {
|
||||
state.loading = value
|
||||
},
|
||||
setNotificationsSilence (state, { value }) {
|
||||
setNotificationsSilence(state, { value }) {
|
||||
state.desktopNotificationSilence = value
|
||||
},
|
||||
markNotificationsAsSeen (state) {
|
||||
markNotificationsAsSeen(state) {
|
||||
state.data.forEach((notification) => {
|
||||
notification.seen = true
|
||||
})
|
||||
},
|
||||
markSingleNotificationAsSeen (state, { id }) {
|
||||
markSingleNotificationAsSeen(state, { id }) {
|
||||
const notification = state.idStore[id]
|
||||
if (notification) notification.seen = true
|
||||
},
|
||||
dismissNotification (state, { id }) {
|
||||
state.data = state.data.filter(n => n.id !== id)
|
||||
dismissNotification(state, { id }) {
|
||||
state.data = state.data.filter((n) => n.id !== id)
|
||||
delete state.idStore[id]
|
||||
},
|
||||
updateNotification (state, { id, updater }) {
|
||||
updateNotification(state, { id, updater }) {
|
||||
const notification = state.idStore[id]
|
||||
notification && updater(notification)
|
||||
}
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
addNewNotifications (store, { notifications }) {
|
||||
addNewNotifications(store, { notifications }) {
|
||||
const { commit, dispatch, state, rootState } = store
|
||||
const validNotifications = notifications.filter((notification) => {
|
||||
// If invalid notification, update ids but don't add it to store
|
||||
|
|
@ -83,13 +83,20 @@ export const notifications = {
|
|||
return true
|
||||
})
|
||||
|
||||
const statusNotifications = validNotifications.filter(notification => isStatusNotification(notification.type) && notification.status)
|
||||
const statusNotifications = validNotifications.filter(
|
||||
(notification) =>
|
||||
isStatusNotification(notification.type) && notification.status,
|
||||
)
|
||||
|
||||
// Synchronous commit to add all the statuses
|
||||
commit('addNewStatuses', { statuses: statusNotifications.map(notification => notification.status) })
|
||||
commit('addNewStatuses', {
|
||||
statuses: statusNotifications.map(
|
||||
(notification) => notification.status,
|
||||
),
|
||||
})
|
||||
|
||||
// Update references to statuses in notifications to ones in the store
|
||||
statusNotifications.forEach(notification => {
|
||||
statusNotifications.forEach((notification) => {
|
||||
const id = notification.status.id
|
||||
const referenceStatus = rootState.statuses.allStatusesObject[id]
|
||||
|
||||
|
|
@ -98,7 +105,7 @@ export const notifications = {
|
|||
}
|
||||
})
|
||||
|
||||
validNotifications.forEach(notification => {
|
||||
validNotifications.forEach((notification) => {
|
||||
if (notification.type === 'pleroma:report') {
|
||||
useReportsStore().addReport(notification.report)
|
||||
}
|
||||
|
|
@ -115,15 +122,17 @@ export const notifications = {
|
|||
|
||||
maybeShowNotification(
|
||||
store,
|
||||
Object.values(useServerSideStorageStore().prefsStorage.simple.muteFilters),
|
||||
notification
|
||||
Object.values(
|
||||
useServerSideStorageStore().prefsStorage.simple.muteFilters,
|
||||
),
|
||||
notification,
|
||||
)
|
||||
} else if (notification.seen) {
|
||||
state.idStore[notification.id].seen = true
|
||||
}
|
||||
})
|
||||
},
|
||||
notificationClicked ({ state, dispatch }, { id }) {
|
||||
notificationClicked({ state, dispatch }, { id }) {
|
||||
const notification = state.idStore[id]
|
||||
const { type, seen } = notification
|
||||
|
||||
|
|
@ -138,42 +147,46 @@ export const notifications = {
|
|||
}
|
||||
}
|
||||
},
|
||||
setNotificationsLoading ({ commit }, { value }) {
|
||||
setNotificationsLoading({ commit }, { value }) {
|
||||
commit('setNotificationsLoading', { value })
|
||||
},
|
||||
setNotificationsSilence ({ commit }, { value }) {
|
||||
setNotificationsSilence({ commit }, { value }) {
|
||||
commit('setNotificationsSilence', { value })
|
||||
},
|
||||
markNotificationsAsSeen ({ rootState, state, commit }) {
|
||||
markNotificationsAsSeen({ rootState, state, commit }) {
|
||||
commit('markNotificationsAsSeen')
|
||||
apiService.markNotificationsAsSeen({
|
||||
id: state.maxId,
|
||||
credentials: rootState.users.currentUser.credentials
|
||||
}).then(() => {
|
||||
closeAllDesktopNotifications(rootState)
|
||||
})
|
||||
apiService
|
||||
.markNotificationsAsSeen({
|
||||
id: state.maxId,
|
||||
credentials: rootState.users.currentUser.credentials,
|
||||
})
|
||||
.then(() => {
|
||||
closeAllDesktopNotifications(rootState)
|
||||
})
|
||||
},
|
||||
markSingleNotificationAsSeen ({ rootState, commit }, { id }) {
|
||||
markSingleNotificationAsSeen({ rootState, commit }, { id }) {
|
||||
commit('markSingleNotificationAsSeen', { id })
|
||||
apiService.markNotificationsAsSeen({
|
||||
single: true,
|
||||
id,
|
||||
credentials: rootState.users.currentUser.credentials
|
||||
}).then(() => {
|
||||
closeDesktopNotification(rootState, { id })
|
||||
})
|
||||
apiService
|
||||
.markNotificationsAsSeen({
|
||||
single: true,
|
||||
id,
|
||||
credentials: rootState.users.currentUser.credentials,
|
||||
})
|
||||
.then(() => {
|
||||
closeDesktopNotification(rootState, { id })
|
||||
})
|
||||
},
|
||||
dismissNotificationLocal ({ commit }, { id }) {
|
||||
dismissNotificationLocal({ commit }, { id }) {
|
||||
commit('dismissNotification', { id })
|
||||
},
|
||||
dismissNotification ({ rootState, commit }, { id }) {
|
||||
dismissNotification({ rootState, commit }, { id }) {
|
||||
commit('dismissNotification', { id })
|
||||
rootState.api.backendInteractor.dismissNotification({ id })
|
||||
},
|
||||
updateNotification ({ commit }, { id, updater }) {
|
||||
updateNotification({ commit }, { id, updater }) {
|
||||
commit('updateNotification', { id, updater })
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default notifications
|
||||
|
|
|
|||
|
|
@ -3,11 +3,9 @@ import { get, set } from 'lodash'
|
|||
const defaultApi = ({ rootState, commit }, { path, value }) => {
|
||||
const params = {}
|
||||
set(params, path, value)
|
||||
return rootState
|
||||
.api
|
||||
.backendInteractor
|
||||
return rootState.api.backendInteractor
|
||||
.updateProfile({ params })
|
||||
.then(result => {
|
||||
.then((result) => {
|
||||
commit('addNewUsers', [result])
|
||||
commit('setCurrentUser', result)
|
||||
})
|
||||
|
|
@ -16,11 +14,9 @@ const defaultApi = ({ rootState, commit }, { path, value }) => {
|
|||
const notificationsApi = ({ rootState, commit }, { path, value, oldValue }) => {
|
||||
const settings = {}
|
||||
set(settings, path, value)
|
||||
return rootState
|
||||
.api
|
||||
.backendInteractor
|
||||
return rootState.api.backendInteractor
|
||||
.updateNotificationSettings({ settings })
|
||||
.then(result => {
|
||||
.then((result) => {
|
||||
if (result.status === 'success') {
|
||||
commit('confirmProfileOption', { name, value })
|
||||
} else {
|
||||
|
|
@ -43,98 +39,99 @@ export const settingsMap = {
|
|||
defaultNSFW: 'source.sensitive', // BROKEN: pleroma/pleroma#2837
|
||||
stripRichContent: {
|
||||
get: 'source.pleroma.no_rich_text',
|
||||
set: 'no_rich_text'
|
||||
set: 'no_rich_text',
|
||||
},
|
||||
// Privacy
|
||||
locked: 'locked',
|
||||
acceptChatMessages: {
|
||||
get: 'pleroma.accepts_chat_messages',
|
||||
set: 'accepts_chat_messages'
|
||||
set: 'accepts_chat_messages',
|
||||
},
|
||||
allowFollowingMove: {
|
||||
get: 'pleroma.allow_following_move',
|
||||
set: 'allow_following_move'
|
||||
set: 'allow_following_move',
|
||||
},
|
||||
discoverable: {
|
||||
get: 'source.pleroma.discoverable',
|
||||
set: 'discoverable'
|
||||
set: 'discoverable',
|
||||
},
|
||||
hideFavorites: {
|
||||
get: 'pleroma.hide_favorites',
|
||||
set: 'hide_favorites'
|
||||
set: 'hide_favorites',
|
||||
},
|
||||
hideFollowers: {
|
||||
get: 'pleroma.hide_followers',
|
||||
set: 'hide_followers'
|
||||
set: 'hide_followers',
|
||||
},
|
||||
hideFollows: {
|
||||
get: 'pleroma.hide_follows',
|
||||
set: 'hide_follows'
|
||||
set: 'hide_follows',
|
||||
},
|
||||
hideFollowersCount: {
|
||||
get: 'pleroma.hide_followers_count',
|
||||
set: 'hide_followers_count'
|
||||
set: 'hide_followers_count',
|
||||
},
|
||||
hideFollowsCount: {
|
||||
get: 'pleroma.hide_follows_count',
|
||||
set: 'hide_follows_count'
|
||||
set: 'hide_follows_count',
|
||||
},
|
||||
// NotificationSettingsAPIs
|
||||
webPushHideContents: {
|
||||
get: 'pleroma.notification_settings.hide_notification_contents',
|
||||
set: 'hide_notification_contents',
|
||||
api: notificationsApi
|
||||
api: notificationsApi,
|
||||
},
|
||||
blockNotificationsFromStrangers: {
|
||||
get: 'pleroma.notification_settings.block_from_strangers',
|
||||
set: 'block_from_strangers',
|
||||
api: notificationsApi
|
||||
}
|
||||
api: notificationsApi,
|
||||
},
|
||||
}
|
||||
|
||||
export const defaultState = Object.fromEntries(Object.keys(settingsMap).map(key => [key, null]))
|
||||
export const defaultState = Object.fromEntries(
|
||||
Object.keys(settingsMap).map((key) => [key, null]),
|
||||
)
|
||||
|
||||
const profileConfig = {
|
||||
state: { ...defaultState },
|
||||
mutations: {
|
||||
confirmProfileOption (state, { name, value }) {
|
||||
confirmProfileOption(state, { name, value }) {
|
||||
set(state, name, value)
|
||||
},
|
||||
wipeProfileOption (state, { name }) {
|
||||
wipeProfileOption(state, { name }) {
|
||||
set(state, name, null)
|
||||
},
|
||||
wipeAllProfileOptions (state) {
|
||||
Object.keys(settingsMap).forEach(key => {
|
||||
wipeAllProfileOptions(state) {
|
||||
Object.keys(settingsMap).forEach((key) => {
|
||||
set(state, key, null)
|
||||
})
|
||||
},
|
||||
// Set the settings based on their path location
|
||||
setCurrentUser (state, user) {
|
||||
setCurrentUser(state, user) {
|
||||
Object.entries(settingsMap).forEach((map) => {
|
||||
const [name, value] = map
|
||||
const { get: path = value } = value
|
||||
set(state, name, get(user._original, path))
|
||||
})
|
||||
}
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
setProfileOption ({ rootState, state, commit }, { name, value }) {
|
||||
setProfileOption({ rootState, state, commit }, { name, value }) {
|
||||
const oldValue = get(state, name)
|
||||
const map = settingsMap[name]
|
||||
if (!map) throw new Error('Invalid server-side setting')
|
||||
const { set: path = map, api = defaultApi } = map
|
||||
commit('wipeProfileOption', { name })
|
||||
|
||||
api({ rootState, commit }, { path, value, oldValue })
|
||||
.catch((e) => {
|
||||
console.warn('Error setting server-side option:', e)
|
||||
commit('confirmProfileOption', { name, value: oldValue })
|
||||
})
|
||||
api({ rootState, commit }, { path, value, oldValue }).catch((e) => {
|
||||
console.warn('Error setting server-side option:', e)
|
||||
commit('confirmProfileOption', { name, value: oldValue })
|
||||
})
|
||||
},
|
||||
logout ({ commit }) {
|
||||
logout({ commit }) {
|
||||
commit('wipeAllProfileOptions')
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default profileConfig
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import {
|
|||
first,
|
||||
last,
|
||||
isArray,
|
||||
omitBy
|
||||
omitBy,
|
||||
} from 'lodash'
|
||||
import apiService from '../services/api/api.service.js'
|
||||
import { useInterfaceStore } from 'src/stores/interface'
|
||||
|
|
@ -29,7 +29,7 @@ const emptyTl = (userId = 0) => ({
|
|||
followers: [],
|
||||
friends: [],
|
||||
userId,
|
||||
flushMarker: 0
|
||||
flushMarker: 0,
|
||||
})
|
||||
|
||||
export const defaultState = () => ({
|
||||
|
|
@ -52,8 +52,8 @@ export const defaultState = () => ({
|
|||
dms: emptyTl(),
|
||||
bookmarks: emptyTl(),
|
||||
list: emptyTl(),
|
||||
bubble: emptyTl()
|
||||
}
|
||||
bubble: emptyTl(),
|
||||
},
|
||||
})
|
||||
|
||||
export const prepareStatus = (status) => {
|
||||
|
|
@ -73,7 +73,10 @@ const mergeOrAdd = (arr, obj, item) => {
|
|||
// We already have this, so only merge the new info.
|
||||
// We ignore null values to avoid overwriting existing properties with missing data
|
||||
// we also skip 'user' because that is handled by users module
|
||||
merge(oldItem, omitBy(item, (v, k) => v === null || k === 'user'))
|
||||
merge(
|
||||
oldItem,
|
||||
omitBy(item, (v, k) => v === null || k === 'user'),
|
||||
)
|
||||
// Reactivity fix.
|
||||
oldItem.attachments.splice(oldItem.attachments.length)
|
||||
return { item: oldItem, new: false }
|
||||
|
|
@ -116,26 +119,32 @@ const getLatestScrobble = (state, user) => {
|
|||
return
|
||||
}
|
||||
|
||||
if (state.scrobblesNextFetch[user.id] && state.scrobblesNextFetch[user.id] > Date.now()) {
|
||||
if (
|
||||
state.scrobblesNextFetch[user.id] &&
|
||||
state.scrobblesNextFetch[user.id] > Date.now()
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
state.scrobblesNextFetch[user.id] = Date.now() + 24 * 60 * 60 * 1000
|
||||
if (!scrobblesSupport) return
|
||||
apiService.fetchScrobbles({ accountId: user.id }).then((scrobbles) => {
|
||||
if (scrobbles?.error) {
|
||||
state.pleromaScrobblesAvailable = false
|
||||
return
|
||||
}
|
||||
apiService
|
||||
.fetchScrobbles({ accountId: user.id })
|
||||
.then((scrobbles) => {
|
||||
if (scrobbles?.error) {
|
||||
state.pleromaScrobblesAvailable = false
|
||||
return
|
||||
}
|
||||
|
||||
if (scrobbles.length > 0) {
|
||||
user.latestScrobble = scrobbles[0]
|
||||
if (scrobbles.length > 0) {
|
||||
user.latestScrobble = scrobbles[0]
|
||||
|
||||
state.scrobblesNextFetch[user.id] = Date.now() + 60 * 1000
|
||||
}
|
||||
}).catch(e => {
|
||||
console.warn('cannot fetch scrobbles', e)
|
||||
})
|
||||
state.scrobblesNextFetch[user.id] = Date.now() + 60 * 1000
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.warn('cannot fetch scrobbles', e)
|
||||
})
|
||||
}
|
||||
|
||||
// Add status to the global storages (arrays and objects maintaining statuses) except timelines
|
||||
|
|
@ -156,7 +165,18 @@ const addStatusToGlobalStorage = (state, data) => {
|
|||
return result
|
||||
}
|
||||
|
||||
const addNewStatuses = (state, { statuses, showImmediately = false, timeline, user = {}, noIdUpdate = false, userId, pagination = {} }) => {
|
||||
const addNewStatuses = (
|
||||
state,
|
||||
{
|
||||
statuses,
|
||||
showImmediately = false,
|
||||
timeline,
|
||||
user = {},
|
||||
noIdUpdate = false,
|
||||
userId,
|
||||
pagination = {},
|
||||
},
|
||||
) => {
|
||||
// Sanity check
|
||||
if (!isArray(statuses)) {
|
||||
return false
|
||||
|
|
@ -169,11 +189,19 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
|
|||
// pagination.maxId is the oldest of the returned statuses when fetching older,
|
||||
// and pagination.minId is the newest when fetching newer. The names come directly
|
||||
// from the arguments they're supposed to be passed as for the next fetch.
|
||||
const minNew = pagination.maxId || (statuses.length > 0 ? minBy(statuses, 'id').id : 0)
|
||||
const maxNew = pagination.minId || (statuses.length > 0 ? maxBy(statuses, 'id').id : 0)
|
||||
const minNew =
|
||||
pagination.maxId || (statuses.length > 0 ? minBy(statuses, 'id').id : 0)
|
||||
const maxNew =
|
||||
pagination.minId || (statuses.length > 0 ? maxBy(statuses, 'id').id : 0)
|
||||
|
||||
const newer = timeline && (maxNew > timelineObject.maxId || timelineObject.maxId === 0) && statuses.length > 0
|
||||
const older = timeline && (minNew < timelineObject.minId || timelineObject.minId === 0) && statuses.length > 0
|
||||
const newer =
|
||||
timeline &&
|
||||
(maxNew > timelineObject.maxId || timelineObject.maxId === 0) &&
|
||||
statuses.length > 0
|
||||
const older =
|
||||
timeline &&
|
||||
(minNew < timelineObject.minId || timelineObject.minId === 0) &&
|
||||
statuses.length > 0
|
||||
|
||||
if (!noIdUpdate && newer) {
|
||||
timelineObject.maxId = maxNew
|
||||
|
|
@ -185,7 +213,10 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
|
|||
// This makes sure that user timeline won't get data meant for other
|
||||
// user. I.e. opening different user profiles makes request which could
|
||||
// return data late after user already viewing different user profile
|
||||
if ((timeline === 'user' || timeline === 'media') && timelineObject.userId !== userId) {
|
||||
if (
|
||||
(timeline === 'user' || timeline === 'media') &&
|
||||
timelineObject.userId !== userId
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +226,10 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
|
|||
|
||||
if (result.new) {
|
||||
// We are mentioned in a post
|
||||
if (status.type === 'status' && find(status.attentions, { id: user.id })) {
|
||||
if (
|
||||
status.type === 'status' &&
|
||||
find(status.attentions, { id: user.id })
|
||||
) {
|
||||
const mentions = state.timelines.mentions
|
||||
|
||||
// Add the mention to the mentions timeline
|
||||
|
|
@ -220,20 +254,32 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
|
|||
let resultForCurrentTimeline
|
||||
// Some statuses should only be added to the global status repository.
|
||||
if (timeline && addToTimeline) {
|
||||
resultForCurrentTimeline = mergeOrAdd(timelineObject.statuses, timelineObject.statusesObject, status)
|
||||
resultForCurrentTimeline = mergeOrAdd(
|
||||
timelineObject.statuses,
|
||||
timelineObject.statusesObject,
|
||||
status,
|
||||
)
|
||||
}
|
||||
|
||||
if (timeline && showImmediately) {
|
||||
// Add it directly to the visibleStatuses, don't change
|
||||
// newStatusCount
|
||||
mergeOrAdd(timelineObject.visibleStatuses, timelineObject.visibleStatusesObject, status)
|
||||
mergeOrAdd(
|
||||
timelineObject.visibleStatuses,
|
||||
timelineObject.visibleStatusesObject,
|
||||
status,
|
||||
)
|
||||
} else if (timeline && addToTimeline && resultForCurrentTimeline.new) {
|
||||
// Just change newStatuscount
|
||||
timelineObject.newStatusCount += 1
|
||||
}
|
||||
|
||||
if (status.quote) {
|
||||
addStatus(status.quote, /* showImmediately = */ false, /* addToTimeline = */ false)
|
||||
addStatus(
|
||||
status.quote,
|
||||
/* showImmediately = */ false,
|
||||
/* addToTimeline = */ false,
|
||||
)
|
||||
}
|
||||
|
||||
return status
|
||||
|
|
@ -266,13 +312,19 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
|
|||
let retweet
|
||||
// If the retweeted status is already there, don't add the retweet
|
||||
// to the timeline.
|
||||
if (timeline && find(timelineObject.statuses, (s) => {
|
||||
if (s.retweeted_status) {
|
||||
return s.id === retweetedStatus.id || s.retweeted_status.id === retweetedStatus.id
|
||||
} else {
|
||||
return s.id === retweetedStatus.id
|
||||
}
|
||||
})) {
|
||||
if (
|
||||
timeline &&
|
||||
find(timelineObject.statuses, (s) => {
|
||||
if (s.retweeted_status) {
|
||||
return (
|
||||
s.id === retweetedStatus.id ||
|
||||
s.retweeted_status.id === retweetedStatus.id
|
||||
)
|
||||
} else {
|
||||
return s.id === retweetedStatus.id
|
||||
}
|
||||
})
|
||||
) {
|
||||
// Already have it visible (either as the original or another RT), don't add to timeline, don't show.
|
||||
retweet = addStatus(status, false, false)
|
||||
} else {
|
||||
|
|
@ -295,7 +347,7 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
|
|||
default: (unknown) => {
|
||||
console.warn('unknown status type')
|
||||
console.warn(unknown)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
each(statuses, (status) => {
|
||||
|
|
@ -315,35 +367,41 @@ const removeStatus = (state, { timeline, userId }) => {
|
|||
if (userId) {
|
||||
remove(timelineObject.statuses, { user: { id: userId } })
|
||||
remove(timelineObject.visibleStatuses, { user: { id: userId } })
|
||||
timelineObject.minVisibleId = timelineObject.visibleStatuses.length > 0 ? last(timelineObject.visibleStatuses).id : 0
|
||||
timelineObject.maxId = timelineObject.statuses.length > 0 ? first(timelineObject.statuses).id : 0
|
||||
timelineObject.minVisibleId =
|
||||
timelineObject.visibleStatuses.length > 0
|
||||
? last(timelineObject.visibleStatuses).id
|
||||
: 0
|
||||
timelineObject.maxId =
|
||||
timelineObject.statuses.length > 0 ? first(timelineObject.statuses).id : 0
|
||||
}
|
||||
}
|
||||
|
||||
export const mutations = {
|
||||
addNewStatuses,
|
||||
removeStatus,
|
||||
showNewStatuses (state, { timeline }) {
|
||||
const oldTimeline = (state.timelines[timeline])
|
||||
showNewStatuses(state, { timeline }) {
|
||||
const oldTimeline = state.timelines[timeline]
|
||||
|
||||
oldTimeline.newStatusCount = 0
|
||||
oldTimeline.visibleStatuses = slice(oldTimeline.statuses, 0, 50)
|
||||
oldTimeline.minVisibleId = last(oldTimeline.visibleStatuses).id
|
||||
oldTimeline.minId = oldTimeline.minVisibleId
|
||||
oldTimeline.visibleStatusesObject = {}
|
||||
each(oldTimeline.visibleStatuses, (status) => { oldTimeline.visibleStatusesObject[status.id] = status })
|
||||
each(oldTimeline.visibleStatuses, (status) => {
|
||||
oldTimeline.visibleStatusesObject[status.id] = status
|
||||
})
|
||||
},
|
||||
resetStatuses (state) {
|
||||
resetStatuses(state) {
|
||||
const emptyState = defaultState()
|
||||
Object.entries(emptyState).forEach(([key, value]) => {
|
||||
state[key] = value
|
||||
})
|
||||
},
|
||||
clearTimeline (state, { timeline, excludeUserId = false }) {
|
||||
clearTimeline(state, { timeline, excludeUserId = false }) {
|
||||
const userId = excludeUserId ? state.timelines[timeline].userId : undefined
|
||||
state.timelines[timeline] = emptyTl(userId)
|
||||
},
|
||||
setFavorited (state, { status, value }) {
|
||||
setFavorited(state, { status, value }) {
|
||||
const newStatus = state.allStatusesObject[status.id]
|
||||
|
||||
if (newStatus.favorited !== value) {
|
||||
|
|
@ -356,7 +414,7 @@ export const mutations = {
|
|||
|
||||
newStatus.favorited = value
|
||||
},
|
||||
setFavoritedConfirm (state, { status, user }) {
|
||||
setFavoritedConfirm(state, { status, user }) {
|
||||
const newStatus = state.allStatusesObject[status.id]
|
||||
newStatus.favorited = status.favorited
|
||||
newStatus.fave_num = status.fave_num
|
||||
|
|
@ -367,15 +425,19 @@ export const mutations = {
|
|||
newStatus.favoritedBy.push(user)
|
||||
}
|
||||
},
|
||||
setMutedStatus (state, status) {
|
||||
setMutedStatus(state, status) {
|
||||
const newStatus = state.allStatusesObject[status.id]
|
||||
newStatus.thread_muted = status.thread_muted
|
||||
|
||||
if (newStatus.thread_muted !== undefined) {
|
||||
state.conversationsObject[newStatus.statusnet_conversation_id].forEach(status => { status.thread_muted = newStatus.thread_muted })
|
||||
state.conversationsObject[newStatus.statusnet_conversation_id].forEach(
|
||||
(status) => {
|
||||
status.thread_muted = newStatus.thread_muted
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
setRetweeted (state, { status, value }) {
|
||||
setRetweeted(state, { status, value }) {
|
||||
const newStatus = state.allStatusesObject[status.id]
|
||||
|
||||
if (newStatus.repeated !== value) {
|
||||
|
|
@ -388,7 +450,7 @@ export const mutations = {
|
|||
|
||||
newStatus.repeated = value
|
||||
},
|
||||
setRetweetedConfirm (state, { status, user }) {
|
||||
setRetweetedConfirm(state, { status, user }) {
|
||||
const newStatus = state.allStatusesObject[status.id]
|
||||
newStatus.repeated = status.repeated
|
||||
newStatus.repeat_num = status.repeat_num
|
||||
|
|
@ -399,73 +461,79 @@ export const mutations = {
|
|||
newStatus.rebloggedBy.push(user)
|
||||
}
|
||||
},
|
||||
setBookmarked (state, { status, value }) {
|
||||
setBookmarked(state, { status, value }) {
|
||||
const newStatus = state.allStatusesObject[status.id]
|
||||
newStatus.bookmarked = value
|
||||
newStatus.bookmark_folder_id = status.bookmark_folder_id
|
||||
},
|
||||
setBookmarkedConfirm (state, { status }) {
|
||||
setBookmarkedConfirm(state, { status }) {
|
||||
const newStatus = state.allStatusesObject[status.id]
|
||||
newStatus.bookmarked = status.bookmarked
|
||||
if (status.pleroma) newStatus.bookmark_folder_id = status.pleroma.bookmark_folder
|
||||
if (status.pleroma)
|
||||
newStatus.bookmark_folder_id = status.pleroma.bookmark_folder
|
||||
},
|
||||
setDeleted (state, { status }) {
|
||||
setDeleted(state, { status }) {
|
||||
const newStatus = state.allStatusesObject[status.id]
|
||||
if (newStatus) newStatus.deleted = true
|
||||
},
|
||||
setManyDeleted (state, condition) {
|
||||
Object.values(state.allStatusesObject).forEach(status => {
|
||||
setManyDeleted(state, condition) {
|
||||
Object.values(state.allStatusesObject).forEach((status) => {
|
||||
if (condition(status)) {
|
||||
status.deleted = true
|
||||
}
|
||||
})
|
||||
},
|
||||
setLoading (state, { timeline, value }) {
|
||||
setLoading(state, { timeline, value }) {
|
||||
state.timelines[timeline].loading = value
|
||||
},
|
||||
setNsfw (state, { id, nsfw }) {
|
||||
setNsfw(state, { id, nsfw }) {
|
||||
const newStatus = state.allStatusesObject[id]
|
||||
newStatus.nsfw = nsfw
|
||||
},
|
||||
queueFlush (state, { timeline, id }) {
|
||||
queueFlush(state, { timeline, id }) {
|
||||
state.timelines[timeline].flushMarker = id
|
||||
},
|
||||
queueFlushAll (state) {
|
||||
queueFlushAll(state) {
|
||||
Object.keys(state.timelines).forEach((timeline) => {
|
||||
state.timelines[timeline].flushMarker = state.timelines[timeline].maxId
|
||||
})
|
||||
},
|
||||
addRepeats (state, { id, rebloggedByUsers, currentUser }) {
|
||||
addRepeats(state, { id, rebloggedByUsers, currentUser }) {
|
||||
const newStatus = state.allStatusesObject[id]
|
||||
newStatus.rebloggedBy = rebloggedByUsers.filter(_ => _)
|
||||
newStatus.rebloggedBy = rebloggedByUsers.filter((_) => _)
|
||||
// repeats stats can be incorrect based on polling condition, let's update them using the most recent data
|
||||
newStatus.repeat_num = newStatus.rebloggedBy.length
|
||||
newStatus.repeated = !!newStatus.rebloggedBy.find(({ id }) => currentUser.id === id)
|
||||
newStatus.repeated = !!newStatus.rebloggedBy.find(
|
||||
({ id }) => currentUser.id === id,
|
||||
)
|
||||
},
|
||||
addFavs (state, { id, favoritedByUsers, currentUser }) {
|
||||
addFavs(state, { id, favoritedByUsers, currentUser }) {
|
||||
const newStatus = state.allStatusesObject[id]
|
||||
newStatus.favoritedBy = favoritedByUsers.filter(_ => _)
|
||||
newStatus.favoritedBy = favoritedByUsers.filter((_) => _)
|
||||
// favorites stats can be incorrect based on polling condition, let's update them using the most recent data
|
||||
newStatus.fave_num = newStatus.favoritedBy.length
|
||||
newStatus.favorited = !!newStatus.favoritedBy.find(({ id }) => currentUser.id === id)
|
||||
newStatus.favorited = !!newStatus.favoritedBy.find(
|
||||
({ id }) => currentUser.id === id,
|
||||
)
|
||||
},
|
||||
addEmojiReactionsBy (state, { id, emojiReactions }) {
|
||||
addEmojiReactionsBy(state, { id, emojiReactions }) {
|
||||
const status = state.allStatusesObject[id]
|
||||
status.emoji_reactions = emojiReactions
|
||||
},
|
||||
addOwnReaction (state, { id, emoji, currentUser }) {
|
||||
addOwnReaction(state, { id, emoji, currentUser }) {
|
||||
const status = state.allStatusesObject[id]
|
||||
const reactionIndex = findIndex(status.emoji_reactions, { name: emoji })
|
||||
const reaction = status.emoji_reactions[reactionIndex] || { name: emoji, count: 0, accounts: [] }
|
||||
const reaction = status.emoji_reactions[reactionIndex] || {
|
||||
name: emoji,
|
||||
count: 0,
|
||||
accounts: [],
|
||||
}
|
||||
|
||||
const newReaction = {
|
||||
...reaction,
|
||||
count: reaction.count + 1,
|
||||
me: true,
|
||||
accounts: [
|
||||
...reaction.accounts,
|
||||
currentUser
|
||||
]
|
||||
accounts: [...reaction.accounts, currentUser],
|
||||
}
|
||||
|
||||
// Update count of existing reaction if it exists, otherwise append at the end
|
||||
|
|
@ -475,7 +543,7 @@ export const mutations = {
|
|||
status.emoji_reactions = [...status.emoji_reactions, newReaction]
|
||||
}
|
||||
},
|
||||
removeOwnReaction (state, { id, emoji, currentUser }) {
|
||||
removeOwnReaction(state, { id, emoji, currentUser }) {
|
||||
const status = state.allStatusesObject[id]
|
||||
const reactionIndex = findIndex(status.emoji_reactions, { name: emoji })
|
||||
if (reactionIndex < 0) return
|
||||
|
|
@ -487,42 +555,70 @@ export const mutations = {
|
|||
...reaction,
|
||||
count: reaction.count - 1,
|
||||
me: false,
|
||||
accounts: accounts.filter(acc => acc.id !== currentUser.id)
|
||||
accounts: accounts.filter((acc) => acc.id !== currentUser.id),
|
||||
}
|
||||
|
||||
if (newReaction.count > 0) {
|
||||
status.emoji_reactions[reactionIndex] = newReaction
|
||||
} else {
|
||||
status.emoji_reactions = status.emoji_reactions.filter(r => r.name !== emoji)
|
||||
status.emoji_reactions = status.emoji_reactions.filter(
|
||||
(r) => r.name !== emoji,
|
||||
)
|
||||
}
|
||||
},
|
||||
updateStatusWithPoll (state, { id, poll }) {
|
||||
updateStatusWithPoll(state, { id, poll }) {
|
||||
const status = state.allStatusesObject[id]
|
||||
status.poll = poll
|
||||
},
|
||||
setVirtualHeight (state, { statusId, height }) {
|
||||
setVirtualHeight(state, { statusId, height }) {
|
||||
state.allStatusesObject[statusId].virtualHeight = height
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
const statuses = {
|
||||
state: defaultState(),
|
||||
actions: {
|
||||
addNewStatuses ({ rootState, commit }, { statuses, showImmediately = false, timeline = false, noIdUpdate = false, userId, pagination }) {
|
||||
commit('addNewStatuses', { statuses, showImmediately, timeline, noIdUpdate, user: rootState.users.currentUser, userId, pagination })
|
||||
addNewStatuses(
|
||||
{ rootState, commit },
|
||||
{
|
||||
statuses,
|
||||
showImmediately = false,
|
||||
timeline = false,
|
||||
noIdUpdate = false,
|
||||
userId,
|
||||
pagination,
|
||||
},
|
||||
) {
|
||||
commit('addNewStatuses', {
|
||||
statuses,
|
||||
showImmediately,
|
||||
timeline,
|
||||
noIdUpdate,
|
||||
user: rootState.users.currentUser,
|
||||
userId,
|
||||
pagination,
|
||||
})
|
||||
},
|
||||
fetchStatus ({ rootState, dispatch }, id) {
|
||||
return rootState.api.backendInteractor.fetchStatus({ id })
|
||||
fetchStatus({ rootState, dispatch }, id) {
|
||||
return rootState.api.backendInteractor
|
||||
.fetchStatus({ id })
|
||||
.then((status) => dispatch('addNewStatuses', { statuses: [status] }))
|
||||
},
|
||||
fetchStatusSource ({ rootState }, status) {
|
||||
return apiService.fetchStatusSource({ id: status.id, credentials: rootState.users.currentUser.credentials })
|
||||
fetchStatusSource({ rootState }, status) {
|
||||
return apiService.fetchStatusSource({
|
||||
id: status.id,
|
||||
credentials: rootState.users.currentUser.credentials,
|
||||
})
|
||||
},
|
||||
fetchStatusHistory (_, status) {
|
||||
fetchStatusHistory(_, status) {
|
||||
return apiService.fetchStatusHistory({ status })
|
||||
},
|
||||
deleteStatus ({ rootState, commit }, status) {
|
||||
apiService.deleteStatus({ id: status.id, credentials: rootState.users.currentUser.credentials })
|
||||
deleteStatus({ rootState, commit }, status) {
|
||||
apiService
|
||||
.deleteStatus({
|
||||
id: status.id,
|
||||
credentials: rootState.users.currentUser.credentials,
|
||||
})
|
||||
.then(() => {
|
||||
commit('setDeleted', { status })
|
||||
})
|
||||
|
|
@ -531,141 +627,208 @@ const statuses = {
|
|||
level: 'error',
|
||||
messageKey: 'status.delete_error',
|
||||
messageArgs: [e.message],
|
||||
timeout: 5000
|
||||
timeout: 5000,
|
||||
})
|
||||
})
|
||||
},
|
||||
deleteStatusById ({ rootState, commit }, id) {
|
||||
deleteStatusById({ rootState, commit }, id) {
|
||||
const status = rootState.statuses.allStatusesObject[id]
|
||||
commit('setDeleted', { status })
|
||||
},
|
||||
markStatusesAsDeleted ({ commit }, condition) {
|
||||
markStatusesAsDeleted({ commit }, condition) {
|
||||
commit('setManyDeleted', condition)
|
||||
},
|
||||
favorite ({ rootState, commit }, status) {
|
||||
favorite({ rootState, commit }, status) {
|
||||
// Optimistic favoriting...
|
||||
commit('setFavorited', { status, value: true })
|
||||
rootState.api.backendInteractor.favorite({ id: status.id })
|
||||
.then(status => commit('setFavoritedConfirm', { status, user: rootState.users.currentUser }))
|
||||
rootState.api.backendInteractor
|
||||
.favorite({ id: status.id })
|
||||
.then((status) =>
|
||||
commit('setFavoritedConfirm', {
|
||||
status,
|
||||
user: rootState.users.currentUser,
|
||||
}),
|
||||
)
|
||||
},
|
||||
unfavorite ({ rootState, commit }, status) {
|
||||
unfavorite({ rootState, commit }, status) {
|
||||
// Optimistic unfavoriting...
|
||||
commit('setFavorited', { status, value: false })
|
||||
rootState.api.backendInteractor.unfavorite({ id: status.id })
|
||||
.then(status => commit('setFavoritedConfirm', { status, user: rootState.users.currentUser }))
|
||||
rootState.api.backendInteractor
|
||||
.unfavorite({ id: status.id })
|
||||
.then((status) =>
|
||||
commit('setFavoritedConfirm', {
|
||||
status,
|
||||
user: rootState.users.currentUser,
|
||||
}),
|
||||
)
|
||||
},
|
||||
fetchPinnedStatuses ({ rootState, dispatch }, userId) {
|
||||
rootState.api.backendInteractor.fetchPinnedStatuses({ id: userId })
|
||||
.then(statuses => dispatch('addNewStatuses', { statuses, timeline: 'user', userId, showImmediately: true, noIdUpdate: true }))
|
||||
fetchPinnedStatuses({ rootState, dispatch }, userId) {
|
||||
rootState.api.backendInteractor
|
||||
.fetchPinnedStatuses({ id: userId })
|
||||
.then((statuses) =>
|
||||
dispatch('addNewStatuses', {
|
||||
statuses,
|
||||
timeline: 'user',
|
||||
userId,
|
||||
showImmediately: true,
|
||||
noIdUpdate: true,
|
||||
}),
|
||||
)
|
||||
},
|
||||
pinStatus ({ rootState, dispatch }, statusId) {
|
||||
return rootState.api.backendInteractor.pinOwnStatus({ id: statusId })
|
||||
pinStatus({ rootState, dispatch }, statusId) {
|
||||
return rootState.api.backendInteractor
|
||||
.pinOwnStatus({ id: statusId })
|
||||
.then((status) => dispatch('addNewStatuses', { statuses: [status] }))
|
||||
},
|
||||
unpinStatus ({ rootState, dispatch }, statusId) {
|
||||
rootState.api.backendInteractor.unpinOwnStatus({ id: statusId })
|
||||
unpinStatus({ rootState, dispatch }, statusId) {
|
||||
rootState.api.backendInteractor
|
||||
.unpinOwnStatus({ id: statusId })
|
||||
.then((status) => dispatch('addNewStatuses', { statuses: [status] }))
|
||||
},
|
||||
muteConversation ({ rootState, commit }, { id: statusId }) {
|
||||
return rootState.api.backendInteractor.muteConversation({ id: statusId })
|
||||
muteConversation({ rootState, commit }, { id: statusId }) {
|
||||
return rootState.api.backendInteractor
|
||||
.muteConversation({ id: statusId })
|
||||
.then((status) => commit('setMutedStatus', status))
|
||||
},
|
||||
unmuteConversation ({ rootState, commit }, { id: statusId }) {
|
||||
return rootState.api.backendInteractor.unmuteConversation({ id: statusId })
|
||||
unmuteConversation({ rootState, commit }, { id: statusId }) {
|
||||
return rootState.api.backendInteractor
|
||||
.unmuteConversation({ id: statusId })
|
||||
.then((status) => commit('setMutedStatus', status))
|
||||
},
|
||||
retweet ({ rootState, commit }, status) {
|
||||
retweet({ rootState, commit }, status) {
|
||||
// Optimistic retweeting...
|
||||
commit('setRetweeted', { status, value: true })
|
||||
rootState.api.backendInteractor.retweet({ id: status.id })
|
||||
.then(status => commit('setRetweetedConfirm', { status: status.retweeted_status, user: rootState.users.currentUser }))
|
||||
rootState.api.backendInteractor
|
||||
.retweet({ id: status.id })
|
||||
.then((status) =>
|
||||
commit('setRetweetedConfirm', {
|
||||
status: status.retweeted_status,
|
||||
user: rootState.users.currentUser,
|
||||
}),
|
||||
)
|
||||
},
|
||||
unretweet ({ rootState, commit }, status) {
|
||||
unretweet({ rootState, commit }, status) {
|
||||
// Optimistic unretweeting...
|
||||
commit('setRetweeted', { status, value: false })
|
||||
rootState.api.backendInteractor.unretweet({ id: status.id })
|
||||
.then(status => commit('setRetweetedConfirm', { status, user: rootState.users.currentUser }))
|
||||
rootState.api.backendInteractor
|
||||
.unretweet({ id: status.id })
|
||||
.then((status) =>
|
||||
commit('setRetweetedConfirm', {
|
||||
status,
|
||||
user: rootState.users.currentUser,
|
||||
}),
|
||||
)
|
||||
},
|
||||
bookmark ({ rootState, commit }, status) {
|
||||
bookmark({ rootState, commit }, status) {
|
||||
commit('setBookmarked', { status, value: true })
|
||||
rootState.api.backendInteractor.bookmarkStatus({ id: status.id, folder_id: status.bookmark_folder_id })
|
||||
.then(status => {
|
||||
rootState.api.backendInteractor
|
||||
.bookmarkStatus({ id: status.id, folder_id: status.bookmark_folder_id })
|
||||
.then((status) => {
|
||||
commit('setBookmarkedConfirm', { status })
|
||||
})
|
||||
},
|
||||
unbookmark ({ rootState, commit }, status) {
|
||||
unbookmark({ rootState, commit }, status) {
|
||||
commit('setBookmarked', { status, value: false })
|
||||
rootState.api.backendInteractor.unbookmarkStatus({ id: status.id })
|
||||
.then(status => {
|
||||
rootState.api.backendInteractor
|
||||
.unbookmarkStatus({ id: status.id })
|
||||
.then((status) => {
|
||||
commit('setBookmarkedConfirm', { status })
|
||||
})
|
||||
},
|
||||
queueFlush ({ commit }, { timeline, id }) {
|
||||
queueFlush({ commit }, { timeline, id }) {
|
||||
commit('queueFlush', { timeline, id })
|
||||
},
|
||||
queueFlushAll ({ commit }) {
|
||||
queueFlushAll({ commit }) {
|
||||
commit('queueFlushAll')
|
||||
},
|
||||
fetchFavsAndRepeats ({ rootState, commit }, id) {
|
||||
fetchFavsAndRepeats({ rootState, commit }, id) {
|
||||
Promise.all([
|
||||
rootState.api.backendInteractor.fetchFavoritedByUsers({ id }),
|
||||
rootState.api.backendInteractor.fetchRebloggedByUsers({ id })
|
||||
rootState.api.backendInteractor.fetchRebloggedByUsers({ id }),
|
||||
]).then(([favoritedByUsers, rebloggedByUsers]) => {
|
||||
commit('addFavs', { id, favoritedByUsers, currentUser: rootState.users.currentUser })
|
||||
commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser })
|
||||
commit('addFavs', {
|
||||
id,
|
||||
favoritedByUsers,
|
||||
currentUser: rootState.users.currentUser,
|
||||
})
|
||||
commit('addRepeats', {
|
||||
id,
|
||||
rebloggedByUsers,
|
||||
currentUser: rootState.users.currentUser,
|
||||
})
|
||||
})
|
||||
},
|
||||
reactWithEmoji ({ rootState, dispatch, commit }, { id, emoji }) {
|
||||
reactWithEmoji({ rootState, dispatch, commit }, { id, emoji }) {
|
||||
const currentUser = rootState.users.currentUser
|
||||
if (!currentUser) return
|
||||
|
||||
commit('addOwnReaction', { id, emoji, currentUser })
|
||||
rootState.api.backendInteractor.reactWithEmoji({ id, emoji }).then(
|
||||
() => {
|
||||
dispatch('fetchEmojiReactionsBy', id)
|
||||
}
|
||||
)
|
||||
rootState.api.backendInteractor.reactWithEmoji({ id, emoji }).then(() => {
|
||||
dispatch('fetchEmojiReactionsBy', id)
|
||||
})
|
||||
},
|
||||
unreactWithEmoji ({ rootState, dispatch, commit }, { id, emoji }) {
|
||||
unreactWithEmoji({ rootState, dispatch, commit }, { id, emoji }) {
|
||||
const currentUser = rootState.users.currentUser
|
||||
if (!currentUser) return
|
||||
|
||||
commit('removeOwnReaction', { id, emoji, currentUser })
|
||||
rootState.api.backendInteractor.unreactWithEmoji({ id, emoji }).then(
|
||||
() => {
|
||||
rootState.api.backendInteractor
|
||||
.unreactWithEmoji({ id, emoji })
|
||||
.then(() => {
|
||||
dispatch('fetchEmojiReactionsBy', id)
|
||||
}
|
||||
)
|
||||
})
|
||||
},
|
||||
fetchEmojiReactionsBy ({ rootState, commit }, id) {
|
||||
return rootState.api.backendInteractor.fetchEmojiReactions({ id }).then(
|
||||
emojiReactions => {
|
||||
commit('addEmojiReactionsBy', { id, emojiReactions, currentUser: rootState.users.currentUser })
|
||||
}
|
||||
)
|
||||
fetchEmojiReactionsBy({ rootState, commit }, id) {
|
||||
return rootState.api.backendInteractor
|
||||
.fetchEmojiReactions({ id })
|
||||
.then((emojiReactions) => {
|
||||
commit('addEmojiReactionsBy', {
|
||||
id,
|
||||
emojiReactions,
|
||||
currentUser: rootState.users.currentUser,
|
||||
})
|
||||
})
|
||||
},
|
||||
fetchFavs ({ rootState, commit }, id) {
|
||||
rootState.api.backendInteractor.fetchFavoritedByUsers({ id })
|
||||
.then(favoritedByUsers => commit('addFavs', { id, favoritedByUsers, currentUser: rootState.users.currentUser }))
|
||||
fetchFavs({ rootState, commit }, id) {
|
||||
rootState.api.backendInteractor
|
||||
.fetchFavoritedByUsers({ id })
|
||||
.then((favoritedByUsers) =>
|
||||
commit('addFavs', {
|
||||
id,
|
||||
favoritedByUsers,
|
||||
currentUser: rootState.users.currentUser,
|
||||
}),
|
||||
)
|
||||
},
|
||||
fetchRepeats ({ rootState, commit }, id) {
|
||||
rootState.api.backendInteractor.fetchRebloggedByUsers({ id })
|
||||
.then(rebloggedByUsers => commit('addRepeats', { id, rebloggedByUsers, currentUser: rootState.users.currentUser }))
|
||||
fetchRepeats({ rootState, commit }, id) {
|
||||
rootState.api.backendInteractor
|
||||
.fetchRebloggedByUsers({ id })
|
||||
.then((rebloggedByUsers) =>
|
||||
commit('addRepeats', {
|
||||
id,
|
||||
rebloggedByUsers,
|
||||
currentUser: rootState.users.currentUser,
|
||||
}),
|
||||
)
|
||||
},
|
||||
search (store, { q, resolve, limit, offset, following, type }) {
|
||||
return store.rootState.api.backendInteractor.search2({ q, resolve, limit, offset, following, type })
|
||||
search(store, { q, resolve, limit, offset, following, type }) {
|
||||
return store.rootState.api.backendInteractor
|
||||
.search2({ q, resolve, limit, offset, following, type })
|
||||
.then((data) => {
|
||||
store.commit('addNewUsers', data.accounts)
|
||||
store.commit('addNewUsers', data.statuses.map(s => s.user).filter(u => u))
|
||||
store.commit(
|
||||
'addNewUsers',
|
||||
data.statuses.map((s) => s.user).filter((u) => u),
|
||||
)
|
||||
store.commit('addNewStatuses', { statuses: data.statuses })
|
||||
return data
|
||||
})
|
||||
},
|
||||
setVirtualHeight ({ commit }, { statusId, height }) {
|
||||
setVirtualHeight({ commit }, { statusId, height }) {
|
||||
commit('setVirtualHeight', { statusId, height })
|
||||
}
|
||||
},
|
||||
},
|
||||
mutations
|
||||
mutations,
|
||||
}
|
||||
|
||||
export default statuses
|
||||
|
|
|
|||
|
|
@ -1,10 +1,25 @@
|
|||
import { compact, map, each, mergeWith, last, concat, uniq, isArray } from 'lodash'
|
||||
import {
|
||||
compact,
|
||||
map,
|
||||
each,
|
||||
mergeWith,
|
||||
last,
|
||||
concat,
|
||||
uniq,
|
||||
isArray,
|
||||
} from 'lodash'
|
||||
|
||||
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
|
||||
import { windowWidth, windowHeight } from '../services/window_utils/window_utils'
|
||||
import {
|
||||
windowWidth,
|
||||
windowHeight,
|
||||
} from '../services/window_utils/window_utils'
|
||||
import apiService from '../services/api/api.service.js'
|
||||
import oauthApi from '../services/new_api/oauth.js'
|
||||
import { registerPushNotifications, unregisterPushNotifications } from '../services/sw/sw.js'
|
||||
import {
|
||||
registerPushNotifications,
|
||||
unregisterPushNotifications,
|
||||
} from '../services/sw/sw.js'
|
||||
|
||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||
|
|
@ -14,7 +29,9 @@ import { declarations } from 'src/modules/config_declaration'
|
|||
|
||||
// TODO: Unify with mergeOrAdd in statuses.js
|
||||
export const mergeOrAdd = (arr, obj, item) => {
|
||||
if (!item) { return false }
|
||||
if (!item) {
|
||||
return false
|
||||
}
|
||||
const oldItem = obj[item.id]
|
||||
if (oldItem) {
|
||||
// We already have this, so only merge the new info.
|
||||
|
|
@ -39,7 +56,8 @@ const getNotificationPermission = () => {
|
|||
const Notification = window.Notification
|
||||
|
||||
if (!Notification) return Promise.resolve(null)
|
||||
if (Notification.permission === 'default') return Notification.requestPermission()
|
||||
if (Notification.permission === 'default')
|
||||
return Notification.requestPermission()
|
||||
return Promise.resolve(Notification.permission)
|
||||
}
|
||||
|
||||
|
|
@ -51,30 +69,43 @@ const blockUser = (store, args) => {
|
|||
store.commit('updateUserRelationship', [predictedRelationship])
|
||||
store.commit('addBlockId', id)
|
||||
|
||||
return store.rootState.api.backendInteractor.blockUser({ id, expiresIn })
|
||||
return store.rootState.api.backendInteractor
|
||||
.blockUser({ id, expiresIn })
|
||||
.then((relationship) => {
|
||||
store.commit('updateUserRelationship', [relationship])
|
||||
store.commit('addBlockId', id)
|
||||
|
||||
store.commit('removeStatus', { timeline: 'friends', userId: id })
|
||||
store.commit('removeStatus', { timeline: 'public', userId: id })
|
||||
store.commit('removeStatus', { timeline: 'publicAndExternal', userId: id })
|
||||
store.commit('removeStatus', {
|
||||
timeline: 'publicAndExternal',
|
||||
userId: id,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const unblockUser = (store, id) => {
|
||||
return store.rootState.api.backendInteractor.unblockUser({ id })
|
||||
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
||||
return store.rootState.api.backendInteractor
|
||||
.unblockUser({ id })
|
||||
.then((relationship) =>
|
||||
store.commit('updateUserRelationship', [relationship]),
|
||||
)
|
||||
}
|
||||
|
||||
const removeUserFromFollowers = (store, id) => {
|
||||
return store.rootState.api.backendInteractor.removeUserFromFollowers({ id })
|
||||
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
||||
return store.rootState.api.backendInteractor
|
||||
.removeUserFromFollowers({ id })
|
||||
.then((relationship) =>
|
||||
store.commit('updateUserRelationship', [relationship]),
|
||||
)
|
||||
}
|
||||
|
||||
const editUserNote = (store, { id, comment }) => {
|
||||
return store.rootState.api.backendInteractor.editUserNote({ id, comment })
|
||||
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
||||
return store.rootState.api.backendInteractor
|
||||
.editUserNote({ id, comment })
|
||||
.then((relationship) =>
|
||||
store.commit('updateUserRelationship', [relationship]),
|
||||
)
|
||||
}
|
||||
|
||||
const muteUser = (store, args) => {
|
||||
|
|
@ -85,7 +116,8 @@ const muteUser = (store, args) => {
|
|||
store.commit('updateUserRelationship', [predictedRelationship])
|
||||
store.commit('addMuteId', id)
|
||||
|
||||
return store.rootState.api.backendInteractor.muteUser({ id, expiresIn })
|
||||
return store.rootState.api.backendInteractor
|
||||
.muteUser({ id, expiresIn })
|
||||
.then((relationship) => {
|
||||
store.commit('updateUserRelationship', [relationship])
|
||||
store.commit('addMuteId', id)
|
||||
|
|
@ -97,92 +129,105 @@ const unmuteUser = (store, id) => {
|
|||
predictedRelationship.muting = false
|
||||
store.commit('updateUserRelationship', [predictedRelationship])
|
||||
|
||||
return store.rootState.api.backendInteractor.unmuteUser({ id })
|
||||
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
||||
return store.rootState.api.backendInteractor
|
||||
.unmuteUser({ id })
|
||||
.then((relationship) =>
|
||||
store.commit('updateUserRelationship', [relationship]),
|
||||
)
|
||||
}
|
||||
|
||||
const hideReblogs = (store, userId) => {
|
||||
return store.rootState.api.backendInteractor.followUser({ id: userId, reblogs: false })
|
||||
return store.rootState.api.backendInteractor
|
||||
.followUser({ id: userId, reblogs: false })
|
||||
.then((relationship) => {
|
||||
store.commit('updateUserRelationship', [relationship])
|
||||
})
|
||||
}
|
||||
|
||||
const showReblogs = (store, userId) => {
|
||||
return store.rootState.api.backendInteractor.followUser({ id: userId, reblogs: true })
|
||||
.then((relationship) => store.commit('updateUserRelationship', [relationship]))
|
||||
return store.rootState.api.backendInteractor
|
||||
.followUser({ id: userId, reblogs: true })
|
||||
.then((relationship) =>
|
||||
store.commit('updateUserRelationship', [relationship]),
|
||||
)
|
||||
}
|
||||
|
||||
const muteDomain = (store, domain) => {
|
||||
return store.rootState.api.backendInteractor.muteDomain({ domain })
|
||||
return store.rootState.api.backendInteractor
|
||||
.muteDomain({ domain })
|
||||
.then(() => store.commit('addDomainMute', domain))
|
||||
}
|
||||
|
||||
const unmuteDomain = (store, domain) => {
|
||||
return store.rootState.api.backendInteractor.unmuteDomain({ domain })
|
||||
return store.rootState.api.backendInteractor
|
||||
.unmuteDomain({ domain })
|
||||
.then(() => store.commit('removeDomainMute', domain))
|
||||
}
|
||||
|
||||
export const mutations = {
|
||||
tagUser (state, { user: { id }, tag }) {
|
||||
tagUser(state, { user: { id }, tag }) {
|
||||
const user = state.usersObject[id]
|
||||
const tags = user.tags || []
|
||||
const newTags = tags.concat([tag])
|
||||
user.tags = newTags
|
||||
},
|
||||
untagUser (state, { user: { id }, tag }) {
|
||||
untagUser(state, { user: { id }, tag }) {
|
||||
const user = state.usersObject[id]
|
||||
const tags = user.tags || []
|
||||
const newTags = tags.filter(t => t !== tag)
|
||||
const newTags = tags.filter((t) => t !== tag)
|
||||
user.tags = newTags
|
||||
},
|
||||
updateRight (state, { user: { id }, right, value }) {
|
||||
updateRight(state, { user: { id }, right, value }) {
|
||||
const user = state.usersObject[id]
|
||||
const newRights = user.rights
|
||||
newRights[right] = value
|
||||
user.rights = newRights
|
||||
},
|
||||
updateActivationStatus (state, { user: { id }, deactivated }) {
|
||||
updateActivationStatus(state, { user: { id }, deactivated }) {
|
||||
const user = state.usersObject[id]
|
||||
user.deactivated = deactivated
|
||||
},
|
||||
setCurrentUser (state, user) {
|
||||
setCurrentUser(state, user) {
|
||||
state.lastLoginName = user.screen_name
|
||||
state.currentUser = mergeWith(state.currentUser || {}, user, mergeArrayLength)
|
||||
state.currentUser = mergeWith(
|
||||
state.currentUser || {},
|
||||
user,
|
||||
mergeArrayLength,
|
||||
)
|
||||
},
|
||||
clearCurrentUser (state) {
|
||||
clearCurrentUser(state) {
|
||||
state.currentUser = false
|
||||
state.lastLoginName = false
|
||||
},
|
||||
beginLogin (state) {
|
||||
beginLogin(state) {
|
||||
state.loggingIn = true
|
||||
},
|
||||
endLogin (state) {
|
||||
endLogin(state) {
|
||||
state.loggingIn = false
|
||||
},
|
||||
saveFriendIds (state, { id, friendIds }) {
|
||||
saveFriendIds(state, { id, friendIds }) {
|
||||
const user = state.usersObject[id]
|
||||
user.friendIds = uniq(concat(user.friendIds || [], friendIds))
|
||||
},
|
||||
saveFollowerIds (state, { id, followerIds }) {
|
||||
saveFollowerIds(state, { id, followerIds }) {
|
||||
const user = state.usersObject[id]
|
||||
user.followerIds = uniq(concat(user.followerIds || [], followerIds))
|
||||
},
|
||||
// Because frontend doesn't have a reason to keep these stuff in memory
|
||||
// outside of viewing someones user profile.
|
||||
clearFriends (state, userId) {
|
||||
clearFriends(state, userId) {
|
||||
const user = state.usersObject[userId]
|
||||
if (user) {
|
||||
user.friendIds = []
|
||||
}
|
||||
},
|
||||
clearFollowers (state, userId) {
|
||||
clearFollowers(state, userId) {
|
||||
const user = state.usersObject[userId]
|
||||
if (user) {
|
||||
user.followerIds = []
|
||||
}
|
||||
},
|
||||
addNewUsers (state, users) {
|
||||
addNewUsers(state, users) {
|
||||
each(users, (user) => {
|
||||
if (user.relationship) {
|
||||
state.relationships[user.relationship.id] = user.relationship
|
||||
|
|
@ -194,51 +239,51 @@ export const mutations = {
|
|||
}
|
||||
})
|
||||
},
|
||||
updateUserRelationship (state, relationships) {
|
||||
updateUserRelationship(state, relationships) {
|
||||
relationships.forEach((relationship) => {
|
||||
state.relationships[relationship.id] = relationship
|
||||
})
|
||||
},
|
||||
updateUserInLists (state, { id, inLists }) {
|
||||
updateUserInLists(state, { id, inLists }) {
|
||||
state.usersObject[id].inLists = inLists
|
||||
},
|
||||
saveBlockIds (state, blockIds) {
|
||||
saveBlockIds(state, blockIds) {
|
||||
state.currentUser.blockIds = blockIds
|
||||
},
|
||||
addBlockId (state, blockId) {
|
||||
addBlockId(state, blockId) {
|
||||
if (state.currentUser.blockIds.indexOf(blockId) === -1) {
|
||||
state.currentUser.blockIds.push(blockId)
|
||||
}
|
||||
},
|
||||
setBlockIdsMaxId (state, blockIdsMaxId) {
|
||||
setBlockIdsMaxId(state, blockIdsMaxId) {
|
||||
state.currentUser.blockIdsMaxId = blockIdsMaxId
|
||||
},
|
||||
saveMuteIds (state, muteIds) {
|
||||
saveMuteIds(state, muteIds) {
|
||||
state.currentUser.muteIds = muteIds
|
||||
},
|
||||
setMuteIdsMaxId (state, muteIdsMaxId) {
|
||||
setMuteIdsMaxId(state, muteIdsMaxId) {
|
||||
state.currentUser.muteIdsMaxId = muteIdsMaxId
|
||||
},
|
||||
addMuteId (state, muteId) {
|
||||
addMuteId(state, muteId) {
|
||||
if (state.currentUser.muteIds.indexOf(muteId) === -1) {
|
||||
state.currentUser.muteIds.push(muteId)
|
||||
}
|
||||
},
|
||||
saveDomainMutes (state, domainMutes) {
|
||||
saveDomainMutes(state, domainMutes) {
|
||||
state.currentUser.domainMutes = domainMutes
|
||||
},
|
||||
addDomainMute (state, domain) {
|
||||
addDomainMute(state, domain) {
|
||||
if (state.currentUser.domainMutes.indexOf(domain) === -1) {
|
||||
state.currentUser.domainMutes.push(domain)
|
||||
}
|
||||
},
|
||||
removeDomainMute (state, domain) {
|
||||
removeDomainMute(state, domain) {
|
||||
const index = state.currentUser.domainMutes.indexOf(domain)
|
||||
if (index !== -1) {
|
||||
state.currentUser.domainMutes.splice(index, 1)
|
||||
}
|
||||
},
|
||||
setPinnedToUser (state, status) {
|
||||
setPinnedToUser(state, status) {
|
||||
const user = state.usersObject[status.user.id]
|
||||
user.pinnedStatusIds = user.pinnedStatusIds || []
|
||||
const index = user.pinnedStatusIds.indexOf(status.id)
|
||||
|
|
@ -249,55 +294,57 @@ export const mutations = {
|
|||
user.pinnedStatusIds.splice(index, 1)
|
||||
}
|
||||
},
|
||||
setUserForStatus (state, status) {
|
||||
setUserForStatus(state, status) {
|
||||
status.user = state.usersObject[status.user.id]
|
||||
},
|
||||
setUserForNotification (state, notification) {
|
||||
setUserForNotification(state, notification) {
|
||||
if (notification.type !== 'follow') {
|
||||
notification.action.user = state.usersObject[notification.action.user.id]
|
||||
}
|
||||
notification.from_profile = state.usersObject[notification.from_profile.id]
|
||||
},
|
||||
setColor (state, { user: { id }, highlighted }) {
|
||||
setColor(state, { user: { id }, highlighted }) {
|
||||
const user = state.usersObject[id]
|
||||
user.highlight = highlighted
|
||||
},
|
||||
signUpPending (state) {
|
||||
signUpPending(state) {
|
||||
state.signUpPending = true
|
||||
state.signUpErrors = []
|
||||
state.signUpNotice = {}
|
||||
},
|
||||
signUpSuccess (state) {
|
||||
signUpSuccess(state) {
|
||||
state.signUpPending = false
|
||||
},
|
||||
signUpFailure (state, errors) {
|
||||
signUpFailure(state, errors) {
|
||||
state.signUpPending = false
|
||||
state.signUpErrors = errors
|
||||
state.signUpNotice = {}
|
||||
},
|
||||
signUpNotice (state, notice) {
|
||||
signUpNotice(state, notice) {
|
||||
state.signUpPending = false
|
||||
state.signUpErrors = []
|
||||
state.signUpNotice = notice
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const getters = {
|
||||
findUser: state => query => {
|
||||
findUser: (state) => (query) => {
|
||||
return state.usersObject[query]
|
||||
},
|
||||
findUserByName: state => query => {
|
||||
findUserByName: (state) => (query) => {
|
||||
return state.usersByNameObject[query.toLowerCase()]
|
||||
},
|
||||
findUserByUrl: state => query => {
|
||||
return state.users
|
||||
.find(u => u.statusnet_profile_url &&
|
||||
u.statusnet_profile_url.toLowerCase() === query.toLowerCase())
|
||||
findUserByUrl: (state) => (query) => {
|
||||
return state.users.find(
|
||||
(u) =>
|
||||
u.statusnet_profile_url &&
|
||||
u.statusnet_profile_url.toLowerCase() === query.toLowerCase(),
|
||||
)
|
||||
},
|
||||
relationship: state => id => {
|
||||
relationship: (state) => (id) => {
|
||||
const rel = id && state.relationships[id]
|
||||
return rel || { id, loading: true }
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
export const defaultState = {
|
||||
|
|
@ -310,7 +357,7 @@ export const defaultState = {
|
|||
signUpPending: false,
|
||||
signUpErrors: [],
|
||||
signUpNotice: {},
|
||||
relationships: {}
|
||||
relationships: {},
|
||||
}
|
||||
|
||||
const users = {
|
||||
|
|
@ -318,47 +365,54 @@ const users = {
|
|||
mutations,
|
||||
getters,
|
||||
actions: {
|
||||
fetchUserIfMissing (store, id) {
|
||||
fetchUserIfMissing(store, id) {
|
||||
if (!store.getters.findUser(id)) {
|
||||
store.dispatch('fetchUser', id)
|
||||
}
|
||||
},
|
||||
fetchUser (store, id) {
|
||||
return store.rootState.api.backendInteractor.fetchUser({ id })
|
||||
fetchUser(store, id) {
|
||||
return store.rootState.api.backendInteractor
|
||||
.fetchUser({ id })
|
||||
.then((user) => {
|
||||
store.commit('addNewUsers', [user])
|
||||
return user
|
||||
})
|
||||
},
|
||||
fetchUserByName (store, name) {
|
||||
return store.rootState.api.backendInteractor.fetchUserByName({ name })
|
||||
fetchUserByName(store, name) {
|
||||
return store.rootState.api.backendInteractor
|
||||
.fetchUserByName({ name })
|
||||
.then((user) => {
|
||||
store.commit('addNewUsers', [user])
|
||||
return user
|
||||
})
|
||||
},
|
||||
fetchUserRelationship (store, id) {
|
||||
fetchUserRelationship(store, id) {
|
||||
if (store.state.currentUser) {
|
||||
store.rootState.api.backendInteractor.fetchUserRelationship({ id })
|
||||
.then((relationships) => store.commit('updateUserRelationship', relationships))
|
||||
store.rootState.api.backendInteractor
|
||||
.fetchUserRelationship({ id })
|
||||
.then((relationships) =>
|
||||
store.commit('updateUserRelationship', relationships),
|
||||
)
|
||||
}
|
||||
},
|
||||
fetchUserInLists (store, id) {
|
||||
fetchUserInLists(store, id) {
|
||||
if (store.state.currentUser) {
|
||||
store.rootState.api.backendInteractor.fetchUserInLists({ id })
|
||||
store.rootState.api.backendInteractor
|
||||
.fetchUserInLists({ id })
|
||||
.then((inLists) => store.commit('updateUserInLists', { id, inLists }))
|
||||
}
|
||||
},
|
||||
fetchBlocks (store, args) {
|
||||
fetchBlocks(store, args) {
|
||||
const { reset } = args || {}
|
||||
|
||||
const maxId = store.state.currentUser.blockIdsMaxId
|
||||
return store.rootState.api.backendInteractor.fetchBlocks({ maxId })
|
||||
return store.rootState.api.backendInteractor
|
||||
.fetchBlocks({ maxId })
|
||||
.then((blocks) => {
|
||||
if (reset) {
|
||||
store.commit('saveBlockIds', map(blocks, 'id'))
|
||||
} else {
|
||||
map(blocks, 'id').map(id => store.commit('addBlockId', id))
|
||||
map(blocks, 'id').map((id) => store.commit('addBlockId', id))
|
||||
}
|
||||
if (blocks.length) {
|
||||
store.commit('setBlockIdsMaxId', last(blocks).id)
|
||||
|
|
@ -367,34 +421,35 @@ const users = {
|
|||
return blocks
|
||||
})
|
||||
},
|
||||
blockUser (store, data) {
|
||||
blockUser(store, data) {
|
||||
return blockUser(store, data)
|
||||
},
|
||||
unblockUser (store, data) {
|
||||
unblockUser(store, data) {
|
||||
return unblockUser(store, data)
|
||||
},
|
||||
removeUserFromFollowers (store, id) {
|
||||
removeUserFromFollowers(store, id) {
|
||||
return removeUserFromFollowers(store, id)
|
||||
},
|
||||
blockUsers (store, data = []) {
|
||||
return Promise.all(data.map(d => blockUser(store, d)))
|
||||
blockUsers(store, data = []) {
|
||||
return Promise.all(data.map((d) => blockUser(store, d)))
|
||||
},
|
||||
unblockUsers (store, data = []) {
|
||||
return Promise.all(data.map(d => unblockUser(store, d)))
|
||||
unblockUsers(store, data = []) {
|
||||
return Promise.all(data.map((d) => unblockUser(store, d)))
|
||||
},
|
||||
editUserNote (store, args) {
|
||||
editUserNote(store, args) {
|
||||
return editUserNote(store, args)
|
||||
},
|
||||
fetchMutes (store, args) {
|
||||
fetchMutes(store, args) {
|
||||
const { reset } = args || {}
|
||||
|
||||
const maxId = store.state.currentUser.muteIdsMaxId
|
||||
return store.rootState.api.backendInteractor.fetchMutes({ maxId })
|
||||
return store.rootState.api.backendInteractor
|
||||
.fetchMutes({ maxId })
|
||||
.then((mutes) => {
|
||||
if (reset) {
|
||||
store.commit('saveMuteIds', map(mutes, 'id'))
|
||||
} else {
|
||||
map(mutes, 'id').map(id => store.commit('addMuteId', id))
|
||||
map(mutes, 'id').map((id) => store.commit('addMuteId', id))
|
||||
}
|
||||
if (mutes.length) {
|
||||
store.commit('setMuteIdsMaxId', last(mutes).id)
|
||||
|
|
@ -403,99 +458,118 @@ const users = {
|
|||
return mutes
|
||||
})
|
||||
},
|
||||
muteUser (store, data) {
|
||||
muteUser(store, data) {
|
||||
return muteUser(store, data)
|
||||
},
|
||||
unmuteUser (store, id) {
|
||||
unmuteUser(store, id) {
|
||||
return unmuteUser(store, id)
|
||||
},
|
||||
hideReblogs (store, id) {
|
||||
hideReblogs(store, id) {
|
||||
return hideReblogs(store, id)
|
||||
},
|
||||
showReblogs (store, id) {
|
||||
showReblogs(store, id) {
|
||||
return showReblogs(store, id)
|
||||
},
|
||||
muteUsers (store, data = []) {
|
||||
return Promise.all(data.map(d => muteUser(store, d)))
|
||||
muteUsers(store, data = []) {
|
||||
return Promise.all(data.map((d) => muteUser(store, d)))
|
||||
},
|
||||
unmuteUsers (store, ids = []) {
|
||||
return Promise.all(ids.map(d => unmuteUser(store, d)))
|
||||
unmuteUsers(store, ids = []) {
|
||||
return Promise.all(ids.map((d) => unmuteUser(store, d)))
|
||||
},
|
||||
fetchDomainMutes (store) {
|
||||
return store.rootState.api.backendInteractor.fetchDomainMutes()
|
||||
fetchDomainMutes(store) {
|
||||
return store.rootState.api.backendInteractor
|
||||
.fetchDomainMutes()
|
||||
.then((domainMutes) => {
|
||||
store.commit('saveDomainMutes', domainMutes)
|
||||
return domainMutes
|
||||
})
|
||||
},
|
||||
muteDomain (store, domain) {
|
||||
muteDomain(store, domain) {
|
||||
return muteDomain(store, domain)
|
||||
},
|
||||
unmuteDomain (store, domain) {
|
||||
unmuteDomain(store, domain) {
|
||||
return unmuteDomain(store, domain)
|
||||
},
|
||||
muteDomains (store, domains = []) {
|
||||
return Promise.all(domains.map(domain => muteDomain(store, domain)))
|
||||
muteDomains(store, domains = []) {
|
||||
return Promise.all(domains.map((domain) => muteDomain(store, domain)))
|
||||
},
|
||||
unmuteDomains (store, domain = []) {
|
||||
return Promise.all(domain.map(domain => unmuteDomain(store, domain)))
|
||||
unmuteDomains(store, domain = []) {
|
||||
return Promise.all(domain.map((domain) => unmuteDomain(store, domain)))
|
||||
},
|
||||
fetchFriends ({ rootState, commit }, id) {
|
||||
fetchFriends({ rootState, commit }, id) {
|
||||
const user = rootState.users.usersObject[id]
|
||||
const maxId = last(user.friendIds)
|
||||
return rootState.api.backendInteractor.fetchFriends({ id, maxId })
|
||||
return rootState.api.backendInteractor
|
||||
.fetchFriends({ id, maxId })
|
||||
.then((friends) => {
|
||||
commit('addNewUsers', friends)
|
||||
commit('saveFriendIds', { id, friendIds: map(friends, 'id') })
|
||||
return friends
|
||||
})
|
||||
},
|
||||
fetchFollowers ({ rootState, commit }, id) {
|
||||
fetchFollowers({ rootState, commit }, id) {
|
||||
const user = rootState.users.usersObject[id]
|
||||
const maxId = last(user.followerIds)
|
||||
return rootState.api.backendInteractor.fetchFollowers({ id, maxId })
|
||||
return rootState.api.backendInteractor
|
||||
.fetchFollowers({ id, maxId })
|
||||
.then((followers) => {
|
||||
commit('addNewUsers', followers)
|
||||
commit('saveFollowerIds', { id, followerIds: map(followers, 'id') })
|
||||
return followers
|
||||
})
|
||||
},
|
||||
clearFriends ({ commit }, userId) {
|
||||
clearFriends({ commit }, userId) {
|
||||
commit('clearFriends', userId)
|
||||
},
|
||||
clearFollowers ({ commit }, userId) {
|
||||
clearFollowers({ commit }, userId) {
|
||||
commit('clearFollowers', userId)
|
||||
},
|
||||
subscribeUser ({ rootState, commit }, id) {
|
||||
return rootState.api.backendInteractor.followUser({ id, notify: true })
|
||||
.then((relationship) => commit('updateUserRelationship', [relationship]))
|
||||
subscribeUser({ rootState, commit }, id) {
|
||||
return rootState.api.backendInteractor
|
||||
.followUser({ id, notify: true })
|
||||
.then((relationship) =>
|
||||
commit('updateUserRelationship', [relationship]),
|
||||
)
|
||||
},
|
||||
unsubscribeUser ({ rootState, commit }, id) {
|
||||
return rootState.api.backendInteractor.followUser({ id, notify: false })
|
||||
.then((relationship) => commit('updateUserRelationship', [relationship]))
|
||||
unsubscribeUser({ rootState, commit }, id) {
|
||||
return rootState.api.backendInteractor
|
||||
.followUser({ id, notify: false })
|
||||
.then((relationship) =>
|
||||
commit('updateUserRelationship', [relationship]),
|
||||
)
|
||||
},
|
||||
toggleActivationStatus ({ rootState, commit }, { user }) {
|
||||
const api = user.deactivated ? rootState.api.backendInteractor.activateUser : rootState.api.backendInteractor.deactivateUser
|
||||
api({ user })
|
||||
.then((user) => { const deactivated = !user.is_active; commit('updateActivationStatus', { user, deactivated }) })
|
||||
toggleActivationStatus({ rootState, commit }, { user }) {
|
||||
const api = user.deactivated
|
||||
? rootState.api.backendInteractor.activateUser
|
||||
: rootState.api.backendInteractor.deactivateUser
|
||||
api({ user }).then((user) => {
|
||||
const deactivated = !user.is_active
|
||||
commit('updateActivationStatus', { user, deactivated })
|
||||
})
|
||||
},
|
||||
registerPushNotifications (store) {
|
||||
registerPushNotifications(store) {
|
||||
const token = store.state.currentUser.credentials
|
||||
const vapidPublicKey = store.rootState.instance.vapidPublicKey
|
||||
const isEnabled = store.rootState.config.webPushNotifications
|
||||
const notificationVisibility = store.rootState.config.notificationVisibility
|
||||
const notificationVisibility =
|
||||
store.rootState.config.notificationVisibility
|
||||
|
||||
registerPushNotifications(isEnabled, vapidPublicKey, token, notificationVisibility)
|
||||
registerPushNotifications(
|
||||
isEnabled,
|
||||
vapidPublicKey,
|
||||
token,
|
||||
notificationVisibility,
|
||||
)
|
||||
},
|
||||
unregisterPushNotifications (store) {
|
||||
unregisterPushNotifications(store) {
|
||||
const token = store.state.currentUser.credentials
|
||||
|
||||
unregisterPushNotifications(token)
|
||||
},
|
||||
addNewUsers ({ commit }, users) {
|
||||
addNewUsers({ commit }, users) {
|
||||
commit('addNewUsers', users)
|
||||
},
|
||||
addNewStatuses (store, { statuses }) {
|
||||
addNewStatuses(store, { statuses }) {
|
||||
const users = map(statuses, 'user')
|
||||
const retweetedUsers = compact(map(statuses, 'retweeted_status.user'))
|
||||
store.commit('addNewUsers', users)
|
||||
|
|
@ -514,10 +588,10 @@ const users = {
|
|||
store.commit('setPinnedToUser', status)
|
||||
})
|
||||
},
|
||||
addNewNotifications (store, { notifications }) {
|
||||
addNewNotifications(store, { notifications }) {
|
||||
const users = map(notifications, 'from_profile')
|
||||
const targetUsers = map(notifications, 'target').filter(_ => _)
|
||||
const notificationIds = notifications.map(_ => _.id)
|
||||
const targetUsers = map(notifications, 'target').filter((_) => _)
|
||||
const notificationIds = notifications.map((_) => _.id)
|
||||
store.commit('addNewUsers', users)
|
||||
store.commit('addNewUsers', targetUsers)
|
||||
|
||||
|
|
@ -531,29 +605,32 @@ const users = {
|
|||
store.commit('setUserForNotification', notification)
|
||||
})
|
||||
},
|
||||
searchUsers ({ rootState, commit }, { query }) {
|
||||
return rootState.api.backendInteractor.searchUsers({ query })
|
||||
searchUsers({ rootState, commit }, { query }) {
|
||||
return rootState.api.backendInteractor
|
||||
.searchUsers({ query })
|
||||
.then((users) => {
|
||||
commit('addNewUsers', users)
|
||||
return users
|
||||
})
|
||||
},
|
||||
async signUp (store, userInfo) {
|
||||
async signUp(store, userInfo) {
|
||||
const oauthStore = useOAuthStore()
|
||||
store.commit('signUpPending')
|
||||
|
||||
try {
|
||||
const token = await oauthStore.ensureAppToken()
|
||||
const data = await apiService.register(
|
||||
{ credentials: token, params: { ...userInfo } }
|
||||
)
|
||||
const data = await apiService.register({
|
||||
credentials: token,
|
||||
params: { ...userInfo },
|
||||
})
|
||||
|
||||
if (data.access_token) {
|
||||
store.commit('signUpSuccess')
|
||||
oauthStore.setToken(data.access_token)
|
||||
store.dispatch('loginUser', data.access_token)
|
||||
return 'ok'
|
||||
} else { // Request succeeded, but user cannot login yet.
|
||||
} else {
|
||||
// Request succeeded, but user cannot login yet.
|
||||
store.commit('signUpNotice', data)
|
||||
return 'request_sent'
|
||||
}
|
||||
|
|
@ -563,22 +640,23 @@ const users = {
|
|||
throw e
|
||||
}
|
||||
},
|
||||
async getCaptcha (store) {
|
||||
async getCaptcha(store) {
|
||||
return store.rootState.api.backendInteractor.getCaptcha()
|
||||
},
|
||||
|
||||
logout (store) {
|
||||
logout(store) {
|
||||
const oauth = useOAuthStore()
|
||||
const { instance } = store.rootState
|
||||
|
||||
// NOTE: No need to verify the app still exists, because if it doesn't,
|
||||
// the token will be invalid too
|
||||
return oauth.ensureApp()
|
||||
return oauth
|
||||
.ensureApp()
|
||||
.then((app) => {
|
||||
const params = {
|
||||
app,
|
||||
instance: instance.server,
|
||||
token: oauth.userToken
|
||||
token: oauth.userToken,
|
||||
}
|
||||
|
||||
return oauthApi.revokeToken(params)
|
||||
|
|
@ -588,7 +666,10 @@ const users = {
|
|||
store.dispatch('disconnectFromSocket')
|
||||
oauth.clearToken()
|
||||
store.dispatch('stopFetchingTimeline', 'friends')
|
||||
store.commit('setBackendInteractor', backendInteractorService(oauth.getToken))
|
||||
store.commit(
|
||||
'setBackendInteractor',
|
||||
backendInteractorService(oauth.getToken),
|
||||
)
|
||||
store.dispatch('stopFetchingNotifications')
|
||||
store.dispatch('stopFetchingLists')
|
||||
store.dispatch('stopFetchingBookmarkFolders')
|
||||
|
|
@ -602,13 +683,14 @@ const users = {
|
|||
store.commit('clearServerSideStorage')
|
||||
})
|
||||
},
|
||||
loginUser (store, accessToken) {
|
||||
loginUser(store, accessToken) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const commit = store.commit
|
||||
const dispatch = store.dispatch
|
||||
const rootState = store.rootState
|
||||
commit('beginLogin')
|
||||
store.rootState.api.backendInteractor.verifyCredentials(accessToken)
|
||||
store.rootState.api.backendInteractor
|
||||
.verifyCredentials(accessToken)
|
||||
.then((data) => {
|
||||
if (!data.error) {
|
||||
const user = data
|
||||
|
|
@ -624,11 +706,15 @@ const users = {
|
|||
|
||||
dispatch('fetchEmoji')
|
||||
|
||||
getNotificationPermission()
|
||||
.then(permission => useInterfaceStore().setNotificationPermission(permission))
|
||||
getNotificationPermission().then((permission) =>
|
||||
useInterfaceStore().setNotificationPermission(permission),
|
||||
)
|
||||
|
||||
// Set our new backend interactor
|
||||
commit('setBackendInteractor', backendInteractorService(accessToken))
|
||||
commit(
|
||||
'setBackendInteractor',
|
||||
backendInteractorService(accessToken),
|
||||
)
|
||||
|
||||
// Do server-side storage migrations
|
||||
|
||||
|
|
@ -645,17 +731,23 @@ const users = {
|
|||
useServerSideStorageStore().setFlag({ flag: 'configMigration', value: 0 })
|
||||
/**/
|
||||
|
||||
const { configMigration } = useServerSideStorageStore().flagStorage
|
||||
const { configMigration } =
|
||||
useServerSideStorageStore().flagStorage
|
||||
declarations
|
||||
.filter(x => {
|
||||
return x.store === 'server-side' &&
|
||||
.filter((x) => {
|
||||
return (
|
||||
x.store === 'server-side' &&
|
||||
x.migrationNum > 0 &&
|
||||
x.migrationNum > configMigration
|
||||
)
|
||||
})
|
||||
.toSorted((a, b) => a.configMigration - b.configMigration)
|
||||
.forEach(value => {
|
||||
.forEach((value) => {
|
||||
value.migration(useServerSideStorageStore(), store.rootState)
|
||||
useServerSideStorageStore().setFlag({ flag: 'configMigration', value: value.migrationNum })
|
||||
useServerSideStorageStore().setFlag({
|
||||
flag: 'configMigration',
|
||||
value: value.migrationNum,
|
||||
})
|
||||
useServerSideStorageStore().pushServerSideStorage()
|
||||
})
|
||||
|
||||
|
|
@ -689,12 +781,20 @@ const users = {
|
|||
if (store.getters.mergedConfig.useStreamingApi) {
|
||||
dispatch('fetchTimeline', { timeline: 'friends', since: null })
|
||||
dispatch('fetchNotifications', { since: null })
|
||||
dispatch('enableMastoSockets', true).catch((error) => {
|
||||
console.error('Failed initializing MastoAPI Streaming socket', error)
|
||||
}).then(() => {
|
||||
dispatch('fetchChats', { latest: true })
|
||||
setTimeout(() => dispatch('setNotificationsSilence', false), 10000)
|
||||
})
|
||||
dispatch('enableMastoSockets', true)
|
||||
.catch((error) => {
|
||||
console.error(
|
||||
'Failed initializing MastoAPI Streaming socket',
|
||||
error,
|
||||
)
|
||||
})
|
||||
.then(() => {
|
||||
dispatch('fetchChats', { latest: true })
|
||||
setTimeout(
|
||||
() => dispatch('setNotificationsSilence', false),
|
||||
10000,
|
||||
)
|
||||
})
|
||||
} else {
|
||||
startPolling()
|
||||
}
|
||||
|
|
@ -706,7 +806,8 @@ const users = {
|
|||
useInterfaceStore().setLayoutHeight(windowHeight())
|
||||
|
||||
// Fetch our friends
|
||||
store.rootState.api.backendInteractor.fetchFriends({ id: user.id })
|
||||
store.rootState.api.backendInteractor
|
||||
.fetchFriends({ id: user.id })
|
||||
.then((friends) => commit('addNewUsers', friends))
|
||||
} else {
|
||||
const response = data.error
|
||||
|
|
@ -733,8 +834,8 @@ const users = {
|
|||
reject(new Error('Failed to connect to server, try again'))
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
export default users
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue