ref: URL utils class
This commit is contained in:
@@ -37,6 +37,8 @@
|
|||||||
547F52F72EB2CAC7002B6D5F /* Preview+Footer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 547F52F62EB2CAC7002B6D5F /* Preview+Footer.swift */; };
|
547F52F72EB2CAC7002B6D5F /* Preview+Footer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 547F52F62EB2CAC7002B6D5F /* Preview+Footer.swift */; };
|
||||||
547F52F92EB2CBAB002B6D5F /* Date+Format.swift in Sources */ = {isa = PBXBuildFile; fileRef = 547F52F82EB2CBAB002B6D5F /* Date+Format.swift */; };
|
547F52F92EB2CBAB002B6D5F /* Date+Format.swift in Sources */ = {isa = PBXBuildFile; fileRef = 547F52F82EB2CBAB002B6D5F /* Date+Format.swift */; };
|
||||||
549E3B9F2EBA9D2500ADFF56 /* QLAppBundle Preview Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 54442C202E378BAF008A870E /* QLAppBundle Preview Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
549E3B9F2EBA9D2500ADFF56 /* QLAppBundle Preview Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 54442C202E378BAF008A870E /* QLAppBundle Preview Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
|
549E3BA12EBAE7D300ADFF56 /* URL+File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 549E3BA02EBAE7D300ADFF56 /* URL+File.swift */; };
|
||||||
|
549E3BA22EBAECD400ADFF56 /* URL+File.swift in Sources */ = {isa = PBXBuildFile; fileRef = 549E3BA02EBAE7D300ADFF56 /* URL+File.swift */; };
|
||||||
54AE5BFF2EB3DB1000B4CFC7 /* ThumbnailProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54AE5BFD2EB3DB1000B4CFC7 /* ThumbnailProvider.swift */; };
|
54AE5BFF2EB3DB1000B4CFC7 /* ThumbnailProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54AE5BFD2EB3DB1000B4CFC7 /* ThumbnailProvider.swift */; };
|
||||||
54B6FFEE2EB6A847007397C0 /* AssetCarReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54B6FFEC2EB6A847007397C0 /* AssetCarReader.swift */; };
|
54B6FFEE2EB6A847007397C0 /* AssetCarReader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54B6FFEC2EB6A847007397C0 /* AssetCarReader.swift */; };
|
||||||
54B6FFEF2EB6A8E0007397C0 /* CoreUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54D3A6F52EA4610B001EF4F6 /* CoreUI.framework */; };
|
54B6FFEF2EB6A8E0007397C0 /* CoreUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54D3A6F52EA4610B001EF4F6 /* CoreUI.framework */; };
|
||||||
@@ -152,6 +154,7 @@
|
|||||||
547F52FB2EB37F10002B6D5F /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
547F52FB2EB37F10002B6D5F /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||||
547F52FC2EB37F3A002B6D5F /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
|
547F52FC2EB37F3A002B6D5F /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
|
||||||
549E3B9E2EBA8FDA00ADFF56 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = "<group>"; };
|
549E3B9E2EBA8FDA00ADFF56 /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = "<group>"; };
|
||||||
|
549E3BA02EBAE7D300ADFF56 /* URL+File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+File.swift"; sourceTree = "<group>"; };
|
||||||
54AE5BFB2EB3DB1000B4CFC7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
54AE5BFB2EB3DB1000B4CFC7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
54AE5BFC2EB3DB1000B4CFC7 /* QLThumbnail.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = QLThumbnail.entitlements; sourceTree = "<group>"; };
|
54AE5BFC2EB3DB1000B4CFC7 /* QLThumbnail.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = QLThumbnail.entitlements; sourceTree = "<group>"; };
|
||||||
54AE5BFD2EB3DB1000B4CFC7 /* ThumbnailProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbnailProvider.swift; sourceTree = "<group>"; };
|
54AE5BFD2EB3DB1000B4CFC7 /* ThumbnailProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbnailProvider.swift; sourceTree = "<group>"; };
|
||||||
@@ -222,6 +225,7 @@
|
|||||||
547F52E92EB2C672002B6D5F /* Preview+FileInfo.swift */,
|
547F52E92EB2C672002B6D5F /* Preview+FileInfo.swift */,
|
||||||
547F52F62EB2CAC7002B6D5F /* Preview+Footer.swift */,
|
547F52F62EB2CAC7002B6D5F /* Preview+Footer.swift */,
|
||||||
5405CF642EA1376B00613856 /* Zip.swift */,
|
5405CF642EA1376B00613856 /* Zip.swift */,
|
||||||
|
549E3BA02EBAE7D300ADFF56 /* URL+File.swift */,
|
||||||
54D3A6EF2EA3F49F001EF4F6 /* NSBezierPath+RoundedRect.swift */,
|
54D3A6EF2EA3F49F001EF4F6 /* NSBezierPath+RoundedRect.swift */,
|
||||||
547F52F82EB2CBAB002B6D5F /* Date+Format.swift */,
|
547F52F82EB2CBAB002B6D5F /* Date+Format.swift */,
|
||||||
);
|
);
|
||||||
@@ -540,6 +544,7 @@
|
|||||||
547F52E82EB2C41C002B6D5F /* PreviewGenerator.swift in Sources */,
|
547F52E82EB2C41C002B6D5F /* PreviewGenerator.swift in Sources */,
|
||||||
547F52EB2EB2C672002B6D5F /* Preview+FileInfo.swift in Sources */,
|
547F52EB2EB2C672002B6D5F /* Preview+FileInfo.swift in Sources */,
|
||||||
547F52ED2EB2C822002B6D5F /* Preview+AppInfo.swift in Sources */,
|
547F52ED2EB2C822002B6D5F /* Preview+AppInfo.swift in Sources */,
|
||||||
|
549E3BA12EBAE7D300ADFF56 /* URL+File.swift in Sources */,
|
||||||
547F52F42EB2CA05002B6D5F /* Preview+Entitlements.swift in Sources */,
|
547F52F42EB2CA05002B6D5F /* Preview+Entitlements.swift in Sources */,
|
||||||
5405CF5E2EA1199B00613856 /* MetaInfo.swift in Sources */,
|
5405CF5E2EA1199B00613856 /* MetaInfo.swift in Sources */,
|
||||||
547F52F92EB2CBAB002B6D5F /* Date+Format.swift in Sources */,
|
547F52F92EB2CBAB002B6D5F /* Date+Format.swift in Sources */,
|
||||||
@@ -556,6 +561,7 @@
|
|||||||
547899722EB38F3D00F96B80 /* MetaInfo.swift in Sources */,
|
547899722EB38F3D00F96B80 /* MetaInfo.swift in Sources */,
|
||||||
547899732EB38F3D00F96B80 /* NSBezierPath+RoundedRect.swift in Sources */,
|
547899732EB38F3D00F96B80 /* NSBezierPath+RoundedRect.swift in Sources */,
|
||||||
54AE5BFF2EB3DB1000B4CFC7 /* ThumbnailProvider.swift in Sources */,
|
54AE5BFF2EB3DB1000B4CFC7 /* ThumbnailProvider.swift in Sources */,
|
||||||
|
549E3BA22EBAECD400ADFF56 /* URL+File.swift in Sources */,
|
||||||
547899752EB38F3D00F96B80 /* AppIcon.swift in Sources */,
|
547899752EB38F3D00F96B80 /* AppIcon.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|||||||
@@ -13,12 +13,9 @@ class PreviewViewController: NSViewController, QLPreviewingController {
|
|||||||
|
|
||||||
/// Load resource file either from user documents dir (if exists) or app bundle (default).
|
/// Load resource file either from user documents dir (if exists) or app bundle (default).
|
||||||
func bundleFile(filename: String, ext: String) throws -> String {
|
func bundleFile(filename: String, ext: String) throws -> String {
|
||||||
if let appSupport = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
|
if let userFile = URL.UserModDir?.appendingPathComponent(filename + "." + ext, isDirectory: false), userFile.exists() {
|
||||||
let override = appSupport.appendingPathComponent(filename + "." + ext)
|
return try String(contentsOf: userFile, encoding: .utf8)
|
||||||
if FileManager.default.fileExists(atPath: override.path) {
|
// else: do NOT copy! Breaks on future updates
|
||||||
return try String(contentsOfFile: override.path, encoding: .utf8)
|
|
||||||
}
|
|
||||||
// else: do NOT copy! Breaks on future updates
|
|
||||||
}
|
}
|
||||||
// else, load bundle file
|
// else, load bundle file
|
||||||
let path = Bundle.main.url(forResource: filename, withExtension: ext)
|
let path = Bundle.main.url(forResource: filename, withExtension: ext)
|
||||||
|
|||||||
@@ -1,27 +1,12 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension PreviewGenerator {
|
extension PreviewGenerator {
|
||||||
/// Calculate file / folder size.
|
|
||||||
private func getFileSize(_ path: String) -> Int64 {
|
|
||||||
var isDir: ObjCBool = false
|
|
||||||
FileManager.default.fileExists(atPath: path, isDirectory: &isDir)
|
|
||||||
if !isDir.boolValue {
|
|
||||||
return try! FileManager.default.attributesOfItem(atPath: path)[.size] as! Int64
|
|
||||||
}
|
|
||||||
var fileSize: Int64 = 0
|
|
||||||
for child in try! FileManager.default.subpathsOfDirectory(atPath: path) {
|
|
||||||
fileSize += try! FileManager.default.attributesOfItem(atPath: path + "/" + child)[.size] as! Int64
|
|
||||||
}
|
|
||||||
return fileSize
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Process meta information about the file itself. Like file size and last modification.
|
/// Process meta information about the file itself. Like file size and last modification.
|
||||||
mutating func procFileInfo(_ url: URL) {
|
mutating func procFileInfo(_ url: URL) {
|
||||||
let attrs = try? FileManager.default.attributesOfItem(atPath: url.path)
|
|
||||||
self.apply([
|
self.apply([
|
||||||
"FileName": escapeXML(url.lastPathComponent),
|
"FileName": escapeXML(url.lastPathComponent),
|
||||||
"FileSize": ByteCountFormatter.string(fromByteCount: getFileSize(url.path), countStyle: .file),
|
"FileSize": url.fileSizeHuman(),
|
||||||
"FileModified": (attrs?[.modificationDate] as? Date)?.mediumFormat() ?? "",
|
"FileModified": url.modificationDate()?.mediumFormat() ?? "",
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -36,3 +21,32 @@ private func escapeXML(_ stringToEscape: String) -> String {
|
|||||||
.replacingOccurrences(of: "<", with: "<")
|
.replacingOccurrences(of: "<", with: "<")
|
||||||
.replacingOccurrences(of: ">", with: ">")
|
.replacingOccurrences(of: ">", with: ">")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension URL {
|
||||||
|
/// Last modification date of file (or folder)
|
||||||
|
@inlinable func modificationDate() -> Date? {
|
||||||
|
(try? FileManager.default.attributesOfItem(atPath: self.path))?[.modificationDate] as? Date
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calls `fileSize()`. Will convert `Int` to human readable `String`.
|
||||||
|
func fileSizeHuman() -> String {
|
||||||
|
ByteCountFormatter.string(fromByteCount: self.fileSize(), countStyle: .file)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - private methods
|
||||||
|
|
||||||
|
/// Calculate file or folder size.
|
||||||
|
private func fileSize() -> Int64 {
|
||||||
|
var isDir: ObjCBool = false
|
||||||
|
FileManager.default.fileExists(atPath: self.path, isDirectory: &isDir)
|
||||||
|
if !isDir.boolValue {
|
||||||
|
return try! FileManager.default.attributesOfItem(atPath: self.path)[.size] as! Int64
|
||||||
|
}
|
||||||
|
var fileSize: Int64 = 0
|
||||||
|
for child in try! FileManager.default.subpathsOfDirectory(atPath: self.path) {
|
||||||
|
fileSize += try! FileManager.default.attributesOfItem(atPath: self.path + "/" + child)[.size] as! Int64
|
||||||
|
}
|
||||||
|
return fileSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
12
src/URL+File.swift
Normal file
12
src/URL+File.swift
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension URL {
|
||||||
|
/// Folder where user can mofifications to html template
|
||||||
|
static let UserModDir: URL? =
|
||||||
|
FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
|
||||||
|
|
||||||
|
/// Returns `true` if file or folder exists.
|
||||||
|
@inlinable func exists() -> Bool {
|
||||||
|
FileManager.default.fileExists(atPath: self.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user