dsh-folia 3.6.0 → 3.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -16274,35 +16274,61 @@ window.__ModuleLoader__.load({
16274
16274
 
16275
16275
  React.useEffect(() => { load(false); }, [load]);
16276
16276
 
16277
- // ── 「应用」= 写 active + 刷新页面 ─────────────────────────────────────────
16278
- // 皮肤中心**只在页面加载时**应用皮肤,而它的控制器没有导出(0.4.8 与 0.4.11 都
16279
- // 没有全局句柄 / activate API / 文件监听)。所以让用户"点一下就出效果"的唯一
16280
- // 可行做法,是让页面重新加载一次,触发它的 boot。
16281
- //
16282
- // 用 sessionStorage 留时间戳标记:页面确实重载了,标记就还在(同一标签页会话内
16283
- // 有效)—— 据此判断"刷新到底发生了没有",而不是靠猜。刷新被桌面壳吞掉时,
16284
- // 标记留在原地,4 秒后给出明确的兜底提示。
16285
- React.useEffect(() => {
16286
- try {
16287
- const raw = sessionStorage.getItem("folia.applyPending");
16288
- if (!raw) return;
16289
- sessionStorage.removeItem("folia.applyPending");
16290
- const o = JSON.parse(raw);
16291
- if (o && Date.now() - Number(o.at || 0) < 20000) {
16277
+ // 轮询验证的清理(组件卸载/重新选中时别留下定时器)。
16278
+ const pollRef = React.useRef(null);
16279
+ React.useEffect(() => () => {
16280
+ if (pollRef.current !== null) { clearInterval(pollRef.current); pollRef.current = null; }
16281
+ }, []);
16282
+
16283
+ /**
16284
+ * 写 active 之后**验证皮肤中心有没有真的应用**。
16285
+ *
16286
+ * 为什么不需要刷新页面:皮肤中心的客户端运行时自带轮询 ——
16287
+ *
16288
+ * const SELECTION_POLL_MS = 2e3;
16289
+ * function watchPersistedSelection(store, intervalMs = SELECTION_POLL_MS) {
16290
+ * const tick = async () => {
16291
+ * const next = await readPersistedSelection(store); // GET /api/skin-center/v2/active
16292
+ * if (next === undefined || next === applied) return;
16293
+ * applied = next;
16294
+ * await convergeOnSelection(store, next); // ← 自动应用
16295
+ * };
16296
+ * store.window.setInterval(tick, intervalMs); // 注意是 store.window.setInterval
16297
+ * }
16298
+ *
16299
+ * 那个 `/active` 读的就是我们刚写的 `skin-center-active.json`。所以写完之后它会在
16300
+ * 2 秒内自己收敛过去 —— 之前"必须刷新"的假象,是我们自己的热注入在覆盖它的结果。
16301
+ *
16302
+ * 它的收敛成功标志很明确:`<html data-dsh-skin="<id>">`。我们就盯这个属性:
16303
+ * 出现了 = 真的应用了;5 次(约 6 秒)还没出现 = 没应用,如实说。
16304
+ */
16305
+ function verifyApplied(id, label) {
16306
+ if (pollRef.current !== null) { clearInterval(pollRef.current); pollRef.current = null; }
16307
+ let tries = 0;
16308
+ pollRef.current = setInterval(() => {
16309
+ tries += 1;
16310
+ let stamped = null;
16311
+ try { stamped = document.documentElement.getAttribute("data-dsh-skin"); } catch { stamped = null; }
16312
+ if (stamped === id) {
16313
+ clearInterval(pollRef.current); pollRef.current = null;
16314
+ setNote({ kind: "ok", text: weT("已应用:「") + label + weT("」—— 皮肤中心已收敛(无需刷新)") });
16315
+ return;
16316
+ }
16317
+ if (tries >= 9) { // 约 11 秒:host 会先写 null 再写目标 id(900ms),引擎每 2s 轮询一次
16318
+ clearInterval(pollRef.current); pollRef.current = null;
16292
16319
  setNote({
16293
- kind: "ok",
16294
- text: weT("页面已重新加载,「") + (o.label || o.id)
16295
- + weT("」应由皮肤中心应用。若仍无变化,请到「设置 → 皮肤」点「应用」。"),
16320
+ kind: "err",
16321
+ text: weT("已写入「") + label + weT("」,但皮肤中心没有应用。可能原因:壁纸仍在台(皮肤会被抑制)或这套皮肤校验未通过。可到「设置 → 皮肤」点「应用」确认。"),
16296
16322
  });
16297
16323
  }
16298
- } catch { /* sessionStorage 不可用就跳过,不影响主流程 */ }
16299
- }, []);
16324
+ }, 1200);
16325
+ }
16300
16326
 
16301
16327
  /**
16302
16328
  * 执行一个动作。
16303
16329
  * · install / remove:宿主真正干活(下载解压 / 删目录)。
16304
- * · activate:**只写 active**(`skin-center-active.json`),然后告诉用户下一步。
16305
- * 不注入任何样式 —— 那一步归皮肤中心。
16330
+ * · activate:**只写 active**(`skin-center-active.json`)—— 不注入任何样式,
16331
+ * 应用由皮肤中心自己轮询完成,我们只负责验证结果。
16306
16332
  */
16307
16333
  async function act(kind, id, label) {
16308
16334
  if (busy) return;
@@ -16318,31 +16344,19 @@ window.__ModuleLoader__.load({
16318
16344
  } else if (kind === "activate") {
16319
16345
  setActive(id);
16320
16346
  setList((prev) => prev.map((x) => ({ ...x, active: x.id === id })));
16321
- // 皮肤与壁纸都在铺背景,必须互斥:先让壁纸让位。
16347
+ // 皮肤与壁纸都在铺背景,必须互斥:皮肤中心在壁纸在台时会**主动抑制皮肤**,
16348
+ // 所以这一步不是"顺手",而是"应用能否成功"的前提。
16322
16349
  try {
16323
16350
  if (typeof onClearWallpaper === "function") await Promise.resolve(onClearWallpaper());
16324
16351
  } catch { /* 清壁纸失败不影响选中本身 */ }
16325
- setNote({
16326
- kind: "ok",
16327
- text: skinCenter
16328
- ? weT("已选中「") + label + weT("」,正在重新加载页面让皮肤生效…")
16329
- : weT("已选中「") + label + weT("」—— 未检测到皮肤中心,无法渲染;请安装 @linxin666/dsh-client-ui-skin-center 后重启"),
16330
- });
16331
- // 只有皮肤中心在台时,刷新才有意义(boot 时它会应用 active)。
16332
16352
  if (skinCenter) {
16333
- try {
16334
- sessionStorage.setItem("folia.applyPending", JSON.stringify({ id, label, at: Date.now() }));
16335
- } catch { /* 不可用就退化:不刷新,只给提示 */ }
16336
- setTimeout(() => {
16337
- try { window.location.reload(); } catch { /* 桌面壳拦了刷新 */ }
16338
- }, 700);
16339
- // 兜底:4 秒后页面还在(说明刷新被吞),明确告诉用户改用手动重启。
16340
- setTimeout(() => {
16341
- setNote({
16342
- kind: "err",
16343
- text: weT("页面没有自动刷新 —— 桌面壳可能拦了刷新。请手动重启 DSH 让「") + label + weT("」生效。"),
16344
- });
16345
- }, 4000);
16353
+ setNote({ kind: "ok", text: weT("已选中「") + label + weT("」,等待皮肤中心应用(约 2 秒)…") });
16354
+ verifyApplied(id, label);
16355
+ } else {
16356
+ setNote({
16357
+ kind: "err",
16358
+ text: weT("已写入「") + label + weT("」,但本机没有皮肤中心,无法渲染。请安装 @linxin666/dsh-client-ui-skin-center 后重启。"),
16359
+ });
16346
16360
  }
16347
16361
  } else if (kind === "remove") {
16348
16362
  setNote({ kind: "ok", text: weT("已删除:") + label });