mirror of
https://github.com/yattee/yattee.git
synced 2024-12-22 21:43:41 +00:00
Player layout fixes
This commit is contained in:
parent
06b7bc79e8
commit
6c71cd72b1
@ -110,7 +110,9 @@ final class NavigationModel: ObservableObject {
|
|||||||
navigation.sidebarSectionChanged.toggle()
|
navigation.sidebarSectionChanged.toggle()
|
||||||
navigation.tabSelection = .recentlyOpened(recent.tag)
|
navigation.tabSelection = .recentlyOpened(recent.tag)
|
||||||
} else {
|
} else {
|
||||||
navigation.presentingChannel = true
|
withAnimation {
|
||||||
|
navigation.presentingChannel = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -139,7 +141,9 @@ final class NavigationModel: ObservableObject {
|
|||||||
navigation.sidebarSectionChanged.toggle()
|
navigation.sidebarSectionChanged.toggle()
|
||||||
navigation.tabSelection = .recentlyOpened(recent.tag)
|
navigation.tabSelection = .recentlyOpened(recent.tag)
|
||||||
} else {
|
} else {
|
||||||
navigation.presentingPlaylist = true
|
withAnimation {
|
||||||
|
navigation.presentingPlaylist = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,14 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
avPlayer.timeControlStatus == .playing
|
avPlayer.timeControlStatus == .playing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var aspectRatio: Double {
|
||||||
|
#if os(tvOS)
|
||||||
|
VideoPlayerView.defaultAspectRatio
|
||||||
|
#else
|
||||||
|
controller?.aspectRatio ?? VideoPlayerView.defaultAspectRatio
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
var isSeeking: Bool {
|
var isSeeking: Bool {
|
||||||
// TODO: implement this maybe?
|
// TODO: implement this maybe?
|
||||||
false
|
false
|
||||||
@ -144,14 +152,10 @@ final class AVPlayerBackend: PlayerBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func enterFullScreen() {
|
func enterFullScreen() {
|
||||||
controller?.playerView
|
model.toggleFullscreen(model?.playingFullScreen ?? false)
|
||||||
.perform(NSSelectorFromString("enterFullScreenAnimated:completionHandler:"), with: false, with: nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func exitFullScreen() {
|
func exitFullScreen() {}
|
||||||
controller?.playerView
|
|
||||||
.perform(NSSelectorFromString("exitFullScreenAnimated:completionHandler:"), with: false, with: nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
#if os(tvOS)
|
#if os(tvOS)
|
||||||
func closePiP(wasPlaying: Bool) {
|
func closePiP(wasPlaying: Bool) {
|
||||||
|
@ -86,6 +86,10 @@ final class MPVBackend: PlayerBackend {
|
|||||||
client?.tracksCount ?? -1
|
client?.tracksCount ?? -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var aspectRatio: Double {
|
||||||
|
client?.aspectRatio ?? VideoPlayerView.defaultAspectRatio
|
||||||
|
}
|
||||||
|
|
||||||
var frameDropCount: Int {
|
var frameDropCount: Int {
|
||||||
client?.frameDropCount ?? 0
|
client?.frameDropCount ?? 0
|
||||||
}
|
}
|
||||||
|
@ -185,6 +185,20 @@ final class MPVClient: ObservableObject {
|
|||||||
mpv.isNil ? 0.0 : getDouble("demuxer-cache-duration")
|
mpv.isNil ? 0.0 : getDouble("demuxer-cache-duration")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var aspectRatio: Double {
|
||||||
|
guard !mpv.isNil else { return VideoPlayerView.defaultAspectRatio }
|
||||||
|
let aspect = getDouble("video-params/aspect")
|
||||||
|
return aspect.isZero ? VideoPlayerView.defaultAspectRatio : aspect
|
||||||
|
}
|
||||||
|
|
||||||
|
var dh: Double {
|
||||||
|
let defaultDh = 500.0
|
||||||
|
guard !mpv.isNil else { return defaultDh }
|
||||||
|
|
||||||
|
let dh = getDouble("video-params/dh")
|
||||||
|
return dh.isZero ? defaultDh : dh
|
||||||
|
}
|
||||||
|
|
||||||
var duration: CMTime {
|
var duration: CMTime {
|
||||||
CMTime.secondsInDefaultTimescale(mpv.isNil ? -1 : getDouble("duration"))
|
CMTime.secondsInDefaultTimescale(mpv.isNil ? -1 : getDouble("duration"))
|
||||||
}
|
}
|
||||||
@ -240,7 +254,24 @@ final class MPVClient: ObservableObject {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
glView?.frame = CGRect(x: 0, y: 0, width: roundedWidth, height: roundedHeight)
|
DispatchQueue.main.async { [weak self] in
|
||||||
|
guard let self = self else { return }
|
||||||
|
UIView.animate(withDuration: 0.2, animations: {
|
||||||
|
let height = [self.backend.model.playerSize.height, self.backend.model.playerSize.width / self.aspectRatio].min()!
|
||||||
|
let offsetY = self.backend.model.playingFullScreen ? ((self.backend.model.playerSize.height / 2.0) - (height / 2)) : 0
|
||||||
|
self.glView?.frame = CGRect(x: 0, y: offsetY, width: roundedWidth, height: height)
|
||||||
|
}) { completion in
|
||||||
|
if completion {
|
||||||
|
self.logger.info("setting player size to \(roundedWidth),\(roundedHeight) FINISHED")
|
||||||
|
|
||||||
|
self.glView?.queue.async {
|
||||||
|
self.glView.display()
|
||||||
|
}
|
||||||
|
self.backend?.controls?.objectWillChange.send()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,8 @@ protocol PlayerBackend {
|
|||||||
var isSeeking: Bool { get }
|
var isSeeking: Bool { get }
|
||||||
var playerItemDuration: CMTime? { get }
|
var playerItemDuration: CMTime? { get }
|
||||||
|
|
||||||
|
var aspectRatio: Double { get }
|
||||||
|
|
||||||
func bestPlayable(_ streams: [Stream], maxResolution: ResolutionSetting) -> Stream?
|
func bestPlayable(_ streams: [Stream], maxResolution: ResolutionSetting) -> Stream?
|
||||||
func canPlay(_ stream: Stream) -> Bool
|
func canPlay(_ stream: Stream) -> Bool
|
||||||
|
|
||||||
|
@ -170,7 +170,9 @@ final class PlayerModel: ObservableObject {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
self?.presentingPlayer = true
|
withAnimation {
|
||||||
|
self?.presentingPlayer = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
@ -182,7 +184,9 @@ final class PlayerModel: ObservableObject {
|
|||||||
func hide() {
|
func hide() {
|
||||||
DispatchQueue.main.async { [weak self] in
|
DispatchQueue.main.async { [weak self] in
|
||||||
self?.playingFullScreen = false
|
self?.playingFullScreen = false
|
||||||
self?.presentingPlayer = false
|
withAnimation {
|
||||||
|
self?.presentingPlayer = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
@ -625,26 +629,28 @@ final class PlayerModel: ObservableObject {
|
|||||||
controls.resetTimer()
|
controls.resetTimer()
|
||||||
|
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
Windows.player.toggleFullScreen()
|
if isFullScreen {
|
||||||
#endif
|
Windows.player.toggleFullScreen()
|
||||||
|
|
||||||
#if os(iOS)
|
|
||||||
setNeedsDrawing(false)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
playingFullScreen = !isFullScreen
|
|
||||||
|
|
||||||
#if os(iOS)
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { [weak self] in
|
|
||||||
self?.setNeedsDrawing(true)
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#if os(iOS)
|
||||||
|
withAnimation(.linear(duration: 0.2)) {
|
||||||
|
playingFullScreen = !isFullScreen
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
playingFullScreen = !isFullScreen
|
||||||
|
#endif
|
||||||
|
|
||||||
if playingFullScreen {
|
#if os(macOS)
|
||||||
guard !(UIApplication.shared.windows.first?.windowScene?.interfaceOrientation.isLandscape ?? true) else {
|
if !isFullScreen {
|
||||||
return
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
|
||||||
|
Windows.player.toggleFullScreen()
|
||||||
}
|
}
|
||||||
Orientation.lockOrientation(.landscape, andRotateTo: .landscapeRight)
|
}
|
||||||
} else {
|
#endif
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
|
if !playingFullScreen {
|
||||||
Orientation.lockOrientation(.allButUpsideDown, andRotateTo: .portrait)
|
Orientation.lockOrientation(.allButUpsideDown, andRotateTo: .portrait)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -145,25 +145,35 @@ struct AppTabNavigation: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private var channelView: some View {
|
@ViewBuilder private var channelView: some View {
|
||||||
ChannelVideosView()
|
if navigation.presentingChannel {
|
||||||
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
ChannelVideosView()
|
||||||
.environment(\.inChannelView, true)
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
||||||
.environment(\.navigationStyle, .tab)
|
.environment(\.inChannelView, true)
|
||||||
.environmentObject(accounts)
|
.environment(\.navigationStyle, .tab)
|
||||||
.environmentObject(navigation)
|
.environmentObject(accounts)
|
||||||
.environmentObject(player)
|
.environmentObject(navigation)
|
||||||
.environmentObject(subscriptions)
|
.environmentObject(player)
|
||||||
.environmentObject(thumbnailsModel)
|
.environmentObject(subscriptions)
|
||||||
|
.environmentObject(thumbnailsModel)
|
||||||
|
.transition(.asymmetric(insertion: .flipFromBottom, removal: .move(edge: .bottom)))
|
||||||
|
} else {
|
||||||
|
EmptyView()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var playlistView: some View {
|
@ViewBuilder private var playlistView: some View {
|
||||||
ChannelPlaylistView()
|
if navigation.presentingPlaylist {
|
||||||
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
ChannelPlaylistView()
|
||||||
.environmentObject(accounts)
|
.environment(\.managedObjectContext, persistenceController.container.viewContext)
|
||||||
.environmentObject(navigation)
|
.environmentObject(accounts)
|
||||||
.environmentObject(player)
|
.environmentObject(navigation)
|
||||||
.environmentObject(subscriptions)
|
.environmentObject(player)
|
||||||
.environmentObject(thumbnailsModel)
|
.environmentObject(subscriptions)
|
||||||
|
.environmentObject(thumbnailsModel)
|
||||||
|
.transition(.asymmetric(insertion: .flipFromBottom, removal: .move(edge: .bottom)))
|
||||||
|
} else {
|
||||||
|
EmptyView()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ struct ContentView: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
var videoPlayer: some View {
|
@ViewBuilder var videoPlayer: some View {
|
||||||
VideoPlayerView()
|
VideoPlayerView()
|
||||||
.environmentObject(accounts)
|
.environmentObject(accounts)
|
||||||
.environmentObject(comments)
|
.environmentObject(comments)
|
||||||
|
@ -25,12 +25,15 @@ struct VideoPlayerSizeModifier: ViewModifier {
|
|||||||
|
|
||||||
func body(content: Content) -> some View {
|
func body(content: Content) -> some View {
|
||||||
content
|
content
|
||||||
.frame(maxHeight: fullScreen ? .infinity : maxHeight)
|
.frame(width: geometry.size.width)
|
||||||
.aspectRatio(usedAspectRatio, contentMode: .fit)
|
.frame(maxHeight: maxHeight)
|
||||||
|
#if !os(macOS)
|
||||||
|
.aspectRatio(fullScreen ? nil : usedAspectRatio, contentMode: usedAspectRatioContentMode)
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
var usedAspectRatio: Double {
|
var usedAspectRatio: Double {
|
||||||
guard aspectRatio != nil else {
|
guard aspectRatio != nil, aspectRatio != 0 else {
|
||||||
return VideoPlayerView.defaultAspectRatio
|
return VideoPlayerView.defaultAspectRatio
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +56,10 @@ struct VideoPlayerSizeModifier: ViewModifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var maxHeight: Double {
|
var maxHeight: Double {
|
||||||
|
guard !fullScreen else {
|
||||||
|
return .infinity
|
||||||
|
}
|
||||||
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
let height = verticalSizeClass == .regular ? geometry.size.height - minimumHeightLeft : .infinity
|
let height = verticalSizeClass == .regular ? geometry.size.height - minimumHeightLeft : .infinity
|
||||||
#else
|
#else
|
||||||
|
@ -21,10 +21,12 @@ struct VideoPlayerView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@State private var playerSize: CGSize = .zero { didSet {
|
@State private var playerSize: CGSize = .zero { didSet {
|
||||||
if playerSize.width > 900 && Defaults[.playerSidebar] == .whenFits {
|
withAnimation {
|
||||||
sidebarQueue = true
|
if playerSize.width > 900 && Defaults[.playerSidebar] == .whenFits {
|
||||||
} else {
|
sidebarQueue = true
|
||||||
sidebarQueue = false
|
} else {
|
||||||
|
sidebarQueue = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@State private var hoveringPlayer = false
|
@State private var hoveringPlayer = false
|
||||||
@ -92,6 +94,7 @@ struct VideoPlayerView: View {
|
|||||||
playerSize = geometry.size
|
playerSize = geometry.size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// .ignoresSafeArea(.all, edges: playerEdgesIgnoringSafeArea)
|
||||||
.onChange(of: geometry.size) { size in
|
.onChange(of: geometry.size) { size in
|
||||||
self.playerSize = size
|
self.playerSize = size
|
||||||
}
|
}
|
||||||
@ -134,6 +137,15 @@ struct VideoPlayerView: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var playerEdgesIgnoringSafeArea: Edge.Set {
|
||||||
|
#if os(iOS)
|
||||||
|
if fullScreenLayout, UIDevice.current.orientation.isLandscape {
|
||||||
|
return [.vertical]
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
var content: some View {
|
var content: some View {
|
||||||
Group {
|
Group {
|
||||||
ZStack(alignment: .bottomLeading) {
|
ZStack(alignment: .bottomLeading) {
|
||||||
@ -173,23 +185,25 @@ struct VideoPlayerView: View {
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
GeometryReader { geometry in
|
GeometryReader { geometry in
|
||||||
VStack(spacing: 0) {
|
Group {
|
||||||
if player.playingInPictureInPicture {
|
if player.playingInPictureInPicture {
|
||||||
pictureInPicturePlaceholder
|
pictureInPicturePlaceholder
|
||||||
} else {
|
} else {
|
||||||
playerView
|
playerView
|
||||||
|
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
.modifier(
|
.modifier(
|
||||||
VideoPlayerSizeModifier(
|
VideoPlayerSizeModifier(
|
||||||
geometry: geometry,
|
geometry: geometry,
|
||||||
aspectRatio: player.avPlayerBackend.controller?.aspectRatio,
|
aspectRatio: player.backend.aspectRatio,
|
||||||
fullScreen: player.playingFullScreen
|
fullScreen: fullScreenLayout
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.overlay(playerPlaceholder)
|
.overlay(playerPlaceholder)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// .ignoresSafeArea(.all, edges: fullScreenLayout ? .bottom : Edge.Set())
|
||||||
.frame(maxWidth: fullScreenLayout ? .infinity : nil, maxHeight: fullScreenLayout ? .infinity : nil)
|
.frame(maxWidth: fullScreenLayout ? .infinity : nil, maxHeight: fullScreenLayout ? .infinity : nil)
|
||||||
.onHover { hovering in
|
.onHover { hovering in
|
||||||
hoveringPlayer = hovering
|
hoveringPlayer = hovering
|
||||||
@ -197,7 +211,7 @@ struct VideoPlayerView: View {
|
|||||||
}
|
}
|
||||||
#if !os(macOS)
|
#if !os(macOS)
|
||||||
.gesture(
|
.gesture(
|
||||||
DragGesture(coordinateSpace: .global)
|
DragGesture(minimumDistance: 0, coordinateSpace: .global)
|
||||||
.onChanged { value in
|
.onChanged { value in
|
||||||
guard player.presentingPlayer,
|
guard player.presentingPlayer,
|
||||||
!playerControls.presentingControlsOverlay else { return }
|
!playerControls.presentingControlsOverlay else { return }
|
||||||
@ -242,20 +256,19 @@ struct VideoPlayerView: View {
|
|||||||
if !player.playingFullScreen {
|
if !player.playingFullScreen {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
if verticalSizeClass == .regular {
|
VideoDetails(sidebarQueue: sidebarQueue, fullScreen: $fullScreenDetails)
|
||||||
VideoDetails(sidebarQueue: sidebarQueue, fullScreen: $fullScreenDetails)
|
.edgesIgnoringSafeArea(.bottom)
|
||||||
.edgesIgnoringSafeArea(.bottom)
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
VideoDetails(sidebarQueue: sidebarQueue, fullScreen: $fullScreenDetails)
|
VideoDetails(sidebarQueue: sidebarQueue, fullScreen: $fullScreenDetails)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
#if !os(macOS)
|
||||||
|
.transition(.move(edge: .bottom))
|
||||||
|
#endif
|
||||||
.background(colorScheme == .dark ? Color.black : Color.white)
|
.background(colorScheme == .dark ? Color.black : Color.white)
|
||||||
.modifier(VideoDetailsPaddingModifier(
|
.modifier(VideoDetailsPaddingModifier(
|
||||||
playerSize: player.playerSize,
|
playerSize: player.playerSize,
|
||||||
aspectRatio: player.avPlayerBackend.controller?.aspectRatio,
|
aspectRatio: player.backend.aspectRatio,
|
||||||
fullScreen: fullScreenDetails
|
fullScreen: fullScreenDetails
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -263,6 +276,7 @@ struct VideoPlayerView: View {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
.background(((colorScheme == .dark || fullScreenLayout) ? Color.black : Color.white).edgesIgnoringSafeArea(.all))
|
.background(((colorScheme == .dark || fullScreenLayout) ? Color.black : Color.white).edgesIgnoringSafeArea(.all))
|
||||||
#if os(macOS)
|
#if os(macOS)
|
||||||
.frame(minWidth: 650)
|
.frame(minWidth: 650)
|
||||||
@ -272,6 +286,7 @@ struct VideoPlayerView: View {
|
|||||||
if sidebarQueue {
|
if sidebarQueue {
|
||||||
PlayerQueueView(sidebarQueue: true, fullScreen: $fullScreenDetails)
|
PlayerQueueView(sidebarQueue: true, fullScreen: $fullScreenDetails)
|
||||||
.frame(maxWidth: 350)
|
.frame(maxWidth: 350)
|
||||||
|
.transition(.move(edge: .trailing))
|
||||||
}
|
}
|
||||||
#elseif os(macOS)
|
#elseif os(macOS)
|
||||||
if Defaults[.playerSidebar] != .never {
|
if Defaults[.playerSidebar] != .never {
|
||||||
@ -281,49 +296,66 @@ struct VideoPlayerView: View {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ignoresSafeArea(.all, edges: fullScreenLayout ? .vertical : Edge.Set())
|
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
.statusBar(hidden: player.playingFullScreen)
|
.statusBar(hidden: player.playingFullScreen)
|
||||||
.navigationBarHidden(true)
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
var playerView: some View {
|
var playerView: some View {
|
||||||
ZStack(alignment: .top) {
|
ZStack(alignment: .top) {
|
||||||
switch player.activeBackend {
|
Group {
|
||||||
case .mpv:
|
switch player.activeBackend {
|
||||||
player.mpvPlayerView
|
case .mpv:
|
||||||
.overlay(GeometryReader { proxy in
|
player.mpvPlayerView
|
||||||
Color.clear
|
.overlay(GeometryReader { proxy in
|
||||||
.onAppear {
|
Color.clear
|
||||||
player.playerSize = proxy.size
|
.onAppear {
|
||||||
}
|
player.playerSize = proxy.size
|
||||||
.onChange(of: proxy.size) { _ in
|
}
|
||||||
player.playerSize = proxy.size
|
.onChange(of: proxy.size) { _ in
|
||||||
}
|
player.playerSize = proxy.size
|
||||||
})
|
}
|
||||||
case .appleAVPlayer:
|
})
|
||||||
player.avPlayerView
|
case .appleAVPlayer:
|
||||||
#if os(iOS)
|
player.avPlayerView
|
||||||
.onAppear {
|
#if os(iOS)
|
||||||
player.pipController = .init(playerLayer: player.playerLayerView.playerLayer)
|
.onAppear {
|
||||||
let pipDelegate = PiPDelegate()
|
player.pipController = .init(playerLayer: player.playerLayerView.playerLayer)
|
||||||
pipDelegate.player = player
|
let pipDelegate = PiPDelegate()
|
||||||
|
pipDelegate.player = player
|
||||||
|
|
||||||
player.pipDelegate = pipDelegate
|
player.pipDelegate = pipDelegate
|
||||||
player.pipController?.delegate = pipDelegate
|
player.pipController?.delegate = pipDelegate
|
||||||
player.playerLayerView.playerLayer.player = player.avPlayerBackend.avPlayer
|
player.playerLayerView.playerLayer.player = player.avPlayerBackend.avPlayer
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#if os(iOS)
|
||||||
|
.padding(.top, player.playingFullScreen && verticalSizeClass == .regular ? 20 : 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !os(tvOS)
|
#if !os(tvOS)
|
||||||
PlayerGestures()
|
PlayerGestures()
|
||||||
PlayerControls(player: player, thumbnails: thumbnails)
|
PlayerControls(player: player, thumbnails: thumbnails)
|
||||||
|
#if os(iOS)
|
||||||
|
.padding(.top, fullScreenLayout ? (safeAreaInsets.top.isZero ? safeAreaInsets.bottom : safeAreaInsets.top) : 0)
|
||||||
|
.padding(.bottom, fullScreenLayout ? safeAreaInsets.bottom : 0)
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
.ignoresSafeArea(.all, edges: fullScreenLayout ? .vertical : Edge.Set())
|
||||||
|
#if os(iOS)
|
||||||
|
.statusBarHidden(fullScreenLayout)
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if os(iOS)
|
||||||
|
var safeAreaInsets: UIEdgeInsets {
|
||||||
|
UIApplication.shared.windows.first?.safeAreaInsets ?? .init()
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
var fullScreenLayout: Bool {
|
var fullScreenLayout: Bool {
|
||||||
#if os(iOS)
|
#if os(iOS)
|
||||||
player.playingFullScreen || verticalSizeClass == .compact
|
player.playingFullScreen || verticalSizeClass == .compact
|
||||||
@ -471,10 +503,6 @@ struct VideoPlayerView: View {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
|
|
||||||
player.exitFullScreen()
|
|
||||||
}
|
|
||||||
|
|
||||||
Orientation.lockOrientation(.portrait)
|
Orientation.lockOrientation(.portrait)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,8 +61,6 @@ struct ChannelPlaylistView: View {
|
|||||||
viewVerticalOffset = Self.hiddenOffset
|
viewVerticalOffset = Self.hiddenOffset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.offset(y: viewVerticalOffset)
|
|
||||||
.animation(.easeIn(duration: 0.2), value: viewVerticalOffset)
|
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
BrowserPlayerControls {
|
BrowserPlayerControls {
|
||||||
@ -105,7 +103,9 @@ struct ChannelPlaylistView: View {
|
|||||||
ToolbarItem(placement: .navigation) {
|
ToolbarItem(placement: .navigation) {
|
||||||
if navigationStyle == .tab {
|
if navigationStyle == .tab {
|
||||||
Button("Done") {
|
Button("Done") {
|
||||||
navigation.presentingPlaylist = false
|
withAnimation {
|
||||||
|
navigation.presentingPlaylist = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,8 +57,6 @@ struct ChannelVideosView: View {
|
|||||||
viewVerticalOffset = Self.hiddenOffset
|
viewVerticalOffset = Self.hiddenOffset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.offset(y: viewVerticalOffset)
|
|
||||||
.animation(.easeIn(duration: 0.2), value: viewVerticalOffset)
|
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
BrowserPlayerControls {
|
BrowserPlayerControls {
|
||||||
@ -104,7 +102,9 @@ struct ChannelVideosView: View {
|
|||||||
ToolbarItem(placement: .navigation) {
|
ToolbarItem(placement: .navigation) {
|
||||||
if navigationStyle == .tab {
|
if navigationStyle == .tab {
|
||||||
Button("Done") {
|
Button("Done") {
|
||||||
navigation.presentingChannel = false
|
withAnimation {
|
||||||
|
navigation.presentingChannel = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user