mirror of
https://github.com/cranci1/Sora.git
synced 2026-04-04 16:49:44 +00:00
perfect
This commit is contained in:
parent
6de740ee6c
commit
b4ea1bc29b
2 changed files with 33 additions and 33 deletions
|
|
@ -5,7 +5,7 @@
|
|||
// Created by Pratik on 08/01/23.
|
||||
//
|
||||
// Thanks to pratikg29 for this code inside his open source project "https://github.com/pratikg29/Custom-Slider-Control?ref=iosexample.com"
|
||||
// I did edit just a little bit the code for my liking (added a buffer indicator, etc.)
|
||||
// I did edit some of the code for my liking (added a buffer indicator, etc.)
|
||||
|
||||
import SwiftUI
|
||||
|
||||
|
|
@ -156,30 +156,25 @@ import SwiftUI
|
|||
return (total > 0) ? (normalized / total) : 0
|
||||
}
|
||||
|
||||
// Convert fraction to clamped 0...1
|
||||
private func clampedFraction(_ f: T) -> T {
|
||||
max(0, min(f, 1))
|
||||
}
|
||||
|
||||
// Convert fraction to actual time in seconds (or whatever T is)
|
||||
private func getCurrentValue() -> T {
|
||||
let total = inRange.upperBound - inRange.lowerBound
|
||||
let frac = clampedFraction(localRealProgress + localTempProgress)
|
||||
return frac * total + inRange.lowerBound
|
||||
}
|
||||
|
||||
// Clamp the final value to [lowerBound, upperBound]
|
||||
private func clampedValue(_ raw: T) -> T {
|
||||
max(inRange.lowerBound, min(raw, inRange.upperBound))
|
||||
}
|
||||
|
||||
// The actual width of the played portion in pixels
|
||||
private func playedWidth(boundsWidth: CGFloat) -> CGFloat {
|
||||
let frac = fraction(of: value)
|
||||
return max(0, min(boundsWidth * CGFloat(frac), boundsWidth))
|
||||
}
|
||||
|
||||
// The actual width of the buffered portion in pixels
|
||||
private func bufferWidth(boundsWidth: CGFloat) -> CGFloat {
|
||||
let frac = fraction(of: bufferValue)
|
||||
return max(0, min(boundsWidth * CGFloat(frac), boundsWidth))
|
||||
|
|
|
|||
|
|
@ -93,7 +93,6 @@ class CustomMediaPlayerViewController: UIViewController {
|
|||
}
|
||||
}
|
||||
|
||||
// We’ll use this context to KVO loadedTimeRanges
|
||||
private var playerItemKVOContext = 0
|
||||
private var loadedTimeRangesObservation: NSKeyValueObservation?
|
||||
|
||||
|
|
@ -153,6 +152,7 @@ class CustomMediaPlayerViewController: UIViewController {
|
|||
setupPlayerViewController()
|
||||
setupControls()
|
||||
setupSkipAndDismissGestures()
|
||||
addInvisibleControlOverlays()
|
||||
setupSubtitleLabel()
|
||||
setupDismissButton()
|
||||
setupQualityButton()
|
||||
|
|
@ -200,26 +200,22 @@ class CustomMediaPlayerViewController: UIViewController {
|
|||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
|
||||
NotificationCenter.default.removeObserver(self, name: .AVPlayerItemNewAccessLogEntry, object: nil)
|
||||
|
||||
// Remove KVO observer for loadedTimeRanges
|
||||
player.currentItem?.removeObserver(self,
|
||||
forKeyPath: "loadedTimeRanges",
|
||||
context: &playerItemKVOContext)
|
||||
|
||||
if let playbackSpeed = player?.rate {
|
||||
UserDefaults.standard.set(playbackSpeed, forKey: "lastPlaybackSpeed")
|
||||
}
|
||||
player.pause()
|
||||
updateTimer?.invalidate()
|
||||
inactivityTimer?.invalidate()
|
||||
loadedTimeRangesObservation?.invalidate()
|
||||
loadedTimeRangesObservation = nil
|
||||
|
||||
if let token = timeObserverToken {
|
||||
player.removeTimeObserver(token)
|
||||
timeObserverToken = nil
|
||||
}
|
||||
|
||||
UserDefaults.standard.set(player.rate, forKey: "lastPlaybackSpeed")
|
||||
updateTimer?.invalidate()
|
||||
inactivityTimer?.invalidate()
|
||||
|
||||
player.pause()
|
||||
|
||||
if let playbackSpeed = player?.rate {
|
||||
UserDefaults.standard.set(playbackSpeed, forKey: "lastPlaybackSpeed")
|
||||
}
|
||||
|
||||
if let currentItem = player.currentItem, currentItem.duration.seconds > 0 {
|
||||
let progress = currentTimeVal / currentItem.duration.seconds
|
||||
|
|
@ -238,7 +234,6 @@ class CustomMediaPlayerViewController: UIViewController {
|
|||
}
|
||||
}
|
||||
|
||||
// Observing loadedTimeRanges:
|
||||
override func observeValue(forKeyPath keyPath: String?,
|
||||
of object: Any?,
|
||||
change: [NSKeyValueChangeKey : Any]?,
|
||||
|
|
@ -259,7 +254,6 @@ class CustomMediaPlayerViewController: UIViewController {
|
|||
|
||||
if let timeRange = item.loadedTimeRanges.first?.timeRangeValue {
|
||||
let buffered = CMTimeGetSeconds(timeRange.start) + CMTimeGetSeconds(timeRange.duration)
|
||||
// This is how many seconds are currently buffered:
|
||||
DispatchQueue.main.async {
|
||||
self.sliderViewModel.bufferValue = buffered
|
||||
}
|
||||
|
|
@ -366,10 +360,10 @@ class CustomMediaPlayerViewController: UIViewController {
|
|||
value: Binding(get: { self.sliderViewModel.sliderValue },
|
||||
set: { self.sliderViewModel.sliderValue = $0 }),
|
||||
inRange: 0...(duration > 0 ? duration : 1.0),
|
||||
bufferValue: self.sliderViewModel.bufferValue, // <--- pass in buffer
|
||||
bufferValue: self.sliderViewModel.bufferValue,
|
||||
activeFillColor: .white,
|
||||
fillColor: .white.opacity(0.5),
|
||||
bufferColor: .white.opacity(0.2), // <--- buffer color
|
||||
bufferColor: .white.opacity(0.2),
|
||||
emptyColor: .white.opacity(0.3),
|
||||
height: 30,
|
||||
onEditingChanged: { editing in
|
||||
|
|
@ -411,6 +405,20 @@ class CustomMediaPlayerViewController: UIViewController {
|
|||
])
|
||||
}
|
||||
|
||||
|
||||
func addInvisibleControlOverlays() {
|
||||
let playPauseOverlay = UIButton(type: .custom)
|
||||
playPauseOverlay.backgroundColor = .clear
|
||||
playPauseOverlay.addTarget(self, action: #selector(togglePlayPause), for: .touchUpInside)
|
||||
view.addSubview(playPauseOverlay)
|
||||
playPauseOverlay.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
playPauseOverlay.centerXAnchor.constraint(equalTo: playPauseButton.centerXAnchor),
|
||||
playPauseOverlay.centerYAnchor.constraint(equalTo: playPauseButton.centerYAnchor),
|
||||
playPauseOverlay.widthAnchor.constraint(equalTo: playPauseButton.widthAnchor, constant: 20),
|
||||
playPauseOverlay.heightAnchor.constraint(equalTo: playPauseButton.heightAnchor, constant: 20)
|
||||
])
|
||||
}
|
||||
|
||||
func setupSkipAndDismissGestures() {
|
||||
let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap(_:)))
|
||||
|
|
@ -715,7 +723,6 @@ class CustomMediaPlayerViewController: UIViewController {
|
|||
self.currentTimeVal = time.seconds
|
||||
self.duration = currentDuration
|
||||
|
||||
// If user is not dragging the slider, keep it in sync:
|
||||
if !self.isSliderEditing {
|
||||
self.sliderViewModel.sliderValue = max(0, min(self.currentTimeVal, self.duration))
|
||||
}
|
||||
|
|
@ -730,7 +737,6 @@ class CustomMediaPlayerViewController: UIViewController {
|
|||
self.subtitleLabel.text = ""
|
||||
}
|
||||
|
||||
// Rebuild the slider if needed (to ensure the SwiftUI view updates).
|
||||
DispatchQueue.main.async {
|
||||
self.sliderHostingController?.rootView = MusicProgressSlider(
|
||||
value: Binding(get: {
|
||||
|
|
@ -739,24 +745,23 @@ class CustomMediaPlayerViewController: UIViewController {
|
|||
self.sliderViewModel.sliderValue = max(0, min($0, self.duration))
|
||||
}),
|
||||
inRange: 0...(self.duration > 0 ? self.duration : 1.0),
|
||||
bufferValue: self.sliderViewModel.bufferValue, // pass buffer
|
||||
bufferValue: self.sliderViewModel.bufferValue,
|
||||
activeFillColor: .white,
|
||||
fillColor: .white.opacity(0.6),
|
||||
bufferColor: .white.opacity(0.36),
|
||||
emptyColor: .white.opacity(0.3),
|
||||
height: 30,
|
||||
onEditingChanged: { editing in
|
||||
self.isSliderEditing = editing
|
||||
if !editing {
|
||||
let seekTime = CMTime(seconds: self.sliderViewModel.sliderValue,
|
||||
preferredTimescale: 600)
|
||||
self.player.seek(to: seekTime)
|
||||
let targetTime = CMTime(seconds: self.sliderViewModel.sliderValue, preferredTimescale: 600)
|
||||
self.player.seek(to: targetTime) { [weak self] finished in
|
||||
self?.updateBufferValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// Check whether to show/hide "Watch Next" button
|
||||
let isNearEnd = (self.duration - self.currentTimeVal) <= (self.duration * 0.10)
|
||||
&& self.currentTimeVal != self.duration
|
||||
&& self.showWatchNextButton
|
||||
|
|
|
|||
Loading…
Reference in a new issue