diff --git a/NextcloudTalk/NCMediaViewerPageViewController.swift b/NextcloudTalk/NCMediaViewerPageViewController.swift index 81a0c4f8b..507d24929 100644 --- a/NextcloudTalk/NCMediaViewerPageViewController.swift +++ b/NextcloudTalk/NCMediaViewerPageViewController.swift @@ -3,13 +3,15 @@ // SPDX-License-Identifier: GPL-3.0-or-later // +import AVKit +import AVFoundation import Foundation import UIKit import SwiftyGif @objc protocol NCMediaViewerPageViewControllerDelegate { @objc func mediaViewerPageZoomDidChange(_ controller: NCMediaViewerPageViewController, _ scale: Double) - @objc func mediaViewerPageImageDidLoad(_ controller: NCMediaViewerPageViewController) + @objc func mediaViewerPageMediaDidLoad(_ controller: NCMediaViewerPageViewController) } @objcMembers class NCMediaViewerPageViewController: UIViewController, NCChatFileControllerDelegate, NCZoomableViewDelegate { @@ -72,6 +74,10 @@ import SwiftyGif return self.imageView.image } + public var currentVideoURL: URL? + + private var playerViewController: AVPlayerViewController? + private lazy var activityIndicator = { let indicator = NCActivityIndicator(frame: .init(x: 0, y: 0, width: 100, height: 100)) indicator.translatesAutoresizingMaskIntoConstraints = false @@ -121,6 +127,7 @@ import SwiftyGif func showErrorView() { self.imageView.image = nil + self.removePlayerViewControllerIfNeeded() self.view.addSubview(self.errorView) NSLayoutConstraint.activate([ @@ -136,24 +143,18 @@ import SwiftyGif self.activityIndicator.stopAnimating() self.activityIndicator.isHidden = true - guard let localPath = fileStatus.fileLocalPath, let image = UIImage(contentsOfFile: localPath) else { + guard let localPath = fileStatus.fileLocalPath else { self.showErrorView() return } - if let file = message.file(), message.isAnimatableGif, - let data = try? Data(contentsOf: URL(fileURLWithPath: localPath)), let gifImage = try? UIImage(gifData: data) { - - self.imageView.setGifImage(gifImage) + if NCUtils.isImage(fileType: message.file().mimetype) { + displayImage(from: localPath) + } else if NCUtils.isVideo(fileType: message.file().mimetype) { + playVideo(from: localPath) } else { - self.imageView.image = image + self.showErrorView() } - - // Adjust the view to the new image (use the non-gif version here for correct dimensions) - self.zoomableView.contentViewSize = image.size - self.zoomableView.resizeContentView() - - self.delegate?.mediaViewerPageImageDidLoad(self) } func fileControllerDidFailLoadingFile(_ fileController: NCChatFileController, withErrorDescription errorDescription: String) { @@ -188,4 +189,69 @@ import SwiftyGif func contentViewZoomDidChange(_ view: NCZoomableView, _ scale: Double) { self.delegate?.mediaViewerPageZoomDidChange(self, scale) } + + private func displayImage(from localPath: String) { + guard let image = UIImage(contentsOfFile: localPath) else { + self.showErrorView() + return + } + + if let file = message.file(), message.isAnimatableGif, + let data = try? Data(contentsOf: URL(fileURLWithPath: localPath)), + let gifImage = try? UIImage(gifData: data) { + + self.imageView.setGifImage(gifImage) + } else { + self.imageView.image = image + } + + // Adjust the view to the new image (use the non-gif version here for correct dimensions) + self.zoomableView.contentViewSize = image.size + self.zoomableView.resizeContentView() + + self.zoomableView.isHidden = false + self.imageView.isHidden = false + + removePlayerViewControllerIfNeeded() + self.delegate?.mediaViewerPageMediaDidLoad(self) + } + + private func playVideo(from localPath: String) { + do { + try AVAudioSession.sharedInstance().setCategory(.playback, mode: .moviePlayback, options: []) + try AVAudioSession.sharedInstance().setActive(true) + } catch { + print("Failed to set audio session category: \(error)") + } + + let videoURL = URL(fileURLWithPath: localPath) + self.currentVideoURL = videoURL + let player = AVPlayer(url: videoURL) + let playerViewController = AVPlayerViewController() + playerViewController.player = player + self.playerViewController = playerViewController + + self.addChild(playerViewController) + self.view.addSubview(playerViewController.view) + playerViewController.view.frame = self.view.bounds + playerViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] + playerViewController.didMove(toParent: self) + + self.zoomableView.contentViewSize = playerViewController.view.bounds.size + self.zoomableView.resizeContentView() + self.zoomableView.isHidden = false + self.imageView.isHidden = true + + self.delegate?.mediaViewerPageMediaDidLoad(self) + } + + private func removePlayerViewControllerIfNeeded() { + if let playerVC = self.playerViewController { + playerVC.willMove(toParent: nil) + playerVC.view.removeFromSuperview() + playerVC.removeFromParent() + self.playerViewController = nil + self.currentVideoURL = nil + } + } } diff --git a/NextcloudTalk/NCMediaViewerViewController.swift b/NextcloudTalk/NCMediaViewerViewController.swift index ed75a2af8..e37bb792d 100644 --- a/NextcloudTalk/NCMediaViewerViewController.swift +++ b/NextcloudTalk/NCMediaViewerViewController.swift @@ -16,14 +16,20 @@ import UIKit private lazy var shareButton = { let shareButton = UIBarButtonItem(title: nil, style: .plain, target: nil, action: nil) - shareButton.isEnabled = false shareButton.primaryAction = UIAction(title: "", image: .init(systemName: "square.and.arrow.up"), handler: { [unowned self, unowned shareButton] _ in - guard let mediaPageViewController = self.getCurrentPageViewController(), - let image = mediaPageViewController.currentImage - else { return } + guard let mediaPageViewController = self.getCurrentPageViewController() else { return } + + var itemsToShare: [Any] = [] - let activityViewController = UIActivityViewController(activityItems: [image], applicationActivities: nil) + if let image = mediaPageViewController.currentImage { + itemsToShare.append(image) + } else if let videoURL = mediaPageViewController.currentVideoURL { + itemsToShare.append(videoURL) + } else { + return + } + let activityViewController = UIActivityViewController(activityItems: itemsToShare, applicationActivities: nil) activityViewController.popoverPresentationController?.barButtonItem = shareButton self.present(activityViewController, animated: true) @@ -106,7 +112,7 @@ import UIKit let messageObject = self.getAllFileMessages().objects(with: prevQuery).lastObject() if let message = messageObject as? NCChatMessage { - if NCUtils.isImage(fileType: message.file().mimetype) { + if NCUtils.isImage(fileType: message.file().mimetype) || NCUtils.isVideo(fileType: message.file().mimetype) { return message } @@ -122,7 +128,7 @@ import UIKit let messageObject = self.getAllFileMessages().objects(with: prevQuery).firstObject() if let message = messageObject as? NCChatMessage { - if NCUtils.isImage(fileType: message.file().mimetype) { + if NCUtils.isImage(fileType: message.file().mimetype) || NCUtils.isVideo(fileType: message.file().mimetype) { return message } @@ -158,7 +164,7 @@ import UIKit guard let mediaPageViewController = self.getCurrentPageViewController() else { return } self.navigationItem.title = mediaPageViewController.navigationItem.title - self.shareButton.isEnabled = (mediaPageViewController.currentImage != nil) + self.shareButton.isEnabled = (mediaPageViewController.currentImage != nil) || (mediaPageViewController.currentVideoURL != nil) } // MARK: - NCMediaViewerPageViewController delegate @@ -178,7 +184,7 @@ import UIKit } } - func mediaViewerPageImageDidLoad(_ controller: NCMediaViewerPageViewController) { + func mediaViewerPageMediaDidLoad(_ controller: NCMediaViewerPageViewController) { if let mediaPageViewController = self.getCurrentPageViewController(), mediaPageViewController.isEqual(controller) { self.shareButton.isEnabled = true }