mirror of
https://github.com/metabolist/metatext.git
synced 2024-05-28 21:28:04 +00:00
Media playing
This commit is contained in:
parent
fe6aa0f115
commit
f4cd293ec2
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue