Skip to content

Commit

Permalink
added video support in media view
Browse files Browse the repository at this point in the history
Closes #1702

Signed-off-by: Daniel Standfest <daniel@standfest.io>
  • Loading branch information
Daniel Standfest authored and DanielStandfest committed Nov 27, 2024
1 parent 57650d0 commit 9104ac8
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 24 deletions.
14 changes: 14 additions & 0 deletions NextcloudTalk/BaseChatViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3378,6 +3378,20 @@ import SwiftUI
return
}

let filePath = fileParameter.path ?? ""
let fileExtension = URL(fileURLWithPath: filePath).pathExtension.lowercased()

if NCUtils.isVideo(fileType: fileParameter.mimetype) {
// Skip unsupported formats here ("webm" and "mkv") and use VLC later
if !fileExtension.isEmpty, !VLCKitVideoViewController.supportedFileExtensions.contains(fileExtension) {
let mediaViewController = NCMediaViewerViewController(initialMessage: message)
let navController = CustomPresentableNavigationController(rootViewController: mediaViewController)

self.present(navController, interactiveDismissalType: .standard)
return
}
}

if fileParameter.fileStatus != nil && fileParameter.fileStatus?.isDownloading ?? false {
print("File already downloading -> skipping new download")
return
Expand Down
92 changes: 79 additions & 13 deletions NextcloudTalk/NCMediaViewerPageViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -121,6 +127,7 @@ import SwiftyGif

func showErrorView() {
self.imageView.image = nil
self.removePlayerViewControllerIfNeeded()
self.view.addSubview(self.errorView)

NSLayoutConstraint.activate([
Expand All @@ -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) {
Expand Down Expand Up @@ -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
}
}
}
42 changes: 31 additions & 11 deletions NextcloudTalk/NCMediaViewerViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -110,11 +116,18 @@ import UIKit
let messageObject = queriedObjects.lastObject()

if let message = messageObject as? NCChatMessage {
if NCUtils.isImage(fileType: message.file().mimetype) {
guard let filePath = message.file().path else {
return self.getPreviousFileMessage(from: message)
}

let fileType = message.file().mimetype
let isSupportedMedia = NCUtils.isImage(fileType: fileType) || NCUtils.isVideo(fileType: fileType)
let isUnsupportedExtension = VLCKitVideoViewController.supportedFileExtensions.contains(URL(fileURLWithPath: filePath).pathExtension.lowercased())

if isSupportedMedia && !isUnsupportedExtension {
return message
}

// The current message contains a file, but not an image -> try to find another message
return self.getPreviousFileMessage(from: message)
}

Expand All @@ -127,11 +140,18 @@ import UIKit
guard let messageObject = self.getAllFileMessages()?.objects(with: prevQuery).firstObject() else { return nil }

if let message = messageObject as? NCChatMessage {
if NCUtils.isImage(fileType: message.file().mimetype) {
guard let filePath = message.file().path else {
return self.getNextFileMessage(from: message)
}

let fileType = message.file().mimetype
let isSupportedMedia = NCUtils.isImage(fileType: fileType) || NCUtils.isVideo(fileType: fileType)
let isUnsupportedExtension = VLCKitVideoViewController.supportedFileExtensions.contains(URL(fileURLWithPath: filePath).pathExtension.lowercased())

if isSupportedMedia && !isUnsupportedExtension {
return message
}

// The current message contains a file, but not an image -> try to find another message
return self.getNextFileMessage(from: message)
}

Expand Down Expand Up @@ -163,7 +183,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
Expand All @@ -183,7 +203,7 @@ import UIKit
}
}

func mediaViewerPageImageDidLoad(_ controller: NCMediaViewerPageViewController) {
func mediaViewerPageMediaDidLoad(_ controller: NCMediaViewerPageViewController) {
if let mediaPageViewController = self.getCurrentPageViewController(), mediaPageViewController.isEqual(controller) {
self.shareButton.isEnabled = true
}
Expand Down

0 comments on commit 9104ac8

Please sign in to comment.