Skip to content

Commit

Permalink
Add audio and video previewing (#90)
Browse files Browse the repository at this point in the history
  • Loading branch information
sujaygarlanka authored Feb 13, 2020
1 parent d58b082 commit c5cf069
Show file tree
Hide file tree
Showing 10 changed files with 365 additions and 102 deletions.
12 changes: 12 additions & 0 deletions BoxPreviewSDK.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
3549BB501DA38A2000C63030 /* BoxPreviewSDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 3549BB181DA3890B00C63030 /* BoxPreviewSDK.h */; settings = {ATTRIBUTES = (Public, ); }; };
359649031FB18CC000FC7ADC /* BoxPreviewSDK.swift in Sources */ = {isa = PBXBuildFile; fileRef = 359649021FB18CBF00FC7ADC /* BoxPreviewSDK.swift */; };
919E896722DFC45700E94CCA /* BoxPreviewError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 919E896622DFC45700E94CCA /* BoxPreviewError.swift */; };
F9D5628B23AC63FE003553D8 /* AVViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F9D5628A23AC63FE003553D8 /* AVViewController.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -133,6 +134,7 @@
35B7422D1F82A5DF00829B21 /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = Carthage/Build/iOS/Nimble.framework; sourceTree = "<group>"; };
35B7422E1F82A5E000829B21 /* Quick.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quick.framework; path = Carthage/Build/iOS/Quick.framework; sourceTree = "<group>"; };
919E896622DFC45700E94CCA /* BoxPreviewError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BoxPreviewError.swift; sourceTree = "<group>"; };
F9D5628A23AC63FE003553D8 /* AVViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AVViewController.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -265,6 +267,7 @@
0CEFC90122C219640013B84B /* Viewers */ = {
isa = PBXGroup;
children = (
F9D5628923AC63E3003553D8 /* AV */,
0C7B97A622CB73560086F6A1 /* QuickLook */,
0CEFC90322C219760013B84B /* Image */,
0CEFC90222C219720013B84B /* PDF */,
Expand Down Expand Up @@ -396,6 +399,14 @@
path = Errors;
sourceTree = "<group>";
};
F9D5628923AC63E3003553D8 /* AV */ = {
isa = PBXGroup;
children = (
F9D5628A23AC63FE003553D8 /* AVViewController.swift */,
);
path = AV;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXHeadersBuildPhase section */
Expand Down Expand Up @@ -614,6 +625,7 @@
0C02F8E422E06A7300B6419F /* CustomProgressView.swift in Sources */,
0C871F76230ACCE000F51102 /* SearchNavigationView.swift in Sources */,
0C61953922CA3874004B7302 /* ThumbnailGridViewController.swift in Sources */,
F9D5628B23AC63FE003553D8 /* AVViewController.swift in Sources */,
17B32FE322FC64AC0043CFBE /* ThumbnailHorizontalGridViewController.swift in Sources */,
0CAF0A7223055D7A00F685C2 /* SearchHistoryHeaderView.swift in Sources */,
0C5FD99022DF177C002F47A5 /* UIDevice+Box.swift in Sources */,
Expand Down
6 changes: 3 additions & 3 deletions BoxPreviewSampleApp/ViewControllers/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class ViewController: UITableViewController {
override func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = folderItems[indexPath.row]
if case let .file(file) = item {
showPreviewViewController(fileId: file.id)
showPreviewViewController(file: file)
}
}
}
Expand Down Expand Up @@ -124,8 +124,8 @@ private extension ViewController {
}
}

func showPreviewViewController(fileId: String) {
let previewController: PreviewViewController = previewSDK.openFile(fileId: fileId, delegate: self)
func showPreviewViewController(file: File) {
let previewController: PreviewViewController = previewSDK.openFile(file: file, delegate: self)
navigationController?.pushViewController(previewController, animated: true)
}
}
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
Changelog
=========

# Next Release

__Breaking Changes:__

__New Features and Enhancements:__

- Add audio and video previewing

## v3.1.0 [2020-01-10]

__Breaking Changes:__
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ class ViewController: UITableViewController {
override func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = folderItems[indexPath.row]
if case let .file(file) = item {
showPreviewViewController(fileId: file.id)
showPreviewViewController(file: file)
}
}
}
Expand Down Expand Up @@ -207,8 +207,8 @@ private extension ViewController {
}
}

func showPreviewViewController(fileId: String) {
let previewController: PreviewViewController? = previewSDK?.openFile(fileId: fileId, delegate: self)
func showPreviewViewController(file: File) {
let previewController: PreviewViewController? = previewSDK?.openFile(file: file, delegate: self)

guard let unwrappedPreviewController = previewController else {
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ class ViewController: UITableViewController, ASWebAuthenticationPresentationCont
override func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = folderItems[indexPath.row]
if case let .file(file) = item {
showPreviewViewController(fileId: file.id)
showPreviewViewController(file: file)
}
}
}
Expand Down Expand Up @@ -209,8 +209,8 @@ private extension ViewController {
}
}

func showPreviewViewController(fileId: String) {
let previewController: PreviewViewController? = previewSDK?.openFile(fileId: fileId, delegate: self)
func showPreviewViewController(file: File) {
let previewController: PreviewViewController? = previewSDK?.openFile(file: file, delegate: self)

guard let unwrappedPreviewController = previewController else {
return
Expand Down
15 changes: 15 additions & 0 deletions Sources/Core/BoxPreviewSDK.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,19 @@ public extension BoxPreviewSDK {
allowedAction: [FileInteractions] = FileInteractions.allCases) -> PreviewViewController {
return PreviewViewController(client: client, fileId: fileId, delegate: delegate, allowedActions: allowedAction)
}

/// Creates UIViewController for previewing file detail. This is the preferred openFile method as it makes less API calls than calling openFile with just the fileID.
///
/// - Parameters:
/// - file: File Info object of the file to preview.
/// - delegate: Delegate for catching the errors for further handling.
/// - allowedAction: Actions on image user can perform such as saving to library or files. By default all actions are allowed.
/// - customErrorView: Error view with custom design. To implement your own error view, implement ErrorView protocol and pass new error view here.
/// Error view is then displayed full screen.
/// - Returns: Returns UIViewController displaying detail of the file.
func openFile(file: File,
delegate: PreviewViewControllerDelegate? = nil,
allowedAction: [FileInteractions] = FileInteractions.allCases) -> PreviewViewController {
return PreviewViewController(client: client, file: file, delegate: delegate, allowedActions: allowedAction)
}
}
72 changes: 39 additions & 33 deletions Sources/Core/UI/PreviewHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,37 +15,23 @@ internal class PreviewHelper {
// MARK: - Properties

var client: BoxClient
var fileId: String
var file: File?
var fileName: String?
var filePath: URL?
private var supportedFileFormat = ["pdf", "jpg", "jpeg", "png", "tiff", "tif", "gif", "bmp", "BMPf", "ico", "cur", "xbm"]
var AVFileFormat = ["mp4", "mov", "wmv", "flv", "avi", "mp3"]
var otherFileFormat = ["pdf", "jpg", "jpeg", "png", "tiff", "tif", "gif", "bmp", "BMPf", "ico", "cur", "xbm"]
var supportedFileFormat: [String] {
return AVFileFormat + otherFileFormat
}

// MARK: - Init

public init(client: BoxClient, fileId: String) {
public init(client: BoxClient) {
self.client = client
self.fileId = fileId
}

// MARK: - Helpers

func downloadBoxFile(progress: @escaping (Progress) -> Void, completion: @escaping (Result<Void, BoxSDKError>) -> Void) {
client.files.get(fileId: fileId) { [weak self] (result: Result<File, BoxSDKError>) in
guard let self = self else {
return
}

switch result {
case let .failure(error):
completion(.failure(error))
return

case let .success(file):
self.downloadFile(file: file, progress: progress, completion: completion)
}
}
}


func getChildViewController(withActions actions: [FileInteractions]) -> Result<PreviewItemChildViewController, BoxPreviewError> {
var childViewController: PreviewItemChildViewController

Expand All @@ -58,11 +44,11 @@ internal class PreviewHelper {
do {
let data = try Data(contentsOf: unwrappedFileURL)
if let document = PDFDocument(data: data) {
childViewController = PDFViewController(document: document, title: unwrappedFileURL.lastPathComponent, actions: actions)
childViewController = PDFViewController(document: document, title: fileName, actions: actions)
return .success(childViewController)
}
else {
return .failure(BoxPreviewError(message: .unableToReadFile(fileId)))
return .failure(BoxPreviewError(message: .unableToReadFile(file?.id ?? "")))
}
}
catch {
Expand All @@ -72,32 +58,51 @@ internal class PreviewHelper {
do {
let data = try Data(contentsOf: unwrappedFileURL)
if let image = UIImage(data: data) {
childViewController = ImageViewController(image: image, title: unwrappedFileURL.lastPathComponent, actions: actions)
childViewController = ImageViewController(image: image, title: fileName, actions: actions)
return .success(childViewController)
}
else {
return .failure(BoxPreviewError(message: .unableToReadFile(fileId)))
return .failure(BoxPreviewError(message: .unableToReadFile(file?.id ?? "")))
}
}
catch {
return .failure(BoxPreviewError(error: error))
}
case "mp4", "mov", "wmv", "flv", "avi", "mp3":
childViewController = AVViewController(url: unwrappedFileURL, file: file, actions: actions)
return .success(childViewController)
case "m3u8":
childViewController = AVViewController(url: unwrappedFileURL, file: file, client: client, actions: actions)
return .success(childViewController)
default:
return .failure(BoxPreviewError(message: .unknownFileType(unwrappedFileURL.pathExtension)))
}
}


// MARK: - Private helpers

private func downloadFile(file: File, progress: @escaping (Progress) -> Void,
completion: @escaping (Result<Void, BoxSDKError>) -> Void) {
func downloadFile(file: File,
representations: [FileRepresentation]? = nil,
progress: @escaping (Progress) -> Void,
completion: @escaping (Result<Void, BoxSDKError>) -> Void) {
guard let fileName = file.name,
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
return
}
self.fileName = fileName
self.file = file

var fileURL = documentsURL.appendingPathComponent(fileName)
if supportedFileFormat.contains(fileURL.pathExtension) {
if let streamRepresentation = representations?.first(where: { $0.representation == "hls" }) {
guard let streamURL = streamRepresentation.content?.urlTemplate else {
return
}
// Gets content URL for a stream from the API, then replaces the last path component `{asset+path}` with `master.m3u8`.
// This newly formed URL is the HLS stream
fileURL = URL(fileURLWithPath: streamURL)
fileURL.deleteLastPathComponent()
fileURL.appendPathComponent("master.m3u8")
completion(self.processFileDownload(to: fileURL, result: .success(())))
}
else if supportedFileFormat.contains(fileURL.pathExtension) {
self.client.files.download(
fileId: file.id,
destinationURL: fileURL,
Expand All @@ -106,7 +111,6 @@ internal class PreviewHelper {
guard let self = self else {
return
}

completion(self.processFileDownload(to: fileURL, result: result))
}
)
Expand All @@ -126,6 +130,8 @@ internal class PreviewHelper {
}
}

// MARK: - Private helpers

private func processFileDownload(to fileURL: URL, result: Result<Void, BoxSDKError>) -> Result<Void, BoxSDKError> {
switch result {
case .success:
Expand Down
9 changes: 9 additions & 0 deletions Sources/Core/UI/PreviewItemChildViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,4 +122,13 @@ extension PreviewItemChildViewController {
let activityController: UIActivityViewController = UIActivityViewController(activityItems: [path], applicationActivities: nil)
present(activityController, animated: true, completion: nil)
}

/// Displays available share and other options for a file.
///
/// - Parameters:
/// - filePath: URL of the file path to the downloaded file
func displayAllShareOptions(filePath: URL) {
let activityController: UIActivityViewController = UIActivityViewController(activityItems: [filePath], applicationActivities: nil)
present(activityController, animated: true, completion: nil)
}
}
Loading

0 comments on commit c5cf069

Please sign in to comment.