Compare commits
16 commits
97f2de913d
...
7bd01ca116
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7bd01ca116 | ||
|
|
ae127a8d51 | ||
|
|
5ff886ba94 | ||
|
|
c64f97ca5e | ||
|
|
97e3f24bdf | ||
|
|
bb09d6a9d1 | ||
|
|
ad52027760 | ||
|
|
b485ccd82e | ||
|
|
8d6a93aa66 | ||
|
|
f60a5c404e | ||
|
|
feb7135cc5 | ||
|
|
2deb74a6cf | ||
|
|
039870daf0 | ||
|
|
fdc0f39187 | ||
|
|
946682b3b4 | ||
|
|
cbd79a48af |
23 changed files with 144 additions and 181 deletions
|
|
@ -184,7 +184,10 @@ export const fetchStatusHistory = ({ id, credentials }) =>
|
||||||
return {
|
return {
|
||||||
...rest,
|
...rest,
|
||||||
data: [...data].reverse().map((item) => {
|
data: [...data].reverse().map((item) => {
|
||||||
item.originalStatus = status
|
// History data is missing a lot of stuff present in original
|
||||||
|
// but we're really only missing the id for the timeago, the
|
||||||
|
// rest seem to render just fine.
|
||||||
|
item.id = id
|
||||||
return parseStatus(item)
|
return parseStatus(item)
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,7 @@ const Chat = {
|
||||||
|
|
||||||
if (this.testMode) return
|
if (this.testMode) return
|
||||||
this.deactivate()
|
this.deactivate()
|
||||||
|
this.detachSocket()
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
conversationId() {
|
conversationId() {
|
||||||
|
|
@ -456,10 +457,16 @@ const Chat = {
|
||||||
|
|
||||||
// Sanity check
|
// Sanity check
|
||||||
if (!this.isConversation && message.chat_id !== this.chat.id) {
|
if (!this.isConversation && message.chat_id !== this.chat.id) {
|
||||||
|
// This is spammy, we get chat updates from a global chat update
|
||||||
|
// handler, which naturally receives updates for ALL chats.
|
||||||
|
// There is no way to subscribe to specific chat updates and listen
|
||||||
|
// to that in the API.
|
||||||
|
/*
|
||||||
console.warn(
|
console.warn(
|
||||||
`Chat message doesn't belong to current chat (id: ${this.chat.id})!!`,
|
`Chat message doesn't belong to current chat (id: ${this.chat.id})!!`,
|
||||||
message,
|
message,
|
||||||
)
|
)
|
||||||
|
*/
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,8 @@ const List = {
|
||||||
default: () => '',
|
default: () => '',
|
||||||
},
|
},
|
||||||
preSelect: {
|
preSelect: {
|
||||||
type: Array,
|
type: Set,
|
||||||
default: [],
|
default: new Set(),
|
||||||
},
|
},
|
||||||
nonInteractive: {
|
nonInteractive: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
|
|
@ -48,7 +48,7 @@ const List = {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
items: [],
|
items: [],
|
||||||
selected: new Set(this.preSelect),
|
selected: new Set(this.preSelect), // clone
|
||||||
loading: false,
|
loading: false,
|
||||||
bottomedOut: true,
|
bottomedOut: true,
|
||||||
error: null,
|
error: null,
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,7 @@ const Status = {
|
||||||
return this.statusoid ?? useStatusesStore().allStatuses.get(this.statusId)
|
return this.statusoid ?? useStatusesStore().allStatuses.get(this.statusId)
|
||||||
},
|
},
|
||||||
repeatedStatus() {
|
repeatedStatus() {
|
||||||
|
if (this.status.retweeted_status === undefined) return undefined
|
||||||
return useStatusesStore().allStatuses.get(this.status.retweeted_status.id)
|
return useStatusesStore().allStatuses.get(this.status.retweeted_status.id)
|
||||||
},
|
},
|
||||||
repeater() {
|
repeater() {
|
||||||
|
|
@ -198,7 +199,7 @@ const Status = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
isRepeat() {
|
isRepeat() {
|
||||||
return !!this.status.retweeted_status
|
return !!this.repeatedStatus
|
||||||
},
|
},
|
||||||
repeaterName() {
|
repeaterName() {
|
||||||
return this.status.user.name || this.status.user.screen_name_ui
|
return this.status.user.name || this.status.user.screen_name_ui
|
||||||
|
|
@ -313,19 +314,19 @@ const Status = {
|
||||||
return !this.unmuted && !this.shouldNotMute && this.muteReasons.length > 0
|
return !this.unmuted && !this.shouldNotMute && this.muteReasons.length > 0
|
||||||
},
|
},
|
||||||
userIsMuted() {
|
userIsMuted() {
|
||||||
if (this.status.user.id === this.currentUser?.id) return false
|
if (!this.currentUser) return false
|
||||||
const { reblog } = this.status
|
if (this.user === this.currentUser) return false
|
||||||
const relationship = useUsersStore().relationship(this.status.user.id)
|
if (this.repeater === this.currentUser) return false
|
||||||
const relationshipReblog =
|
const relationship = useUsersStore().relationship(this.user.id)
|
||||||
reblog && useUsersStore().relationship(reblog.user.id)
|
const relationshipRepeat = useUsersStore().relationship(this.repeater?.id)
|
||||||
return (
|
return (
|
||||||
(status.muted && !status.thread_muted) ||
|
(this.status.muted && !this.status.thread_muted) ||
|
||||||
// Reprööt of a muted post according to BE
|
// Reprööt of a muted post according to BE
|
||||||
(reblog?.muted && !reblog.thread_muted) ||
|
(this.repeatedStatus?.muted && !this.repeatedStatus.thread_muted) ||
|
||||||
// Muted user
|
// Muted user
|
||||||
relationship.muting ||
|
relationship.muting ||
|
||||||
// Muted user of a reprööt
|
// Muted user of a reprööt
|
||||||
relationshipReblog?.muting
|
relationshipRepeat?.muting
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
shouldNotMute() {
|
shouldNotMute() {
|
||||||
|
|
|
||||||
|
|
@ -174,20 +174,7 @@ export const BUTTONS = [
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
action({ status }) {
|
action({ status }) {
|
||||||
const originalStatus = { ...status }
|
useStatusHistoryStore().openModal(status.id)
|
||||||
const stripFieldsList = [
|
|
||||||
'attachments',
|
|
||||||
'created_at',
|
|
||||||
'emojis',
|
|
||||||
'text',
|
|
||||||
'raw_html',
|
|
||||||
'nsfw',
|
|
||||||
'poll',
|
|
||||||
'summary',
|
|
||||||
'summary_raw_html',
|
|
||||||
]
|
|
||||||
stripFieldsList.forEach((p) => delete originalStatus[p])
|
|
||||||
useStatusHistoryStore().openModal(originalStatus.id)
|
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,6 @@
|
||||||
v-if="favoritesTabVisible"
|
v-if="favoritesTabVisible"
|
||||||
key="favorites"
|
key="favorites"
|
||||||
:label="$t('user_card.favorites')"
|
:label="$t('user_card.favorites')"
|
||||||
:disabled="favorites.visibleStatusIds.size === 0"
|
|
||||||
:title="$t('user_card.favorites')"
|
:title="$t('user_card.favorites')"
|
||||||
:timeline-ref="{ name: 'favorites', argument: userId }"
|
:timeline-ref="{ name: 'favorites', argument: userId }"
|
||||||
:argument="isUs ? undefined : userId"
|
:argument="isUs ? undefined : userId"
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ const UserReportingModal = {
|
||||||
// Reset state
|
// Reset state
|
||||||
this.comment = ''
|
this.comment = ''
|
||||||
this.forward = false
|
this.forward = false
|
||||||
this.statusIdsToReport = new Set(this.reportModal.preTickedIds)
|
this.statusIdsToReport = new Set(this.reportModal.preTickedIds) // cloning
|
||||||
this.processing = false
|
this.processing = false
|
||||||
this.error = false
|
this.error = false
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,9 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="user-reporting-panel-right">
|
<div class="user-reporting-panel-right">
|
||||||
<List
|
<List
|
||||||
:external-items="reportModal.statuses"
|
:external-items="reportModal.statusIds"
|
||||||
:pre-select="reportModal.preTickedIds"
|
:pre-select="reportModal.preTickedIds"
|
||||||
|
:get-key="(item) => item"
|
||||||
selectable
|
selectable
|
||||||
@select="onListSelect"
|
@select="onListSelect"
|
||||||
>
|
>
|
||||||
|
|
@ -61,7 +62,7 @@
|
||||||
<Status
|
<Status
|
||||||
:in-conversation="false"
|
:in-conversation="false"
|
||||||
:focused="false"
|
:focused="false"
|
||||||
:statusoid="item"
|
:status-id="item"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</List>
|
</List>
|
||||||
|
|
|
||||||
|
|
@ -1,58 +1,20 @@
|
||||||
import { shuffle } from 'lodash'
|
import { shuffle } from 'lodash'
|
||||||
|
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
import { useUsersStore } from 'src/stores/users.js'
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { fetchUser, suggestions } from 'src/api/public.js'
|
import { fetchUser, suggestions } from 'src/api/public.js'
|
||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||||
|
|
||||||
function showWhoToFollow(panel, reply) {
|
|
||||||
const shuffled = shuffle(reply)
|
|
||||||
|
|
||||||
panel.usersToFollow.forEach((toFollow, index) => {
|
|
||||||
const user = shuffled[index]
|
|
||||||
const img = user.avatar || useInstanceStore().instanceIdentity.defaultAvatar
|
|
||||||
const name = user.acct
|
|
||||||
|
|
||||||
toFollow.img = img
|
|
||||||
toFollow.name = name
|
|
||||||
|
|
||||||
fetchUser({
|
|
||||||
id: name,
|
|
||||||
credentials: useOAuthStore().token,
|
|
||||||
}).then((result) => {
|
|
||||||
const { data: externalUser } = result
|
|
||||||
useUsersStore().addNewUsers(result)
|
|
||||||
toFollow.id = externalUser.id
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function getWhoToFollow(panel) {
|
|
||||||
const credentials = useOAuthStore().token
|
|
||||||
if (credentials) {
|
|
||||||
panel.usersToFollow.forEach((toFollow) => {
|
|
||||||
toFollow.name = 'Loading...'
|
|
||||||
})
|
|
||||||
suggestions({ credentials }).then(({ data: reply }) => {
|
|
||||||
showWhoToFollow(panel, reply)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const WhoToFollowPanel = {
|
const WhoToFollowPanel = {
|
||||||
data: () => ({
|
data: () => ({
|
||||||
usersToFollow: [],
|
usersToFollow: [],
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
user: function () {
|
user() {
|
||||||
return useUsersStore().currentUser.screen_name
|
return useUsersStore().currentUser.screen_name
|
||||||
},
|
},
|
||||||
suggestionsEnabled() {
|
|
||||||
return useInstanceCapabilitiesStore().suggestionsEnabled
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
userProfileLink(id, name) {
|
userProfileLink(id, name) {
|
||||||
|
|
@ -62,23 +24,53 @@ const WhoToFollowPanel = {
|
||||||
useInstanceStore().restrictedNicknames,
|
useInstanceStore().restrictedNicknames,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
getWhoToFollow() {
|
||||||
watch: {
|
this.usersToFollow.forEach((toFollow) => {
|
||||||
user: function () {
|
toFollow.name = 'Loading...'
|
||||||
if (this.suggestionsEnabled) {
|
})
|
||||||
getWhoToFollow()
|
|
||||||
}
|
suggestions({ credentials: useOAuthStore().token }).then(
|
||||||
|
({ data: reply }) => {
|
||||||
|
this.showWhoToFollow(reply)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
showWhoToFollow(reply) {
|
||||||
|
const shuffled = shuffle(reply)
|
||||||
|
|
||||||
|
this.usersToFollow.forEach((toFollow, index) => {
|
||||||
|
const user = shuffled[index]
|
||||||
|
const img =
|
||||||
|
user.avatar || useInstanceStore().instanceIdentity.defaultAvatar
|
||||||
|
const name = user.acct
|
||||||
|
|
||||||
|
toFollow.img = img
|
||||||
|
toFollow.name = name
|
||||||
|
|
||||||
|
fetchUser({
|
||||||
|
id: name,
|
||||||
|
credentials: useOAuthStore().token,
|
||||||
|
}).then((result) => {
|
||||||
|
const { data: externalUser } = result
|
||||||
|
useUsersStore().addNewUsers(result)
|
||||||
|
toFollow.id = externalUser.id
|
||||||
|
})
|
||||||
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted: function () {
|
watch: {
|
||||||
|
user() {
|
||||||
|
this.getWhoToFollow()
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
this.usersToFollow = new Array(3).fill().map(() => ({
|
this.usersToFollow = new Array(3).fill().map(() => ({
|
||||||
img: useInstanceStore().instanceIdentity.defaultAvatar,
|
img: useInstanceStore().instanceIdentity.defaultAvatar,
|
||||||
name: '',
|
name: '',
|
||||||
id: 0,
|
id: 0,
|
||||||
}))
|
}))
|
||||||
if (this.suggestionsEnabled) {
|
|
||||||
getWhoToFollow()
|
this.getWhoToFollow()
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import { useUsersStore } from 'src/stores/users.js'
|
||||||
export const piniaPushNotificationsPlugin = ({ store }) => {
|
export const piniaPushNotificationsPlugin = ({ store }) => {
|
||||||
const validActions = {
|
const validActions = {
|
||||||
sync_config: new Set(['setPreference']),
|
sync_config: new Set(['setPreference']),
|
||||||
interface: new Set(['setNotificationPermission', 'setLoginStatus']),
|
interface: new Set(['setNotificationPermission', 'onLogin', 'onLogout']),
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validActions[store.$id]) return // Not applicable to the store
|
if (!validActions[store.$id]) return // Not applicable to the store
|
||||||
|
|
@ -21,7 +21,7 @@ export const piniaPushNotificationsPlugin = ({ store }) => {
|
||||||
useInterfaceStore().notificationPermission === 'granted'
|
useInterfaceStore().notificationPermission === 'granted'
|
||||||
let permissionPresent =
|
let permissionPresent =
|
||||||
useInterfaceStore().notificationPermission !== undefined
|
useInterfaceStore().notificationPermission !== undefined
|
||||||
let user = !!useUsersStore().currentUser
|
let user = useUsersStore().loggedIn
|
||||||
|
|
||||||
if (store.$id === 'instance') {
|
if (store.$id === 'instance') {
|
||||||
if (actionName === 'set' && args[0].path === 'vapidPublicKey') {
|
if (actionName === 'set' && args[0].path === 'vapidPublicKey') {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
export const maybeShowChatNotification = (chat) => {
|
export const maybeShowChatNotification = (chat) => {
|
||||||
if (!chat.lastMessage) return
|
if (!chat.lastMessage) return
|
||||||
|
if (chat.unread === 0) return
|
||||||
if (useUsersStore().currentUser.id === chat.lastMessage.account_id) return
|
if (useUsersStore().currentUser.id === chat.lastMessage.account_id) return
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
|
|
|
||||||
|
|
@ -342,10 +342,6 @@ export const parseStatus = (data) => {
|
||||||
output.favoritedBy = []
|
output.favoritedBy = []
|
||||||
output.rebloggedBy = []
|
output.rebloggedBy = []
|
||||||
|
|
||||||
if (Object.hasOwn(data, 'originalStatus')) {
|
|
||||||
Object.assign(output, data.originalStatus)
|
|
||||||
}
|
|
||||||
|
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -430,11 +430,9 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
|
||||||
})
|
})
|
||||||
|
|
||||||
resultUserIds.data.forEach((userId) => {
|
resultUserIds.data.forEach((userId) => {
|
||||||
window.vuex.dispatch(
|
useStatusesStore().wipeUserStatuses(status.user.id)
|
||||||
'markStatusesAsDeleted',
|
// Users are technically never deleted, just deactivated
|
||||||
(status) => userId === status.user.id,
|
// so there's no real need to delete them from store.
|
||||||
)
|
|
||||||
// TODO when migrated to pinia, also remove user
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return resultUserIds
|
return resultUserIds
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { find, omitBy, orderBy, sumBy } from 'lodash'
|
import { orderBy, sumBy } from 'lodash'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
import { maybeShowChatNotification } from '../services/chat_utils/chat_utils.js'
|
import { maybeShowChatNotification } from '../services/chat_utils/chat_utils.js'
|
||||||
|
|
@ -10,28 +10,19 @@ import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { chats } from 'src/api/chats.js'
|
import { chats } from 'src/api/chats.js'
|
||||||
|
|
||||||
const emptyChatList = () => ({
|
|
||||||
data: [],
|
|
||||||
idStore: {},
|
|
||||||
})
|
|
||||||
|
|
||||||
const defaultState = {
|
const defaultState = {
|
||||||
chatList: emptyChatList(),
|
data: new Map(),
|
||||||
chatListFetcher: null,
|
fetcher: null,
|
||||||
}
|
|
||||||
|
|
||||||
const getChatById = (state, id) => {
|
|
||||||
return find(state.chatList.data, { id })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useChatsStore = defineStore('chats', {
|
export const useChatsStore = defineStore('chats', {
|
||||||
state: () => ({ ...defaultState }),
|
state: () => ({ ...defaultState }),
|
||||||
getters: {
|
getters: {
|
||||||
sortedChatList(state) {
|
sortedChatList(state) {
|
||||||
return orderBy(state.chatList.data, ['updated_at'], ['desc'])
|
return orderBy([...state.data.values()], ['updated_at'], ['desc'])
|
||||||
},
|
},
|
||||||
unreadChatsCount(state) {
|
unreadChatsCount(state) {
|
||||||
return sumBy(state.chatList.data, 'unread')
|
return sumBy([...state.data.values()], 'unread')
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
|
|
@ -42,16 +33,19 @@ export const useChatsStore = defineStore('chats', {
|
||||||
et,
|
et,
|
||||||
}
|
}
|
||||||
|
|
||||||
et.addEventListener('pleroma:chat_update', this.updateChat)
|
et.addEventListener('pleroma:chat_update', ({ data: { chatUpdate } }) => {
|
||||||
|
this.updateChat(chatUpdate)
|
||||||
|
})
|
||||||
|
|
||||||
useStreamingStore().addSubscriber(socket)
|
useStreamingStore().addSubscriber(socket)
|
||||||
},
|
},
|
||||||
startFetching() {
|
startFetching() {
|
||||||
const fetcher = () => this.fetchChats()
|
this.fetcher = () => promiseInterval(() => this.fetchChats(), 5000)
|
||||||
this.setChatListFetcher(() => promiseInterval(fetcher, 5000))
|
this.fetcher()
|
||||||
},
|
},
|
||||||
stopFetching() {
|
stopFetching() {
|
||||||
this.setChatListFetcher(null)
|
this.fetcher?.stop()
|
||||||
|
this.fetcher = null
|
||||||
},
|
},
|
||||||
async fetchChats() {
|
async fetchChats() {
|
||||||
this.addNewChats(
|
this.addNewChats(
|
||||||
|
|
@ -60,16 +54,10 @@ export const useChatsStore = defineStore('chats', {
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
setChatListFetcher(fetcher) {
|
|
||||||
const prevFetcher = this.chatListFetcher
|
|
||||||
if (prevFetcher) {
|
|
||||||
prevFetcher.stop()
|
|
||||||
}
|
|
||||||
this.chatListFetcher = fetcher?.()
|
|
||||||
},
|
|
||||||
resetChats() {
|
resetChats() {
|
||||||
this.chatList = emptyChatList()
|
this.data = new Map()
|
||||||
this.setChatListFetcher(null)
|
this.stopFetching()
|
||||||
|
this.startFetching()
|
||||||
},
|
},
|
||||||
addNewChats(result) {
|
addNewChats(result) {
|
||||||
useUsersStore().addNewUsers({
|
useUsersStore().addNewUsers({
|
||||||
|
|
@ -77,45 +65,30 @@ export const useChatsStore = defineStore('chats', {
|
||||||
data: result.data.map((k) => k.account).filter(Boolean),
|
data: result.data.map((k) => k.account).filter(Boolean),
|
||||||
})
|
})
|
||||||
|
|
||||||
result.data.forEach((updatedChat) => {
|
// We do unshift in update so we reverse the chat list here
|
||||||
const chat = getChatById(this, updatedChat.id)
|
result.data.forEach((chat) => this.updateChat(chat))
|
||||||
|
|
||||||
if (chat) {
|
|
||||||
chat.lastMessage = updatedChat.lastMessage
|
|
||||||
chat.unread = updatedChat.unread
|
|
||||||
chat.updated_at = updatedChat.updated_at
|
|
||||||
} else {
|
|
||||||
this.chatList.data.push(updatedChat)
|
|
||||||
this.chatList.idStore[updatedChat.id] = updatedChat
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
readChat(id) {
|
readChat(id) {
|
||||||
const chat = getChatById(this, id)
|
const chat = this.data.get(id)
|
||||||
if (chat) {
|
if (chat) {
|
||||||
chat.unread = 0
|
chat.unread = 0
|
||||||
|
} else {
|
||||||
|
console.error(`Chat ${id} not found!`)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateChat({ data: { chatUpdate: updatedChat } }) {
|
updateChat(updatedChat) {
|
||||||
const chat = getChatById(this, updatedChat.id)
|
const chat = this.data.get(updatedChat.id)
|
||||||
if (chat) {
|
if (chat) {
|
||||||
chat.lastMessage = updatedChat.lastMessage
|
chat.lastMessage = updatedChat.lastMessage
|
||||||
chat.unread = updatedChat.unread
|
chat.unread = updatedChat.unread
|
||||||
chat.updated_at = updatedChat.updated_at
|
chat.updated_at = updatedChat.updated_at
|
||||||
} else {
|
} else {
|
||||||
this.chatList.data.unshift(updatedChat)
|
this.data.set(updatedChat.id, updatedChat)
|
||||||
}
|
}
|
||||||
maybeShowChatNotification(chat)
|
maybeShowChatNotification(chat ?? updatedChat)
|
||||||
this.chatList.idStore[updatedChat.id] = updatedChat
|
|
||||||
},
|
},
|
||||||
deleteChat(id) {
|
deleteChat(id) {
|
||||||
this.chats.data = this.chats.data.filter(
|
this.data.delete(id)
|
||||||
(conversation) => conversation.last_status.id !== id,
|
|
||||||
)
|
|
||||||
this.chats.idStore = omitBy(
|
|
||||||
this.chats.idStore,
|
|
||||||
(conversation) => conversation.last_status.id === id,
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ const timelineFetcher = (timeline, argument, credentials) => {
|
||||||
return { statuses, pagination }
|
return { statuses, pagination }
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
if (error.statusCode === 403 && timeline === 'favorites') {
|
if (error.statusCode === 403 && timeline.name === 'favorites') {
|
||||||
useInstanceCapabilitiesStore().pleromaPublicFavouritesAvailable = false
|
useInstanceCapabilitiesStore().pleromaPublicFavouritesAvailable = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { filter } from 'lodash'
|
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
|
|
@ -11,28 +10,23 @@ export const useReportsStore = defineStore('reports', {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
reportModal: {
|
reportModal: {
|
||||||
userId: null,
|
userId: null,
|
||||||
statuses: [],
|
statusIds: new Set(),
|
||||||
preTickedIds: [],
|
preTickedIds: new Set(),
|
||||||
activated: false,
|
activated: false,
|
||||||
},
|
},
|
||||||
reports: {},
|
reports: {},
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
openUserReportingModal({ userId, statusIds = [] }) {
|
openUserReportingModal({ userId, statusIds = [] }) {
|
||||||
const preTickedStatuses = statusIds.map((id) =>
|
const preTickedIds = new Set(statusIds)
|
||||||
useStatusesStore().allStatuses.get(id),
|
// There shouldn't be a case where this is undefined
|
||||||
)
|
const userAllStatusesIds = useStatusesStore().statusesPerUser.get(userId)
|
||||||
const preTickedIds = statusIds
|
// Set constructor should take care of duplicated IDs and order,
|
||||||
const statuses = preTickedStatuses.concat(
|
// later duplicated IDs will be dropped in favor of earlier
|
||||||
filter(
|
const sortedIds = new Set([...preTickedIds, ...userAllStatusesIds])
|
||||||
window.vuex.state.statuses.allStatuses,
|
|
||||||
(status) =>
|
|
||||||
status.user.id === userId && !preTickedIds.includes(status.id),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
this.reportModal.userId = userId
|
this.reportModal.userId = userId
|
||||||
this.reportModal.statuses = statuses
|
this.reportModal.statusIds = sortedIds
|
||||||
this.reportModal.preTickedIds = preTickedIds
|
this.reportModal.preTickedIds = preTickedIds
|
||||||
this.reportModal.activated = true
|
this.reportModal.activated = true
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import {
|
||||||
|
|
||||||
export const defaultState = () => ({
|
export const defaultState = () => ({
|
||||||
allStatuses: new Map(),
|
allStatuses: new Map(),
|
||||||
|
statusesPerUser: new Map(),
|
||||||
timestamps: new WeakMap(),
|
timestamps: new WeakMap(),
|
||||||
scrobblesNextFetch: {},
|
scrobblesNextFetch: {},
|
||||||
conversations: new Map(),
|
conversations: new Map(),
|
||||||
|
|
@ -83,6 +84,12 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
// in case of likes (which are not statuses) it should return null
|
// in case of likes (which are not statuses) it should return null
|
||||||
const addStatus = (data) => {
|
const addStatus = (data) => {
|
||||||
const [status] = this.mergeOrAdd(this.allStatuses, data, timestamp)
|
const [status] = this.mergeOrAdd(this.allStatuses, data, timestamp)
|
||||||
|
let userSet = this.statusesPerUser.get(status.user.id)
|
||||||
|
if (userSet === undefined) {
|
||||||
|
userSet = new Set()
|
||||||
|
this.statusesPerUser.set(status.user.id, userSet)
|
||||||
|
}
|
||||||
|
userSet.add(status.id)
|
||||||
|
|
||||||
// Add to conversation
|
// Add to conversation
|
||||||
const conversations = this.conversations
|
const conversations = this.conversations
|
||||||
|
|
@ -527,14 +534,19 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
|
|
||||||
// For when blocking a user
|
// For when blocking a user
|
||||||
wipeUserStatuses(userId) {
|
wipeUserStatuses(userId) {
|
||||||
const removed = new Set()
|
const removed = this.statusesPerUser.get(userId)
|
||||||
this.allStatuses.forEach((status) => {
|
removed.forEach((statusId) => {
|
||||||
if (status.user.id === userId) {
|
const status = this.allStatuses.get(statusId)
|
||||||
this.allStatuses.delete(status.id)
|
this.allStatuses.delete(statusId)
|
||||||
|
const conversationSet = this.conversations.get(
|
||||||
removed.add(status.id)
|
status.statusnet_conversation_id,
|
||||||
|
)
|
||||||
|
conversationSet.delete(statusId)
|
||||||
|
if (conversationSet.size === 0) {
|
||||||
|
this.conversations.delete(status.statusnet_conversation_id)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
this.statusesPerUser.delete(userId)
|
||||||
return removed
|
return removed
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ export const useStreamingStore = defineStore('streaming', {
|
||||||
this.subscriptions.get(stream.name).delete(stream.argument)
|
this.subscriptions.get(stream.name).delete(stream.argument)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state === WSConnectionStatus.JOINED) {
|
if (stream && this.state === WSConnectionStatus.JOINED) {
|
||||||
this.socket.unsubscribe(...this.getSubArgs(stream))
|
this.socket.unsubscribe(...this.getSubArgs(stream))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -131,7 +131,6 @@ export const useStreamingStore = defineStore('streaming', {
|
||||||
},
|
},
|
||||||
|
|
||||||
getSubArgs(stream) {
|
getSubArgs(stream) {
|
||||||
if (stream === undefined) return []
|
|
||||||
const argumentKey = ARGUMENT_MAP[stream.name]
|
const argumentKey = ARGUMENT_MAP[stream.name]
|
||||||
const args = argumentKey
|
const args = argumentKey
|
||||||
? {
|
? {
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ export const useTimelinesStore = defineStore('timelines', {
|
||||||
if (timeline.persistent && !persistent) return
|
if (timeline.persistent && !persistent) return
|
||||||
|
|
||||||
if (
|
if (
|
||||||
timelineName === 'favourites' &&
|
timelineName === 'favorites' &&
|
||||||
!useInstanceCapabilitiesStore().pleromaPublicFavouritesAvailable
|
!useInstanceCapabilitiesStore().pleromaPublicFavouritesAvailable
|
||||||
) {
|
) {
|
||||||
console.warn("Instance doesn't support public favorites timeline")
|
console.warn("Instance doesn't support public favorites timeline")
|
||||||
|
|
|
||||||
|
|
@ -561,6 +561,7 @@ export const useUsersStore = defineStore('users', {
|
||||||
|
|
||||||
const ids = useStatusesStore().wipeUserStatuses(id)
|
const ids = useStatusesStore().wipeUserStatuses(id)
|
||||||
useTimelinesStore().wipeStatuses(ids)
|
useTimelinesStore().wipeStatuses(ids)
|
||||||
|
useNotificationsStore().wipeStatuses(ids)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
blockUsers(data = []) {
|
blockUsers(data = []) {
|
||||||
|
|
|
||||||
|
|
@ -32,10 +32,6 @@ const global = {
|
||||||
$store: {
|
$store: {
|
||||||
state: {
|
state: {
|
||||||
api: {},
|
api: {},
|
||||||
users: {},
|
|
||||||
statuses: {
|
|
||||||
allStatusesObject: {},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
$route: {
|
$route: {
|
||||||
|
|
|
||||||
|
|
@ -9,15 +9,6 @@ import {
|
||||||
describe('The UserHighlight store', () => {
|
describe('The UserHighlight store', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
setActivePinia(createPinia())
|
setActivePinia(createPinia())
|
||||||
window.vuex = {
|
|
||||||
state: {
|
|
||||||
users: {
|
|
||||||
currentUser: {
|
|
||||||
fqn: 'foo@bar.tld',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('mutations', () => {
|
describe('mutations', () => {
|
||||||
|
|
|
||||||
|
|
@ -1124,6 +1124,12 @@ describe('Users store', () => {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
vi.spyOn(useNotificationsStore(), 'wipeStatuses').mockImplementation(
|
||||||
|
async () => {
|
||||||
|
/* no-op */
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
const store = useUsersStore()
|
const store = useUsersStore()
|
||||||
const { storeAction, apiUrl } = actionKeys(action)
|
const { storeAction, apiUrl } = actionKeys(action)
|
||||||
await store[storeAction](userId)
|
await store[storeAction](userId)
|
||||||
|
|
@ -1155,6 +1161,12 @@ describe('Users store', () => {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
vi.spyOn(useNotificationsStore(), 'wipeStatuses').mockImplementation(
|
||||||
|
async () => {
|
||||||
|
/* no-op */
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
const store = useUsersStore()
|
const store = useUsersStore()
|
||||||
const { storeAction, apiUrl } = actionKeys(action)
|
const { storeAction, apiUrl } = actionKeys(action)
|
||||||
await store[storeAction](userId, 20)
|
await store[storeAction](userId, 20)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue