i think it's usable now
This commit is contained in:
parent
5b9ab6b1ea
commit
37f501108b
42 changed files with 296 additions and 1295 deletions
|
|
@ -1,15 +1,11 @@
|
||||||
import AuthForm from 'src/components/auth_form/auth_form.js'
|
import AuthForm from 'src/components/auth_form/auth_form.js'
|
||||||
import BookmarkTimeline from 'src/components/bookmark_timeline/bookmark_timeline.vue'
|
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 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 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 QuotesTimeline from 'src/components/quotes_timeline/quotes_timeline.vue'
|
||||||
import RemoteUserResolver from 'src/components/remote_user_resolver/remote_user_resolver.vue'
|
import RemoteUserResolver from 'src/components/remote_user_resolver/remote_user_resolver.vue'
|
||||||
import TagTimeline from 'src/components/tag_timeline/tag_timeline.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 { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
|
|
@ -42,22 +38,38 @@ export default (store) => {
|
||||||
{
|
{
|
||||||
name: 'public-external-timeline',
|
name: 'public-external-timeline',
|
||||||
path: '/main/all',
|
path: '/main/all',
|
||||||
component: PublicAndExternalTimeline,
|
component: Timeline,
|
||||||
|
props: () => ({
|
||||||
|
timelineName: 'publicAndExternal',
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'public-timeline',
|
name: 'public-timeline',
|
||||||
path: '/main/public',
|
path: '/main/public',
|
||||||
component: PublicTimeline,
|
component: Timeline,
|
||||||
|
props: () => ({
|
||||||
|
timelineName: 'public',
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'friends',
|
name: 'friends',
|
||||||
path: '/main/friends',
|
path: '/main/friends',
|
||||||
component: FriendsTimeline,
|
component: Timeline,
|
||||||
beforeEnter: validateAuthenticatedRoute,
|
beforeEnter: validateAuthenticatedRoute,
|
||||||
|
props: () => ({
|
||||||
|
timelineName: 'friends',
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{ name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline },
|
{ name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline },
|
||||||
{ name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline },
|
{ name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline },
|
||||||
{ name: 'bubble', path: '/bubble', component: BubbleTimeline },
|
{
|
||||||
|
name: 'bubble',
|
||||||
|
path: '/bubble',
|
||||||
|
component: Timeline,
|
||||||
|
props: () => ({
|
||||||
|
timelineName: 'bubble',
|
||||||
|
}),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'conversation',
|
name: 'conversation',
|
||||||
path: '/notice/:id',
|
path: '/notice/:id',
|
||||||
|
|
@ -105,8 +117,11 @@ export default (store) => {
|
||||||
{
|
{
|
||||||
name: 'dms',
|
name: 'dms',
|
||||||
path: '/users/:username/dms',
|
path: '/users/:username/dms',
|
||||||
component: DMs,
|
component: Timeline,
|
||||||
beforeEnter: validateAuthenticatedRoute,
|
beforeEnter: validateAuthenticatedRoute,
|
||||||
|
props: () => ({
|
||||||
|
timelineName: 'dms',
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'registration',
|
name: 'registration',
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import Timeline from 'src/components/timeline/timeline.vue'
|
import Timeline from 'src/components/timeline/timeline.vue'
|
||||||
|
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
|
||||||
const Bookmarks = {
|
const Bookmarks = {
|
||||||
created() {
|
created() {
|
||||||
this.$store.commit('clearTimeline', { timeline: 'bookmarks' })
|
useStatusesStore().clearTimeline({ timeline: 'bookmarks' })
|
||||||
this.$store.dispatch('startFetchingTimeline', {
|
this.$store.dispatch('startFetchingTimeline', {
|
||||||
timeline: 'bookmarks',
|
timeline: 'bookmarks',
|
||||||
bookmarkFolderId: this.folderId || null,
|
bookmarkFolderId: this.folderId || null,
|
||||||
|
|
@ -21,7 +23,7 @@ const Bookmarks = {
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
folderId() {
|
folderId() {
|
||||||
this.$store.commit('clearTimeline', { timeline: 'bookmarks' })
|
useStatusesStore().clearTimeline({ timeline: 'bookmarks' })
|
||||||
this.$store.dispatch('stopFetchingTimeline', 'bookmarks')
|
this.$store.dispatch('stopFetchingTimeline', 'bookmarks')
|
||||||
this.$store.dispatch('startFetchingTimeline', {
|
this.$store.dispatch('startFetchingTimeline', {
|
||||||
timeline: 'bookmarks',
|
timeline: 'bookmarks',
|
||||||
|
|
@ -30,7 +32,7 @@ const Bookmarks = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
unmounted() {
|
unmounted() {
|
||||||
this.$store.commit('clearTimeline', { timeline: 'bookmarks' })
|
useStatusesStore().clearTimeline({ timeline: 'bookmarks' })
|
||||||
this.$store.dispatch('stopFetchingTimeline', 'bookmarks')
|
this.$store.dispatch('stopFetchingTimeline', 'bookmarks')
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<template>
|
|
||||||
<Timeline
|
|
||||||
:title="$t('nav.bubble')"
|
|
||||||
:timeline="timeline"
|
|
||||||
:timeline-name="'bubble'"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="./bubble_timeline.js"></script>
|
|
||||||
|
|
@ -19,6 +19,7 @@ import UserPopover from 'src/components/user_popover/user_popover.vue'
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
import { useUsersStore } from 'src/stores/users.js'
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
|
|
@ -100,9 +101,9 @@ const ChatMessage = {
|
||||||
return !this.message.in_reply_to_status_id
|
return !this.message.in_reply_to_status_id
|
||||||
},
|
},
|
||||||
customReplyTo() {
|
customReplyTo() {
|
||||||
return this.$store.state.statuses.allStatusesObject[
|
return useStatusesStore().allStatuses.get(
|
||||||
this.message.in_reply_to_status_id
|
this.message.in_reply_to_status_id,
|
||||||
]
|
)
|
||||||
},
|
},
|
||||||
replyToName() {
|
replyToName() {
|
||||||
if (this.message.in_reply_to_screen_name) {
|
if (this.message.in_reply_to_screen_name) {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import { useChatsStore } from 'src/stores/chats.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
import { useUsersStore } from 'src/stores/users.js'
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|
@ -122,7 +123,7 @@ const Chat = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
conversationId() {
|
conversationId() {
|
||||||
const status = this.$store.state.statuses.allStatusesObject[this.statusId]
|
const status = useStatusesStore().allStatuses.get(this.statusId)
|
||||||
return get(
|
return get(
|
||||||
status,
|
status,
|
||||||
'retweeted_status.statusnet_conversation_id',
|
'retweeted_status.statusnet_conversation_id',
|
||||||
|
|
|
||||||
|
|
@ -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 as mapPiniaState } from 'pinia'
|
||||||
import { mapState } from 'vuex'
|
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 RichContent from 'src/components/rich_content/rich_content.jsx'
|
||||||
import ThreadTree from 'src/components/thread_tree/thread_tree.vue'
|
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 { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
|
||||||
import { fetchConversation, fetchStatus } from 'src/api/public.js'
|
import { fetchConversation, fetchStatus } from 'src/api/public.js'
|
||||||
import { WSConnectionStatus } from 'src/api/websocket.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 = {
|
const conversation = {
|
||||||
props: {
|
props: {
|
||||||
statusId: {
|
statusId: {
|
||||||
|
|
@ -166,7 +153,7 @@ const conversation = {
|
||||||
return this.virtualHidden && this.suspendable
|
return this.virtualHidden && this.suspendable
|
||||||
},
|
},
|
||||||
status() {
|
status() {
|
||||||
return this.$store.state.statuses.allStatusesObject[this.statusId]
|
return useStatusesStore().allStatuses.get(this.statusId)
|
||||||
},
|
},
|
||||||
originalStatusId() {
|
originalStatusId() {
|
||||||
if (this.status.retweeted_status) {
|
if (this.status.retweeted_status) {
|
||||||
|
|
@ -187,15 +174,11 @@ const conversation = {
|
||||||
return [this.status]
|
return [this.status]
|
||||||
}
|
}
|
||||||
|
|
||||||
const conversation = clone(
|
const conversation = useStatusesStore().conversations.get(
|
||||||
this.$store.state.statuses.conversationsObject[this.conversationId],
|
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() {
|
statusMap() {
|
||||||
return this.conversation.reduce((res, s) => {
|
return this.conversation.reduce((res, s) => {
|
||||||
|
|
@ -441,7 +424,7 @@ const conversation = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
virtualHidden() {
|
virtualHidden() {
|
||||||
this.$store.dispatch('setVirtualHeight', {
|
useStatusesStore().setVirtualHeight({
|
||||||
statusId: this.statusId,
|
statusId: this.statusId,
|
||||||
height: `${this.$el.clientHeight}px`,
|
height: `${this.$el.clientHeight}px`,
|
||||||
})
|
})
|
||||||
|
|
@ -453,9 +436,12 @@ const conversation = {
|
||||||
fetchConversation({
|
fetchConversation({
|
||||||
id: this.statusId,
|
id: this.statusId,
|
||||||
credentials: useOAuthStore().token,
|
credentials: useOAuthStore().token,
|
||||||
}).then(({ data: { ancestors, descendants } }) => {
|
}).then(({ data: { ancestors, descendants }, timestamp }) => {
|
||||||
this.$store.dispatch('addNewStatuses', { statuses: ancestors })
|
useStatusesStore().addNewStatuses({ statuses: ancestors, timestamp })
|
||||||
this.$store.dispatch('addNewStatuses', { statuses: descendants })
|
useStatusesStore().addNewStatuses({
|
||||||
|
statuses: descendants,
|
||||||
|
timestamp,
|
||||||
|
})
|
||||||
this.setFocused(this.originalStatusId)
|
this.setFocused(this.originalStatusId)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -482,17 +468,17 @@ const conversation = {
|
||||||
this.focused = id
|
this.focused = id
|
||||||
|
|
||||||
if (!this.streamingEnabled) {
|
if (!this.streamingEnabled) {
|
||||||
this.$store.dispatch('fetchStatus', id)
|
useStatusesStore().fetchStatus(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$store.dispatch('fetchFavsAndRepeats', id)
|
useStatusesStore().fetchFavsAndRepeats(id)
|
||||||
this.$store.dispatch('fetchEmojiReactionsBy', id)
|
useStatusesStore().fetchEmojiReactionsBy(id)
|
||||||
},
|
},
|
||||||
toggleExpanded() {
|
toggleExpanded() {
|
||||||
this.expanded = !this.expanded
|
this.expanded = !this.expanded
|
||||||
},
|
},
|
||||||
getConversationId(statusId) {
|
getConversationId(statusId) {
|
||||||
const status = this.$store.state.statuses.allStatusesObject[statusId]
|
const status = useStatusesStore().allStatuses.get(statusId)
|
||||||
return get(
|
return get(
|
||||||
status,
|
status,
|
||||||
'retweeted_status.statusnet_conversation_id',
|
'retweeted_status.statusnet_conversation_id',
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<template>
|
|
||||||
<Timeline
|
|
||||||
:title="$t('nav.dms')"
|
|
||||||
:timeline="timeline"
|
|
||||||
:timeline-name="'dms'"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="./dm_timeline.js"></script>
|
|
||||||
|
|
@ -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 StatusContent from 'src/components/status_content/status_content.vue'
|
||||||
|
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faPollH } from '@fortawesome/free-solid-svg-icons'
|
import { faPollH } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
@ -65,7 +66,7 @@ const Draft = {
|
||||||
},
|
},
|
||||||
refStatus() {
|
refStatus() {
|
||||||
return this.draft.refId
|
return this.draft.refId
|
||||||
? this.$store.state.statuses.allStatusesObject[this.draft.refId]
|
? useStatusesStore().allStatuses.get(this.draft.refId)
|
||||||
: undefined
|
: undefined
|
||||||
},
|
},
|
||||||
localCollapseSubjectDefault() {
|
localCollapseSubjectDefault() {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import UserListPopover from 'src/components/user_list_popover/user_list_popover.
|
||||||
|
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
import { useUsersStore } from 'src/stores/users.js'
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
|
|
@ -62,10 +63,7 @@ const EmojiReactions = {
|
||||||
async fetchEmojiReactionsByIfMissing() {
|
async fetchEmojiReactionsByIfMissing() {
|
||||||
const hasNoAccounts = this.status.emoji_reactions.find((r) => !r.accounts)
|
const hasNoAccounts = this.status.emoji_reactions.find((r) => !r.accounts)
|
||||||
if (hasNoAccounts) {
|
if (hasNoAccounts) {
|
||||||
return await this.$store.dispatch(
|
return await useStatusesStore().fetchEmojiReactionsBy(this.status.id)
|
||||||
'fetchEmojiReactionsBy',
|
|
||||||
this.status.id,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
reactWith(emoji) {
|
reactWith(emoji) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<template>
|
|
||||||
<Timeline
|
|
||||||
:title="$t('nav.timeline')"
|
|
||||||
:timeline="timeline"
|
|
||||||
:timeline-name="'friends'"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="./friends_timeline.js"></script>
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import Timeline from 'src/components/timeline/timeline.vue'
|
import Timeline from 'src/components/timeline/timeline.vue'
|
||||||
|
|
||||||
import { useListsStore } from 'src/stores/lists.js'
|
import { useListsStore } from 'src/stores/lists.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
|
||||||
const ListsTimeline = {
|
const ListsTimeline = {
|
||||||
data() {
|
data() {
|
||||||
|
|
@ -21,7 +22,7 @@ const ListsTimeline = {
|
||||||
if (route.name === 'lists-timeline' && route.params.id !== this.listId) {
|
if (route.name === 'lists-timeline' && route.params.id !== this.listId) {
|
||||||
this.listId = route.params.id
|
this.listId = route.params.id
|
||||||
this.$store.dispatch('stopFetchingTimeline', 'list')
|
this.$store.dispatch('stopFetchingTimeline', 'list')
|
||||||
this.$store.commit('clearTimeline', { timeline: 'list' })
|
useStatusesStore().clearTimeline({ timeline: 'list' })
|
||||||
useListsStore().fetchList({ listId: this.listId })
|
useListsStore().fetchList({ listId: this.listId })
|
||||||
this.$store.dispatch('startFetchingTimeline', {
|
this.$store.dispatch('startFetchingTimeline', {
|
||||||
timeline: 'list',
|
timeline: 'list',
|
||||||
|
|
@ -40,7 +41,7 @@ const ListsTimeline = {
|
||||||
},
|
},
|
||||||
unmounted() {
|
unmounted() {
|
||||||
this.$store.dispatch('stopFetchingTimeline', 'list')
|
this.$store.dispatch('stopFetchingTimeline', 'list')
|
||||||
this.$store.commit('clearTimeline', { timeline: 'list' })
|
useStatusesStore().clearTimeline({ timeline: 'list' })
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<template>
|
|
||||||
<Timeline
|
|
||||||
:title="$t('nav.twkn')"
|
|
||||||
:timeline="timeline"
|
|
||||||
:timeline-name="'publicAndExternal'"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="./public_and_external_timeline.js"></script>
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<template>
|
|
||||||
<Timeline
|
|
||||||
:title="$t('nav.public_tl')"
|
|
||||||
:timeline="timeline"
|
|
||||||
:timeline-name="'public'"
|
|
||||||
/>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script src="./public_timeline.js"></script>
|
|
||||||
|
|
@ -5,6 +5,7 @@ import Popover from 'src/components/popover/popover.vue'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useLocalConfigStore } from 'src/stores/local_config.js'
|
import { useLocalConfigStore } from 'src/stores/local_config.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_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 { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||||
import { useUsersStore } from 'src/stores/users.js'
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
|
|
@ -27,7 +28,7 @@ const QuickFilterSettings = {
|
||||||
path: 'replyVisibility',
|
path: 'replyVisibility',
|
||||||
value: visibility,
|
value: visibility,
|
||||||
})
|
})
|
||||||
this.$store.dispatch('queueFlushAll')
|
useStatusesStore().queueFlushAll()
|
||||||
},
|
},
|
||||||
openTab(tab) {
|
openTab(tab) {
|
||||||
useInterfaceStore().openSettingsModalTab(tab)
|
useInterfaceStore().openSettingsModalTab(tab)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
|
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
|
|
@ -45,7 +47,7 @@ export default {
|
||||||
computed: {
|
computed: {
|
||||||
quotedStatus() {
|
quotedStatus() {
|
||||||
return this.statusId
|
return this.statusId
|
||||||
? this.$store.state.statuses.allStatusesObject[this.statusId]
|
? useStatusesStore().allStatuses.get(this.statusId)
|
||||||
: undefined
|
: undefined
|
||||||
},
|
},
|
||||||
shouldDisplayQuote() {
|
shouldDisplayQuote() {
|
||||||
|
|
@ -79,8 +81,8 @@ export default {
|
||||||
this.fetchAttempted = true
|
this.fetchAttempted = true
|
||||||
this.fetching = true
|
this.fetching = true
|
||||||
this.$emit('loading', true)
|
this.$emit('loading', true)
|
||||||
this.$store
|
useStatusesStore()
|
||||||
.dispatch('fetchStatus', this.statusId)
|
.fetchStatus(this.statusId)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.displayQuote = true
|
this.displayQuote = true
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import Timeline from 'src/components/timeline/timeline.vue'
|
import Timeline from 'src/components/timeline/timeline.vue'
|
||||||
|
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
|
||||||
const QuotesTimeline = {
|
const QuotesTimeline = {
|
||||||
created() {
|
created() {
|
||||||
this.$store.commit('clearTimeline', { timeline: 'quotes' })
|
useStatusesStore().clearTimeline({ timeline: 'tag' })
|
||||||
this.$store.dispatch('startFetchingTimeline', {
|
this.$store.dispatch('startFetchingTimeline', {
|
||||||
timeline: 'quotes',
|
timeline: 'quotes',
|
||||||
statusId: this.statusId,
|
statusId: this.statusId,
|
||||||
|
|
@ -21,7 +23,7 @@ const QuotesTimeline = {
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
statusId() {
|
statusId() {
|
||||||
this.$store.commit('clearTimeline', { timeline: 'quotes' })
|
useStatusesStore().clearTimeline({ timeline: 'tag' })
|
||||||
this.$store.dispatch('startFetchingTimeline', {
|
this.$store.dispatch('startFetchingTimeline', {
|
||||||
timeline: 'quotes',
|
timeline: 'quotes',
|
||||||
statusId: this.statusId,
|
statusId: this.statusId,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import Conversation from 'src/components/conversation/conversation.vue'
|
||||||
import FollowCard from 'src/components/follow_card/follow_card.vue'
|
import FollowCard from 'src/components/follow_card/follow_card.vue'
|
||||||
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
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 { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
|
|
@ -39,11 +40,11 @@ const Search = {
|
||||||
return this.userIds.map((userId) => useUsersStore().findUser(userId))
|
return this.userIds.map((userId) => useUsersStore().findUser(userId))
|
||||||
},
|
},
|
||||||
visibleStatuses() {
|
visibleStatuses() {
|
||||||
const allStatusesObject = this.$store.state.statuses.allStatusesObject
|
const allStatuses = useStatusesStore().allStatuses
|
||||||
|
|
||||||
return this.statuses.filter(
|
return this.statuses.filter(
|
||||||
(status) =>
|
(status) =>
|
||||||
allStatusesObject[status.id] && !allStatusesObject[status.id].deleted,
|
allStatuses.has(status.id) && !allStatuses.get(status.id).deleted,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import UnitSetting from '../helpers/unit_setting.vue'
|
||||||
|
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
|
||||||
const ClutterTab = {
|
const ClutterTab = {
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -35,7 +36,7 @@ const ClutterTab = {
|
||||||
// Updating nested properties
|
// Updating nested properties
|
||||||
watch: {
|
watch: {
|
||||||
replyVisibility() {
|
replyVisibility() {
|
||||||
this.$store.dispatch('queueFlushAll')
|
useStatusesStore().queueFlushAll()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import UnitSetting from '../helpers/unit_setting.vue'
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_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 { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|
@ -265,7 +266,7 @@ const FilteringTab = {
|
||||||
// Updating nested properties
|
// Updating nested properties
|
||||||
watch: {
|
watch: {
|
||||||
replyVisibility() {
|
replyVisibility() {
|
||||||
this.$store.dispatch('queueFlushAll')
|
useStatusesStore().queueFlushAll()
|
||||||
},
|
},
|
||||||
muteFiltersObject() {
|
muteFiltersObject() {
|
||||||
this.muteFiltersDraftObject = cloneDeep(
|
this.muteFiltersDraftObject = cloneDeep(
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import {
|
||||||
import { useInstanceStore } from 'src/stores/instance.js'
|
import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_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 { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||||
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
|
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
|
||||||
import { useUsersStore } from 'src/stores/users.js'
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
@ -206,7 +207,7 @@ const Status = {
|
||||||
},
|
},
|
||||||
statusFromGlobalRepository() {
|
statusFromGlobalRepository() {
|
||||||
// NOTE: Consider to replace status with 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() {
|
loggedIn() {
|
||||||
return !!this.currentUser
|
return !!this.currentUser
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { useInstanceStore } from 'src/stores/instance.js'
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
import { useReportsStore } from 'src/stores/reports.js'
|
import { useReportsStore } from 'src/stores/reports.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
import { useStatusHistoryStore } from 'src/stores/statusHistory.js'
|
import { useStatusHistoryStore } from 'src/stores/statusHistory.js'
|
||||||
|
|
||||||
const PRIVATE_SCOPES = new Set(['private', 'direct'])
|
const PRIVATE_SCOPES = new Set(['private', 'direct'])
|
||||||
|
|
@ -52,7 +53,7 @@ export const BUTTONS = [
|
||||||
(currentUser.id === status.user.id ||
|
(currentUser.id === status.user.id ||
|
||||||
!PRIVATE_SCOPES.has(status.visibility)),
|
!PRIVATE_SCOPES.has(status.visibility)),
|
||||||
toggleable: true,
|
toggleable: true,
|
||||||
confirm: ({ status, getters }) =>
|
confirm: ({ status }) =>
|
||||||
!status.repeated && useMergedConfigStore().mergedConfig.modalOnRepeat,
|
!status.repeated && useMergedConfigStore().mergedConfig.modalOnRepeat,
|
||||||
confirmStrings: {
|
confirmStrings: {
|
||||||
title: 'status.repeat_confirm_title',
|
title: 'status.repeat_confirm_title',
|
||||||
|
|
@ -60,11 +61,11 @@ export const BUTTONS = [
|
||||||
confirm: 'status.repeat_confirm_accept_button',
|
confirm: 'status.repeat_confirm_accept_button',
|
||||||
cancel: 'status.repeat_confirm_cancel_button',
|
cancel: 'status.repeat_confirm_cancel_button',
|
||||||
},
|
},
|
||||||
action({ status, dispatch }) {
|
action({ status }) {
|
||||||
if (!status.repeated) {
|
if (!status.repeated) {
|
||||||
return dispatch('retweet', { id: status.id })
|
return useStatusesStore().retweet(status.id)
|
||||||
} else {
|
} else {
|
||||||
return dispatch('unretweet', { id: status.id })
|
return useStatusesStore().unretweet(status.id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -82,11 +83,11 @@ export const BUTTONS = [
|
||||||
counter: ({ status }) => status.fave_num,
|
counter: ({ status }) => status.fave_num,
|
||||||
anonLink: true,
|
anonLink: true,
|
||||||
toggleable: true,
|
toggleable: true,
|
||||||
action({ status, dispatch }) {
|
action({ status }) {
|
||||||
if (!status.favorited) {
|
if (!status.favorited) {
|
||||||
return dispatch('favorite', { id: status.id })
|
return useStatusesStore().favorite(status.id)
|
||||||
} else {
|
} else {
|
||||||
return dispatch('unfavorite', { id: status.id })
|
return useStatusesStore().unfavorite(status.id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -112,7 +113,7 @@ export const BUTTONS = [
|
||||||
if: ({ loggedIn }) => loggedIn,
|
if: ({ loggedIn }) => loggedIn,
|
||||||
toggleable: false,
|
toggleable: false,
|
||||||
dropdown: true,
|
dropdown: true,
|
||||||
action({ status, dispatch, emit }) {
|
action({ status, emit }) {
|
||||||
/* prevent hiding */
|
/* prevent hiding */
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -130,11 +131,11 @@ export const BUTTONS = [
|
||||||
PUBLIC_SCOPES.has(status.visibility)
|
PUBLIC_SCOPES.has(status.visibility)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
action({ status, dispatch }) {
|
action({ status }) {
|
||||||
if (status.pinned) {
|
if (status.pinned) {
|
||||||
return dispatch('unpinStatus', status.id)
|
return useStatusesStore().unpinStatus(status.id)
|
||||||
} else {
|
} else {
|
||||||
return dispatch('pinStatus', status.id)
|
return useStatusesStore().pinStatus(status.id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -150,11 +151,11 @@ export const BUTTONS = [
|
||||||
label: ({ status }) =>
|
label: ({ status }) =>
|
||||||
status.bookmarked ? 'status.unbookmark' : 'status.bookmark',
|
status.bookmarked ? 'status.unbookmark' : 'status.bookmark',
|
||||||
if: ({ loggedIn }) => loggedIn,
|
if: ({ loggedIn }) => loggedIn,
|
||||||
action({ status, dispatch }) {
|
action({ status }) {
|
||||||
if (status.bookmarked) {
|
if (status.bookmarked) {
|
||||||
return dispatch('unbookmark', { id: status.id })
|
return useStatusesStore().unbookmark(status.id)
|
||||||
} else {
|
} else {
|
||||||
return dispatch('bookmark', { id: status.id })
|
return useStatusesStore().bookmark(status.id)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -165,7 +166,7 @@ export const BUTTONS = [
|
||||||
name: 'editHistory',
|
name: 'editHistory',
|
||||||
icon: 'history',
|
icon: 'history',
|
||||||
label: 'status.status_history',
|
label: 'status.status_history',
|
||||||
if({ status, state }) {
|
if({ status }) {
|
||||||
return (
|
return (
|
||||||
useInstanceCapabilitiesStore().editingAvailable &&
|
useInstanceCapabilitiesStore().editingAvailable &&
|
||||||
status.edited_at !== null
|
status.edited_at !== null
|
||||||
|
|
@ -196,26 +197,28 @@ export const BUTTONS = [
|
||||||
name: 'edit',
|
name: 'edit',
|
||||||
icon: 'pen',
|
icon: 'pen',
|
||||||
label: 'status.edit',
|
label: 'status.edit',
|
||||||
if({ status, loggedIn, currentUser, state }) {
|
if({ status, loggedIn, currentUser }) {
|
||||||
return (
|
return (
|
||||||
loggedIn &&
|
loggedIn &&
|
||||||
useInstanceCapabilitiesStore().editingAvailable &&
|
useInstanceCapabilitiesStore().editingAvailable &&
|
||||||
status.user.id === currentUser.id
|
status.user.id === currentUser.id
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
action({ dispatch, status }) {
|
action({ status }) {
|
||||||
return dispatch('fetchStatusSource', { id: status.id }).then((data) =>
|
return useStatusesStore()
|
||||||
useEditStatusStore().openEditStatusModal({
|
.fetchStatusSource(status.id)
|
||||||
statusId: status.id,
|
.then((data) =>
|
||||||
statusSubject: data.spoiler_text,
|
useEditStatusStore().openEditStatusModal({
|
||||||
statusText: data.text,
|
statusId: status.id,
|
||||||
statusIsSensitive: status.nsfw,
|
statusSubject: data.spoiler_text,
|
||||||
statusPoll: status.poll,
|
statusText: data.text,
|
||||||
statusFiles: [...status.attachments],
|
statusIsSensitive: status.nsfw,
|
||||||
statusVisibility: status.visibility,
|
statusPoll: status.poll,
|
||||||
statusContentType: data.content_type,
|
statusFiles: [...status.attachments],
|
||||||
}),
|
statusVisibility: status.visibility,
|
||||||
)
|
statusContentType: data.content_type,
|
||||||
|
}),
|
||||||
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -260,15 +263,15 @@ export const BUTTONS = [
|
||||||
currentUser.privileges.has('messages_delete'))
|
currentUser.privileges.has('messages_delete'))
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
confirm: ({ getters }) => useMergedConfigStore().mergedConfig.modalOnDelete,
|
confirm: () => useMergedConfigStore().mergedConfig.modalOnDelete,
|
||||||
confirmStrings: {
|
confirmStrings: {
|
||||||
title: 'status.delete_confirm_title',
|
title: 'status.delete_confirm_title',
|
||||||
body: 'status.delete_confirm',
|
body: 'status.delete_confirm',
|
||||||
confirm: 'status.delete_confirm_accept_button',
|
confirm: 'status.delete_confirm_accept_button',
|
||||||
cancel: 'status.delete_confirm_cancel_button',
|
cancel: 'status.delete_confirm_cancel_button',
|
||||||
},
|
},
|
||||||
action({ dispatch, status }) {
|
action({ status }) {
|
||||||
return dispatch('deleteStatus', { id: status.id })
|
return useStatusesStore().deleteStatus(status.id)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -287,7 +290,7 @@ export const BUTTONS = [
|
||||||
},
|
},
|
||||||
toggleable: false,
|
toggleable: false,
|
||||||
dropdown: true,
|
dropdown: true,
|
||||||
action({ status, dispatch, emit }) {
|
action({ status, emit }) {
|
||||||
/* prevent hiding */
|
/* prevent hiding */
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -298,7 +301,7 @@ export const BUTTONS = [
|
||||||
name: 'share',
|
name: 'share',
|
||||||
icon: 'share-alt',
|
icon: 'share-alt',
|
||||||
label: 'status.copy_link',
|
label: 'status.copy_link',
|
||||||
action({ state, status, router }) {
|
action({ status, router }) {
|
||||||
navigator.clipboard.writeText(
|
navigator.clipboard.writeText(
|
||||||
[
|
[
|
||||||
useInstanceStore().server,
|
useInstanceStore().server,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { get } from 'lodash'
|
||||||
|
|
||||||
import Modal from 'src/components/modal/modal.vue'
|
import Modal from 'src/components/modal/modal.vue'
|
||||||
|
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
import { useStatusHistoryStore } from 'src/stores/statusHistory.js'
|
import { useStatusHistoryStore } from 'src/stores/statusHistory.js'
|
||||||
|
|
||||||
const StatusHistoryModal = {
|
const StatusHistoryModal = {
|
||||||
|
|
@ -50,9 +51,11 @@ const StatusHistoryModal = {
|
||||||
this.statuses = []
|
this.statuses = []
|
||||||
},
|
},
|
||||||
fetchStatusHistory() {
|
fetchStatusHistory() {
|
||||||
this.$store.dispatch('fetchStatusHistory', this.params).then((data) => {
|
useStatusesStore()
|
||||||
this.statuses = data
|
.fetchStatusHistory(this.params)
|
||||||
})
|
.then((data) => {
|
||||||
|
this.statuses = data
|
||||||
|
})
|
||||||
},
|
},
|
||||||
closeModal() {
|
closeModal() {
|
||||||
useStatusHistoryStore().closeStatusHistoryModal()
|
useStatusHistoryStore().closeStatusHistoryModal()
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { find } from 'lodash'
|
|
||||||
|
|
||||||
import Popover from 'src/components/popover/popover.vue'
|
import Popover from 'src/components/popover/popover.vue'
|
||||||
|
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
|
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
|
|
@ -17,7 +17,7 @@ const StatusPopover = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
status() {
|
status() {
|
||||||
return find(this.$store.state.statuses.allStatuses, { id: this.statusId })
|
return useStatusesStore().allStatuses.get(this.statusId)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -30,8 +30,8 @@ const StatusPopover = {
|
||||||
this.error = true
|
this.error = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.$store
|
useStatusesStore()
|
||||||
.dispatch('fetchStatus', this.statusId)
|
.fetchStatus(this.statusId)
|
||||||
.then(() => (this.error = false))
|
.then(() => (this.error = false))
|
||||||
.catch(() => (this.error = true))
|
.catch(() => (this.error = true))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import Timeline from 'src/components/timeline/timeline.vue'
|
import Timeline from 'src/components/timeline/timeline.vue'
|
||||||
|
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
|
||||||
const TagTimeline = {
|
const TagTimeline = {
|
||||||
created() {
|
created() {
|
||||||
this.$store.commit('clearTimeline', { timeline: 'tag' })
|
useStatusesStore().clearTimeline({ timeline: 'tag' })
|
||||||
this.$store.dispatch('startFetchingTimeline', {
|
this.$store.dispatch('startFetchingTimeline', {
|
||||||
timeline: 'tag',
|
timeline: 'tag',
|
||||||
tag: this.tag,
|
tag: this.tag,
|
||||||
|
|
@ -21,7 +23,7 @@ const TagTimeline = {
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
tag() {
|
tag() {
|
||||||
this.$store.commit('clearTimeline', { timeline: 'tag' })
|
useStatusesStore().clearTimeline({ timeline: 'tag' })
|
||||||
this.$store.dispatch('startFetchingTimeline', {
|
this.$store.dispatch('startFetchingTimeline', {
|
||||||
timeline: 'tag',
|
timeline: 'tag',
|
||||||
tag: this.tag,
|
tag: this.tag,
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import TimelineMenu from 'src/components/timeline_menu/timeline_menu.vue'
|
||||||
|
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
import { useUsersStore } from 'src/stores/users.js'
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import timelineFetcher from 'src/services/timeline_fetcher/timeline_fetcher.service.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)
|
library.add(faCircleNotch, faCog, faMinus, faArrowUp, faCirclePlus, faCheck)
|
||||||
|
|
||||||
const Timeline = {
|
const Timeline = {
|
||||||
props: [
|
props: {
|
||||||
'timeline',
|
timelineName: String,
|
||||||
'timelineName',
|
userId: String,
|
||||||
'title',
|
listId: String,
|
||||||
'userId',
|
statusId: String,
|
||||||
'listId',
|
bookmarkFolderId: String,
|
||||||
'statusId',
|
tag: String,
|
||||||
'bookmarkFolderId',
|
embedded: Boolean,
|
||||||
'tag',
|
count: Number,
|
||||||
'embedded',
|
pinnedStatusIds: Set,
|
||||||
'count',
|
inProfile: Boolean,
|
||||||
'pinnedStatusIds',
|
footerSlipgate: Object, // reference to an element where we should put our footer
|
||||||
'inProfile',
|
},
|
||||||
'footerSlipgate', // reference to an element where we should put our footer
|
|
||||||
],
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showScrollTop: false,
|
showScrollTop: false,
|
||||||
|
|
@ -59,8 +58,11 @@ const Timeline = {
|
||||||
QuickViewSettings,
|
QuickViewSettings,
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
timeline() {
|
||||||
|
return useStatusesStore().timelines[this.timelineName]
|
||||||
|
},
|
||||||
filteredVisibleStatuses() {
|
filteredVisibleStatuses() {
|
||||||
return this.timeline.visibleStatuses.filter(
|
return [...this.timeline.visibleStatuses.values()].filter(
|
||||||
(status) =>
|
(status) =>
|
||||||
this.timelineName !== 'user' ||
|
this.timelineName !== 'user' ||
|
||||||
(status.id >= this.timeline.minId &&
|
(status.id >= this.timeline.minId &&
|
||||||
|
|
@ -116,13 +118,13 @@ const Timeline = {
|
||||||
return keyBy(this.pinnedStatusIds)
|
return keyBy(this.pinnedStatusIds)
|
||||||
},
|
},
|
||||||
statusesToDisplay() {
|
statusesToDisplay() {
|
||||||
const amount = this.timeline.visibleStatuses.length
|
const amount = this.timeline.visibleStatuses.size
|
||||||
const statusesPerSide = Math.ceil(Math.max(3, window.innerHeight / 80))
|
const statusesPerSide = Math.ceil(Math.max(3, window.innerHeight / 80))
|
||||||
const nonPinnedIndex =
|
const nonPinnedIndex =
|
||||||
this.virtualScrollIndex - this.filteredPinnedStatusIds.length
|
this.virtualScrollIndex - this.filteredPinnedStatusIds.length
|
||||||
const min = Math.max(0, nonPinnedIndex - statusesPerSide)
|
const min = Math.max(0, nonPinnedIndex - statusesPerSide)
|
||||||
const max = Math.min(amount, 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() {
|
virtualScrollingEnabled() {
|
||||||
return useMergedConfigStore().mergedConfig.virtualScrolling
|
return useMergedConfigStore().mergedConfig.virtualScrolling
|
||||||
|
|
@ -143,7 +145,6 @@ const Timeline = {
|
||||||
}
|
}
|
||||||
|
|
||||||
timelineFetcher.fetchAndUpdate({
|
timelineFetcher.fetchAndUpdate({
|
||||||
store,
|
|
||||||
credentials,
|
credentials,
|
||||||
timeline: this.timelineName,
|
timeline: this.timelineName,
|
||||||
showImmediately,
|
showImmediately,
|
||||||
|
|
@ -175,7 +176,7 @@ const Timeline = {
|
||||||
this.handleVisibilityChange,
|
this.handleVisibilityChange,
|
||||||
false,
|
false,
|
||||||
)
|
)
|
||||||
this.$store.commit('setLoading', {
|
useStatusesStore().setLoading({
|
||||||
timeline: this.timelineName,
|
timeline: this.timelineName,
|
||||||
value: false,
|
value: false,
|
||||||
})
|
})
|
||||||
|
|
@ -197,30 +198,31 @@ const Timeline = {
|
||||||
},
|
},
|
||||||
showNewStatuses() {
|
showNewStatuses() {
|
||||||
if (this.timeline.flushMarker !== 0) {
|
if (this.timeline.flushMarker !== 0) {
|
||||||
this.$store.commit('clearTimeline', {
|
useStatusesStore().clearTimeline({
|
||||||
timeline: this.timelineName,
|
timeline: this.timelineName,
|
||||||
excludeUserId: true,
|
excludeUserId: true,
|
||||||
})
|
})
|
||||||
this.$store.commit('queueFlush', { timeline: this.timelineName, id: 0 })
|
useStatusesStore().queueFlush({ timeline: this.timelineName, id: 0 })
|
||||||
if (this.timelineName === 'user') {
|
if (this.timelineName === 'user') {
|
||||||
this.$store.dispatch('fetchPinnedStatuses', this.userId)
|
this.$store.dispatch('fetchPinnedStatuses', this.userId)
|
||||||
}
|
}
|
||||||
this.fetchOlderStatuses()
|
this.fetchOlderStatuses()
|
||||||
} else {
|
} else {
|
||||||
this.blockClicksTemporarily()
|
this.blockClicksTemporarily()
|
||||||
this.$store.commit('showNewStatuses', { timeline: this.timelineName })
|
useStatusesStore().showNewStatuses(this.timelineName)
|
||||||
this.paused = false
|
this.paused = false
|
||||||
}
|
}
|
||||||
window.scrollTo({ top: 0 })
|
window.scrollTo({ top: 0 })
|
||||||
},
|
},
|
||||||
fetchOlderStatuses: throttle(
|
fetchOlderStatuses: throttle(
|
||||||
function () {
|
function () {
|
||||||
const store = this.$store
|
|
||||||
const credentials = useUsersStore().currentUser.credentials
|
const credentials = useUsersStore().currentUser.credentials
|
||||||
store.commit('setLoading', { timeline: this.timelineName, value: true })
|
useStatusesStore().setLoading({
|
||||||
|
timeline: this.timelineName,
|
||||||
|
value: true,
|
||||||
|
})
|
||||||
timelineFetcher
|
timelineFetcher
|
||||||
.fetchAndUpdate({
|
.fetchAndUpdate({
|
||||||
store,
|
|
||||||
credentials,
|
credentials,
|
||||||
timeline: this.timelineName,
|
timeline: this.timelineName,
|
||||||
older: true,
|
older: true,
|
||||||
|
|
@ -237,7 +239,7 @@ const Timeline = {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.finally(() =>
|
.finally(() =>
|
||||||
store.commit('setLoading', {
|
useStatusesStore().setLoading({
|
||||||
timeline: this.timelineName,
|
timeline: this.timelineName,
|
||||||
value: false,
|
value: false,
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@
|
||||||
:status-id="status.id"
|
:status-id="status.id"
|
||||||
:in-profile="inProfile"
|
:in-profile="inProfile"
|
||||||
:profile-user-id="userId"
|
:profile-user-id="userId"
|
||||||
:virtual-hidden="virtualScrollingEnabled && !statusesToDisplay.includes(status.id)"
|
:virtual-hidden="virtualScrollingEnabled && !statusesToDisplay.has(status.id)"
|
||||||
collapsable
|
collapsable
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import UserCard from 'src/components/user_card/user_card.vue'
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
import { useUsersStore } from 'src/stores/users.js'
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
|
|
@ -106,7 +107,9 @@ const UserProfile = {
|
||||||
const startFetchingTimeline = (timeline, userId) => {
|
const startFetchingTimeline = (timeline, userId) => {
|
||||||
// Clear timeline only if load another user's profile
|
// Clear timeline only if load another user's profile
|
||||||
if (userId !== this.$store.state.statuses.timelines[timeline].userId) {
|
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 })
|
this.$store.dispatch('startFetchingTimeline', { timeline, userId })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useNotificationsStore } from 'src/stores/notifications.js'
|
import { useNotificationsStore } from 'src/stores/notifications.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
import { useShoutStore } from 'src/stores/shout.js'
|
import { useShoutStore } from 'src/stores/shout.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
|
||||||
import { fetchTimeline } from 'src/api/timelines.js'
|
import { fetchTimeline } from 'src/api/timelines.js'
|
||||||
import {
|
import {
|
||||||
|
|
@ -123,14 +124,16 @@ const api = {
|
||||||
data: message.notification,
|
data: message.notification,
|
||||||
})
|
})
|
||||||
} else if (message.event === 'update') {
|
} else if (message.event === 'update') {
|
||||||
dispatch('addNewStatuses', {
|
useStatusesStore().addNewStatuses({
|
||||||
|
timestamp: Date.now(),
|
||||||
statuses: [message.status],
|
statuses: [message.status],
|
||||||
userId: false,
|
userId: false,
|
||||||
showImmediately: timelineData.visibleStatuses.length === 0,
|
showImmediately: timelineData.visibleStatuses.length === 0,
|
||||||
timeline: 'friends',
|
timeline: 'friends',
|
||||||
})
|
})
|
||||||
} else if (message.event === 'status.update') {
|
} else if (message.event === 'status.update') {
|
||||||
dispatch('addNewStatuses', {
|
useStatusesStore().addNewStatuses({
|
||||||
|
timestamp: Date.now(),
|
||||||
statuses: [message.status],
|
statuses: [message.status],
|
||||||
userId: false,
|
userId: false,
|
||||||
showImmediately:
|
showImmediately:
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
import api from './api.js'
|
import api from './api.js'
|
||||||
import drafts from './drafts.js'
|
import drafts from './drafts.js'
|
||||||
import profileConfig from './profileConfig.js'
|
import profileConfig from './profileConfig.js'
|
||||||
import statuses from './statuses.js'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
statuses,
|
|
||||||
api,
|
api,
|
||||||
profileConfig,
|
profileConfig,
|
||||||
drafts,
|
drafts,
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import { map } from 'lodash'
|
import { map } from 'lodash'
|
||||||
|
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
import { useUsersStore } from 'src/stores/users.js'
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|
@ -38,9 +39,10 @@ const postStatus = ({
|
||||||
poll,
|
poll,
|
||||||
preview,
|
preview,
|
||||||
idempotencyKey,
|
idempotencyKey,
|
||||||
}).then(({ data }) => {
|
}).then(({ data, timestamp }) => {
|
||||||
if (!preview)
|
if (!preview)
|
||||||
store.dispatch('addNewStatuses', {
|
useStatusesStore().addNewStatuses({
|
||||||
|
timestamp,
|
||||||
statuses: [data],
|
statuses: [data],
|
||||||
timeline: 'friends',
|
timeline: 'friends',
|
||||||
showImmediately: true,
|
showImmediately: true,
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,12 @@ import { promiseInterval } from '../promise_interval/promise_interval.js'
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
import { useUsersStore } from 'src/stores/users.js'
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
import { fetchTimeline } from 'src/api/timelines.js'
|
import { fetchTimeline } from 'src/api/timelines.js'
|
||||||
|
|
||||||
const update = ({
|
const update = ({
|
||||||
store,
|
|
||||||
statuses,
|
statuses,
|
||||||
timeline,
|
timeline,
|
||||||
showImmediately,
|
showImmediately,
|
||||||
|
|
@ -20,8 +20,8 @@ const update = ({
|
||||||
}) => {
|
}) => {
|
||||||
const ccTimeline = camelCase(timeline)
|
const ccTimeline = camelCase(timeline)
|
||||||
|
|
||||||
store.dispatch('addNewStatuses', {
|
useStatusesStore().addNewStatuses({
|
||||||
timeline: ccTimeline,
|
timelineName: ccTimeline,
|
||||||
userId,
|
userId,
|
||||||
listId,
|
listId,
|
||||||
statuses,
|
statuses,
|
||||||
|
|
@ -31,7 +31,6 @@ const update = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchAndUpdate = ({
|
const fetchAndUpdate = ({
|
||||||
store,
|
|
||||||
credentials,
|
credentials,
|
||||||
timeline = 'friends',
|
timeline = 'friends',
|
||||||
older = false,
|
older = false,
|
||||||
|
|
@ -45,8 +44,7 @@ const fetchAndUpdate = ({
|
||||||
sinceId,
|
sinceId,
|
||||||
}) => {
|
}) => {
|
||||||
const args = { timeline, credentials }
|
const args = { timeline, credentials }
|
||||||
const rootState = store.rootState || store.state
|
const timelineData = useStatusesStore().timelines[camelCase(timeline)]
|
||||||
const timelineData = rootState.statuses.timelines[camelCase(timeline)]
|
|
||||||
const { hideMutedPosts, replyVisibility } =
|
const { hideMutedPosts, replyVisibility } =
|
||||||
useMergedConfigStore().mergedConfig
|
useMergedConfigStore().mergedConfig
|
||||||
const loggedIn = !!useUsersStore().currentUser
|
const loggedIn = !!useUsersStore().currentUser
|
||||||
|
|
@ -86,10 +84,9 @@ const fetchAndUpdate = ({
|
||||||
!timelineData.loading &&
|
!timelineData.loading &&
|
||||||
numStatusesBeforeFetch > 0
|
numStatusesBeforeFetch > 0
|
||||||
) {
|
) {
|
||||||
store.dispatch('queueFlush', { timeline, id: timelineData.maxId })
|
useStatusesStore().queueFlush({ timeline, id: timelineData.maxId })
|
||||||
}
|
}
|
||||||
update({
|
update({
|
||||||
store,
|
|
||||||
statuses,
|
statuses,
|
||||||
timeline,
|
timeline,
|
||||||
showImmediately,
|
showImmediately,
|
||||||
|
|
@ -116,23 +113,21 @@ const fetchAndUpdate = ({
|
||||||
const startFetching = ({
|
const startFetching = ({
|
||||||
timeline = 'friends',
|
timeline = 'friends',
|
||||||
credentials,
|
credentials,
|
||||||
store,
|
|
||||||
userId,
|
userId,
|
||||||
listId,
|
listId,
|
||||||
statusId,
|
statusId,
|
||||||
bookmarkFolderId,
|
bookmarkFolderId,
|
||||||
tag,
|
tag,
|
||||||
}) => {
|
}) => {
|
||||||
const rootState = store.rootState || store.state
|
const timelineData = useStatusesStore().timelines[camelCase(timeline)]
|
||||||
const timelineData = rootState.statuses.timelines[camelCase(timeline)]
|
const showImmediately = timelineData.visibleStatuses.size === 0
|
||||||
const showImmediately = timelineData.visibleStatuses.length === 0
|
console.log(timeline)
|
||||||
timelineData.userId = userId
|
timelineData.userId = userId
|
||||||
timelineData.listId = listId
|
timelineData.listId = listId
|
||||||
timelineData.bookmarkFolderId = bookmarkFolderId
|
timelineData.bookmarkFolderId = bookmarkFolderId
|
||||||
fetchAndUpdate({
|
fetchAndUpdate({
|
||||||
timeline,
|
timeline,
|
||||||
credentials,
|
credentials,
|
||||||
store,
|
|
||||||
showImmediately,
|
showImmediately,
|
||||||
userId,
|
userId,
|
||||||
listId,
|
listId,
|
||||||
|
|
@ -144,7 +139,6 @@ const startFetching = ({
|
||||||
fetchAndUpdate({
|
fetchAndUpdate({
|
||||||
timeline,
|
timeline,
|
||||||
credentials,
|
credentials,
|
||||||
store,
|
|
||||||
userId,
|
userId,
|
||||||
listId,
|
listId,
|
||||||
statusId,
|
statusId,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import { cloneDeep, differenceWith, get, isEqual, set } from 'lodash'
|
||||||
import { defineStore } from 'pinia'
|
import { defineStore } from 'pinia'
|
||||||
|
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
addNewEmojiFile,
|
addNewEmojiFile,
|
||||||
|
|
@ -362,6 +363,7 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
|
||||||
async fetchStatuses(opts) {
|
async fetchStatuses(opts) {
|
||||||
const {
|
const {
|
||||||
data: { total, activities },
|
data: { total, activities },
|
||||||
|
timestamp,
|
||||||
} = await listStatuses({
|
} = await listStatuses({
|
||||||
credentials: useOAuthStore().token,
|
credentials: useOAuthStore().token,
|
||||||
opts,
|
opts,
|
||||||
|
|
@ -369,7 +371,7 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
|
||||||
|
|
||||||
const statuses = activities.map(parseStatus)
|
const statuses = activities.map(parseStatus)
|
||||||
|
|
||||||
await window.vuex.dispatch('addNewStatuses', { statuses })
|
useStatusesStore().addNewStatuses({ statuses, timestamp })
|
||||||
|
|
||||||
return {
|
return {
|
||||||
items: statuses,
|
items: statuses,
|
||||||
|
|
@ -377,13 +379,13 @@ export const useAdminSettingsStore = defineStore('adminSettings', {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async changeStatusScope(opts) {
|
async changeStatusScope(opts) {
|
||||||
const { data } = await changeStatusScope({
|
const { data, timestamp } = await changeStatusScope({
|
||||||
credentials: useOAuthStore().token,
|
credentials: useOAuthStore().token,
|
||||||
opts,
|
opts,
|
||||||
})
|
})
|
||||||
const status = parseStatus(data)
|
const status = parseStatus(data)
|
||||||
|
|
||||||
await window.vuex.dispatch('addNewStatuses', { statuses: [status] })
|
useStatusesStore().addNewStatuses({ statuses: [status], timestamp })
|
||||||
},
|
},
|
||||||
|
|
||||||
// Users stuff
|
// Users stuff
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import { useI18nStore } from 'src/stores/i18n.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
import { useReportsStore } from 'src/stores/reports.js'
|
import { useReportsStore } from 'src/stores/reports.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||||
import { useUsersStore } from 'src/stores/users.js'
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
|
|
@ -80,7 +81,7 @@ export const useNotificationsStore = defineStore('notifications', {
|
||||||
)
|
)
|
||||||
|
|
||||||
// Synchronous commit to add all the statuses
|
// Synchronous commit to add all the statuses
|
||||||
window.vuex.commit('addNewStatuses', {
|
useStatusesStore().addNewStatuses({
|
||||||
timestamp,
|
timestamp,
|
||||||
statuses: statusNotifications.map(
|
statuses: statusNotifications.map(
|
||||||
(notification) => notification.status,
|
(notification) => notification.status,
|
||||||
|
|
@ -90,7 +91,7 @@ export const useNotificationsStore = defineStore('notifications', {
|
||||||
// Update references to statuses in notifications to ones in the store
|
// Update references to statuses in notifications to ones in the store
|
||||||
statusNotifications.forEach((notification) => {
|
statusNotifications.forEach((notification) => {
|
||||||
const id = notification.status.id
|
const id = notification.status.id
|
||||||
const referenceStatus = window.vuex.state.statuses.allStatusesObject[id]
|
const referenceStatus = useStatusesStore().allStatuses.get(id)
|
||||||
|
|
||||||
if (referenceStatus) {
|
if (referenceStatus) {
|
||||||
notification.status = referenceStatus
|
notification.status = referenceStatus
|
||||||
|
|
@ -103,7 +104,7 @@ export const useNotificationsStore = defineStore('notifications', {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (notification.type === 'pleroma:emoji_reaction') {
|
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
|
// Only add a new notification if we don't have one for the same action
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import { defineStore } from 'pinia'
|
||||||
|
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
|
|
||||||
import { setReportState } from 'src/api/admin.js'
|
import { setReportState } from 'src/api/admin.js'
|
||||||
|
|
||||||
|
|
@ -18,8 +19,8 @@ export const useReportsStore = defineStore('reports', {
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
openUserReportingModal({ userId, statusIds = [] }) {
|
openUserReportingModal({ userId, statusIds = [] }) {
|
||||||
const preTickedStatuses = statusIds.map(
|
const preTickedStatuses = statusIds.map((id) =>
|
||||||
(id) => window.vuex.state.statuses.allStatusesObject[id],
|
useStatusesStore().allStatuses.get(id),
|
||||||
)
|
)
|
||||||
const preTickedIds = statusIds
|
const preTickedIds = statusIds
|
||||||
const statuses = preTickedStatuses.concat(
|
const statuses = preTickedStatuses.concat(
|
||||||
|
|
|
||||||
|
|
@ -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 { defineStore } from 'pinia'
|
||||||
|
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
|
|
@ -33,7 +33,7 @@ import {
|
||||||
unretweet,
|
unretweet,
|
||||||
} from 'src/api/user.js'
|
} from 'src/api/user.js'
|
||||||
|
|
||||||
const emptyTl = () => ({
|
const emptyTl = (userId) => ({
|
||||||
statuses: new Map(),
|
statuses: new Map(),
|
||||||
faves: [],
|
faves: [],
|
||||||
visibleStatuses: new Map(),
|
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 getLatestScrobble = (user) => {
|
||||||
const scrobblesSupport =
|
const scrobblesSupport =
|
||||||
useInstanceCapabilitiesStore().pleromaScrobblesAvailable
|
useInstanceCapabilitiesStore().pleromaScrobblesAvailable
|
||||||
|
|
@ -149,7 +106,6 @@ const getLatestScrobble = (user) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const USER_TIMELINES = new Set(['user', 'userPinned', 'media'])
|
const USER_TIMELINES = new Set(['user', 'userPinned', 'media'])
|
||||||
|
|
||||||
export const useStatusesStore = defineStore('statuses', {
|
export const useStatusesStore = defineStore('statuses', {
|
||||||
|
|
@ -160,8 +116,8 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
showImmediately = false,
|
showImmediately = false,
|
||||||
timelineName,
|
timelineName,
|
||||||
user = {},
|
user = {},
|
||||||
|
userId,
|
||||||
noIdUpdate = false,
|
noIdUpdate = false,
|
||||||
Id,
|
|
||||||
pagination = {},
|
pagination = {},
|
||||||
timestamp,
|
timestamp,
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -179,17 +135,14 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
// This makes sure that user timeline won't get data meant for other
|
// This makes sure that user timeline won't get data meant for other
|
||||||
// user. I.e. opening different user profiles makes request which could
|
// user. I.e. opening different user profiles makes request which could
|
||||||
// return data late after user already viewing different user profile
|
// return data late after user already viewing different user profile
|
||||||
if (
|
if (USER_TIMELINES.has(timelineName) && timeline.userId !== userId) {
|
||||||
USER_TIMELINES.has(timelineName) &&
|
|
||||||
timeline.userId !== userId
|
|
||||||
) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const addStatus = (data, showImmediately, addToTimeline = true) => {
|
const addStatus = (data, showImmediately, addToTimeline = true) => {
|
||||||
getLatestScrobble(data.user)
|
getLatestScrobble(data.user)
|
||||||
|
|
||||||
const [status] = mergeOrAdd(this.allStatuses, data)
|
const [status] = this.mergeOrAdd(this.allStatuses, data)
|
||||||
|
|
||||||
// Add to conversation
|
// Add to conversation
|
||||||
const conversations = this.conversations
|
const conversations = this.conversations
|
||||||
|
|
@ -210,7 +163,7 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
|
|
||||||
// Add the mention to the mentions timeline
|
// Add the mention to the mentions timeline
|
||||||
if (timeline !== mentions) {
|
if (timeline !== mentions) {
|
||||||
const [, isNew] = mergeOrAdd(mentions.statuses, status)
|
const [, isNew] = this.mergeOrAdd(mentions.statuses, data)
|
||||||
if (isNew) mentions.newStatusCount += 1
|
if (isNew) mentions.newStatusCount += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -218,21 +171,23 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
if (status.visibility === 'direct') {
|
if (status.visibility === 'direct') {
|
||||||
const dms = this.timelines.dms
|
const dms = this.timelines.dms
|
||||||
|
|
||||||
const [, isNew] = mergeOrAdd(dms.statuses, status)
|
const [, isNew] = this.mergeOrAdd(dms.statuses, data)
|
||||||
if (isNew) dms.newStatusCount += 1
|
if (isNew) dms.newStatusCount += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some statuses should only be added to the global status repository.
|
// Some statuses should only be added to the global status repository.
|
||||||
if (timeline && addToTimeline) {
|
if (timeline && addToTimeline) {
|
||||||
// Decide if we should treat the status as new for this timeline.
|
// Decide if we should treat the status as new for this timeline.
|
||||||
const [status, isNew] = mergeOrAdd(timeline.statuses, status)
|
const [status, isNew] = this.mergeOrAdd(timeline.statuses, data)
|
||||||
if (showImmediately) {
|
if (isNew) {
|
||||||
// Add it directly to the visibleStatuses, don't change
|
if (showImmediately) {
|
||||||
// newStatusCount
|
// Add it directly to the visibleStatuses, don't change
|
||||||
timeline.visibleStatuses.add(status.id, status)
|
// newStatusCount
|
||||||
} else {
|
timeline.visibleStatuses.set(status.id, status)
|
||||||
// Just change newStatuscount
|
} else {
|
||||||
timeline.newStatusCount += 1
|
// Just change newStatuscount
|
||||||
|
timeline.newStatusCount += 1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,12 +211,17 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
},
|
},
|
||||||
retweet: (status) => {
|
retweet: (status) => {
|
||||||
// RetweetedStatuses are never shown immediately
|
// RetweetedStatuses are never shown immediately
|
||||||
const retweetedStatus = addStatus(status.retweeted_status, false, false)
|
const retweetedStatus = addStatus(
|
||||||
|
status.retweeted_status,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
|
||||||
let retweet
|
let retweet
|
||||||
// If the retweeted status is already there, don't add the retweet
|
// If the retweeted status is already there, don't add the retweet
|
||||||
// to the timeline.
|
// to the timeline.
|
||||||
if (timeline?.statuses.values().some((s) => {
|
if (
|
||||||
|
[...(timeline?.statuses.values() ?? [])].some((s) => {
|
||||||
if (s.retweeted_status) {
|
if (s.retweeted_status) {
|
||||||
return (
|
return (
|
||||||
s.id === retweetedStatus.id ||
|
s.id === retweetedStatus.id ||
|
||||||
|
|
@ -313,6 +273,35 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
processor(status)
|
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) {
|
fetchStatus(id) {
|
||||||
return fetchStatus({ id }).then(({ data: status, timestamp }) =>
|
return fetchStatus({ id }).then(({ data: status, timestamp }) =>
|
||||||
this.addNewStatuses({ statuses: [status], timestamp }),
|
this.addNewStatuses({ statuses: [status], timestamp }),
|
||||||
|
|
@ -376,10 +365,7 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
fetchFavsAndRepeats(id) {
|
fetchFavsAndRepeats(id) {
|
||||||
return Promise.all([
|
return Promise.all([this.fetchFavs(id), this.fetchRepeats(id)])
|
||||||
this.fetchFavs(id),
|
|
||||||
this.fetchRepeats(id),
|
|
||||||
])
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Updates
|
// Updates
|
||||||
|
|
@ -414,8 +400,8 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
const minNew = pagination.maxId ?? minBy(statuses, 'id').id ?? ''
|
const minNew = pagination.maxId ?? minBy(statuses, 'id').id ?? ''
|
||||||
const maxNew = pagination.minId ?? maxBy(statuses, 'id').id ?? ''
|
const maxNew = pagination.minId ?? maxBy(statuses, 'id').id ?? ''
|
||||||
|
|
||||||
const newer = (maxNew > timeline.maxId || timeline.maxId === '')
|
const newer = maxNew > timeline.maxId || timeline.maxId === ''
|
||||||
const older = (minNew < timeline.minId || timeline.minId === '')
|
const older = minNew < timeline.minId || timeline.minId === ''
|
||||||
|
|
||||||
if (newer) {
|
if (newer) {
|
||||||
timeline.maxId = maxNew
|
timeline.maxId = maxNew
|
||||||
|
|
@ -429,8 +415,10 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
|
|
||||||
timeline.newStatusCount = 0
|
timeline.newStatusCount = 0
|
||||||
|
|
||||||
timeline.visibleStatuses = new Map([...timeline.statuses.entries()].slice(0, 50))
|
timeline.visibleStatuses = new Map(
|
||||||
timeline.minVisibleId = last(timeline.visibleStatuses).id
|
[...timeline.statuses.entries()].slice(0, 50),
|
||||||
|
)
|
||||||
|
timeline.minVisibleId = last(timeline.visibleStatuses.keys())
|
||||||
timeline.minId = ''
|
timeline.minId = ''
|
||||||
timeline.maxId = ''
|
timeline.maxId = ''
|
||||||
this.updateTimelineExtremes(timeline, [...timeline.statuses.values()])
|
this.updateTimelineExtremes(timeline, [...timeline.statuses.values()])
|
||||||
|
|
@ -442,9 +430,9 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
this[key] = value
|
this[key] = value
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
clearTimeline(state, { timeline, excludeUserId = false }) {
|
clearTimeline({ timeline, excludeUserId = false }) {
|
||||||
const userId = excludeUserId ? state.timelines[timeline].userId : undefined
|
const userId = excludeUserId ? this.timelines[timeline].userId : undefined
|
||||||
state.timelines[timeline] = emptyTl(userId)
|
this.timelines[timeline] = emptyTl(userId)
|
||||||
},
|
},
|
||||||
queueFlush({ timeline, id }) {
|
queueFlush({ timeline, id }) {
|
||||||
this.timelines[timeline].flushMarker = id
|
this.timelines[timeline].flushMarker = id
|
||||||
|
|
@ -650,8 +638,8 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
},
|
},
|
||||||
setBookmarked({ id, value, bookmark_folder_id }) {
|
setBookmarked({ id, value, bookmark_folder_id }) {
|
||||||
const status = this.allStatuses.get(id)
|
const status = this.allStatuses.get(id)
|
||||||
newStatus.bookmarked = value
|
status.bookmarked = value
|
||||||
newStatus.bookmark_folder_id = value ? bookmark_folder_id : null
|
status.bookmark_folder_id = value ? bookmark_folder_id : null
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Mute
|
/// Mute
|
||||||
|
|
@ -659,25 +647,29 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
return muteConversation({
|
return muteConversation({
|
||||||
id,
|
id,
|
||||||
credentials: useOAuthStore().token,
|
credentials: useOAuthStore().token,
|
||||||
}).then(({ data: status, timestamp }) => {
|
})
|
||||||
this.addNewStatuses({
|
.then(({ data: status, timestamp }) => {
|
||||||
statuses: [status],
|
this.addNewStatuses({
|
||||||
timestamp,
|
statuses: [status],
|
||||||
|
timestamp,
|
||||||
|
})
|
||||||
|
return status
|
||||||
})
|
})
|
||||||
return status
|
.then((status) => this.setMutedStatus(status))
|
||||||
}).then((status) => this.setMutedStatus(status))
|
|
||||||
},
|
},
|
||||||
unmuteConversation(id) {
|
unmuteConversation(id) {
|
||||||
return unmuteConversation({
|
return unmuteConversation({
|
||||||
id,
|
id,
|
||||||
credentials: useOAuthStore().token,
|
credentials: useOAuthStore().token,
|
||||||
}).then(({ data: status, timestamp }) => {
|
})
|
||||||
this.addNewStatuses({
|
.then(({ data: status, timestamp }) => {
|
||||||
statuses: [status],
|
this.addNewStatuses({
|
||||||
timestamp,
|
statuses: [status],
|
||||||
|
timestamp,
|
||||||
|
})
|
||||||
|
return status
|
||||||
})
|
})
|
||||||
return status
|
.then((status) => this.setMutedStatus(status))
|
||||||
}).then((status) => this.setMutedStatus(status))
|
|
||||||
},
|
},
|
||||||
setMutedStatus({ id, thread_muted }) {
|
setMutedStatus({ id, thread_muted }) {
|
||||||
// Setting thread_muted flag on all other known statuses
|
// Setting thread_muted flag on all other known statuses
|
||||||
|
|
@ -686,11 +678,11 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
newStatus.thread_muted = thread_muted
|
newStatus.thread_muted = thread_muted
|
||||||
|
|
||||||
if (newStatus.thread_muted !== undefined) {
|
if (newStatus.thread_muted !== undefined) {
|
||||||
state.conversations.get(newStatus.statusnet_conversation_id).forEach(
|
this.conversations
|
||||||
(status) => {
|
.get(newStatus.statusnet_conversation_id)
|
||||||
|
.forEach((status) => {
|
||||||
status.thread_muted = thread_muted
|
status.thread_muted = thread_muted
|
||||||
},
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -774,9 +766,7 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
statuses: data.statuses,
|
statuses: data.statuses,
|
||||||
})
|
})
|
||||||
|
|
||||||
data.statuses = data.statuses.map(
|
data.statuses = data.statuses.map((s) => this.allStatuses.get(s.id))
|
||||||
(s) => this.allStatuses.get(s.id),
|
|
||||||
)
|
|
||||||
return data
|
return data
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
@ -785,8 +775,7 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
removeUserStatuses({ timelineName, userId }) {
|
removeUserStatuses({ timelineName, userId }) {
|
||||||
const timeline = this.timelines[timelineName]
|
const timeline = this.timelines[timelineName]
|
||||||
|
|
||||||
timeline
|
timeline.statuses
|
||||||
.statuses
|
|
||||||
.values()
|
.values()
|
||||||
.filter(({ user }) => user.id === userId)
|
.filter(({ user }) => user.id === userId)
|
||||||
.forEach(({ id }) => {
|
.forEach(({ id }) => {
|
||||||
|
|
@ -795,8 +784,8 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
})
|
})
|
||||||
timeline.minVisibleId =
|
timeline.minVisibleId =
|
||||||
timeline.visibleStatuses.length > 0
|
timeline.visibleStatuses.length > 0
|
||||||
? last(timeline.visibleStatuses).id
|
? last(timeline.visibleStatuses).id
|
||||||
: 0
|
: 0
|
||||||
timeline.maxId =
|
timeline.maxId =
|
||||||
timeline.statuses.length > 0 ? first(timeline.statuses).id : 0
|
timeline.statuses.length > 0 ? first(timeline.statuses).id : 0
|
||||||
},
|
},
|
||||||
|
|
@ -807,8 +796,8 @@ export const useStatusesStore = defineStore('statuses', {
|
||||||
const status = this.allStatuses.get(id)
|
const status = this.allStatuses.get(id)
|
||||||
status.poll = poll
|
status.poll = poll
|
||||||
},
|
},
|
||||||
setLoading(state, { timeline, value }) {
|
setLoading({ timeline, value }) {
|
||||||
state.timelines[timeline].loading = value
|
this.timelines[timeline].loading = value
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,9 @@ import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.j
|
||||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||||
import { useListsStore } from 'src/stores/lists.js'
|
import { useListsStore } from 'src/stores/lists.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useNotificationsStore } from 'src/stores/notifications.js'
|
||||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||||
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
|
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
|
||||||
|
|
||||||
|
|
@ -144,12 +146,12 @@ export const useUsersStore = defineStore('users', {
|
||||||
const { data, timestamp } = response
|
const { data, timestamp } = response
|
||||||
const users = Array.isArray(data) ? data : [data]
|
const users = Array.isArray(data) ? data : [data]
|
||||||
|
|
||||||
users.forEach((user) => {
|
return users.map((user) => {
|
||||||
const existing = this.users.get(user.id) ?? {}
|
const existing = this.users.get(user.id) ?? {}
|
||||||
const oldTimestamp = this.timestamps.get(existing)
|
const oldTimestamp = this.timestamps.get(existing)
|
||||||
|
|
||||||
// implicit: if oldTimestamp is undefined this will still be false
|
// 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: unused0, ...old } = existing
|
||||||
const { relationship: unused1, ...neu } = user
|
const { relationship: unused1, ...neu } = user
|
||||||
|
|
@ -163,6 +165,8 @@ export const useUsersStore = defineStore('users', {
|
||||||
if (user.id === this.currentUser.id) {
|
if (user.id === this.currentUser.id) {
|
||||||
this.currentUser = newUser
|
this.currentUser = newUser
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this.users.get(user.id)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
updateUserRelationship(relationships) {
|
updateUserRelationship(relationships) {
|
||||||
|
|
@ -594,7 +598,7 @@ export const useUsersStore = defineStore('users', {
|
||||||
useBookmarkFoldersStore().stopFetching()
|
useBookmarkFoldersStore().stopFetching()
|
||||||
store.dispatch('stopFetchingFollowRequests')
|
store.dispatch('stopFetchingFollowRequests')
|
||||||
store.commit('clearNotifications')
|
store.commit('clearNotifications')
|
||||||
store.commit('resetStatuses')
|
useStatusesStore().resetStatuses()
|
||||||
useChatsStore().resetChats()
|
useChatsStore().resetChats()
|
||||||
oauth.clearToken()
|
oauth.clearToken()
|
||||||
Cookies.remove('__Host-pleroma_key', { path: '/' })
|
Cookies.remove('__Host-pleroma_key', { path: '/' })
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { mountOpts } from '../../../fixtures/setup_test'
|
||||||
|
|
||||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||||
|
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||||
import { useUsersStore } from 'src/stores/users.js'
|
import { useUsersStore } from 'src/stores/users.js'
|
||||||
|
|
||||||
const currentUser = {
|
const currentUser = {
|
||||||
|
|
@ -37,7 +38,7 @@ const replyMountOpts = (props) =>
|
||||||
props,
|
props,
|
||||||
afterStore(store) {
|
afterStore(store) {
|
||||||
useUsersStore().currentUser = currentUser
|
useUsersStore().currentUser = currentUser
|
||||||
store.state.statuses.allStatusesObject = {
|
useStatusesStore().allStatuses = {
|
||||||
[repliedStatus.id]: repliedStatus,
|
[repliedStatus.id]: repliedStatus,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue