not great

This commit is contained in:
Seiike 2025-04-03 22:34:47 +02:00
parent 2711cafc93
commit 78a5660bed
3 changed files with 183 additions and 1 deletions

View file

@ -0,0 +1,137 @@
//
// VerticalVolumeSlider.swift
// Custom Seekbar
//
// Created by Pratik on 08/01/23.
// Modified to update screen brightness when used as a brightness slider.
//
import SwiftUI
struct VerticalVolumeSlider<T: BinaryFloatingPoint>: View {
@Binding var value: T
let inRange: ClosedRange<T>
let activeFillColor: Color
let fillColor: Color
let emptyColor: Color
let width: CGFloat
let onEditingChanged: (Bool) -> Void
// private variables
@State private var localRealProgress: T = 0
@State private var localTempProgress: T = 0
@GestureState private var isActive: Bool = false
var body: some View {
GeometryReader { bounds in
ZStack {
GeometryReader { geo in
ZStack(alignment: .bottom) {
RoundedRectangle(cornerRadius: isActive ? width : width/2, style: .continuous)
.fill(emptyColor)
RoundedRectangle(cornerRadius: isActive ? width : width/2, style: .continuous)
.fill(isActive ? activeFillColor : fillColor)
.mask({
VStack {
Spacer(minLength: 0)
Rectangle()
.frame(height: max(geo.size.height * CGFloat((localRealProgress + localTempProgress)), 0),
alignment: .leading)
}
})
Image(systemName: getIconName)
.font(.system(size: 16, weight: .medium, design: .rounded))
.foregroundColor(fillColor)
.animation(.spring(), value: localRealProgress)
.frame(maxHeight: .infinity, alignment: .bottom)
.padding(.bottom)
.overlay {
Image(systemName: getIconName)
.font(.system(size: 16, weight: .medium, design: .rounded))
.foregroundColor(.gray)
.animation(.spring(), value: localRealProgress)
.frame(maxHeight: .infinity, alignment: .bottom)
.padding(.bottom)
.mask {
VStack {
Spacer(minLength: 0)
Rectangle()
.frame(height: max(geo.size.height * CGFloat((localRealProgress + localTempProgress)), 0),
alignment: .leading)
}
}
}
.frame(maxWidth: isActive ? .infinity : 0)
.opacity(isActive ? 1 : 0)
}
.clipped()
}
.frame(height: isActive ? bounds.size.height * 1.15 : bounds.size.height, alignment: .center)
// .shadow(color: .black.opacity(0.1), radius: isActive ? 20 : 0, x: 0, y: 0)
.animation(animation, value: isActive)
}
.frame(width: bounds.size.width, height: bounds.size.height, alignment: .center)
.gesture(DragGesture(minimumDistance: 0, coordinateSpace: .local)
.updating($isActive) { value, state, transaction in
state = true
}
.onChanged { gesture in
localTempProgress = T(-gesture.translation.height / bounds.size.height)
value = max(min(getPrgValue(), inRange.upperBound), inRange.lowerBound)
}
.onEnded { _ in
localRealProgress = max(min(localRealProgress + localTempProgress, 1), 0)
localTempProgress = 0
}
)
.onChange(of: isActive) { newValue in
value = max(min(getPrgValue(), inRange.upperBound), inRange.lowerBound)
onEditingChanged(newValue)
}
.onAppear {
localRealProgress = getPrgPercentage(value)
}
.onChange(of: value) { newValue in
if !isActive {
localRealProgress = getPrgPercentage(newValue)
}
}
}
.frame(width: isActive ? width * 4 : width, alignment: .center)
.offset(x: isActive ? -10 : 0)
.onChange(of: value) { newValue in
UIScreen.main.brightness = CGFloat(newValue)
}
}
private var getIconName: String {
var name = "speaker.wave."
switch CGFloat((localRealProgress + localTempProgress)) {
case ..<0.01:
name = "speaker.slash.fill"
case ..<0.3:
name += "1.fill"
case ..<0.6:
name += "2.fill"
default:
name += "3.fill"
}
return name
}
private var animation: Animation {
return .spring()
}
private func getPrgPercentage(_ value: T) -> T {
let range = inRange.upperBound - inRange.lowerBound
let correctedStartValue = value - inRange.lowerBound
let percentage = correctedStartValue / range
return percentage
}
private func getPrgValue() -> T {
return ((localRealProgress + localTempProgress) * (inRange.upperBound - inRange.lowerBound)) + inRange.lowerBound
}
}

View file

@ -40,8 +40,11 @@ class CustomMediaPlayerViewController: UIViewController {
var currentTimeVal: Double = 0.0
var duration: Double = 0.0
var isVideoLoaded = false
var showWatchNextButton = true
var brightnessValue: Double = Double(UIScreen.main.brightness)
var brightnessSliderHostingController: UIHostingController<VerticalVolumeSlider<Double>>?
var showWatchNextButton = true
var watchNextButtonTimer: Timer?
var isWatchNextRepositioned: Bool = false
var isWatchNextVisible: Bool = false
@ -151,6 +154,7 @@ class CustomMediaPlayerViewController: UIViewController {
loadSubtitleSettings()
setupPlayerViewController()
setupControls()
brightnessControl()
setupSkipAndDismissGestures()
addInvisibleControlOverlays()
setupSubtitleLabel()
@ -406,6 +410,43 @@ class CustomMediaPlayerViewController: UIViewController {
}
func brightnessControl() {
let brightnessSlider = VerticalVolumeSlider(
value: Binding(
get: { self.brightnessValue },
set: { newValue in
self.brightnessValue = newValue
// No need to update UIScreen.main.brightness here since it's handled inside VerticalVolumeSlider.
}
),
inRange: 0...1,
activeFillColor: .white, // Preserves original active color
fillColor: .white.opacity(0.5), // Preserves original fill color
emptyColor: .white.opacity(0.3), // Preserves original empty color
width: 15, // Keeps the original width and corner style
onEditingChanged: { editing in
// Optionally handle editing events here.
}
)
// Embed the slider in a UIHostingController.
brightnessSliderHostingController = UIHostingController(rootView: brightnessSlider)
guard let brightnessSliderView = brightnessSliderHostingController?.view else { return }
brightnessSliderView.backgroundColor = .clear
brightnessSliderView.translatesAutoresizingMaskIntoConstraints = false
controlsContainerView.addSubview(brightnessSliderView)
// Position the slider on the left side of the player while preserving its original appearance.
NSLayoutConstraint.activate([
brightnessSliderView.leadingAnchor.constraint(equalTo: controlsContainerView.leadingAnchor, constant: -10),
brightnessSliderView.centerYAnchor.constraint(equalTo: controlsContainerView.centerYAnchor),
brightnessSliderView.widthAnchor.constraint(equalToConstant: 15), // Match the slider's defined width
brightnessSliderView.heightAnchor.constraint(equalToConstant: 170) // Adjust height to properly display the slider
])
}
func addInvisibleControlOverlays() {
let playPauseOverlay = UIButton(type: .custom)
playPauseOverlay.backgroundColor = .clear

View file

@ -62,6 +62,7 @@
13EA2BD52D32D97400C1EBD7 /* CustomPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13EA2BD12D32D97400C1EBD7 /* CustomPlayer.swift */; };
13EA2BD62D32D97400C1EBD7 /* Double+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13EA2BD32D32D97400C1EBD7 /* Double+Extension.swift */; };
13EA2BD92D32D98400C1EBD7 /* NormalPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13EA2BD82D32D98400C1EBD7 /* NormalPlayer.swift */; };
1E3F5EC82D9F16B7003F310F /* VerticalVolumeSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E3F5EC72D9F16B7003F310F /* VerticalVolumeSlider.swift */; };
1E9FF1D32D403E49008AC100 /* SettingsViewLoggerFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9FF1D22D403E42008AC100 /* SettingsViewLoggerFilter.swift */; };
1EAC7A322D888BC50083984D /* MusicProgressSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EAC7A312D888BC50083984D /* MusicProgressSlider.swift */; };
73D164D52D8B5B470011A360 /* JavaScriptCore+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73D164D42D8B5B340011A360 /* JavaScriptCore+Extensions.swift */; };
@ -123,6 +124,7 @@
13EA2BD12D32D97400C1EBD7 /* CustomPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomPlayer.swift; sourceTree = "<group>"; };
13EA2BD32D32D97400C1EBD7 /* Double+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Double+Extension.swift"; sourceTree = "<group>"; };
13EA2BD82D32D98400C1EBD7 /* NormalPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NormalPlayer.swift; sourceTree = "<group>"; };
1E3F5EC72D9F16B7003F310F /* VerticalVolumeSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerticalVolumeSlider.swift; sourceTree = "<group>"; };
1E9FF1D22D403E42008AC100 /* SettingsViewLoggerFilter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewLoggerFilter.swift; sourceTree = "<group>"; };
1EAC7A312D888BC50083984D /* MusicProgressSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MusicProgressSlider.swift; sourceTree = "<group>"; };
73D164D42D8B5B340011A360 /* JavaScriptCore+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "JavaScriptCore+Extensions.swift"; sourceTree = "<group>"; };
@ -440,6 +442,7 @@
13EA2BD22D32D97400C1EBD7 /* Components */ = {
isa = PBXGroup;
children = (
1E3F5EC72D9F16B7003F310F /* VerticalVolumeSlider.swift */,
13EA2BD32D32D97400C1EBD7 /* Double+Extension.swift */,
1EAC7A312D888BC50083984D /* MusicProgressSlider.swift */,
);
@ -571,6 +574,7 @@
133D7C6E2D2BE2500075467E /* SoraApp.swift in Sources */,
138AA1B92D2D66FD0021F9DF /* CircularProgressBar.swift in Sources */,
1334FF4D2D786C93007E289F /* TMDB-Seasonal.swift in Sources */,
1E3F5EC82D9F16B7003F310F /* VerticalVolumeSlider.swift in Sources */,
13DB468D2D90093A008CBC03 /* Anilist-Login.swift in Sources */,
73D164D52D8B5B470011A360 /* JavaScriptCore+Extensions.swift in Sources */,
132AF1232D9995C300A0140B /* JSController-Details.swift in Sources */,