import SwiftUI /// Apple Intelligence 式多彩流光线:蓝→紫→粉→橙→青,横向无缝循环流动。 /// 全 App「AI 计算中」时刻的统一视觉点缀(日记 AI 辅助、身体档案报告生成/检索等待等)。 /// /// 注意:这条线的颜色是刻意走出 `Tj.Palette` 单色系统的 AI 高光点缀(应产品要求的 /// Apple 风格),仅此组件如此;其余 UI 仍严格守 §9 单色 token。 /// /// 驱动方式用 `TimelineView(.animation)` 而非 `.onAppear` + `repeatForever`:这条线出现的 /// 场景(流式回答、tok/s 每 0.5s 刷新等)父视图都在高频重绘,隐式 `repeatForever` 动画会被 /// 反复打断/重置 → 看起来「几乎不动」。TimelineView 按显示刷新率直接从时间算偏移,与父视图 /// 重绘完全解耦,任何场景下都匀速流动。 struct AIFlowBar: View { var height: CGFloat = 3 /// 颜色平移一整圈(一个完整色序)的秒数,越小越快。 var cycle: Double = 0.6 private static let base: [Color] = [ Color(red: 0.35, green: 0.47, blue: 0.98), // 蓝 Color(red: 0.62, green: 0.36, blue: 0.92), // 紫 Color(red: 0.96, green: 0.40, blue: 0.62), // 粉 Color(red: 1.00, green: 0.55, blue: 0.30), // 橙 Color(red: 0.30, green: 0.80, blue: 0.92), // 青 ] /// 色序重复两遍并以首色收尾(共 11 个 stop,均匀分布):一个色周期恰好占据画布宽度, /// 平移一个画布宽度后首尾同色,循环完全无缝。 private static let gradient: Gradient = { let colors = base + base + [base[0]] let last = CGFloat(colors.count - 1) return Gradient(stops: colors.enumerated().map { i, c in Gradient.Stop(color: c, location: CGFloat(i) / last) }) }() var body: some View { TimelineView(.animation) { timeline in GeometryReader { geo in let w = geo.size.width let t = timeline.date.timeIntervalSinceReferenceDate let progress = CGFloat(t.truncatingRemainder(dividingBy: cycle) / cycle) Capsule() .fill(LinearGradient(gradient: Self.gradient, startPoint: .leading, endPoint: .trailing)) .frame(width: w * 2) .offset(x: -w * progress) } } .frame(height: height) .clipShape(Capsule()) } }