Skip to content

Commit 0db0194

Browse files
committed
Improve:路径相关处理始终调用FileManager API避免书签文件夹失效
1 parent 780a61e commit 0db0194

12 files changed

Lines changed: 301 additions & 105 deletions

File tree

Rime-Wanxiang-Updater/components/HomeView.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export function HomeView() {
9393
}
9494

9595
function checkKey(c: AppConfig) {
96-
return [c.releaseSource, c.schemeEdition, c.proSchemeKey, c.hamsterRootPath].join("|")
96+
return [c.releaseSource, c.schemeEdition, c.proSchemeKey, c.hamsterRootPath, c.hamsterBookmarkName].join("|")
9797
}
9898

9999
async function refreshLocal(current: AppConfig) {
@@ -121,6 +121,13 @@ export function HomeView() {
121121

122122
try {
123123
const fm: any = (globalThis as any).FileManager
124+
if (fm?.bookmarkedPath && (current.hamsterBookmarkName || current.hamsterRootPath)) {
125+
if (current.hamsterBookmarkName) {
126+
const p = fm.bookmarkedPath(current.hamsterBookmarkName)
127+
const resolved = p && typeof p.then === "function" ? await p : p
128+
if (resolved) candidates.unshift(String(resolved))
129+
}
130+
}
124131
if (fm?.getAllFileBookmarks && fm?.bookmarkedPath && current.hamsterRootPath) {
125132
const r = fm.getAllFileBookmarks()
126133
const list = r && typeof r.then === "function" ? await r : r
@@ -130,7 +137,7 @@ export function HomeView() {
130137
const match = arr.find((b: any) => {
131138
const p = norm(String(b?.path ?? ""))
132139
const n = String(b?.name ?? "")
133-
return (p && p === target) || (n && n === current.hamsterRootPath)
140+
return (p && p === target) || (current.hamsterBookmarkName ? n === current.hamsterBookmarkName : false)
134141
})
135142
if (match?.name) {
136143
const p = fm.bookmarkedPath(match.name)
@@ -166,7 +173,7 @@ export function HomeView() {
166173
const current = loadConfig()
167174
setCfg(current)
168175
void refreshLocal(current)
169-
}, [cfg.schemeEdition, cfg.proSchemeKey, cfg.releaseSource, cfg.hamsterRootPath])
176+
}, [cfg.schemeEdition, cfg.proSchemeKey, cfg.releaseSource, cfg.hamsterRootPath, cfg.hamsterBookmarkName])
170177

171178
useEffect(() => {
172179
const current = loadConfig()

Rime-Wanxiang-Updater/components/SettingsView.tsx

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,19 @@ const INPUT_METHODS: { label: string; value: InputMethod }[] = [
4343
{ label: "元书输入法", value: "hamster3" },
4444
]
4545

46+
function isPromiseLike(v: any): v is Promise<any> {
47+
return !!v && typeof v === "object" && typeof v.then === "function"
48+
}
49+
50+
async function callMaybeAsync(fn: any, thisArg: any, args: any[]) {
51+
try {
52+
const r = fn.apply(thisArg, args)
53+
return isPromiseLike(r) ? await r : r
54+
} catch {
55+
return undefined
56+
}
57+
}
58+
4659
function CenterRowButton(props: {
4760
title: string
4861
role?: "cancel" | "destructive"
@@ -85,6 +98,7 @@ export function SettingsView(props: {
8598
const initialSchemeEdition = initialCfg.schemeEdition
8699
const initialProSchemeKey = initialCfg.proSchemeKey
87100
const initialHamsterRootPath = initialCfg.hamsterRootPath
101+
const initialHamsterBookmarkName = initialCfg.hamsterBookmarkName
88102
const [cfg, setCfg] = useState<AppConfig>(initialCfg)
89103

90104
// ✅ 用 number 承载 Picker 值(与你示例一致)
@@ -174,12 +188,33 @@ export function SettingsView(props: {
174188
.filter((x: any) => x.name && x.path)
175189
setBookmarks(cleaned)
176190

177-
const target = current?.hamsterRootPath ?? cfg.hamsterRootPath
191+
const targetName = current?.hamsterBookmarkName ?? cfg.hamsterBookmarkName
192+
const targetPath = current?.hamsterRootPath ?? cfg.hamsterRootPath
178193
if (cleaned.length) {
179-
const idx = cleaned.findIndex((b) => b.path === target)
194+
let idx = -1
195+
if (targetName) idx = cleaned.findIndex((b) => b.name === targetName)
196+
if (idx < 0 && targetPath) idx = cleaned.findIndex((b) => b.path === targetPath)
180197
setBookmarkIdx(idx >= 0 ? idx : 0)
181-
if (idx < 0 && !target) {
182-
setCfg((c) => ({ ...c, hamsterRootPath: cleaned[0].path }))
198+
if (idx >= 0) {
199+
const matched = cleaned[idx]
200+
const resolved = fm?.bookmarkedPath
201+
? String((await callMaybeAsync(fm.bookmarkedPath, fm, [matched.name])) ?? matched.path)
202+
: matched.path
203+
const pathChanged = resolved !== targetPath || matched.name !== targetName
204+
if (pathChanged) {
205+
setCfg((c) => ({ ...c, hamsterRootPath: resolved, hamsterBookmarkName: matched.name }))
206+
try {
207+
const next = { ...loadConfig(), hamsterRootPath: resolved, hamsterBookmarkName: matched.name }
208+
saveConfig(next)
209+
props.onDone?.(next)
210+
} catch {}
211+
}
212+
} else if (!targetPath) {
213+
setCfg((c) => ({
214+
...c,
215+
hamsterRootPath: cleaned[0].path,
216+
hamsterBookmarkName: cleaned[0].name,
217+
}))
183218
}
184219
} else {
185220
setBookmarkIdx(0)
@@ -212,7 +247,9 @@ export function SettingsView(props: {
212247
const schemeChanged =
213248
fixed.schemeEdition !== initialSchemeEdition ||
214249
(fixed.schemeEdition === "pro" && fixed.proSchemeKey !== initialProSchemeKey)
215-
const pathChanged = fixed.hamsterRootPath !== initialHamsterRootPath
250+
const pathChanged =
251+
fixed.hamsterRootPath !== initialHamsterRootPath ||
252+
fixed.hamsterBookmarkName !== initialHamsterBookmarkName
216253
if (schemeChanged && !pathChanged) {
217254
try {
218255
const { rimeDir } = await detectRimeDir(fixed)
@@ -252,7 +289,7 @@ export function SettingsView(props: {
252289
<TextField
253290
label={<Text>路径</Text>}
254291
value={cfg.hamsterRootPath}
255-
onChanged={(v: string) => setCfg((c) => ({ ...c, hamsterRootPath: v }))}
292+
onChanged={(v: string) => setCfg((c) => ({ ...c, hamsterRootPath: v, hamsterBookmarkName: "" }))}
256293
prompt="粘贴或选择 Hamster 根目录"
257294
textFieldStyle="roundedBorder"
258295
/>
@@ -269,12 +306,22 @@ export function SettingsView(props: {
269306
setBookmarkIdx(idx)
270307
const b = bookmarks[idx]
271308
if (b?.path) {
272-
const next: AppConfig = { ...cfg, hamsterRootPath: b.path }
273-
setCfg(next)
274-
try {
275-
saveConfig(next)
276-
props.onDone?.(next)
277-
} catch {}
309+
;(async () => {
310+
const fm: any = (globalThis as any).FileManager ?? Runtime.FileManager
311+
const resolved = fm?.bookmarkedPath
312+
? String((await callMaybeAsync(fm.bookmarkedPath, fm, [b.name])) ?? b.path)
313+
: b.path
314+
const next: AppConfig = {
315+
...cfg,
316+
hamsterRootPath: resolved,
317+
hamsterBookmarkName: b.name,
318+
}
319+
setCfg(next)
320+
try {
321+
saveConfig(next)
322+
props.onDone?.(next)
323+
} catch {}
324+
})()
278325
}
279326
}}
280327
>
Lines changed: 35 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,31 @@
11
// File: utils/config.ts
2-
import { Runtime } from "./runtime";
2+
import { Runtime } from "./runtime"
33

4-
export type ReleaseSource = "cnb" | "github";
5-
export type SchemeEdition = "base" | "pro";
6-
export type ProSchemeKey =
7-
| "moqi"
8-
| "flypy"
9-
| "zrm"
10-
| "tiger"
11-
| "wubi"
12-
| "hanxin"
13-
| "shouyou";
14-
export type InputMethod = "hamster" | "hamster3";
4+
export type ReleaseSource = "cnb" | "github"
5+
export type SchemeEdition = "base" | "pro"
6+
export type ProSchemeKey = "moqi" | "flypy" | "zrm" | "tiger" | "wubi" | "hanxin" | "shouyou"
7+
export type InputMethod = "hamster" | "hamster3"
158

169
export type AppConfig = {
17-
hamsterRootPath: string;
18-
releaseSource: ReleaseSource;
19-
githubToken: string;
10+
hamsterRootPath: string
11+
hamsterBookmarkName: string
12+
releaseSource: ReleaseSource
13+
githubToken: string
2014

21-
schemeEdition: SchemeEdition;
22-
proSchemeKey: ProSchemeKey;
15+
schemeEdition: SchemeEdition
16+
proSchemeKey: ProSchemeKey
2317

24-
excludePatternsText: string; // 按行
25-
autoDeployAfterDownload: boolean;
26-
inputMethod: InputMethod;
27-
autoCheckOnLaunch: boolean;
28-
};
18+
excludePatternsText: string // 按行
19+
autoDeployAfterDownload: boolean
20+
inputMethod: InputMethod
21+
autoCheckOnLaunch: boolean
22+
}
2923

30-
const KEY = "wanxiang_updater_cfg_v2";
24+
const KEY = "wanxiang_updater_cfg_v2"
3125

3226
export const DEFAULT_CONFIG: AppConfig = {
3327
hamsterRootPath: "",
28+
hamsterBookmarkName: "",
3429
releaseSource: "cnb",
3530
githubToken: "",
3631
schemeEdition: "base",
@@ -39,37 +34,34 @@ export const DEFAULT_CONFIG: AppConfig = {
3934
autoDeployAfterDownload: true,
4035
inputMethod: "hamster",
4136
autoCheckOnLaunch: false,
42-
};
37+
}
4338

4439
export function loadConfig(): AppConfig {
45-
const st: any = (globalThis as any).Storage ?? (Runtime as any);
40+
const st: any = (globalThis as any).Storage ?? Runtime as any
4641
try {
47-
const raw = st?.get?.(KEY) ?? st?.getString?.(KEY);
48-
if (!raw) return DEFAULT_CONFIG;
49-
const obj = JSON.parse(raw);
50-
if (obj?.inputMethod === "cang") obj.inputMethod = "hamster";
51-
if (obj?.inputMethod === "yushu" || obj?.inputMethod === "yuanshu")
52-
obj.inputMethod = "hamster3";
53-
return { ...DEFAULT_CONFIG, ...obj };
42+
const raw = st?.get?.(KEY) ?? st?.getString?.(KEY)
43+
if (!raw) return DEFAULT_CONFIG
44+
const obj = JSON.parse(raw)
45+
if (obj?.inputMethod === "cang") obj.inputMethod = "hamster"
46+
if (obj?.inputMethod === "yushu" || obj?.inputMethod === "yuanshu") obj.inputMethod = "hamster3"
47+
if (typeof obj?.hamsterBookmarkName !== "string") obj.hamsterBookmarkName = ""
48+
return { ...DEFAULT_CONFIG, ...obj }
5449
} catch {
55-
return DEFAULT_CONFIG;
50+
return DEFAULT_CONFIG
5651
}
5752
}
5853

5954
export function saveConfig(cfg: AppConfig) {
60-
const st: any = (globalThis as any).Storage ?? (Runtime as any);
61-
const raw = JSON.stringify(cfg);
62-
if (st?.set) st.set(KEY, raw);
63-
else if (st?.setString) st.setString(KEY, raw);
64-
else
65-
throw new Error(
66-
"Storage API 不存在:请确认 Scripting 是否提供 Storage.set/get",
67-
);
55+
const st: any = (globalThis as any).Storage ?? Runtime as any
56+
const raw = JSON.stringify(cfg)
57+
if (st?.set) st.set(KEY, raw)
58+
else if (st?.setString) st.setString(KEY, raw)
59+
else throw new Error("Storage API 不存在:请确认 Scripting 是否提供 Storage.set/get")
6860
}
6961

7062
export function getExcludePatterns(cfg: AppConfig): string[] {
7163
return cfg.excludePatternsText
7264
.split(/\r?\n/g)
73-
.map((s) => s.trim())
74-
.filter(Boolean);
65+
.map(s => s.trim())
66+
.filter(Boolean)
7567
}

Rime-Wanxiang-Updater/utils/downloader.tsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ export type DownloadProgress = {
66
speedBps?: number
77
}
88

9+
export type DownloadStateEvent =
10+
| {
11+
type: "retrying"
12+
attempt: number
13+
maxAttempts: number
14+
}
15+
916
declare const BackgroundURLSession: any
1017

1118
const LARGE_FALLBACK_BYTES = 50 * 1024 * 1024
@@ -301,15 +308,17 @@ function readBytes(task: any): { received?: number; total?: number } {
301308
export async function downloadWithProgress(
302309
url: string,
303310
dstPath: string,
304-
onProgress?: (p: DownloadProgress) => void
311+
onProgress?: (p: DownloadProgress) => void,
312+
onState?: (e: DownloadStateEvent) => void
305313
) {
306-
return downloadWithProgressInternal(url, dstPath, onProgress, 0)
314+
return downloadWithProgressInternal(url, dstPath, onProgress, onState, 0)
307315
}
308316

309317
async function downloadWithProgressInternal(
310318
url: string,
311319
dstPath: string,
312320
onProgress: ((p: DownloadProgress) => void) | undefined,
321+
onState: ((e: DownloadStateEvent) => void) | undefined,
313322
attempt: number
314323
) {
315324
if (!BackgroundURLSession || typeof BackgroundURLSession.startDownload !== "function") {
@@ -438,8 +447,13 @@ async function downloadWithProgressInternal(
438447
if (Date.now() - lastProgressAt > STALL_TIMEOUT_MS) {
439448
cancelTask(task)
440449
if (attempt < MAX_RETRY) {
450+
onState?.({
451+
type: "retrying",
452+
attempt: attempt + 2,
453+
maxAttempts: MAX_RETRY + 1,
454+
})
441455
await removeFileLoose(dstPath)
442-
return downloadWithProgressInternal(url, dstPath, onProgress, attempt + 1)
456+
return downloadWithProgressInternal(url, dstPath, onProgress, onState, attempt + 1)
443457
}
444458
throw new Error("下载超时:进度长时间无变化")
445459
}

Rime-Wanxiang-Updater/utils/hamster.tsx

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,43 @@ async function callMaybeAsync(fn: any, thisArg: any, args: any[]) {
1515
}
1616
}
1717

18-
async function resolveBookmarkPath(rawPath: string): Promise<string> {
18+
async function resolveBookmarkPath(rawPath: string, bookmarkName?: string): Promise<string> {
1919
const fm = Runtime.FileManager
20-
if (!rawPath) return ""
21-
if (!fm?.getAllFileBookmarks || !fm?.bookmarkedPath) return rawPath
20+
const raw = String(rawPath ?? "").trim()
21+
const name = String(bookmarkName ?? "").trim()
22+
if (!fm?.bookmarkedPath) return raw
23+
try {
24+
if (name) {
25+
const resolvedByName = await callMaybeAsync(fm.bookmarkedPath, fm, [name])
26+
if (resolvedByName) return String(resolvedByName)
27+
}
28+
} catch {}
29+
if (!fm?.getAllFileBookmarks) return raw
2230
try {
2331
const list = await callMaybeAsync(fm.getAllFileBookmarks, fm, [])
2432
const arr = Array.isArray(list) ? list : []
2533
const norm = (s: string) => s.replace(/\/+$/, "")
26-
const target = norm(String(rawPath))
34+
const target = norm(raw)
2735
const match = arr.find((b: any) => {
2836
const p = norm(String(b?.path ?? ""))
2937
const n = String(b?.name ?? "")
30-
return (p && p === target) || (n && n === rawPath)
38+
return (name && n === name) || (target && p && p === target)
3139
})
3240
if (match?.name) {
3341
const resolved = await callMaybeAsync(fm.bookmarkedPath, fm, [match.name])
3442
if (resolved) return String(resolved)
43+
if (match?.path) return String(match.path)
3544
}
3645
} catch {}
37-
return rawPath
46+
return raw
3847
}
3948

4049
// 这里按你之前的逻辑:从 hamsterRootPath 推断实际 rime 目录
4150
export async function detectRimeDir(cfg: AppConfig): Promise<{ engine: "仓输入法" | "元书输入法"; rimeDir: string }> {
4251
const fm = Runtime.FileManager
4352
const rawRoot = cfg.hamsterRootPath?.trim()
44-
const root = rawRoot ? await resolveBookmarkPath(rawRoot) : ""
53+
const bookmarkName = cfg.hamsterBookmarkName?.trim()
54+
const root = await resolveBookmarkPath(rawRoot, bookmarkName)
4555
if (!root) return { engine: "仓输入法", rimeDir: "" }
4656
if (!fm?.exists) return { engine: "仓输入法", rimeDir: root }
4757

0 commit comments

Comments
 (0)