1
0
mirror of https://github.com/yattee/yattee.git synced 2024-12-15 06:40:32 +05:30

tvOS fixes

This commit is contained in:
Arkadiusz Fal 2022-03-27 21:22:13 +02:00
parent 011ca5dac2
commit b9dfdeb23f
6 changed files with 154 additions and 67 deletions

View File

@ -276,6 +276,13 @@ final class MPVBackend: PlayerBackend {
startClientUpdates() startClientUpdates()
onFileLoaded = nil onFileLoaded = nil
case MPV_EVENT_PLAYBACK_RESTART:
isLoadingVideo = false
onFileLoaded?()
startClientUpdates()
onFileLoaded = nil
case MPV_EVENT_UNPAUSE: case MPV_EVENT_UNPAUSE:
isLoadingVideo = false isLoadingVideo = false

View File

@ -10,6 +10,14 @@ struct PlayerControls: View {
#if os(iOS) #if os(iOS)
@Environment(\.verticalSizeClass) private var verticalSizeClass @Environment(\.verticalSizeClass) private var verticalSizeClass
#elseif os(tvOS)
enum Field: Hashable {
case play
case backward
case forward
}
@FocusState private var focusedField: Field?
#endif #endif
init(player: PlayerModel) { init(player: PlayerModel) {
@ -57,14 +65,27 @@ struct PlayerControls: View {
} }
.opacity(model.presentingControls ? 1 : 0) .opacity(model.presentingControls ? 1 : 0)
} }
#if os(tvOS)
.onChange(of: model.presentingControls) { _ in
if model.presentingControls {
focusedField = .play
}
}
.onChange(of: focusedField) { _ in
model.resetTimer()
}
#else
.background(controlsBackground) .background(controlsBackground)
#endif
.environment(\.colorScheme, .dark) .environment(\.colorScheme, .dark)
} }
#if !os(tvOS)
var controlsBackground: some View { var controlsBackground: some View {
PlayerGestures() PlayerGestures()
.background(Color.black.opacity(model.presentingControls ? 0.5 : 0)) .background(Color.black.opacity(model.presentingControls ? 0.5 : 0))
} }
#endif
var timeline: some View { var timeline: some View {
TimelineView(duration: durationBinding, current: currentTimeBinding, cornerRadius: 0) TimelineView(duration: durationBinding, current: currentTimeBinding, cornerRadius: 0)
@ -93,12 +114,17 @@ struct PlayerControls: View {
Spacer() Spacer()
#if !os(tvOS)
ToggleBackendButton() ToggleBackendButton()
Text("") Text("")
StreamControl() StreamControl()
#if os(macOS) #if os(macOS)
.frame(maxWidth: 160) .frame(maxWidth: 160)
#endif #endif
#else
Text(player.stream?.description ?? "")
#endif
} }
.foregroundColor(.primary) .foregroundColor(.primary)
.padding(.trailing, 4) .padding(.trailing, 4)
@ -111,7 +137,9 @@ struct PlayerControls: View {
} label: { } label: {
Image(systemName: "chevron.down.circle.fill") Image(systemName: "chevron.down.circle.fill")
} }
#if !os(tvOS)
.keyboardShortcut(.cancelAction) .keyboardShortcut(.cancelAction)
#endif
} }
private var playbackStatus: String { private var playbackStatus: String {
@ -146,7 +174,9 @@ struct PlayerControls: View {
var buttonsBar: some View { var buttonsBar: some View {
HStack { HStack {
#if !os(tvOS)
fullscreenButton fullscreenButton
#endif
Spacer() Spacer()
// button("Music Mode", systemImage: "music.note") // button("Music Mode", systemImage: "music.note")
} }
@ -159,15 +189,26 @@ struct PlayerControls: View {
) { ) {
model.toggleFullscreen(fullScreenLayout) model.toggleFullscreen(fullScreenLayout)
} }
#if !os(tvOS)
.keyboardShortcut(fullScreenLayout ? .cancelAction : .defaultAction) .keyboardShortcut(fullScreenLayout ? .cancelAction : .defaultAction)
#endif
} }
var mediumButtonsBar: some View { var mediumButtonsBar: some View {
HStack { HStack {
#if !os(tvOS)
button("Seek Backward", systemImage: "gobackward.10", size: 50, cornerRadius: 10) { button("Seek Backward", systemImage: "gobackward.10", size: 50, cornerRadius: 10) {
player.backend.seek(relative: .secondsInDefaultTimescale(-10)) player.backend.seek(relative: .secondsInDefaultTimescale(-10))
} }
#if os(tvOS)
.focused($focusedField, equals: .backward)
#else
.keyboardShortcut("k") .keyboardShortcut("k")
.keyboardShortcut(.leftArrow)
#endif
#endif
Spacer() Spacer()
@ -179,15 +220,27 @@ struct PlayerControls: View {
) { ) {
player.backend.togglePlay() player.backend.togglePlay()
} }
#if os(tvOS)
.focused($focusedField, equals: .play)
#else
.keyboardShortcut("p") .keyboardShortcut("p")
.keyboardShortcut(.space)
#endif
.disabled(model.isLoadingVideo) .disabled(model.isLoadingVideo)
Spacer() Spacer()
#if !os(tvOS)
button("Seek Forward", systemImage: "goforward.10", size: 50, cornerRadius: 10) { button("Seek Forward", systemImage: "goforward.10", size: 50, cornerRadius: 10) {
player.backend.seek(relative: .secondsInDefaultTimescale(10)) player.backend.seek(relative: .secondsInDefaultTimescale(10))
} }
#if os(tvOS)
.focused($focusedField, equals: .forward)
#else
.keyboardShortcut("l") .keyboardShortcut("l")
.keyboardShortcut(.rightArrow)
#endif
#endif
} }
.font(.system(size: 30)) .font(.system(size: 30))
.padding(.horizontal, 4) .padding(.horizontal, 4)
@ -234,7 +287,7 @@ struct PlayerControls: View {
} }
var fullScreenLayout: Bool { var fullScreenLayout: Bool {
#if !os(macOS) #if os(iOS)
model.playingFullscreen || verticalSizeClass == .compact model.playingFullscreen || verticalSizeClass == .compact
#else #else
model.playingFullscreen model.playingFullscreen

View File

@ -47,6 +47,7 @@ struct TimelineView: View {
.frame(maxHeight: height * 2) .frame(maxHeight: height * 2)
#if !os(tvOS)
.gesture( .gesture(
DragGesture(minimumDistance: 0) DragGesture(minimumDistance: 0)
.onChanged { value in .onChanged { value in
@ -79,6 +80,7 @@ struct TimelineView: View {
controls.resetTimer() controls.resetTimer()
} }
) )
#endif
ZStack { ZStack {
RoundedRectangle(cornerRadius: cornerRadius) RoundedRectangle(cornerRadius: cornerRadius)
@ -100,11 +102,13 @@ struct TimelineView: View {
self.size = size self.size = size
} }
}) })
#if !os(tvOS)
.gesture(DragGesture(minimumDistance: 0).onEnded { value in .gesture(DragGesture(minimumDistance: 0).onEnded { value in
let target = (value.location.x / size.width) * units let target = (value.location.x / size.width) * units
current = target current = target
player.backend.seek(to: target) player.backend.seek(to: target)
}) })
#endif
} }
var projectedValue: Double { var projectedValue: Double {

View File

@ -89,7 +89,7 @@ struct VideoDetails: View {
if fullScreen { if fullScreen {
fullScreen = false fullScreen = false
} else { } else {
self.presentationMode.wrappedValue.dismiss() self.player.hide()
} }
} }
} }

View File

@ -93,8 +93,26 @@ struct VideoPlayerView: View {
Group { Group {
Group { Group {
#if os(tvOS) #if os(tvOS)
player.playerView playerView
.ignoresSafeArea(.all, edges: .all) .ignoresSafeArea(.all, edges: .all)
.onMoveCommand { direction in
if direction == .left {
playerControls.resetTimer()
player.backend.seek(relative: .secondsInDefaultTimescale(-10))
}
if direction == .right {
playerControls.resetTimer()
player.backend.seek(relative: .secondsInDefaultTimescale(10))
}
if direction == .up {
playerControls.show()
playerControls.resetTimer()
}
if direction == .down {
playerControls.show()
playerControls.resetTimer()
}
}
#else #else
GeometryReader { geometry in GeometryReader { geometry in
VStack(spacing: 0) { VStack(spacing: 0) {
@ -103,30 +121,8 @@ struct VideoPlayerView: View {
} else if player.playingInPictureInPicture { } else if player.playingInPictureInPicture {
pictureInPicturePlaceholder(geometry: geometry) pictureInPicturePlaceholder(geometry: geometry)
} else { } else {
ZStack(alignment: .top) { playerView
switch player.activeBackend { #if !os(tvOS)
case .mpv:
player.mpvPlayerView
.overlay(GeometryReader { proxy in
Color.clear
.onAppear {
player.playerSize = proxy.size
// TODO: move to backend method
player.mpvBackend.client?.setSize(proxy.size.width, proxy.size.height)
}
.onChange(of: proxy.size) { _ in
player.playerSize = proxy.size
player.mpvBackend.client?.setSize(proxy.size.width, proxy.size.height)
}
})
case .appleAVPlayer:
player.avPlayerView
}
PlayerGestures()
PlayerControls(player: player)
}
.modifier( .modifier(
VideoPlayerSizeModifier( VideoPlayerSizeModifier(
geometry: geometry, geometry: geometry,
@ -134,6 +130,7 @@ struct VideoPlayerView: View {
fullScreen: playerControls.playingFullscreen fullScreen: playerControls.playingFullscreen
) )
) )
#endif
} }
} }
.frame(maxWidth: fullScreenLayout ? .infinity : nil, maxHeight: fullScreenLayout ? .infinity : nil) .frame(maxWidth: fullScreenLayout ? .infinity : nil, maxHeight: fullScreenLayout ? .infinity : nil)
@ -165,6 +162,7 @@ struct VideoPlayerView: View {
.background(Color.black) .background(Color.black)
#if !os(tvOS)
if !playerControls.playingFullscreen { if !playerControls.playingFullscreen {
Group { Group {
#if os(iOS) #if os(iOS)
@ -183,6 +181,7 @@ struct VideoPlayerView: View {
fullScreen: fullScreenDetails fullScreen: fullScreenDetails
)) ))
} }
#endif
} }
#endif #endif
} }
@ -205,14 +204,40 @@ struct VideoPlayerView: View {
} }
} }
.ignoresSafeArea(.all, edges: fullScreenLayout ? .vertical : Edge.Set()) .ignoresSafeArea(.all, edges: fullScreenLayout ? .vertical : Edge.Set())
#if !os(macOS) #if os(iOS)
.statusBar(hidden: playerControls.playingFullscreen) .statusBar(hidden: playerControls.playingFullscreen)
.navigationBarHidden(true) .navigationBarHidden(true)
#endif #endif
} }
var playerView: some View {
ZStack(alignment: .top) {
switch player.activeBackend {
case .mpv:
player.mpvPlayerView
.overlay(GeometryReader { proxy in
Color.clear
.onAppear {
player.playerSize = proxy.size
}
.onChange(of: proxy.size) { _ in
player.playerSize = proxy.size
}
})
case .appleAVPlayer:
player.avPlayerView
}
#if !os(tvOS)
PlayerGestures()
#endif
PlayerControls(player: player)
}
}
var fullScreenLayout: Bool { var fullScreenLayout: Bool {
#if !os(macOS) #if os(iOS)
playerControls.playingFullscreen || verticalSizeClass == .compact playerControls.playingFullscreen || verticalSizeClass == .compact
#else #else
playerControls.playingFullscreen playerControls.playingFullscreen

View File

@ -212,7 +212,6 @@
373CFAEF2697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373CFAEE2697A78B003CB2C6 /* AddToPlaylistView.swift */; }; 373CFAEF2697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373CFAEE2697A78B003CB2C6 /* AddToPlaylistView.swift */; };
373CFAF02697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373CFAEE2697A78B003CB2C6 /* AddToPlaylistView.swift */; }; 373CFAF02697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373CFAEE2697A78B003CB2C6 /* AddToPlaylistView.swift */; };
373CFAF12697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373CFAEE2697A78B003CB2C6 /* AddToPlaylistView.swift */; }; 373CFAF12697A78B003CB2C6 /* AddToPlaylistView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373CFAEE2697A78B003CB2C6 /* AddToPlaylistView.swift */; };
3740457227E91A4C00DC8A64 /* StreamControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3795593527B08538007FF8F4 /* StreamControl.swift */; };
374108D1272B11B2006C5CC8 /* PictureInPictureDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374108D0272B11B2006C5CC8 /* PictureInPictureDelegate.swift */; }; 374108D1272B11B2006C5CC8 /* PictureInPictureDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 374108D0272B11B2006C5CC8 /* PictureInPictureDelegate.swift */; };
3741A32C27E7EFFD00D266D1 /* PlayerControls.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37030FFE27B04DCC00ECDDAA /* PlayerControls.swift */; }; 3741A32C27E7EFFD00D266D1 /* PlayerControls.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37030FFE27B04DCC00ECDDAA /* PlayerControls.swift */; };
3743B86927216D3600261544 /* ChannelCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3743B86727216D3600261544 /* ChannelCell.swift */; }; 3743B86927216D3600261544 /* ChannelCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3743B86727216D3600261544 /* ChannelCell.swift */; };
@ -2942,7 +2941,6 @@
3743CA50270EFE3400E4D32B /* PlayerQueueRow.swift in Sources */, 3743CA50270EFE3400E4D32B /* PlayerQueueRow.swift in Sources */,
376BE50827347B57009AD608 /* SettingsHeader.swift in Sources */, 376BE50827347B57009AD608 /* SettingsHeader.swift in Sources */,
37A9966026D6F9B9006E3224 /* FavoritesView.swift in Sources */, 37A9966026D6F9B9006E3224 /* FavoritesView.swift in Sources */,
3740457227E91A4C00DC8A64 /* StreamControl.swift in Sources */,
37001565271B1F250049C794 /* AccountsModel.swift in Sources */, 37001565271B1F250049C794 /* AccountsModel.swift in Sources */,
3751B4B427836902000B7DF4 /* SearchPage.swift in Sources */, 3751B4B427836902000B7DF4 /* SearchPage.swift in Sources */,
374C0541272472C0009BDDBE /* PlayerSponsorBlock.swift in Sources */, 374C0541272472C0009BDDBE /* PlayerSponsorBlock.swift in Sources */,