feat: thumbnail icon
This commit is contained in:
@@ -21,6 +21,18 @@
|
||||
545459C52EA469EA002892E5 /* template.html in Resources */ = {isa = PBXBuildFile; fileRef = 54D3A6F32EA4603B001EF4F6 /* template.html */; };
|
||||
545459C72EA4773A002892E5 /* AppIcon+Car.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545459C62EA4773A002892E5 /* AppIcon+Car.swift */; };
|
||||
545459C92EA47C37002892E5 /* Plist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545459C82EA47C37002892E5 /* Plist.swift */; };
|
||||
54581FD12EB29A0B0043A0B3 /* QuickLookThumbnailing.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54581FD02EB29A0B0043A0B3 /* QuickLookThumbnailing.framework */; };
|
||||
54581FD22EB29A0B0043A0B3 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54442C222E378BAF008A870E /* Quartz.framework */; };
|
||||
54581FDA2EB29A0B0043A0B3 /* QLThumbnail.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 54581FCF2EB29A0B0043A0B3 /* QLThumbnail.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
54581FE42EB29A2B0043A0B3 /* CoreUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 54D3A6F52EA4610B001EF4F6 /* CoreUI.framework */; };
|
||||
54581FEF2EB29A570043A0B3 /* Shared.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5405CF5D2EA1199B00613856 /* Shared.swift */; };
|
||||
54581FF02EB29A5E0043A0B3 /* AppIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D3A6ED2EA39CC6001EF4F6 /* AppIcon.swift */; };
|
||||
54581FF12EB29A620043A0B3 /* AppIcon+Car.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545459C62EA4773A002892E5 /* AppIcon+Car.swift */; };
|
||||
54581FF72EB29A820043A0B3 /* Zip.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5405CF642EA1376B00613856 /* Zip.swift */; };
|
||||
54581FFD2EB29AB70043A0B3 /* Plist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 545459C82EA47C37002892E5 /* Plist.swift */; };
|
||||
545820032EB29B0A0043A0B3 /* RoundedIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D3A6EF2EA3F49F001EF4F6 /* RoundedIcon.swift */; };
|
||||
545820222EB29B3D0043A0B3 /* ThumbnailProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5458201F2EB29B3D0043A0B3 /* ThumbnailProvider.swift */; };
|
||||
545820232EB29B4C0043A0B3 /* defaultIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 54D3A6F22EA4603B001EF4F6 /* defaultIcon.png */; };
|
||||
5469E11D2EA5930C00D46CE7 /* Entitlements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5469E11C2EA5930C00D46CE7 /* Entitlements.swift */; };
|
||||
54D3A6EC2EA31B52001EF4F6 /* AppCategories.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D3A6EB2EA31B52001EF4F6 /* AppCategories.swift */; };
|
||||
54D3A6EE2EA39CC6001EF4F6 /* AppIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D3A6ED2EA39CC6001EF4F6 /* AppIcon.swift */; };
|
||||
@@ -38,6 +50,13 @@
|
||||
remoteGlobalIDString = 54442C1F2E378BAF008A870E;
|
||||
remoteInfo = QLPreview;
|
||||
};
|
||||
54581FD82EB29A0B0043A0B3 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 54442BEC2E378B71008A870E /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 54581FCE2EB29A0B0043A0B3;
|
||||
remoteInfo = QLThumbnail;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@@ -47,6 +66,7 @@
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
54581FDA2EB29A0B0043A0B3 /* QLThumbnail.appex in Embed Foundation Extensions */,
|
||||
54442C302E378BAF008A870E /* QLPreview.appex in Embed Foundation Extensions */,
|
||||
);
|
||||
name = "Embed Foundation Extensions";
|
||||
@@ -71,9 +91,13 @@
|
||||
54442C772E378BE0008A870E /* QLPreview.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = QLPreview.entitlements; sourceTree = "<group>"; };
|
||||
545459C62EA4773A002892E5 /* AppIcon+Car.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppIcon+Car.swift"; sourceTree = "<group>"; };
|
||||
545459C82EA47C37002892E5 /* Plist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Plist.swift; sourceTree = "<group>"; };
|
||||
54581FCF2EB29A0B0043A0B3 /* QLThumbnail.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = QLThumbnail.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
54581FD02EB29A0B0043A0B3 /* QuickLookThumbnailing.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLookThumbnailing.framework; path = System/Library/Frameworks/QuickLookThumbnailing.framework; sourceTree = SDKROOT; };
|
||||
5458201D2EB29B3D0043A0B3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
5458201E2EB29B3D0043A0B3 /* QLThumbnail.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = QLThumbnail.entitlements; sourceTree = "<group>"; };
|
||||
5458201F2EB29B3D0043A0B3 /* ThumbnailProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbnailProvider.swift; sourceTree = "<group>"; };
|
||||
5469E11C2EA5930C00D46CE7 /* Entitlements.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Entitlements.swift; sourceTree = "<group>"; };
|
||||
5485EE362EB1460C009E3905 /* Network.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Network.framework; path = System/Library/Frameworks/Network.framework; sourceTree = SDKROOT; };
|
||||
54D3A6E52EA31B13001EF4F6 /* ThumbnailGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThumbnailGenerator.swift; sourceTree = "<group>"; };
|
||||
54D3A6EB2EA31B52001EF4F6 /* AppCategories.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCategories.swift; sourceTree = "<group>"; };
|
||||
54D3A6ED2EA39CC6001EF4F6 /* AppIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIcon.swift; sourceTree = "<group>"; };
|
||||
54D3A6EF2EA3F49F001EF4F6 /* RoundedIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoundedIcon.swift; sourceTree = "<group>"; };
|
||||
@@ -110,6 +134,16 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
54581FCC2EB29A0B0043A0B3 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
54581FD12EB29A0B0043A0B3 /* QuickLookThumbnailing.framework in Frameworks */,
|
||||
54581FD22EB29A0B0043A0B3 /* Quartz.framework in Frameworks */,
|
||||
54581FE42EB29A2B0043A0B3 /* CoreUI.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
@@ -124,7 +158,6 @@
|
||||
545459C82EA47C37002892E5 /* Plist.swift */,
|
||||
5405CF642EA1376B00613856 /* Zip.swift */,
|
||||
5469E11C2EA5930C00D46CE7 /* Entitlements.swift */,
|
||||
54D3A6E52EA31B13001EF4F6 /* ThumbnailGenerator.swift */,
|
||||
5405CF5B2EA1191A00613856 /* PreviewGenerator.swift */,
|
||||
);
|
||||
path = src;
|
||||
@@ -138,6 +171,7 @@
|
||||
541051562E37AFC10083670B /* src */,
|
||||
54442C6F2E378BDD008A870E /* QLApps */,
|
||||
54442C782E378BE0008A870E /* QLPreview */,
|
||||
545820202EB29B3D0043A0B3 /* QLThumbnail */,
|
||||
54442C212E378BAF008A870E /* Frameworks */,
|
||||
54442BF52E378B71008A870E /* Products */,
|
||||
);
|
||||
@@ -148,6 +182,7 @@
|
||||
children = (
|
||||
54442BF42E378B71008A870E /* QLApps.app */,
|
||||
54442C202E378BAF008A870E /* QLPreview.appex */,
|
||||
54581FCF2EB29A0B0043A0B3 /* QLThumbnail.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@@ -166,6 +201,7 @@
|
||||
54D3A6FC2EA465A9001EF4F6 /* CoreServices.framework */,
|
||||
54D3A6FA2EA46588001EF4F6 /* CoreGraphics.framework */,
|
||||
54442C222E378BAF008A870E /* Quartz.framework */,
|
||||
54581FD02EB29A0B0043A0B3 /* QuickLookThumbnailing.framework */,
|
||||
);
|
||||
name = Frameworks;
|
||||
sourceTree = "<group>";
|
||||
@@ -192,6 +228,16 @@
|
||||
path = QLPreview;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
545820202EB29B3D0043A0B3 /* QLThumbnail */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
5458201D2EB29B3D0043A0B3 /* Info.plist */,
|
||||
5458201E2EB29B3D0043A0B3 /* QLThumbnail.entitlements */,
|
||||
5458201F2EB29B3D0043A0B3 /* ThumbnailProvider.swift */,
|
||||
);
|
||||
path = QLThumbnail;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
54D3A6F42EA46069001EF4F6 /* resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -226,6 +272,7 @@
|
||||
);
|
||||
dependencies = (
|
||||
54442C2F2E378BAF008A870E /* PBXTargetDependency */,
|
||||
54581FD92EB29A0B0043A0B3 /* PBXTargetDependency */,
|
||||
);
|
||||
name = QLApps;
|
||||
packageProductDependencies = (
|
||||
@@ -253,6 +300,25 @@
|
||||
productReference = 54442C202E378BAF008A870E /* QLPreview.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
54581FCE2EB29A0B0043A0B3 /* QLThumbnail */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 54581FDE2EB29A0B0043A0B3 /* Build configuration list for PBXNativeTarget "QLThumbnail" */;
|
||||
buildPhases = (
|
||||
54581FCB2EB29A0B0043A0B3 /* Sources */,
|
||||
54581FCC2EB29A0B0043A0B3 /* Frameworks */,
|
||||
54581FCD2EB29A0B0043A0B3 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = QLThumbnail;
|
||||
packageProductDependencies = (
|
||||
);
|
||||
productName = QLThumbnail;
|
||||
productReference = 54581FCF2EB29A0B0043A0B3 /* QLThumbnail.appex */;
|
||||
productType = "com.apple.product-type.app-extension";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
@@ -269,6 +335,9 @@
|
||||
54442C1F2E378BAF008A870E = {
|
||||
CreatedOnToolsVersion = 16.4;
|
||||
};
|
||||
54581FCE2EB29A0B0043A0B3 = {
|
||||
CreatedOnToolsVersion = 16.4;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 54442BEF2E378B71008A870E /* Build configuration list for PBXProject "QLApps" */;
|
||||
@@ -287,6 +356,7 @@
|
||||
targets = (
|
||||
54442BF32E378B71008A870E /* QLApps */,
|
||||
54442C1F2E378BAF008A870E /* QLPreview */,
|
||||
54581FCE2EB29A0B0043A0B3 /* QLThumbnail */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
@@ -312,6 +382,14 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
54581FCD2EB29A0B0043A0B3 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
545820232EB29B4C0043A0B3 /* defaultIcon.png in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@@ -340,6 +418,20 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
54581FCB2EB29A0B0043A0B3 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
54581FFD2EB29AB70043A0B3 /* Plist.swift in Sources */,
|
||||
54581FEF2EB29A570043A0B3 /* Shared.swift in Sources */,
|
||||
54581FF02EB29A5E0043A0B3 /* AppIcon.swift in Sources */,
|
||||
54581FF72EB29A820043A0B3 /* Zip.swift in Sources */,
|
||||
545820032EB29B0A0043A0B3 /* RoundedIcon.swift in Sources */,
|
||||
545820222EB29B3D0043A0B3 /* ThumbnailProvider.swift in Sources */,
|
||||
54581FF12EB29A620043A0B3 /* AppIcon+Car.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
@@ -348,6 +440,11 @@
|
||||
target = 54442C1F2E378BAF008A870E /* QLPreview */;
|
||||
targetProxy = 54442C2E2E378BAF008A870E /* PBXContainerItemProxy */;
|
||||
};
|
||||
54581FD92EB29A0B0043A0B3 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 54581FCE2EB29A0B0043A0B3 /* QLThumbnail */;
|
||||
targetProxy = 54581FD82EB29A0B0043A0B3 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
@@ -404,7 +501,7 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 773;
|
||||
CURRENT_PROJECT_VERSION = 842;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = UY657LKNHJ;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
@@ -475,7 +572,7 @@
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 773;
|
||||
CURRENT_PROJECT_VERSION = 842;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = UY657LKNHJ;
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
@@ -617,6 +714,62 @@
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
54581FDB2EB29A0B0043A0B3 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = QLThumbnail/QLThumbnail.entitlements;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = UY657LKNHJ;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = QLThumbnail/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = QLThumbnail;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
"@executable_path/../../../../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = de.relikd.QLApps.QLThumbnail;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_INCLUDE_PATHS = "$(SRCROOT)/PrivateFrameworks/CoreUI.framework $(inherited)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
54581FDC2EB29A0B0043A0B3 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = QLThumbnail/QLThumbnail.entitlements;
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=macosx*]" = UY657LKNHJ;
|
||||
ENABLE_HARDENED_RUNTIME = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = QLThumbnail/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = QLThumbnail;
|
||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/../Frameworks",
|
||||
"@executable_path/../../../../Frameworks",
|
||||
);
|
||||
MACOSX_DEPLOYMENT_TARGET = 15.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = de.relikd.QLApps.QLThumbnail;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_INCLUDE_PATHS = "$(SRCROOT)/PrivateFrameworks/CoreUI.framework $(inherited)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
@@ -647,6 +800,15 @@
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
54581FDE2EB29A0B0043A0B3 /* Build configuration list for PBXNativeTarget "QLThumbnail" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
54581FDB2EB29A0B0043A0B3 /* Debug */,
|
||||
54581FDC2EB29A0B0043A0B3 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 54442BEC2E378B71008A870E /* Project object */;
|
||||
|
||||
@@ -4,7 +4,7 @@ import WebKit // WebView
|
||||
import os // OSLog
|
||||
|
||||
// show Console logs with subsystem:de.relikd.QLApps
|
||||
private let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "main")
|
||||
private let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "preview-plugin")
|
||||
|
||||
class PreviewViewController: NSViewController, QLPreviewingController {
|
||||
|
||||
|
||||
24
QLThumbnail/Info.plist
Normal file
24
QLThumbnail/Info.plist
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionAttributes</key>
|
||||
<dict>
|
||||
<key>QLSupportedContentTypes</key>
|
||||
<array>
|
||||
<string>com.apple.itunes.ipa</string>
|
||||
<string>com.apple.application-and-system-extension</string>
|
||||
<string>com.apple.xcode.archive</string>
|
||||
</array>
|
||||
<key>QLThumbnailMinimumDimension</key>
|
||||
<integer>16</integer>
|
||||
</dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.quicklook.thumbnail</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).ThumbnailProvider</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
10
QLThumbnail/QLThumbnail.entitlements
Normal file
10
QLThumbnail/QLThumbnail.entitlements
Normal file
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.app-sandbox</key>
|
||||
<true/>
|
||||
<key>com.apple.security.files.user-selected.read-only</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
43
QLThumbnail/ThumbnailProvider.swift
Normal file
43
QLThumbnail/ThumbnailProvider.swift
Normal file
@@ -0,0 +1,43 @@
|
||||
import QuickLookThumbnailing
|
||||
import os // OSLog
|
||||
|
||||
// show Console logs with subsystem:de.relikd.QLApps
|
||||
private let log = OSLog(subsystem: Bundle.main.bundleIdentifier!, category: "thumbnail-plugin")
|
||||
|
||||
extension QLThumbnailReply {
|
||||
/// call private method `setIconFlavor:`
|
||||
/// see https://medium.com/swlh/calling-ios-and-macos-hidden-api-in-style-1a924f244ad1
|
||||
fileprivate func setFlavor(_ flavor: Int) {
|
||||
typealias setIconFlavorMethod = @convention(c) (NSObject, Selector, NSInteger) -> Bool
|
||||
let selector = NSSelectorFromString("setIconFlavor:")
|
||||
let imp = self.method(for: selector)
|
||||
let method = unsafeBitCast(imp, to: setIconFlavorMethod.self)
|
||||
_ = method(self, selector, flavor)
|
||||
}
|
||||
}
|
||||
|
||||
class ThumbnailProvider: QLThumbnailProvider {
|
||||
|
||||
// TODO: sadly, this does not seem to work for .xarchive and .appex
|
||||
// Probably overwritten by Apple somehow
|
||||
|
||||
override func provideThumbnail(for request: QLFileThumbnailRequest, _ handler: @escaping (QLThumbnailReply?, Error?) -> Void) {
|
||||
let meta = QuickLookInfo(request.fileURL)
|
||||
let icon = AppIcon(meta)
|
||||
let plistApp = meta.readPlistApp()
|
||||
let img = icon.extractImage(from: plistApp).withRoundCorners()
|
||||
|
||||
// First way: Draw the thumbnail into the current context, set up with UIKit's coordinate system.
|
||||
let reply = QLThumbnailReply(contextSize: request.maximumSize, currentContextDrawing: { () -> Bool in
|
||||
img.draw(in: CGRect(origin: .zero, size: request.maximumSize))
|
||||
return true
|
||||
})
|
||||
// defer in case `setFlavor` fails
|
||||
defer {
|
||||
handler(reply, nil)
|
||||
}
|
||||
// 0: Plain transparent, 1: Shadow, 2: Book, 3: Movie, 4: Address, 5: Image,
|
||||
// 6: Gloss, 7: Slide, 8: Square, 9: Border, 11: Calendar, 12: Pattern
|
||||
reply.setFlavor(meta.type == .Archive ? 12 : 0) // .archive looks like "in development"
|
||||
}
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
import Foundation
|
||||
|
||||
////#import "Shared.h"
|
||||
//#import "AppIcon.h"
|
||||
//
|
||||
//// makro to stop further processing
|
||||
//#define ALLOW_EXIT if (QLThumbnailRequestIsCancelled(thumbnail)) { return noErr; }
|
||||
//
|
||||
////Layout constants
|
||||
//#define BADGE_MARGIN 10.0
|
||||
//#define MIN_BADGE_WIDTH 40.0
|
||||
//#define BADGE_HEIGHT 75.0
|
||||
//#define BADGE_MARGIN_X 60.0
|
||||
//#define BADGE_MARGIN_Y 80.0
|
||||
//
|
||||
////Drawing constants
|
||||
//#define BADGE_BG_COLOR [NSColor lightGrayColor]
|
||||
//#define BADGE_VALID_COLOR [NSColor colorWithCalibratedRed:(0/255.0) green:(98/255.0) blue:(25/255.0) alpha:1]
|
||||
//#define BADGE_EXPIRING_COLOR [NSColor colorWithCalibratedRed:(146/255.0) green:(95/255.0) blue:(28/255.0) alpha:1]
|
||||
//#define BADGE_EXPIRED_COLOR [NSColor colorWithCalibratedRed:(141/255.0) green:(0/255.0) blue:(7/255.0) alpha:1]
|
||||
//#define BADGE_FONT [NSFont boldSystemFontOfSize:64]
|
||||
//
|
||||
//
|
||||
//OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize);
|
||||
//void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbnail);
|
||||
//
|
||||
///* -----------------------------------------------------------------------------
|
||||
// Generate a thumbnail for file
|
||||
//
|
||||
// This function's job is to create thumbnail for designated file as fast as possible
|
||||
// ----------------------------------------------------------------------------- */
|
||||
//
|
||||
//// MARK: .ipa .xcarchive
|
||||
//
|
||||
//OSStatus renderAppIcon(QuickLookInfo meta, QLThumbnailRequestRef thumbnail) {
|
||||
// AppIcon *icon = [AppIcon load:meta];
|
||||
// if (!icon.canExtractImage) {
|
||||
// return noErr;
|
||||
// }
|
||||
//
|
||||
// // set magic flag to draw icon without additional markers
|
||||
// static const NSString *IconFlavor;
|
||||
// if (@available(macOS 10.15, *)) {
|
||||
// IconFlavor = @"icon";
|
||||
// } else {
|
||||
// IconFlavor = @"IconFlavor";
|
||||
// }
|
||||
// NSDictionary *propertiesDict = nil;
|
||||
// if (meta.type == FileTypeArchive) {
|
||||
// // 0: Plain transparent, 1: Shadow, 2: Book, 3: Movie, 4: Address, 5: Image,
|
||||
// // 6: Gloss, 7: Slide, 8: Square, 9: Border, 11: Calendar, 12: Pattern
|
||||
// propertiesDict = @{IconFlavor : @(12)}; // looks like "in development"
|
||||
// } else {
|
||||
// propertiesDict = @{IconFlavor : @(0)}; // no border, no anything
|
||||
// }
|
||||
//
|
||||
// NSImage *appIcon = [[icon extractImage:nil] withRoundCorners];
|
||||
// ALLOW_EXIT
|
||||
//
|
||||
// // image-only icons can be drawn efficiently by calling `SetImage` directly.
|
||||
// QLThumbnailRequestSetImageWithData(thumbnail, (__bridge CFDataRef)[appIcon TIFFRepresentation], (__bridge CFDictionaryRef)propertiesDict);
|
||||
// return noErr;
|
||||
//}
|
||||
//
|
||||
//
|
||||
//// MARK: .provisioning
|
||||
//
|
||||
//OSStatus renderProvision(QuickLookInfo meta, QLThumbnailRequestRef thumbnail, BOOL iconMode) {
|
||||
// NSDictionary *propertyList = readPlistProvision(meta);
|
||||
// ALLOW_EXIT
|
||||
//
|
||||
// NSUInteger devicesCount = arrayOrNil(propertyList[@"ProvisionedDevices"]).count;
|
||||
// NSDate *expirationDate = dateOrNil(propertyList[@"ExpirationDate"]);
|
||||
//
|
||||
// NSImage *appIcon = nil;
|
||||
// if (iconMode) {
|
||||
// NSURL *iconURL = [[NSBundle bundleWithIdentifier:kPluginBundleId] URLForResource:@"blankIcon" withExtension:@"png"];
|
||||
// appIcon = [[NSImage alloc] initWithContentsOfURL:iconURL];
|
||||
// } else {
|
||||
// appIcon = [[NSWorkspace sharedWorkspace] iconForFileType:meta.UTI];
|
||||
// [appIcon setSize:NSMakeSize(512, 512)];
|
||||
// }
|
||||
// ALLOW_EXIT
|
||||
//
|
||||
// NSRect renderRect = NSMakeRect(0.0, 0.0, appIcon.size.width, appIcon.size.height);
|
||||
//
|
||||
// // Font attributes
|
||||
// NSColor *outlineColor;
|
||||
// switch (expirationStatus(expirationDate)) {
|
||||
// case ExpirationStatusExpired: outlineColor = BADGE_EXPIRED_COLOR; break;
|
||||
// case ExpirationStatusExpiring: outlineColor = BADGE_EXPIRING_COLOR; break;
|
||||
// case ExpirationStatusValid: outlineColor = BADGE_VALID_COLOR; break;
|
||||
// }
|
||||
//
|
||||
// NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
||||
// paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
|
||||
// paragraphStyle.alignment = NSTextAlignmentCenter;
|
||||
//
|
||||
// NSDictionary *fontAttrs = @{
|
||||
// NSFontAttributeName : BADGE_FONT,
|
||||
// NSForegroundColorAttributeName : outlineColor,
|
||||
// NSParagraphStyleAttributeName: paragraphStyle
|
||||
// };
|
||||
//
|
||||
// // Badge size & placement
|
||||
// int badgeX = renderRect.origin.x + BADGE_MARGIN_X;
|
||||
// int badgeY = renderRect.origin.y + renderRect.size.height - BADGE_HEIGHT - BADGE_MARGIN_Y;
|
||||
// if (!iconMode) {
|
||||
// badgeX += 75;
|
||||
// badgeY -= 10;
|
||||
// }
|
||||
// int badgeNumX = badgeX + BADGE_MARGIN;
|
||||
// NSPoint badgeTextPoint = NSMakePoint(badgeNumX, badgeY);
|
||||
//
|
||||
// NSString *badge = [NSString stringWithFormat:@"%lu",(unsigned long)devicesCount];
|
||||
// NSSize badgeNumSize = [badge sizeWithAttributes:fontAttrs];
|
||||
// int badgeWidth = badgeNumSize.width + BADGE_MARGIN * 2;
|
||||
// NSRect badgeOutlineRect = NSMakeRect(badgeX, badgeY, MAX(badgeWidth, MIN_BADGE_WIDTH), BADGE_HEIGHT);
|
||||
//
|
||||
// // Do as much work as possible before the `CreateContext`. We can try to quit early before that!
|
||||
// CGContextRef _context = QLThumbnailRequestCreateContext(thumbnail, renderRect.size, false, NULL);
|
||||
// if (_context) {
|
||||
// NSGraphicsContext *_graphicsContext = [NSGraphicsContext graphicsContextWithCGContext:(void *)_context flipped:NO];
|
||||
// [NSGraphicsContext setCurrentContext:_graphicsContext];
|
||||
// [appIcon drawInRect:renderRect];
|
||||
//
|
||||
// NSBezierPath *badgePath = [NSBezierPath bezierPathWithRoundedRect:badgeOutlineRect xRadius:10 yRadius:10];
|
||||
// [badgePath setLineWidth:8.0];
|
||||
// [BADGE_BG_COLOR set];
|
||||
// [badgePath fill];
|
||||
// [outlineColor set];
|
||||
// [badgePath stroke];
|
||||
//
|
||||
// [badge drawAtPoint:badgeTextPoint withAttributes:fontAttrs];
|
||||
//
|
||||
// QLThumbnailRequestFlushContext(thumbnail, _context);
|
||||
// CFRelease(_context);
|
||||
// }
|
||||
// return noErr;
|
||||
//}
|
||||
//
|
||||
//
|
||||
//// MARK: Main Entry
|
||||
//
|
||||
//OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize) {
|
||||
// @autoreleasepool {
|
||||
// QuickLookInfo meta = initQLInfo(contentTypeUTI, url);
|
||||
//
|
||||
// if (meta.type == FileTypeProvision) {
|
||||
// NSDictionary *optionsDict = (__bridge NSDictionary *)options;
|
||||
// BOOL iconMode = ([optionsDict objectForKey:(NSString *)kQLThumbnailOptionIconModeKey]) ? YES : NO;
|
||||
// return renderProvision(meta, thumbnail, iconMode);
|
||||
// } else {
|
||||
// return renderAppIcon(meta, thumbnail);
|
||||
// }
|
||||
// }
|
||||
// return noErr;
|
||||
//}
|
||||
//
|
||||
//void CancelThumbnailGeneration(void *thisInterface, QLThumbnailRequestRef thumbnail) {
|
||||
// // Implement only if supported
|
||||
//}
|
||||
Reference in New Issue
Block a user