yattee/Shared/Settings/QualitySettings.swift

212 lines
7.4 KiB
Swift
Raw Normal View History

2022-08-14 17:06:22 +00:00
import Defaults
import SwiftUI
struct QualitySettings: View {
@State private var presentingProfileForm = false
2022-08-14 22:15:18 +00:00
@State private var editedProfileID: QualityProfile.ID?
2022-08-14 17:06:22 +00:00
@EnvironmentObject<SettingsModel> private var settings
2022-08-14 17:06:22 +00:00
@Default(.qualityProfiles) private var qualityProfiles
2022-08-14 17:06:22 +00:00
@Default(.batteryCellularProfile) private var batteryCellularProfile
@Default(.batteryNonCellularProfile) private var batteryNonCellularProfile
@Default(.chargingCellularProfile) private var chargingCellularProfile
@Default(.chargingNonCellularProfile) private var chargingNonCellularProfile
@Default(.forceAVPlayerForLiveStreams) private var forceAVPlayerForLiveStreams
2022-08-14 17:06:22 +00:00
var body: some View {
VStack(alignment: .leading) {
2022-08-14 17:06:22 +00:00
#if os(macOS)
sections
Spacer()
#else
List {
sections
}
#endif
}
.sheet(isPresented: $presentingProfileForm) {
2022-08-14 22:15:18 +00:00
QualityProfileForm(qualityProfileID: $editedProfileID)
2022-08-14 17:06:22 +00:00
}
#if os(tvOS)
.frame(maxWidth: 1000)
#elseif os(iOS)
.listStyle(.insetGrouped)
#endif
.navigationTitle("Quality")
}
var sections: some View {
Group {
Group {
#if os(tvOS)
Section(header: Text("Default Profile")) {
Text("\(QualityProfilesModel.shared.tvOSProfile?.description ?? "None")")
}
#elseif os(iOS)
if UIDevice.current.hasCellularCapabilites {
Section(header: Text("Battery")) {
Picker("Wi-Fi", selection: $batteryNonCellularProfile) { profilePickerOptions }
Picker("Cellular", selection: $batteryCellularProfile) { profilePickerOptions }
}
Section(header: Text("Charging")) {
Picker("Wi-Fi", selection: $chargingNonCellularProfile) { profilePickerOptions }
Picker("Cellular", selection: $chargingCellularProfile) { profilePickerOptions }
}
} else {
nonCellularBatteryDevicesProfilesPickers
}
#else
if Power.hasInternalBattery {
nonCellularBatteryDevicesProfilesPickers
} else {
Picker("Default", selection: $chargingNonCellularProfile) { profilePickerOptions }
}
#endif
forceAVPlayerForLiveStreamsToggle
2022-08-14 17:06:22 +00:00
}
.disabled(qualityProfiles.isEmpty)
Section(header: SettingsHeader(text: "Profiles"), footer: profilesFooter) {
profilesList
Button {
2022-08-14 22:15:18 +00:00
editedProfileID = nil
2022-08-14 17:06:22 +00:00
presentingProfileForm = true
} label: {
Label("Add profile...", systemImage: "plus")
}
}
.frame(maxWidth: .infinity, alignment: .leading)
HStack {
Button {
settings.presentAlert(
Alert(
title: Text("Are you sure you want to restore default quality profiles?"),
message: Text("This will remove all your custom profiles and return their default values. This cannot be reverted."),
primaryButton: .destructive(Text("Reset")) {
QualityProfilesModel.shared.reset()
},
secondaryButton: .cancel()
)
)
} label: {
Text("Restore default profiles...")
.foregroundColor(.red)
}
Spacer()
}
2022-08-14 17:06:22 +00:00
}
}
@ViewBuilder var nonCellularBatteryDevicesProfilesPickers: some View {
Picker("Battery", selection: $batteryNonCellularProfile) { profilePickerOptions }
Picker("Charging", selection: $chargingNonCellularProfile) { profilePickerOptions }
}
@ViewBuilder var forceAVPlayerForLiveStreamsToggle: some View {
Toggle("Always use AVPlayer for live videos", isOn: $forceAVPlayerForLiveStreams)
}
2022-08-14 17:06:22 +00:00
@ViewBuilder func profileControl(_ qualityProfile: QualityProfile) -> some View {
#if os(tvOS)
Button {
QualityProfilesModel.shared.applyToAll(qualityProfile)
} label: {
Text(qualityProfile.description)
}
#else
Text(qualityProfile.description)
#endif
}
var profilePickerOptions: some View {
ForEach(qualityProfiles) { qualityProfile in
Text(qualityProfile.description).tag(qualityProfile.id)
}
}
var profilesFooter: some View {
#if os(tvOS)
Text("You can switch between profiles in playback settings controls.")
#else
Text("You can use automatic profile selection based on current device status or switch it in video playback settings controls.")
.foregroundColor(.secondary)
#endif
}
@ViewBuilder var profilesList: some View {
let list = ForEach(qualityProfiles) { qualityProfile in
profileControl(qualityProfile)
.contextMenu {
Button {
QualityProfilesModel.shared.applyToAll(qualityProfile)
} label: {
#if os(tvOS)
Text("Make default")
#elseif os(iOS)
Label("Apply to all", systemImage: "wand.and.stars")
#else
if Power.hasInternalBattery {
Text("Apply to all")
} else {
Text("Make default")
}
#endif
}
Button {
2022-08-14 22:15:18 +00:00
editedProfileID = qualityProfile.id
2022-08-14 17:06:22 +00:00
presentingProfileForm = true
} label: {
Label("Edit...", systemImage: "pencil")
}
Button {
QualityProfilesModel.shared.remove(qualityProfile)
} label: {
Label("Remove", systemImage: "trash")
}
#if os(tvOS)
Button("Cancel", role: .cancel) {}
#endif
}
}
if #available(macOS 12.0, *) {
#if os(macOS)
List {
list
}
.listStyle(.inset(alternatesRowBackgrounds: true))
#else
list
#endif
} else {
#if os(macOS)
List {
list
}
#else
list
#endif
}
}
}
struct QualitySettings_Previews: PreviewProvider {
static var previews: some View {
#if os(macOS)
QualitySettings()
#else
NavigationView {
EmptyView()
QualitySettings()
}
.navigationViewStyle(.stack)
#endif
}
}