import SwiftUI import AVFoundation import SwiftBricks /// ProgressSlider自定义Widget — 播放进度条+拖动seek struct ProgressSliderWidget: View { let bridge: PlayerBridge let schema: ControlSchema @ObservedObject var engine: BricksEngine @State private var progress: Double = 0 @State private var duration: Double = 0 @State private var isDragging: Bool = false var body: some View { GeometryReader { geo in ZStack(alignment: .leading) { // 背景轨道 RoundedRectangle(cornerRadius: 2) .fill(Color.secondary.opacity(0.3)) .frame(height: 4) // 已播放进度 RoundedRectangle(cornerRadius: 2) .fill(Color.accentColor) .frame(width: geo.size.width * progressRatio, height: 4) // 拖动滑块 Circle() .fill(Color.accentColor) .frame(width: 14, height: 14) .offset(x: geo.size.width * progressRatio - 7) .shadow(radius: 2) } .frame(height: 20) .contentShape(Rectangle()) .gesture( DragGesture(minimumDistance: 0) .onChanged { value in isDragging = true let ratio = max(0, min(1, value.location.x / geo.size.width)) if duration > 0 { let seekTime = ratio * duration bridge.player.seek(to: CMTime(seconds: seekTime, preferredTimescale: 600)) } } .onEnded { _ in isDragging = false } ) } .frame(height: 20) .onReceive(engine.store.$values) { values in if let val = values["progress_slider"] as? String { let parts = val.split(separator: "/") if parts.count == 2, let cur = Double(parts[0]), let total = Double(parts[1]) { if !isDragging { progress = cur duration = total } } } } } private var progressRatio: Double { guard duration > 0 else { return 0 } return max(0, min(1, progress / duration)) } }