From 3f871bce2cf3098b0502bfaa96cabba9ebafa7a0 Mon Sep 17 00:00:00 2001 From: Arkadiusz Fal Date: Sat, 24 Aug 2024 17:52:35 +0200 Subject: [PATCH] Fix possible crashes --- Model/Player/Backends/MPVBackend.swift | 4 +- Model/PlaylistsModel.swift | 5 +- Shared/Player/PlayerViewController.swift | 211 ----------------------- 3 files changed, 6 insertions(+), 214 deletions(-) delete mode 100644 Shared/Player/PlayerViewController.swift diff --git a/Model/Player/Backends/MPVBackend.swift b/Model/Player/Backends/MPVBackend.swift index 49cfb2f7..a79f95eb 100644 --- a/Model/Player/Backends/MPVBackend.swift +++ b/Model/Player/Backends/MPVBackend.swift @@ -360,8 +360,8 @@ final class MPVBackend: PlayerBackend { setRate(model.currentRate) // After the video has ended, hitting play restarts the video from the beginning. - if currentTime?.seconds.formattedAsPlaybackTime() == model.playerTime.duration.seconds.formattedAsPlaybackTime() && - currentTime!.seconds > 0 && model.playerTime.duration.seconds > 0 + if let currentTime, currentTime.seconds.formattedAsPlaybackTime() == model.playerTime.duration.seconds.formattedAsPlaybackTime() && + currentTime.seconds > 0 && model.playerTime.duration.seconds > 0 { seek(to: 0, seekType: .loopRestart) } diff --git a/Model/PlaylistsModel.swift b/Model/PlaylistsModel.swift index 5f8659ad..52024f64 100644 --- a/Model/PlaylistsModel.swift +++ b/Model/PlaylistsModel.swift @@ -69,7 +69,10 @@ final class PlaylistsModel: ObservableObject { .onSuccess { resource in self.error = nil if let playlists: [Playlist] = resource.typedContent() { - self.playlists = playlists + DispatchQueue.main.async { [weak self] in + guard let self else { return } + self.playlists = playlists + } PlaylistsCacheModel.shared.storePlaylist(account: account, playlists: playlists) onSuccess() } diff --git a/Shared/Player/PlayerViewController.swift b/Shared/Player/PlayerViewController.swift deleted file mode 100644 index 6084f016..00000000 --- a/Shared/Player/PlayerViewController.swift +++ /dev/null @@ -1,211 +0,0 @@ -import AVKit -import Defaults -import SwiftUI - -final class PlayerViewController: UIViewController { - var playerLoaded = false - var commentsModel: CommentsModel! - var navigationModel: NavigationModel! - var playerModel: PlayerModel! - var subscriptionsModel: SubscriptionsModel! - var playerView = AVPlayerViewController() - - let persistenceController = PersistenceController.shared - - #if !os(tvOS) - var aspectRatio: Double? { - let ratio = Double(playerView.videoBounds.width) / Double(playerView.videoBounds.height) - - guard ratio.isFinite else { - return VideoPlayerView.defaultAspectRatio // swiftlint:disable:this implicit_return - } - - return [ratio, 1.0].max()! - } - #endif - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - loadPlayer() - - #if os(tvOS) - if !playerView.isBeingPresented, !playerView.isBeingDismissed { - present(playerView, animated: false) - } - #endif - } - - #if os(tvOS) - override func viewDidDisappear(_ animated: Bool) { - super.viewDidDisappear(animated) - - if !playerModel.presentingPlayer, !Defaults[.pauseOnHidingPlayer], !playerModel.isPlaying { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in - self?.playerModel.play() - } - } - } - #endif - - func loadPlayer() { - guard !playerLoaded else { - return - } - - playerModel.controller = self - playerView.player = playerModel.player - playerView.allowsPictureInPicturePlayback = true - #if os(iOS) - if #available(iOS 14.2, *) { - playerView.canStartPictureInPictureAutomaticallyFromInline = true - } - #endif - playerView.delegate = self - - #if os(tvOS) - var infoViewControllers = [UIHostingController]() - if CommentsModel.enabled { - infoViewControllers.append(infoViewController([.comments], title: "Comments")) - } - - var queueSections = [NowPlayingView.ViewSection.playingNext] - if Defaults[.showHistoryInPlayer] { - queueSections.append(.playedPreviously) - } - - infoViewControllers.append(contentsOf: [ - infoViewController([.related], title: "Related"), - infoViewController(queueSections, title: "Queue") - ]) - - playerView.customInfoViewControllers = infoViewControllers - #else - embedViewController() - #endif - } - - #if os(tvOS) - func infoViewController( - _ sections: [NowPlayingView.ViewSection], - title: String - ) -> UIHostingController { - let controller = UIHostingController( - rootView: - AnyV/Users/arek/Developer/Yattee/Shared/Player/PlayerViewController.swift.iew( - NowPlayingView(sections: sections, inInfoViewController: true) - .frame(maxHeight: 600) - .environmentObject(commentsModel) - .environmentObject(playerModel) - .environmentObject(subscriptionsModel) - .environment(\.managedObjectContext, persistenceController.container.viewContext) - ) - ) - - controller.title = title - - return controller - } - #else - func embedViewController() { - playerView.view.frame = view.bounds - - addChild(playerView) - view.addSubview(playerView.view) - - playerView.didMove(toParent: self) - } - #endif -} - -extension PlayerViewController: AVPlayerViewControllerDelegate { - func playerViewControllerShouldDismiss(_: AVPlayerViewController) -> Bool { - true - } - - func playerViewControllerShouldAutomaticallyDismissAtPictureInPictureStart(_: AVPlayerViewController) -> Bool { - true - } - - func playerViewControllerWillBeginDismissalTransition(_: AVPlayerViewController) { - if Defaults[.pauseOnHidingPlayer] { - playerModel.pause() - } - dismiss(animated: false) - } - - func playerViewControllerDidEndDismissalTransition(_: AVPlayerViewController) {} - - func playerViewController( - _: AVPlayerViewController, - willBeginFullScreenPresentationWithAnimationCoordinator context: UIViewControllerTransitionCoordinator - ) { - playerModel.playingFullscreen = true - - #if os(iOS) - if !context.isCancelled, Defaults[.lockLandscapeWhenEnteringFullscreen] { - Orientation.lockOrientation(.landscape, andRotateTo: UIDevice.current.orientation.isLandscape ? nil : .landscapeRight) - } - #endif - } - - func playerViewController( - _: AVPlayerViewController, - willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator - ) { - let wasPlaying = playerModel.isPlaying - coordinator.animate(alongsideTransition: nil) { context in - #if os(iOS) - if wasPlaying { - self.playerModel.play() - } - #endif - if !context.isCancelled { - #if os(iOS) - self.playerModel.lockedOrientation = nil - if Defaults[.enterFullscreenInLandscape] { - Orientation.lockOrientation(.portrait, andRotateTo: .portrait) - } - - self.playerModel.playingFullscreen = false - - if wasPlaying { - self.playerModel.play() - } - #endif - } - } - } - - func playerViewController( - _: AVPlayerViewController, - restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void - ) { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - if self.navigationModel.presentingChannel { - self.playerModel.playerNavigationLinkActive = true - } else { - self.playerModel.show() - } - - #if os(tvOS) - if self.playerModel.playingInPictureInPicture { - self.present(self.playerView, animated: false) { - completionHandler(true) - } - } - #else - completionHandler(true) - #endif - } - } - - func playerViewControllerWillStartPictureInPicture(_: AVPlayerViewController) { - playerModel.playingInPictureInPicture = true - playerModel.playerNavigationLinkActive = false - } - - func playerViewControllerWillStopPictureInPicture(_: AVPlayerViewController) { - playerModel.playingInPictureInPicture = false - } -}