diff --git a/apps/app-frontend/src/components/ui/QuickInstanceSwitcher.vue b/apps/app-frontend/src/components/ui/QuickInstanceSwitcher.vue index 256a0d0121..6d41adb369 100644 --- a/apps/app-frontend/src/components/ui/QuickInstanceSwitcher.vue +++ b/apps/app-frontend/src/components/ui/QuickInstanceSwitcher.vue @@ -5,7 +5,9 @@ import { commonMessages, ContextMenu, defineMessages, + injectAuth, injectNotificationManager, + injectUserPreferences, useVIntl, } from '@modrinth/ui' import { useQuery } from '@tanstack/vue-query' @@ -15,6 +17,7 @@ import { useRouter } from 'vue-router' import NavButton from '@/components/ui/NavButton.vue' import { useAppEvent } from '@/composables/use-app-event' +import { useAppSettings } from '@/composables/use-app-settings.ts' import { handleSevereError } from '@/composables/use-error.js' import { QUICK_INSTANCE_LIMIT_MAX, @@ -28,7 +31,11 @@ import { showInstanceInFolder } from '@/helpers/utils' import { instanceListQueryOptions } from '@/pages/instance/query-options' const ITEM_SIZE = 52 +const SYNC_DEBOUNCE_MS = 1000 const { handleError } = injectNotificationManager() +const auth = injectAuth() +const { updatePreferences } = injectUserPreferences() +const appSettings = useAppSettings() const instancesQuery = useQuery(instanceListQueryOptions()) const router = useRouter() const instanceOptions = ref() @@ -97,6 +104,41 @@ const setLimit = (count) => { } } +const syncLimitToAccount = () => { + if (!appSettings.syncFeaturesAcrossDevices || !auth.user.value) { + return + } + updatePreferences({ + behavior: { + quick_instance_count: quickInstances.limit.value ?? QUICK_INSTANCE_LIMIT_MAX, + }, + }).catch(() => undefined) +} + +let syncTimeout = null + +const cancelScheduledSync = () => { + if (syncTimeout !== null) { + clearTimeout(syncTimeout) + syncTimeout = null + } +} + +const scheduleSync = () => { + cancelScheduledSync() + syncTimeout = setTimeout(() => { + syncTimeout = null + syncLimitToAccount() + }, SYNC_DEBOUNCE_MS) +} + +const flushScheduledSync = () => { + if (syncTimeout !== null) { + cancelScheduledSync() + syncLimitToAccount() + } +} + const nudgeLimit = (delta) => { if (!canDrag.value) { return @@ -105,11 +147,17 @@ const nudgeLimit = (delta) => { if (target < 0 || target > maxVisible.value) { flashOverdrag() } + const previousLimit = quickInstances.limit.value setLimit(target) + if (quickInstances.limit.value !== previousLimit) { + scheduleSync() + } } let dragStartY = 0 let dragStartCount = 0 +let dragStartLimit = null +let dragHadPendingSync = false let wasOverdragging = false let overdragTimeout = null @@ -142,6 +190,9 @@ const onDividerPointerDown = (event) => { clearOverdragFlash() dragStartY = event.clientY dragStartCount = visibleCount.value + dragStartLimit = quickInstances.limit.value + dragHadPendingSync = syncTimeout !== null + cancelScheduledSync() document.body.classList.add('quick-instance-dragging') event.currentTarget.setPointerCapture(event.pointerId) } @@ -171,6 +222,9 @@ const endDrag = (event) => { if (event?.currentTarget?.hasPointerCapture?.(event.pointerId)) { event.currentTarget.releasePointerCapture(event.pointerId) } + if (dragHadPendingSync || quickInstances.limit.value !== dragStartLimit) { + syncLimitToAccount() + } } const onDividerPointerUp = (event) => { @@ -191,6 +245,7 @@ onMounted(() => { onUnmounted(() => { resizeObserver?.disconnect() + flushScheduledSync() document.body.classList.remove('quick-instance-dragging') clearOverdragFlash() })