fix iOS
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
#if os(iOS)
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - LivePlayerGestureLayer
|
||||
|
||||
/// 直播播放器手势交互层 - 专为直播场景设计
|
||||
/// 直播不需要快进快退,仅支持:
|
||||
/// - 单击:显示/隐藏控制层
|
||||
/// - 双击:暂停/播放
|
||||
/// - 右侧垂直滑动:调节音量
|
||||
/// - 左侧垂直滑动:调节亮度
|
||||
struct LivePlayerGestureLayer: View {
|
||||
// MARK: - Callbacks
|
||||
let onTogglePlayPause: () -> Void
|
||||
let onToggleControls: () -> Void
|
||||
let onVolumeChanged: (CGFloat) -> Void
|
||||
|
||||
// MARK: - State
|
||||
@State private var gestureMode: LiveGestureMode = .none
|
||||
@State private var showIndicator = false
|
||||
@State private var dragStartX: CGFloat = 0
|
||||
@State private var accumulatedBrightnessDelta: CGFloat = 0
|
||||
@State private var accumulatedVolumeDelta: CGFloat = 0
|
||||
|
||||
enum LiveGestureMode: Equatable {
|
||||
case none
|
||||
case adjustingBrightness(delta: CGFloat)
|
||||
case adjustingVolume(delta: CGFloat)
|
||||
}
|
||||
|
||||
// MARK: - Body
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geometry in
|
||||
Color.clear
|
||||
.contentShape(Rectangle())
|
||||
.gesture(dragGesture(in: geometry))
|
||||
.onTapGesture(count: 2) {
|
||||
HapticManager.shared.lightImpact()
|
||||
onTogglePlayPause()
|
||||
}
|
||||
.onTapGesture(count: 1) {
|
||||
onToggleControls()
|
||||
}
|
||||
.overlay { gestureIndicatorOverlay }
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Drag Gesture
|
||||
|
||||
private func dragGesture(in geometry: GeometryProxy) -> some Gesture {
|
||||
DragGesture(minimumDistance: 15)
|
||||
.onChanged { value in
|
||||
if gestureMode == .none {
|
||||
dragStartX = value.startLocation.x
|
||||
HapticManager.shared.lightImpact()
|
||||
}
|
||||
|
||||
let absV = abs(value.translation.height)
|
||||
guard absV > 15 else { return }
|
||||
|
||||
let isLeftHalf = dragStartX < geometry.size.width / 2
|
||||
let delta = -value.translation.height / 300.0
|
||||
|
||||
if isLeftHalf {
|
||||
gestureMode = .adjustingBrightness(delta: delta)
|
||||
// Apply brightness directly
|
||||
let newBrightness = max(0, min(1, UIScreen.main.brightness + (delta - accumulatedBrightnessDelta)))
|
||||
UIScreen.main.brightness = newBrightness
|
||||
accumulatedBrightnessDelta = delta
|
||||
} else {
|
||||
gestureMode = .adjustingVolume(delta: delta)
|
||||
let volumeDelta = delta - accumulatedVolumeDelta
|
||||
onVolumeChanged(volumeDelta)
|
||||
accumulatedVolumeDelta = delta
|
||||
}
|
||||
|
||||
withAnimation(.easeInOut(duration: 0.2)) {
|
||||
showIndicator = true
|
||||
}
|
||||
}
|
||||
.onEnded { _ in
|
||||
gestureMode = .none
|
||||
accumulatedBrightnessDelta = 0
|
||||
accumulatedVolumeDelta = 0
|
||||
withAnimation(.easeInOut(duration: 0.2)) {
|
||||
showIndicator = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Gesture Indicator Overlay
|
||||
|
||||
@ViewBuilder
|
||||
private var gestureIndicatorOverlay: some View {
|
||||
if showIndicator {
|
||||
VStack(spacing: 8) {
|
||||
indicatorIcon
|
||||
indicatorText
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.vertical, 12)
|
||||
.background(.ultraThinMaterial)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
.opacity(showIndicator ? 1 : 0)
|
||||
.animation(.easeInOut(duration: 0.2), value: showIndicator)
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var indicatorIcon: some View {
|
||||
switch gestureMode {
|
||||
case .adjustingBrightness:
|
||||
Image(systemName: "sun.max.fill")
|
||||
.font(.title2)
|
||||
.foregroundColor(.yellow)
|
||||
case .adjustingVolume:
|
||||
Image(systemName: "speaker.wave.2.fill")
|
||||
.font(.title2)
|
||||
.foregroundColor(.white)
|
||||
case .none:
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var indicatorText: some View {
|
||||
switch gestureMode {
|
||||
case .adjustingBrightness:
|
||||
let percentage = Int(UIScreen.main.brightness * 100)
|
||||
Text("\(percentage)%")
|
||||
.font(.caption)
|
||||
.foregroundColor(.white)
|
||||
case .adjustingVolume:
|
||||
Text("音量")
|
||||
.font(.caption)
|
||||
.foregroundColor(.white)
|
||||
case .none:
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user