diff --git a/src/boot/routes.js b/src/boot/routes.js
index 6956d0140..3b21d874d 100644
--- a/src/boot/routes.js
+++ b/src/boot/routes.js
@@ -1,15 +1,11 @@
import AuthForm from 'src/components/auth_form/auth_form.js'
import BookmarkTimeline from 'src/components/bookmark_timeline/bookmark_timeline.vue'
-import BubbleTimeline from 'src/components/bubble_timeline/bubble_timeline.vue'
import ConversationPage from 'src/components/conversation-page/conversation-page.vue'
-import DMs from 'src/components/dm_timeline/dm_timeline.vue'
-import FriendsTimeline from 'src/components/friends_timeline/friends_timeline.vue'
import NavPanel from 'src/components/nav_panel/nav_panel.vue'
-import PublicAndExternalTimeline from 'src/components/public_and_external_timeline/public_and_external_timeline.vue'
-import PublicTimeline from 'src/components/public_timeline/public_timeline.vue'
import QuotesTimeline from 'src/components/quotes_timeline/quotes_timeline.vue'
import RemoteUserResolver from 'src/components/remote_user_resolver/remote_user_resolver.vue'
import TagTimeline from 'src/components/tag_timeline/tag_timeline.vue'
+import Timeline from 'src/components/timeline/timeline.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
@@ -42,22 +38,38 @@ export default (store) => {
{
name: 'public-external-timeline',
path: '/main/all',
- component: PublicAndExternalTimeline,
+ component: Timeline,
+ props: () => ({
+ timelineName: 'publicAndExternal',
+ }),
},
{
name: 'public-timeline',
path: '/main/public',
- component: PublicTimeline,
+ component: Timeline,
+ props: () => ({
+ timelineName: 'public',
+ }),
},
{
name: 'friends',
path: '/main/friends',
- component: FriendsTimeline,
+ component: Timeline,
beforeEnter: validateAuthenticatedRoute,
+ props: () => ({
+ timelineName: 'friends',
+ }),
},
{ name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline },
{ name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline },
- { name: 'bubble', path: '/bubble', component: BubbleTimeline },
+ {
+ name: 'bubble',
+ path: '/bubble',
+ component: Timeline,
+ props: () => ({
+ timelineName: 'bubble',
+ }),
+ },
{
name: 'conversation',
path: '/notice/:id',
@@ -105,8 +117,11 @@ export default (store) => {
{
name: 'dms',
path: '/users/:username/dms',
- component: DMs,
+ component: Timeline,
beforeEnter: validateAuthenticatedRoute,
+ props: () => ({
+ timelineName: 'dms',
+ }),
},
{
name: 'registration',
diff --git a/src/components/bookmark_timeline/bookmark_timeline.js b/src/components/bookmark_timeline/bookmark_timeline.js
index bf633c18c..dbda08ba1 100644
--- a/src/components/bookmark_timeline/bookmark_timeline.js
+++ b/src/components/bookmark_timeline/bookmark_timeline.js
@@ -1,8 +1,10 @@
import Timeline from 'src/components/timeline/timeline.vue'
+import { useStatusesStore } from 'src/stores/statuses.js'
+
const Bookmarks = {
created() {
- this.$store.commit('clearTimeline', { timeline: 'bookmarks' })
+ useStatusesStore().clearTimeline({ timeline: 'bookmarks' })
this.$store.dispatch('startFetchingTimeline', {
timeline: 'bookmarks',
bookmarkFolderId: this.folderId || null,
@@ -21,7 +23,7 @@ const Bookmarks = {
},
watch: {
folderId() {
- this.$store.commit('clearTimeline', { timeline: 'bookmarks' })
+ useStatusesStore().clearTimeline({ timeline: 'bookmarks' })
this.$store.dispatch('stopFetchingTimeline', 'bookmarks')
this.$store.dispatch('startFetchingTimeline', {
timeline: 'bookmarks',
@@ -30,7 +32,7 @@ const Bookmarks = {
},
},
unmounted() {
- this.$store.commit('clearTimeline', { timeline: 'bookmarks' })
+ useStatusesStore().clearTimeline({ timeline: 'bookmarks' })
this.$store.dispatch('stopFetchingTimeline', 'bookmarks')
},
}
diff --git a/src/components/bubble_timeline/bubble_timeline.vue b/src/components/bubble_timeline/bubble_timeline.vue
deleted file mode 100644
index 4aefa2729..000000000
--- a/src/components/bubble_timeline/bubble_timeline.vue
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
diff --git a/src/components/chat_message/chat_message.js b/src/components/chat_message/chat_message.js
index 0428b404e..5d086aade 100644
--- a/src/components/chat_message/chat_message.js
+++ b/src/components/chat_message/chat_message.js
@@ -19,6 +19,7 @@ import UserPopover from 'src/components/user_popover/user_popover.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInterfaceStore } from 'src/stores/interface'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useUsersStore } from 'src/stores/users.js'
import { library } from '@fortawesome/fontawesome-svg-core'
@@ -100,9 +101,9 @@ const ChatMessage = {
return !this.message.in_reply_to_status_id
},
customReplyTo() {
- return this.$store.state.statuses.allStatusesObject[
- this.message.in_reply_to_status_id
- ]
+ return useStatusesStore().allStatuses.get(
+ this.message.in_reply_to_status_id,
+ )
},
replyToName() {
if (this.message.in_reply_to_screen_name) {
diff --git a/src/components/chat_view/chat_view.js b/src/components/chat_view/chat_view.js
index 1998c9453..498ddbd84 100644
--- a/src/components/chat_view/chat_view.js
+++ b/src/components/chat_view/chat_view.js
@@ -19,6 +19,7 @@ import { useChatsStore } from 'src/stores/chats.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useOAuthStore } from 'src/stores/oauth.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useUsersStore } from 'src/stores/users.js'
import {
@@ -122,7 +123,7 @@ const Chat = {
},
computed: {
conversationId() {
- const status = this.$store.state.statuses.allStatusesObject[this.statusId]
+ const status = useStatusesStore().allStatuses.get(this.statusId)
return get(
status,
'retweeted_status.statusnet_conversation_id',
diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js
index ea5637944..4d51b8461 100644
--- a/src/components/conversation/conversation.js
+++ b/src/components/conversation/conversation.js
@@ -1,4 +1,4 @@
-import { clone, filter, findIndex, get, reduce } from 'lodash'
+import { get, reduce } from 'lodash'
import { mapState as mapPiniaState } from 'pinia'
import { mapState } from 'vuex'
@@ -9,9 +9,10 @@ import QuickViewSettings from 'src/components/quick_view_settings/quick_view_set
import RichContent from 'src/components/rich_content/rich_content.jsx'
import ThreadTree from 'src/components/thread_tree/thread_tree.vue'
-import { useInterfaceStore } from 'src/stores/interface'
+import { useInterfaceStore } from 'src/stores/interface.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useOAuthStore } from 'src/stores/oauth.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { fetchConversation, fetchStatus } from 'src/api/public.js'
import { WSConnectionStatus } from 'src/api/websocket.js'
@@ -51,20 +52,6 @@ const sortById = (a, b) => {
}
}
-const sortAndFilterConversation = (conversation, statusoid) => {
- if (statusoid.type === 'retweet') {
- conversation = filter(
- conversation,
- (status) =>
- status.type === 'retweet' ||
- status.id !== statusoid.retweeted_status.id,
- )
- } else {
- conversation = filter(conversation, (status) => status.type !== 'retweet')
- }
- return conversation.filter(Boolean).sort(sortById)
-}
-
const conversation = {
props: {
statusId: {
@@ -166,7 +153,7 @@ const conversation = {
return this.virtualHidden && this.suspendable
},
status() {
- return this.$store.state.statuses.allStatusesObject[this.statusId]
+ return useStatusesStore().allStatuses.get(this.statusId)
},
originalStatusId() {
if (this.status.retweeted_status) {
@@ -187,15 +174,11 @@ const conversation = {
return [this.status]
}
- const conversation = clone(
- this.$store.state.statuses.conversationsObject[this.conversationId],
+ const conversation = useStatusesStore().conversations.get(
+ this.conversationId,
)
- const statusIndex = findIndex(conversation, { id: this.originalStatusId })
- if (statusIndex !== -1) {
- conversation[statusIndex] = this.status
- }
- return sortAndFilterConversation(conversation, this.status)
+ return [...conversation.values()].toSorted(sortById)
},
statusMap() {
return this.conversation.reduce((res, s) => {
@@ -441,7 +424,7 @@ const conversation = {
}
},
virtualHidden() {
- this.$store.dispatch('setVirtualHeight', {
+ useStatusesStore().setVirtualHeight({
statusId: this.statusId,
height: `${this.$el.clientHeight}px`,
})
@@ -453,9 +436,12 @@ const conversation = {
fetchConversation({
id: this.statusId,
credentials: useOAuthStore().token,
- }).then(({ data: { ancestors, descendants } }) => {
- this.$store.dispatch('addNewStatuses', { statuses: ancestors })
- this.$store.dispatch('addNewStatuses', { statuses: descendants })
+ }).then(({ data: { ancestors, descendants }, timestamp }) => {
+ useStatusesStore().addNewStatuses({ statuses: ancestors, timestamp })
+ useStatusesStore().addNewStatuses({
+ statuses: descendants,
+ timestamp,
+ })
this.setFocused(this.originalStatusId)
})
} else {
@@ -482,17 +468,17 @@ const conversation = {
this.focused = id
if (!this.streamingEnabled) {
- this.$store.dispatch('fetchStatus', id)
+ useStatusesStore().fetchStatus(id)
}
- this.$store.dispatch('fetchFavsAndRepeats', id)
- this.$store.dispatch('fetchEmojiReactionsBy', id)
+ useStatusesStore().fetchFavsAndRepeats(id)
+ useStatusesStore().fetchEmojiReactionsBy(id)
},
toggleExpanded() {
this.expanded = !this.expanded
},
getConversationId(statusId) {
- const status = this.$store.state.statuses.allStatusesObject[statusId]
+ const status = useStatusesStore().allStatuses.get(statusId)
return get(
status,
'retweeted_status.statusnet_conversation_id',
diff --git a/src/components/dm_timeline/dm_timeline.js b/src/components/dm_timeline/dm_timeline.js
deleted file mode 100644
index d54044ff7..000000000
--- a/src/components/dm_timeline/dm_timeline.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import Timeline from 'src/components/timeline/timeline.vue'
-
-const DMs = {
- computed: {
- timeline() {
- return this.$store.state.statuses.timelines.dms
- },
- },
- components: {
- Timeline,
- },
-}
-
-export default DMs
diff --git a/src/components/dm_timeline/dm_timeline.vue b/src/components/dm_timeline/dm_timeline.vue
deleted file mode 100644
index c4e4d0703..000000000
--- a/src/components/dm_timeline/dm_timeline.vue
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
diff --git a/src/components/draft/draft.js b/src/components/draft/draft.js
index 49e186eae..1c7f419c6 100644
--- a/src/components/draft/draft.js
+++ b/src/components/draft/draft.js
@@ -6,6 +6,7 @@ import PostStatusForm from 'src/components/post_status_form/post_status_form.vue
import StatusContent from 'src/components/status_content/status_content.vue'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faPollH } from '@fortawesome/free-solid-svg-icons'
@@ -65,7 +66,7 @@ const Draft = {
},
refStatus() {
return this.draft.refId
- ? this.$store.state.statuses.allStatusesObject[this.draft.refId]
+ ? useStatusesStore().allStatuses.get(this.draft.refId)
: undefined
},
localCollapseSubjectDefault() {
diff --git a/src/components/emoji_reactions/emoji_reactions.js b/src/components/emoji_reactions/emoji_reactions.js
index b3b538a9a..f8b121232 100644
--- a/src/components/emoji_reactions/emoji_reactions.js
+++ b/src/components/emoji_reactions/emoji_reactions.js
@@ -3,6 +3,7 @@ import UserListPopover from 'src/components/user_list_popover/user_list_popover.
import { useInstanceStore } from 'src/stores/instance.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useUsersStore } from 'src/stores/users.js'
import { library } from '@fortawesome/fontawesome-svg-core'
@@ -62,10 +63,7 @@ const EmojiReactions = {
async fetchEmojiReactionsByIfMissing() {
const hasNoAccounts = this.status.emoji_reactions.find((r) => !r.accounts)
if (hasNoAccounts) {
- return await this.$store.dispatch(
- 'fetchEmojiReactionsBy',
- this.status.id,
- )
+ return await useStatusesStore().fetchEmojiReactionsBy(this.status.id)
}
},
reactWith(emoji) {
diff --git a/src/components/friends_timeline/friends_timeline.js b/src/components/friends_timeline/friends_timeline.js
deleted file mode 100644
index b6bee7305..000000000
--- a/src/components/friends_timeline/friends_timeline.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import Timeline from 'src/components/timeline/timeline.vue'
-
-const FriendsTimeline = {
- components: {
- Timeline,
- },
- computed: {
- timeline() {
- return this.$store.state.statuses.timelines.friends
- },
- },
-}
-
-export default FriendsTimeline
diff --git a/src/components/friends_timeline/friends_timeline.vue b/src/components/friends_timeline/friends_timeline.vue
deleted file mode 100644
index 01a568123..000000000
--- a/src/components/friends_timeline/friends_timeline.vue
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
diff --git a/src/components/lists_timeline/lists_timeline.js b/src/components/lists_timeline/lists_timeline.js
index a06220a37..ae58e58ed 100644
--- a/src/components/lists_timeline/lists_timeline.js
+++ b/src/components/lists_timeline/lists_timeline.js
@@ -1,6 +1,7 @@
import Timeline from 'src/components/timeline/timeline.vue'
import { useListsStore } from 'src/stores/lists.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
const ListsTimeline = {
data() {
@@ -21,7 +22,7 @@ const ListsTimeline = {
if (route.name === 'lists-timeline' && route.params.id !== this.listId) {
this.listId = route.params.id
this.$store.dispatch('stopFetchingTimeline', 'list')
- this.$store.commit('clearTimeline', { timeline: 'list' })
+ useStatusesStore().clearTimeline({ timeline: 'list' })
useListsStore().fetchList({ listId: this.listId })
this.$store.dispatch('startFetchingTimeline', {
timeline: 'list',
@@ -40,7 +41,7 @@ const ListsTimeline = {
},
unmounted() {
this.$store.dispatch('stopFetchingTimeline', 'list')
- this.$store.commit('clearTimeline', { timeline: 'list' })
+ useStatusesStore().clearTimeline({ timeline: 'list' })
},
}
diff --git a/src/components/public_and_external_timeline/public_and_external_timeline.js b/src/components/public_and_external_timeline/public_and_external_timeline.js
deleted file mode 100644
index 6dc8df02a..000000000
--- a/src/components/public_and_external_timeline/public_and_external_timeline.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import Timeline from 'src/components/timeline/timeline.vue'
-
-const PublicAndExternalTimeline = {
- components: {
- Timeline,
- },
- computed: {
- timeline() {
- return this.$store.state.statuses.timelines.publicAndExternal
- },
- },
- created() {
- this.$store.dispatch('startFetchingTimeline', {
- timeline: 'publicAndExternal',
- })
- },
- unmounted() {
- this.$store.dispatch('stopFetchingTimeline', 'publicAndExternal')
- },
-}
-
-export default PublicAndExternalTimeline
diff --git a/src/components/public_and_external_timeline/public_and_external_timeline.vue b/src/components/public_and_external_timeline/public_and_external_timeline.vue
deleted file mode 100644
index fcd915acb..000000000
--- a/src/components/public_and_external_timeline/public_and_external_timeline.vue
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
diff --git a/src/components/public_timeline/public_timeline.js b/src/components/public_timeline/public_timeline.js
deleted file mode 100644
index bbeae47af..000000000
--- a/src/components/public_timeline/public_timeline.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import Timeline from 'src/components/timeline/timeline.vue'
-
-const PublicTimeline = {
- components: {
- Timeline,
- },
- computed: {
- timeline() {
- return this.$store.state.statuses.timelines.public
- },
- },
- created() {
- this.$store.dispatch('startFetchingTimeline', { timeline: 'public' })
- },
- unmounted() {
- this.$store.dispatch('stopFetchingTimeline', 'public')
- },
-}
-
-export default PublicTimeline
diff --git a/src/components/public_timeline/public_timeline.vue b/src/components/public_timeline/public_timeline.vue
deleted file mode 100644
index 5720068df..000000000
--- a/src/components/public_timeline/public_timeline.vue
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
diff --git a/src/components/quick_filter_settings/quick_filter_settings.js b/src/components/quick_filter_settings/quick_filter_settings.js
index 533d19313..089cb1d26 100644
--- a/src/components/quick_filter_settings/quick_filter_settings.js
+++ b/src/components/quick_filter_settings/quick_filter_settings.js
@@ -5,6 +5,7 @@ import Popover from 'src/components/popover/popover.vue'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useLocalConfigStore } from 'src/stores/local_config.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { useUsersStore } from 'src/stores/users.js'
@@ -27,7 +28,7 @@ const QuickFilterSettings = {
path: 'replyVisibility',
value: visibility,
})
- this.$store.dispatch('queueFlushAll')
+ useStatusesStore().queueFlushAll()
},
openTab(tab) {
useInterfaceStore().openSettingsModalTab(tab)
diff --git a/src/components/quote/quote.js b/src/components/quote/quote.js
index 439d3440a..1f230b488 100644
--- a/src/components/quote/quote.js
+++ b/src/components/quote/quote.js
@@ -1,3 +1,5 @@
+import { useStatusesStore } from 'src/stores/statuses.js'
+
import { library } from '@fortawesome/fontawesome-svg-core'
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
@@ -45,7 +47,7 @@ export default {
computed: {
quotedStatus() {
return this.statusId
- ? this.$store.state.statuses.allStatusesObject[this.statusId]
+ ? useStatusesStore().allStatuses.get(this.statusId)
: undefined
},
shouldDisplayQuote() {
@@ -79,8 +81,8 @@ export default {
this.fetchAttempted = true
this.fetching = true
this.$emit('loading', true)
- this.$store
- .dispatch('fetchStatus', this.statusId)
+ useStatusesStore()
+ .fetchStatus(this.statusId)
.then(() => {
this.displayQuote = true
})
diff --git a/src/components/quotes_timeline/quotes_timeline.js b/src/components/quotes_timeline/quotes_timeline.js
index f92f109be..4778f1daa 100644
--- a/src/components/quotes_timeline/quotes_timeline.js
+++ b/src/components/quotes_timeline/quotes_timeline.js
@@ -1,8 +1,10 @@
import Timeline from 'src/components/timeline/timeline.vue'
+import { useStatusesStore } from 'src/stores/statuses.js'
+
const QuotesTimeline = {
created() {
- this.$store.commit('clearTimeline', { timeline: 'quotes' })
+ useStatusesStore().clearTimeline({ timeline: 'tag' })
this.$store.dispatch('startFetchingTimeline', {
timeline: 'quotes',
statusId: this.statusId,
@@ -21,7 +23,7 @@ const QuotesTimeline = {
},
watch: {
statusId() {
- this.$store.commit('clearTimeline', { timeline: 'quotes' })
+ useStatusesStore().clearTimeline({ timeline: 'tag' })
this.$store.dispatch('startFetchingTimeline', {
timeline: 'quotes',
statusId: this.statusId,
diff --git a/src/components/search/search.js b/src/components/search/search.js
index 2a6ed5c3e..e4c2c5674 100644
--- a/src/components/search/search.js
+++ b/src/components/search/search.js
@@ -4,6 +4,7 @@ import Conversation from 'src/components/conversation/conversation.vue'
import FollowCard from 'src/components/follow_card/follow_card.vue'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useUsersStore } from 'src/stores/users.js'
import { library } from '@fortawesome/fontawesome-svg-core'
@@ -39,11 +40,11 @@ const Search = {
return this.userIds.map((userId) => useUsersStore().findUser(userId))
},
visibleStatuses() {
- const allStatusesObject = this.$store.state.statuses.allStatusesObject
+ const allStatuses = useStatusesStore().allStatuses
return this.statuses.filter(
(status) =>
- allStatusesObject[status.id] && !allStatusesObject[status.id].deleted,
+ allStatuses.has(status.id) && !allStatuses.get(status.id).deleted,
)
},
},
diff --git a/src/components/settings_modal/tabs/clutter_tab.js b/src/components/settings_modal/tabs/clutter_tab.js
index 87269eb99..a3f6e77a5 100644
--- a/src/components/settings_modal/tabs/clutter_tab.js
+++ b/src/components/settings_modal/tabs/clutter_tab.js
@@ -11,6 +11,7 @@ import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
const ClutterTab = {
components: {
@@ -35,7 +36,7 @@ const ClutterTab = {
// Updating nested properties
watch: {
replyVisibility() {
- this.$store.dispatch('queueFlushAll')
+ useStatusesStore().queueFlushAll()
},
},
}
diff --git a/src/components/settings_modal/tabs/filtering_tab.js b/src/components/settings_modal/tabs/filtering_tab.js
index 3a9cad6d2..9d49eca81 100644
--- a/src/components/settings_modal/tabs/filtering_tab.js
+++ b/src/components/settings_modal/tabs/filtering_tab.js
@@ -14,6 +14,7 @@ import UnitSetting from '../helpers/unit_setting.vue'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import {
@@ -265,7 +266,7 @@ const FilteringTab = {
// Updating nested properties
watch: {
replyVisibility() {
- this.$store.dispatch('queueFlushAll')
+ useStatusesStore().queueFlushAll()
},
muteFiltersObject() {
this.muteFiltersDraftObject = cloneDeep(
diff --git a/src/components/status/status.js b/src/components/status/status.js
index 5839eadde..1f942827b 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -23,6 +23,7 @@ import {
import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
import { useUsersStore } from 'src/stores/users.js'
@@ -206,7 +207,7 @@ const Status = {
},
statusFromGlobalRepository() {
// NOTE: Consider to replace status with statusFromGlobalRepository
- return this.$store.state.statuses.allStatusesObject[this.status.id]
+ return useStatusesStore().allStatuses.get(this.status.id)
},
loggedIn() {
return !!this.currentUser
diff --git a/src/components/status_action_buttons/buttons_definitions.js b/src/components/status_action_buttons/buttons_definitions.js
index 6c94b43a5..b13bed033 100644
--- a/src/components/status_action_buttons/buttons_definitions.js
+++ b/src/components/status_action_buttons/buttons_definitions.js
@@ -3,6 +3,7 @@ import { useInstanceStore } from 'src/stores/instance.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useReportsStore } from 'src/stores/reports.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useStatusHistoryStore } from 'src/stores/statusHistory.js'
const PRIVATE_SCOPES = new Set(['private', 'direct'])
@@ -52,7 +53,7 @@ export const BUTTONS = [
(currentUser.id === status.user.id ||
!PRIVATE_SCOPES.has(status.visibility)),
toggleable: true,
- confirm: ({ status, getters }) =>
+ confirm: ({ status }) =>
!status.repeated && useMergedConfigStore().mergedConfig.modalOnRepeat,
confirmStrings: {
title: 'status.repeat_confirm_title',
@@ -60,11 +61,11 @@ export const BUTTONS = [
confirm: 'status.repeat_confirm_accept_button',
cancel: 'status.repeat_confirm_cancel_button',
},
- action({ status, dispatch }) {
+ action({ status }) {
if (!status.repeated) {
- return dispatch('retweet', { id: status.id })
+ return useStatusesStore().retweet(status.id)
} else {
- return dispatch('unretweet', { id: status.id })
+ return useStatusesStore().unretweet(status.id)
}
},
},
@@ -82,11 +83,11 @@ export const BUTTONS = [
counter: ({ status }) => status.fave_num,
anonLink: true,
toggleable: true,
- action({ status, dispatch }) {
+ action({ status }) {
if (!status.favorited) {
- return dispatch('favorite', { id: status.id })
+ return useStatusesStore().favorite(status.id)
} else {
- return dispatch('unfavorite', { id: status.id })
+ return useStatusesStore().unfavorite(status.id)
}
},
},
@@ -112,7 +113,7 @@ export const BUTTONS = [
if: ({ loggedIn }) => loggedIn,
toggleable: false,
dropdown: true,
- action({ status, dispatch, emit }) {
+ action({ status, emit }) {
/* prevent hiding */
},
},
@@ -130,11 +131,11 @@ export const BUTTONS = [
PUBLIC_SCOPES.has(status.visibility)
)
},
- action({ status, dispatch }) {
+ action({ status }) {
if (status.pinned) {
- return dispatch('unpinStatus', status.id)
+ return useStatusesStore().unpinStatus(status.id)
} else {
- return dispatch('pinStatus', status.id)
+ return useStatusesStore().pinStatus(status.id)
}
},
},
@@ -150,11 +151,11 @@ export const BUTTONS = [
label: ({ status }) =>
status.bookmarked ? 'status.unbookmark' : 'status.bookmark',
if: ({ loggedIn }) => loggedIn,
- action({ status, dispatch }) {
+ action({ status }) {
if (status.bookmarked) {
- return dispatch('unbookmark', { id: status.id })
+ return useStatusesStore().unbookmark(status.id)
} else {
- return dispatch('bookmark', { id: status.id })
+ return useStatusesStore().bookmark(status.id)
}
},
},
@@ -165,7 +166,7 @@ export const BUTTONS = [
name: 'editHistory',
icon: 'history',
label: 'status.status_history',
- if({ status, state }) {
+ if({ status }) {
return (
useInstanceCapabilitiesStore().editingAvailable &&
status.edited_at !== null
@@ -196,26 +197,28 @@ export const BUTTONS = [
name: 'edit',
icon: 'pen',
label: 'status.edit',
- if({ status, loggedIn, currentUser, state }) {
+ if({ status, loggedIn, currentUser }) {
return (
loggedIn &&
useInstanceCapabilitiesStore().editingAvailable &&
status.user.id === currentUser.id
)
},
- action({ dispatch, status }) {
- return dispatch('fetchStatusSource', { id: status.id }).then((data) =>
- useEditStatusStore().openEditStatusModal({
- statusId: status.id,
- statusSubject: data.spoiler_text,
- statusText: data.text,
- statusIsSensitive: status.nsfw,
- statusPoll: status.poll,
- statusFiles: [...status.attachments],
- statusVisibility: status.visibility,
- statusContentType: data.content_type,
- }),
- )
+ action({ status }) {
+ return useStatusesStore()
+ .fetchStatusSource(status.id)
+ .then((data) =>
+ useEditStatusStore().openEditStatusModal({
+ statusId: status.id,
+ statusSubject: data.spoiler_text,
+ statusText: data.text,
+ statusIsSensitive: status.nsfw,
+ statusPoll: status.poll,
+ statusFiles: [...status.attachments],
+ statusVisibility: status.visibility,
+ statusContentType: data.content_type,
+ }),
+ )
},
},
{
@@ -260,15 +263,15 @@ export const BUTTONS = [
currentUser.privileges.has('messages_delete'))
)
},
- confirm: ({ getters }) => useMergedConfigStore().mergedConfig.modalOnDelete,
+ confirm: () => useMergedConfigStore().mergedConfig.modalOnDelete,
confirmStrings: {
title: 'status.delete_confirm_title',
body: 'status.delete_confirm',
confirm: 'status.delete_confirm_accept_button',
cancel: 'status.delete_confirm_cancel_button',
},
- action({ dispatch, status }) {
- return dispatch('deleteStatus', { id: status.id })
+ action({ status }) {
+ return useStatusesStore().deleteStatus(status.id)
},
},
{
@@ -287,7 +290,7 @@ export const BUTTONS = [
},
toggleable: false,
dropdown: true,
- action({ status, dispatch, emit }) {
+ action({ status, emit }) {
/* prevent hiding */
},
},
@@ -298,7 +301,7 @@ export const BUTTONS = [
name: 'share',
icon: 'share-alt',
label: 'status.copy_link',
- action({ state, status, router }) {
+ action({ status, router }) {
navigator.clipboard.writeText(
[
useInstanceStore().server,
diff --git a/src/components/status_history_modal/status_history_modal.js b/src/components/status_history_modal/status_history_modal.js
index c165fe411..b27c19b73 100644
--- a/src/components/status_history_modal/status_history_modal.js
+++ b/src/components/status_history_modal/status_history_modal.js
@@ -2,6 +2,7 @@ import { get } from 'lodash'
import Modal from 'src/components/modal/modal.vue'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useStatusHistoryStore } from 'src/stores/statusHistory.js'
const StatusHistoryModal = {
@@ -50,9 +51,11 @@ const StatusHistoryModal = {
this.statuses = []
},
fetchStatusHistory() {
- this.$store.dispatch('fetchStatusHistory', this.params).then((data) => {
- this.statuses = data
- })
+ useStatusesStore()
+ .fetchStatusHistory(this.params)
+ .then((data) => {
+ this.statuses = data
+ })
},
closeModal() {
useStatusHistoryStore().closeStatusHistoryModal()
diff --git a/src/components/status_popover/status_popover.js b/src/components/status_popover/status_popover.js
index 95da91ba7..e9fc2398d 100644
--- a/src/components/status_popover/status_popover.js
+++ b/src/components/status_popover/status_popover.js
@@ -1,7 +1,7 @@
-import { find } from 'lodash'
-
import Popover from 'src/components/popover/popover.vue'
+import { useStatusesStore } from 'src/stores/statuses.js'
+
import { library } from '@fortawesome/fontawesome-svg-core'
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
@@ -17,7 +17,7 @@ const StatusPopover = {
},
computed: {
status() {
- return find(this.$store.state.statuses.allStatuses, { id: this.statusId })
+ return useStatusesStore().allStatuses.get(this.statusId)
},
},
components: {
@@ -30,8 +30,8 @@ const StatusPopover = {
this.error = true
return
}
- this.$store
- .dispatch('fetchStatus', this.statusId)
+ useStatusesStore()
+ .fetchStatus(this.statusId)
.then(() => (this.error = false))
.catch(() => (this.error = true))
}
diff --git a/src/components/tag_timeline/tag_timeline.js b/src/components/tag_timeline/tag_timeline.js
index e82e86cfd..da3fcb693 100644
--- a/src/components/tag_timeline/tag_timeline.js
+++ b/src/components/tag_timeline/tag_timeline.js
@@ -1,8 +1,10 @@
import Timeline from 'src/components/timeline/timeline.vue'
+import { useStatusesStore } from 'src/stores/statuses.js'
+
const TagTimeline = {
created() {
- this.$store.commit('clearTimeline', { timeline: 'tag' })
+ useStatusesStore().clearTimeline({ timeline: 'tag' })
this.$store.dispatch('startFetchingTimeline', {
timeline: 'tag',
tag: this.tag,
@@ -21,7 +23,7 @@ const TagTimeline = {
},
watch: {
tag() {
- this.$store.commit('clearTimeline', { timeline: 'tag' })
+ useStatusesStore().clearTimeline({ timeline: 'tag' })
this.$store.dispatch('startFetchingTimeline', {
timeline: 'tag',
tag: this.tag,
diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js
index de025a253..e3ba35e07 100644
--- a/src/components/timeline/timeline.js
+++ b/src/components/timeline/timeline.js
@@ -9,6 +9,7 @@ import TimelineMenu from 'src/components/timeline_menu/timeline_menu.vue'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useUsersStore } from 'src/stores/users.js'
import timelineFetcher from 'src/services/timeline_fetcher/timeline_fetcher.service.js'
@@ -26,21 +27,19 @@ import {
library.add(faCircleNotch, faCog, faMinus, faArrowUp, faCirclePlus, faCheck)
const Timeline = {
- props: [
- 'timeline',
- 'timelineName',
- 'title',
- 'userId',
- 'listId',
- 'statusId',
- 'bookmarkFolderId',
- 'tag',
- 'embedded',
- 'count',
- 'pinnedStatusIds',
- 'inProfile',
- 'footerSlipgate', // reference to an element where we should put our footer
- ],
+ props: {
+ timelineName: String,
+ userId: String,
+ listId: String,
+ statusId: String,
+ bookmarkFolderId: String,
+ tag: String,
+ embedded: Boolean,
+ count: Number,
+ pinnedStatusIds: Set,
+ inProfile: Boolean,
+ footerSlipgate: Object, // reference to an element where we should put our footer
+ },
data() {
return {
showScrollTop: false,
@@ -59,8 +58,11 @@ const Timeline = {
QuickViewSettings,
},
computed: {
+ timeline() {
+ return useStatusesStore().timelines[this.timelineName]
+ },
filteredVisibleStatuses() {
- return this.timeline.visibleStatuses.filter(
+ return [...this.timeline.visibleStatuses.values()].filter(
(status) =>
this.timelineName !== 'user' ||
(status.id >= this.timeline.minId &&
@@ -116,13 +118,13 @@ const Timeline = {
return keyBy(this.pinnedStatusIds)
},
statusesToDisplay() {
- const amount = this.timeline.visibleStatuses.length
+ const amount = this.timeline.visibleStatuses.size
const statusesPerSide = Math.ceil(Math.max(3, window.innerHeight / 80))
const nonPinnedIndex =
this.virtualScrollIndex - this.filteredPinnedStatusIds.length
const min = Math.max(0, nonPinnedIndex - statusesPerSide)
const max = Math.min(amount, nonPinnedIndex + statusesPerSide)
- return this.timeline.visibleStatuses.slice(min, max).map((_) => _.id)
+ return new Set([...this.timeline.visibleStatuses.keys()].slice(min, max))
},
virtualScrollingEnabled() {
return useMergedConfigStore().mergedConfig.virtualScrolling
@@ -143,7 +145,6 @@ const Timeline = {
}
timelineFetcher.fetchAndUpdate({
- store,
credentials,
timeline: this.timelineName,
showImmediately,
@@ -175,7 +176,7 @@ const Timeline = {
this.handleVisibilityChange,
false,
)
- this.$store.commit('setLoading', {
+ useStatusesStore().setLoading({
timeline: this.timelineName,
value: false,
})
@@ -197,30 +198,31 @@ const Timeline = {
},
showNewStatuses() {
if (this.timeline.flushMarker !== 0) {
- this.$store.commit('clearTimeline', {
+ useStatusesStore().clearTimeline({
timeline: this.timelineName,
excludeUserId: true,
})
- this.$store.commit('queueFlush', { timeline: this.timelineName, id: 0 })
+ useStatusesStore().queueFlush({ timeline: this.timelineName, id: 0 })
if (this.timelineName === 'user') {
this.$store.dispatch('fetchPinnedStatuses', this.userId)
}
this.fetchOlderStatuses()
} else {
this.blockClicksTemporarily()
- this.$store.commit('showNewStatuses', { timeline: this.timelineName })
+ useStatusesStore().showNewStatuses(this.timelineName)
this.paused = false
}
window.scrollTo({ top: 0 })
},
fetchOlderStatuses: throttle(
function () {
- const store = this.$store
const credentials = useUsersStore().currentUser.credentials
- store.commit('setLoading', { timeline: this.timelineName, value: true })
+ useStatusesStore().setLoading({
+ timeline: this.timelineName,
+ value: true,
+ })
timelineFetcher
.fetchAndUpdate({
- store,
credentials,
timeline: this.timelineName,
older: true,
@@ -237,7 +239,7 @@ const Timeline = {
}
})
.finally(() =>
- store.commit('setLoading', {
+ useStatusesStore().setLoading({
timeline: this.timelineName,
value: false,
}),
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
index 287934657..38a2ae144 100644
--- a/src/components/timeline/timeline.vue
+++ b/src/components/timeline/timeline.vue
@@ -90,7 +90,7 @@
:status-id="status.id"
:in-profile="inProfile"
:profile-user-id="userId"
- :virtual-hidden="virtualScrollingEnabled && !statusesToDisplay.includes(status.id)"
+ :virtual-hidden="virtualScrollingEnabled && !statusesToDisplay.has(status.id)"
collapsable
/>
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index 310d66d1d..49065c2a9 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -9,6 +9,7 @@ import UserCard from 'src/components/user_card/user_card.vue'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useUsersStore } from 'src/stores/users.js'
import { library } from '@fortawesome/fontawesome-svg-core'
@@ -106,7 +107,9 @@ const UserProfile = {
const startFetchingTimeline = (timeline, userId) => {
// Clear timeline only if load another user's profile
if (userId !== this.$store.state.statuses.timelines[timeline].userId) {
- this.$store.commit('clearTimeline', { timeline })
+ useStatusesStore().clearTimeline({ timeline: 'user' })
+ useStatusesStore().clearTimeline({ timeline: 'userPinned' })
+ useStatusesStore().clearTimeline({ timeline: 'media' })
}
this.$store.dispatch('startFetchingTimeline', { timeline, userId })
}
diff --git a/src/modules/api.js b/src/modules/api.js
index d91fc04fb..e686df0fe 100644
--- a/src/modules/api.js
+++ b/src/modules/api.js
@@ -8,6 +8,7 @@ import { useInterfaceStore } from 'src/stores/interface.js'
import { useNotificationsStore } from 'src/stores/notifications.js'
import { useOAuthStore } from 'src/stores/oauth.js'
import { useShoutStore } from 'src/stores/shout.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { fetchTimeline } from 'src/api/timelines.js'
import {
@@ -123,14 +124,16 @@ const api = {
data: message.notification,
})
} else if (message.event === 'update') {
- dispatch('addNewStatuses', {
+ useStatusesStore().addNewStatuses({
+ timestamp: Date.now(),
statuses: [message.status],
userId: false,
showImmediately: timelineData.visibleStatuses.length === 0,
timeline: 'friends',
})
} else if (message.event === 'status.update') {
- dispatch('addNewStatuses', {
+ useStatusesStore().addNewStatuses({
+ timestamp: Date.now(),
statuses: [message.status],
userId: false,
showImmediately:
diff --git a/src/modules/index.js b/src/modules/index.js
index 8b48e4e31..6aa236257 100644
--- a/src/modules/index.js
+++ b/src/modules/index.js
@@ -1,10 +1,8 @@
import api from './api.js'
import drafts from './drafts.js'
import profileConfig from './profileConfig.js'
-import statuses from './statuses.js'
export default {
- statuses,
api,
profileConfig,
drafts,
diff --git a/src/modules/statuses.js b/src/modules/statuses.js
deleted file mode 100644
index 7a1444ad3..000000000
--- a/src/modules/statuses.js
+++ /dev/null
@@ -1,906 +0,0 @@
-import {
- each,
- find,
- findIndex,
- first,
- last,
- maxBy,
- merge,
- minBy,
- omitBy,
- remove,
-} from 'lodash'
-
-import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
-import { useInterfaceStore } from 'src/stores/interface.js'
-import { useOAuthStore } from 'src/stores/oauth.js'
-import { useUsersStore } from 'src/stores/users.js'
-
-import {
- fetchEmojiReactions,
- fetchFavoritedByUsers,
- fetchPinnedStatuses,
- fetchRebloggedByUsers,
- fetchScrobbles,
- fetchStatus,
- fetchStatusHistory,
- fetchStatusSource,
- search2,
-} from 'src/api/public.js'
-import {
- bookmarkStatus,
- deleteStatus,
- favorite,
- muteConversation,
- pinOwnStatus,
- reactWithEmoji,
- retweet,
- unbookmarkStatus,
- unfavorite,
- unmuteConversation,
- unpinOwnStatus,
- unreactWithEmoji,
- unretweet,
-} from 'src/api/user.js'
-
-const emptyTl = (userId = 0) => ({
- statuses: [],
- statusesObject: {},
- faves: [],
- visibleStatuses: [],
- visibleStatusesObject: {},
- newStatusCount: 0,
- maxId: '',
- minId: '',
- minVisibleId: 0,
- loading: false,
- followers: [],
- friends: [],
- userId,
- flushMarker: 0,
-})
-
-export const defaultState = () => ({
- allStatuses: [],
- scrobblesNextFetch: {},
- allStatusesObject: {},
- conversationsObject: {},
- maxId: '',
- favorites: new Set(),
- timelines: {
- mentions: emptyTl(),
- public: emptyTl(),
- user: emptyTl(),
- favorites: emptyTl(),
- media: emptyTl(),
- publicAndExternal: emptyTl(),
- friends: emptyTl(),
- tag: emptyTl(),
- dms: emptyTl(),
- bookmarks: emptyTl(),
- list: emptyTl(),
- bubble: emptyTl(),
- },
-})
-
-export const prepareStatus = (status) => {
- // Set deleted flag
- status.deleted = false
-
- // To make the array reactive
- status.attachments = status.attachments || []
-
- return status
-}
-
-const mergeOrAdd = (arr, obj, item) => {
- const oldItem = obj[item.id]
-
- if (oldItem) {
- // 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'),
- )
- // Reactivity fix.
- oldItem.attachments.splice(oldItem.attachments.length)
- return { item: oldItem, new: false }
- } else {
- // This is a new item, prepare it
- prepareStatus(item)
- arr.push(item)
- obj[item.id] = item
- return { item, new: true }
- }
-}
-
-const sortById = (a, b) => {
- const seqA = Number(a.id)
- const seqB = Number(b.id)
- const isSeqA = !Number.isNaN(seqA)
- const isSeqB = !Number.isNaN(seqB)
- if (isSeqA && isSeqB) {
- return seqA > seqB ? -1 : 1
- } else if (isSeqA && !isSeqB) {
- return 1
- } else if (!isSeqA && isSeqB) {
- return -1
- } else {
- return a.id > b.id ? -1 : 1
- }
-}
-
-const sortTimeline = (timeline) => {
- timeline.visibleStatuses = timeline.visibleStatuses.sort(sortById)
- timeline.statuses = timeline.statuses.sort(sortById)
- timeline.minVisibleId = last(timeline.visibleStatuses)?.id
- return timeline
-}
-
-const getLatestScrobble = (state, user) => {
- const scrobblesSupport =
- useInstanceCapabilitiesStore().pleromaScrobblesAvailable
-
- if (!scrobblesSupport || !user.name || user.id === 'undefined') {
- return
- }
-
- 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
- fetchScrobbles({ accountId: user.id })
- .then(({ data: scrobbles }) => {
- if (scrobbles?.error) {
- useInstanceCapabilitiesStore().set('pleromaScrobblesAvailable', false)
- return
- }
-
- if (scrobbles.length > 0) {
- user.latestScrobble = scrobbles[0]
-
- 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
-const addStatusToGlobalStorage = (state, data) => {
- getLatestScrobble(state, data.user)
- const result = mergeOrAdd(state.allStatuses, state.allStatusesObject, data)
- if (result.new) {
- // Add to conversation
- const status = result.item
- const conversationsObject = state.conversationsObject
- const conversationId = status.statusnet_conversation_id
- if (conversationsObject[conversationId]) {
- conversationsObject[conversationId].push(status)
- } else {
- conversationsObject[conversationId] = [status]
- }
- }
- return result
-}
-
-const addNewStatuses = (
- state,
- {
- statuses,
- showImmediately = false,
- timeline,
- user = {},
- noIdUpdate = false,
- userId,
- pagination = {},
- },
-) => {
- // Sanity check
- if (!Array.isArray(statuses)) {
- return false
- }
-
- const allStatuses = state.allStatuses
- const timelineObject = state.timelines[timeline]
-
- // Mismatch between API pagination and our internal minId/maxId tracking systems:
- // 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 newer =
- timeline &&
- (maxNew > timelineObject.maxId || timelineObject.maxId === '') &&
- statuses.length > 0
- const older =
- timeline &&
- (minNew < timelineObject.minId || timelineObject.minId === '') &&
- statuses.length > 0
-
- if (!noIdUpdate && newer) {
- timelineObject.maxId = maxNew
- }
- if (!noIdUpdate && older) {
- timelineObject.minId = minNew
- }
-
- // 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
- ) {
- return
- }
-
- const addStatus = (data, showImmediately, addToTimeline = true) => {
- const result = addStatusToGlobalStorage(state, data)
- const status = result.item
-
- if (result.new) {
- // We are mentioned in a post
- if (
- status.type === 'status' &&
- find(status.attentions, { id: user.id })
- ) {
- const mentions = state.timelines.mentions
-
- // Add the mention to the mentions timeline
- if (timelineObject !== mentions) {
- mergeOrAdd(mentions.statuses, mentions.statusesObject, status)
- mentions.newStatusCount += 1
-
- sortTimeline(mentions)
- }
- }
- if (status.visibility === 'direct') {
- const dms = state.timelines.dms
-
- mergeOrAdd(dms.statuses, dms.statusesObject, status)
- dms.newStatusCount += 1
-
- sortTimeline(dms)
- }
- }
-
- // Decide if we should treat the status as new for this timeline.
- let resultForCurrentTimeline
- // Some statuses should only be added to the global status repository.
- if (timeline && addToTimeline) {
- 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,
- )
- } else if (timeline && addToTimeline && resultForCurrentTimeline.new) {
- // Just change newStatuscount
- timelineObject.newStatusCount += 1
- }
-
- if (status.quote) {
- addStatus(
- status.quote,
- /* showImmediately = */ false,
- /* addToTimeline = */ false,
- )
- }
-
- return status
- }
-
- const favoriteStatus = (favorite) => {
- const status = find(allStatuses, { id: favorite.in_reply_to_status_id })
- if (status) {
- // This is our favorite, so the relevant bit.
- if (favorite.user.id === user.id) {
- status.favorited = true
- } else {
- status.fave_num += 1
- }
- }
- return status
- }
-
- const processors = {
- status: (status) => {
- addStatus(status, showImmediately)
- },
- edit: (status) => {
- addStatus(status, showImmediately)
- },
- retweet: (status) => {
- // RetweetedStatuses are never shown immediately
- const retweetedStatus = addStatus(status.retweeted_status, false, false)
-
- let retweet
- // If the retweeted status is already there, don't add the retweet
- // to the timeline.
- if (
- 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 {
- retweet = addStatus(status, showImmediately)
- }
-
- retweet.retweeted_status = retweetedStatus
- },
- favorite: (favorite) => {
- // Only update if this is a new favorite.
- // Ignore our own favorites because we get info about likes as response to like request
- if (!state.favorites.has(favorite.id)) {
- state.favorites.add(favorite.id)
- favoriteStatus(favorite)
- }
- },
- follow: () => {
- // NOOP, it is known status but we don't do anything about it for now
- },
- default: (unknown) => {
- console.warn('unknown status type', unknown)
- },
- }
-
- each(statuses, (status) => {
- const type = status.type
- const processor = processors[type] || processors.default
- processor(status)
- })
-
- // Keep the visible statuses sorted
- if (timeline && !(timeline === 'bookmarks')) {
- sortTimeline(timelineObject)
- }
-}
-
-const removeStatus = (state, { timeline, userId }) => {
- const timelineObject = state.timelines[timeline]
- 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
- }
-}
-
-export const mutations = {
- addNewStatuses,
- removeStatus,
- showNewStatuses(state, { timeline }) {
- const oldTimeline = state.timelines[timeline]
-
- oldTimeline.newStatusCount = 0
- oldTimeline.visibleStatuses = oldTimeline.statuses.slice(0, 50)
- oldTimeline.minVisibleId = last(oldTimeline.visibleStatuses).id
- oldTimeline.minId = oldTimeline.minVisibleId
- oldTimeline.visibleStatusesObject = {}
- each(oldTimeline.visibleStatuses, (status) => {
- oldTimeline.visibleStatusesObject[status.id] = status
- })
- },
- resetStatuses(state) {
- const emptyState = defaultState()
- Object.entries(emptyState).forEach(([key, value]) => {
- state[key] = value
- })
- },
- clearTimeline(state, { timeline, excludeUserId = false }) {
- const userId = excludeUserId ? state.timelines[timeline].userId : undefined
- state.timelines[timeline] = emptyTl(userId)
- },
- setFavorited(state, { status, value }) {
- const newStatus = state.allStatusesObject[status.id]
-
- if (newStatus.favorited !== value) {
- if (value) {
- newStatus.fave_num++
- } else {
- newStatus.fave_num--
- }
- }
-
- newStatus.favorited = value
- },
- setFavoritedConfirm(state, { status, user }) {
- const newStatus = state.allStatusesObject[status.id]
- newStatus.favorited = status.favorited
- newStatus.fave_num = status.fave_num
- const index = findIndex(newStatus.favoritedBy, { id: user.id })
- if (index !== -1 && !newStatus.favorited) {
- newStatus.favoritedBy.splice(index, 1)
- } else if (index === -1 && newStatus.favorited) {
- newStatus.favoritedBy.push(user)
- }
- },
- 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
- },
- )
- }
- },
- setRetweeted(state, { status, value }) {
- const newStatus = state.allStatusesObject[status.id]
-
- if (newStatus.repeated !== value) {
- if (value) {
- newStatus.repeat_num++
- } else {
- newStatus.repeat_num--
- }
- }
-
- newStatus.repeated = value
- },
- setRetweetedConfirm(state, { status, user }) {
- const newStatus = state.allStatusesObject[status.id]
- newStatus.repeated = status.repeated
- newStatus.repeat_num = status.repeat_num
- const index = findIndex(newStatus.rebloggedBy, { id: user.id })
- if (index !== -1 && !newStatus.repeated) {
- newStatus.rebloggedBy.splice(index, 1)
- } else if (index === -1 && newStatus.repeated) {
- newStatus.rebloggedBy.push(user)
- }
- },
- setBookmarked(state, { status, value }) {
- const newStatus = state.allStatusesObject[status.id]
- newStatus.bookmarked = value
- newStatus.bookmark_folder_id = status.bookmark_folder_id
- },
- setBookmarkedConfirm(state, { status }) {
- const newStatus = state.allStatusesObject[status.id]
- newStatus.bookmarked = status.bookmarked
- if (status.pleroma)
- newStatus.bookmark_folder_id = status.pleroma.bookmark_folder
- },
- setDeleted(state, { status }) {
- const newStatus = state.allStatusesObject[status.id]
- if (newStatus) newStatus.deleted = true
- },
- setManyDeleted(state, condition) {
- Object.values(state.allStatusesObject).forEach((status) => {
- if (condition(status)) {
- status.deleted = true
- }
- })
- },
- setLoading(state, { timeline, value }) {
- state.timelines[timeline].loading = value
- },
- setNsfw(state, { id, nsfw }) {
- const newStatus = state.allStatusesObject[id]
- newStatus.nsfw = nsfw
- },
- queueFlush(state, { timeline, id }) {
- state.timelines[timeline].flushMarker = id
- },
- queueFlushAll(state) {
- Object.keys(state.timelines).forEach((timeline) => {
- state.timelines[timeline].flushMarker = state.timelines[timeline].maxId
- })
- },
- addRepeats(state, { id, rebloggedByUsers, currentUser }) {
- const newStatus = state.allStatusesObject[id]
- newStatus.rebloggedBy = rebloggedByUsers.filter(Boolean)
- // 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,
- )
- },
- addFavs(state, { id, favoritedByUsers, currentUser }) {
- const newStatus = state.allStatusesObject[id]
- newStatus.favoritedBy = favoritedByUsers.filter(Boolean)
- // 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,
- )
- },
- addEmojiReactionsBy(state, { id, emojiReactions }) {
- const status = state.allStatusesObject[id]
- status.emoji_reactions = emojiReactions
- },
- 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 newReaction = {
- ...reaction,
- count: reaction.count + 1,
- me: true,
- accounts: [...reaction.accounts, currentUser],
- }
-
- // Update count of existing reaction if it exists, otherwise append at the end
- if (reactionIndex >= 0) {
- status.emoji_reactions[reactionIndex] = newReaction
- } else {
- status.emoji_reactions = [...status.emoji_reactions, newReaction]
- }
- },
- removeOwnReaction(state, { id, emoji, currentUser }) {
- const status = state.allStatusesObject[id]
- const reactionIndex = findIndex(status.emoji_reactions, { name: emoji })
- if (reactionIndex < 0) return
-
- const reaction = status.emoji_reactions[reactionIndex]
- const accounts = reaction.accounts || []
-
- const newReaction = {
- ...reaction,
- count: reaction.count - 1,
- me: false,
- 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,
- )
- }
- },
- updateStatusWithPoll(state, { id, poll }) {
- const status = state.allStatusesObject[id]
- status.poll = poll
- },
- 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,
- },
- ) {
- return commit('addNewStatuses', {
- statuses,
- showImmediately,
- timeline,
- noIdUpdate,
- user: useUsersStore().currentUser,
- userId,
- pagination,
- })
- },
- fetchStatus({ rootState, dispatch }, id) {
- return fetchStatus({ id }).then(({ data: status }) =>
- dispatch('addNewStatuses', { statuses: [status] }),
- )
- },
- fetchStatusSource({ rootState }, status) {
- return fetchStatusSource({
- id: status.id,
- credentials: useOAuthStore().token,
- }).then(({ data }) => data)
- },
- fetchStatusHistory(_, status) {
- return fetchStatusHistory({ status }).then(({ data }) => data)
- },
- deleteStatus({ rootState, commit }, status) {
- deleteStatus({
- id: status.id,
- credentials: useOAuthStore().token,
- })
- .then(() => {
- commit('setDeleted', { status })
- })
- .catch((e) => {
- useInterfaceStore().pushGlobalNotice({
- level: 'error',
- messageKey: 'status.delete_error',
- messageArgs: [e.message],
- timeout: 5000,
- })
- })
- },
- deleteStatusById({ rootState, commit }, id) {
- const status = rootState.statuses.allStatusesObject[id]
- commit('setDeleted', { status })
- },
- markStatusesAsDeleted({ commit }, condition) {
- commit('setManyDeleted', condition)
- },
- favorite({ rootState, commit }, status) {
- // Optimistic favoriting...
- commit('setFavorited', { status, value: true })
- favorite({
- id: status.id,
- credentials: useOAuthStore().token,
- }).then(({ data: status }) =>
- commit('setFavoritedConfirm', {
- status,
- user: useUsersStore().currentUser,
- }),
- )
- },
- unfavorite({ rootState, commit }, status) {
- // Optimistic unfavoriting...
- commit('setFavorited', { status, value: false })
- unfavorite({
- id: status.id,
- credentials: useOAuthStore().token,
- }).then(({ data: status }) =>
- commit('setFavoritedConfirm', {
- status,
- user: useUsersStore().currentUser,
- }),
- )
- },
- fetchPinnedStatuses({ rootState, dispatch }, userId) {
- fetchPinnedStatuses({
- id: userId,
- credentials: useOAuthStore().token,
- }).then(({ data: statuses }) =>
- dispatch('addNewStatuses', {
- statuses,
- timeline: 'user',
- userId,
- showImmediately: true,
- noIdUpdate: true,
- }),
- )
- },
- pinStatus({ rootState, dispatch }, statusId) {
- return pinOwnStatus({
- id: statusId,
- credentials: useOAuthStore().token,
- }).then(({ data: status }) =>
- dispatch('addNewStatuses', { statuses: [status] }),
- )
- },
- unpinStatus({ rootState, dispatch }, statusId) {
- return unpinOwnStatus({
- id: statusId,
- credentials: useOAuthStore().token,
- }).then(({ data: status }) =>
- dispatch('addNewStatuses', { statuses: [status] }),
- )
- },
- muteConversation({ rootState, commit }, { id: statusId }) {
- return muteConversation({
- id: statusId,
- credentials: useOAuthStore().token,
- }).then(({ data: status }) => commit('setMutedStatus', status))
- },
- unmuteConversation({ rootState, commit }, { id: statusId }) {
- return unmuteConversation({
- id: statusId,
- credentials: useOAuthStore().token,
- }).then(({ data: status }) => commit('setMutedStatus', status))
- },
- retweet({ rootState, commit }, status) {
- // Optimistic retweeting...
- commit('setRetweeted', { status, value: true })
- retweet({
- id: status.id,
- credentials: useOAuthStore().token,
- }).then(({ data: status }) =>
- commit('setRetweetedConfirm', {
- status: status.retweeted_status,
- user: useUsersStore().currentUser,
- }),
- )
- },
- unretweet({ rootState, commit }, status) {
- // Optimistic unretweeting...
- commit('setRetweeted', { status, value: false })
- unretweet({
- id: status.id,
- credentials: useOAuthStore().token,
- }).then(({ data: status }) =>
- commit('setRetweetedConfirm', {
- status,
- user: useUsersStore().currentUser,
- }),
- )
- },
- bookmark({ rootState, commit }, status) {
- commit('setBookmarked', { status, value: true })
- bookmarkStatus({
- id: status.id,
- folder_id: status.bookmark_folder_id,
- credentials: useOAuthStore().token,
- }).then(({ data: status }) => {
- commit('setBookmarkedConfirm', { status })
- })
- },
- unbookmark({ rootState, commit }, status) {
- commit('setBookmarked', { status, value: false })
- unbookmarkStatus({
- id: status.id,
- credentials: useOAuthStore().token,
- }).then(({ data: status }) => {
- commit('setBookmarkedConfirm', { status })
- })
- },
- queueFlush({ commit }, { timeline, id }) {
- commit('queueFlush', { timeline, id })
- },
- queueFlushAll({ commit }) {
- commit('queueFlushAll')
- },
- fetchFavsAndRepeats({ rootState, commit }, id) {
- Promise.all([
- fetchFavoritedByUsers({
- id,
- credentials: useOAuthStore().token,
- }).then(({ data }) => data),
- fetchRebloggedByUsers({
- id,
- credentials: useOAuthStore().token,
- }).then(({ data }) => data),
- ]).then(([favoritedByUsers, rebloggedByUsers]) => {
- commit('addFavs', {
- id,
- favoritedByUsers,
- currentUser: useUsersStore().currentUser,
- })
- commit('addRepeats', {
- id,
- rebloggedByUsers,
- currentUser: useUsersStore().currentUser,
- })
- })
- },
- reactWithEmoji({ rootState, dispatch, commit }, { id, emoji }) {
- const currentUser = useUsersStore().currentUser
- if (!currentUser) return
-
- commit('addOwnReaction', { id, emoji, currentUser })
- reactWithEmoji({
- id,
- emoji,
- credentials: useOAuthStore().token,
- }).then(() => {
- dispatch('fetchEmojiReactionsBy', id)
- })
- },
- unreactWithEmoji({ rootState, dispatch, commit }, { id, emoji }) {
- const currentUser = useUsersStore().currentUser
- if (!currentUser) return
-
- commit('removeOwnReaction', { id, emoji, currentUser })
- unreactWithEmoji({
- id,
- emoji,
- currentUser: useUsersStore().currentUser,
- }).then(() => {
- dispatch('fetchEmojiReactionsBy', id)
- })
- },
- fetchEmojiReactionsBy({ rootState, commit }, id) {
- return fetchEmojiReactions({
- id,
- credentials: useOAuthStore().token,
- }).then(({ data: emojiReactions }) => {
- commit('addEmojiReactionsBy', {
- id,
- emojiReactions,
- currentUser: useUsersStore().currentUser,
- })
- })
- },
- fetchFavs({ rootState, commit }, id) {
- fetchFavoritedByUsers({
- id,
- credentials: useOAuthStore().token,
- }).then(({ data: favoritedByUsers }) =>
- commit('addFavs', {
- id,
- favoritedByUsers,
- currentUser: useUsersStore().currentUser,
- }),
- )
- },
- fetchRepeats({ rootState, commit }, id) {
- fetchRebloggedByUsers({
- id,
- credentials: useOAuthStore().token,
- }).then(({ data: rebloggedByUsers }) =>
- commit('addRepeats', {
- id,
- rebloggedByUsers,
- currentUser: useUsersStore().currentUser,
- }),
- )
- },
- search(store, { q, resolve, limit, offset, following, type }) {
- return search2({
- q,
- resolve,
- limit,
- offset,
- following,
- type,
- credentials: useOAuthStore().token,
- }).then((result) => {
- const { data, ...rest } = result
- useUsersStore().addNewUsers({
- ...rest,
- data: data.accounts,
- })
- useUsersStore().addNewUsers({
- ...rest,
- data: data.statuses.map((s) => s.user).filter(Boolean),
- })
- store.commit('addNewStatuses', {
- statuses: data.statuses,
- })
-
- data.statuses = data.statuses.map(
- (s) => store.state.allStatusesObject[s.id],
- )
- return data
- })
- },
- setVirtualHeight({ commit }, { statusId, height }) {
- commit('setVirtualHeight', { statusId, height })
- },
- },
- mutations,
-}
-
-export default statuses
diff --git a/src/services/status_poster/status_poster.service.js b/src/services/status_poster/status_poster.service.js
index af000a40e..a25f60107 100644
--- a/src/services/status_poster/status_poster.service.js
+++ b/src/services/status_poster/status_poster.service.js
@@ -1,5 +1,6 @@
import { map } from 'lodash'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useUsersStore } from 'src/stores/users.js'
import {
@@ -38,9 +39,10 @@ const postStatus = ({
poll,
preview,
idempotencyKey,
- }).then(({ data }) => {
+ }).then(({ data, timestamp }) => {
if (!preview)
- store.dispatch('addNewStatuses', {
+ useStatusesStore().addNewStatuses({
+ timestamp,
statuses: [data],
timeline: 'friends',
showImmediately: true,
diff --git a/src/services/timeline_fetcher/timeline_fetcher.service.js b/src/services/timeline_fetcher/timeline_fetcher.service.js
index 647ed90ef..b7097f4e0 100644
--- a/src/services/timeline_fetcher/timeline_fetcher.service.js
+++ b/src/services/timeline_fetcher/timeline_fetcher.service.js
@@ -5,12 +5,12 @@ import { promiseInterval } from '../promise_interval/promise_interval.js'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useUsersStore } from 'src/stores/users.js'
import { fetchTimeline } from 'src/api/timelines.js'
const update = ({
- store,
statuses,
timeline,
showImmediately,
@@ -20,8 +20,8 @@ const update = ({
}) => {
const ccTimeline = camelCase(timeline)
- store.dispatch('addNewStatuses', {
- timeline: ccTimeline,
+ useStatusesStore().addNewStatuses({
+ timelineName: ccTimeline,
userId,
listId,
statuses,
@@ -31,7 +31,6 @@ const update = ({
}
const fetchAndUpdate = ({
- store,
credentials,
timeline = 'friends',
older = false,
@@ -45,8 +44,7 @@ const fetchAndUpdate = ({
sinceId,
}) => {
const args = { timeline, credentials }
- const rootState = store.rootState || store.state
- const timelineData = rootState.statuses.timelines[camelCase(timeline)]
+ const timelineData = useStatusesStore().timelines[camelCase(timeline)]
const { hideMutedPosts, replyVisibility } =
useMergedConfigStore().mergedConfig
const loggedIn = !!useUsersStore().currentUser
@@ -86,10 +84,9 @@ const fetchAndUpdate = ({
!timelineData.loading &&
numStatusesBeforeFetch > 0
) {
- store.dispatch('queueFlush', { timeline, id: timelineData.maxId })
+ useStatusesStore().queueFlush({ timeline, id: timelineData.maxId })
}
update({
- store,
statuses,
timeline,
showImmediately,
@@ -116,23 +113,21 @@ const fetchAndUpdate = ({
const startFetching = ({
timeline = 'friends',
credentials,
- store,
userId,
listId,
statusId,
bookmarkFolderId,
tag,
}) => {
- const rootState = store.rootState || store.state
- const timelineData = rootState.statuses.timelines[camelCase(timeline)]
- const showImmediately = timelineData.visibleStatuses.length === 0
+ const timelineData = useStatusesStore().timelines[camelCase(timeline)]
+ const showImmediately = timelineData.visibleStatuses.size === 0
+ console.log(timeline)
timelineData.userId = userId
timelineData.listId = listId
timelineData.bookmarkFolderId = bookmarkFolderId
fetchAndUpdate({
timeline,
credentials,
- store,
showImmediately,
userId,
listId,
@@ -144,7 +139,6 @@ const startFetching = ({
fetchAndUpdate({
timeline,
credentials,
- store,
userId,
listId,
statusId,
diff --git a/src/stores/admin_settings.js b/src/stores/admin_settings.js
index 766da26fb..c00b7a29b 100644
--- a/src/stores/admin_settings.js
+++ b/src/stores/admin_settings.js
@@ -2,6 +2,7 @@ import { cloneDeep, differenceWith, get, isEqual, set } from 'lodash'
import { defineStore } from 'pinia'
import { useOAuthStore } from 'src/stores/oauth.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import {
addNewEmojiFile,
@@ -362,6 +363,7 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
async fetchStatuses(opts) {
const {
data: { total, activities },
+ timestamp,
} = await listStatuses({
credentials: useOAuthStore().token,
opts,
@@ -369,7 +371,7 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
const statuses = activities.map(parseStatus)
- await window.vuex.dispatch('addNewStatuses', { statuses })
+ useStatusesStore().addNewStatuses({ statuses, timestamp })
return {
items: statuses,
@@ -377,13 +379,13 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
}
},
async changeStatusScope(opts) {
- const { data } = await changeStatusScope({
+ const { data, timestamp } = await changeStatusScope({
credentials: useOAuthStore().token,
opts,
})
const status = parseStatus(data)
- await window.vuex.dispatch('addNewStatuses', { statuses: [status] })
+ useStatusesStore().addNewStatuses({ statuses: [status], timestamp })
},
// Users stuff
diff --git a/src/stores/notifications.js b/src/stores/notifications.js
index 507e40759..1099b0e83 100644
--- a/src/stores/notifications.js
+++ b/src/stores/notifications.js
@@ -14,6 +14,7 @@ import { useI18nStore } from 'src/stores/i18n.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useOAuthStore } from 'src/stores/oauth.js'
import { useReportsStore } from 'src/stores/reports.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { useUsersStore } from 'src/stores/users.js'
@@ -80,7 +81,7 @@ export const useNotificationsStore = defineStore('notifications', {
)
// Synchronous commit to add all the statuses
- window.vuex.commit('addNewStatuses', {
+ useStatusesStore().addNewStatuses({
timestamp,
statuses: statusNotifications.map(
(notification) => notification.status,
@@ -90,7 +91,7 @@ export const useNotificationsStore = defineStore('notifications', {
// Update references to statuses in notifications to ones in the store
statusNotifications.forEach((notification) => {
const id = notification.status.id
- const referenceStatus = window.vuex.state.statuses.allStatusesObject[id]
+ const referenceStatus = useStatusesStore().allStatuses.get(id)
if (referenceStatus) {
notification.status = referenceStatus
@@ -103,7 +104,7 @@ export const useNotificationsStore = defineStore('notifications', {
}
if (notification.type === 'pleroma:emoji_reaction') {
- window.vuex.dispatch('fetchEmojiReactionsBy', notification.status.id)
+ useStatusesStore().fetchEmojiReactionsBy(notification.status.id)
}
// Only add a new notification if we don't have one for the same action
diff --git a/src/stores/reports.js b/src/stores/reports.js
index 7d319d8e3..1c4d89bca 100644
--- a/src/stores/reports.js
+++ b/src/stores/reports.js
@@ -3,6 +3,7 @@ import { defineStore } from 'pinia'
import { useInterfaceStore } from 'src/stores/interface.js'
import { useOAuthStore } from 'src/stores/oauth.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { setReportState } from 'src/api/admin.js'
@@ -18,8 +19,8 @@ export const useReportsStore = defineStore('reports', {
}),
actions: {
openUserReportingModal({ userId, statusIds = [] }) {
- const preTickedStatuses = statusIds.map(
- (id) => window.vuex.state.statuses.allStatusesObject[id],
+ const preTickedStatuses = statusIds.map((id) =>
+ useStatusesStore().allStatuses.get(id),
)
const preTickedIds = statusIds
const statuses = preTickedStatuses.concat(
diff --git a/src/stores/statuses.js b/src/stores/statuses.js
index 1fda114cd..55060e251 100644
--- a/src/stores/statuses.js
+++ b/src/stores/statuses.js
@@ -1,4 +1,4 @@
-import { each, first, last, maxBy, merge, minBy, omitBy, remove } from 'lodash'
+import { first, last, maxBy, minBy } from 'lodash'
import { defineStore } from 'pinia'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
@@ -33,7 +33,7 @@ import {
unretweet,
} from 'src/api/user.js'
-const emptyTl = () => ({
+const emptyTl = (userId) => ({
statuses: new Map(),
faves: [],
visibleStatuses: new Map(),
@@ -71,49 +71,6 @@ export const defaultState = () => ({
},
})
-const mergeOrAdd = (map, status, timestamp) => {
- const existing = map.get(status.id)
- const oldTimestamp = this.timestamps.get(existing)
-
- const { user: unused0, ...old } = existing ?? {}
- const { user: statusUser, ...neu } = status
-
- const [user] = useUsersStore().addNewUsers({ data: statusUser, timestamp })
-
- existing.user = user
-
- // implicit: if oldTimestamp is undefined this will still be false
- if (oldTimestamp > timestamp) return [existing, false] // not overwriting old data with new
-
- const newStatus = {
- ...old,
- ...neu,
- user,
- }
-
- map.set(item.id, item)
-
- this.timestamps.set(newStatus, timestamp)
-
- return [map.get(item.id), true]
-}
-
-const sortById = (a, b) => {
- const seqA = Number(a.id)
- const seqB = Number(b.id)
- const isSeqA = !Number.isNaN(seqA)
- const isSeqB = !Number.isNaN(seqB)
- if (isSeqA && isSeqB) {
- return seqA > seqB ? -1 : 1
- } else if (isSeqA && !isSeqB) {
- return 1
- } else if (!isSeqA && isSeqB) {
- return -1
- } else {
- return a.id > b.id ? -1 : 1
- }
-}
-
const getLatestScrobble = (user) => {
const scrobblesSupport =
useInstanceCapabilitiesStore().pleromaScrobblesAvailable
@@ -149,7 +106,6 @@ const getLatestScrobble = (user) => {
})
}
-
const USER_TIMELINES = new Set(['user', 'userPinned', 'media'])
export const useStatusesStore = defineStore('statuses', {
@@ -160,8 +116,8 @@ export const useStatusesStore = defineStore('statuses', {
showImmediately = false,
timelineName,
user = {},
+ userId,
noIdUpdate = false,
- Id,
pagination = {},
timestamp,
}) {
@@ -179,17 +135,14 @@ export const useStatusesStore = defineStore('statuses', {
// 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 (
- USER_TIMELINES.has(timelineName) &&
- timeline.userId !== userId
- ) {
+ if (USER_TIMELINES.has(timelineName) && timeline.userId !== userId) {
return
}
const addStatus = (data, showImmediately, addToTimeline = true) => {
getLatestScrobble(data.user)
- const [status] = mergeOrAdd(this.allStatuses, data)
+ const [status] = this.mergeOrAdd(this.allStatuses, data)
// Add to conversation
const conversations = this.conversations
@@ -210,7 +163,7 @@ export const useStatusesStore = defineStore('statuses', {
// Add the mention to the mentions timeline
if (timeline !== mentions) {
- const [, isNew] = mergeOrAdd(mentions.statuses, status)
+ const [, isNew] = this.mergeOrAdd(mentions.statuses, data)
if (isNew) mentions.newStatusCount += 1
}
}
@@ -218,21 +171,23 @@ export const useStatusesStore = defineStore('statuses', {
if (status.visibility === 'direct') {
const dms = this.timelines.dms
- const [, isNew] = mergeOrAdd(dms.statuses, status)
+ const [, isNew] = this.mergeOrAdd(dms.statuses, data)
if (isNew) dms.newStatusCount += 1
}
// Some statuses should only be added to the global status repository.
if (timeline && addToTimeline) {
// Decide if we should treat the status as new for this timeline.
- const [status, isNew] = mergeOrAdd(timeline.statuses, status)
- if (showImmediately) {
- // Add it directly to the visibleStatuses, don't change
- // newStatusCount
- timeline.visibleStatuses.add(status.id, status)
- } else {
- // Just change newStatuscount
- timeline.newStatusCount += 1
+ const [status, isNew] = this.mergeOrAdd(timeline.statuses, data)
+ if (isNew) {
+ if (showImmediately) {
+ // Add it directly to the visibleStatuses, don't change
+ // newStatusCount
+ timeline.visibleStatuses.set(status.id, status)
+ } else {
+ // Just change newStatuscount
+ timeline.newStatusCount += 1
+ }
}
}
@@ -256,12 +211,17 @@ export const useStatusesStore = defineStore('statuses', {
},
retweet: (status) => {
// RetweetedStatuses are never shown immediately
- const retweetedStatus = addStatus(status.retweeted_status, false, false)
+ const retweetedStatus = addStatus(
+ status.retweeted_status,
+ false,
+ false,
+ )
let retweet
// If the retweeted status is already there, don't add the retweet
// to the timeline.
- if (timeline?.statuses.values().some((s) => {
+ if (
+ [...(timeline?.statuses.values() ?? [])].some((s) => {
if (s.retweeted_status) {
return (
s.id === retweetedStatus.id ||
@@ -313,6 +273,35 @@ export const useStatusesStore = defineStore('statuses', {
processor(status)
})
},
+ mergeOrAdd(map, status, timestamp) {
+ const existing = map.get(status.id) ?? {}
+ const oldTimestamp = this.timestamps.get(existing)
+
+ const { user: unused0, ...old } = existing
+ const { user: statusUser, ...neu } = status
+
+ const [user] = useUsersStore().addNewUsers({
+ data: statusUser,
+ timestamp,
+ })
+
+ existing.user = user // reactive update in case we return old
+
+ // implicit: if oldTimestamp is undefined this will still be false
+ if (oldTimestamp > timestamp) return [existing, false] // not overwriting old data with new
+
+ const newStatus = {
+ ...old,
+ ...neu,
+ user,
+ }
+
+ map.set(newStatus.id, newStatus)
+
+ this.timestamps.set(newStatus, timestamp)
+
+ return [map.get(newStatus.id), true]
+ },
fetchStatus(id) {
return fetchStatus({ id }).then(({ data: status, timestamp }) =>
this.addNewStatuses({ statuses: [status], timestamp }),
@@ -376,10 +365,7 @@ export const useStatusesStore = defineStore('statuses', {
)
},
fetchFavsAndRepeats(id) {
- return Promise.all([
- this.fetchFavs(id),
- this.fetchRepeats(id),
- ])
+ return Promise.all([this.fetchFavs(id), this.fetchRepeats(id)])
},
// Updates
@@ -414,8 +400,8 @@ export const useStatusesStore = defineStore('statuses', {
const minNew = pagination.maxId ?? minBy(statuses, 'id').id ?? ''
const maxNew = pagination.minId ?? maxBy(statuses, 'id').id ?? ''
- const newer = (maxNew > timeline.maxId || timeline.maxId === '')
- const older = (minNew < timeline.minId || timeline.minId === '')
+ const newer = maxNew > timeline.maxId || timeline.maxId === ''
+ const older = minNew < timeline.minId || timeline.minId === ''
if (newer) {
timeline.maxId = maxNew
@@ -429,8 +415,10 @@ export const useStatusesStore = defineStore('statuses', {
timeline.newStatusCount = 0
- timeline.visibleStatuses = new Map([...timeline.statuses.entries()].slice(0, 50))
- timeline.minVisibleId = last(timeline.visibleStatuses).id
+ timeline.visibleStatuses = new Map(
+ [...timeline.statuses.entries()].slice(0, 50),
+ )
+ timeline.minVisibleId = last(timeline.visibleStatuses.keys())
timeline.minId = ''
timeline.maxId = ''
this.updateTimelineExtremes(timeline, [...timeline.statuses.values()])
@@ -442,9 +430,9 @@ export const useStatusesStore = defineStore('statuses', {
this[key] = value
})
},
- clearTimeline(state, { timeline, excludeUserId = false }) {
- const userId = excludeUserId ? state.timelines[timeline].userId : undefined
- state.timelines[timeline] = emptyTl(userId)
+ clearTimeline({ timeline, excludeUserId = false }) {
+ const userId = excludeUserId ? this.timelines[timeline].userId : undefined
+ this.timelines[timeline] = emptyTl(userId)
},
queueFlush({ timeline, id }) {
this.timelines[timeline].flushMarker = id
@@ -650,8 +638,8 @@ export const useStatusesStore = defineStore('statuses', {
},
setBookmarked({ id, value, bookmark_folder_id }) {
const status = this.allStatuses.get(id)
- newStatus.bookmarked = value
- newStatus.bookmark_folder_id = value ? bookmark_folder_id : null
+ status.bookmarked = value
+ status.bookmark_folder_id = value ? bookmark_folder_id : null
},
/// Mute
@@ -659,25 +647,29 @@ export const useStatusesStore = defineStore('statuses', {
return muteConversation({
id,
credentials: useOAuthStore().token,
- }).then(({ data: status, timestamp }) => {
- this.addNewStatuses({
- statuses: [status],
- timestamp,
+ })
+ .then(({ data: status, timestamp }) => {
+ this.addNewStatuses({
+ statuses: [status],
+ timestamp,
+ })
+ return status
})
- return status
- }).then((status) => this.setMutedStatus(status))
+ .then((status) => this.setMutedStatus(status))
},
unmuteConversation(id) {
return unmuteConversation({
id,
credentials: useOAuthStore().token,
- }).then(({ data: status, timestamp }) => {
- this.addNewStatuses({
- statuses: [status],
- timestamp,
+ })
+ .then(({ data: status, timestamp }) => {
+ this.addNewStatuses({
+ statuses: [status],
+ timestamp,
+ })
+ return status
})
- return status
- }).then((status) => this.setMutedStatus(status))
+ .then((status) => this.setMutedStatus(status))
},
setMutedStatus({ id, thread_muted }) {
// Setting thread_muted flag on all other known statuses
@@ -686,11 +678,11 @@ export const useStatusesStore = defineStore('statuses', {
newStatus.thread_muted = thread_muted
if (newStatus.thread_muted !== undefined) {
- state.conversations.get(newStatus.statusnet_conversation_id).forEach(
- (status) => {
+ this.conversations
+ .get(newStatus.statusnet_conversation_id)
+ .forEach((status) => {
status.thread_muted = thread_muted
- },
- )
+ })
}
},
@@ -774,9 +766,7 @@ export const useStatusesStore = defineStore('statuses', {
statuses: data.statuses,
})
- data.statuses = data.statuses.map(
- (s) => this.allStatuses.get(s.id),
- )
+ data.statuses = data.statuses.map((s) => this.allStatuses.get(s.id))
return data
})
},
@@ -785,8 +775,7 @@ export const useStatusesStore = defineStore('statuses', {
removeUserStatuses({ timelineName, userId }) {
const timeline = this.timelines[timelineName]
- timeline
- .statuses
+ timeline.statuses
.values()
.filter(({ user }) => user.id === userId)
.forEach(({ id }) => {
@@ -795,8 +784,8 @@ export const useStatusesStore = defineStore('statuses', {
})
timeline.minVisibleId =
timeline.visibleStatuses.length > 0
- ? last(timeline.visibleStatuses).id
- : 0
+ ? last(timeline.visibleStatuses).id
+ : 0
timeline.maxId =
timeline.statuses.length > 0 ? first(timeline.statuses).id : 0
},
@@ -807,8 +796,8 @@ export const useStatusesStore = defineStore('statuses', {
const status = this.allStatuses.get(id)
status.poll = poll
},
- setLoading(state, { timeline, value }) {
- state.timelines[timeline].loading = value
+ setLoading({ timeline, value }) {
+ this.timelines[timeline].loading = value
},
},
})
diff --git a/src/stores/users.js b/src/stores/users.js
index 7554d937e..4aba00743 100644
--- a/src/stores/users.js
+++ b/src/stores/users.js
@@ -20,7 +20,9 @@ import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.j
import { useInterfaceStore } from 'src/stores/interface.js'
import { useListsStore } from 'src/stores/lists.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
+import { useNotificationsStore } from 'src/stores/notifications.js'
import { useOAuthStore } from 'src/stores/oauth.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useSyncConfigStore } from 'src/stores/sync_config.js'
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
@@ -144,12 +146,12 @@ export const useUsersStore = defineStore('users', {
const { data, timestamp } = response
const users = Array.isArray(data) ? data : [data]
- users.forEach((user) => {
+ return users.map((user) => {
const existing = this.users.get(user.id) ?? {}
const oldTimestamp = this.timestamps.get(existing)
// implicit: if oldTimestamp is undefined this will still be false
- if (oldTimestamp > timestamp) return // not overwriting old data with new
+ if (oldTimestamp > timestamp) return existing // not overwriting old data with new
const { relationship: unused0, ...old } = existing
const { relationship: unused1, ...neu } = user
@@ -163,6 +165,8 @@ export const useUsersStore = defineStore('users', {
if (user.id === this.currentUser.id) {
this.currentUser = newUser
}
+
+ return this.users.get(user.id)
})
},
updateUserRelationship(relationships) {
@@ -594,7 +598,7 @@ export const useUsersStore = defineStore('users', {
useBookmarkFoldersStore().stopFetching()
store.dispatch('stopFetchingFollowRequests')
store.commit('clearNotifications')
- store.commit('resetStatuses')
+ useStatusesStore().resetStatuses()
useChatsStore().resetChats()
oauth.clearToken()
Cookies.remove('__Host-pleroma_key', { path: '/' })
diff --git a/test/unit/specs/components/post_status_form.spec.js b/test/unit/specs/components/post_status_form.spec.js
index 50b7471f2..0c0be4143 100644
--- a/test/unit/specs/components/post_status_form.spec.js
+++ b/test/unit/specs/components/post_status_form.spec.js
@@ -6,6 +6,7 @@ import { mountOpts } from '../../../fixtures/setup_test'
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
+import { useStatusesStore } from 'src/stores/statuses.js'
import { useUsersStore } from 'src/stores/users.js'
const currentUser = {
@@ -37,7 +38,7 @@ const replyMountOpts = (props) =>
props,
afterStore(store) {
useUsersStore().currentUser = currentUser
- store.state.statuses.allStatusesObject = {
+ useStatusesStore().allStatuses = {
[repliedStatus.id]: repliedStatus,
}
},