fix: 进度持久化与断点恢复 + VoiceInput 权限/异常加固 + Jev 故障优雅降级

This commit is contained in:
Jayway Liu
2026-10-03 18:30:36 +08:00
parent b0c7ef2daf
commit e854b4e610
6 changed files with 258 additions and 31 deletions
+10 -4
View File
@@ -2,6 +2,7 @@ import { useEffect, useMemo, useState } from 'react';
import './App.css';
import { StoryEngine } from './engine/engine';
import { LocalStorageEventStore } from './engine/eventStore';
import { LocalStorageProgressStore } from './engine/progress';
import { SqliteEventStore, isTauriRuntime } from './engine/sqliteEventStore';
import type { Chapter } from './engine/types';
import { getJevClient } from './services/jev';
@@ -20,15 +21,20 @@ export default function App() {
const [consent, setConsent] = useState<'unknown' | 'needed' | 'granted'>('unknown');
// 引擎与存储整个会话只建一次;重玩走 engine.replay()(新 sessionId,旧事件保留)
// 运行时选择:Tauri 原生端用 SQLite,浏览器 dev 用 localStorage(同一 append-only 接口)
const { engine, store, jev } = useMemo(() => {
const { engine, store, jev, progress } = useMemo(() => {
const store = isTauriRuntime() ? new SqliteEventStore() : new LocalStorageEventStore();
const jev = getJevClient();
return { engine: new StoryEngine(chapters, store, jev), store, jev };
const progress = new LocalStorageProgressStore();
return { engine: new StoryEngine(chapters, store, jev, undefined, progress), store, jev, progress };
}, []);
useEffect(() => {
void engine.hasConsent().then((ok) => setConsent(ok ? 'granted' : 'needed'));
}, [engine]);
void engine.hasConsent().then((ok) => {
// 同意门之后才恢复剧情进度(刷新/热更新前的断点)
if (ok) engine.restore(progress.load());
setConsent(ok ? 'granted' : 'needed');
});
}, [engine, progress]);
if (consent !== 'granted') {
return (