refactor: 文件目录重构

This commit is contained in:
Junhui Chen 2025-09-09 11:32:38 +08:00
parent 552193b4c1
commit a3c4806271
39 changed files with 135 additions and 8 deletions

View File

@ -71,14 +71,14 @@
## 任务清单(同步 todo ## 任务清单(同步 todo
- [x] nav-1 统一导航(移除子页面 NavigationViewRouter 返回) - [x] nav-1 统一导航(移除子页面 NavigationViewRouter 返回)
- [ ] mvvm-1 BlindBox 引入 ViewModel迁移逻辑 - [x] mvvm-1 BlindBox 引入 ViewModel迁移逻辑
- [x] timer-1 计时器降频与取消 - [x] timer-1 计时器降频与取消
- [x] polling-1 轮询可取消化 - [x] polling-1 轮询可取消化
- [ ] media-1 媒体与动画优化GIF->Lottie/可见播放) - [x] media-1 媒体与动画优化GIF->Lottie/可见播放)
- [ ] concurrency-1 @MainActor 与线程安全 - [x] concurrency-1 @MainActor 与线程安全
- [x] netlog-1 网络日志开关与限流 - [x] netlog-1 网络日志开关与限流
- [ ] structure-1 目录重组 - [ ] structure-1 目录重组(进行中)
- [ ] perf-1 性能埋点与基线 - [ ] perf-1 性能埋点与基线(进行中)
## 进度记录(每次执行后更新) ## 进度记录(每次执行后更新)
- 2025-09-08 15:41 +08: 创建 specs 目录与本说明v0.1)。 - 2025-09-08 15:41 +08: 创建 specs 目录与本说明v0.1)。
@ -98,6 +98,70 @@
- 倒计时迁移至 VM新增 `startCountdown/stopCountdown``countdownText`,视图使用 `viewModel.countdownText` 展示;`ContentView` 移除本地倒计时与定时器。 - 倒计时迁移至 VM新增 `startCountdown/stopCountdown``countdownText`,视图使用 `viewModel.countdownText` 展示;`ContentView` 移除本地倒计时与定时器。
- 首帧无闪烁:`ContentView` 初始 `animationPhase = .none`,监听 `viewModel.didBootstrap` 后按初始状态(大小写不敏感)切换 `loading/ready`;操作按钮在 `didBootstrap` 前隐藏。 - 首帧无闪烁:`ContentView` 初始 `animationPhase = .none`,监听 `viewModel.didBootstrap` 后按初始状态(大小写不敏感)切换 `loading/ready`;操作按钮在 `didBootstrap` 前隐藏。
- 媒体优化起步:将 `loading` 阶段的 GIF 替换为 Lottie`LottieView(name: "loading")`,资源位于 `wake/Assets/Lottie/loading.json`)。 - 媒体优化起步:将 `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 的第 13 步迁移:
- 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/<Feature>/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` - 采用顶层 `NavigationStack + Router`,子页面取消 `NavigationView`

View File

@ -38,7 +38,25 @@
AB4FA8642E4F7074005D9955 /* Exceptions for "wake" folder in "wake" target */ = { AB4FA8642E4F7074005D9955 /* Exceptions for "wake" folder in "wake" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet; isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = ( 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, 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 */; target = ABB4E2072E4B75D900660198 /* wake */;
}; };

View File

@ -0,0 +1,2 @@
# Core/DesignSystem
存放 `Theme.swift``Typography.swift` 等设计系统文件。

View File

@ -0,0 +1,2 @@
# Core/Diagnostics
性能与诊断相关:`Performance.swift`,以及后续埋点/日志工具。

View File

@ -0,0 +1,2 @@
# Core/Navigation
存放路由与导航相关:`Router.swift`

View File

@ -0,0 +1,2 @@
# Core/Network
通用网络层与配置:`NetworkService.swift``APIConfig.swift`、ApiClient 公共代码。

9
wake/Core/README.md Normal file
View File

@ -0,0 +1,9 @@
# Core
跨特性共享的核心能力:
- DesignSystem主题、字体、间距
- Navigation路由/导航栈)
- Diagnostics性能与日志
- Network网络与配置
建议通过 Xcode Group 先完成组织,再视需要同步到磁盘。

View File

@ -0,0 +1,2 @@
# Features/BlindBox/API
盲盒相关 API 封装与轮询:`BlindBoxApi.swift``BlindBoxPolling.swift`

View File

@ -0,0 +1,2 @@
# Features/BlindBox/Components
盲盒专属子组件与片段视图。

View File

@ -0,0 +1,2 @@
# Features/BlindBox/Models
盲盒业务模型:`BlindModels.swift` 等。

View File

@ -0,0 +1,2 @@
# Features/BlindBox
盲盒业务代码View / ViewModel / API / Models / Components。

View File

@ -410,7 +410,7 @@ struct BlindBoxView: View {
VStack(spacing: 20) { VStack(spacing: 20) {
switch animationPhase { switch animationPhase {
case .loading: case .loading:
LottieView(name: "loading") LottieView(name: "loading", isPlaying: animationPhase == .loading && !showScalingOverlay)
.frame(width: 300, height: 300) .frame(width: 300, height: 300)
// .onAppear { // .onAppear {
// DispatchQueue.main.asyncAfter(deadline: .now() + 6) { // DispatchQueue.main.asyncAfter(deadline: .now() + 6) {
@ -422,7 +422,7 @@ struct BlindBoxView: View {
case .ready: case .ready:
ZStack { ZStack {
LottieView(name: "data") LottieView(name: "data", isPlaying: animationPhase == .ready && !showScalingOverlay)
.frame(width: 300, height: 300) .frame(width: 300, height: 300)
// Add a transparent overlay to capture taps // Add a transparent overlay to capture taps
@ -454,7 +454,7 @@ struct BlindBoxView: View {
case .opening: case .opening:
ZStack { ZStack {
if !showMedia { if !showMedia {
GIFView(name: "BlindOpen") LottieView(name: "open", loopMode: .playOnce, isPlaying: !showMedia)
.frame(width: 300, height: 300) .frame(width: 300, height: 300)
.scaleEffect(scale) .scaleEffect(scale)
} }

View File

@ -0,0 +1,2 @@
# Features/BlindBox/View
盲盒界面视图文件(例如 `BlindBoxView.swift`)。

View File

@ -154,6 +154,8 @@ final class BlindBoxViewModel: ObservableObject {
} }
func openBlindBox(for id: String) async throws { 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) try await BlindBoxApi.shared.openBlindBox(boxId: id)
} }

View File

@ -0,0 +1,2 @@
# Features/BlindBox/ViewModel
盲盒视图模型,如 `BlindBoxViewModel.swift`

View File

@ -0,0 +1,2 @@
# Features/Subscribe
订阅相关页面与组件:`SubscribeView``CreditsInfoCard``PlanCompare` 等。

View File

@ -0,0 +1,2 @@
# SharedUI/Animation
Lottie 等动画封装:`LottieView.swift`

View File

@ -0,0 +1,2 @@
# SharedUI/Controls
通用按钮、输入控件等。

View File

@ -0,0 +1,2 @@
# SharedUI/Graphics
共享图形包装。

View File

@ -0,0 +1,2 @@
# SharedUI/Media
媒体通用视图:`GIFView.swift``SVGImage.swift`/`SVGImageHtml.swift` 等。

View File

@ -0,0 +1,2 @@
# SharedUI/Modals
通用弹层与模态:`SheetModal.swift` 等。

2
wake/SharedUI/README.md Normal file
View File

@ -0,0 +1,2 @@
# SharedUI
跨特性共享 UI 组件与资源包装Animation、Media、Modals、Controls、Graphics 等。