Media playing

This commit is contained in:
Justin Mazzocchi 2020-10-19 23:41:10 -07:00
parent fe6aa0f115
commit f4cd293ec2
No known key found for this signature in database
GPG key ID: E223E6937AAFB01C
6 changed files with 67 additions and 11 deletions

View file

@ -1,5 +1,6 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import AVKit
import Combine import Combine
import UIKit import UIKit
@ -27,6 +28,8 @@ extension AppDelegate: UIApplicationDelegate {
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
self.application = application self.application = application
try? AVAudioSession.sharedInstance().setCategory(.ambient, mode: .default)
return true return true
} }

View file

@ -1,5 +1,6 @@
// Copyright © 2020 Metabolist. All rights reserved. // Copyright © 2020 Metabolist. All rights reserved.
import AVKit
import Combine import Combine
import SafariServices import SafariServices
import SwiftUI import SwiftUI
@ -170,6 +171,16 @@ extension TableViewController {
} }
} }
extension TableViewController: AVPlayerViewControllerDelegate {
func playerViewController(
_ playerViewController: AVPlayerViewController,
willEndFullScreenPresentationWithAnimationCoordinator coordinator: UIViewControllerTransitionCoordinator) {
try? AVAudioSession.sharedInstance().setCategory(.ambient, mode: .default)
playerViewController.player?.isMuted = true
updateAutoplayViews()
}
}
private extension TableViewController { private extension TableViewController {
static let autoplayViews = [PlayerView](repeating: .init(), count: 4) static let autoplayViews = [PlayerView](repeating: .init(), count: 4)
static var visibleVideoURLs = Set<URL>() static var visibleVideoURLs = Set<URL>()
@ -250,7 +261,7 @@ private extension TableViewController {
break break
case let .share(url): case let .share(url):
share(url: url) share(url: url)
case let.navigation(navigation): case let .navigation(navigation):
switch navigation { switch navigation {
case let .collection(collectionService): case let .collection(collectionService):
show(TableViewController( show(TableViewController(
@ -273,6 +284,35 @@ private extension TableViewController {
case .webfingerEnd: case .webfingerEnd:
webfingerIndicatorView.stopAnimating() webfingerIndicatorView.stopAnimating()
} }
case let .attachment(attachmentViewModel, statusViewModel):
present(attachmentViewModel: attachmentViewModel, statusViewModel: statusViewModel)
}
}
func present(attachmentViewModel: AttachmentViewModel, statusViewModel: StatusViewModel) {
switch attachmentViewModel.attachment.type {
case .audio, .video:
let playerViewController = AVPlayerViewController()
let player: AVPlayer
if attachmentViewModel.attachment.type == .video {
player = PlayerCache.shared.player(url: attachmentViewModel.attachment.url)
} else {
player = AVPlayer(url: attachmentViewModel.attachment.url)
}
playerViewController.delegate = self
playerViewController.player = player
present(playerViewController, animated: true) {
try? AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
player.isMuted = false
player.play()
}
case .image, .gifv:
break
case .unknown:
break
} }
} }

View file

@ -6,5 +6,6 @@ import ServiceLayer
public enum CollectionItemEvent { public enum CollectionItemEvent {
case ignorableOutput case ignorableOutput
case navigation(Navigation) case navigation(Navigation)
case attachment(AttachmentViewModel, StatusViewModel)
case share(URL) case share(URL)
} }

View file

@ -127,28 +127,28 @@ public extension StatusViewModel {
func toggleShowContent() { func toggleShowContent() {
eventsSubject.send( eventsSubject.send(
statusService.toggleShowContent() statusService.toggleShowContent()
.map { _ in CollectionItemEvent.ignorableOutput } .map { _ in .ignorableOutput }
.eraseToAnyPublisher()) .eraseToAnyPublisher())
} }
func toggleShowAttachments() { func toggleShowAttachments() {
eventsSubject.send( eventsSubject.send(
statusService.toggleShowAttachments() statusService.toggleShowAttachments()
.map { _ in CollectionItemEvent.ignorableOutput } .map { _ in .ignorableOutput }
.eraseToAnyPublisher()) .eraseToAnyPublisher())
} }
func urlSelected(_ url: URL) { func urlSelected(_ url: URL) {
eventsSubject.send( eventsSubject.send(
statusService.navigationService.item(url: url) statusService.navigationService.item(url: url)
.map { CollectionItemEvent.navigation($0) } .map { .navigation($0) }
.setFailureType(to: Error.self) .setFailureType(to: Error.self)
.eraseToAnyPublisher()) .eraseToAnyPublisher())
} }
func accountSelected() { func accountSelected() {
eventsSubject.send( eventsSubject.send(
Just(CollectionItemEvent.navigation( Just(.navigation(
.profile( .profile(
statusService.navigationService.profileService( statusService.navigationService.profileService(
account: statusService.status.displayStatus.account)))) account: statusService.status.displayStatus.account))))
@ -158,14 +158,14 @@ public extension StatusViewModel {
func rebloggedBySelected() { func rebloggedBySelected() {
eventsSubject.send( eventsSubject.send(
Just(CollectionItemEvent.navigation(.collection(statusService.rebloggedByService()))) Just(.navigation(.collection(statusService.rebloggedByService())))
.setFailureType(to: Error.self) .setFailureType(to: Error.self)
.eraseToAnyPublisher()) .eraseToAnyPublisher())
} }
func favoritedBySelected() { func favoritedBySelected() {
eventsSubject.send( eventsSubject.send(
Just(CollectionItemEvent.navigation(.collection(statusService.favoritedByService()))) Just(.navigation(.collection(statusService.favoritedByService())))
.setFailureType(to: Error.self) .setFailureType(to: Error.self)
.eraseToAnyPublisher()) .eraseToAnyPublisher())
} }
@ -173,14 +173,18 @@ public extension StatusViewModel {
func toggleFavorited() { func toggleFavorited() {
eventsSubject.send( eventsSubject.send(
statusService.toggleFavorited() statusService.toggleFavorited()
.map { _ in CollectionItemEvent.ignorableOutput } .map { _ in .ignorableOutput }
.eraseToAnyPublisher()) .eraseToAnyPublisher())
} }
func attachmentSelected(viewModel: AttachmentViewModel) {
eventsSubject.send(Just(.attachment(viewModel, self)).setFailureType(to: Error.self).eraseToAnyPublisher())
}
func shareStatus() { func shareStatus() {
guard let url = statusService.status.displayStatus.url else { return } guard let url = statusService.status.displayStatus.url else { return }
eventsSubject.send(Just(CollectionItemEvent.share(url)).setFailureType(to: Error.self).eraseToAnyPublisher()) eventsSubject.send(Just(.share(url)).setFailureType(to: Error.self).eraseToAnyPublisher())
} }
} }

View file

@ -109,6 +109,10 @@ private extension StatusAttachmentView {
switch viewModel.attachment.type { switch viewModel.attachment.type {
case .image, .video, .gifv: case .image, .video, .gifv:
imageView.kf.setImage(with: viewModel.attachment.previewUrl) imageView.kf.setImage(with: viewModel.attachment.previewUrl)
case .audio:
playImageView.image = UIImage(systemName: "waveform.circle",
withConfiguration: UIImage.SymbolConfiguration(textStyle: .largeTitle))
backgroundColor = .secondarySystemBackground
default: default:
break break
} }

View file

@ -30,8 +30,12 @@ final class StatusAttachmentsView: UIView {
rightStackView.isHidden = attachmentCount == 1 rightStackView.isHidden = attachmentCount == 1
for (index, viewModel) in attachmentViewModels.enumerated() { for (index, attachmentViewModel) in attachmentViewModels.enumerated() {
let attachmentView = StatusAttachmentView(viewModel: viewModel) let attachmentView = StatusAttachmentView(viewModel: attachmentViewModel)
attachmentView.button.addAction(
UIAction { [weak self] _ in self?.viewModel?.attachmentSelected(viewModel: attachmentViewModel) },
for: .touchUpInside)
if attachmentCount == 2 && index == 1 if attachmentCount == 2 && index == 1
|| attachmentCount == 3 && index != 0 || attachmentCount == 3 && index != 0