mirror of
https://github.com/moku-project/Moku.git
synced 2026-06-13 09:19:56 -05:00
Fix: MacOS TitleBar & History Reactive-Glitch
This commit is contained in:
@@ -14,10 +14,8 @@ Minor Revisions:
|
|||||||
- Add Hover Info on Library (Make sure doesn't conflict with additional clicks)
|
- Add Hover Info on Library (Make sure doesn't conflict with additional clicks)
|
||||||
|
|
||||||
Priority Bugs:
|
Priority Bugs:
|
||||||
- Resume on Home-Page leads to Reader, not Cached 5 chapters
|
|
||||||
- Fix History (Counting Chapters, Etc)
|
|
||||||
- Cache ALL Cover Pictures & Details for Manga in Library
|
- Cache ALL Cover Pictures & Details for Manga in Library
|
||||||
|
- MacOS Full-Screen & UI Compatability (TitleBar)
|
||||||
|
|
||||||
General/Misc Bugs:
|
General/Misc Bugs:
|
||||||
- Fix Highlightable Elements
|
- Fix Highlightable Elements
|
||||||
@@ -27,6 +25,9 @@ General/Misc Bugs:
|
|||||||
- Investigate Prod vs. Dev Directory Change/Data Load (Caused by Library Algorithm Revision?)
|
- Investigate Prod vs. Dev Directory Change/Data Load (Caused by Library Algorithm Revision?)
|
||||||
|
|
||||||
In-Progress:`
|
In-Progress:`
|
||||||
|
- Fix Reader Chapter Shifts (Glitched Sentinel)
|
||||||
|
- Still Shifts Down after reading ~8+ Chapters?
|
||||||
|
- Identify When Chapters are Unloaded, How to Preserve Structure
|
||||||
|
|
||||||
|
|
||||||
Important Commands:
|
Important Commands:
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
inherit version;
|
inherit version;
|
||||||
src = frontendSrc;
|
src = frontendSrc;
|
||||||
fetcherVersion = 1;
|
fetcherVersion = 1;
|
||||||
hash = "sha256-G82kmXm1prRpU9kqUyFHSABVt1fikMzvz78+w/gFKvQ=";
|
hash = "sha256-4QUSgWgMu7FGn44+TGmACheokPhaBdHvA/055SqUs0Q=";
|
||||||
};
|
};
|
||||||
|
|
||||||
buildPhase = "pnpm build";
|
buildPhase = "pnpm build";
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "^2.0.0",
|
"@tauri-apps/api": "^2.0.0",
|
||||||
|
"@tauri-apps/plugin-os": "^2.3.2",
|
||||||
"@tauri-apps/plugin-shell": "^2.3.5",
|
"@tauri-apps/plugin-shell": "^2.3.5",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"phosphor-svelte": "^3.1.0",
|
"phosphor-svelte": "^3.1.0",
|
||||||
|
|||||||
Generated
+10
@@ -11,6 +11,9 @@ importers:
|
|||||||
'@tauri-apps/api':
|
'@tauri-apps/api':
|
||||||
specifier: ^2.0.0
|
specifier: ^2.0.0
|
||||||
version: 2.10.1
|
version: 2.10.1
|
||||||
|
'@tauri-apps/plugin-os':
|
||||||
|
specifier: ^2.3.2
|
||||||
|
version: 2.3.2
|
||||||
'@tauri-apps/plugin-shell':
|
'@tauri-apps/plugin-shell':
|
||||||
specifier: ^2.3.5
|
specifier: ^2.3.5
|
||||||
version: 2.3.5
|
version: 2.3.5
|
||||||
@@ -436,6 +439,9 @@ packages:
|
|||||||
engines: {node: '>= 10'}
|
engines: {node: '>= 10'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
'@tauri-apps/plugin-os@2.3.2':
|
||||||
|
resolution: {integrity: sha512-n+nXWeuSeF9wcEsSPmRnBEGrRgOy6jjkSU+UVCOV8YUGKb2erhDOxis7IqRXiRVHhY8XMKks00BJ0OAdkpf6+A==}
|
||||||
|
|
||||||
'@tauri-apps/plugin-shell@2.3.5':
|
'@tauri-apps/plugin-shell@2.3.5':
|
||||||
resolution: {integrity: sha512-jewtULhiQ7lI7+owCKAjc8tYLJr92U16bPOeAa472LHJdgaibLP83NcfAF2e+wkEcA53FxKQAZ7byDzs2eeizg==}
|
resolution: {integrity: sha512-jewtULhiQ7lI7+owCKAjc8tYLJr92U16bPOeAa472LHJdgaibLP83NcfAF2e+wkEcA53FxKQAZ7byDzs2eeizg==}
|
||||||
|
|
||||||
@@ -1032,6 +1038,10 @@ snapshots:
|
|||||||
'@tauri-apps/cli-win32-ia32-msvc': 2.10.1
|
'@tauri-apps/cli-win32-ia32-msvc': 2.10.1
|
||||||
'@tauri-apps/cli-win32-x64-msvc': 2.10.1
|
'@tauri-apps/cli-win32-x64-msvc': 2.10.1
|
||||||
|
|
||||||
|
'@tauri-apps/plugin-os@2.3.2':
|
||||||
|
dependencies:
|
||||||
|
'@tauri-apps/api': 2.10.1
|
||||||
|
|
||||||
'@tauri-apps/plugin-shell@2.3.5':
|
'@tauri-apps/plugin-shell@2.3.5':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@tauri-apps/api': 2.10.1
|
'@tauri-apps/api': 2.10.1
|
||||||
|
|||||||
Generated
+95
@@ -1107,6 +1107,16 @@ dependencies = [
|
|||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gethostname"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
|
||||||
|
dependencies = [
|
||||||
|
"rustix",
|
||||||
|
"windows-link 0.2.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.1.16"
|
version = "0.1.16"
|
||||||
@@ -1998,6 +2008,7 @@ dependencies = [
|
|||||||
"tauri",
|
"tauri",
|
||||||
"tauri-build",
|
"tauri-build",
|
||||||
"tauri-plugin-http",
|
"tauri-plugin-http",
|
||||||
|
"tauri-plugin-os",
|
||||||
"tauri-plugin-process",
|
"tauri-plugin-process",
|
||||||
"tauri-plugin-shell",
|
"tauri-plugin-shell",
|
||||||
"tauri-plugin-updater",
|
"tauri-plugin-updater",
|
||||||
@@ -2061,6 +2072,18 @@ version = "1.0.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.30.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.11.0",
|
||||||
|
"cfg-if",
|
||||||
|
"cfg_aliases",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nodrop"
|
name = "nodrop"
|
||||||
version = "0.1.14"
|
version = "0.1.14"
|
||||||
@@ -2200,6 +2223,16 @@ dependencies = [
|
|||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-core-location"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ca347214e24bc973fc025fd0d36ebb179ff30536ed1f80252706db19ee452009"
|
||||||
|
dependencies = [
|
||||||
|
"objc2",
|
||||||
|
"objc2-foundation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2-core-text"
|
name = "objc2-core-text"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
@@ -2316,8 +2349,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
|
checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.0",
|
||||||
|
"block2",
|
||||||
"objc2",
|
"objc2",
|
||||||
|
"objc2-cloud-kit",
|
||||||
|
"objc2-core-data",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
|
"objc2-core-graphics",
|
||||||
|
"objc2-core-image",
|
||||||
|
"objc2-core-location",
|
||||||
|
"objc2-core-text",
|
||||||
|
"objc2-foundation",
|
||||||
|
"objc2-quartz-core",
|
||||||
|
"objc2-user-notifications",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-user-notifications"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9df9128cbbfef73cda168416ccf7f837b62737d748333bfe9ab71c245d76613e"
|
||||||
|
dependencies = [
|
||||||
|
"objc2",
|
||||||
"objc2-foundation",
|
"objc2-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2367,6 +2419,22 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_info"
|
||||||
|
version = "3.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e4022a17595a00d6a369236fdae483f0de7f0a339960a53118b818238e132224"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"log",
|
||||||
|
"nix",
|
||||||
|
"objc2",
|
||||||
|
"objc2-foundation",
|
||||||
|
"objc2-ui-kit",
|
||||||
|
"serde",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_pipe"
|
name = "os_pipe"
|
||||||
version = "1.2.3"
|
version = "1.2.3"
|
||||||
@@ -3806,6 +3874,15 @@ dependencies = [
|
|||||||
"syn 2.0.117",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sys-locale"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sysinfo"
|
name = "sysinfo"
|
||||||
version = "0.32.1"
|
version = "0.32.1"
|
||||||
@@ -4099,6 +4176,24 @@ dependencies = [
|
|||||||
"urlpattern",
|
"urlpattern",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-plugin-os"
|
||||||
|
version = "2.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8f08346c8deb39e96f86973da0e2d76cbb933d7ac9b750f6dc4daf955a6f997"
|
||||||
|
dependencies = [
|
||||||
|
"gethostname",
|
||||||
|
"log",
|
||||||
|
"os_info",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serialize-to-javascript",
|
||||||
|
"sys-locale",
|
||||||
|
"tauri",
|
||||||
|
"tauri-plugin",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-plugin-process"
|
name = "tauri-plugin-process"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ serde_json = "1"
|
|||||||
walkdir = "2"
|
walkdir = "2"
|
||||||
sysinfo = "0.32"
|
sysinfo = "0.32"
|
||||||
dirs = "5"
|
dirs = "5"
|
||||||
|
tauri-plugin-os = "2.3.2"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|||||||
@@ -549,6 +549,7 @@ fn restart_app(app: tauri::AppHandle) {
|
|||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
|
.plugin(tauri_plugin_os::init())
|
||||||
.plugin(tauri_plugin_shell::init())
|
.plugin(tauri_plugin_shell::init())
|
||||||
.plugin(tauri_plugin_http::init())
|
.plugin(tauri_plugin_http::init())
|
||||||
.plugin(tauri_plugin_process::init())
|
.plugin(tauri_plugin_process::init())
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
"minHeight": 600,
|
"minHeight": 600,
|
||||||
"resizable": true,
|
"resizable": true,
|
||||||
"fullscreen": false,
|
"fullscreen": false,
|
||||||
"decorations": false,
|
"decorations": true,
|
||||||
"center": true
|
"center": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,4 +1,13 @@
|
|||||||
{
|
{
|
||||||
|
"app": {
|
||||||
|
"windows": [
|
||||||
|
{
|
||||||
|
"decorations": true,
|
||||||
|
"titleBarStyle": "overlay",
|
||||||
|
"hiddenTitle": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"bundle": {
|
"bundle": {
|
||||||
"targets": ["dmg"],
|
"targets": ["dmg"],
|
||||||
"externalBin": [
|
"externalBin": [
|
||||||
|
|||||||
+13
-1
@@ -3,6 +3,7 @@
|
|||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
import { listen } from "@tauri-apps/api/event";
|
import { listen } from "@tauri-apps/api/event";
|
||||||
import { getVersion } from "@tauri-apps/api/app";
|
import { getVersion } from "@tauri-apps/api/app";
|
||||||
|
import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||||
import { gql } from "./lib/client";
|
import { gql } from "./lib/client";
|
||||||
import { GET_DOWNLOAD_STATUS } from "./lib/queries";
|
import { GET_DOWNLOAD_STATUS } from "./lib/queries";
|
||||||
import { store, addToast, setActiveDownloads, setSettingsOpen } from "./store/state.svelte";
|
import { store, addToast, setActiveDownloads, setSettingsOpen } from "./store/state.svelte";
|
||||||
@@ -16,6 +17,7 @@
|
|||||||
import MangaPreview from "./components/shared/MangaPreview.svelte";
|
import MangaPreview from "./components/shared/MangaPreview.svelte";
|
||||||
|
|
||||||
const MAX_ATTEMPTS = 60;
|
const MAX_ATTEMPTS = 60;
|
||||||
|
const win = getCurrentWindow();
|
||||||
|
|
||||||
let serverProbeOk = $state(!store.settings.autoStartServer);
|
let serverProbeOk = $state(!store.settings.autoStartServer);
|
||||||
let appReady = $state(!store.settings.autoStartServer);
|
let appReady = $state(!store.settings.autoStartServer);
|
||||||
@@ -147,6 +149,15 @@
|
|||||||
platformScale = await invoke<number>("get_platform_ui_scale").catch(() => 1);
|
platformScale = await invoke<number>("get_platform_ui_scale").catch(() => 1);
|
||||||
applyZoom();
|
applyZoom();
|
||||||
|
|
||||||
|
// ── Fullscreen state sync ─────────────────────────────────────────────────
|
||||||
|
// Seed the initial state, then keep it in sync on every resize event.
|
||||||
|
// onResized is the correct Tauri 2 API — it fires on fullscreen enter/exit,
|
||||||
|
// window snap, and manual resize. isFullscreen() is cheap (single IPC call).
|
||||||
|
store.isFullscreen = await win.isFullscreen();
|
||||||
|
const unlistenResize = await win.onResized(async () => {
|
||||||
|
store.isFullscreen = await win.isFullscreen();
|
||||||
|
});
|
||||||
|
|
||||||
if (store.settings.autoStartServer) {
|
if (store.settings.autoStartServer) {
|
||||||
invoke<void>("spawn_server", { binary: store.settings.serverBinary }).catch((err: any) => {
|
invoke<void>("spawn_server", { binary: store.settings.serverBinary }).catch((err: any) => {
|
||||||
if (err?.kind === "NotConfigured") {
|
if (err?.kind === "NotConfigured") {
|
||||||
@@ -181,6 +192,7 @@
|
|||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
|
unlistenResize();
|
||||||
if (store.settings.autoStartServer) invoke("kill_server").catch(() => {});
|
if (store.settings.autoStartServer) invoke("kill_server").catch(() => {});
|
||||||
if (idleTimer) clearTimeout(idleTimer);
|
if (idleTimer) clearTimeout(idleTimer);
|
||||||
if (pollInterval) clearInterval(pollInterval);
|
if (pollInterval) clearInterval(pollInterval);
|
||||||
@@ -215,7 +227,7 @@
|
|||||||
<SplashScreen mode="idle" showCards={store.settings.splashCards ?? true}
|
<SplashScreen mode="idle" showCards={store.settings.splashCards ?? true}
|
||||||
onDismiss={() => setTimeout(() => idle = false, 340)} />
|
onDismiss={() => setTimeout(() => idle = false, 340)} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if !store.activeChapter}<TitleBar />{/if}
|
{#if !store.activeChapter && !store.isFullscreen}<TitleBar />{/if}
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{#if store.activeChapter}<Reader />{:else}<Layout />{/if}
|
{#if store.activeChapter}<Reader />{:else}<Layout />{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,10 +1,27 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { onMount } from "svelte";
|
||||||
import { getCurrentWindow } from "@tauri-apps/api/window";
|
import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||||
|
import { platform } from "@tauri-apps/plugin-os";
|
||||||
|
|
||||||
const win = getCurrentWindow();
|
const win = getCurrentWindow();
|
||||||
|
const isMac = platform() === "macos";
|
||||||
|
|
||||||
|
let isFullscreen = $state(false);
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
isFullscreen = await win.isFullscreen();
|
||||||
|
const unlisten = await win.onResized(async () => {
|
||||||
|
isFullscreen = await win.isFullscreen();
|
||||||
|
});
|
||||||
|
return unlisten;
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{#if !isFullscreen}
|
||||||
<div class="bar" data-tauri-drag-region>
|
<div class="bar" data-tauri-drag-region>
|
||||||
|
{#if isMac}<div class="mac-spacer"></div>{/if}
|
||||||
<span class="title" data-tauri-drag-region>Moku</span>
|
<span class="title" data-tauri-drag-region>Moku</span>
|
||||||
|
{#if !isMac}
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<button onclick={() => win.minimize()} title="Minimize" aria-label="Minimize">
|
<button onclick={() => win.minimize()} title="Minimize" aria-label="Minimize">
|
||||||
<svg width="10" height="1" viewBox="0 0 10 1">
|
<svg width="10" height="1" viewBox="0 0 10 1">
|
||||||
@@ -23,7 +40,9 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.bar {
|
.bar {
|
||||||
@@ -38,6 +57,12 @@
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-app-region: drag;
|
-webkit-app-region: drag;
|
||||||
}
|
}
|
||||||
|
/* Spacer to clear the native macOS traffic lights (~70px) */
|
||||||
|
.mac-spacer {
|
||||||
|
width: 70px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
-webkit-app-region: drag;
|
||||||
|
}
|
||||||
.title {
|
.title {
|
||||||
font-family: var(--font-ui);
|
font-family: var(--font-ui);
|
||||||
font-size: var(--text-2xs);
|
font-size: var(--text-2xs);
|
||||||
|
|||||||
@@ -115,6 +115,9 @@
|
|||||||
let abortCtrl: AbortController | null = null;
|
let abortCtrl: AbortController | null = null;
|
||||||
let loadingId: number | null = null;
|
let loadingId: number | null = null;
|
||||||
let navToken = 0;
|
let navToken = 0;
|
||||||
|
// Only write history after the user has genuinely moved past the opening page.
|
||||||
|
// Prevents the "started on page 1" entry being saved as last position on close.
|
||||||
|
let hasNavigated = false;
|
||||||
|
|
||||||
// ─── Derived ──────────────────────────────────────────────────────────────────
|
// ─── Derived ──────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -190,6 +193,7 @@
|
|||||||
navToken++;
|
navToken++;
|
||||||
appending = false;
|
appending = false;
|
||||||
markedRead = new Set();
|
markedRead = new Set();
|
||||||
|
hasNavigated = false;
|
||||||
loading = true;
|
loading = true;
|
||||||
error = null;
|
error = null;
|
||||||
pageGroups = [];
|
pageGroups = [];
|
||||||
@@ -394,17 +398,33 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ─── Progress / history tracking ─────────────────────────────────────────────
|
// ─── Progress / history tracking ─────────────────────────────────────────────
|
||||||
|
// Only records history after the user has genuinely navigated (pageNumber > 1,
|
||||||
|
// or scrolled past page 1 in longstrip). This prevents the chapter-open event
|
||||||
|
// from writing "page 1" as the last-read position, which caused the history to
|
||||||
|
// always show the chapter you started on rather than where you left off.
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (store.activeChapter && lastPage && store.activeManga) {
|
// Use displayChapter, not store.activeChapter — in longstrip with autoNext,
|
||||||
const chapterId = store.activeChapter.id;
|
// store.activeChapter stays as the chapter you *opened* (e.g. ch61) while
|
||||||
const chapterName = store.activeChapter.name;
|
// displayChapter tracks visibleChapterId (the chapter actually on screen).
|
||||||
|
// Using store.activeChapter here caused every history write to stamp ch61
|
||||||
|
// even when the user had scrolled all the way to ch72.
|
||||||
|
const ch = displayChapter ?? store.activeChapter;
|
||||||
|
if (ch && lastPage && store.activeManga) {
|
||||||
|
const chapterId = ch.id;
|
||||||
|
const chapterName = ch.name;
|
||||||
const mangaId = store.activeManga.id;
|
const mangaId = store.activeManga.id;
|
||||||
const mangaTitle = store.activeManga.title;
|
const mangaTitle = store.activeManga.title;
|
||||||
const thumb = store.activeManga.thumbnailUrl;
|
const thumb = store.activeManga.thumbnailUrl;
|
||||||
const pageNum = store.pageNumber;
|
const pageNum = store.pageNumber;
|
||||||
const atLast = store.pageNumber === lastPage;
|
const atLast = store.pageNumber === lastPage;
|
||||||
|
|
||||||
|
// Mark that the user has moved past the initial load.
|
||||||
|
if (pageNum > 1) hasNavigated = true;
|
||||||
|
|
||||||
untrack(() => {
|
untrack(() => {
|
||||||
|
// Skip the very first page-1 write that fires on chapter load.
|
||||||
|
if (!hasNavigated) return;
|
||||||
addHistory({ mangaId, mangaTitle, thumbnailUrl: thumb, chapterId, chapterName, pageNumber: pageNum, readAt: Date.now() });
|
addHistory({ mangaId, mangaTitle, thumbnailUrl: thumb, chapterId, chapterName, pageNumber: pageNum, readAt: Date.now() });
|
||||||
if (style !== "longstrip" && store.settings.autoMarkRead && atLast) markChapterRead(chapterId);
|
if (style !== "longstrip" && store.settings.autoMarkRead && atLast) markChapterRead(chapterId);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -272,6 +272,8 @@ class Store {
|
|||||||
toasts: Toast[] = $state([]);
|
toasts: Toast[] = $state([]);
|
||||||
activeChapter: Chapter | null = $state(null);
|
activeChapter: Chapter | null = $state(null);
|
||||||
activeChapterList: Chapter[] = $state([]);
|
activeChapterList: Chapter[] = $state([]);
|
||||||
|
// UI-only: synced from Tauri window events in App.svelte. Not persisted.
|
||||||
|
isFullscreen: boolean = $state(false);
|
||||||
|
|
||||||
// ── Discover session cache ────────────────────────────────────────────────
|
// ── Discover session cache ────────────────────────────────────────────────
|
||||||
// Survives navigation within a session but is never persisted to localStorage.
|
// Survives navigation within a session but is never persisted to localStorage.
|
||||||
@@ -300,6 +302,9 @@ class Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
closeReader() {
|
closeReader() {
|
||||||
|
// Null activeChapter FIRST so the history $effect in Reader can't fire
|
||||||
|
// one last time with stale chapter + pageNumber=1, overwriting the real
|
||||||
|
// last-read position with page 1.
|
||||||
this.activeChapter = null;
|
this.activeChapter = null;
|
||||||
this.activeChapterList = [];
|
this.activeChapterList = [];
|
||||||
this.pageUrls = [];
|
this.pageUrls = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user