moderately usable state
This commit is contained in:
parent
d77163cf91
commit
d0c3eafa84
15 changed files with 570 additions and 338 deletions
|
|
@ -110,8 +110,6 @@ const conversation = {
|
|||
},
|
||||
computed: {
|
||||
status() {
|
||||
console.log(this.statusId)
|
||||
console.log(useStatusesStore().allStatuses.get(this.statusId))
|
||||
return useStatusesStore().allStatuses.get(this.statusId)
|
||||
},
|
||||
maxDepthToShowByDefault() {
|
||||
|
|
|
|||
|
|
@ -23,11 +23,11 @@ import {
|
|||
import { useInstanceStore } from 'src/stores/instance.js'
|
||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||
import { useScrobblesStore } from 'src/stores/scrobbles.js'
|
||||
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||
import { useSyncConfigStore } from 'src/stores/sync_config.js'
|
||||
import { useUserHighlightStore } from 'src/stores/user_highlight.js'
|
||||
import { useUsersStore } from 'src/stores/users.js'
|
||||
import { useScrobblesStore } from 'src/stores/scrobbles.js'
|
||||
|
||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||
|
||||
|
|
@ -136,6 +136,12 @@ const Status = {
|
|||
status() {
|
||||
return this.statusoid ?? useStatusesStore().allStatuses.get(this.statusId)
|
||||
},
|
||||
repeater() {
|
||||
return useUsersStore().findUser(this.status.user.id)
|
||||
},
|
||||
user() {
|
||||
return useUsersStore().findUser(this.mainStatus.user.id)
|
||||
},
|
||||
showReasonMutedThread() {
|
||||
return (
|
||||
(this.mainStatus.thread_muted ||
|
||||
|
|
@ -153,38 +159,31 @@ const Status = {
|
|||
return this.mergedConfig.scaleMfm
|
||||
},
|
||||
repeaterClass() {
|
||||
const user = this.status.user
|
||||
return highlightClass(user)
|
||||
return highlightClass(this.repeater)
|
||||
},
|
||||
userClass() {
|
||||
const user = this.retweet
|
||||
? this.status.retweeted_status.user
|
||||
: this.status.user
|
||||
return highlightClass(user)
|
||||
return highlightClass(this.user)
|
||||
},
|
||||
deleted() {
|
||||
return this.status.deleted
|
||||
},
|
||||
repeaterStyle() {
|
||||
const user = this.status.user
|
||||
return highlightStyle(useUserHighlightStore().get(user.screen_name))
|
||||
return highlightStyle(useUserHighlightStore().get(this.repeater.screen_name))
|
||||
},
|
||||
userStyle() {
|
||||
if (this.noHeading) return
|
||||
const user = this.retweet
|
||||
? this.status.retweeted_status.user
|
||||
: this.status.user
|
||||
return highlightStyle(useUserHighlightStore().get(user.screen_name))
|
||||
return highlightStyle(useUserHighlightStore().get(this.user.screen_name))
|
||||
},
|
||||
userProfileLink() {
|
||||
return this.generateUserProfileLink(
|
||||
this.status.user.id,
|
||||
this.status.user.screen_name,
|
||||
this.user.id,
|
||||
this.user.screen_name,
|
||||
)
|
||||
},
|
||||
replyProfileLink() {
|
||||
if (this.isReply) {
|
||||
const user = useUsersStore().findUser(this.status.in_reply_to_user_id)
|
||||
const user = useUsersStore().findUser(this.mainStatus.in_reply_to_user_id)
|
||||
// FIXME Why user not found sometimes???
|
||||
return user ? user.statusnet_profile_url : 'NOT_FOUND'
|
||||
}
|
||||
|
|
@ -192,19 +191,16 @@ const Status = {
|
|||
retweet() {
|
||||
return !!this.status.retweeted_status
|
||||
},
|
||||
retweeterUser() {
|
||||
return this.status.user
|
||||
},
|
||||
retweeter() {
|
||||
repeaterName() {
|
||||
return this.status.user.name || this.status.user.screen_name_ui
|
||||
},
|
||||
retweeterHtml() {
|
||||
repeaterHtml() {
|
||||
return this.status.user.name
|
||||
},
|
||||
retweeterProfileLink() {
|
||||
repeaterProfileLink() {
|
||||
return this.generateUserProfileLink(
|
||||
this.status.user.id,
|
||||
this.status.user.screen_name,
|
||||
this.repeater.id,
|
||||
this.repeater.screen_name,
|
||||
)
|
||||
},
|
||||
mainStatus() {
|
||||
|
|
@ -214,10 +210,6 @@ const Status = {
|
|||
return this.status
|
||||
}
|
||||
},
|
||||
statusFromGlobalRepository() {
|
||||
// NOTE: Consider to replace status with statusFromGlobalRepository
|
||||
return useStatusesStore().allStatuses.get(this.status.id)
|
||||
},
|
||||
loggedIn() {
|
||||
return !!this.currentUser
|
||||
},
|
||||
|
|
@ -367,22 +359,22 @@ const Status = {
|
|||
},
|
||||
isReply() {
|
||||
return !!(
|
||||
this.status.in_reply_to_status_id && this.status.in_reply_to_user_id
|
||||
this.mainStatus.in_reply_to_status_id && this.mainStatus.in_reply_to_user_id
|
||||
)
|
||||
},
|
||||
replyToName() {
|
||||
if (this.status.in_reply_to_screen_name) {
|
||||
if (this.mainStatus.in_reply_to_screen_name) {
|
||||
return this.status.in_reply_to_screen_name
|
||||
} else {
|
||||
const user = useUsersStore().findUser(this.status.in_reply_to_user_id)
|
||||
const user = useUsersStore().findUser(this.mainStatus.in_reply_to_user_id)
|
||||
return user?.screen_name_ui
|
||||
}
|
||||
},
|
||||
combinedFavsAndRepeatsUsers() {
|
||||
// Use the status from the global status repository since favs and repeats are saved in it
|
||||
const combinedUsers = [].concat(
|
||||
this.statusFromGlobalRepository.favoritedBy,
|
||||
this.statusFromGlobalRepository.rebloggedBy,
|
||||
this.mainStatus.favoritedBy,
|
||||
this.mainStatus.rebloggedBy,
|
||||
)
|
||||
return uniqBy(combinedUsers, 'id')
|
||||
},
|
||||
|
|
@ -400,7 +392,7 @@ const Status = {
|
|||
!this.hidePostStats &&
|
||||
this.focused &&
|
||||
(this.combinedFavsAndRepeatsUsers.length > 0 ||
|
||||
this.statusFromGlobalRepository.quotes_count)
|
||||
this.mainStatus.quotes_count)
|
||||
)
|
||||
},
|
||||
muteBotStatuses() {
|
||||
|
|
@ -431,7 +423,7 @@ const Status = {
|
|||
return this.$i18n.t('general.scope_in_timeline.' + this.status.visibility)
|
||||
},
|
||||
isEdited() {
|
||||
return this.status.edited_at !== null
|
||||
return this.mainStatus.edited_at !== null
|
||||
},
|
||||
editingAvailable() {
|
||||
return useInstanceCapabilitiesStore().editingAvailable
|
||||
|
|
@ -562,22 +554,22 @@ const Status = {
|
|||
focused: function (id) {
|
||||
this.scrollIfFocused(id)
|
||||
},
|
||||
'status.repeat_num': function (num) {
|
||||
'mainStatus.repeat_num': function (num) {
|
||||
// refetch repeats when repeat_num is changed in any way
|
||||
if (
|
||||
this.focused &&
|
||||
this.statusFromGlobalRepository.rebloggedBy &&
|
||||
this.statusFromGlobalRepository.rebloggedBy.length !== num
|
||||
this.mainStatus.rebloggedBy &&
|
||||
this.mainStatus.rebloggedBy.length !== num
|
||||
) {
|
||||
this.$store.dispatch('fetchRepeats', this.status.id)
|
||||
}
|
||||
},
|
||||
'status.fave_num': function (num) {
|
||||
'mainStatus.fave_num': function (num) {
|
||||
// refetch favs when fave_num is changed in any way
|
||||
if (
|
||||
this.focused &&
|
||||
this.statusFromGlobalRepository.favoritedBy &&
|
||||
this.statusFromGlobalRepository.favoritedBy.length !== num
|
||||
this.mainStatus.favoritedBy &&
|
||||
this.mainStatus.favoritedBy.length !== num
|
||||
) {
|
||||
this.$store.dispatch('fetchFavs', this.status.id)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
icon="retweet"
|
||||
/>
|
||||
<user-link
|
||||
:user="status.user"
|
||||
:user="repeater"
|
||||
:at="false"
|
||||
/>
|
||||
</small>
|
||||
|
|
@ -53,32 +53,31 @@
|
|||
class="status-container repeat-info"
|
||||
>
|
||||
<UserAvatar
|
||||
v-if="retweet"
|
||||
class="left-side repeater-avatar"
|
||||
:user-id="statusoid.user.id"
|
||||
:user-id="repeater.id"
|
||||
/>
|
||||
<div class="right-side faint">
|
||||
<bdi
|
||||
class="status-username repeater-name"
|
||||
:title="retweeter"
|
||||
:title="repeaterName"
|
||||
>
|
||||
<router-link
|
||||
v-if="retweeterHtml"
|
||||
:to="retweeterProfileLink"
|
||||
v-if="repeaterHtml"
|
||||
:to="repeaterProfileLink"
|
||||
>
|
||||
<RichContent
|
||||
:html="retweeterHtml"
|
||||
:emoji="retweeterUser.emoji"
|
||||
:html="repeaterHtml"
|
||||
:emoji="repeater.emoji"
|
||||
:allow-non-square-emoji="allowNonSquareEmoji"
|
||||
:pause-mfm="pauseMfm"
|
||||
:scale-mfm="scaleMfm"
|
||||
:is-local="retweeterUser.is_local"
|
||||
:is-local="repeater.is_local"
|
||||
/>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-else
|
||||
:to="retweeterProfileLink"
|
||||
>{{ retweeter }}</router-link>
|
||||
:to="repeaterProfileLink"
|
||||
>{{ repeaterName }}</router-link>
|
||||
</bdi>
|
||||
<div class="repeat-label">
|
||||
<FAIcon
|
||||
|
|
@ -103,24 +102,24 @@
|
|||
class="left-side"
|
||||
>
|
||||
<a
|
||||
v-if="status.user?.name"
|
||||
v-if="user.name"
|
||||
:href="$router.resolve(userProfileLink).href"
|
||||
@click.prevent
|
||||
>
|
||||
<UserPopover
|
||||
:user-id="status.user.id"
|
||||
:user-id="user.id"
|
||||
:overlay-centers="true"
|
||||
>
|
||||
<UserAvatar
|
||||
class="post-avatar"
|
||||
:compact="compact"
|
||||
:user-id="status?.user.id"
|
||||
:user-id="user.id"
|
||||
/>
|
||||
</UserPopover>
|
||||
</a>
|
||||
<UserAvatar
|
||||
v-else
|
||||
:user-id="status?.user.id"
|
||||
:user-id="user.id"
|
||||
class="post-avatar"
|
||||
:compact="compact"
|
||||
:title="$t('status.unknown_user_info')"
|
||||
|
|
@ -133,38 +132,38 @@
|
|||
>
|
||||
<div class="heading-name-row">
|
||||
<div
|
||||
v-if="status.user"
|
||||
v-if="user"
|
||||
class="heading-left"
|
||||
>
|
||||
<h4
|
||||
v-if="status.user.name_html"
|
||||
v-if="user.name_html"
|
||||
class="status-username"
|
||||
:title="status.user.name"
|
||||
:title="user.name"
|
||||
>
|
||||
<RichContent
|
||||
:html="status.user.name"
|
||||
:emoji="status.user.emoji"
|
||||
:html="user.name"
|
||||
:emoji="user.emoji"
|
||||
:allow-non-square-emoji="allowNonSquareEmoji"
|
||||
:is-local="status.user.is_local"
|
||||
:is-local="user.is_local"
|
||||
/>
|
||||
</h4>
|
||||
<h4
|
||||
v-else
|
||||
class="status-username"
|
||||
:title="status.user.name"
|
||||
:title="user.name"
|
||||
>
|
||||
{{ status.user.name }}
|
||||
{{ user.name }}
|
||||
</h4>
|
||||
<user-link
|
||||
class="account-name"
|
||||
:title="status.user.screen_name_ui"
|
||||
:user="status.user"
|
||||
:title="user.screen_name_ui"
|
||||
:user="user"
|
||||
:at="false"
|
||||
/>
|
||||
<img
|
||||
v-if="!!(status.user && status.user.favicon)"
|
||||
v-if="!!(user && user.favicon)"
|
||||
class="status-favicon"
|
||||
:src="status.user.favicon"
|
||||
:src="user.favicon"
|
||||
>
|
||||
</div>
|
||||
|
||||
|
|
@ -184,12 +183,12 @@
|
|||
:to="{ name: 'conversation', params: { id: status.id } }"
|
||||
>
|
||||
<Timeago
|
||||
:time="status.created_at"
|
||||
:time="mainStatus.created_at"
|
||||
:auto-update="60"
|
||||
/>
|
||||
</router-link>
|
||||
<span
|
||||
v-if="status.visibility"
|
||||
v-if="mainStatus.visibility"
|
||||
class="visibility-icon"
|
||||
:title="visibilityLocalized"
|
||||
>
|
||||
|
|
@ -305,10 +304,10 @@
|
|||
<template #replyToWithIcon>
|
||||
<StatusPopover
|
||||
v-if="!isPreview"
|
||||
:status-id="status.parent_visible && status.in_reply_to_status_id"
|
||||
:status-id="mainStatus.parent_visible && mainStatus.in_reply_to_status_id"
|
||||
class="reply-to-popover"
|
||||
style="min-width: 0;"
|
||||
:class="{ '-strikethrough': !status.parent_visible }"
|
||||
:class="{ '-strikethrough': !mainStatus.parent_visible }"
|
||||
>
|
||||
<button
|
||||
class="button-unstyled reply-to"
|
||||
|
|
@ -397,7 +396,7 @@
|
|||
<template #time>
|
||||
<Timeago
|
||||
template-key="time.in_past"
|
||||
:time="status.edited_at"
|
||||
:time="mainStatus.edited_at"
|
||||
:auto-update="60"
|
||||
:long-format="true"
|
||||
/>
|
||||
|
|
@ -462,31 +461,31 @@
|
|||
>
|
||||
<div class="stats">
|
||||
<UserListPopover
|
||||
v-if="statusFromGlobalRepository.rebloggedBy && statusFromGlobalRepository.rebloggedBy.length > 0"
|
||||
:users="statusFromGlobalRepository.rebloggedBy"
|
||||
v-if="mainStatus.rebloggedBy && mainStatus.rebloggedBy.length > 0"
|
||||
:users="mainStatus.rebloggedBy"
|
||||
>
|
||||
<div class="stat-count">
|
||||
<a class="stat-title">{{ $t('status.repeats') }}</a>
|
||||
<div class="stat-number">
|
||||
{{ statusFromGlobalRepository.rebloggedBy.length }}
|
||||
{{ mainStatus.rebloggedBy.length }}
|
||||
</div>
|
||||
</div>
|
||||
</UserListPopover>
|
||||
<UserListPopover
|
||||
v-if="statusFromGlobalRepository.favoritedBy && statusFromGlobalRepository.favoritedBy.length > 0"
|
||||
:users="statusFromGlobalRepository.favoritedBy"
|
||||
v-if="mainStatus.favoritedBy && mainStatus.favoritedBy.length > 0"
|
||||
:users="mainStatus.favoritedBy"
|
||||
>
|
||||
<div
|
||||
class="stat-count"
|
||||
>
|
||||
<a class="stat-title">{{ $t('status.favorites') }}</a>
|
||||
<div class="stat-number">
|
||||
{{ statusFromGlobalRepository.favoritedBy.length }}
|
||||
{{ mainStatus.favoritedBy.length }}
|
||||
</div>
|
||||
</div>
|
||||
</UserListPopover>
|
||||
<router-link
|
||||
v-if="statusFromGlobalRepository.quotes_count > 0"
|
||||
v-if="mainStatus.quotes_count > 0"
|
||||
:to="{ name: 'quotes', params: { id: status.id } }"
|
||||
>
|
||||
<div
|
||||
|
|
@ -494,7 +493,7 @@
|
|||
>
|
||||
<a class="stat-title">{{ $t('status.quotes') }}</a>
|
||||
<div class="stat-number">
|
||||
{{ statusFromGlobalRepository.quotes_count }}
|
||||
{{ mainStatus.quotes_count }}
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
|
|
@ -507,13 +506,13 @@
|
|||
|
||||
<EmojiReactions
|
||||
v-if="(mergedConfig.emojiReactionsOnTimeline || focused) && (!noHeading && !isPreview)"
|
||||
:status="status"
|
||||
:status="mainStatus"
|
||||
/>
|
||||
|
||||
<StatusActionButtons
|
||||
v-if="!noHeading && !isPreview"
|
||||
class="status-action-buttons"
|
||||
:status="status"
|
||||
:status="mainStatus"
|
||||
:replying="replying"
|
||||
@toggle-replying="toggleReplyForm"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -15,6 +15,11 @@ const StatusPopover = {
|
|||
error: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
status() {
|
||||
return useStatusesStore().allStatuses.get(this.statusId)
|
||||
},
|
||||
},
|
||||
components: {
|
||||
Popover,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import ScrollTopButton from 'src/components/scroll_top_button/scroll_top_button.
|
|||
import TimelineMenu from 'src/components/timeline_menu/timeline_menu.vue'
|
||||
|
||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||
import { useMergedConfigStore } from 'src/stores/merged_config.js'
|
||||
import { useTimelinesStore } from 'src/stores/timelines.js'
|
||||
|
||||
|
|
@ -54,8 +55,9 @@ const Timeline = {
|
|||
return useTimelinesStore()[this.timelineRef.name]
|
||||
},
|
||||
filteredVisibleStatuses() {
|
||||
return [...this.timeline.visibleStatusesIds.keys()]
|
||||
.map((id) => this.timeline.statuses.get(id))
|
||||
return this.timeline.order
|
||||
.filter((id) => this.timeline.visibleStatusIds.has(id))
|
||||
.map((id) => useStatusesStore().allStatuses.get(id))
|
||||
.filter(({ pinned }) => (this.skipPinned ? !pinned : true))
|
||||
},
|
||||
newStatusCount() {
|
||||
|
|
@ -98,12 +100,12 @@ const Timeline = {
|
|||
}
|
||||
},
|
||||
statusesToDisplay() {
|
||||
const amount = this.timeline.visibleStatusesIds.size
|
||||
const amount = this.timeline.visibleStatusIds.size
|
||||
const statusesPerSide = Math.ceil(Math.max(3, window.innerHeight / 80))
|
||||
const min = Math.max(0, this.virtualScrollIndex - statusesPerSide)
|
||||
const max = Math.min(amount, this.virtualScrollIndex + statusesPerSide)
|
||||
return new Set(
|
||||
[...this.timeline.visibleStatusesIds.keys()].slice(min, max),
|
||||
this.timeline.order.slice(min, max),
|
||||
)
|
||||
},
|
||||
virtualScrollingEnabled() {
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@
|
|||
<Timeline
|
||||
key="media"
|
||||
:label="$t('user_card.media')"
|
||||
:disabled="!media.visibleStatusesIds.size"
|
||||
:disabled="media.visibleStatusIds.size === 0"
|
||||
:title="$t('user_card.media')"
|
||||
:timeline-ref="{ name: 'media', argument: userId }"
|
||||
embedded
|
||||
|
|
@ -92,7 +92,7 @@
|
|||
v-if="favoritesTabVisible"
|
||||
key="favorites"
|
||||
:label="$t('user_card.favorites')"
|
||||
:disabled="!favorites.visibleStatusesIds.size"
|
||||
:disabled="favorites.visibleStatusIds.size === 0"
|
||||
:title="$t('user_card.favorites')"
|
||||
:timeline-ref="{ name: 'favorites', argument: userId }"
|
||||
:argument="isUs ? undefined : userId"
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ const REPLY_VISIBILITY_TIMELINES = new Set([
|
|||
|
||||
const fetchAndUpdate = (
|
||||
{ timeline, argument, credentials },
|
||||
{ maxId, sinceId, older = false, showImmediately = false },
|
||||
{ older = false, showImmediately = false },
|
||||
) => {
|
||||
timeline.loading = true
|
||||
const { hideMutedPosts, replyVisibility } =
|
||||
|
|
@ -31,13 +31,9 @@ const fetchAndUpdate = (
|
|||
|
||||
if (older) {
|
||||
// When minId = 0 we need to fetch without maxId param
|
||||
args.maxId = maxId || timeline.minId || null
|
||||
args.maxId = timeline.minId || null
|
||||
} else {
|
||||
if (sinceId === undefined) {
|
||||
args.sinceId = timeline.maxId
|
||||
} else if (sinceId !== null) {
|
||||
args.sinceId = sinceId
|
||||
}
|
||||
args.sinceId = timeline.maxId || null
|
||||
}
|
||||
|
||||
args.withMuted = !hideMutedPosts
|
||||
|
|
@ -45,7 +41,7 @@ const fetchAndUpdate = (
|
|||
args.replyVisibility = replyVisibility
|
||||
}
|
||||
|
||||
const numStatusesBeforeFetch = timeline.statuses.size
|
||||
const numStatusesBeforeFetch = timeline.statusIds.size
|
||||
|
||||
return fetchTimeline(args)
|
||||
.then((response) => {
|
||||
|
|
@ -62,10 +58,12 @@ const fetchAndUpdate = (
|
|||
const processed = useStatusesStore()
|
||||
.addNewStatuses({ statuses, timestamp })
|
||||
.filter(Boolean)
|
||||
.map(({ id }) => id)
|
||||
|
||||
useTimelinesStore().addStatusesToTimeline(timeline.name, argument, {
|
||||
statuses: processed,
|
||||
showImmediately,
|
||||
older,
|
||||
pagination,
|
||||
})
|
||||
return { statuses, pagination }
|
||||
|
|
@ -95,8 +93,6 @@ const timelineFetcher = (timeline, argument, credentials) => {
|
|||
|
||||
const boundFetchAndUpdate = ({
|
||||
showImmediately,
|
||||
maxId,
|
||||
sinceId,
|
||||
older,
|
||||
} = {}) =>
|
||||
fetchAndUpdate(
|
||||
|
|
@ -106,8 +102,6 @@ const timelineFetcher = (timeline, argument, credentials) => {
|
|||
credentials,
|
||||
},
|
||||
{
|
||||
maxId,
|
||||
sinceId,
|
||||
older,
|
||||
showImmediately,
|
||||
},
|
||||
|
|
@ -117,7 +111,7 @@ const timelineFetcher = (timeline, argument, credentials) => {
|
|||
if (state.interval) throw new Error('Interval already exists!')
|
||||
|
||||
boundFetchAndUpdate({
|
||||
showImmediately: timeline.visibleStatusesIds.size === 0,
|
||||
showImmediately: timeline.visibleStatusIds.size === 0,
|
||||
})
|
||||
|
||||
state.interval = promiseInterval(boundFetchAndUpdate, 10000)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import {
|
||||
fetchScrobbles,
|
||||
} from 'src/api/public.js'
|
||||
|
||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||
import { useUsersStore } from 'src/stores/users.js'
|
||||
|
||||
import { fetchScrobbles } from 'src/api/public.js'
|
||||
|
||||
export const defaultState = () => ({
|
||||
scrobblesNextFetch: new Map(),
|
||||
|
|
@ -13,7 +14,7 @@ export const useScrobblesStore = defineStore('scrobbles', {
|
|||
actions: {
|
||||
getLatestScrobble(userId) {
|
||||
const scrobblesSupport =
|
||||
useInstanceCapabilitiesStore().pleromaScrobblesAvailable
|
||||
useInstanceCapabilitiesStore().pleromaScrobblesAvailable
|
||||
|
||||
if (!scrobblesSupport) {
|
||||
return
|
||||
|
|
@ -29,12 +30,12 @@ export const useScrobblesStore = defineStore('scrobbles', {
|
|||
.then(({ data: scrobbles }) => {
|
||||
useUsersStore().findUser(userId).latestScrobble = scrobbles[0]
|
||||
|
||||
this.scrobblesNextFetch.set(user.id, Date.now() + 60 * 1000)
|
||||
this.scrobblesNextFetch.set(userId, Date.now() + 60 * 1000)
|
||||
})
|
||||
.catch((e) => {
|
||||
useInstanceCapabilitiesStore().set('pleromaScrobblesAvailable', false)
|
||||
console.warn('cannot fetch scrobbles', e)
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
55
src/stores/search.js
Normal file
55
src/stores/search.js
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import { defineStore } from 'pinia'
|
||||
|
||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||
import { useUsersStore } from 'src/stores/users.js'
|
||||
|
||||
import { search2 } from 'src/api/public.js'
|
||||
|
||||
export const useSearchStore = defineStore('search', {
|
||||
actions: {
|
||||
async search({ q, resolve, limit, offset, following, type }) {
|
||||
const { data, ...rest } = await search2({
|
||||
q,
|
||||
resolve,
|
||||
limit,
|
||||
offset,
|
||||
following,
|
||||
type,
|
||||
credentials: useOAuthStore().token,
|
||||
})
|
||||
|
||||
const { accounts, statuses } = data
|
||||
|
||||
useUsersStore().addNewUsers({
|
||||
...rest,
|
||||
data: accounts,
|
||||
})
|
||||
|
||||
useStatusesStore().addNewStatuses({
|
||||
...rest,
|
||||
statuses,
|
||||
})
|
||||
|
||||
const output = {}
|
||||
output.statuses = statuses.map((s) =>
|
||||
useStatusesStore().allStatuses.get(s.id),
|
||||
)
|
||||
output.accounts = accounts.map((s) => useUsersStore().findUser(s.id))
|
||||
return output
|
||||
},
|
||||
|
||||
// Search
|
||||
searchUsers({ query }) {
|
||||
return searchUsers({
|
||||
query,
|
||||
credentials: useOAuthStore().token,
|
||||
}).then((result) => {
|
||||
const { data } = result
|
||||
useUsersStore().addNewUsers(result)
|
||||
|
||||
return data.map((s) => useUsersStore().findUser(s.id))
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
import { defineStore } from 'pinia'
|
||||
|
||||
import { useInstanceCapabilitiesStore } from 'src/stores/instance_capabilities.js'
|
||||
import { useInterfaceStore } from 'src/stores/interface.js'
|
||||
import { useOAuthStore } from 'src/stores/oauth.js'
|
||||
import { useStreamingStore } from 'src/stores/streaming.js'
|
||||
|
|
@ -240,6 +239,10 @@ export const useStatusesStore = defineStore('statuses', {
|
|||
const status = this.allStatuses.get(id)
|
||||
status.emoji_reactions = emojiReactions
|
||||
},
|
||||
updateStatusWithPoll(id, poll) {
|
||||
const status = this.allStatuses.get(id)
|
||||
status.poll = poll
|
||||
},
|
||||
|
||||
// Actions
|
||||
requestInteract({ name, id, optimisticCall, apiCall, argument, value }) {
|
||||
|
|
@ -524,49 +527,20 @@ export const useStatusesStore = defineStore('statuses', {
|
|||
|
||||
// For when blocking a user
|
||||
wipeUserStatuses(userId) {
|
||||
const removed = new Set()
|
||||
this.allStatuses.forEach((status) => {
|
||||
if (status.user.id === userId) {
|
||||
this.allStatuses.delete(status.id)
|
||||
|
||||
removed.add(status.id)
|
||||
}
|
||||
})
|
||||
return removed
|
||||
},
|
||||
|
||||
// Search
|
||||
search({ 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),
|
||||
})
|
||||
|
||||
this.addNewStatuses({
|
||||
statuses: data.statuses,
|
||||
})
|
||||
|
||||
data.statuses = data.statuses.map((s) => this.allStatuses.get(s.id))
|
||||
return data
|
||||
})
|
||||
},
|
||||
// Misc
|
||||
setVirtualHeight({ statusId, height }) {
|
||||
this.allStatuses.get(statusId).virtualHeight = height
|
||||
},
|
||||
updateStatusWithPoll({ id, poll }) {
|
||||
const status = this.allStatuses.get(id)
|
||||
status.poll = poll
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
|||
|
|
@ -12,16 +12,17 @@ import timelineFetcher from 'src/services/timeline_fetcher/timeline_fetcher.serv
|
|||
const emptyTl = (name, argument = null) => {
|
||||
const result = {
|
||||
name,
|
||||
statuses: new Map(),
|
||||
visibleStatusesIds: new Set(),
|
||||
order: [],
|
||||
statusIds: new Set(),
|
||||
visibleStatusIds: new Set(),
|
||||
newStatusCount: 0,
|
||||
maxId: '',
|
||||
minId: '',
|
||||
minVisibleId: '',
|
||||
loading: false,
|
||||
streaming: false,
|
||||
flushMarker: 0,
|
||||
fetcher: null,
|
||||
socket: null,
|
||||
}
|
||||
|
||||
const property = ARGUMENT_MAP[name]
|
||||
|
|
@ -88,6 +89,11 @@ export const useTimelinesStore = defineStore('timelines', {
|
|||
return
|
||||
}
|
||||
|
||||
const property = ARGUMENT_MAP[timelineName]
|
||||
if (property) {
|
||||
timeline[property] = argument
|
||||
}
|
||||
|
||||
timeline.fetcher = timelineFetcher(
|
||||
timeline,
|
||||
argument,
|
||||
|
|
@ -156,7 +162,11 @@ export const useTimelinesStore = defineStore('timelines', {
|
|||
},
|
||||
deactivateAll() {
|
||||
TIMELINES.forEach((name) => {
|
||||
this.deactivate(name, true)
|
||||
try {
|
||||
this.deactivate(name, true)
|
||||
} catch (e) {
|
||||
console.error(`Failed to deactivate timeline ${name}`)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
|
|
@ -169,7 +179,7 @@ export const useTimelinesStore = defineStore('timelines', {
|
|||
showImmediately = false,
|
||||
noIdUpdate = false,
|
||||
pagination = {},
|
||||
nested = false,
|
||||
older = false
|
||||
},
|
||||
) {
|
||||
if (statuses.length === 0) return
|
||||
|
|
@ -179,7 +189,7 @@ export const useTimelinesStore = defineStore('timelines', {
|
|||
// user. I.e. opening different user profiles makes request which could
|
||||
// return data late after user already viewing different user profile
|
||||
// Same can happen with tags etc.
|
||||
const property = ARGUMENT_MAP[name]
|
||||
const property = ARGUMENT_MAP[timelineName]
|
||||
|
||||
if (property && timeline[property] !== argument) {
|
||||
return
|
||||
|
|
@ -188,59 +198,36 @@ export const useTimelinesStore = defineStore('timelines', {
|
|||
if (!noIdUpdate) {
|
||||
this.updateTimelineExtremes(
|
||||
timeline,
|
||||
statuses.map((x) => x.id),
|
||||
pagination,
|
||||
)
|
||||
}
|
||||
|
||||
statuses.forEach((status) => {
|
||||
const isNew = !timeline.statuses.has(status.id)
|
||||
timeline.statuses.set(status.id, status)
|
||||
const filtered = statuses.filter((id) => !timeline.statusIds.has(id))
|
||||
if (older) {
|
||||
timeline.order.push(...filtered)
|
||||
} else {
|
||||
timeline.order.unshift(...filtered)
|
||||
}
|
||||
|
||||
statuses.forEach((statusId) => {
|
||||
const isNew = !timeline.statusIds.has(statusId)
|
||||
timeline.statusIds.add(statusId)
|
||||
|
||||
if (isNew) {
|
||||
if (showImmediately) {
|
||||
// Add it directly to the visibleStatuses, don't change
|
||||
// newStatusCount
|
||||
timeline.visibleStatusesIds.add(status.id)
|
||||
timeline.visibleStatusIds.add(statusId)
|
||||
} else {
|
||||
// Just change newStatuscount
|
||||
timeline.newStatusCount += 1
|
||||
}
|
||||
}
|
||||
|
||||
if (nested) return
|
||||
// We are mentioned in a post
|
||||
if (
|
||||
status.type === 'status' &&
|
||||
status.attentions.some(
|
||||
({ id }) => id === useUsersStore().currentUser?.id,
|
||||
)
|
||||
) {
|
||||
// Add the mention to the mentions timeline
|
||||
if (timeline !== this.mentions) {
|
||||
this.addStatusesToTimeline('mentions', null, {
|
||||
statuses: [status],
|
||||
nested: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (status.visibility === 'direct') {
|
||||
if (timeline !== this.dms) {
|
||||
this.addStatusesToTimeline('dms', null, {
|
||||
statuses: [status],
|
||||
nested: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
onStreamMessage(timeline, argument, event) {
|
||||
// This relies on statuses store to process this event first
|
||||
const status = useStatusesStore().allStatuses.get(event.data.status.id)
|
||||
|
||||
this.addStatusesToTimeline(timeline, argument, {
|
||||
statuses: [status],
|
||||
statuses: [event.data.status.id],
|
||||
})
|
||||
},
|
||||
|
||||
|
|
@ -278,10 +265,10 @@ export const useTimelinesStore = defineStore('timelines', {
|
|||
},
|
||||
|
||||
// Queues & Timeline manip
|
||||
updateTimelineExtremes(timeline, statuses, pagination = {}) {
|
||||
updateTimelineExtremes(timeline, pagination = {}) {
|
||||
// Can't use Math.min/max because it doesn't work with string (duh)
|
||||
const minNew = pagination.maxId ?? min(...statuses) ?? ''
|
||||
const maxNew = pagination.minId ?? max(...statuses) ?? ''
|
||||
const minNew = pagination.maxId ?? last(timeline.order) ?? ''
|
||||
const maxNew = pagination.minId ?? first(timeline.order) ?? ''
|
||||
|
||||
const newer = maxNew > timeline.maxId
|
||||
const older = minNew < timeline.minId
|
||||
|
|
@ -292,20 +279,17 @@ export const useTimelinesStore = defineStore('timelines', {
|
|||
if (older || timeline.minId === '') {
|
||||
timeline.minId = minNew
|
||||
}
|
||||
|
||||
this.syncOrder(timeline)
|
||||
},
|
||||
showNewStatuses(timelineName) {
|
||||
const timeline = this[timelineName]
|
||||
|
||||
timeline.newStatusCount = 0
|
||||
|
||||
timeline.visibleStatusesIds = new Set(
|
||||
[...timeline.statuses.keys()].slice(0, 50),
|
||||
)
|
||||
timeline.minVisibleId = last(timeline.visibleStatusesIds.keys())
|
||||
timeline.minId = ''
|
||||
timeline.maxId = ''
|
||||
|
||||
this.updateTimelineExtremes(timeline, [...timeline.statuses.keys()])
|
||||
timeline.visibleStatusIds = new Set([...timeline.statusIds])
|
||||
},
|
||||
syncOrder(timeline) {
|
||||
timeline.order = timeline.order.filter((id) => timeline.statusIds.has(id))
|
||||
},
|
||||
queueFlush(timeline, id) {
|
||||
this[timeline].flushMarker = id
|
||||
|
|
@ -317,23 +301,16 @@ export const useTimelinesStore = defineStore('timelines', {
|
|||
},
|
||||
|
||||
// Misc
|
||||
wipeUserStatuses(userId) {
|
||||
wipeStatuses(ids) {
|
||||
TIMELINES.forEach((timelineName) => {
|
||||
const timeline = this.timelines[timelineName]
|
||||
const timeline = this[timelineName]
|
||||
|
||||
timeline.statuses
|
||||
.values()
|
||||
.filter(({ user }) => user.id === userId)
|
||||
.forEach(({ id }) => {
|
||||
timeline.statuses.delete(id)
|
||||
timeline.visibleStatusesIds.delete(id)
|
||||
})
|
||||
timeline.minVisibleId =
|
||||
timeline.visibleStatusesIds.size > 0
|
||||
? last(timeline.visibleStatusesIds).id
|
||||
: 0
|
||||
timeline.maxId =
|
||||
timeline.statuses.length > 0 ? first(timeline.statuses).id : 0
|
||||
ids.forEach((id) => {
|
||||
timeline.statusIds.delete(id)
|
||||
timeline.visibleStatusIds.delete(id)
|
||||
})
|
||||
|
||||
this.syncOrder(timeline)
|
||||
})
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -746,17 +746,6 @@ export const useUsersStore = defineStore('users', {
|
|||
useInterfaceStore().onLogout()
|
||||
})
|
||||
},
|
||||
|
||||
// Search
|
||||
searchUsers({ query }) {
|
||||
return searchUsers({
|
||||
query,
|
||||
credentials: useOAuthStore().token,
|
||||
}).then(({ data: users }) => {
|
||||
this.addNewUsers(users)
|
||||
return users
|
||||
})
|
||||
},
|
||||
},
|
||||
persist: {
|
||||
paths: ['lastLoginName'],
|
||||
|
|
|
|||
|
|
@ -51,125 +51,12 @@ const externalProfileStore = createStore({
|
|||
mutations,
|
||||
actions,
|
||||
getters: testGetters,
|
||||
state: {
|
||||
interface: {
|
||||
browserSupport: '',
|
||||
},
|
||||
instance: {
|
||||
hideUserStats: true,
|
||||
},
|
||||
statuses: {
|
||||
timelines: {
|
||||
user: {
|
||||
statuses: [],
|
||||
statusesObject: {},
|
||||
faves: [],
|
||||
visibleStatuses: [],
|
||||
visibleStatusesObject: {},
|
||||
newStatusCount: 0,
|
||||
maxId: 0,
|
||||
minVisibleId: 0,
|
||||
loading: false,
|
||||
followers: [],
|
||||
friends: [],
|
||||
viewing: 'statuses',
|
||||
userId: 100,
|
||||
flushMarker: 0,
|
||||
},
|
||||
media: {
|
||||
statuses: [],
|
||||
statusesObject: {},
|
||||
faves: [],
|
||||
visibleStatuses: [],
|
||||
visibleStatusesObject: {},
|
||||
newStatusCount: 0,
|
||||
maxId: 0,
|
||||
minVisibleId: 0,
|
||||
loading: false,
|
||||
followers: [],
|
||||
friends: [],
|
||||
viewing: 'statuses',
|
||||
userId: 100,
|
||||
flushMarker: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
users: {
|
||||
currentUser: {
|
||||
credentials: '',
|
||||
},
|
||||
usersObject: { 100: extUser },
|
||||
usersByNameObject: {},
|
||||
users: [extUser],
|
||||
relationships: {},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
const localProfileStore = createStore({
|
||||
mutations,
|
||||
actions,
|
||||
getters: testGetters,
|
||||
state: {
|
||||
interface: {
|
||||
browserSupport: '',
|
||||
},
|
||||
config: {
|
||||
colors: '',
|
||||
highlight: {},
|
||||
customTheme: {
|
||||
colors: [],
|
||||
},
|
||||
},
|
||||
instance: {
|
||||
hideUserStats: true,
|
||||
},
|
||||
statuses: {
|
||||
timelines: {
|
||||
user: {
|
||||
statuses: [],
|
||||
statusesObject: {},
|
||||
faves: [],
|
||||
visibleStatuses: [],
|
||||
visibleStatusesObject: {},
|
||||
newStatusCount: 0,
|
||||
maxId: 0,
|
||||
minVisibleId: 0,
|
||||
loading: false,
|
||||
followers: [],
|
||||
friends: [],
|
||||
viewing: 'statuses',
|
||||
userId: 100,
|
||||
flushMarker: 0,
|
||||
},
|
||||
media: {
|
||||
statuses: [],
|
||||
statusesObject: {},
|
||||
faves: [],
|
||||
visibleStatuses: [],
|
||||
visibleStatusesObject: {},
|
||||
newStatusCount: 0,
|
||||
maxId: 0,
|
||||
minVisibleId: 0,
|
||||
loading: false,
|
||||
followers: [],
|
||||
friends: [],
|
||||
viewing: 'statuses',
|
||||
userId: 100,
|
||||
flushMarker: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
users: {
|
||||
currentUser: {
|
||||
credentials: '',
|
||||
},
|
||||
usersObject: { 100: localUser },
|
||||
usersByNameObject: { testuser: localUser },
|
||||
users: [localUser],
|
||||
relationships: {},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// https://github.com/vuejs/test-utils/issues/1382
|
||||
|
|
|
|||
|
|
@ -626,8 +626,9 @@ describe('Statuses store', () => {
|
|||
timestamp: 1,
|
||||
})
|
||||
|
||||
store.wipeUserStatuses('u19')
|
||||
const result = store.wipeUserStatuses('u19')
|
||||
|
||||
expect(store.allStatuses).to.have.length(19)
|
||||
expect(result).to.eql(new Set(['s19']))
|
||||
})
|
||||
})
|
||||
|
|
|
|||
358
test/unit/specs/stores/timelines.spec.js
Normal file
358
test/unit/specs/stores/timelines.spec.js
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
import { createTestingPinia } from '@pinia/testing'
|
||||
import { setActivePinia } from 'pinia'
|
||||
|
||||
import { useStatusesStore } from 'src/stores/statuses.js'
|
||||
import { useTimelinesStore } from 'src/stores/timelines.js'
|
||||
import { useStreamingStore } from 'src/stores/streaming.js'
|
||||
|
||||
describe('Timelines store', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers()
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
useTimelinesStore().deactivateAll()
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
describe('activate', () => {
|
||||
it('streamable', () => {
|
||||
const store = useTimelinesStore()
|
||||
const sub = vi.fn()
|
||||
useStreamingStore().addSubscriber = sub
|
||||
|
||||
console.log(store.activate)
|
||||
store.activate('friends', undefined, true)
|
||||
|
||||
expect(sub).to.have.been.called
|
||||
expect(store.friends.fetcher).to.not.be.null
|
||||
expect(store.friends.socket).to.not.be.null
|
||||
})
|
||||
|
||||
it('non-streamable', () => {
|
||||
const store = useTimelinesStore()
|
||||
const sub = vi.fn()
|
||||
useStreamingStore().addSubscriber = sub
|
||||
|
||||
console.log(store.activate)
|
||||
store.activate('user', '1')
|
||||
|
||||
expect(sub).to.not.have.been.called
|
||||
expect(store.user.fetcher).to.not.be.null
|
||||
expect(store.user.socket).to.be.null
|
||||
})
|
||||
})
|
||||
|
||||
describe('deactivate', () => {
|
||||
it('streamable', () => {
|
||||
const store = useTimelinesStore()
|
||||
const unsub = vi.fn()
|
||||
useStreamingStore().removeSubscriber = unsub
|
||||
|
||||
store.activate('friends', undefined, true)
|
||||
// Checking so that they were set properly before
|
||||
// since reset changes them to ''
|
||||
store.friends.maxId = '3'
|
||||
store.friends.minId = '4'
|
||||
store.friends.statusIds = new Set(['3','4'])
|
||||
store.friends.visibleStausIds = new Set(['3','4'])
|
||||
store.deactivate('friends', true)
|
||||
|
||||
expect(unsub).to.have.been.called
|
||||
expect(store.friends.fetcher).to.be.null
|
||||
expect(store.friends.socket).to.be.null
|
||||
expect(store.friends.statusIds).to.have.length(0)
|
||||
expect(store.friends.visibleStatusIds).to.have.length(0)
|
||||
expect(store.friends).to.have.property('maxId', '')
|
||||
expect(store.friends).to.have.property('minId', '')
|
||||
})
|
||||
|
||||
it('non-streamable', () => {
|
||||
const store = useTimelinesStore()
|
||||
const unsub = vi.fn()
|
||||
useStreamingStore().removeSubscriber = unsub
|
||||
|
||||
store.activate('user', '1')
|
||||
// Checking so that they were set properly before
|
||||
// since reset changes them to ''
|
||||
store.user.maxId = '3'
|
||||
store.user.minId = '4'
|
||||
store.user.statusIds = new Set(['3','4'])
|
||||
store.user.visibleStausIds = new Set(['3','4'])
|
||||
store.deactivate('user')
|
||||
|
||||
expect(unsub).to.not.have.been.called
|
||||
expect(store.user.fetcher).to.be.null
|
||||
expect(store.user.socket).to.be.null
|
||||
expect(store.user.statusIds).to.have.length(0)
|
||||
expect(store.user.visibleStatusIds).to.have.length(0)
|
||||
expect(store.user).to.have.property('maxId', '')
|
||||
expect(store.user).to.have.property('minId', '')
|
||||
})
|
||||
})
|
||||
|
||||
describe('updateTimelineExtremes', () => {
|
||||
it('should derive extremes from data', () => {
|
||||
const store = useTimelinesStore()
|
||||
const timeline = useTimelinesStore().friends
|
||||
timeline.order = ['4','1','3','2']
|
||||
timeline.statusesIds = new Set(timeline.order)
|
||||
store.updateTimelineExtremes(timeline)
|
||||
|
||||
expect(store.friends).to.have.property('maxId', '4')
|
||||
expect(store.friends).to.have.property('minId', '2')
|
||||
})
|
||||
|
||||
it('should use extremes from pagination', () => {
|
||||
const store = useTimelinesStore()
|
||||
const timeline = useTimelinesStore().friends
|
||||
store.updateTimelineExtremes(
|
||||
timeline,
|
||||
{ maxId: '1', minId: '2' }
|
||||
)
|
||||
|
||||
// Min and max are swapped!
|
||||
expect(store.friends).to.have.property('maxId', '2')
|
||||
expect(store.friends).to.have.property('minId', '1')
|
||||
})
|
||||
})
|
||||
|
||||
describe('addStatusesToTimeline', () => {
|
||||
it('adds the status to the given timeline', () => {
|
||||
const store = useTimelinesStore()
|
||||
const statuses = ['1','2','3']
|
||||
|
||||
store.activate('list', '1')
|
||||
store.addStatusesToTimeline(
|
||||
'list',
|
||||
'1',
|
||||
{
|
||||
statuses,
|
||||
pagination: { minId: '1', maxId: '3' }
|
||||
}
|
||||
)
|
||||
|
||||
expect(store.list.order).to.eql(statuses)
|
||||
expect(store.list.statusIds).to.eql(new Set(statuses))
|
||||
expect(store.list.visibleStatusIds).to.eql(new Set())
|
||||
expect(store.list.newStatusCount).to.equal(3)
|
||||
expect(store.list).to.have.property('maxId', '1')
|
||||
expect(store.list).to.have.property('minId', '3')
|
||||
})
|
||||
|
||||
it('ignores duplicates', () => {
|
||||
const store = useTimelinesStore()
|
||||
const statuses = ['1','2','3']
|
||||
|
||||
store.activate('list', '1')
|
||||
store.addStatusesToTimeline(
|
||||
'list',
|
||||
'1',
|
||||
{
|
||||
statuses,
|
||||
pagination: { minId: '1', maxId: '3' }
|
||||
}
|
||||
)
|
||||
store.addStatusesToTimeline(
|
||||
'list',
|
||||
'1',
|
||||
{
|
||||
statuses,
|
||||
pagination: { minId: '1', maxId: '3' }
|
||||
}
|
||||
)
|
||||
|
||||
expect(store.list.order).to.eql(statuses)
|
||||
expect(store.list.statusIds).to.eql(new Set(statuses))
|
||||
expect(store.list.visibleStatusIds).to.eql(new Set())
|
||||
expect(store.list.newStatusCount).to.equal(3)
|
||||
expect(store.list).to.have.property('maxId', '1')
|
||||
expect(store.list).to.have.property('minId', '3')
|
||||
})
|
||||
|
||||
it('adds the status the given timeline, directly visible', () => {
|
||||
const store = useTimelinesStore()
|
||||
const statuses = ['1','2','3']
|
||||
|
||||
store.activate('list', '1')
|
||||
store.addStatusesToTimeline(
|
||||
'list',
|
||||
'1',
|
||||
{
|
||||
statuses,
|
||||
showImmediately: true,
|
||||
pagination: { minId: '1', maxId: '3' }
|
||||
}
|
||||
)
|
||||
|
||||
expect(store.list.order).to.eql(statuses)
|
||||
expect(store.list.statusIds).to.eql(new Set(statuses))
|
||||
expect(store.list.visibleStatusIds).to.eql(new Set(statuses))
|
||||
expect(store.list.newStatusCount).to.equal(0)
|
||||
expect(store.list).to.have.property('maxId', '1')
|
||||
expect(store.list).to.have.property('minId', '3')
|
||||
})
|
||||
|
||||
it('does not update the maxId when the noIdUpdate flag is set', () => {
|
||||
const store = useTimelinesStore()
|
||||
const statuses = ['1','2','3']
|
||||
|
||||
store.activate('list', '1')
|
||||
store.addStatusesToTimeline(
|
||||
'list',
|
||||
'1',
|
||||
{
|
||||
statuses,
|
||||
noIdUpdate: true,
|
||||
pagination: { minId: '1', maxId: '3' }
|
||||
}
|
||||
)
|
||||
|
||||
expect(store.list.order).to.eql(statuses)
|
||||
expect(store.list.statusIds).to.eql(new Set(statuses))
|
||||
expect(store.list.visibleStatusIds).to.eql(new Set())
|
||||
expect(store.list.newStatusCount).to.equal(3)
|
||||
expect(store.list).to.have.property('maxId', '')
|
||||
expect(store.list).to.have.property('minId', '')
|
||||
})
|
||||
|
||||
it('does not update timeline if it belongs to a different arugment', () => {
|
||||
const store = useTimelinesStore()
|
||||
const statuses = ['1','2','3']
|
||||
|
||||
store.activate('list', '1')
|
||||
store.addStatusesToTimeline(
|
||||
'list',
|
||||
'2',
|
||||
{
|
||||
statuses,
|
||||
noIdUpdate: true,
|
||||
pagination: { minId: '1', maxId: '3' }
|
||||
}
|
||||
)
|
||||
|
||||
expect(store.list.order).to.eql([])
|
||||
expect(store.list.statusIds).to.eql(new Set())
|
||||
expect(store.list.visibleStatusIds).to.eql(new Set())
|
||||
expect(store.list.newStatusCount).to.equal(0)
|
||||
expect(store.list).to.have.property('maxId', '')
|
||||
expect(store.list).to.have.property('minId', '')
|
||||
})
|
||||
|
||||
it('prepends timeline with new statuses', () => {
|
||||
const store = useTimelinesStore()
|
||||
const statuses1 = ['3','2','1']
|
||||
const statuses2 = ['6','5','4']
|
||||
|
||||
store.activate('list', '1')
|
||||
store.addStatusesToTimeline(
|
||||
'list',
|
||||
'1',
|
||||
{
|
||||
statuses: statuses1,
|
||||
pagination: { minId: '3', maxId: '1' }
|
||||
}
|
||||
)
|
||||
store.addStatusesToTimeline(
|
||||
'list',
|
||||
'1',
|
||||
{
|
||||
statuses: statuses2,
|
||||
pagination: { minId: '6', maxId: '4' }
|
||||
}
|
||||
)
|
||||
|
||||
const newOrder = [...statuses2, ...statuses1]
|
||||
expect(store.list.order).to.eql(newOrder)
|
||||
expect(store.list.statusIds).to.eql(new Set(newOrder))
|
||||
expect(store.list.visibleStatusIds).to.eql(new Set())
|
||||
expect(store.list.newStatusCount).to.equal(6)
|
||||
expect(store.list).to.have.property('maxId', '6')
|
||||
expect(store.list).to.have.property('minId', '1')
|
||||
})
|
||||
|
||||
it('appends timeline with new statuses if fetching older', () => {
|
||||
const store = useTimelinesStore()
|
||||
const statuses1 = ['6','5','4']
|
||||
const statuses2 = ['3','2','1']
|
||||
|
||||
store.activate('list', '1')
|
||||
store.addStatusesToTimeline(
|
||||
'list',
|
||||
'1',
|
||||
{
|
||||
statuses: statuses1,
|
||||
pagination: { minId: '6', maxId: '4' },
|
||||
}
|
||||
)
|
||||
store.addStatusesToTimeline(
|
||||
'list',
|
||||
'1',
|
||||
{
|
||||
statuses: statuses2,
|
||||
pagination: { minId: '3', maxId: '1' },
|
||||
older: true,
|
||||
}
|
||||
)
|
||||
|
||||
const newOrder = [...statuses1, ...statuses2]
|
||||
expect(store.list.order).to.eql(newOrder)
|
||||
expect(store.list.statusIds).to.eql(new Set(newOrder))
|
||||
expect(store.list.visibleStatusIds).to.eql(new Set())
|
||||
expect(store.list.newStatusCount).to.equal(6)
|
||||
expect(store.list).to.have.property('maxId', '6')
|
||||
expect(store.list).to.have.property('minId', '1')
|
||||
})
|
||||
})
|
||||
|
||||
describe('showNewStatuses', () => {
|
||||
it('resets counter and makes all ids visible', () => {
|
||||
const store = useTimelinesStore()
|
||||
const statuses = ['1','2','3']
|
||||
|
||||
store.activate('public')
|
||||
store.addStatusesToTimeline(
|
||||
'public',
|
||||
undefined,
|
||||
{
|
||||
statuses,
|
||||
pagination: { minId: '1', maxId: '3' }
|
||||
}
|
||||
)
|
||||
|
||||
expect(store.public.statusIds).to.eql(new Set(statuses))
|
||||
expect(store.public.visibleStatusIds).to.eql(new Set())
|
||||
expect(store.public.newStatusCount).to.equal(3)
|
||||
store.showNewStatuses('public')
|
||||
expect(store.public.visibleStatusIds).to.eql(new Set(statuses))
|
||||
expect(store.public.newStatusCount).to.equal(0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('wipeStatuses', () => {
|
||||
it('clears all statuses', () => {
|
||||
const store = useTimelinesStore()
|
||||
|
||||
store.activate('friends')
|
||||
store.activate('public')
|
||||
store.addStatusesToTimeline(
|
||||
'public',
|
||||
undefined,
|
||||
{
|
||||
statuses: ['1','2','3','0']
|
||||
}
|
||||
)
|
||||
store.addStatusesToTimeline(
|
||||
'friends',
|
||||
undefined,
|
||||
{
|
||||
statuses: ['5','0','9','1']
|
||||
}
|
||||
)
|
||||
store.wipeStatuses(['0'])
|
||||
expect(store.friends.statusIds).to.not.have.members('0')
|
||||
expect(store.public.statusIds).to.not.have.members('0')
|
||||
})
|
||||
})
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue