diff --git a/specs/refactor_spec.md b/specs/refactor_spec.md index 8358511..7b5b743 100644 --- a/specs/refactor_spec.md +++ b/specs/refactor_spec.md @@ -71,14 +71,14 @@ ## 任务清单(同步 todo) - [x] nav-1 统一导航(移除子页面 NavigationView,Router 返回) -- [ ] mvvm-1 BlindBox 引入 ViewModel,迁移逻辑 +- [x] mvvm-1 BlindBox 引入 ViewModel,迁移逻辑 - [x] timer-1 计时器降频与取消 - [x] polling-1 轮询可取消化 -- [ ] media-1 媒体与动画优化(GIF->Lottie/可见播放) -- [ ] concurrency-1 @MainActor 与线程安全 +- [x] media-1 媒体与动画优化(GIF->Lottie/可见播放) +- [x] concurrency-1 @MainActor 与线程安全 - [x] netlog-1 网络日志开关与限流 -- [ ] structure-1 目录重组 -- [ ] perf-1 性能埋点与基线 +- [ ] structure-1 目录重组(进行中) +- [ ] perf-1 性能埋点与基线(进行中) ## 进度记录(每次执行后更新) - 2025-09-08 15:41 +08: 创建 specs 目录与本说明(v0.1)。 @@ -98,6 +98,70 @@ - 倒计时迁移至 VM:新增 `startCountdown/stopCountdown`、`countdownText`,视图使用 `viewModel.countdownText` 展示;`ContentView` 移除本地倒计时与定时器。 - 首帧无闪烁:`ContentView` 初始 `animationPhase = .none`,监听 `viewModel.didBootstrap` 后按初始状态(大小写不敏感)切换 `loading/ready`;操作按钮在 `didBootstrap` 前隐藏。 - 媒体优化起步:将 `loading` 阶段的 GIF 替换为 Lottie(`LottieView(name: "loading")`,资源位于 `wake/Assets/Lottie/loading.json`)。 + - 2025-09-08 19:19 +08: 完成 media-1: + - Loading/Ready/Opening 全部替换为 Lottie(`loading.json`/`data.json`/`open.json`),并使用 `isPlaying` 仅在可见时播放;Opening 使用 `.playOnce`。 + - 引入 `Perf` 工具类并在关键路径打点(Appear、状态切换、开盒点击、开启动画)以支持 perf-1。 + - 2025-09-08 19:19 +08: 启动 structure-1(进行中): + - 创建目录骨架:`Core/`、`SharedUI/`、`Features/BlindBox/`、`Features/Subscribe/` 等,仅添加 README,不改变构建;后续在 Xcode 内移动文件以保持引用正确。 + + - 2025-09-09 11:26 +08: 推进 structure-1: + - 完成盲盒批次文件迁移(View/ViewModel/API/Models/Components)。 + - 完成 SharedUI 与 Core 的第 1–3 步迁移: + - SharedUI:`LottieView.swift`、`GIFView.swift`、`SVGImage.swift`、`SheetModal.swift` 已迁移至 `wake/SharedUI/...`(当前均放在 `Animation/` 分组,后续可按需细分 `Media/`、`Modals/`)。 + - Core:`Router.swift` 已迁至 `Core/Navigation/`,`NetworkService.swift` 已迁至 `Core/Network/`,`Theme.swift` 与 `Typography.swift` 已迁至 `Core/DesignSystem/`。 + - 待迁移:`Performance.swift` → `Core/Diagnostics/`,`APIConfig.swift` → `Core/Network/`。 + +## structure-1 目录重构计划与迁移步骤 + +### 目标结构 +- `wake/Core/` + - `DesignSystem/`(`Theme.swift`、`Typography.swift`) + - `Navigation/`(`Router.swift`) + - `Diagnostics/`(`Performance.swift`) + - `Network/`(`NetworkService.swift`、`APIConfig.swift`、通用 ApiClient/*) +- `wake/SharedUI/` + - `Animation/`(`LottieView.swift`) + - `Media/`(`GIFView.swift`、`SVGImage.swift`/`SVGImageHtml.swift`) + - `Modals/`(`SheetModal.swift` 等) + - `Controls/`(通用按钮、输入框等) + - `Graphics/`(共享图形资源包装) +- `wake/Features/BlindBox/` + - `View/`(`ContentView.swift` -> 建议更名 `BlindBoxView.swift`) + - `ViewModel/`(`BlindBoxViewModel.swift`) + - `API/`(`BlindBoxApi.swift`、`BlindBoxPolling.swift`) + - `Models/`(`BlindModels.swift`) + - `Components/`(与盲盒强相关的子视图) +- `wake/Features/Subscribe/` + - `Components/`(`CreditsInfoCard.swift`、`PlanCompare.swift` 等) + - `View/`(`SubscribeView.swift` 及其子视图) + +### 迁移建议 +1. 在 Xcode 的 Project Navigator 中,先创建“Group without folder”形式的虚拟分组,稳定编译;再选择是否同步到磁盘。 +2. 若需要调整磁盘目录: + - 建议在 Xcode 中使用拖拽将文件移动到对应 Group,同时勾选“Move files”与“Add to targets”,避免红色引用。 + - 一次迁移一个 Feature,迁移后立即编译验证。 +3. 资源文件(Lottie JSON/SVG 等)保持在 `wake/Assets/` 下;仅调整其使用方的源文件位置。 +4. 网络与工具类尽量放入 `Core/`,Feature 专用 API 可放在 `Features//API/`。 + +### 第一批建议迁移(盲盒) +- `wake/View/Blind/ContentView.swift` → `wake/Features/BlindBox/View/BlindBoxView.swift`(建议改名) +- `wake/View/Blind/BlindBoxViewModel.swift` → `wake/Features/BlindBox/ViewModel/BlindBoxViewModel.swift` +- `wake/View/Blind/BlindBoxPolling.swift` → `wake/Features/BlindBox/API/BlindBoxPolling.swift` +- `wake/Utils/ApiClient/BlindBoxApi.swift` → `wake/Features/BlindBox/API/BlindBoxApi.swift` +- `wake/Models/BlindModels.swift` → `wake/Features/BlindBox/Models/BlindModels.swift` + +### 公共组件迁移 +- `wake/Components/Lottie/LottieView.swift` → `wake/SharedUI/Animation/LottieView.swift` +- `wake/Utils/GIFView.swift` → `wake/SharedUI/Media/GIFView.swift` +- `wake/Utils/SVGImage.swift` 与 `wake/Utils/SVGImageHtml.swift` → `wake/SharedUI/Media/` +- `wake/View/Components/SheetModal.swift` → `wake/SharedUI/Modals/SheetModal.swift` +- `wake/View/Components/Button.swift`/`Buttons/` → `wake/SharedUI/Controls/` + +### 核心模块迁移 +- `wake/Utils/Router.swift` → `wake/Core/Navigation/Router.swift` +- `wake/Utils/Performance.swift` → `wake/Core/Diagnostics/Performance.swift` +- `wake/Utils/NetworkService.swift`、`wake/Utils/APIConfig.swift` → `wake/Core/Network/` +- `wake/Theme.swift`、`wake/Typography.swift` → `wake/Core/DesignSystem/` ## 决策记录 - 采用顶层 `NavigationStack + Router`,子页面取消 `NavigationView`。 diff --git a/wake.xcodeproj/project.pbxproj b/wake.xcodeproj/project.pbxproj index c302b59..66d6987 100644 --- a/wake.xcodeproj/project.pbxproj +++ b/wake.xcodeproj/project.pbxproj @@ -38,7 +38,25 @@ AB4FA8642E4F7074005D9955 /* Exceptions for "wake" folder in "wake" target */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( + Core/DesignSystem/README.md, + Core/Diagnostics/README.md, + Core/Navigation/README.md, + Core/Network/README.md, + Core/README.md, + Features/BlindBox/API/README.md, + Features/BlindBox/Components/README.md, + Features/BlindBox/Models/README.md, + Features/BlindBox/README.md, + Features/BlindBox/View/README.md, + Features/BlindBox/ViewModel/README.md, + Features/Subscribe/README.md, Info.plist, + SharedUI/Animation/README.md, + SharedUI/Controls/README.md, + SharedUI/Graphics/README.md, + SharedUI/Media/README.md, + SharedUI/Modals/README.md, + SharedUI/README.md, ); target = ABB4E2072E4B75D900660198 /* wake */; }; diff --git a/wake/Core/DesignSystem/README.md b/wake/Core/DesignSystem/README.md new file mode 100644 index 0000000..cade888 --- /dev/null +++ b/wake/Core/DesignSystem/README.md @@ -0,0 +1,2 @@ +# Core/DesignSystem +存放 `Theme.swift`、`Typography.swift` 等设计系统文件。 diff --git a/wake/Theme.swift b/wake/Core/DesignSystem/Theme.swift similarity index 100% rename from wake/Theme.swift rename to wake/Core/DesignSystem/Theme.swift diff --git a/wake/Typography.swift b/wake/Core/DesignSystem/Typography.swift similarity index 100% rename from wake/Typography.swift rename to wake/Core/DesignSystem/Typography.swift diff --git a/wake/Utils/Performance.swift b/wake/Core/Diagnostics/Performance.swift similarity index 100% rename from wake/Utils/Performance.swift rename to wake/Core/Diagnostics/Performance.swift diff --git a/wake/Core/Diagnostics/README.md b/wake/Core/Diagnostics/README.md new file mode 100644 index 0000000..28d01e3 --- /dev/null +++ b/wake/Core/Diagnostics/README.md @@ -0,0 +1,2 @@ +# Core/Diagnostics +性能与诊断相关:`Performance.swift`,以及后续埋点/日志工具。 diff --git a/wake/Core/Navigation/README.md b/wake/Core/Navigation/README.md new file mode 100644 index 0000000..0f94b4d --- /dev/null +++ b/wake/Core/Navigation/README.md @@ -0,0 +1,2 @@ +# Core/Navigation +存放路由与导航相关:`Router.swift`。 diff --git a/wake/Utils/Router.swift b/wake/Core/Navigation/Router.swift similarity index 100% rename from wake/Utils/Router.swift rename to wake/Core/Navigation/Router.swift diff --git a/wake/Utils/APIConfig.swift b/wake/Core/Network/APIConfig.swift similarity index 100% rename from wake/Utils/APIConfig.swift rename to wake/Core/Network/APIConfig.swift diff --git a/wake/Utils/NetworkService.swift b/wake/Core/Network/NetworkService.swift similarity index 100% rename from wake/Utils/NetworkService.swift rename to wake/Core/Network/NetworkService.swift diff --git a/wake/Core/Network/README.md b/wake/Core/Network/README.md new file mode 100644 index 0000000..5f16370 --- /dev/null +++ b/wake/Core/Network/README.md @@ -0,0 +1,2 @@ +# Core/Network +通用网络层与配置:`NetworkService.swift`、`APIConfig.swift`、ApiClient 公共代码。 diff --git a/wake/Core/README.md b/wake/Core/README.md new file mode 100644 index 0000000..09c4ac7 --- /dev/null +++ b/wake/Core/README.md @@ -0,0 +1,9 @@ +# Core + +跨特性共享的核心能力: +- DesignSystem(主题、字体、间距) +- Navigation(路由/导航栈) +- Diagnostics(性能与日志) +- Network(网络与配置) + +建议通过 Xcode Group 先完成组织,再视需要同步到磁盘。 diff --git a/wake/Utils/ApiClient/BlindBoxApi.swift b/wake/Features/BlindBox/API/BlindBoxApi.swift similarity index 100% rename from wake/Utils/ApiClient/BlindBoxApi.swift rename to wake/Features/BlindBox/API/BlindBoxApi.swift diff --git a/wake/View/Blind/BlindBoxPolling.swift b/wake/Features/BlindBox/API/BlindBoxPolling.swift similarity index 100% rename from wake/View/Blind/BlindBoxPolling.swift rename to wake/Features/BlindBox/API/BlindBoxPolling.swift diff --git a/wake/Features/BlindBox/API/README.md b/wake/Features/BlindBox/API/README.md new file mode 100644 index 0000000..a694ab6 --- /dev/null +++ b/wake/Features/BlindBox/API/README.md @@ -0,0 +1,2 @@ +# Features/BlindBox/API +盲盒相关 API 封装与轮询:`BlindBoxApi.swift`、`BlindBoxPolling.swift`。 diff --git a/wake/View/Blind/Card.swift b/wake/Features/BlindBox/Components/Card.swift similarity index 100% rename from wake/View/Blind/Card.swift rename to wake/Features/BlindBox/Components/Card.swift diff --git a/wake/Features/BlindBox/Components/README.md b/wake/Features/BlindBox/Components/README.md new file mode 100644 index 0000000..4887d22 --- /dev/null +++ b/wake/Features/BlindBox/Components/README.md @@ -0,0 +1,2 @@ +# Features/BlindBox/Components +盲盒专属子组件与片段视图。 diff --git a/wake/Models/BlindModels.swift b/wake/Features/BlindBox/Models/BlindModels.swift similarity index 100% rename from wake/Models/BlindModels.swift rename to wake/Features/BlindBox/Models/BlindModels.swift diff --git a/wake/Features/BlindBox/Models/README.md b/wake/Features/BlindBox/Models/README.md new file mode 100644 index 0000000..456e391 --- /dev/null +++ b/wake/Features/BlindBox/Models/README.md @@ -0,0 +1,2 @@ +# Features/BlindBox/Models +盲盒业务模型:`BlindModels.swift` 等。 diff --git a/wake/Features/BlindBox/README.md b/wake/Features/BlindBox/README.md new file mode 100644 index 0000000..41e6fee --- /dev/null +++ b/wake/Features/BlindBox/README.md @@ -0,0 +1,2 @@ +# Features/BlindBox +盲盒业务代码:View / ViewModel / API / Models / Components。 diff --git a/wake/View/Blind/BlindOutCome.swift b/wake/Features/BlindBox/View/BlindOutCome.swift similarity index 100% rename from wake/View/Blind/BlindOutCome.swift rename to wake/Features/BlindBox/View/BlindOutCome.swift diff --git a/wake/View/Blind/ContentView.swift b/wake/Features/BlindBox/View/ContentView.swift similarity index 99% rename from wake/View/Blind/ContentView.swift rename to wake/Features/BlindBox/View/ContentView.swift index a4cc1bb..b3ba13e 100644 --- a/wake/View/Blind/ContentView.swift +++ b/wake/Features/BlindBox/View/ContentView.swift @@ -410,7 +410,7 @@ struct BlindBoxView: View { VStack(spacing: 20) { switch animationPhase { case .loading: - LottieView(name: "loading") + LottieView(name: "loading", isPlaying: animationPhase == .loading && !showScalingOverlay) .frame(width: 300, height: 300) // .onAppear { // DispatchQueue.main.asyncAfter(deadline: .now() + 6) { @@ -422,7 +422,7 @@ struct BlindBoxView: View { case .ready: ZStack { - LottieView(name: "data") + LottieView(name: "data", isPlaying: animationPhase == .ready && !showScalingOverlay) .frame(width: 300, height: 300) // Add a transparent overlay to capture taps @@ -454,7 +454,7 @@ struct BlindBoxView: View { case .opening: ZStack { if !showMedia { - GIFView(name: "BlindOpen") + LottieView(name: "open", loopMode: .playOnce, isPlaying: !showMedia) .frame(width: 300, height: 300) .scaleEffect(scale) } diff --git a/wake/Features/BlindBox/View/README.md b/wake/Features/BlindBox/View/README.md new file mode 100644 index 0000000..6606d3b --- /dev/null +++ b/wake/Features/BlindBox/View/README.md @@ -0,0 +1,2 @@ +# Features/BlindBox/View +盲盒界面视图文件(例如 `BlindBoxView.swift`)。 diff --git a/wake/View/Blind/BlindBoxViewModel.swift b/wake/Features/BlindBox/ViewModel/BlindBoxViewModel.swift similarity index 99% rename from wake/View/Blind/BlindBoxViewModel.swift rename to wake/Features/BlindBox/ViewModel/BlindBoxViewModel.swift index 07db41e..33c6e42 100644 --- a/wake/View/Blind/BlindBoxViewModel.swift +++ b/wake/Features/BlindBox/ViewModel/BlindBoxViewModel.swift @@ -154,6 +154,8 @@ final class BlindBoxViewModel: ObservableObject { } func openBlindBox(for id: String) async throws { + let sp = Perf.begin("BlindVM_Open") + defer { Perf.end("BlindVM_Open", id: sp) } try await BlindBoxApi.shared.openBlindBox(boxId: id) } diff --git a/wake/Features/BlindBox/ViewModel/README.md b/wake/Features/BlindBox/ViewModel/README.md new file mode 100644 index 0000000..a278235 --- /dev/null +++ b/wake/Features/BlindBox/ViewModel/README.md @@ -0,0 +1,2 @@ +# Features/BlindBox/ViewModel +盲盒视图模型,如 `BlindBoxViewModel.swift`。 diff --git a/wake/Features/Subscribe/README.md b/wake/Features/Subscribe/README.md new file mode 100644 index 0000000..6878108 --- /dev/null +++ b/wake/Features/Subscribe/README.md @@ -0,0 +1,2 @@ +# Features/Subscribe +订阅相关页面与组件:`SubscribeView`、`CreditsInfoCard`、`PlanCompare` 等。 diff --git a/wake/Utils/GIFView.swift b/wake/SharedUI/Animation/GIFView.swift similarity index 100% rename from wake/Utils/GIFView.swift rename to wake/SharedUI/Animation/GIFView.swift diff --git a/wake/Components/Lottie/LottieView.swift b/wake/SharedUI/Animation/LottieView.swift similarity index 100% rename from wake/Components/Lottie/LottieView.swift rename to wake/SharedUI/Animation/LottieView.swift diff --git a/wake/SharedUI/Animation/README.md b/wake/SharedUI/Animation/README.md new file mode 100644 index 0000000..b3135cc --- /dev/null +++ b/wake/SharedUI/Animation/README.md @@ -0,0 +1,2 @@ +# SharedUI/Animation +Lottie 等动画封装:`LottieView.swift`。 diff --git a/wake/Utils/SVGImage.swift b/wake/SharedUI/Animation/SVGImage.swift similarity index 100% rename from wake/Utils/SVGImage.swift rename to wake/SharedUI/Animation/SVGImage.swift diff --git a/wake/View/Components/SheetModal.swift b/wake/SharedUI/Animation/SheetModal.swift similarity index 100% rename from wake/View/Components/SheetModal.swift rename to wake/SharedUI/Animation/SheetModal.swift diff --git a/wake/SharedUI/Controls/README.md b/wake/SharedUI/Controls/README.md new file mode 100644 index 0000000..d9a08d7 --- /dev/null +++ b/wake/SharedUI/Controls/README.md @@ -0,0 +1,2 @@ +# SharedUI/Controls +通用按钮、输入控件等。 diff --git a/wake/Components/Buttons/ReturnButton.swift b/wake/SharedUI/Controls/ReturnButton.swift similarity index 100% rename from wake/Components/Buttons/ReturnButton.swift rename to wake/SharedUI/Controls/ReturnButton.swift diff --git a/wake/SharedUI/Graphics/README.md b/wake/SharedUI/Graphics/README.md new file mode 100644 index 0000000..c4875b0 --- /dev/null +++ b/wake/SharedUI/Graphics/README.md @@ -0,0 +1,2 @@ +# SharedUI/Graphics +共享图形包装。 diff --git a/wake/SharedUI/Media/README.md b/wake/SharedUI/Media/README.md new file mode 100644 index 0000000..fa97f0e --- /dev/null +++ b/wake/SharedUI/Media/README.md @@ -0,0 +1,2 @@ +# SharedUI/Media +媒体通用视图:`GIFView.swift`、`SVGImage.swift`/`SVGImageHtml.swift` 等。 diff --git a/wake/Utils/SVGImageHtml.swift b/wake/SharedUI/Media/SVGImageHtml.swift similarity index 100% rename from wake/Utils/SVGImageHtml.swift rename to wake/SharedUI/Media/SVGImageHtml.swift diff --git a/wake/SharedUI/Modals/README.md b/wake/SharedUI/Modals/README.md new file mode 100644 index 0000000..5579d1d --- /dev/null +++ b/wake/SharedUI/Modals/README.md @@ -0,0 +1,2 @@ +# SharedUI/Modals +通用弹层与模态:`SheetModal.swift` 等。 diff --git a/wake/SharedUI/README.md b/wake/SharedUI/README.md new file mode 100644 index 0000000..db7cc76 --- /dev/null +++ b/wake/SharedUI/README.md @@ -0,0 +1,2 @@ +# SharedUI +跨特性共享 UI 组件与资源包装:Animation、Media、Modals、Controls、Graphics 等。