Regular TV layout

This commit is contained in:
Arkadiusz Fal 2022-08-29 00:21:12 +02:00
parent 44600831a6
commit 945dbfe00b
6 changed files with 124 additions and 21 deletions

View File

@ -45,7 +45,7 @@ struct FixtureEnvironmentObjectsModifier: ViewModifier {
player.currentItem = PlayerQueueItem( player.currentItem = PlayerQueueItem(
Video( Video(
videoID: "", videoID: "",
title: "", title: "Video Name",
author: "", author: "",
length: 0, length: 0,
published: "2 days ago", published: "2 days ago",

View File

@ -102,8 +102,8 @@ extension Defaults.Keys {
static let playerControlsLayoutDefault = UIDevice.current.userInterfaceIdiom == .pad ? PlayerControlsLayout.medium : .small static let playerControlsLayoutDefault = UIDevice.current.userInterfaceIdiom == .pad ? PlayerControlsLayout.medium : .small
static let fullScreenPlayerControlsLayoutDefault = UIDevice.current.userInterfaceIdiom == .pad ? PlayerControlsLayout.medium : .small static let fullScreenPlayerControlsLayoutDefault = UIDevice.current.userInterfaceIdiom == .pad ? PlayerControlsLayout.medium : .small
#elseif os(tvOS) #elseif os(tvOS)
static let playerControlsLayoutDefault = PlayerControlsLayout.veryLarge static let playerControlsLayoutDefault = PlayerControlsLayout.tvRegular
static let fullScreenPlayerControlsLayoutDefault = PlayerControlsLayout.veryLarge static let fullScreenPlayerControlsLayoutDefault = PlayerControlsLayout.tvRegular
#else #else
static let playerControlsLayoutDefault = PlayerControlsLayout.medium static let playerControlsLayoutDefault = PlayerControlsLayout.medium
static let fullScreenPlayerControlsLayoutDefault = PlayerControlsLayout.medium static let fullScreenPlayerControlsLayoutDefault = PlayerControlsLayout.medium
@ -129,7 +129,12 @@ extension Defaults.Keys {
#if !os(macOS) #if !os(macOS)
static let pauseOnEnteringBackground = Key<Bool>("pauseOnEnteringBackground", default: true) static let pauseOnEnteringBackground = Key<Bool>("pauseOnEnteringBackground", default: true)
#endif #endif
static let closeLastItemOnPlaybackEnd = Key<Bool>("closeLastItemOnPlaybackEnd", default: false) #if os(tvOS)
static let closeLastItemOnPlaybackEndDefault = true
#else
static let closeLastItemOnPlaybackEndDefault = false
#endif
static let closeLastItemOnPlaybackEnd = Key<Bool>("closeLastItemOnPlaybackEnd", default: closeLastItemOnPlaybackEndDefault)
#if os(tvOS) #if os(tvOS)
static let closePlayerOnItemCloseDefault = true static let closePlayerOnItemCloseDefault = true

View File

@ -19,9 +19,9 @@ struct Seek: View {
var body: some View { var body: some View {
Button(action: model.restoreTime) { Button(action: model.restoreTime) {
VStack(spacing: 2) { VStack(spacing: playerControlsLayout.osdSpacing) {
ProgressBar(value: progress) ProgressBar(value: progress)
.frame(maxHeight: 5) .frame(maxHeight: playerControlsLayout.osdProgressBarHeight)
timeline timeline
@ -37,6 +37,7 @@ struct Seek: View {
Text(chapter.title) Text(chapter.title)
.multilineTextAlignment(.center) .multilineTextAlignment(.center)
.font(.system(size: playerControlsLayout.chapterFontSize)) .font(.system(size: playerControlsLayout.chapterFontSize))
.fixedSize(horizontal: false, vertical: true)
} }
if let segment = projectedSegment { if let segment = projectedSegment {
Text(SponsorBlockAPI.categoryDescription(segment.category) ?? "Sponsor") Text(SponsorBlockAPI.categoryDescription(segment.category) ?? "Sponsor")
@ -44,6 +45,7 @@ struct Seek: View {
.foregroundColor(Color("AppRedColor")) .foregroundColor(Color("AppRedColor"))
} }
} else { } else {
#if !os(tvOS)
if !model.restoreSeekTime.isNil { if !model.restoreSeekTime.isNil {
Divider() Divider()
Label(model.restoreSeekPlaybackTime, systemImage: "arrow.counterclockwise") Label(model.restoreSeekPlaybackTime, systemImage: "arrow.counterclockwise")
@ -51,7 +53,7 @@ struct Seek: View {
.font(.system(size: playerControlsLayout.chapterFontSize).monospacedDigit()) .font(.system(size: playerControlsLayout.chapterFontSize).monospacedDigit())
.frame(height: playerControlsLayout.chapterFontSize + 5) .frame(height: playerControlsLayout.chapterFontSize + 5)
} }
#endif
Group { Group {
switch model.lastSeekType { switch model.lastSeekType {
case let .segmentSkip(category): case let .segmentSkip(category):
@ -67,7 +69,7 @@ struct Seek: View {
} }
#if os(tvOS) #if os(tvOS)
.frame(minWidth: 250, minHeight: 100) .frame(minWidth: 250, minHeight: 100)
.padding(10) .padding(30)
#endif #endif
.frame(maxWidth: playerControlsLayout.seekOSDWidth) .frame(maxWidth: playerControlsLayout.seekOSDWidth)
.padding(2) .padding(2)

View File

@ -49,7 +49,7 @@ struct PlayerControls: View {
.transition(.opacity) .transition(.opacity)
.frame(maxWidth: .infinity, alignment: .topLeading) .frame(maxWidth: .infinity, alignment: .topLeading)
#if os(tvOS) #if os(tvOS)
.offset(x: 10, y: 5) .offset(x: 10, y: 10)
.focused($focusedField, equals: .seekOSD) .focused($focusedField, equals: .seekOSD)
.onChange(of: player.playerTime.lastSeekTime) { _ in .onChange(of: player.playerTime.lastSeekTime) { _ in
if !model.presentingControls { if !model.presentingControls {
@ -108,8 +108,26 @@ struct PlayerControls: View {
Spacer() Spacer()
if playerControlsLayout.displaysTitleLine {
VStack(alignment: .leading) {
Text(player.currentVideo?.title ?? "Not Playing")
.shadow(radius: 10)
.font(.system(size: playerControlsLayout.titleLineFontSize).bold())
.lineLimit(1)
Text(player.currentVideo?.channel.name ?? "")
.fontWeight(.semibold)
.shadow(radius: 10)
.foregroundColor(.secondary)
.font(.system(size: playerControlsLayout.authorLineFontSize))
.lineLimit(1)
}
.frame(maxWidth: .infinity, alignment: .leading)
.offset(y: -40)
}
timeline timeline
.frame(maxWidth: 1000)
.padding(.bottom, 2) .padding(.bottom, 2)
} }
.zIndex(1) .zIndex(1)
@ -135,9 +153,6 @@ struct PlayerControls: View {
musicModeButton musicModeButton
#endif #endif
} }
#if os(tvOS)
.frame(width: 1200)
#endif
.zIndex(0) .zIndex(0)
#if os(tvOS) #if os(tvOS)
.offset(y: -playerControlsLayout.timelineHeight - 30) .offset(y: -playerControlsLayout.timelineHeight - 30)

View File

@ -2,6 +2,7 @@ import Defaults
import Foundation import Foundation
enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable { enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
case tvRegular
case veryLarge case veryLarge
case large case large
case medium case medium
@ -10,6 +11,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var description: String { var description: String {
switch self { switch self {
case .tvRegular:
return "TV"
case .veryLarge: case .veryLarge:
return "Very Large" return "Very Large"
default: default:
@ -19,6 +22,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var buttonsSpacing: Double { var buttonsSpacing: Double {
switch self { switch self {
case .tvRegular:
return 80
case .veryLarge: case .veryLarge:
return 40 return 40
case .large: case .large:
@ -34,6 +39,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var buttonFontSize: Double { var buttonFontSize: Double {
switch self { switch self {
case .tvRegular:
return 48
case .veryLarge: case .veryLarge:
return 35 return 35
case .large: case .large:
@ -49,6 +56,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var bigButtonFontSize: Double { var bigButtonFontSize: Double {
switch self { switch self {
case .tvRegular:
return 65
case .veryLarge: case .veryLarge:
return 55 return 55
case .large: case .large:
@ -64,6 +73,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var buttonSize: Double { var buttonSize: Double {
switch self { switch self {
case .tvRegular:
return 90
case .veryLarge: case .veryLarge:
return 60 return 60
case .large: case .large:
@ -79,6 +90,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var bigButtonSize: Double { var bigButtonSize: Double {
switch self { switch self {
case .tvRegular:
return 100
case .veryLarge: case .veryLarge:
return 85 return 85
case .large: case .large:
@ -94,6 +107,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var segmentFontSize: Double { var segmentFontSize: Double {
switch self { switch self {
case .tvRegular:
return 20
case .veryLarge: case .veryLarge:
return 16 return 16
case .large: case .large:
@ -109,6 +124,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var chapterFontSize: Double { var chapterFontSize: Double {
switch self { switch self {
case .tvRegular:
return 24
case .veryLarge: case .veryLarge:
return 20 return 20
case .large: case .large:
@ -124,6 +141,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var projectedTimeFontSize: Double { var projectedTimeFontSize: Double {
switch self { switch self {
case .tvRegular:
return 30
case .veryLarge: case .veryLarge:
return 25 return 25
case .large: case .large:
@ -139,6 +158,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var thumbSize: Double { var thumbSize: Double {
switch self { switch self {
case .tvRegular:
return 45
case .veryLarge: case .veryLarge:
return 35 return 35
case .large: case .large:
@ -154,6 +175,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var timeFontSize: Double { var timeFontSize: Double {
switch self { switch self {
case .tvRegular:
return 45
case .veryLarge: case .veryLarge:
return 35 return 35
case .large: case .large:
@ -169,6 +192,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var bufferingStateFontSize: Double { var bufferingStateFontSize: Double {
switch self { switch self {
case .tvRegular:
return 45
case .veryLarge: case .veryLarge:
return 30 return 30
case .large: case .large:
@ -184,6 +209,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var timeLeadingEdgePadding: Double { var timeLeadingEdgePadding: Double {
switch self { switch self {
case .tvRegular:
return 20
case .veryLarge: case .veryLarge:
return 5 return 5
case .large: case .large:
@ -199,6 +226,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var timeTrailingEdgePadding: Double { var timeTrailingEdgePadding: Double {
switch self { switch self {
case .tvRegular:
return 20
case .veryLarge: case .veryLarge:
return 16 return 16
case .large: case .large:
@ -214,6 +243,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var timelineHeight: Double { var timelineHeight: Double {
switch self { switch self {
case .tvRegular:
return 80
case .veryLarge: case .veryLarge:
return 40 return 40
case .large: case .large:
@ -229,6 +260,8 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var seekOSDWidth: Double { var seekOSDWidth: Double {
switch self { switch self {
case .tvRegular:
return 240
case .veryLarge: case .veryLarge:
return 240 return 240
case .large: case .large:
@ -245,4 +278,50 @@ enum PlayerControlsLayout: String, CaseIterable, Defaults.Serializable {
var osdVerticalOffset: Double { var osdVerticalOffset: Double {
buttonSize buttonSize
} }
var osdProgressBarHeight: Double {
switch self {
case .tvRegular:
return 20
case .veryLarge:
return 10
case .large:
return 8
case .medium:
return 5
case .small:
return 5
case .smaller:
return 2
}
}
var osdSpacing: Double {
switch self {
case .tvRegular:
return 8
case .veryLarge:
return 8
case .large:
return 6
case .medium:
return 4
case .small:
return 2
case .smaller:
return 2
}
}
var displaysTitleLine: Bool {
self == .tvRegular
}
var titleLineFontSize: Double {
60
}
var authorLineFontSize: Double {
30
}
} }

View File

@ -60,7 +60,9 @@ struct VideoPlayerView: View {
@EnvironmentObject<PlayerModel> internal var player @EnvironmentObject<PlayerModel> internal var player
@EnvironmentObject<PlayerControlsModel> internal var playerControls @EnvironmentObject<PlayerControlsModel> internal var playerControls
@EnvironmentObject<RecentsModel> internal var recents @EnvironmentObject<RecentsModel> internal var recents
#if os(macOS)
@EnvironmentObject<SearchModel> internal var search @EnvironmentObject<SearchModel> internal var search
#endif
@EnvironmentObject<ThumbnailsModel> internal var thumbnails @EnvironmentObject<ThumbnailsModel> internal var thumbnails
@Default(.horizontalPlayerGestureEnabled) var horizontalPlayerGestureEnabled @Default(.horizontalPlayerGestureEnabled) var horizontalPlayerGestureEnabled