mirror of
https://github.com/cranci1/Sora.git
synced 2026-03-11 17:45:37 +00:00
i despise unclean merges 🙏 (also heres ur fidget spinner) (#83)
This commit is contained in:
parent
ad07457cf7
commit
f512faba06
2 changed files with 79 additions and 50 deletions
|
|
@ -61,23 +61,18 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
|
||||
private var isDoubleTapSkipEnabled: Bool {
|
||||
if UserDefaults.standard.object(forKey: "doubleTapSeekEnabled") == nil {
|
||||
return true
|
||||
return false
|
||||
}
|
||||
return UserDefaults.standard.bool(forKey: "doubleTapSeekEnabled")
|
||||
}
|
||||
|
||||
var showWatchNextButton = true
|
||||
var watchNextButtonTimer: Timer?
|
||||
var isWatchNextRepositioned: Bool = false
|
||||
var isWatchNextVisible: Bool = false
|
||||
var lastDuration: Double = 0.0
|
||||
var watchNextButtonAppearedAt: Double?
|
||||
|
||||
var portraitButtonVisibleConstraints: [NSLayoutConstraint] = []
|
||||
var portraitButtonHiddenConstraints: [NSLayoutConstraint] = []
|
||||
var landscapeButtonVisibleConstraints: [NSLayoutConstraint] = []
|
||||
var landscapeButtonHiddenConstraints: [NSLayoutConstraint] = []
|
||||
var currentMarqueeConstraints: [NSLayoutConstraint] = []
|
||||
private var currentMenuButtonTrailing: NSLayoutConstraint!
|
||||
|
||||
|
||||
var subtitleForegroundColor: String = "white"
|
||||
var subtitleBackgroundEnabled: Bool = true
|
||||
|
|
@ -287,6 +282,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
} else {
|
||||
marqueeLabel.lineBreakMode = .byClipping
|
||||
}
|
||||
updateMenuButtonConstraints()
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
|
|
@ -336,8 +332,17 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if self.qualityButton.isHidden && self.isHLSStream {
|
||||
// 1) reveal the quality button
|
||||
self.qualityButton.isHidden = false
|
||||
self.qualityButton.menu = self.qualitySelectionMenu()
|
||||
|
||||
// 2) update the trailing constraint for the menuButton
|
||||
self.updateMenuButtonConstraints()
|
||||
|
||||
// 3) animate the shift
|
||||
UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseInOut) {
|
||||
self.view.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -420,7 +425,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
|
||||
let playPauseTap = UITapGestureRecognizer(target: self, action: #selector(togglePlayPause))
|
||||
playPauseTap.delaysTouchesBegan = false
|
||||
playPauseTap.delegate = self // Ensure you return true in shouldRecognizeSimultaneouslyWith
|
||||
playPauseTap.delegate = self
|
||||
playPauseButton.addGestureRecognizer(playPauseTap)
|
||||
|
||||
|
||||
|
|
@ -809,10 +814,11 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
|
||||
NSLayoutConstraint.activate([
|
||||
menuButton.topAnchor.constraint(equalTo: qualityButton.topAnchor),
|
||||
menuButton.trailingAnchor.constraint(equalTo: qualityButton.leadingAnchor, constant: -6),
|
||||
menuButton.widthAnchor.constraint(equalToConstant: 40),
|
||||
menuButton.heightAnchor.constraint(equalToConstant: 40)
|
||||
menuButton.heightAnchor.constraint(equalToConstant: 40),
|
||||
])
|
||||
|
||||
currentMenuButtonTrailing = menuButton.trailingAnchor.constraint(equalTo: qualityButton.leadingAnchor, constant: -6)
|
||||
}
|
||||
|
||||
func setupSpeedButton() {
|
||||
|
|
@ -916,11 +922,11 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
qualityButton.menu = qualitySelectionMenu()
|
||||
qualityButton.isHidden = true
|
||||
|
||||
speedButton.layer.shadowColor = UIColor.black.cgColor
|
||||
speedButton.layer.shadowOffset = CGSize(width: 0, height: 2)
|
||||
speedButton.layer.shadowOpacity = 0.6
|
||||
speedButton.layer.shadowRadius = 4
|
||||
speedButton.layer.masksToBounds = false
|
||||
qualityButton.layer.shadowColor = UIColor.black.cgColor
|
||||
qualityButton.layer.shadowOffset = CGSize(width: 0, height: 2)
|
||||
qualityButton.layer.shadowOpacity = 0.6
|
||||
qualityButton.layer.shadowRadius = 4
|
||||
qualityButton.layer.masksToBounds = false
|
||||
|
||||
controlsContainerView.addSubview(qualityButton)
|
||||
qualityButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
|
|
@ -1040,37 +1046,9 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
}
|
||||
)
|
||||
}
|
||||
|
||||
let isNearEnd = (self.duration - self.currentTimeVal) <= (self.duration * 0.10)
|
||||
&& self.currentTimeVal != self.duration
|
||||
&& self.showWatchNextButton
|
||||
&& self.duration != 0
|
||||
|
||||
|
||||
if isNearEnd {
|
||||
if !self.isWatchNextVisible {
|
||||
self.watchNextButtonAppearedAt = self.currentTimeVal
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func repositionWatchNextButton() {
|
||||
self.isWatchNextRepositioned = true
|
||||
UIView.animate(withDuration: 0.3, animations: {
|
||||
NSLayoutConstraint.deactivate(self.watchNextButtonNormalConstraints)
|
||||
NSLayoutConstraint.activate(self.watchNextButtonControlsConstraints)
|
||||
self.view.layoutIfNeeded()
|
||||
self.watchNextButton.alpha = 0.0
|
||||
}, completion: { _ in
|
||||
self.watchNextButton.isHidden = true
|
||||
})
|
||||
self.watchNextButtonTimer?.invalidate()
|
||||
self.watchNextButtonTimer = nil
|
||||
}
|
||||
|
||||
func startUpdateTimer() {
|
||||
updateTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in
|
||||
|
|
@ -1079,6 +1057,25 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
}
|
||||
}
|
||||
|
||||
func updateMenuButtonConstraints() {
|
||||
// tear down last one
|
||||
currentMenuButtonTrailing.isActive = false
|
||||
|
||||
// pick the “next” visible control
|
||||
let anchor: NSLayoutXAxisAnchor
|
||||
if !qualityButton.isHidden {
|
||||
anchor = qualityButton.leadingAnchor
|
||||
} else if !speedButton.isHidden {
|
||||
anchor = speedButton.leadingAnchor
|
||||
} else {
|
||||
anchor = controlsContainerView.trailingAnchor
|
||||
}
|
||||
|
||||
// rebuild & activate
|
||||
currentMenuButtonTrailing = menuButton.trailingAnchor.constraint(equalTo: anchor, constant: -6)
|
||||
currentMenuButtonTrailing.isActive = true
|
||||
}
|
||||
|
||||
@objc func toggleControls() {
|
||||
isControlsVisible.toggle()
|
||||
UIView.animate(withDuration: 0.2, delay: 0, options: .curveEaseInOut, animations: {
|
||||
|
|
@ -1096,6 +1093,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
player.seek(to: CMTime(seconds: currentTimeVal, preferredTimescale: 600)) { [weak self] finished in
|
||||
guard self != nil else { return }
|
||||
}
|
||||
animateButtonRotation(backwardButton, clockwise: false)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1107,6 +1105,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
player.seek(to: CMTime(seconds: currentTimeVal, preferredTimescale: 600)) { [weak self] finished in
|
||||
guard self != nil else { return }
|
||||
}
|
||||
animateButtonRotation(forwardButton)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1117,6 +1116,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
player.seek(to: CMTime(seconds: currentTimeVal, preferredTimescale: 600)) { [weak self] finished in
|
||||
guard self != nil else { return }
|
||||
}
|
||||
animateButtonRotation(backwardButton, clockwise: false)
|
||||
}
|
||||
|
||||
@objc func seekForward() {
|
||||
|
|
@ -1125,6 +1125,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
currentTimeVal = min(currentTimeVal + finalSkip, duration)
|
||||
player.seek(to: CMTime(seconds: currentTimeVal, preferredTimescale: 600)) { [weak self] finished in
|
||||
guard self != nil else { return } }
|
||||
animateButtonRotation(forwardButton)
|
||||
}
|
||||
|
||||
@objc func handleDoubleTap(_ gesture: UITapGestureRecognizer) {
|
||||
|
|
@ -1240,6 +1241,30 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
}
|
||||
}
|
||||
|
||||
private func animateButtonRotation(_ button: UIView, clockwise: Bool = true) {
|
||||
if button.layer.animation(forKey: "rotate360") != nil {
|
||||
return
|
||||
}
|
||||
button.superview?.layoutIfNeeded()
|
||||
|
||||
button.layer.shouldRasterize = true
|
||||
button.layer.rasterizationScale = UIScreen.main.scale
|
||||
button.layer.allowsEdgeAntialiasing = true
|
||||
|
||||
let rotation = CABasicAnimation(keyPath: "transform.rotation.z")
|
||||
rotation.fromValue = 0
|
||||
rotation.toValue = CGFloat.pi * 2 * (clockwise ? 1 : -1)
|
||||
rotation.duration = 0.43
|
||||
rotation.timingFunction = CAMediaTimingFunction(name: .linear)
|
||||
|
||||
button.layer.add(rotation, forKey: "rotate360")
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + rotation.duration) {
|
||||
button.layer.shouldRasterize = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func parseM3U8(url: URL, completion: @escaping () -> Void) {
|
||||
var request = URLRequest(url: url)
|
||||
request.addValue("\(module.metadata.baseUrl)", forHTTPHeaderField: "Referer")
|
||||
|
|
@ -1403,19 +1428,23 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
|||
|
||||
parseM3U8(url: url) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
if let lastSelectedQuality = UserDefaults.standard.string(forKey: "lastSelectedQuality"),
|
||||
self.qualities.contains(where: { $0.1 == lastSelectedQuality }) {
|
||||
self.switchToQuality(urlString: lastSelectedQuality)
|
||||
if let last = UserDefaults.standard.string(forKey: "lastSelectedQuality"),
|
||||
self.qualities.contains(where: { $0.1 == last }) {
|
||||
self.switchToQuality(urlString: last)
|
||||
}
|
||||
|
||||
// reveal + animate
|
||||
self.qualityButton.isHidden = false
|
||||
self.qualityButton.menu = self.qualitySelectionMenu()
|
||||
self.updateMarqueeConstraints()
|
||||
self.updateMenuButtonConstraints()
|
||||
UIView.animate(withDuration: 0.25, delay: 0, options: .curveEaseInOut) {
|
||||
self.view.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
isHLSStream = false
|
||||
qualityButton.isHidden = true
|
||||
updateMenuButtonConstraints()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ struct SettingsViewPlayer: View {
|
|||
@AppStorage("skipIncrementHold") private var skipIncrementHold: Double = 30.0
|
||||
@AppStorage("holdForPauseEnabled") private var holdForPauseEnabled = false
|
||||
@AppStorage("skip85Visible") private var skip85Visible: Bool = true
|
||||
@AppStorage("doubleTapSeekEnabled") private var doubleTapSeekEnabled: Bool = true
|
||||
@AppStorage("doubleTapSeekEnabled") private var doubleTapSeekEnabled: Bool = false
|
||||
|
||||
|
||||
private let mediaPlayers = ["Default", "VLC", "OutPlayer", "Infuse", "nPlayer", "Sora"]
|
||||
|
|
|
|||
Loading…
Reference in a new issue