From 71ee4052f34d99eaecc03a77593c05b451615f03 Mon Sep 17 00:00:00 2001 From: Zerebos Date: Sat, 23 May 2026 21:19:07 -0400 Subject: [PATCH] Cleanup routes and ux --- src/routes/+layout.svelte | 120 ++++++++++++++++++- src/routes/settings/+layout.svelte | 1 + src/routes/settings/general/+page.svelte | 66 +---------- src/routes/settings/server/+page.svelte | 139 +++++++++++++++++++++++ 4 files changed, 260 insertions(+), 66 deletions(-) create mode 100644 src/routes/settings/server/+page.svelte diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 1fb2cb2..bda8848 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -11,6 +11,7 @@ import { notificationsState } from '$lib/state/notifications.svelte' import { readerState } from '$lib/state/reader.svelte' import { clearDiscordPresence, isSupported, setDiscordPresence } from '$lib/platform-service' + import { loadDownloads } from '$lib/request-manager/downloads' import SplashScreen from '$lib/ui/chrome/SplashScreen.svelte' import AuthGate from '$lib/ui/chrome/AuthGate.svelte' import Sidebar from '$lib/ui/chrome/Sidebar.svelte' @@ -22,6 +23,7 @@ let splashVisible = $state(true) let bypassed = $state(false) + let closeDialogOpen = $state(false) const isTauri = typeof window !== 'undefined' && '__TAURI_INTERNALS__' in window const pathname = $derived($page.url.pathname as string) @@ -32,6 +34,32 @@ const showShell = $derived(appState.status === 'ready' || bypassed) const splashCards = $derived(settingsState.splashCards ?? true) + async function handleClose() { + if (!isTauri) return + const { getCurrentWindow } = await import('@tauri-apps/api/window') + const win = getCurrentWindow() + const action = settingsState.closeAction + if (action === 'tray') { + await win.hide() + } else if (action === 'ask') { + closeDialogOpen = true + } else { + await win.close() + } + } + + async function confirmQuit() { + closeDialogOpen = false + const { getCurrentWindow } = await import('@tauri-apps/api/window') + await getCurrentWindow().close() + } + + async function confirmTray() { + closeDialogOpen = false + const { getCurrentWindow } = await import('@tauri-apps/api/window') + await getCurrentWindow().hide() + } + function canUseDiscordRpc(): boolean { try { return isSupported('discord-rpc') @@ -141,10 +169,45 @@ }) } + const DOWNLOAD_POLL_MS = 8_000 + let downloadPollId: ReturnType | null = null + + function startDownloadPolling() { + if (downloadPollId !== null) return + void loadDownloads() + downloadPollId = setInterval(() => { + void loadDownloads() + }, DOWNLOAD_POLL_MS) + } + + function stopDownloadPolling() { + if (downloadPollId !== null) { + clearInterval(downloadPollId) + downloadPollId = null + } + } + + if (appState.status === 'ready') { + startDownloadPolling() + } + + const stopStatusWatch = $effect.root(() => { + $effect(() => { + if (appState.status === 'ready') { + startDownloadPolling() + } else { + stopDownloadPolling() + } + }) + return () => {} + }) + return () => { appState.idle = false stopZoomKey() stopIdleDetection() + stopDownloadPolling() + stopStatusWatch() window.removeEventListener('resize', handleResize) unmountSystemThemeSync() stopTauriScale?.() @@ -175,7 +238,7 @@
{#if isTauri} - import('@tauri-apps/api/window').then(m => m.getCurrentWindow().close())} /> + {/if}
@@ -193,6 +256,20 @@ {/if} +{#if closeDialogOpen} + +{/if} + \ No newline at end of file diff --git a/src/routes/settings/+layout.svelte b/src/routes/settings/+layout.svelte index 68896b4..33dab66 100644 --- a/src/routes/settings/+layout.svelte +++ b/src/routes/settings/+layout.svelte @@ -3,6 +3,7 @@ const sections = [ ['general', 'General'], + ['server', 'Server'], ['appearance', 'Appearance'], ['reader', 'Reader'], ['library', 'Library'], diff --git a/src/routes/settings/general/+page.svelte b/src/routes/settings/general/+page.svelte index 6897c8e..601ee08 100644 --- a/src/routes/settings/general/+page.svelte +++ b/src/routes/settings/general/+page.svelte @@ -1,7 +1,6 @@ @@ -13,7 +12,7 @@

General

Application basics

-

Core behavior, server connection, and desktop shell preferences.

+

Core behavior and desktop shell preferences.

@@ -44,69 +43,6 @@
-
-
-
Server URL
-
Base URL for the Suwayomi server.
-
- updateSettings({serverUrl: (event.currentTarget as HTMLInputElement).value})} - /> -
- - - - - -
-
-
-
Advanced server options
-
Custom binary path and launch args.
-
- -
- {#if advancedOpen} -
- - -
- {/if} -
-
Idle screen timeout
diff --git a/src/routes/settings/server/+page.svelte b/src/routes/settings/server/+page.svelte new file mode 100644 index 0000000..372a969 --- /dev/null +++ b/src/routes/settings/server/+page.svelte @@ -0,0 +1,139 @@ + + + + Settings - Server + + +
+
+

Server

+

Server connection

+

Configure the Suwayomi server URL, launch behavior, and file paths.

+
+ +
+
+
+
Server URL
+
Base URL for the Suwayomi server.
+
+ updateSettings({ serverUrl: (event.currentTarget as HTMLInputElement).value })} + /> +
+ + + + + +
+
+
+
Advanced launch options
+
Custom binary path and launch args.
+
+ +
+ {#if advancedOpen} +
+ + +
+ {/if} +
+
+ +
+
+
+
Downloads path
+
Directory where the server stores downloaded chapters.
+
+ updateSettings({ serverDownloadsPath: (event.currentTarget as HTMLInputElement).value })} + /> +
+ +
+
+
Local source path
+
Directory scanned for local manga sources.
+
+ updateSettings({ serverLocalSourcePath: (event.currentTarget as HTMLInputElement).value })} + /> +
+ +
+
+
Extra scan directories
+
Comma-separated additional directories the server should scan.
+
+ { + const raw = (event.currentTarget as HTMLInputElement).value + updateSettings({ extraScanDirs: raw.split(',').map((s) => s.trim()).filter(Boolean) }) + }} + /> +
+
+