mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 21:43:41 +00:00
Minor controls improvements
This commit is contained in:
parent
cb89c4d53d
commit
7a6698897a
@ -1,5 +1,5 @@
|
||||
import CoreMedia
|
||||
import AVFAudio
|
||||
import CoreMedia
|
||||
import Defaults
|
||||
import Foundation
|
||||
|
||||
@ -34,7 +34,6 @@ extension PlayerModel {
|
||||
if let duration = playerItemDuration, segment.endTime.seconds >= duration.seconds - 3 {
|
||||
logger.error("segment end time is: \(segment.end) when player item duration is: \(duration.seconds)")
|
||||
|
||||
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else {
|
||||
return
|
||||
|
@ -164,6 +164,22 @@ class Stream: Equatable, Hashable, Identifiable {
|
||||
return kind == .hls ? "adaptive (HLS)" : "\(resolution.name)\(kind == .stream ? " (\(kind.rawValue))" : "")"
|
||||
}
|
||||
|
||||
var shortQuality: String {
|
||||
if resolution == .hd4320p60 || resolution == .hd4320p {
|
||||
return "8K"
|
||||
} else if resolution == .hd2160p60 ||
|
||||
resolution == .hd2160p50 ||
|
||||
resolution == .hd2160p48 ||
|
||||
resolution == .hd2160p
|
||||
{
|
||||
return "4K"
|
||||
} else if kind == .hls {
|
||||
return "HLS"
|
||||
} else {
|
||||
return resolution.name
|
||||
}
|
||||
}
|
||||
|
||||
var description: String {
|
||||
let formatString = format == .unknown ? "" : " (\(format.rawValue))"
|
||||
return "\(quality)\(formatString) - \(instance?.description ?? "")"
|
||||
|
@ -30,26 +30,17 @@ struct PlayerControls: View {
|
||||
var body: some View {
|
||||
VStack {
|
||||
ZStack(alignment: .bottom) {
|
||||
VStack(spacing: 0) {
|
||||
Group {
|
||||
HStack {
|
||||
statusBar
|
||||
.lineLimit(1)
|
||||
.padding(3)
|
||||
#if os(macOS)
|
||||
.background(VisualEffectBlur(material: .hudWindow))
|
||||
#elseif os(iOS)
|
||||
.background(VisualEffectBlur(blurStyle: .systemThinMaterial))
|
||||
#endif
|
||||
.mask(RoundedRectangle(cornerRadius: 3))
|
||||
|
||||
Spacer()
|
||||
}
|
||||
|
||||
VStack(alignment: .trailing, spacing: 4) {
|
||||
#if !os(tvOS)
|
||||
buttonsBar
|
||||
.padding(.top, 4)
|
||||
.padding(.horizontal, 4)
|
||||
|
||||
HStack(spacing: 4) {
|
||||
qualityButton
|
||||
backendButton
|
||||
}
|
||||
#else
|
||||
Text(player.stream?.description ?? "")
|
||||
#endif
|
||||
|
||||
Spacer()
|
||||
|
||||
@ -77,6 +68,8 @@ struct PlayerControls: View {
|
||||
.padding(.horizontal, 16)
|
||||
}
|
||||
}
|
||||
.padding(.top, 4)
|
||||
.padding(.horizontal, 4)
|
||||
.opacity(model.presentingControls ? 1 : 0)
|
||||
}
|
||||
#if os(tvOS)
|
||||
@ -128,29 +121,6 @@ struct PlayerControls: View {
|
||||
)
|
||||
}
|
||||
|
||||
var statusBar: some View {
|
||||
HStack(spacing: 4) {
|
||||
Text(playbackStatus)
|
||||
|
||||
Text("•")
|
||||
|
||||
#if !os(tvOS)
|
||||
ToggleBackendButton()
|
||||
Text("•")
|
||||
|
||||
StreamControl()
|
||||
#if os(macOS)
|
||||
.frame(maxWidth: 300)
|
||||
#endif
|
||||
#else
|
||||
Text(player.stream?.description ?? "")
|
||||
#endif
|
||||
}
|
||||
.foregroundColor(.primary)
|
||||
.padding(.trailing, 4)
|
||||
.font(.system(size: 14))
|
||||
}
|
||||
|
||||
private var hidePlayerButton: some View {
|
||||
button("Hide", systemImage: "chevron.down") {
|
||||
player.hide()
|
||||
@ -256,6 +226,45 @@ struct PlayerControls: View {
|
||||
#endif
|
||||
}
|
||||
|
||||
@ViewBuilder private var qualityButton: some View {
|
||||
#if os(macOS)
|
||||
StreamControl()
|
||||
.labelsHidden()
|
||||
.frame(maxWidth: 300)
|
||||
#elseif os(iOS)
|
||||
Menu {
|
||||
StreamControl()
|
||||
.frame(width: 45, height: 30)
|
||||
#if os(iOS)
|
||||
.background(VisualEffectBlur(blurStyle: .systemThinMaterial))
|
||||
#endif
|
||||
.mask(RoundedRectangle(cornerRadius: 3))
|
||||
} label: {
|
||||
Text(player.streamSelection?.shortQuality ?? "loading")
|
||||
.frame(width: 140, height: 30)
|
||||
.foregroundColor(.primary)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.foregroundColor(.primary)
|
||||
.frame(width: 140, height: 30)
|
||||
#if os(macOS)
|
||||
.background(VisualEffectBlur(material: .hudWindow))
|
||||
#elseif os(iOS)
|
||||
.background(VisualEffectBlur(blurStyle: .systemThinMaterial))
|
||||
#endif
|
||||
.mask(RoundedRectangle(cornerRadius: 3))
|
||||
#endif
|
||||
}
|
||||
|
||||
@ViewBuilder private var backendButton: some View {
|
||||
button(player.activeBackend.label, width: 100) {
|
||||
player.saveTime {
|
||||
player.changeActiveBackend(from: player.activeBackend, to: player.activeBackend.next())
|
||||
model.resetTimer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var closeVideoButton: some View {
|
||||
button("Close", systemImage: "xmark") {
|
||||
player.pause()
|
||||
@ -351,7 +360,6 @@ struct PlayerControls: View {
|
||||
#endif
|
||||
}
|
||||
.font(.system(size: 20))
|
||||
.padding(.horizontal, 4)
|
||||
}
|
||||
|
||||
private var restartVideoButton: some View {
|
||||
@ -380,8 +388,10 @@ struct PlayerControls: View {
|
||||
|
||||
func button(
|
||||
_ label: String,
|
||||
systemImage: String = "arrow.up.left.and.arrow.down.right",
|
||||
systemImage: String? = nil,
|
||||
size: Double = 30,
|
||||
width: Double? = nil,
|
||||
height: Double? = nil,
|
||||
cornerRadius: Double = 3,
|
||||
active: Bool = false,
|
||||
action: @escaping () -> Void = {}
|
||||
@ -390,14 +400,21 @@ struct PlayerControls: View {
|
||||
action()
|
||||
model.resetTimer()
|
||||
} label: {
|
||||
Label(label, systemImage: systemImage)
|
||||
Group {
|
||||
if let image = systemImage {
|
||||
Label(label, systemImage: image)
|
||||
.labelStyle(.iconOnly)
|
||||
} else {
|
||||
Label(label, systemImage: "")
|
||||
.labelStyle(.titleOnly)
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.foregroundColor(active ? .accentColor : .primary)
|
||||
.frame(width: size, height: size)
|
||||
.frame(width: width ?? size, height: height ?? size)
|
||||
#if os(macOS)
|
||||
.background(VisualEffectBlur(material: .hudWindow))
|
||||
#elseif os(iOS)
|
||||
|
@ -1,23 +0,0 @@
|
||||
import SwiftUI
|
||||
|
||||
struct ToggleBackendButton: View {
|
||||
@EnvironmentObject<PlayerControlsModel> private var controls
|
||||
@EnvironmentObject<PlayerModel> private var player
|
||||
|
||||
var body: some View {
|
||||
Button {
|
||||
player.saveTime {
|
||||
player.changeActiveBackend(from: player.activeBackend, to: player.activeBackend.next())
|
||||
controls.resetTimer()
|
||||
}
|
||||
} label: {
|
||||
Text(player.activeBackend.label)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ToggleBackendButton_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ToggleBackendButton()
|
||||
}
|
||||
}
|
@ -29,27 +29,22 @@ struct StreamControl: View {
|
||||
.disabled(player.isLoadingAvailableStreams)
|
||||
|
||||
#else
|
||||
Menu {
|
||||
Picker("", selection: $player.streamSelection) {
|
||||
ForEach(InstancesModel.all) { instance in
|
||||
let instanceStreams = availableStreamsForInstance(instance)
|
||||
if !instanceStreams.values.isEmpty {
|
||||
let kinds = Array(instanceStreams.keys).sorted { $0 < $1 }
|
||||
Picker("", selection: $player.streamSelection) {
|
||||
|
||||
ForEach(kinds, id: \.self) { key in
|
||||
ForEach(instanceStreams[key] ?? []) { stream in
|
||||
Text(stream.description).tag(Stream?.some(stream))
|
||||
}
|
||||
|
||||
if kinds.count > 1 {
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} label: {
|
||||
Text(player.streamSelection?.quality ?? "no playable streams")
|
||||
}
|
||||
.frame(minWidth: 110)
|
||||
.fixedSize(horizontal: true, vertical: true)
|
||||
.disabled(player.isLoadingAvailableStreams)
|
||||
#endif
|
||||
}
|
||||
|
@ -136,8 +136,6 @@
|
||||
371114EB27B94C8800C2EF7B /* RepeatingTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371114EA27B94C8800C2EF7B /* RepeatingTimer.swift */; };
|
||||
371114EC27B94C8800C2EF7B /* RepeatingTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371114EA27B94C8800C2EF7B /* RepeatingTimer.swift */; };
|
||||
371114ED27B94C8800C2EF7B /* RepeatingTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371114EA27B94C8800C2EF7B /* RepeatingTimer.swift */; };
|
||||
371114EF27B951B800C2EF7B /* ToggleBackendButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371114EE27B951B800C2EF7B /* ToggleBackendButton.swift */; };
|
||||
371114F027B951B800C2EF7B /* ToggleBackendButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371114EE27B951B800C2EF7B /* ToggleBackendButton.swift */; };
|
||||
3711403F26B206A6005B3555 /* SearchModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3711403E26B206A6005B3555 /* SearchModel.swift */; };
|
||||
3711404026B206A6005B3555 /* SearchModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3711403E26B206A6005B3555 /* SearchModel.swift */; };
|
||||
3711404126B206A6005B3555 /* SearchModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3711403E26B206A6005B3555 /* SearchModel.swift */; };
|
||||
@ -349,7 +347,6 @@
|
||||
376CD21626FBE18D001E1AC1 /* Instance+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376CD21526FBE18D001E1AC1 /* Instance+Fixtures.swift */; };
|
||||
376CD21726FBE18D001E1AC1 /* Instance+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376CD21526FBE18D001E1AC1 /* Instance+Fixtures.swift */; };
|
||||
376CD21826FBE18D001E1AC1 /* Instance+Fixtures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 376CD21526FBE18D001E1AC1 /* Instance+Fixtures.swift */; };
|
||||
3772000F27E8EC8800CB2475 /* ToggleBackendButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371114EE27B951B800C2EF7B /* ToggleBackendButton.swift */; };
|
||||
3772002727E8EDF000CB2475 /* libmpv.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3772001327E8ED1600CB2475 /* libmpv.a */; };
|
||||
3772002827E8EDF000CB2475 /* libswscale.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3772001A27E8ED1700CB2475 /* libswscale.a */; };
|
||||
3772002927E8EDF000CB2475 /* libavutil.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3772001627E8ED1700CB2475 /* libavutil.a */; };
|
||||
@ -847,7 +844,6 @@
|
||||
370F4FC827CC16CB001B35DC /* libbrotlicommon.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libbrotlicommon.1.dylib; sourceTree = "<group>"; };
|
||||
370F500A27CC176F001B35DC /* BridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BridgingHeader.h; sourceTree = "<group>"; };
|
||||
371114EA27B94C8800C2EF7B /* RepeatingTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RepeatingTimer.swift; sourceTree = "<group>"; };
|
||||
371114EE27B951B800C2EF7B /* ToggleBackendButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleBackendButton.swift; sourceTree = "<group>"; };
|
||||
3711403E26B206A6005B3555 /* SearchModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchModel.swift; sourceTree = "<group>"; };
|
||||
37130A5A277657090033018A /* Yattee.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Yattee.xcdatamodel; sourceTree = "<group>"; };
|
||||
37130A5E277657300033018A /* PersistenceController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersistenceController.swift; sourceTree = "<group>"; };
|
||||
@ -1315,7 +1311,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
37030FFE27B04DCC00ECDDAA /* PlayerControls.swift */,
|
||||
371114EE27B951B800C2EF7B /* ToggleBackendButton.swift */,
|
||||
);
|
||||
path = Controls;
|
||||
sourceTree = "<group>";
|
||||
@ -2620,7 +2615,6 @@
|
||||
37732FF42703D32400F04329 /* Sidebar.swift in Sources */,
|
||||
37D4B19726717E1500C925CA /* Video.swift in Sources */,
|
||||
37484C2926FC83FF00287258 /* AccountForm.swift in Sources */,
|
||||
371114EF27B951B800C2EF7B /* ToggleBackendButton.swift in Sources */,
|
||||
37E70927271CDDAE00D34DDE /* OpenSettingsButton.swift in Sources */,
|
||||
371F2F1A269B43D300E4A7AB /* NavigationModel.swift in Sources */,
|
||||
37EBD8C627AF26B300F1C24B /* AVPlayerBackend.swift in Sources */,
|
||||
@ -2742,7 +2736,6 @@
|
||||
37B795912771DAE0001CF27B /* OpenURLHandler.swift in Sources */,
|
||||
37DD87C8271C9CFE0027CBF9 /* PlayerStreams.swift in Sources */,
|
||||
376578922685490700D4EA09 /* PlaylistsView.swift in Sources */,
|
||||
371114F027B951B800C2EF7B /* ToggleBackendButton.swift in Sources */,
|
||||
37F9619C27BD89E000058149 /* TapRecognizerViewModifier.swift in Sources */,
|
||||
37484C2626FC83E000287258 /* InstanceForm.swift in Sources */,
|
||||
37D526E42720B4BE00ED2F5E /* View+SwipeGesture.swift in Sources */,
|
||||
@ -3035,7 +3028,6 @@
|
||||
37BC50AE2778BCBA00510953 /* HistoryModel.swift in Sources */,
|
||||
37D526E02720AC4400ED2F5E /* VideosAPI.swift in Sources */,
|
||||
37599F36272B44000087F250 /* FavoritesModel.swift in Sources */,
|
||||
3772000F27E8EC8800CB2475 /* ToggleBackendButton.swift in Sources */,
|
||||
3705B184267B4E4900704544 /* TrendingCategory.swift in Sources */,
|
||||
37E084AD2753D95F00039B7D /* AccountsNavigationLink.swift in Sources */,
|
||||
371B7E6C2759791900D21217 /* CommentsModel.swift in Sources */,
|
||||
|
Loading…
Reference in New Issue
Block a user