diff --git a/src/components/emoji_reactions/emoji_reactions.js b/src/components/emoji_reactions/emoji_reactions.js
index 6296e3c9a..3077ed212 100644
--- a/src/components/emoji_reactions/emoji_reactions.js
+++ b/src/components/emoji_reactions/emoji_reactions.js
@@ -62,7 +62,7 @@ const EmojiReactions = {
},
async fetchEmojiReactionsIfMissing() {
const hasNoAccounts = this.status.emoji_reactions.find((r) => !r.accounts)
- if (hasNoAccounts) {
+ if (!hasNoAccounts) {
return await useStatusesStore().fetchEmojiReactions(this.status.id)
}
},
diff --git a/src/components/mention_link/mention_link.vue b/src/components/mention_link/mention_link.vue
index 33f0d9db7..3973522b0 100644
--- a/src/components/mention_link/mention_link.vue
+++ b/src/components/mention_link/mention_link.vue
@@ -8,15 +8,20 @@
:href="url"
class="original"
target="_blank"
- v-html="content"
- />
+ >
+
+
+
#{{ hashtag.name }}
diff --git a/src/components/status/status.js b/src/components/status/status.js
index 387146db1..16625235d 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -128,6 +128,7 @@ const Status = {
return {
replying: false,
unmuted: false,
+ userExpanded: false,
mediaPlaying: new Set(),
error: null,
headTailLinks: null,
@@ -523,6 +524,9 @@ const Status = {
toggleMute() {
this.unmuted = !this.unmuted
},
+ toggleUserExpanded() {
+ this.userExpanded = !this.userExpanded
+ },
generateUserProfileLink(id, name) {
return generateProfileLink(
id,
@@ -572,12 +576,6 @@ const Status = {
this.$emit('heightChange')
},
},
- unmuted() {
- this.$emit('heightChange')
- },
- error() {
- this.$emit('heightChange')
- },
replying() {
this.$emit('heightChange')
},
@@ -606,6 +604,7 @@ const Status = {
},
isSuspendable: function (suspend) {
this.$emit('suspendableStateChange', { id: this.status.id, suspend })
+ this.$emit('heightChange')
},
},
}
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 5171f7657..0db67f24b 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -549,7 +549,6 @@
@posted="closeReplyForm"
@draft-done="closeReplyForm"
@close-accepted="closeReplyForm"
- @resize="$emit('heightChange')"
/>
diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js
index 3c7e33060..029693651 100644
--- a/src/components/timeline/timeline.js
+++ b/src/components/timeline/timeline.js
@@ -239,7 +239,7 @@ const Timeline = {
const bodyBRect = document.body.getBoundingClientRect()
const height = Math.max(bodyBRect.height, -bodyBRect.y)
if (
- !this.timeline.fetcher.loadingOlder &&
+ !this.timeline.fetcher.loadingOlder.value &&
window.innerHeight + window.pageYOffset >= height - 750
) {
this.fetchOlderStatuses()
diff --git a/src/components/user_avatar/user_avatar.js b/src/components/user_avatar/user_avatar.js
index b80aa8fb8..c8701fe66 100644
--- a/src/components/user_avatar/user_avatar.js
+++ b/src/components/user_avatar/user_avatar.js
@@ -12,7 +12,7 @@ const UserAvatar = {
props: {
// UserID of a user to show avatar of
userId: {
- required: true,
+ required: false, // You can pass null to just render a placeholder
type: String,
},
// Use less space and use alternative roundness
diff --git a/src/components/user_avatar/user_avatar.vue b/src/components/user_avatar/user_avatar.vue
index d9e96d52d..613d224a0 100644
--- a/src/components/user_avatar/user_avatar.vue
+++ b/src/components/user_avatar/user_avatar.vue
@@ -70,6 +70,7 @@
&.-placeholder {
background-color: var(--background);
+ border: 1px solid var(--border)
}
}
diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.js b/src/components/who_to_follow_panel/who_to_follow_panel.js
index 0f7f93556..b87004e44 100644
--- a/src/components/who_to_follow_panel/who_to_follow_panel.js
+++ b/src/components/who_to_follow_panel/who_to_follow_panel.js
@@ -30,8 +30,8 @@ function showWhoToFollow(panel, reply) {
})
}
-function getWhoToFollow() {
- const credentials = useOAuthStore().token
+function getWhoToFollow(panel) {
+ const credentials = panel.$useUsersStore().currentUser.credentials
if (credentials) {
panel.usersToFollow.forEach((toFollow) => {
toFollow.name = 'Loading...'
@@ -66,7 +66,7 @@ const WhoToFollowPanel = {
watch: {
user: function () {
if (this.suggestionsEnabled) {
- getWhoToFollow()
+ getWhoToFollow(this)
}
},
},
@@ -77,7 +77,7 @@ const WhoToFollowPanel = {
id: 0,
}))
if (this.suggestionsEnabled) {
- getWhoToFollow()
+ getWhoToFollow(this)
}
},
}
diff --git a/src/services/chat_utils/chat_utils.js b/src/services/chat_utils/chat_utils.js
index a5c0d67cd..d99c17ed8 100644
--- a/src/services/chat_utils/chat_utils.js
+++ b/src/services/chat_utils/chat_utils.js
@@ -11,14 +11,13 @@ export const maybeShowChatNotification = (chat) => {
title: chat.account.name,
icon: chat.account.profile_image_url,
body: chat.lastMessage.content,
- type: 'chatMention',
}
if (chat.lastMessage.attachment?.type === 'image') {
opts.image = chat.lastMessage.attachment.preview_url
}
- showDesktopNotification(opts)
+ showDesktopNotification(window.vuex.state, opts)
}
export const buildFakeMessage = ({
diff --git a/src/services/status_poster/status_poster.service.js b/src/services/status_poster/status_poster.service.js
index 41038573d..00b8699ac 100644
--- a/src/services/status_poster/status_poster.service.js
+++ b/src/services/status_poster/status_poster.service.js
@@ -2,7 +2,7 @@ import { map } from 'lodash'
import { useStatusesStore } from 'src/stores/statuses.js'
import { useTimelinesStore } from 'src/stores/timelines.js'
-import { useOAuthStore } from 'src/stores/oauth.js'
+import { useUsersStore } from 'src/stores/users.js'
import {
editStatus as apiEditStatus,
@@ -28,7 +28,7 @@ const postStatus = ({
const mediaIds = map(media, 'id')
return apiPostStatus({
- credentials: useOAuthStore().token,
+ credentials: useUsersStore().currentUser.credentials,
status,
spoilerText,
visibility,
@@ -71,7 +71,7 @@ const editStatus = ({
return apiEditStatus({
id: statusId,
- credentials: useOAuthStore().token,
+ credentials: useUsersStore().currentUser.credentials,
status,
spoilerText,
sensitive,
@@ -101,12 +101,12 @@ const editStatus = ({
}
const uploadMedia = ({ store, formData }) => {
- const credentials = useOAuthStore().token
+ const credentials = useUsersStore().currentUser.credentials
return apiUploadMedia({ credentials, formData }).then(({ data }) => data)
}
const setMediaDescription = ({ store, id, description }) => {
- const credentials = useOAuthStore().token
+ const credentials = useUsersStore().currentUser.credentials
return apiSetMediaDescription({ credentials, id, description }).then(
({ data }) => data,
)
diff --git a/src/stores/chats.js b/src/stores/chats.js
index 82bb638dd..9da01c76b 100644
--- a/src/stores/chats.js
+++ b/src/stores/chats.js
@@ -37,10 +37,7 @@ export const useChatsStore = defineStore('chats', {
actions: {
attachSocket() {
const et = new EventTarget()
- const socket = {
- name: 'chats',
- et,
- }
+ const socket = { et }
et.addEventListener('pleroma:chat_update', this.updateChat)
@@ -86,6 +83,9 @@ export const useChatsStore = defineStore('chats', {
chat.lastMessage = updatedChat.lastMessage
chat.unread = updatedChat.unread
chat.updated_at = updatedChat.updated_at
+ if (isNewMessage && chat.unread) {
+ maybeShowChatNotification(chat)
+ }
} else {
this.chatList.data.push(updatedChat)
this.chatList.idStore[updatedChat.id] = updatedChat
@@ -98,16 +98,16 @@ export const useChatsStore = defineStore('chats', {
chat.unread = 0
}
},
- updateChat({ data: { chatUpdate: updatedChat } }) {
+ updateChat({ chat: updatedChat }) {
const chat = getChatById(this, updatedChat.id)
if (chat) {
chat.lastMessage = updatedChat.lastMessage
chat.unread = updatedChat.unread
chat.updated_at = updatedChat.updated_at
- } else {
+ }
+ if (!chat) {
this.chatList.data.unshift(updatedChat)
}
- maybeShowChatNotification(chat)
this.chatList.idStore[updatedChat.id] = updatedChat
},
deleteChat(id) {
diff --git a/src/stores/instance.js b/src/stores/instance.js
index 12480e8c1..123f0b819 100644
--- a/src/stores/instance.js
+++ b/src/stores/instance.js
@@ -14,7 +14,6 @@ import {
import { useInterfaceStore } from 'src/stores/interface.js'
import { useUsersStore } from 'src/stores/users.js'
-import { useOAuthStore } from 'src/stores/oauth.js'
import { fetchKnownDomains } from 'src/api/public.js'
@@ -214,7 +213,7 @@ export const useInstanceStore = defineStore('instance', {
async getKnownDomains() {
try {
const { data } = await fetchKnownDomains({
- credentials: useOAuthStore().token
+ credentials: useUsersStore().currentUser.credentials,
})
this.knownDomains = data
} catch (e) {
diff --git a/src/stores/interface.js b/src/stores/interface.js
index e87a0ecd9..0eba6f158 100644
--- a/src/stores/interface.js
+++ b/src/stores/interface.js
@@ -96,10 +96,7 @@ export const useInterfaceStore = defineStore('interface', {
actions: {
attachSocket() {
const et = new EventTarget()
- const socket = {
- name: 'interface',
- et,
- }
+ const socket = { et }
et.addEventListener('open', this.onStreamConnect)
et.addEventListener('close', this.onStreamDisconnect)
@@ -857,7 +854,7 @@ export const useInterfaceStore = defineStore('interface', {
},
unregisterPushNotifications() {
- const token = useOAuthStore().token
+ const token = this.currentUser.credentials
unregisterPushNotifications(token)
},
diff --git a/src/stores/notifications.js b/src/stores/notifications.js
index 3405fb352..a12ce8133 100644
--- a/src/stores/notifications.js
+++ b/src/stores/notifications.js
@@ -31,9 +31,7 @@ export const defaultState = () => ({
statusIdStore: new Set(),
socket: null,
streaming: false,
- fetching: true,
fetcher: null,
- paused: false,
})
export const useNotificationsStore = defineStore('notifications', {
@@ -42,29 +40,14 @@ export const useNotificationsStore = defineStore('notifications', {
// Init
attachSocket() {
const et = new EventTarget()
- const socket = {
- name: 'notifications',
- et,
- }
+ const socket = { et }
et.addEventListener('notification', this.addNewNotifications)
et.addEventListener('open', this.onStreamConnect)
et.addEventListener('close', this.onStreamDisconnect)
+ useStreamingStore().addSubscriber(socket)
this.socket = socket
- useStreamingStore().addSubscriber(this.socket)
- },
- pause() {
- this.paused = true
- if (this.fetcher && this.fetching) {
- this.stopFetching('Notifications paused')
- }
- },
- resume() {
- this.paused = false
- if (this.fetcher && this.fetching) {
- this.startFetching('Notifications resumed')
- }
},
activate() {
this.attachSocket()
@@ -79,7 +62,7 @@ export const useNotificationsStore = defineStore('notifications', {
this.startFetching('Notifications activated')
},
deactivate() {
- if (this.fetching) {
+ if (!this.streaming) {
this.stopFetching('Notifications deactivated')
}
@@ -94,7 +77,6 @@ export const useNotificationsStore = defineStore('notifications', {
Object.keys(blankState).forEach((k) => {
this[k] = blankState[k]
})
- console.log('[Notifications] Deactivated', this.fetcher)
},
// Poll & Push
@@ -109,30 +91,20 @@ export const useNotificationsStore = defineStore('notifications', {
this.startFetching('Socket disconnected')
},
startFetching(reason) {
- if (this.paused) {
- console.debug(
- '[Notificatiosn] NOT Starting notifications fetcher because it is paused',
- 'Original Reason:',
- reason,
- )
- return
- }
console.debug(
- '[Notifications] Starting notifications fetcher',
+ '[Notifications] Starting fetching notifications',
'Reason:',
reason,
)
this.fetcher.startFetching()
- this.fetching = true
},
stopFetching(reason) {
- this.fetcher.stopFetching()
- this.fetching = false
console.debug(
- '[Notifications] Stopped notifications fetcher',
+ '[Notifications] Stopped fetching notifications',
'Reason:',
reason,
)
+ this.fetcher.stopFetching()
},
// Updates
@@ -251,7 +223,7 @@ export const useNotificationsStore = defineStore('notifications', {
case 'follow_request':
break
default:
- this.markSingleNotificationAsSeen(id)
+ this.markSingleNotificationAsSeen({ id })
}
}
},
diff --git a/src/stores/search.js b/src/stores/search.js
index cd7862d23..ad85712c4 100644
--- a/src/stores/search.js
+++ b/src/stores/search.js
@@ -19,7 +19,7 @@ export const useSearchStore = defineStore('search', {
credentials: useOAuthStore().token,
})
- const { accounts, statuses, hashtags } = data
+ const { accounts, statuses } = data
useUsersStore().addNewUsers({
...rest,
@@ -36,7 +36,6 @@ export const useSearchStore = defineStore('search', {
useStatusesStore().allStatuses.get(s.id),
)
output.accounts = accounts.map((s) => useUsersStore().findUser(s.id))
- output.hashtags = hashtags ?? []
return output
},
diff --git a/src/stores/statuses.js b/src/stores/statuses.js
index 337cb399d..8836a0a77 100644
--- a/src/stores/statuses.js
+++ b/src/stores/statuses.js
@@ -49,7 +49,6 @@ export const useStatusesStore = defineStore('statuses', {
data.forEach((id) => this.setDeleted(id))
const socket = {
- name: 'statuses',
et,
handlers: {
handleUpdate,
@@ -65,9 +64,15 @@ export const useStatusesStore = defineStore('statuses', {
this.socket = socket
},
resetStatuses() {
+ this.socket.et.removeEventListener('update', this.socket.handleUpdate)
+ this.socket.et.removeEventListener(
+ 'status.update',
+ this.socket.handleUpdate,
+ )
+ this.socket.et.removeEventListener('delete', this.socket.handleDelete)
+
const emptyState = defaultState()
Object.entries(emptyState).forEach(([key, value]) => {
- if (key === 'socket') return
this[key] = value
})
},
@@ -149,7 +154,7 @@ export const useStatusesStore = defineStore('statuses', {
const newStatus = {
...old,
- ...Object.fromEntries(Object.entries(neu).filter(([, v]) => v !== undefined)),
+ ...neu,
user,
}
diff --git a/src/stores/streaming.js b/src/stores/streaming.js
index 1b4d07292..5129a571d 100644
--- a/src/stores/streaming.js
+++ b/src/stores/streaming.js
@@ -131,7 +131,6 @@ export const useStreamingStore = defineStore('streaming', {
},
getSubArgs(stream) {
- if (stream === undefined) return undefined
const argumentKey = ARGUMENT_MAP[stream.name]
const args = argumentKey
? {
diff --git a/src/stores/timelines.js b/src/stores/timelines.js
index 190396f48..fe098587a 100644
--- a/src/stores/timelines.js
+++ b/src/stores/timelines.js
@@ -16,11 +16,9 @@ const emptyTl = (name, argument = null) => {
maxId: '',
minId: '',
streaming: false,
- fetching: false,
reloadNeeded: false,
fetcher: null,
socket: null,
- paused: false,
}
const property = ARGUMENT_MAP[name]
@@ -107,16 +105,16 @@ export const useTimelinesStore = defineStore('timelines', {
const openHandler = () => this.onStreamConnect(timelineName, argument)
const closeHandler = () =>
this.onStreamDisconnect(timelineName, argument)
- const messageHandler = (message) => {
- this.onStreamMessage(timelineName, argument, message)
- }
+ const messageHandler =
+ () =>
+ ({ detail: message }) =>
+ this.onStreamMessage(timelineName, argument, message)
et.addEventListener('open', openHandler)
et.addEventListener('close', closeHandler)
et.addEventListener('update', messageHandler)
timeline.socket = {
- name: 'timelines',
stream: {
name: streamName,
argument,
@@ -135,7 +133,7 @@ export const useTimelinesStore = defineStore('timelines', {
deactivate(timelineName, persistent) {
const timeline = this[timelineName]
if (timeline.persistent && !persistent) return
- if (timeline.fetching) {
+ if (!timeline.streaming) {
this.stopFetchingTimeline(timelineName, 'Timeline deactivation')
}
@@ -179,48 +177,6 @@ export const useTimelinesStore = defineStore('timelines', {
})
},
- // Pause
- pause(name) {
- const timeline = this[name]
- timeline.paused = true
- console.debug(
- '[Timelines] Pausing timeline',
- name,
- )
- if (timeline.fetcher && timeline.fetching) {
- timeline.fetcher.stopFetching()
- }
- },
- resume(name) {
- const timeline = this[name]
- timeline.paused = false
- console.debug(
- '[Timelines] Resuming timeline',
- name,
- )
- if (timeline.fetcher && timeline.fetching) {
- timeline.fetcher.startFetching()
- }
- },
- pauseAll() {
- TIMELINES.forEach((name) => {
- try {
- this.pause(name)
- } catch (e) {
- console.error(`[Timelines] Failed to pause timeline ${name}:`, e)
- }
- })
- },
- resumeAll() {
- TIMELINES.forEach((name) => {
- try {
- this.resume(name)
- } catch (e) {
- console.error(`[Timelines] Failed to pause timeline ${name}:`, e)
- }
- })
- },
-
// Update stuff
addStatusesToTimeline(
timelineName,
@@ -275,7 +231,7 @@ export const useTimelinesStore = defineStore('timelines', {
},
onStreamMessage(timeline, argument, event) {
this.addStatusesToTimeline(timeline, argument, {
- statuses: event.data.map(({ id }) => id),
+ statuses: [event.data.status.id],
})
},
@@ -291,28 +247,15 @@ export const useTimelinesStore = defineStore('timelines', {
this.startFetchingTimeline(timeline, argument, 'Socket disconnected')
},
startFetchingTimeline(timelineName, argument, reason) {
- const timeline = this[timelineName]
- console.log('[Timelines]', toValue(timeline))
- if (timeline.paused) {
- console.debug(
- '[Timelines] NOT Starting timeline fetcher because it is paused',
- timelineName,
- argument,
- 'Original Reason:',
- reason,
- )
- return
- }
-
console.debug(
- '[Timelines] Starting timeline fetcher',
+ '[Timelines] Starting fetching timeline',
timelineName,
argument,
'Reason:',
reason,
)
+ const timeline = this[timelineName]
timeline.fetcher.startFetching()
- timeline.fetching = true
},
stopFetchingTimeline(timelineName, reason) {
const timeline = this[timelineName]
@@ -332,7 +275,6 @@ export const useTimelinesStore = defineStore('timelines', {
'Reason:',
reason,
)
- timeline.fetching = false
}
},
diff --git a/src/stores/users.js b/src/stores/users.js
index 9b824bf04..10d9222c9 100644
--- a/src/stores/users.js
+++ b/src/stores/users.js
@@ -2,8 +2,6 @@ import Cookies from 'js-cookie'
import { last } from 'lodash'
import { defineStore } from 'pinia'
-import { WSConnectionStatus } from 'src/api/websocket.js'
-
import { useAnnouncementsStore } from 'src/stores/announcements.js'
import { useBookmarkFoldersStore } from 'src/stores/bookmark_folders.js'
import { useChatsStore } from 'src/stores/chats.js'
@@ -617,15 +615,12 @@ export const useUsersStore = defineStore('users', {
user.domainMutes = new Set()
this.lastLoginName = user.screen_name
- useTimelinesStore().deactivateAll()
- useStatusesStore().resetStatuses()
+ this.currentUser = user
this.users = new Map()
this.usersByName = new Map()
this.usersByURL = new Map()
this.relationships = new Map()
- this.currentUser = user
- this.addNewUsers({ data: user, ...rest })
useInterfaceStore().onLogin()
useSyncConfigStore()
@@ -639,6 +634,7 @@ export const useUsersStore = defineStore('users', {
})
useUserHighlightStore().initUserHighlight(user)
+ this.addNewUsers({ data: user, ...rest })
useEmojiStore().fetchEmoji()
@@ -664,8 +660,8 @@ export const useUsersStore = defineStore('users', {
}
// DMs and Home
- useTimelinesStore().activatePersistents()
useNotificationsStore().activate()
+ useTimelinesStore().activatePersistents()
if (useInstanceCapabilitiesStore().pleromaChatMessagesAvailable) {
// Start fetching chats
@@ -712,16 +708,6 @@ export const useUsersStore = defineStore('users', {
const store = window.vuex
const oauth = useOAuthStore()
- // Pause fetching
- useNotificationsStore().pause()
- useTimelinesStore().pauseAll()
-
- // Pause-less stores
- useAnnouncementsStore().stopFetching()
- useListsStore().stopFetching()
- useBookmarkFoldersStore().stopFetching()
- store?.dispatch('stopFetchingFollowRequests')
-
// NOTE: No need to verify the app still exists, because if it doesn't,
// the token will be invalid too
return oauth
@@ -736,53 +722,28 @@ export const useUsersStore = defineStore('users', {
return revokeToken(params)
})
.then(() => {
- oauth.clearToken()
-
this.currentUser = null
this.lastLoginName = null
- useNotificationsStore().deactivate()
-
- // Full reset on logout success
- useTimelinesStore().deactivateAll()
- useStatusesStore().resetStatuses()
- useChatsStore().resetChats()
-
this.users = new Map()
this.usersByName = new Map()
this.usersByURL = new Map()
this.relationships = new Map()
-
- // Socket is most likely already closed by server
- if (
- useMergedConfigStore().mergedConfig.useStreamingApi
- && useStreamingStore().state !== WSConnectionStatus.CLOSED
- ) {
+ useNotificationsStore().deactivate()
+ useAnnouncementsStore().stopFetching()
+ useListsStore().stopFetching()
+ useBookmarkFoldersStore().stopFetching()
+ store?.dispatch('stopFetchingFollowRequests')
+ useTimelinesStore().deactivateAll()
+ useStatusesStore().resetStatuses()
+ if (useMergedConfigStore().mergedConfig.useStreamingApi) {
useStreamingStore().stopSocket()
}
-
+ useChatsStore().resetChats()
+ oauth.clearToken()
Cookies.remove('__Host-pleroma_key', { path: '/' })
useInterfaceStore().onLogout()
})
- .catch((e) => {
- useInterfaceStore().pushGlobalNotice({
- messageKey: 'user.logout_failure',
- messageArgs: {
- error: e,
- },
- level: 'error',
- })
- console.error('Logout error!', e)
-
- useAnnouncementsStore().startFetching()
- useListsStore().startFetching()
- useBookmarkFoldersStore().startFetching()
- store?.dispatch('startFetchingFollowRequests')
- })
- .finally(() => {
- useNotificationsStore().resume()
- useTimelinesStore().resumeAll()
- })
},
},
persist: {
diff --git a/test/unit/specs/components/rich_content.spec.js b/test/unit/specs/components/rich_content.spec.js
index 19bfdc035..81ce72e87 100644
--- a/test/unit/specs/components/rich_content.spec.js
+++ b/test/unit/specs/components/rich_content.spec.js
@@ -354,11 +354,13 @@ describe('RichContent', () => {
'