diff --git a/changelog.d/avatar_mentions.change b/changelog.d/avatar_mentions.change
deleted file mode 100644
index f75f02ea4..000000000
--- a/changelog.d/avatar_mentions.change
+++ /dev/null
@@ -1 +0,0 @@
-If user avatars next to mentions are enabled it will show empty placeholder avatar next to label while user is being fetched, to avoid jumps
diff --git a/changelog.d/follower-remove.fix b/changelog.d/follower-remove.fix
deleted file mode 100644
index 4b78b087d..000000000
--- a/changelog.d/follower-remove.fix
+++ /dev/null
@@ -1 +0,0 @@
-Fix follower remove API call
diff --git a/changelog.d/streaming_indicator.add b/changelog.d/streaming_indicator.add
index f2abe04a1..547307384 100644
--- a/changelog.d/streaming_indicator.add
+++ b/changelog.d/streaming_indicator.add
@@ -1,3 +1 @@
-Added an indicator next to instance's name showing WebSocket connection status (if enabled).
-Timeline no longer show "loading" indicator at the bottom when fetching newer posts.
-Added small indicator on top of timeline when new posts are being fetched
+Added an indicator next to instance's name showing WebSocket connection status (if enabled)
diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js
index 69fca2f2c..cc4aecfe3 100644
--- a/src/components/conversation/conversation.js
+++ b/src/components/conversation/conversation.js
@@ -1,5 +1,6 @@
import { get, reduce } from 'lodash'
-import { mapState } from 'pinia'
+import { mapState as mapPiniaState } from 'pinia'
+import { mapState } from 'vuex'
import ChatMessageList from 'src/components/chat_message_list/chat_message_list.vue'
import PostStatusForm from 'src/components/post_status_form/post_status_form.vue'
@@ -12,7 +13,6 @@ import { useInterfaceStore } from 'src/stores/interface.js'
import { useMergedConfigStore } from 'src/stores/merged_config.js'
import { useOAuthStore } from 'src/stores/oauth.js'
import { useStatusesStore } from 'src/stores/statuses.js'
-import { useStreamingStore } from 'src/stores/streaming.js'
import { fetchConversation, fetchStatus } from 'src/api/public.js'
import { WSConnectionStatus } from 'src/api/websocket.js'
@@ -93,7 +93,6 @@ const conversation = {
default: false,
},
},
- emits: ['update:virtualHeight'],
data() {
return {
focused: null,
@@ -102,7 +101,6 @@ const conversation = {
inlineDivePosition: null,
loadStatusError: null,
unsuspendibleIds: new Set(),
- virtualHeight: 120,
}
},
created() {
@@ -110,9 +108,6 @@ const conversation = {
this.fetchConversation()
}
},
- mounted() {
- this.updateVirtualHeight()
- },
computed: {
status() {
return useStatusesStore().allStatuses.get(this.statusId)
@@ -365,8 +360,8 @@ const conversation = {
return !!(this.expanded || this.isPage)
},
hiddenStyle() {
- if (this.isExpanded) return {}
- return { height: this.virtualHeight + 'px' }
+ const height = this.status?.virtualHeight || '120px'
+ return this.virtualHidden ? { height } : {}
},
threadDisplayStatus() {
return this.conversation.reduce((a, k) => {
@@ -393,11 +388,11 @@ const conversation = {
maybeFocused() {
return this.isExpanded ? this.focused : null
},
- ...mapState(useMergedConfigStore, ['mergedConfig']),
- ...mapState(useStreamingStore, {
- mastoUserSocketStatus: (state) => state.state,
+ ...mapPiniaState(useMergedConfigStore, ['mergedConfig']),
+ ...mapState({
+ mastoUserSocketStatus: (state) => state.api.mastoUserSocketStatus,
}),
- ...mapState(useInterfaceStore, {
+ ...mapPiniaState(useInterfaceStore, {
mobileLayout: (store) => store.layoutType === 'mobile',
}),
},
@@ -431,7 +426,10 @@ const conversation = {
}
},
virtualHidden() {
- this.updateVirtualHeight()
+ useStatusesStore().setVirtualHeight({
+ statusId: this.statusId,
+ height: `${this.$el.clientHeight}px`,
+ })
},
},
methods: {
@@ -620,16 +618,6 @@ const conversation = {
this.$router.push({ name: 'conversation', params: { id: data.id } })
}
},
- updateVirtualHeight() {
- this.$nextTick(() => {
- this.virtualHeight = this.$refs.body.getBoundingClientRect().height
- this.$emit('update:virtualHeight', {
- id: this.status.id,
- height: this.virtualHeight,
- top: this.$el.clientTop,
- })
- })
- },
},
}
diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue
index cc1376978..ae6e3a0ce 100644
--- a/src/components/conversation/conversation.vue
+++ b/src/components/conversation/conversation.vue
@@ -40,7 +40,6 @@
@@ -57,7 +56,6 @@
diveIntoStatus(status.id)"
@suspendable-state-change="onStatusSuspendStateChange"
- @height-change="updateVirtualHeight"
/>
diff --git a/src/components/desktop_nav/desktop_nav.js b/src/components/desktop_nav/desktop_nav.js
index 15a5cfb15..32d0b37a9 100644
--- a/src/components/desktop_nav/desktop_nav.js
+++ b/src/components/desktop_nav/desktop_nav.js
@@ -135,9 +135,9 @@ export default {
this.showConfirmLogout()
}
},
- async doLogout() {
- await useUsersStore().logout()
+ doLogout() {
this.$router.replace('/main/public')
+ useUsersStore().logout()
this.hideConfirmLogout()
},
onSearchBarToggled(hidden) {
diff --git a/src/components/login_form/login_form.js b/src/components/login_form/login_form.js
index 8801d2c2e..6c2750677 100644
--- a/src/components/login_form/login_form.js
+++ b/src/components/login_form/login_form.js
@@ -1,9 +1,9 @@
-import { mapActions, mapState } from 'pinia'
+import { mapActions, mapState as mapPiniaState } from 'pinia'
+import { mapState } from 'vuex'
import { useAuthFlowStore } from 'src/stores/auth_flow.js'
import { useInstanceStore } from 'src/stores/instance.js'
import { useOAuthStore } from 'src/stores/oauth.js'
-import { useUsersStore } from 'src/stores/users.js'
import { getLoginUrl, getTokenWithCredentials } from 'src/api/oauth.js'
@@ -18,10 +18,12 @@ const LoginForm = {
error: false,
}),
computed: {
- ...mapState(useUsersStore, ['loggingIn']),
- ...mapState(useOAuthStore, ['clientId', 'clientSecret']),
- ...mapState(useInstanceStore, ['server', 'registrationOpen']),
- ...mapState(useAuthFlowStore, {
+ ...mapState({
+ loggingIn: (state) => state.users.loggingIn,
+ }),
+ ...mapPiniaState(useOAuthStore, ['clientId', 'clientSecret']),
+ ...mapPiniaState(useInstanceStore, ['server', 'registrationOpen']),
+ ...mapPiniaState(useAuthFlowStore, {
isTokenAuth: (store) => store.requiredToken,
isPasswordAuth: (store) => !store.requiredToken,
}),
diff --git a/src/components/mention_link/mention_link.js b/src/components/mention_link/mention_link.js
index 5db90ab41..374e62259 100644
--- a/src/components/mention_link/mention_link.js
+++ b/src/components/mention_link/mention_link.js
@@ -29,7 +29,7 @@ const MentionLink = {
},
props: {
url: {
- required: false,
+ required: true,
type: String,
},
content: {
@@ -75,11 +75,11 @@ const MentionLink = {
},
computed: {
user() {
- return this.url ? useUsersStore().findUserByUrl(this.url) : null
+ return this.url && useUsersStore().findUserByUrl(this.url)
},
isYou() {
- if (!this.currentUser) return false
- return this.user === this.currentUser
+ // FIXME why user !== currentUser???
+ return this.user?.id === this.currentUser.id
},
userName() {
return this.user && this.userNameFullUi.split('@')[0]
diff --git a/src/components/mention_link/mention_link.vue b/src/components/mention_link/mention_link.vue
index 3973522b0..33f0d9db7 100644
--- a/src/components/mention_link/mention_link.vue
+++ b/src/components/mention_link/mention_link.vue
@@ -8,20 +8,15 @@
:href="url"
class="original"
target="_blank"
- >
-
-
-
+ v-html="content"
+ />
store.supportsAnnouncements,
}),
- ...mapState(useInstanceCapabilitiesStore, [
+ ...mapPiniaState(useInstanceCapabilitiesStore, [
'pleromaChatMessagesAvailable',
'pleromaBookmarkFoldersAvailable',
'localBubble',
]),
- ...mapState(useInstanceStore, ['federating']),
- ...mapState(useInstanceStore, {
+ ...mapPiniaState(useInstanceStore, ['federating']),
+ ...mapPiniaState(useInstanceStore, {
privateMode: (store) => store.private,
}),
- ...mapState(useSyncConfigStore, {
+ ...mapPiniaState(useSyncConfigStore, {
collapsed: (store) => store.prefsStorage.simple.collapseNav,
pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedNavItems),
}),
- ...mapState(useUsersStore, ['currentUser']),
- ...mapVuexState({
+ ...mapPiniaState(useUsersStore, ['currentUser']),
+ ...mapState({
followRequestCount: (state) => state.api.followRequests.length,
}),
- ...mapState(useChatsStore, ['unreadChatsCount']),
+ ...mapPiniaState(useChatsStore, ['unreadChatsCount']),
timelinesItems() {
return filterNavigation(
Object.entries({ ...TIMELINES })
diff --git a/src/components/navigation/navigation_pins.js b/src/components/navigation/navigation_pins.js
index 2efa94ee4..d1be73819 100644
--- a/src/components/navigation/navigation_pins.js
+++ b/src/components/navigation/navigation_pins.js
@@ -1,5 +1,5 @@
-import { mapState } from 'pinia'
-import { mapState as mapVuexState } from 'vuex'
+import { mapState as mapPiniaState } from 'pinia'
+import { mapState } from 'vuex'
import {
filterNavigation,
@@ -59,26 +59,26 @@ const NavPanel = {
getters() {
return this.$store.getters
},
- ...mapState(useListsStore, {
+ ...mapPiniaState(useListsStore, {
lists: getListEntries,
}),
- ...mapState(useAnnouncementsStore, {
+ ...mapPiniaState(useAnnouncementsStore, {
supportsAnnouncements: (store) => store.supportsAnnouncements,
}),
- ...mapState(useBookmarkFoldersStore, {
+ ...mapPiniaState(useBookmarkFoldersStore, {
bookmarks: getBookmarkFolderEntries,
}),
- ...mapState(useSyncConfigStore, {
+ ...mapPiniaState(useSyncConfigStore, {
pinnedItems: (store) =>
new Set(store.prefsStorage.collections.pinnedNavItems),
}),
- ...mapState(useInstanceStore, ['privateMode', 'federating']),
- ...mapState(useInstanceCapabilitiesStore, [
+ ...mapPiniaState(useInstanceStore, ['privateMode', 'federating']),
+ ...mapPiniaState(useInstanceCapabilitiesStore, [
'pleromaChatMessagesAvailable',
'localBubble',
]),
- ...mapState(useUsersStore, ['currentUser']),
- ...mapVuexState({
+ ...mapPiniaState(useUsersStore, ['currentUser']),
+ ...mapState({
followRequestCount: (state) => state.api.followRequests.length,
}),
pinnedList() {
diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js
index 3c82f455c..a589c0cf6 100644
--- a/src/components/notification/notification.js
+++ b/src/components/notification/notification.js
@@ -118,6 +118,9 @@ const Notification = {
useInstanceStore().restrictedNicknames,
)
},
+ getUser(notification) {
+ return this.$store.state.users.usersObject[notification.from_profile.id]
+ },
interacted() {
this.$emit('interacted')
},
diff --git a/src/components/oauth_callback/oauth_callback.js b/src/components/oauth_callback/oauth_callback.js
index 824ab7bda..bf6e03c9e 100644
--- a/src/components/oauth_callback/oauth_callback.js
+++ b/src/components/oauth_callback/oauth_callback.js
@@ -16,10 +16,10 @@ const oac = {
clientSecret,
instance: useInstanceStore().server,
code: this.code,
- }).then(async ({ data: result }) => {
+ }).then(({ data: result }) => {
oauthStore.setToken(result.access_token)
- await useUsersStore().loginUser(result.access_token)
+ useUsersStore().loginUser(result.access_token)
this.$router.push({ name: 'friends' })
})
}
diff --git a/src/components/quick_filter_settings/quick_filter_settings.js b/src/components/quick_filter_settings/quick_filter_settings.js
index 482524eb6..089cb1d26 100644
--- a/src/components/quick_filter_settings/quick_filter_settings.js
+++ b/src/components/quick_filter_settings/quick_filter_settings.js
@@ -28,7 +28,7 @@ const QuickFilterSettings = {
path: 'replyVisibility',
value: visibility,
})
- useStatusesStore().requireReloadAll()
+ useStatusesStore().queueFlushAll()
},
openTab(tab) {
useInterfaceStore().openSettingsModalTab(tab)
diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue
index 0ad7c026a..0abcfe656 100644
--- a/src/components/registration/registration.vue
+++ b/src/components/registration/registration.vue
@@ -303,7 +303,7 @@
diff --git a/src/components/settings_modal/helpers/vertical_tab_switcher.jsx b/src/components/settings_modal/helpers/vertical_tab_switcher.jsx
index 2f3d5e28f..996939c00 100644
--- a/src/components/settings_modal/helpers/vertical_tab_switcher.jsx
+++ b/src/components/settings_modal/helpers/vertical_tab_switcher.jsx
@@ -1,6 +1,6 @@
// eslint-disable-next-line no-unused
-import { mapState } from 'pinia'
+import { mapState as mapPiniaState } from 'pinia'
import { Fragment } from 'vue'
import { FontAwesomeIcon as FAIcon } from '@fortawesome/vue-fontawesome'
@@ -60,7 +60,7 @@ export default {
return this.$slots.default().findIndex(isWanted) === this.activeIndex
}
},
- ...mapState(useInterfaceStore, {
+ ...mapPiniaState(useInterfaceStore, {
mobileLayout: (store) => store.layoutType === 'mobile',
}),
},
diff --git a/src/components/settings_modal/tabs/clutter_tab.js b/src/components/settings_modal/tabs/clutter_tab.js
index 18300231c..a3f6e77a5 100644
--- a/src/components/settings_modal/tabs/clutter_tab.js
+++ b/src/components/settings_modal/tabs/clutter_tab.js
@@ -36,7 +36,7 @@ const ClutterTab = {
// Updating nested properties
watch: {
replyVisibility() {
- useStatusesStore().requireReloadAll()
+ useStatusesStore().queueFlushAll()
},
},
}
diff --git a/src/components/settings_modal/tabs/filtering_tab.js b/src/components/settings_modal/tabs/filtering_tab.js
index fbc7b8902..9d49eca81 100644
--- a/src/components/settings_modal/tabs/filtering_tab.js
+++ b/src/components/settings_modal/tabs/filtering_tab.js
@@ -266,7 +266,7 @@ const FilteringTab = {
// Updating nested properties
watch: {
replyVisibility() {
- useStatusesStore().requireReloadAll()
+ useStatusesStore().queueFlushAll()
},
muteFiltersObject() {
this.muteFiltersDraftObject = cloneDeep(
diff --git a/src/components/status/status.js b/src/components/status/status.js
index 16625235d..749e0a12e 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -105,6 +105,7 @@ const Status = {
isPreview: Boolean,
noHeading: Boolean,
inlineExpanded: Boolean,
+ showPinned: Boolean,
inProfile: Boolean,
inConversation: Boolean,
inQuote: Boolean,
@@ -117,13 +118,7 @@ const Status = {
threadDisplayStatus: String,
},
- emits: [
- 'goto',
- 'dive',
- 'toggleExpanded',
- 'suspendableStateChange',
- 'heightChange',
- ],
+ emits: ['goto', 'dive', 'toggleExpanded', 'suspendableStateChange'],
data() {
return {
replying: false,
@@ -194,7 +189,7 @@ const Status = {
)
// User referenced in post might not be yet present in store
- // since their data is not included in status data, just the id
+ // since their data is not included in status data
return user?.statusnet_profile_url
}
},
@@ -375,7 +370,7 @@ const Status = {
},
replyToName() {
if (this.mainStatus.in_reply_to_screen_name) {
- return this.mainStatus.in_reply_to_screen_name
+ return this.status.in_reply_to_screen_name
} else {
const user = useUsersStore().findUser(
this.mainStatus.in_reply_to_user_id,
@@ -392,7 +387,7 @@ const Status = {
return uniqBy(combinedUsers, 'id')
},
tags() {
- return [...this.status.tags]
+ return this.status.tags
.filter((tagObj) => Object.hasOwn(tagObj, 'name'))
.map((tagObj) => tagObj.name)
.join(' ')
@@ -544,7 +539,6 @@ const Status = {
this.headTailLinks = headTailLinks
},
toggleThreadDisplay() {
- // FIXME
this.controlledToggleThreadDisplay()
},
scrollIfFocused(focused) {
@@ -563,22 +557,8 @@ const Status = {
}
}
},
- onTransitionEnd() {
- this.$nextTick(() => {
- this.$emit('heightChange')
- })
- },
},
watch: {
- status: {
- deep: true,
- handler() {
- this.$emit('heightChange')
- },
- },
- replying() {
- this.$emit('heightChange')
- },
focused: function (id) {
this.scrollIfFocused(id)
},
@@ -604,7 +584,6 @@ const Status = {
},
isSuspendable: function (suspend) {
this.$emit('suspendableStateChange', { id: this.status.id, suspend })
- this.$emit('heightChange')
},
},
}
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 0db67f24b..f0b2f1277 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -169,7 +169,7 @@
-
+
-
+
-
diff --git a/src/components/tab_switcher/tab_switcher.jsx b/src/components/tab_switcher/tab_switcher.jsx
index b21d4eb04..01913f709 100644
--- a/src/components/tab_switcher/tab_switcher.jsx
+++ b/src/components/tab_switcher/tab_switcher.jsx
@@ -101,10 +101,6 @@ export default {
classesTab.push('active')
classesWrapper.push('active')
}
- if (props.disabled) {
- classesTab.push('disabled')
- classesWrapper.push('disabled')
- }
if (props.image) {
return (
diff --git a/src/components/thread_tree/thread_tree.js b/src/components/thread_tree/thread_tree.js
index 6bcfa469f..491fab78f 100644
--- a/src/components/thread_tree/thread_tree.js
+++ b/src/components/thread_tree/thread_tree.js
@@ -30,7 +30,7 @@ const ThreadTree = {
totalReplyCount: Object,
totalReplyDepth: Object,
},
- emits: ['suspendableStateChange', 'goto', 'dive', 'heightChange'],
+ emits: ['suspendableStateChange', 'goto', 'dive'],
computed: {
currentReplies() {
return this.getReplies(this.statusId).map(({ id }) => id)
diff --git a/src/components/thread_tree/thread_tree.vue b/src/components/thread_tree/thread_tree.vue
index be95f8698..2dae7beee 100644
--- a/src/components/thread_tree/thread_tree.vue
+++ b/src/components/thread_tree/thread_tree.vue
@@ -22,7 +22,6 @@
@goto="$emit('goto', statusId)"
@toggle-expanded="toggleExpanded"
@suspendable-state-change="e => $emit('suspendableStateChange', e)"
- @height-change="e => $emit('heightChange', e)"
/>
$emit('goto', e)"
@dive="(e) => $emit('dive', e)"
@suspendable-state-change="e => $emit('suspendableStateChange', e)"
- @height-change="e => $emit('heightChange', e)"
/>
useStatusesStore().allStatuses.get(id))
.filter(({ pinned }) => (this.skipPinned ? !pinned : true))
},
- count() {
- return this.timeline.order.length
- },
newStatusCount() {
return this.timeline.newStatusCount
},
showLoadButton() {
- return this.timeline.newStatusCount > 0 || this.timeline.reloadNeeded
+ return this.timeline.newStatusCount > 0 || this.timeline.flushMarker !== 0
},
loadButtonString() {
- if (this.timeline.reloadNeeded) {
+ if (this.timeline.flushMarker !== 0) {
return this.$t('timeline.reload')
} else {
return `${this.$t('timeline.show_new')} (${this.newStatusCount})`
}
},
mobileLoadButtonString() {
- if (this.timeline.reloadNeeded) {
+ if (this.timeline.flushMarker !== 0) {
return '+'
} else {
return this.newStatusCount > 99 ? '∞' : this.newStatusCount
@@ -101,7 +99,6 @@ const Timeline = {
}
},
statusesToDisplay() {
- if (!this.virtualScrollingEnabled) return this.visibleStatusIds
const amount = this.timeline.visibleStatusIds.size
const statusesPerSide = Math.ceil(Math.max(3, window.innerHeight / 80))
const min = Math.max(0, this.virtualScrollIndex - statusesPerSide)
@@ -170,8 +167,9 @@ const Timeline = {
if (e.key === '.') this.showNewStatuses()
},
showNewStatuses() {
- if (this.timeline.reloadNeeded) {
+ if (this.timeline.flushMarker !== 0) {
useTimelinesStore().clearTimeline(this.timelineRef.name)
+ useTimelinesStore().queueFlush(this.timelineRef.name, '')
this.fetchOlderStatuses()
} else {
this.blockClicksTemporarily()
@@ -192,12 +190,13 @@ const Timeline = {
if (!this.virtualScrollingEnabled) return
const statuses = this.$refs.timeline.children
- if (statuses.length === 0) return
const cappedScrollIndex = Math.max(
0,
Math.min(this.virtualScrollIndex, statuses.length - 1),
)
+ if (statuses.length === 0) return
+
const height = Math.max(document.body.offsetHeight, window.pageYOffset)
const centerOfScreen = window.pageYOffset + window.innerHeight * 0.5
@@ -235,11 +234,11 @@ const Timeline = {
this.virtualScrollIndex = approxIndex
},
scrollLoad() {
- // TODO simplify this logic
const bodyBRect = document.body.getBoundingClientRect()
const height = Math.max(bodyBRect.height, -bodyBRect.y)
if (
- !this.timeline.fetcher.loadingOlder.value &&
+ !this.timeline.fetcher.loading.value &&
+ this.$el.offsetHeight > 0 &&
window.innerHeight + window.pageYOffset >= height - 750
) {
this.fetchOlderStatuses()
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
index 1435bba48..745d8c399 100644
--- a/src/components/timeline/timeline.vue
+++ b/src/components/timeline/timeline.vue
@@ -1,6 +1,5 @@
-
-
-
+