From ec3f26ccd89139e9eccb5472067219bcba1e8de4 Mon Sep 17 00:00:00 2001 From: Roy Marmelstein Date: Tue, 16 Feb 2016 23:34:24 +0100 Subject: [PATCH] Adding plist and json support --- FileBrowser.podspec | 2 +- FileBrowser.xcodeproj/project.pbxproj | 20 ++- FileBrowser/FBFile.swift | 6 +- FileBrowser/FileListPreview.swift | 4 + FileBrowser/PreviewManager.swift | 15 ++- .../Resources/WebviewPreviewViewContoller.xib | 20 +++ FileBrowser/WebviewPreviewViewContoller.swift | 115 ++++++++++++++++++ examples/Sample/Sample/AppDelegate.swift | 2 +- 8 files changed, 173 insertions(+), 11 deletions(-) create mode 100644 FileBrowser/Resources/WebviewPreviewViewContoller.xib create mode 100644 FileBrowser/WebviewPreviewViewContoller.swift diff --git a/FileBrowser.podspec b/FileBrowser.podspec index 19ab239..a902c58 100644 --- a/FileBrowser.podspec +++ b/FileBrowser.podspec @@ -34,7 +34,7 @@ Pod::Spec.new do |s| s.resources = "FileBrowser/Resources/*.*" # s.public_header_files = 'Pod/Classes/**/*.h' - s.frameworks = 'QuickLook' + s.frameworks = 'QuickLook', 'WebKit' # s.dependency 'AFNetworking', '~> 2.3' end diff --git a/FileBrowser.xcodeproj/project.pbxproj b/FileBrowser.xcodeproj/project.pbxproj index a6a52ec..035619b 100644 --- a/FileBrowser.xcodeproj/project.pbxproj +++ b/FileBrowser.xcodeproj/project.pbxproj @@ -9,12 +9,15 @@ /* Begin PBXBuildFile section */ 3437405B1C6E7DA50090FD6A /* FileListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3437405A1C6E7DA50090FD6A /* FileListViewController.swift */; }; 3439AB681C6F203A0058AF04 /* FileParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3439AB671C6F203A0058AF04 /* FileParser.swift */; }; - 3439AB6A1C6FC6D90058AF04 /* QuickLook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3439AB691C6FC6D90058AF04 /* QuickLook.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; + 3439AB6A1C6FC6D90058AF04 /* QuickLook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3439AB691C6FC6D90058AF04 /* QuickLook.framework */; settings = {ATTRIBUTES = (Required, ); }; }; 3439AB6C1C6FD6650058AF04 /* FileListPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3439AB6B1C6FD6650058AF04 /* FileListPreview.swift */; }; 3439AB701C6FF68C0058AF04 /* FileBrowser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3439AB6F1C6FF68C0058AF04 /* FileBrowser.swift */; }; 343C44631C73CC8100D874FB /* PreviewTransitionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 343C44611C73CC8100D874FB /* PreviewTransitionViewController.swift */; }; 343C44661C73CD3200D874FB /* PreviewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 343C44651C73CD3200D874FB /* PreviewManager.swift */; }; 343C44681C73CD8700D874FB /* PreviewTransitionViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 343C44671C73CD8700D874FB /* PreviewTransitionViewController.xib */; }; + 343C447A1C73CFC400D874FB /* WebviewPreviewViewContoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = 343C44781C73CFC400D874FB /* WebviewPreviewViewContoller.swift */; }; + 343C447D1C73CFD900D874FB /* WebviewPreviewViewContoller.xib in Resources */ = {isa = PBXBuildFile; fileRef = 343C447C1C73CFD900D874FB /* WebviewPreviewViewContoller.xib */; }; + 343C447F1C73D06200D874FB /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 343C447E1C73D06200D874FB /* WebKit.framework */; }; 344169581C67812400B93D28 /* FileBrowser.h in Headers */ = {isa = PBXBuildFile; fileRef = 344169571C67812400B93D28 /* FileBrowser.h */; settings = {ATTRIBUTES = (Public, ); }; }; 3441695F1C67812400B93D28 /* FileBrowser.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 344169541C67812400B93D28 /* FileBrowser.framework */; }; 344169641C67812400B93D28 /* FileBrowserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 344169631C67812400B93D28 /* FileBrowserTests.swift */; }; @@ -50,7 +53,10 @@ 3439AB6F1C6FF68C0058AF04 /* FileBrowser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileBrowser.swift; sourceTree = ""; }; 343C44611C73CC8100D874FB /* PreviewTransitionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewTransitionViewController.swift; sourceTree = ""; }; 343C44651C73CD3200D874FB /* PreviewManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewManager.swift; sourceTree = ""; }; - 343C44671C73CD8700D874FB /* PreviewTransitionViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = PreviewTransitionViewController.xib; path = Resources/PreviewTransitionViewController.xib; sourceTree = ""; }; + 343C44671C73CD8700D874FB /* PreviewTransitionViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PreviewTransitionViewController.xib; sourceTree = ""; }; + 343C44781C73CFC400D874FB /* WebviewPreviewViewContoller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WebviewPreviewViewContoller.swift; sourceTree = ""; }; + 343C447C1C73CFD900D874FB /* WebviewPreviewViewContoller.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WebviewPreviewViewContoller.xib; sourceTree = ""; }; + 343C447E1C73D06200D874FB /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; 344169541C67812400B93D28 /* FileBrowser.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = FileBrowser.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 344169571C67812400B93D28 /* FileBrowser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FileBrowser.h; sourceTree = ""; }; 344169591C67812400B93D28 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -76,6 +82,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 343C447F1C73D06200D874FB /* WebKit.framework in Frameworks */, 3439AB6A1C6FC6D90058AF04 /* QuickLook.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -116,7 +123,7 @@ children = ( 343C44611C73CC8100D874FB /* PreviewTransitionViewController.swift */, 343C44651C73CD3200D874FB /* PreviewManager.swift */, - 343C44671C73CD8700D874FB /* PreviewTransitionViewController.xib */, + 343C44781C73CFC400D874FB /* WebviewPreviewViewContoller.swift */, ); name = Preview; sourceTree = ""; @@ -145,9 +152,9 @@ 344169571C67812400B93D28 /* FileBrowser.h */, 3439AB6F1C6FF68C0058AF04 /* FileBrowser.swift */, 343C445E1C73CB9600D874FB /* Data */, + 349A121D1C706601005435C0 /* Frameworks */, 343C445F1C73CBA900D874FB /* FileList */, 343C44601C73CC3C00D874FB /* Preview */, - 349A121D1C706601005435C0 /* Frameworks */, 349A122A1C707E86005435C0 /* Resources */, 344169591C67812400B93D28 /* Info.plist */, ); @@ -169,6 +176,7 @@ isa = PBXGroup; children = ( 3439AB691C6FC6D90058AF04 /* QuickLook.framework */, + 343C447E1C73D06200D874FB /* WebKit.framework */, ); name = Frameworks; sourceTree = ""; @@ -182,6 +190,8 @@ 349A122E1C707E86005435C0 /* folder@2x.png */, 349A122F1C707E86005435C0 /* image@2x.png */, 349A12301C707E86005435C0 /* pdf@2x.png */, + 343C44671C73CD8700D874FB /* PreviewTransitionViewController.xib */, + 343C447C1C73CFD900D874FB /* WebviewPreviewViewContoller.xib */, 349A12311C707E86005435C0 /* zip@2x.png */, ); path = Resources; @@ -281,6 +291,7 @@ 343C44681C73CD8700D874FB /* PreviewTransitionViewController.xib in Resources */, 349A12331C707E86005435C0 /* file@2x.png in Resources */, 349A12341C707E86005435C0 /* FileBrowser.xib in Resources */, + 343C447D1C73CFD900D874FB /* WebviewPreviewViewContoller.xib in Resources */, 349A12361C707E86005435C0 /* image@2x.png in Resources */, 349A12371C707E86005435C0 /* pdf@2x.png in Resources */, 349A12351C707E86005435C0 /* folder@2x.png in Resources */, @@ -305,6 +316,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 343C447A1C73CFC400D874FB /* WebviewPreviewViewContoller.swift in Sources */, 3439AB701C6FF68C0058AF04 /* FileBrowser.swift in Sources */, 349A12261C707317005435C0 /* FlieListTableView.swift in Sources */, 343C44661C73CD3200D874FB /* PreviewManager.swift in Sources */, diff --git a/FileBrowser/FBFile.swift b/FileBrowser/FBFile.swift index 39bc3f7..c3ccb9a 100644 --- a/FileBrowser/FBFile.swift +++ b/FileBrowser/FBFile.swift @@ -66,8 +66,12 @@ public enum FBFileType: String { case GIF = "gif" /// JPG file case JPG = "jpg" + /// PLIST file + case JSON = "json" /// PDF file case PDF = "pdf" + /// PLIST file + case PLIST = "plist" /// PNG file case PNG = "png" /// ZIP file @@ -88,7 +92,7 @@ public enum FBFileType: String { case JPG, PNG, GIF: fileName = "image@2x.png" case PDF: fileName = "pdf@2x.png" case ZIP: fileName = "zip@2x.png" - case Default: fileName = "file@2x.png" + default: fileName = "file@2x.png" } let file = UIImage(named: fileName, inBundle: bundle, compatibleWithTraitCollection: nil) return file diff --git a/FileBrowser/FileListPreview.swift b/FileBrowser/FileListPreview.swift index 5032111..768aab9 100644 --- a/FileBrowser/FileListPreview.swift +++ b/FileBrowser/FileListPreview.swift @@ -38,6 +38,10 @@ extension FileListViewController: UIViewControllerPreviewingDelegate { if let previewTransitionViewController = viewControllerToCommit as? PreviewTransitionViewController { self.navigationController?.pushViewController(previewTransitionViewController.quickLookPreviewController, animated: true) } + else { + self.navigationController?.pushViewController(viewControllerToCommit, animated: true) + } + } } diff --git a/FileBrowser/PreviewManager.swift b/FileBrowser/PreviewManager.swift index 189b141..5bb193b 100644 --- a/FileBrowser/PreviewManager.swift +++ b/FileBrowser/PreviewManager.swift @@ -15,10 +15,17 @@ class PreviewManager: NSObject, QLPreviewControllerDataSource { func previewViewControllerForFile(file: FBFile) -> UIViewController { - let previewTransitionViewController = PreviewTransitionViewController(nibName: "PreviewTransitionViewController", bundle: NSBundle(forClass: PreviewTransitionViewController.self)) - previewTransitionViewController.quickLookPreviewController.dataSource = self - self.filePath = file.filePath - return previewTransitionViewController + if file.type == .PLIST || file.type == .JSON{ + let webviewPreviewViewContoller = WebviewPreviewViewContoller(nibName: "WebviewPreviewViewContoller", bundle: NSBundle(forClass: WebviewPreviewViewContoller.self)) + webviewPreviewViewContoller.file = file + return webviewPreviewViewContoller + } + else { + let previewTransitionViewController = PreviewTransitionViewController(nibName: "PreviewTransitionViewController", bundle: NSBundle(forClass: PreviewTransitionViewController.self)) + previewTransitionViewController.quickLookPreviewController.dataSource = self + self.filePath = file.filePath + return previewTransitionViewController + } } func numberOfPreviewItemsInPreviewController(controller: QLPreviewController) -> Int { diff --git a/FileBrowser/Resources/WebviewPreviewViewContoller.xib b/FileBrowser/Resources/WebviewPreviewViewContoller.xib new file mode 100644 index 0000000..24a9969 --- /dev/null +++ b/FileBrowser/Resources/WebviewPreviewViewContoller.xib @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/FileBrowser/WebviewPreviewViewContoller.swift b/FileBrowser/WebviewPreviewViewContoller.swift new file mode 100644 index 0000000..123d419 --- /dev/null +++ b/FileBrowser/WebviewPreviewViewContoller.swift @@ -0,0 +1,115 @@ +// +// WebviewPreviewViewContoller.swift +// FileBrowser +// +// Created by Roy Marmelstein on 16/02/2016. +// Copyright © 2016 Roy Marmelstein. All rights reserved. +// + +import UIKit +import WebKit + +/// Webview for rendering items QuickLook will struggle with. +class WebviewPreviewViewContoller: UIViewController { + + var webView = WKWebView() + + var file: FBFile? { + didSet { + self.title = file?.displayName + self.processForDisplay() + } + } + + //MARK: Lifecycle + + override func viewDidLoad() { + super.viewDidLoad() + self.view.addSubview(webView) + + // Add share button + let shareButton = UIBarButtonItem(barButtonSystemItem: .Action, target: self, action: "shareFile") + self.navigationItem.rightBarButtonItem = shareButton + } + + override func viewWillLayoutSubviews() { + super.viewWillLayoutSubviews() + webView.frame = self.view.bounds + } + + //MARK: Share + + func shareFile() { + guard let file = file else { + return + } + let activityViewController = UIActivityViewController(activityItems: [file.filePath], applicationActivities: nil) + self.presentViewController(activityViewController, animated: true, completion: nil) + + } + + //MARK: Processing + + func processForDisplay() { + guard let file = file, let data = NSData(contentsOfURL: file.filePath) else { + return + } + var rawString: String? + + // Prepare plist for display + if file.type == .PLIST { + do { + if let plistDescription = try NSPropertyListSerialization.propertyListWithData(data, options: [], format: nil).description { + rawString = plistDescription + } + } catch {} + } + + // Prepare json file for display + else if file.type == .JSON { + do { + let jsonObject = try NSJSONSerialization.JSONObjectWithData(data, options: []) + if NSJSONSerialization.isValidJSONObject(jsonObject) { + let prettyJSON = try NSJSONSerialization.dataWithJSONObject(jsonObject, options: .PrettyPrinted) + var jsonString = String(data: prettyJSON, encoding: NSUTF8StringEncoding) + // Unescape forward slashes + jsonString = jsonString?.stringByReplacingOccurrencesOfString("\\/", withString: "/") + rawString = jsonString + } + } catch {} + } + + // Default prepare for display + if rawString == nil { + rawString = String(data: data, encoding: NSUTF8StringEncoding) + } + + // Convert and display string + if let convertedString = convertSpecialCharacters(rawString) { + let htmlString = "
\(convertedString)
" + webView.loadHTMLString(htmlString, baseURL: nil) + } + + } + + + // Make sure we convert HTML special characters + // Code from https://gist.github.com/mikesteele/70ae98d04fdc35cb1d5f + func convertSpecialCharacters(string: String?) -> String? { + guard let string = string else { + return nil + } + var newString = string + let char_dictionary = [ + "&": "&", + "<": "<", + ">": ">", + """: "\"", + "'": "'" + ]; + for (escaped_char, unescaped_char) in char_dictionary { + newString = newString.stringByReplacingOccurrencesOfString(escaped_char, withString: unescaped_char, options: NSStringCompareOptions.RegularExpressionSearch, range: nil) + } + return newString + } +} diff --git a/examples/Sample/Sample/AppDelegate.swift b/examples/Sample/Sample/AppDelegate.swift index fdf5e9b..2ec6d1e 100644 --- a/examples/Sample/Sample/AppDelegate.swift +++ b/examples/Sample/Sample/AppDelegate.swift @@ -19,7 +19,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { NSUserDefaults.standardUserDefaults().setBool(true, forKey: "firstLaunch") NSUserDefaults.standardUserDefaults().synchronize() let fileManager = NSFileManager.defaultManager() - let fileNames = ["Baymax.jpg", "BB8.jpg", "Stitch.jpg"] + let fileNames = ["Baymax.jpg", "BB8.jpg", "Stitch.jpg", "Info.plist"] let documentsUrl = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL let bundleUrl = NSBundle.mainBundle().resourceURL // Copy images to documents folder