feat: 新增 Fake 仓库实现(含可提交的打卡/计划与会话)
This commit is contained in:
136
IosClientKit/Sources/CoreRepository/FakePlanRepository.swift
Normal file
136
IosClientKit/Sources/CoreRepository/FakePlanRepository.swift
Normal file
@@ -0,0 +1,136 @@
|
||||
import Combine
|
||||
import CoreDomain
|
||||
import CoreModel
|
||||
import Foundation
|
||||
|
||||
/// Fake 计划仓库(骨架阶段返回假数据,可提交)。
|
||||
public final class FakePlanRepository: PlanRepository, @unchecked Sendable {
|
||||
private let plans: [PlanType: CurrentValueSubject<PlanRecord, Never>]
|
||||
private var submits: [String: CurrentValueSubject<PlanSubmitData, Never>] = [:]
|
||||
private let lock = NSLock()
|
||||
|
||||
public init() {
|
||||
var dict: [PlanType: CurrentValueSubject<PlanRecord, Never>] = [:]
|
||||
for type in PlanType.allCases {
|
||||
dict[type] = CurrentValueSubject<PlanRecord, Never>(Self.seedPlan(type))
|
||||
}
|
||||
plans = dict
|
||||
}
|
||||
|
||||
public func observePlan(type: PlanType) -> AsyncThrowingStream<PlanRecord, Error> {
|
||||
Self.stream(plans[type]!)
|
||||
}
|
||||
|
||||
public func observePlanSubmit(type: PlanType, periodKey: String) -> AsyncThrowingStream<PlanSubmitData, Error> {
|
||||
Self.stream(submitSubject(type: type, periodKey: periodKey))
|
||||
}
|
||||
|
||||
public func savePlan(type: PlanType, periodKey: String, content: String, attachments: [String]) async throws {
|
||||
try await Task.sleep(for: .milliseconds(300))
|
||||
|
||||
let submit = submitSubject(type: type, periodKey: periodKey)
|
||||
let currentSubmit = submit.value
|
||||
submit.value = PlanSubmitData(
|
||||
content: content,
|
||||
attachments: attachments,
|
||||
checked: true,
|
||||
canSubmit: currentSubmit.canSubmit,
|
||||
message: currentSubmit.message,
|
||||
history: currentSubmit.history
|
||||
)
|
||||
|
||||
let plan = plans[type]!
|
||||
let currentPlan = plan.value
|
||||
plan.value = PlanRecord(
|
||||
type: currentPlan.type,
|
||||
periodKey: currentPlan.periodKey,
|
||||
canSubmit: currentPlan.canSubmit,
|
||||
message: currentPlan.message,
|
||||
myChecked: true,
|
||||
myRecord: MyPlanRecord(status: "已完成", submittedTime: "现在", content: content, attachments: attachments),
|
||||
groups: currentPlan.groups,
|
||||
unassignedCount: currentPlan.unassignedCount
|
||||
)
|
||||
}
|
||||
|
||||
private func submitSubject(type: PlanType, periodKey: String) -> CurrentValueSubject<PlanSubmitData, Never> {
|
||||
let key = "\(type.rawValue):\(periodKey)"
|
||||
lock.lock()
|
||||
defer { lock.unlock() }
|
||||
if let existing = submits[key] {
|
||||
return existing
|
||||
}
|
||||
let subject = CurrentValueSubject<PlanSubmitData, Never>(Self.seedSubmit(type: type))
|
||||
submits[key] = subject
|
||||
return subject
|
||||
}
|
||||
|
||||
private static func stream<T>(_ subject: CurrentValueSubject<T, Never>) -> AsyncThrowingStream<T, Error> {
|
||||
AsyncThrowingStream { continuation in
|
||||
let cancellable = subject.sink { continuation.yield($0) }
|
||||
continuation.onTermination = { _ in cancellable.cancel() }
|
||||
}
|
||||
}
|
||||
|
||||
private static func seedPlan(_ type: PlanType) -> PlanRecord {
|
||||
PlanRecord(
|
||||
type: type,
|
||||
periodKey: periodKey(for: type),
|
||||
canSubmit: true,
|
||||
message: type == .weekly ? "本周计划提交截止:周日晚 23:59" : nil,
|
||||
myChecked: type == .weekly,
|
||||
myRecord: type == .weekly
|
||||
? MyPlanRecord(status: "已完成", submittedTime: "今天 18:30", content: "本周完成两章学习,整理笔记并复习错题。", attachments: ["图1", "图2"])
|
||||
: nil,
|
||||
groups: seedGroups(),
|
||||
unassignedCount: 2
|
||||
)
|
||||
}
|
||||
|
||||
private static func seedSubmit(type: PlanType) -> PlanSubmitData {
|
||||
if type == .weekly {
|
||||
return PlanSubmitData(
|
||||
content: "本周完成两章学习,整理笔记并复习错题。",
|
||||
attachments: ["图1", "图2"],
|
||||
checked: true,
|
||||
canSubmit: true,
|
||||
message: nil,
|
||||
history: []
|
||||
)
|
||||
}
|
||||
return PlanSubmitData(
|
||||
content: "",
|
||||
attachments: [],
|
||||
checked: false,
|
||||
canSubmit: true,
|
||||
message: nil,
|
||||
history: [
|
||||
MyPlanRecord(status: "已完成", submittedTime: "2026-08 完成", content: "上月计划内容……", attachments: []),
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
private static func periodKey(for type: PlanType) -> String {
|
||||
switch type {
|
||||
case .weekly: return "2026 第 37 周"
|
||||
case .monthly: return "2026 年 9 月"
|
||||
case .yearly: return "2026 年"
|
||||
}
|
||||
}
|
||||
|
||||
private static func seedGroups() -> [PlanGroup] {
|
||||
[
|
||||
PlanGroup(id: "g1", name: "进阶一组", checkedCount: 4, memberCount: 6, members: seedMembers()),
|
||||
PlanGroup(id: "g2", name: "进阶二组", checkedCount: 5, memberCount: 5, members: seedMembers()),
|
||||
PlanGroup(id: "g3", name: "进阶三组", checkedCount: 2, memberCount: 7, members: seedMembers()),
|
||||
]
|
||||
}
|
||||
|
||||
private static func seedMembers() -> [PlanMember] {
|
||||
[
|
||||
PlanMember(id: "p1", name: "张三", filled: true),
|
||||
PlanMember(id: "p2", name: "李四", filled: true),
|
||||
PlanMember(id: "p3", name: "王五", filled: false),
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user