/ flo / PlayerCustomSlider.swift
PlayerCustomSlider.swift
  1  //
  2  //  CustomSlider.swift
  3  //  flo
  4  //
  5  //  Created by rizaldy on 05/06/24.
  6  //
  7  
  8  import SwiftUI
  9  
 10  struct PlayerCustomSlider: View {
 11    var isMediaLoading: Bool = false
 12  
 13    @Binding var isSeeking: Bool
 14    @Binding var value: Double
 15  
 16    @State private var tempValue: Double = 0.0
 17  
 18    var range: ClosedRange<Double>
 19    var onEnded: (Double) -> Void
 20  
 21    var body: some View {
 22      GeometryReader { geometry in
 23        ZStack(alignment: .leading) {
 24          Rectangle()
 25            .foregroundColor(Color.gray.opacity(0.8))
 26            .frame(height: 5)
 27            .cornerRadius(5)
 28  
 29          Rectangle()
 30            .foregroundColor(Color.white)
 31            .frame(
 32              width: CGFloat(
 33                (self.value - self.range.lowerBound) / (self.range.upperBound - self.range.lowerBound)
 34              ) * geometry.size.width, height: 4
 35            )
 36            .opacity(isMediaLoading ? 0 : 1)
 37            .cornerRadius(2)
 38  
 39          if self.isSeeking {
 40            Circle()
 41              .fill(Color.white)
 42              .frame(width: 12, height: 12)
 43              .opacity(0.8)
 44              .offset(
 45                x: CGFloat(
 46                  (self.tempValue - self.range.lowerBound)
 47                    / (self.range.upperBound - self.range.lowerBound)) * geometry.size.width - 6)
 48          }
 49  
 50          Circle()
 51            .fill(Color.white)
 52            .frame(width: 12, height: 12)
 53            .offset(
 54              x: CGFloat(
 55                (self.value - self.range.lowerBound) / (self.range.upperBound - self.range.lowerBound)
 56              ) * geometry.size.width - 6
 57            )
 58            .opacity(isMediaLoading ? 0 : 1)
 59            .animation(.easeInOut(duration: 0.3), value: self.value)
 60            .gesture(
 61              DragGesture()
 62                .onChanged { gesture in
 63                  self.isSeeking = true
 64  
 65                  let newValue =
 66                    self.range.lowerBound + Double(gesture.location.x / geometry.size.width)
 67                    * (self.range.upperBound - self.range.lowerBound)
 68  
 69                  self.tempValue = newValue
 70                }.onEnded { gesture in
 71                  let newValue =
 72                    self.range.lowerBound + Double(gesture.location.x / geometry.size.width)
 73                    * (self.range.upperBound - self.range.lowerBound)
 74  
 75                  onEnded(newValue)
 76  
 77                  self.isSeeking = false
 78                }
 79            )
 80        }
 81      }
 82      .frame(height: 20)
 83    }
 84  }
 85  
 86  struct CustomSliders_Previews: PreviewProvider {
 87    static var previews: some View {
 88      PreviewWrapper()
 89    }
 90  
 91    struct PreviewWrapper: View {
 92      @State private var value: Double = 0.30
 93      @State private var isSeeking: Bool = false
 94  
 95      var body: some View {
 96        ZStack {
 97          Color.accent
 98          HStack {
 99            PlayerCustomSlider(isSeeking: $isSeeking, value: $value, range: 0...1) { value in
100              self.value = value
101            }
102          }.padding()
103        }.ignoresSafeArea()
104      }
105    }
106  }