mirror of
https://github.com/cranci1/Sora.git
synced 2026-04-21 08:32:00 +00:00
Little hotfix (#120)
* fixed stuffs * OHHHH it was "CURRENT" * now they use UIStackView * subtitle delay maybe * nvm this better * better text
This commit is contained in:
parent
ed6fa24f92
commit
d34099d49d
5 changed files with 131 additions and 70 deletions
|
|
@ -57,7 +57,7 @@ class AniListMutation {
|
||||||
let variables: [String: Any] = [
|
let variables: [String: Any] = [
|
||||||
"mediaId": animeId,
|
"mediaId": animeId,
|
||||||
"progress": episodeNumber,
|
"progress": episodeNumber,
|
||||||
"status": "WATCHING"
|
"status": "CURRENT"
|
||||||
]
|
]
|
||||||
|
|
||||||
let requestBody: [String: Any] = [
|
let requestBody: [String: Any] = [
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,11 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
import MarqueeLabel
|
|
||||||
import AVKit
|
import AVKit
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import AVFoundation
|
|
||||||
import MediaPlayer
|
import MediaPlayer
|
||||||
|
import AVFoundation
|
||||||
|
import MarqueeLabel
|
||||||
|
|
||||||
class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDelegate {
|
class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDelegate {
|
||||||
let module: ScrapingModule
|
let module: ScrapingModule
|
||||||
|
|
@ -71,9 +71,11 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
var subtitleFontSize: Double = 20.0
|
var subtitleFontSize: Double = 20.0
|
||||||
var subtitleShadowRadius: Double = 1.0
|
var subtitleShadowRadius: Double = 1.0
|
||||||
var subtitlesLoader = VTTSubtitlesLoader()
|
var subtitlesLoader = VTTSubtitlesLoader()
|
||||||
|
var subtitleStackView: UIStackView!
|
||||||
|
var subtitleLabels: [UILabel] = []
|
||||||
var subtitlesEnabled: Bool = true {
|
var subtitlesEnabled: Bool = true {
|
||||||
didSet {
|
didSet {
|
||||||
subtitleLabel.isHidden = !subtitlesEnabled
|
subtitleStackView.isHidden = !subtitlesEnabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,7 +85,6 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
var playPauseButton: UIImageView!
|
var playPauseButton: UIImageView!
|
||||||
var backwardButton: UIImageView!
|
var backwardButton: UIImageView!
|
||||||
var forwardButton: UIImageView!
|
var forwardButton: UIImageView!
|
||||||
var subtitleLabel: UILabel!
|
|
||||||
var topSubtitleLabel: UILabel!
|
var topSubtitleLabel: UILabel!
|
||||||
var dismissButton: UIButton!
|
var dismissButton: UIButton!
|
||||||
var menuButton: UIButton!
|
var menuButton: UIButton!
|
||||||
|
|
@ -166,6 +167,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
private var volumeValue: Double = 0.0
|
private var volumeValue: Double = 0.0
|
||||||
private var volumeViewModel = VolumeViewModel()
|
private var volumeViewModel = VolumeViewModel()
|
||||||
var volumeSliderHostingView: UIView?
|
var volumeSliderHostingView: UIView?
|
||||||
|
private var subtitleDelay: Double = 0.0
|
||||||
|
|
||||||
init(module: ScrapingModule,
|
init(module: ScrapingModule,
|
||||||
urlString: String,
|
urlString: String,
|
||||||
|
|
@ -241,8 +243,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
updateSkipButtonsVisibility()
|
updateSkipButtonsVisibility()
|
||||||
setupHoldSpeedIndicator()
|
setupHoldSpeedIndicator()
|
||||||
|
|
||||||
view.bringSubviewToFront(subtitleLabel)
|
view.bringSubviewToFront(subtitleStackView)
|
||||||
view.bringSubviewToFront(topSubtitleLabel)
|
|
||||||
|
|
||||||
AniListMutation().fetchMalID(animeId: aniListID) { [weak self] result in
|
AniListMutation().fetchMalID(animeId: aniListID) { [weak self] result in
|
||||||
switch result {
|
switch result {
|
||||||
|
|
@ -717,48 +718,42 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupSubtitleLabel() {
|
func setupSubtitleLabel() {
|
||||||
subtitleLabel = UILabel()
|
subtitleStackView = UIStackView()
|
||||||
subtitleLabel?.textAlignment = .center
|
subtitleStackView.axis = .vertical
|
||||||
subtitleLabel?.numberOfLines = 0
|
subtitleStackView.alignment = .center
|
||||||
subtitleLabel?.font = UIFont.systemFont(ofSize: CGFloat(subtitleFontSize))
|
subtitleStackView.distribution = .fill
|
||||||
if let subtitleLabel = subtitleLabel {
|
subtitleStackView.spacing = 2
|
||||||
view.addSubview(subtitleLabel)
|
|
||||||
subtitleLabel.translatesAutoresizingMaskIntoConstraints = false
|
if let subtitleStackView = subtitleStackView {
|
||||||
|
view.addSubview(subtitleStackView)
|
||||||
|
subtitleStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
||||||
subtitleBottomToSliderConstraint = subtitleLabel.bottomAnchor.constraint(
|
subtitleBottomToSliderConstraint = subtitleStackView.bottomAnchor.constraint(
|
||||||
equalTo: sliderHostingController?.view.topAnchor ?? view.bottomAnchor,
|
equalTo: sliderHostingController?.view.topAnchor ?? view.bottomAnchor,
|
||||||
constant: -20
|
constant: -20
|
||||||
)
|
)
|
||||||
|
|
||||||
subtitleBottomToSafeAreaConstraint = subtitleLabel.bottomAnchor.constraint(
|
subtitleBottomToSafeAreaConstraint = subtitleStackView.bottomAnchor.constraint(
|
||||||
equalTo: view.safeAreaLayoutGuide.bottomAnchor,
|
equalTo: view.safeAreaLayoutGuide.bottomAnchor,
|
||||||
constant: -subtitleBottomPadding
|
constant: -subtitleBottomPadding
|
||||||
)
|
)
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
subtitleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
subtitleStackView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
||||||
subtitleLabel.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor, constant: 36),
|
subtitleStackView.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor, constant: 36),
|
||||||
subtitleLabel.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor, constant: -36)
|
subtitleStackView.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor, constant: -36)
|
||||||
])
|
])
|
||||||
|
|
||||||
subtitleBottomToSafeAreaConstraint?.isActive = true
|
subtitleBottomToSafeAreaConstraint?.isActive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
topSubtitleLabel = UILabel()
|
for _ in 0..<2 {
|
||||||
topSubtitleLabel?.textAlignment = .center
|
let label = UILabel()
|
||||||
topSubtitleLabel?.numberOfLines = 0
|
label.textAlignment = .center
|
||||||
topSubtitleLabel?.font = UIFont.systemFont(ofSize: CGFloat(subtitleFontSize))
|
label.numberOfLines = 0
|
||||||
topSubtitleLabel?.isHidden = true
|
label.font = UIFont.systemFont(ofSize: CGFloat(subtitleFontSize))
|
||||||
if let topSubtitleLabel = topSubtitleLabel {
|
subtitleLabels.append(label)
|
||||||
view.addSubview(topSubtitleLabel)
|
subtitleStackView.addArrangedSubview(label)
|
||||||
topSubtitleLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
topSubtitleLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
|
||||||
topSubtitleLabel.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 30),
|
|
||||||
topSubtitleLabel.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor, constant: 36),
|
|
||||||
topSubtitleLabel.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor, constant: -36)
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSubtitleLabelAppearance()
|
updateSubtitleLabelAppearance()
|
||||||
|
|
@ -1305,7 +1300,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateSubtitleLabelAppearance() {
|
func updateSubtitleLabelAppearance() {
|
||||||
if let subtitleLabel = subtitleLabel {
|
for subtitleLabel in subtitleLabels {
|
||||||
subtitleLabel.font = UIFont.systemFont(ofSize: CGFloat(subtitleFontSize))
|
subtitleLabel.font = UIFont.systemFont(ofSize: CGFloat(subtitleFontSize))
|
||||||
subtitleLabel.textColor = subtitleUIColor()
|
subtitleLabel.textColor = subtitleUIColor()
|
||||||
subtitleLabel.backgroundColor = subtitleBackgroundEnabled
|
subtitleLabel.backgroundColor = subtitleBackgroundEnabled
|
||||||
|
|
@ -1318,20 +1313,6 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
subtitleLabel.layer.shadowOpacity = 1.0
|
subtitleLabel.layer.shadowOpacity = 1.0
|
||||||
subtitleLabel.layer.shadowOffset = .zero
|
subtitleLabel.layer.shadowOffset = .zero
|
||||||
}
|
}
|
||||||
|
|
||||||
if let topSubtitleLabel = topSubtitleLabel {
|
|
||||||
topSubtitleLabel.font = UIFont.systemFont(ofSize: CGFloat(subtitleFontSize))
|
|
||||||
topSubtitleLabel.textColor = subtitleUIColor()
|
|
||||||
topSubtitleLabel.backgroundColor = subtitleBackgroundEnabled
|
|
||||||
? UIColor.black.withAlphaComponent(0.6)
|
|
||||||
: .clear
|
|
||||||
topSubtitleLabel.layer.cornerRadius = 5
|
|
||||||
topSubtitleLabel.clipsToBounds = true
|
|
||||||
topSubtitleLabel.layer.shadowColor = UIColor.black.cgColor
|
|
||||||
topSubtitleLabel.layer.shadowRadius = CGFloat(subtitleShadowRadius)
|
|
||||||
topSubtitleLabel.layer.shadowOpacity = 1.0
|
|
||||||
topSubtitleLabel.layer.shadowOffset = .zero
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func addTimeObserver() {
|
func addTimeObserver() {
|
||||||
|
|
@ -1360,26 +1341,27 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
UserDefaults.standard.set(self.duration, forKey: "totalTime_\(self.fullUrl)")
|
UserDefaults.standard.set(self.duration, forKey: "totalTime_\(self.fullUrl)")
|
||||||
|
|
||||||
if self.subtitlesEnabled {
|
if self.subtitlesEnabled {
|
||||||
let cues = self.subtitlesLoader.cues.filter { self.currentTimeVal >= $0.startTime && self.currentTimeVal <= $0.endTime }
|
let adjustedTime = self.currentTimeVal - self.subtitleDelay
|
||||||
|
let cues = self.subtitlesLoader.cues.filter { adjustedTime >= $0.startTime && adjustedTime <= $0.endTime }
|
||||||
if cues.count > 0 {
|
if cues.count > 0 {
|
||||||
self.subtitleLabel.text = cues[0].text.strippedHTML
|
self.subtitleLabels[0].text = cues[0].text.strippedHTML
|
||||||
self.subtitleLabel.isHidden = false
|
self.subtitleLabels[0].isHidden = false
|
||||||
} else {
|
} else {
|
||||||
self.subtitleLabel.text = ""
|
self.subtitleLabels[0].text = ""
|
||||||
self.subtitleLabel.isHidden = !self.subtitlesEnabled
|
self.subtitleLabels[0].isHidden = !self.subtitlesEnabled
|
||||||
}
|
}
|
||||||
if cues.count > 1 {
|
if cues.count > 1 {
|
||||||
self.topSubtitleLabel.text = cues[1].text.strippedHTML
|
self.subtitleLabels[1].text = cues[1].text.strippedHTML
|
||||||
self.topSubtitleLabel.isHidden = false
|
self.subtitleLabels[1].isHidden = false
|
||||||
} else {
|
} else {
|
||||||
self.topSubtitleLabel.text = ""
|
self.subtitleLabels[1].text = ""
|
||||||
self.topSubtitleLabel.isHidden = true
|
self.subtitleLabels[1].isHidden = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.subtitleLabel.text = ""
|
self.subtitleLabels[0].text = ""
|
||||||
self.subtitleLabel.isHidden = true
|
self.subtitleLabels[0].isHidden = true
|
||||||
self.topSubtitleLabel.text = ""
|
self.subtitleLabels[1].text = ""
|
||||||
self.topSubtitleLabel.isHidden = true
|
self.subtitleLabels[1].isHidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
let segmentsColor = self.getSegmentsColor()
|
let segmentsColor = self.getSegmentsColor()
|
||||||
|
|
@ -1639,21 +1621,17 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
isDimmed.toggle()
|
isDimmed.toggle()
|
||||||
dimButtonTimer?.invalidate()
|
dimButtonTimer?.invalidate()
|
||||||
|
|
||||||
// animate black overlay
|
|
||||||
UIView.animate(withDuration: 0.25) {
|
UIView.animate(withDuration: 0.25) {
|
||||||
self.blackCoverView.alpha = self.isDimmed ? 1.0 : 0.4
|
self.blackCoverView.alpha = self.isDimmed ? 1.0 : 0.4
|
||||||
}
|
}
|
||||||
|
|
||||||
// fade controls instead of hiding
|
|
||||||
UIView.animate(withDuration: 0.25) {
|
UIView.animate(withDuration: 0.25) {
|
||||||
for view in self.controlsToHide {
|
for view in self.controlsToHide {
|
||||||
view.alpha = self.isDimmed ? 0 : 1
|
view.alpha = self.isDimmed ? 0 : 1
|
||||||
}
|
}
|
||||||
// keep the dim button visible/in front
|
|
||||||
self.dimButton.alpha = self.isDimmed ? 0 : 1
|
self.dimButton.alpha = self.isDimmed ? 0 : 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// swap your trailing constraints on the dim‑button
|
|
||||||
dimButtonToSlider.isActive = !isDimmed
|
dimButtonToSlider.isActive = !isDimmed
|
||||||
dimButtonToRight.isActive = isDimmed
|
dimButtonToRight.isActive = isDimmed
|
||||||
UIView.animate(withDuration: 0.25) { self.view.layoutIfNeeded() }
|
UIView.animate(withDuration: 0.25) { self.view.layoutIfNeeded() }
|
||||||
|
|
@ -1900,7 +1878,6 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
self.switchToQuality(urlString: last)
|
self.switchToQuality(urlString: last)
|
||||||
}
|
}
|
||||||
|
|
||||||
// reveal + animate
|
|
||||||
self.qualityButton.isHidden = false
|
self.qualityButton.isHidden = false
|
||||||
self.qualityButton.menu = self.qualitySelectionMenu()
|
self.qualityButton.menu = self.qualitySelectionMenu()
|
||||||
self.updateMenuButtonConstraints()
|
self.updateMenuButtonConstraints()
|
||||||
|
|
@ -2038,8 +2015,41 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
]
|
]
|
||||||
let paddingMenu = UIMenu(title: "Bottom Padding", children: paddingActions)
|
let paddingMenu = UIMenu(title: "Bottom Padding", children: paddingActions)
|
||||||
|
|
||||||
|
let delayActions = [
|
||||||
|
UIAction(title: "-0.5s") { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.adjustSubtitleDelay(by: -0.5)
|
||||||
|
},
|
||||||
|
UIAction(title: "-0.2s") { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.adjustSubtitleDelay(by: -0.2)
|
||||||
|
},
|
||||||
|
UIAction(title: "+0.2s") { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.adjustSubtitleDelay(by: 0.2)
|
||||||
|
},
|
||||||
|
UIAction(title: "+0.5s") { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.adjustSubtitleDelay(by: 0.5)
|
||||||
|
},
|
||||||
|
UIAction(title: "Custom...") { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
self.presentCustomDelayAlert()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
let resetDelayAction = UIAction(title: "Reset Timing") { [weak self] _ in
|
||||||
|
guard let self = self else { return }
|
||||||
|
SubtitleSettingsManager.shared.update { settings in settings.subtitleDelay = 0.0 }
|
||||||
|
self.subtitleDelay = 0.0
|
||||||
|
self.loadSubtitleSettings()
|
||||||
|
DropManager.shared.showDrop(title: "Subtitle Timing Reset", subtitle: "", duration: 0.5, icon: UIImage(systemName: "clock.arrow.circlepath"))
|
||||||
|
}
|
||||||
|
|
||||||
|
let delayMenu = UIMenu(title: "Subtitle Timing", children: delayActions + [resetDelayAction])
|
||||||
|
|
||||||
let subtitleOptionsMenu = UIMenu(title: "Subtitle Options", children: [
|
let subtitleOptionsMenu = UIMenu(title: "Subtitle Options", children: [
|
||||||
subtitlesToggleAction, colorMenu, fontSizeMenu, shadowMenu, backgroundMenu, paddingMenu
|
subtitlesToggleAction, colorMenu, fontSizeMenu, shadowMenu, backgroundMenu, paddingMenu, delayMenu
|
||||||
])
|
])
|
||||||
|
|
||||||
menuElements = [subtitleOptionsMenu]
|
menuElements = [subtitleOptionsMenu]
|
||||||
|
|
@ -2048,6 +2058,32 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
return UIMenu(title: "", children: menuElements)
|
return UIMenu(title: "", children: menuElements)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func adjustSubtitleDelay(by amount: Double) {
|
||||||
|
let newValue = subtitleDelay + amount
|
||||||
|
let roundedValue = Double(round(newValue * 10) / 10)
|
||||||
|
SubtitleSettingsManager.shared.update { settings in settings.subtitleDelay = roundedValue }
|
||||||
|
self.subtitleDelay = roundedValue
|
||||||
|
self.loadSubtitleSettings()
|
||||||
|
}
|
||||||
|
|
||||||
|
func presentCustomDelayAlert() {
|
||||||
|
let alert = UIAlertController(title: "Enter Custom Delay", message: nil, preferredStyle: .alert)
|
||||||
|
alert.addTextField { textField in
|
||||||
|
textField.placeholder = "Delay in seconds"
|
||||||
|
textField.keyboardType = .decimalPad
|
||||||
|
textField.text = String(format: "%.1f", self.subtitleDelay)
|
||||||
|
}
|
||||||
|
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
|
||||||
|
alert.addAction(UIAlertAction(title: "Done", style: .default) { _ in
|
||||||
|
if let text = alert.textFields?.first?.text, let newDelay = Double(text) {
|
||||||
|
SubtitleSettingsManager.shared.update { settings in settings.subtitleDelay = newDelay }
|
||||||
|
self.subtitleDelay = newDelay
|
||||||
|
self.loadSubtitleSettings()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
present(alert, animated: true)
|
||||||
|
}
|
||||||
|
|
||||||
func presentCustomPaddingAlert() {
|
func presentCustomPaddingAlert() {
|
||||||
let alert = UIAlertController(title: "Enter Custom Padding", message: nil, preferredStyle: .alert)
|
let alert = UIAlertController(title: "Enter Custom Padding", message: nil, preferredStyle: .alert)
|
||||||
alert.addTextField { textField in
|
alert.addTextField { textField in
|
||||||
|
|
@ -2095,6 +2131,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
self.subtitleShadowRadius = settings.shadowRadius
|
self.subtitleShadowRadius = settings.shadowRadius
|
||||||
self.subtitleBackgroundEnabled = settings.backgroundEnabled
|
self.subtitleBackgroundEnabled = settings.backgroundEnabled
|
||||||
self.subtitleBottomPadding = settings.bottomPadding
|
self.subtitleBottomPadding = settings.bottomPadding
|
||||||
|
self.subtitleDelay = settings.subtitleDelay
|
||||||
}
|
}
|
||||||
|
|
||||||
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
||||||
|
|
@ -2178,7 +2215,7 @@ class CustomMediaPlayerViewController: UIViewController, UIGestureRecognizerDele
|
||||||
self.holdSpeedIndicator.alpha = 0.8
|
self.holdSpeedIndicator.alpha = 0.8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func endHoldSpeed() {
|
private func endHoldSpeed() {
|
||||||
player?.rate = originalRate
|
player?.rate = originalRate
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ struct SubtitleSettings: Codable {
|
||||||
var shadowRadius: Double = 1.0
|
var shadowRadius: Double = 1.0
|
||||||
var backgroundEnabled: Bool = true
|
var backgroundEnabled: Bool = true
|
||||||
var bottomPadding: CGFloat = 20.0
|
var bottomPadding: CGFloat = 20.0
|
||||||
|
var subtitleDelay: Double = 0.0
|
||||||
}
|
}
|
||||||
|
|
||||||
class SubtitleSettingsManager {
|
class SubtitleSettingsManager {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
@preconcurrency import WebKit
|
import WebKit
|
||||||
|
|
||||||
private struct ModuleLink: Identifiable {
|
private struct ModuleLink: Identifiable {
|
||||||
let id = UUID()
|
let id = UUID()
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,7 @@ struct SubtitleSettingsSection: View {
|
||||||
@State private var shadowRadius: Double = SubtitleSettingsManager.shared.settings.shadowRadius
|
@State private var shadowRadius: Double = SubtitleSettingsManager.shared.settings.shadowRadius
|
||||||
@State private var backgroundEnabled: Bool = SubtitleSettingsManager.shared.settings.backgroundEnabled
|
@State private var backgroundEnabled: Bool = SubtitleSettingsManager.shared.settings.backgroundEnabled
|
||||||
@State private var bottomPadding: CGFloat = SubtitleSettingsManager.shared.settings.bottomPadding
|
@State private var bottomPadding: CGFloat = SubtitleSettingsManager.shared.settings.bottomPadding
|
||||||
|
@State private var subtitleDelay: Double = SubtitleSettingsManager.shared.settings.subtitleDelay
|
||||||
|
|
||||||
private let colors = ["white", "yellow", "green", "blue", "red", "purple"]
|
private let colors = ["white", "yellow", "green", "blue", "red", "purple"]
|
||||||
private let shadowOptions = [0, 1, 3, 6]
|
private let shadowOptions = [0, 1, 3, 6]
|
||||||
|
|
@ -186,6 +187,28 @@ struct SubtitleSettingsSection: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VStack(alignment: .leading) {
|
||||||
|
Text("Subtitle Delay: \(String(format: "%.1fs", subtitleDelay))")
|
||||||
|
.padding(.bottom, 1)
|
||||||
|
|
||||||
|
HStack {
|
||||||
|
Text("-10s")
|
||||||
|
.font(.system(size: 12))
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
|
||||||
|
Slider(value: $subtitleDelay, in: -10...10, step: 0.1)
|
||||||
|
.onChange(of: subtitleDelay) { newValue in
|
||||||
|
SubtitleSettingsManager.shared.update { settings in
|
||||||
|
settings.subtitleDelay = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text("+10s")
|
||||||
|
.font(.system(size: 12))
|
||||||
|
.foregroundColor(.secondary)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue