diff --git a/Mastodon/Diffiable/Section/StatusSection.swift b/Mastodon/Diffiable/Section/StatusSection.swift index 1d0169ab8..53f7aec87 100644 --- a/Mastodon/Diffiable/Section/StatusSection.swift +++ b/Mastodon/Diffiable/Section/StatusSection.swift @@ -37,7 +37,11 @@ extension StatusSection { StatusSection.configure( cell: cell, dependency: dependency, - readableLayoutFrame: tableView.readableContentGuide.layoutFrame, timestampUpdatePublisher: timestampUpdatePublisher, toot: timelineIndex.toot, requestUserID: timelineIndex.userID, statusItemAttribute: attribute + readableLayoutFrame: tableView.readableContentGuide.layoutFrame, + timestampUpdatePublisher: timestampUpdatePublisher, + toot: timelineIndex.toot, + requestUserID: timelineIndex.userID, + statusItemAttribute: attribute ) } cell.delegate = statusTableViewCellDelegate @@ -52,7 +56,11 @@ extension StatusSection { StatusSection.configure( cell: cell, dependency: dependency, - readableLayoutFrame: tableView.readableContentGuide.layoutFrame, timestampUpdatePublisher: timestampUpdatePublisher, toot: toot, requestUserID: requestUserID, statusItemAttribute: attribute + readableLayoutFrame: tableView.readableContentGuide.layoutFrame, + timestampUpdatePublisher: timestampUpdatePublisher, + toot: toot, + requestUserID: requestUserID, + statusItemAttribute: attribute ) } cell.delegate = statusTableViewCellDelegate @@ -168,7 +176,7 @@ extension StatusSection { // set audio if let audioAttachment = mediaAttachments.filter({ $0.type == .audio }).first { cell.statusView.audioView.isHidden = false - AudioContainerViewModel.configure(cell: cell, audioAttachment: audioAttachment, videoPlaybackService: dependency.context.videoPlaybackService) + AudioContainerViewModel.configure(cell: cell, audioAttachment: audioAttachment ) } else { cell.statusView.audioView.isHidden = true } diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index c9498dbea..01b860da8 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -141,7 +141,7 @@ extension HomeTimelineViewController { override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) - + context.videoPlaybackService.viewDidDisappear(from: self) } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { @@ -236,7 +236,10 @@ extension HomeTimelineViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { handleTableView(tableView, willDisplay: cell, forRowAt: indexPath) } - + + func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { + handleTableView(tableView, didEndDisplaying: cell, forRowAt: indexPath) + } } // MARK: - ContentOffsetAdjustableTimelineViewControllerDelegate diff --git a/Mastodon/Scene/PublicTimeline/PublicTimelineViewController.swift b/Mastodon/Scene/PublicTimeline/PublicTimelineViewController.swift index 50d36d296..820094b1e 100644 --- a/Mastodon/Scene/PublicTimeline/PublicTimelineViewController.swift +++ b/Mastodon/Scene/PublicTimeline/PublicTimelineViewController.swift @@ -81,6 +81,10 @@ extension PublicTimelineViewController { ) } + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + context.videoPlaybackService.viewDidDisappear(from: self) + } } // MARK: - UIScrollViewDelegate @@ -103,6 +107,7 @@ extension PublicTimelineViewController { // MARK: - UITableViewDelegate extension PublicTimelineViewController: UITableViewDelegate { func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { + guard let diffableDataSource = viewModel.diffableDataSource else { return 100 } guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return 100 } @@ -114,8 +119,11 @@ extension PublicTimelineViewController: UITableViewDelegate { } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {} - + func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + handleTableView(tableView, willDisplay: cell, forRowAt: indexPath) + } func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) { + handleTableView(tableView, didEndDisplaying: cell, forRowAt: indexPath) guard let diffableDataSource = viewModel.diffableDataSource else { return } guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return } diff --git a/Mastodon/Scene/Share/ViewModel/AudioContainerViewModel.swift b/Mastodon/Scene/Share/ViewModel/AudioContainerViewModel.swift index 7370c4fef..de804a475 100644 --- a/Mastodon/Scene/Share/ViewModel/AudioContainerViewModel.swift +++ b/Mastodon/Scene/Share/ViewModel/AudioContainerViewModel.swift @@ -12,8 +12,7 @@ import UIKit class AudioContainerViewModel { static func configure( cell: StatusTableViewCell, - audioAttachment: Attachment, - videoPlaybackService: VideoPlaybackService + audioAttachment: Attachment ) { guard let duration = audioAttachment.meta?.original?.duration else { return } let audioView = cell.statusView.audioView @@ -26,15 +25,12 @@ class AudioContainerViewModel { AudioPlayer.shared.pause() } else { AudioPlayer.shared.resume() - videoPlaybackService.pauseWhenPlayAudio() } if AudioPlayer.shared.currentTimeSubject.value == 0 { AudioPlayer.shared.playAudio(audioAttachment: audioAttachment) - videoPlaybackService.pauseWhenPlayAudio() } } else { AudioPlayer.shared.playAudio(audioAttachment: audioAttachment) - videoPlaybackService.pauseWhenPlayAudio() } } .store(in: &cell.disposeBag) diff --git a/Mastodon/Scene/Share/ViewModel/VideoPlayerViewModel.swift b/Mastodon/Scene/Share/ViewModel/VideoPlayerViewModel.swift index e0a2f5ef4..c3f2cf369 100644 --- a/Mastodon/Scene/Share/ViewModel/VideoPlayerViewModel.swift +++ b/Mastodon/Scene/Share/ViewModel/VideoPlayerViewModel.swift @@ -14,6 +14,7 @@ import UIKit final class VideoPlayerViewModel { var disposeBag = Set() + static let appWillPlayVideoNotification = NSNotification.Name(rawValue: "appWillPlayVideoNotification") // input let previewImageURL: URL? let videoURL: URL @@ -63,7 +64,7 @@ final class VideoPlayerViewModel { .sink { [weak self] timeControlStatus in guard let _ = self else { return } guard timeControlStatus == .playing else { return } - AudioPlayer.shared.pauseIfNeed() + NotificationCenter.default.post(name: VideoPlayerViewModel.appWillPlayVideoNotification, object: nil) switch videoKind { case .gif: break diff --git a/Mastodon/Service/AudioPlayer.swift b/Mastodon/Service/AudioPlayer.swift index 02c948c29..646207edb 100644 --- a/Mastodon/Service/AudioPlayer.swift +++ b/Mastodon/Service/AudioPlayer.swift @@ -12,6 +12,9 @@ import Foundation import UIKit final class AudioPlayer: NSObject { + + static let appWillPlayAudioNotification = NSNotification.Name(rawValue: "appWillPlayAudioNotification") + var disposeBag = Set() var player = AVPlayer() @@ -45,6 +48,7 @@ extension AudioPlayer { return } + pushWillPlayAudioNotification() if audioAttachment == attachment { if self.playbackState.value == .stopped { self.seekToTime(time: .zero) @@ -83,6 +87,12 @@ extension AudioPlayer { } } .store(in: &disposeBag) + NotificationCenter.default.publisher(for: VideoPlayerViewModel.appWillPlayVideoNotification) + .sink { [weak self] _ in + guard let self = self else { return } + self.pauseIfNeed() + } + .store(in: &disposeBag) timeObserver = player.addPeriodicTimeObserver(forInterval: CMTimeMake(value: 1, timescale: CMTimeScale(NSEC_PER_SEC)), queue: DispatchQueue.main, using: { [weak self] time in guard let self = self else { return } @@ -119,10 +129,14 @@ extension AudioPlayer { .store(in: &disposeBag) } + func pushWillPlayAudioNotification() { + NotificationCenter.default.post(name: AudioPlayer.appWillPlayAudioNotification, object: nil) + } func isPlaying() -> Bool { - return self.playbackState.value == .readyToPlay || self.playbackState.value == .playing + return playbackState.value == .readyToPlay || playbackState.value == .playing } func resume() { + pushWillPlayAudioNotification() player.play() playbackState.value = .playing } diff --git a/Mastodon/Service/ViedeoPlaybackService.swift b/Mastodon/Service/ViedeoPlaybackService.swift index 724026fdd..49ac3b0df 100644 --- a/Mastodon/Service/ViedeoPlaybackService.swift +++ b/Mastodon/Service/ViedeoPlaybackService.swift @@ -90,6 +90,13 @@ extension VideoPlaybackService { self.playerViewModel(viewModel, didUpdateTimeControlStatus: timeControlStatus) } .store(in: &disposeBag) + + NotificationCenter.default.publisher(for: AudioPlayer.appWillPlayAudioNotification) + .sink { [weak self] _ in + guard let self = self else { return } + self.pauseWhenPlayAudio() + } + .store(in: &disposeBag) } }