import SwiftUI /// Compact Siri-style wave visualizer for watchOS struct WatchVisualizerView: View { let levels: [Float] let isPlaying: Bool private let greenColor = Color(red: 0.3, green: 0.85, blue: 0.45) private let blueColor = Color(red: 0.2, green: 0.55, blue: 1.0) private let purpleColor = Color(red: 0.85, green: 0.25, blue: 0.85) var body: some View { TimelineView(.animation(minimumInterval: 1.0 / 60.0)) { timeline in Canvas { context, size in drawVisualizerContent(context: context, size: size, date: timeline.date) } } } // MARK: - Main draw (broken out for type-checker) private func drawVisualizerContent(context: GraphicsContext, size: CGSize, date: Date) { let w = size.width let h = size.height let count = levels.count guard count >= 2 else { return } let time = date.timeIntervalSinceReferenceDate let spacing = w / CGFloat(count - 1) let layerData: [(Color, Double)] = [ (purpleColor, 0.3), (blueColor, 0.15), (greenColor, 0.0), ] for (color, offset) in layerData { drawWaveLayer( context: context, w: w, h: h, count: count, spacing: spacing, time: time, offset: offset, color: color ) } } // MARK: - Single wave layer private func drawWaveLayer( context: GraphicsContext, w: CGFloat, h: CGFloat, count: Int, spacing: CGFloat, time: TimeInterval, offset: Double, color: Color ) { let points = buildPoints( count: count, spacing: spacing, h: h, time: time, offset: offset ) let curvePath = buildCurve(points: points) var fillPath = Path() fillPath.move(to: CGPoint(x: 0, y: h)) fillPath.addLine(to: points[0]) fillPath.addPath(curvePath) fillPath.addLine(to: CGPoint(x: w, y: h)) fillPath.closeSubpath() context.fill(fillPath, with: .color(color.opacity(0.55))) var strokePath = Path() strokePath.move(to: points[0]) strokePath.addPath(curvePath) context.stroke(strokePath, with: .color(color.opacity(0.6)), lineWidth: 1.2) } // MARK: - Build points array private func buildPoints( count: Int, spacing: CGFloat, h: CGFloat, time: TimeInterval, offset: Double ) -> [CGPoint] { var points: [CGPoint] = [] for i in 0.. Path { var path = Path() guard points.count >= 2 else { return path } for i in 0..<(points.count - 1) { let p0 = i > 0 ? points[i - 1] : points[i] let p1 = points[i] let p2 = points[i + 1] let p3 = (i + 2 < points.count) ? points[i + 2] : p2 let cp1x = p1.x + (p2.x - p0.x) / 6.0 let cp1y = p1.y + (p2.y - p0.y) / 6.0 let cp2x = p2.x - (p3.x - p1.x) / 6.0 let cp2y = p2.y - (p3.y - p1.y) / 6.0 path.addCurve( to: p2, control1: CGPoint(x: cp1x, y: cp1y), control2: CGPoint(x: cp2x, y: cp2y) ) } return path } }