"use client"; /** * AppStorage 完整实现(静态类风格 / localStorage) * * 对齐 Dart 端 `AppStorage`(lib/data/services/storage/app_storage.dart): * - PWA 对话框每日展示 / PWA 事件每日上报 / app-info 每日上报 * - 内部用 `yyyy-MM-dd` 字符串比对实现"每日一次"语义 * * 注意:Dart 端是 `static class` 没有接口,本 TS 版本同样保持静态方法风格。 * 通过 `LocalStorage` 单例 + 懒加载的私有 getter 访问底层存储。 * * 语义: * - `canXxx(today)` 返回 `true` 当且仅当"自上次记录以来日期变了" * (即 stored !== today)。首次调用(key 不存在)也返回 `true`。 * - `recordXxx(today)` 写入 todayString,后续 `canXxx` 在同一天返回 `false`。 */ import { LocalStorage } from "../local_storage"; import { Result, type Result as ResultT } from "@/utils/result"; import { StorageKeys } from "../storage_keys"; export class AppStorage { private static _ls: LocalStorage | null = null; /** 懒加载 LocalStorage 单例,避免模块加载期触发 SSR 副作用。 */ private static get ls(): LocalStorage { if (!AppStorage._ls) AppStorage._ls = LocalStorage.getInstance(); return AppStorage._ls; } /** @internal */ static _resetForTests(): void { AppStorage._ls = null; } // ---- PWA install dialog ---- static async canShowPwaDialog(todayString: string): Promise> { return AppStorage.canReportKey(StorageKeys.lastPwaDialogShown, todayString); } static recordPwaDialogShown(todayString: string): Promise> { return AppStorage.ls.setString(StorageKeys.lastPwaDialogShown, todayString); } // ---- PWA event reporting ---- static canReportPwaEvent(todayString: string): Promise> { return AppStorage.canReportKey(StorageKeys.lastPwaEventReported, todayString); } static recordPwaEventReported(todayString: string): Promise> { return AppStorage.ls.setString(StorageKeys.lastPwaEventReported, todayString); } // ---- app info reporting ---- static canReportAppInfo(todayString: string): Promise> { return AppStorage.canReportKey(StorageKeys.lastAppInfoReported, todayString); } static recordAppInfoReported(todayString: string): Promise> { return AppStorage.ls.setString(StorageKeys.lastAppInfoReported, todayString); } // ---- internal helpers ---- /** * 通用"每日一次"判断: * - 取已记录的日期字符串 * - 缺失 → 允许(true) * - 等于 today → 拒绝(false) * - 不等于 today → 允许(true) */ private static async canReportKey( key: string, todayString: string, ): Promise> { const r = await AppStorage.ls.getString(key); if (!r.success) return r; return Result.ok(r.data === null || r.data !== todayString); } }