- 架构层:ViewModel/ObservableObject、Service/Repository、网络层 APIClient/APIEndpoint/APIError - 设计系统:Color(light:dark:) 自适应 28 色 Token、ColorSchemeManager 深浅色切换 - 全页面:AI 对话/反馈/回忆/薄弱点、知识库 CRUD、学习工作台、复习计划、学习分析、个人中心/设置 - 登录与引导:Sign in with Apple、AppSession 状态管理、引导流程、演示模式 - 本地持久化:FileCache + PersistenceController(学习任务/复习任务/学习记录) - 本地化:zh-Hans Localizable.strings ~120 条、ZXStrings 程序化引用、LanguageManager - 组件库:ZXTabBar/ZXBackHeader/ZXSTaskRow/ZXChartView/ZXTypingIndicator 等 22 个共享组件 - 等待名单:WaitlistView 邮箱收集表单 - 动效:ZXTypingIndicator AI 打字动画、ZXShimmerModifier 骨架屏 - 测试:StudyHomeViewModel/AIChatViewModel/ReviewPlanViewModel/FileCache 共 28 条 - Dynamic Type 支持 + 范围限制 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
79 lines
2.9 KiB
Swift
79 lines
2.9 KiB
Swift
import SwiftUI
|
||
|
||
struct ReviewTaskRow: View {
|
||
let task: ReviewTaskEntity
|
||
let onToggle: () -> Void
|
||
|
||
var body: some View {
|
||
HStack(spacing: 12) {
|
||
Button(action: onToggle) {
|
||
Image(systemName: task.statusEnum == .completed ? "checkmark.circle.fill" : "circle")
|
||
.font(.system(size: 20))
|
||
.foregroundColor(task.statusEnum == .completed ? Color.zxGreen : Color.zxF02)
|
||
}
|
||
|
||
VStack(alignment: .leading, spacing: 4) {
|
||
Text(task.lessonId)
|
||
.font(.system(size: 13, weight: .semibold))
|
||
.foregroundColor(task.statusEnum == .completed ? Color.zxF04 : Color.zxF0)
|
||
|
||
HStack(spacing: 8) {
|
||
reviewTypeTag(task.reviewTypeEnum)
|
||
Text("第 1 次复习")
|
||
.font(.system(size: 10))
|
||
.foregroundColor(Color.zxF035)
|
||
}
|
||
}
|
||
|
||
Spacer()
|
||
|
||
if task.statusEnum == .pending {
|
||
Image(systemName: "play.fill")
|
||
.font(.system(size: 14))
|
||
.foregroundColor(.white)
|
||
.frame(width: 32, height: 32)
|
||
.background(ZXGradient.brand)
|
||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||
}
|
||
}
|
||
.padding(.horizontal, 16)
|
||
.padding(.vertical, 12)
|
||
.background(Color.zxFill003)
|
||
.overlay(
|
||
RoundedRectangle(cornerRadius: 14)
|
||
.stroke(Color.zxBorder006, lineWidth: 1)
|
||
)
|
||
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||
.opacity(task.statusEnum == .completed ? 0.6 : 1)
|
||
.accessibilityLabel("复习任务:\(task.lessonId),\(reviewTypeLabel(task.reviewTypeEnum))")
|
||
.accessibilityHint(task.statusEnum == .completed ? "已完成" : "双击开始复习")
|
||
}
|
||
|
||
private func reviewTypeLabel(_ type: ReviewTaskEntityType) -> String {
|
||
switch type {
|
||
case .spacedRepetition: return "间隔重复"
|
||
case .feynman: return "费曼技巧"
|
||
case .recall: return "主动回忆"
|
||
case .weakPoint: return "薄弱点巩固"
|
||
}
|
||
}
|
||
|
||
func reviewTypeTag(_ type: ReviewTaskEntityType) -> some View {
|
||
let config: (String, Color) = {
|
||
switch type {
|
||
case .spacedRepetition: return ("间隔重复", Color.zxPurple)
|
||
case .feynman: return ("费曼", Color.zxAccent)
|
||
case .recall: return ("回忆", Color.zxOrange)
|
||
case .weakPoint: return ("薄弱", Color.zxYellow)
|
||
}
|
||
}()
|
||
return Text(config.0)
|
||
.font(.system(size: 10, weight: .semibold))
|
||
.foregroundColor(config.1)
|
||
.padding(.horizontal, 6)
|
||
.padding(.vertical, 1)
|
||
.background(config.1.opacity(0.12))
|
||
.clipShape(Capsule())
|
||
}
|
||
}
|