move focused logic into useConversation (for real this time)

This commit is contained in:
Henry Jameson 2026-09-14 21:14:23 +03:00
commit 24b7335903
5 changed files with 82 additions and 83 deletions

View file

@ -21,7 +21,6 @@ import ThreadTree from 'src/components/thread_tree/thread_tree.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 { useStatusesStore } from 'src/stores/statuses.js'
import { useStreamingStore } from 'src/stores/streaming.js'
import { useConversation } from 'src/composables/useConversation.js' import { useConversation } from 'src/composables/useConversation.js'
import { useInterfaceSizes } from 'src/composables/useInterfaceSizes.js' import { useInterfaceSizes } from 'src/composables/useInterfaceSizes.js'
@ -72,18 +71,9 @@ export default {
}, },
emits: ['heightChange', 'suspendableStateChange'], emits: ['heightChange', 'suspendableStateChange'],
setup(props, { emit }) { setup(props, { emit }) {
// # Helpers const router = useRouter()
const getStatusObject = (id) => useStatusesStore().allStatuses.get(id)
const getConversationId = (statusId) => {
const status = getStatusObject(statusId)
return get(
status,
'retweeted_status.statusnet_conversation_id',
get(status, 'statusnet_conversation_id'),
)
}
const scroller = useScrollPosition() const scroller = useScrollPosition()
const tryScrollTo = async (id) => { const tryScrollTo = async (id) => {
if (!id) { if (!id) {
return return
@ -96,19 +86,9 @@ export default {
return await scroller.scrollIntoView(target, { block: 'nearest' }) return await scroller.scrollIntoView(target, { block: 'nearest' })
} }
const { statusId } = toRefs(props)
const router = useRouter()
// # Main Configuration / global state // # Main Configuration / global state
const { mergedConfig } = storeToRefs(useMergedConfigStore()) const { mergedConfig } = storeToRefs(useMergedConfigStore())
const { mastoUserSocketStatus } = storeToRefs(useStreamingStore())
const displayStyle = computed(() => mergedConfig.value.conversationDisplay) const displayStyle = computed(() => mergedConfig.value.conversationDisplay)
const streamingEnabled = computed(
() =>
mergedConfig.value.useStreamingApi &&
mastoUserSocketStatus === WSConnectionStatus.JOINED,
)
const { layoutType } = storeToRefs(useInterfaceStore()) const { layoutType } = storeToRefs(useInterfaceStore())
const mobileLayout = computed(() => layoutType.value === 'mobile') const mobileLayout = computed(() => layoutType.value === 'mobile')
@ -123,24 +103,11 @@ export default {
provide('isPage', isPage) provide('isPage', isPage)
provide('expandable', true) provide('expandable', true)
// # Focus
const focusedId = ref(statusId.value)
const focused = computed(() => (isExpanded.value ? focusedId.value : null))
const setFocused = (id) => {
if (!id) return
focusedId.value = id
if (!streamingEnabled.value) {
useStatusesStore().fetchStatus(id)
}
useStatusesStore().fetchFavsAndRepeats(id)
useStatusesStore().fetchEmojiReactions(id)
}
provide('focused', focused)
// # Main things // # Main things
const { statusId } = toRefs(props)
const { const {
focusedId,
setFocused,
currentStatus, currentStatus,
mainStatus, mainStatus,
conversation, conversation,
@ -148,40 +115,18 @@ export default {
getReplies, getReplies,
fetchConversation, fetchConversation,
loadError, loadError,
} = useConversation(focusedId, isExpanded) } = useConversation(statusId, isExpanded)
watch( watch(
expanded, expanded,
async (value) => { async (value) => {
if (value) { if (value) {
await fetchConversation() await fetchConversation()
} else {
resetDisplayState()
} }
if (isPage.value) return
}, },
{ flush: 'post' }, { flush: 'post' },
) )
const resetDisplayState = () => {
setFocused(statusId.value)
resetThreadDisplay()
}
watch(statusId, (newVal, oldVal) => {
const newConversationId = getConversationId(newVal)
const oldConversationId = getConversationId(oldVal)
if (
newConversationId &&
oldConversationId &&
newConversationId === oldConversationId
) {
setFocused(newVal)
} else {
resetDisplayState()
fetchConversation()
}
})
// Component created // Component created
if (isPage.value) { if (isPage.value) {
fetchConversation() fetchConversation()
@ -204,8 +149,6 @@ export default {
return result return result
} }
const { fontSize } = useInterfaceSizes()
// External virtual scrolling // External virtual scrolling
const unsuspendableIds = ref(new Set()) const unsuspendableIds = ref(new Set())
const suspendable = computed( const suspendable = computed(
@ -228,6 +171,7 @@ export default {
onUnmounted(() => resizeObserver.value.disconnect()) onUnmounted(() => resizeObserver.value.disconnect())
// Placeholder heights. // Placeholder heights.
const { fontSize } = useInterfaceSizes()
const mutedStatusHeight = computed(() => fontSize.value * 1.5) const mutedStatusHeight = computed(() => fontSize.value * 1.5)
const normalStatusHeight = computed(() => fontSize.value * 10) const normalStatusHeight = computed(() => fontSize.value * 10)
const getPlaceholderHeight = (id) => const getPlaceholderHeight = (id) =>
@ -238,6 +182,7 @@ export default {
const anchorIds = computed( const anchorIds = computed(
() => new Set([mainStatus.value?.id, currentStatus.value?.id]), () => new Set([mainStatus.value?.id, currentStatus.value?.id]),
) )
// # Linear style stuff // # Linear style stuff
const isLinearView = computed(() => displayStyle.value !== 'tree') const isLinearView = computed(() => displayStyle.value !== 'tree')
const linearElement = useTemplateRef('linear') const linearElement = useTemplateRef('linear')
@ -274,6 +219,13 @@ export default {
resetThreadDisplay, resetThreadDisplay,
} = useTreeConversationTopology(conversation, replies, focusedId) } = useTreeConversationTopology(conversation, replies, focusedId)
provide('threadDisplay', threadDisplay) provide('threadDisplay', threadDisplay)
watch(
isExpanded,
(value) => {
if (!value) resetThreadDisplay()
},
{ flush: 'post' },
)
const ancestorsElement = useTemplateRef('ancestors') const ancestorsElement = useTemplateRef('ancestors')
const treeScrollCompensation = computed(() => isTreeView.value) const treeScrollCompensation = computed(() => isTreeView.value)
@ -333,7 +285,7 @@ export default {
toggleExpanded, toggleExpanded,
// # Focus // # Focus
focused, focusedId,
setFocused, setFocused,
// # Main things // # Main things

View file

@ -103,7 +103,7 @@
:status-id="element.item.id" :status-id="element.item.id"
:replies="getReplies(element.item.id)" :replies="getReplies(element.item.id)"
:focused="focused === element.item.id" :focused="focusedId === element.item.id"
conversation-rank="ancestor" conversation-rank="ancestor"
:data-status-id="element.id" :data-status-id="element.id"
:data-vs-height="element.height" :data-vs-height="element.height"
@ -149,7 +149,7 @@
:status-id="element.item.id" :status-id="element.item.id"
:replies="getReplies(element.item.id)" :replies="getReplies(element.item.id)"
:focused="focused === element.id || focused === element.item.retweeted_status?.id" :focused="focusedId === element.item.id || focusedId === element.item.retweeted_status?.id"
:data-status-id="element.id" :data-status-id="element.id"
:data-vs-height="element.height" :data-vs-height="element.height"

View file

@ -37,7 +37,7 @@ const ThreadTree = {
], ],
inject: [ inject: [
'conversation', 'conversation',
'focused', 'focusedId',
'replies', 'replies',
'threadDisplay', 'threadDisplay',
'isExpanded', 'isExpanded',

View file

@ -8,8 +8,8 @@
class="conversation-status conversation-status-treeview panel-body" class="conversation-status conversation-status-treeview panel-body"
:status-id="statusId" :status-id="statusId"
:replies="getReplies(statusId)" :replies="getReplies(statusId)"
:focused="focused === statusId"
:focused="focusedId === status.id"
:data-status-id="statusId" :data-status-id="statusId"
:conversation-rank="depth === 0 ? 'current' : 'child'" :conversation-rank="depth === 0 ? 'current' : 'child'"
:thread-display-state="threadDisplay.get(statusId)" :thread-display-state="threadDisplay.get(statusId)"

View file

@ -1,8 +1,13 @@
import { get } from 'lodash-es' import { get } from 'lodash-es'
import { computed, provide, ref } from 'vue' import { storeToRefs } from 'pinia'
import { computed, provide, ref, watch } from 'vue'
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 { useStatusesStore } from 'src/stores/statuses.js'
import { useStreamingStore } from 'src/stores/streaming.js'
import { useMainStatus } from 'src/composables/useMainStatus.js'
import { import {
fetchConversation as apiFetchConversation, fetchConversation as apiFetchConversation,
@ -10,20 +15,58 @@ import {
} from 'src/api/public.js' } from 'src/api/public.js'
export function useConversation(statusId, expanded) { export function useConversation(statusId, expanded) {
const getStatusObject = (id) => useStatusesStore().allStatuses.get(id)
const getConversationId = (statusId) => {
const status = getStatusObject(statusId)
return get(
status,
'retweeted_status.statusnet_conversation_id',
get(status, 'statusnet_conversation_id'),
)
}
const loadError = ref(null) const loadError = ref(null)
const currentStatus = computed(() => getStatusObject(statusId.value)) const { status: currentStatus, mainStatus } = useMainStatus(statusId)
const mainStatus = computed(
() => currentStatus.value?.retweeted_status ?? currentStatus.value, // # Config
const { mergedConfig } = storeToRefs(useMergedConfigStore())
const { mastoUserSocketStatus } = storeToRefs(useStreamingStore())
const streamingEnabled = computed(
() =>
mergedConfig.value.useStreamingApi &&
mastoUserSocketStatus === WSConnectionStatus.JOINED,
)
// # Focus
const focusedId = ref(null)
const { mainStatus: focusedStatus } = useMainStatus(focusedId)
const setFocused = (id) => {
focusedId.value = id
console.log('SF', id)
}
provide('focusedId', focusedId)
watch(mainStatus, (newStatus, oldStatus) => {
setFocused(newStatus.id)
const newConversationId = newStatus?.statusnet_conversation_id
const oldConversationId = oldStatus?.statusnet_conversation_id
if (
newConversationId &&
oldConversationId &&
newConversationId === oldConversationId
) {
} else {
// resetDisplayState()
// fetchConversation()
}
})
watch(expanded, (value) => {
setFocused(value ? statusId.value : null)
}, { immediate: true })
watch(
focusedStatus,
(newVal, oldVal) => {
if (!newVal) return
if (newVal?.id === oldVal?.id) return // prevents infinite loop
if (!streamingEnabled.value) {
useStatusesStore().fetchStatus(newVal.id)
}
useStatusesStore().fetchFavsAndRepeats(newVal.id)
useStatusesStore().fetchEmojiReactions(newVal.id)
},
{ immediate: true },
) )
const sortById = (a, b) => { const sortById = (a, b) => {
@ -43,7 +86,9 @@ export function useConversation(statusId, expanded) {
return idA < idB ? -1 : 1 return idA < idB ? -1 : 1
} }
} }
const conversationId = computed(() => getConversationId(statusId.value)) const conversationId = computed(
() => mainStatus.value.statusnet_conversation_id,
)
const conversation = computed(() => { const conversation = computed(() => {
if (!currentStatus.value) { if (!currentStatus.value) {
return [] return []
@ -117,6 +162,8 @@ export function useConversation(statusId, expanded) {
} }
return { return {
focusedId,
setFocused,
currentStatus, currentStatus,
mainStatus, mainStatus,
conversation, conversation,