Add Quick Look Preview and Thumbnail extensions for .casera files
- Add CaseraQLPreview extension to show custom preview with contractor details and import instructions when viewing .casera files - Add CaseraQLThumbnail extension to display teal icon in Messages and Files app instead of generic white box - Update UTExportedTypeDeclarations to conform to public.content for better system file type recognition 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
27
iosApp/CaseraQLPreview/Base.lproj/MainInterface.storyboard
Normal file
27
iosApp/CaseraQLPreview/Base.lproj/MainInterface.storyboard
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="M4Y-Lb-cyx">
|
||||||
|
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
|
||||||
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--Preview View Controller-->
|
||||||
|
<scene sceneID="cwh-vc-ff4">
|
||||||
|
<objects>
|
||||||
|
<viewController id="M4Y-Lb-cyx" customClass="PreviewViewController" customModule="CaseraQLPreview" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
|
<view key="view" contentMode="scaleToFill" id="S3S-Oj-5AN">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<viewLayoutGuide key="safeArea" id="bzV-dz-m25"/>
|
||||||
|
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
||||||
|
</view>
|
||||||
|
<extendedEdge key="edgesForExtendedLayout"/>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="vXp-U4-Rya" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="705" y="299"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
</document>
|
||||||
38
iosApp/CaseraQLPreview/Info.plist
Normal file
38
iosApp/CaseraQLPreview/Info.plist
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?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>CFBundleDisplayName</key>
|
||||||
|
<string>Casera Preview</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>NSExtension</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionAttributes</key>
|
||||||
|
<dict>
|
||||||
|
<key>QLSupportedContentTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>com.casera.contractor</string>
|
||||||
|
</array>
|
||||||
|
<key>QLSupportsSearchableItems</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
<key>NSExtensionMainStoryboard</key>
|
||||||
|
<string>MainInterface</string>
|
||||||
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
<string>com.apple.quicklook.preview</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
57
iosApp/CaseraQLPreview/PreviewProvider.swift
Normal file
57
iosApp/CaseraQLPreview/PreviewProvider.swift
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
//
|
||||||
|
// PreviewProvider.swift
|
||||||
|
// CaseraQLPreview
|
||||||
|
//
|
||||||
|
// Created by Trey Tartt on 12/6/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import QuickLook
|
||||||
|
|
||||||
|
class PreviewProvider: QLPreviewProvider, QLPreviewingController {
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Use a QLPreviewProvider to provide data-based previews.
|
||||||
|
|
||||||
|
To set up your extension as a data-based preview extension:
|
||||||
|
|
||||||
|
- Modify the extension's Info.plist by setting
|
||||||
|
<key>QLIsDataBasedPreview</key>
|
||||||
|
<true/>
|
||||||
|
|
||||||
|
- Add the supported content types to QLSupportedContentTypes array in the extension's Info.plist.
|
||||||
|
|
||||||
|
- Remove
|
||||||
|
<key>NSExtensionMainStoryboard</key>
|
||||||
|
<string>MainInterface</string>
|
||||||
|
|
||||||
|
and replace it by setting the NSExtensionPrincipalClass to this class, e.g.
|
||||||
|
<key>NSExtensionPrincipalClass</key>
|
||||||
|
<string>$(PRODUCT_MODULE_NAME).PreviewProvider</string>
|
||||||
|
|
||||||
|
- Implement providePreview(for:)
|
||||||
|
*/
|
||||||
|
|
||||||
|
func providePreview(for request: QLFilePreviewRequest) async throws -> QLPreviewReply {
|
||||||
|
|
||||||
|
//You can create a QLPreviewReply in several ways, depending on the format of the data you want to return.
|
||||||
|
//To return Data of a supported content type:
|
||||||
|
|
||||||
|
let contentType = UTType.plainText // replace with your data type
|
||||||
|
|
||||||
|
let reply = QLPreviewReply.init(dataOfContentType: contentType, contentSize: CGSize.init(width: 800, height: 800)) { (replyToUpdate : QLPreviewReply) in
|
||||||
|
|
||||||
|
let data = Data("Hello world".utf8)
|
||||||
|
|
||||||
|
//setting the stringEncoding for text and html data is optional and defaults to String.Encoding.utf8
|
||||||
|
replyToUpdate.stringEncoding = .utf8
|
||||||
|
|
||||||
|
//initialize your data here
|
||||||
|
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
return reply
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
264
iosApp/CaseraQLPreview/PreviewViewController.swift
Normal file
264
iosApp/CaseraQLPreview/PreviewViewController.swift
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
import UIKit
|
||||||
|
import QuickLook
|
||||||
|
|
||||||
|
class PreviewViewController: UIViewController, QLPreviewingController {
|
||||||
|
|
||||||
|
// MARK: - UI Elements
|
||||||
|
|
||||||
|
private let containerView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private let iconImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView()
|
||||||
|
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
imageView.contentMode = .scaleAspectFit
|
||||||
|
imageView.tintColor = UIColor(red: 7/255, green: 160/255, blue: 195/255, alpha: 1) // App primary color
|
||||||
|
let config = UIImage.SymbolConfiguration(pointSize: 60, weight: .light)
|
||||||
|
imageView.image = UIImage(systemName: "person.crop.rectangle.stack", withConfiguration: config)
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
private let titleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
label.font = .systemFont(ofSize: 24, weight: .bold)
|
||||||
|
label.textColor = .label
|
||||||
|
label.textAlignment = .center
|
||||||
|
label.numberOfLines = 2
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private let subtitleLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
label.font = .systemFont(ofSize: 15, weight: .medium)
|
||||||
|
label.textColor = .secondaryLabel
|
||||||
|
label.textAlignment = .center
|
||||||
|
label.text = "Casera Contractor File"
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private let dividerView: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
view.backgroundColor = .separator
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private let detailsStackView: UIStackView = {
|
||||||
|
let stack = UIStackView()
|
||||||
|
stack.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
stack.axis = .vertical
|
||||||
|
stack.spacing = 12
|
||||||
|
stack.alignment = .leading
|
||||||
|
return stack
|
||||||
|
}()
|
||||||
|
|
||||||
|
private let instructionCard: UIView = {
|
||||||
|
let view = UIView()
|
||||||
|
view.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
view.backgroundColor = UIColor(red: 7/255, green: 160/255, blue: 195/255, alpha: 0.1)
|
||||||
|
view.layer.cornerRadius = 12
|
||||||
|
return view
|
||||||
|
}()
|
||||||
|
|
||||||
|
private let instructionLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
label.font = .systemFont(ofSize: 15, weight: .medium)
|
||||||
|
label.textColor = UIColor(red: 7/255, green: 160/255, blue: 195/255, alpha: 1)
|
||||||
|
label.textAlignment = .center
|
||||||
|
label.numberOfLines = 0
|
||||||
|
label.text = "Tap the share button below, then select \"Casera\" to import this contractor."
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
private let arrowImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView()
|
||||||
|
imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
imageView.contentMode = .scaleAspectFit
|
||||||
|
imageView.tintColor = .secondaryLabel
|
||||||
|
let config = UIImage.SymbolConfiguration(pointSize: 24, weight: .medium)
|
||||||
|
imageView.image = UIImage(systemName: "arrow.down", withConfiguration: config)
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
// MARK: - Data
|
||||||
|
|
||||||
|
private var contractorData: ContractorPreviewData?
|
||||||
|
|
||||||
|
// MARK: - Lifecycle
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
print("CaseraQLPreview: viewDidLoad called")
|
||||||
|
setupUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Setup
|
||||||
|
|
||||||
|
private func setupUI() {
|
||||||
|
view.backgroundColor = .systemBackground
|
||||||
|
|
||||||
|
view.addSubview(containerView)
|
||||||
|
containerView.addSubview(iconImageView)
|
||||||
|
containerView.addSubview(titleLabel)
|
||||||
|
containerView.addSubview(subtitleLabel)
|
||||||
|
containerView.addSubview(dividerView)
|
||||||
|
containerView.addSubview(detailsStackView)
|
||||||
|
containerView.addSubview(instructionCard)
|
||||||
|
instructionCard.addSubview(instructionLabel)
|
||||||
|
containerView.addSubview(arrowImageView)
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
containerView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
|
||||||
|
containerView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: -40),
|
||||||
|
containerView.leadingAnchor.constraint(greaterThanOrEqualTo: view.leadingAnchor, constant: 32),
|
||||||
|
containerView.trailingAnchor.constraint(lessThanOrEqualTo: view.trailingAnchor, constant: -32),
|
||||||
|
containerView.widthAnchor.constraint(lessThanOrEqualToConstant: 340),
|
||||||
|
|
||||||
|
iconImageView.topAnchor.constraint(equalTo: containerView.topAnchor),
|
||||||
|
iconImageView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
|
||||||
|
iconImageView.widthAnchor.constraint(equalToConstant: 80),
|
||||||
|
iconImageView.heightAnchor.constraint(equalToConstant: 80),
|
||||||
|
|
||||||
|
titleLabel.topAnchor.constraint(equalTo: iconImageView.bottomAnchor, constant: 16),
|
||||||
|
titleLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
|
||||||
|
titleLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
|
||||||
|
|
||||||
|
subtitleLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 4),
|
||||||
|
subtitleLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
|
||||||
|
subtitleLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
|
||||||
|
|
||||||
|
dividerView.topAnchor.constraint(equalTo: subtitleLabel.bottomAnchor, constant: 20),
|
||||||
|
dividerView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
|
||||||
|
dividerView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
|
||||||
|
dividerView.heightAnchor.constraint(equalToConstant: 1),
|
||||||
|
|
||||||
|
detailsStackView.topAnchor.constraint(equalTo: dividerView.bottomAnchor, constant: 20),
|
||||||
|
detailsStackView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
|
||||||
|
detailsStackView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
|
||||||
|
|
||||||
|
instructionCard.topAnchor.constraint(equalTo: detailsStackView.bottomAnchor, constant: 24),
|
||||||
|
instructionCard.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
|
||||||
|
instructionCard.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
|
||||||
|
|
||||||
|
instructionLabel.topAnchor.constraint(equalTo: instructionCard.topAnchor, constant: 16),
|
||||||
|
instructionLabel.leadingAnchor.constraint(equalTo: instructionCard.leadingAnchor, constant: 16),
|
||||||
|
instructionLabel.trailingAnchor.constraint(equalTo: instructionCard.trailingAnchor, constant: -16),
|
||||||
|
instructionLabel.bottomAnchor.constraint(equalTo: instructionCard.bottomAnchor, constant: -16),
|
||||||
|
|
||||||
|
arrowImageView.topAnchor.constraint(equalTo: instructionCard.bottomAnchor, constant: 16),
|
||||||
|
arrowImageView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor),
|
||||||
|
arrowImageView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
private func addDetailRow(icon: String, text: String) {
|
||||||
|
let rowStack = UIStackView()
|
||||||
|
rowStack.axis = .horizontal
|
||||||
|
rowStack.spacing = 12
|
||||||
|
rowStack.alignment = .center
|
||||||
|
|
||||||
|
let iconView = UIImageView()
|
||||||
|
iconView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
let config = UIImage.SymbolConfiguration(pointSize: 16, weight: .medium)
|
||||||
|
iconView.image = UIImage(systemName: icon, withConfiguration: config)
|
||||||
|
iconView.tintColor = .secondaryLabel
|
||||||
|
iconView.widthAnchor.constraint(equalToConstant: 24).isActive = true
|
||||||
|
iconView.heightAnchor.constraint(equalToConstant: 24).isActive = true
|
||||||
|
|
||||||
|
let textLabel = UILabel()
|
||||||
|
textLabel.font = .systemFont(ofSize: 15)
|
||||||
|
textLabel.textColor = .label
|
||||||
|
textLabel.text = text
|
||||||
|
textLabel.numberOfLines = 1
|
||||||
|
|
||||||
|
rowStack.addArrangedSubview(iconView)
|
||||||
|
rowStack.addArrangedSubview(textLabel)
|
||||||
|
|
||||||
|
detailsStackView.addArrangedSubview(rowStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - QLPreviewingController
|
||||||
|
|
||||||
|
func preparePreviewOfFile(at url: URL) async throws {
|
||||||
|
print("CaseraQLPreview: preparePreviewOfFile called with URL: \(url)")
|
||||||
|
// Parse the .casera file
|
||||||
|
let data = try Data(contentsOf: url)
|
||||||
|
let decoder = JSONDecoder()
|
||||||
|
let contractor = try decoder.decode(ContractorPreviewData.self, from: data)
|
||||||
|
self.contractorData = contractor
|
||||||
|
print("CaseraQLPreview: Parsed contractor: \(contractor.name)")
|
||||||
|
|
||||||
|
await MainActor.run {
|
||||||
|
self.updateUI(with: contractor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateUI(with contractor: ContractorPreviewData) {
|
||||||
|
titleLabel.text = contractor.name
|
||||||
|
|
||||||
|
// Clear existing details
|
||||||
|
detailsStackView.arrangedSubviews.forEach { $0.removeFromSuperview() }
|
||||||
|
|
||||||
|
// Add details
|
||||||
|
if let company = contractor.company, !company.isEmpty {
|
||||||
|
addDetailRow(icon: "building.2", text: company)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let phone = contractor.phone, !phone.isEmpty {
|
||||||
|
addDetailRow(icon: "phone", text: phone)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let email = contractor.email, !email.isEmpty {
|
||||||
|
addDetailRow(icon: "envelope", text: email)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !contractor.specialtyNames.isEmpty {
|
||||||
|
let specialties = contractor.specialtyNames.joined(separator: ", ")
|
||||||
|
addDetailRow(icon: "wrench.and.screwdriver", text: specialties)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let exportedBy = contractor.exportedBy, !exportedBy.isEmpty {
|
||||||
|
addDetailRow(icon: "person", text: "Shared by \(exportedBy)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - Data Model
|
||||||
|
|
||||||
|
struct ContractorPreviewData: Codable {
|
||||||
|
let version: Int
|
||||||
|
let name: String
|
||||||
|
let company: String?
|
||||||
|
let phone: String?
|
||||||
|
let email: String?
|
||||||
|
let website: String?
|
||||||
|
let notes: String?
|
||||||
|
let streetAddress: String?
|
||||||
|
let city: String?
|
||||||
|
let stateProvince: String?
|
||||||
|
let postalCode: String?
|
||||||
|
let specialtyNames: [String]
|
||||||
|
let rating: Double?
|
||||||
|
let isFavorite: Bool
|
||||||
|
let exportedAt: String?
|
||||||
|
let exportedBy: String?
|
||||||
|
|
||||||
|
enum CodingKeys: String, CodingKey {
|
||||||
|
case version, name, company, phone, email, website, notes
|
||||||
|
case streetAddress = "street_address"
|
||||||
|
case city
|
||||||
|
case stateProvince = "state_province"
|
||||||
|
case postalCode = "postal_code"
|
||||||
|
case specialtyNames = "specialty_names"
|
||||||
|
case rating
|
||||||
|
case isFavorite = "is_favorite"
|
||||||
|
case exportedAt = "exported_at"
|
||||||
|
case exportedBy = "exported_by"
|
||||||
|
}
|
||||||
|
}
|
||||||
38
iosApp/CaseraQLThumbnail/Info.plist
Normal file
38
iosApp/CaseraQLThumbnail/Info.plist
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
<?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>CFBundleDisplayName</key>
|
||||||
|
<string>Casera Thumbnail</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>1.0</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>1</string>
|
||||||
|
<key>NSExtension</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionAttributes</key>
|
||||||
|
<dict>
|
||||||
|
<key>QLSupportedContentTypes</key>
|
||||||
|
<array>
|
||||||
|
<string>com.casera.contractor</string>
|
||||||
|
</array>
|
||||||
|
<key>QLThumbnailMinimumDimension</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
|
<key>NSExtensionPrincipalClass</key>
|
||||||
|
<string>$(PRODUCT_MODULE_NAME).ThumbnailProvider</string>
|
||||||
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
<string>com.apple.quicklook.thumbnail</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
38
iosApp/CaseraQLThumbnail/ThumbnailProvider.swift
Normal file
38
iosApp/CaseraQLThumbnail/ThumbnailProvider.swift
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// ThumbnailProvider.swift
|
||||||
|
// CaseraQLThumbnail
|
||||||
|
//
|
||||||
|
// Created by Trey Tartt on 12/6/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import QuickLookThumbnailing
|
||||||
|
|
||||||
|
class ThumbnailProvider: QLThumbnailProvider {
|
||||||
|
|
||||||
|
override func provideThumbnail(for request: QLFileThumbnailRequest, _ handler: @escaping (QLThumbnailReply?, Error?) -> Void) {
|
||||||
|
|
||||||
|
let thumbnailSize = request.maximumSize
|
||||||
|
|
||||||
|
handler(QLThumbnailReply(contextSize: thumbnailSize, currentContextDrawing: { () -> Bool in
|
||||||
|
// Draw background
|
||||||
|
let backgroundColor = UIColor(red: 7/255, green: 160/255, blue: 195/255, alpha: 1)
|
||||||
|
backgroundColor.setFill()
|
||||||
|
UIRectFill(CGRect(origin: .zero, size: thumbnailSize))
|
||||||
|
|
||||||
|
// Draw icon
|
||||||
|
let config = UIImage.SymbolConfiguration(pointSize: min(thumbnailSize.width, thumbnailSize.height) * 0.5, weight: .regular)
|
||||||
|
if let icon = UIImage(systemName: "person.crop.rectangle.stack", withConfiguration: config) {
|
||||||
|
let tintedIcon = icon.withTintColor(.white, renderingMode: .alwaysOriginal)
|
||||||
|
let iconSize = tintedIcon.size
|
||||||
|
let iconOrigin = CGPoint(
|
||||||
|
x: (thumbnailSize.width - iconSize.width) / 2,
|
||||||
|
y: (thumbnailSize.height - iconSize.height) / 2
|
||||||
|
)
|
||||||
|
tintedIcon.draw(at: iconOrigin)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}), nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,10 @@
|
|||||||
1C0789402EBC218B00392B46 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C07893F2EBC218B00392B46 /* WidgetKit.framework */; };
|
1C0789402EBC218B00392B46 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C07893F2EBC218B00392B46 /* WidgetKit.framework */; };
|
||||||
1C0789422EBC218B00392B46 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C0789412EBC218B00392B46 /* SwiftUI.framework */; };
|
1C0789422EBC218B00392B46 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C0789412EBC218B00392B46 /* SwiftUI.framework */; };
|
||||||
1C0789532EBC218D00392B46 /* CaseraExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 1C07893D2EBC218B00392B46 /* CaseraExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
1C0789532EBC218D00392B46 /* CaseraExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 1C07893D2EBC218B00392B46 /* CaseraExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
|
1C81F26B2EE416EE000739EA /* QuickLook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C81F26A2EE416EE000739EA /* QuickLook.framework */; };
|
||||||
|
1C81F2772EE416EF000739EA /* CaseraQLPreview.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 1C81F2692EE416EE000739EA /* CaseraQLPreview.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
|
1C81F2822EE41BB6000739EA /* QuickLookThumbnailing.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C81F2812EE41BB6000739EA /* QuickLookThumbnailing.framework */; };
|
||||||
|
1C81F2892EE41BB6000739EA /* CaseraQLThumbnail.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 1C81F2802EE41BB6000739EA /* CaseraQLThumbnail.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -20,6 +24,20 @@
|
|||||||
remoteGlobalIDString = 1C07893C2EBC218B00392B46;
|
remoteGlobalIDString = 1C07893C2EBC218B00392B46;
|
||||||
remoteInfo = CaseraExtension;
|
remoteInfo = CaseraExtension;
|
||||||
};
|
};
|
||||||
|
1C81F2752EE416EF000739EA /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 6A3E1D84F9F1A2FD92A75A6C /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 1C81F2682EE416EE000739EA;
|
||||||
|
remoteInfo = CaseraQLPreview;
|
||||||
|
};
|
||||||
|
1C81F2872EE41BB6000739EA /* PBXContainerItemProxy */ = {
|
||||||
|
isa = PBXContainerItemProxy;
|
||||||
|
containerPortal = 6A3E1D84F9F1A2FD92A75A6C /* Project object */;
|
||||||
|
proxyType = 1;
|
||||||
|
remoteGlobalIDString = 1C81F27F2EE41BB6000739EA;
|
||||||
|
remoteInfo = CaseraQLThumbnail;
|
||||||
|
};
|
||||||
1CBF16002ECD8AE4001BF56C /* PBXContainerItemProxy */ = {
|
1CBF16002ECD8AE4001BF56C /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = 6A3E1D84F9F1A2FD92A75A6C /* Project object */;
|
containerPortal = 6A3E1D84F9F1A2FD92A75A6C /* Project object */;
|
||||||
@@ -44,6 +62,8 @@
|
|||||||
dstSubfolderSpec = 13;
|
dstSubfolderSpec = 13;
|
||||||
files = (
|
files = (
|
||||||
1C0789532EBC218D00392B46 /* CaseraExtension.appex in Embed Foundation Extensions */,
|
1C0789532EBC218D00392B46 /* CaseraExtension.appex in Embed Foundation Extensions */,
|
||||||
|
1C81F2892EE41BB6000739EA /* CaseraQLThumbnail.appex in Embed Foundation Extensions */,
|
||||||
|
1C81F2772EE416EF000739EA /* CaseraQLPreview.appex in Embed Foundation Extensions */,
|
||||||
);
|
);
|
||||||
name = "Embed Foundation Extensions";
|
name = "Embed Foundation Extensions";
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
@@ -56,6 +76,10 @@
|
|||||||
1C0789412EBC218B00392B46 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
1C0789412EBC218B00392B46 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
|
||||||
1C0789612EBC2F5400392B46 /* CaseraExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CaseraExtension.entitlements; sourceTree = "<group>"; };
|
1C0789612EBC2F5400392B46 /* CaseraExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = CaseraExtension.entitlements; sourceTree = "<group>"; };
|
||||||
1C685CD22EC5539000A9669B /* CaseraTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CaseraTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
1C685CD22EC5539000A9669B /* CaseraTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CaseraTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
1C81F2692EE416EE000739EA /* CaseraQLPreview.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = CaseraQLPreview.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
1C81F26A2EE416EE000739EA /* QuickLook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLook.framework; path = System/Library/Frameworks/QuickLook.framework; sourceTree = SDKROOT; };
|
||||||
|
1C81F2802EE41BB6000739EA /* CaseraQLThumbnail.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = CaseraQLThumbnail.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
1C81F2812EE41BB6000739EA /* QuickLookThumbnailing.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLookThumbnailing.framework; path = System/Library/Frameworks/QuickLookThumbnailing.framework; sourceTree = SDKROOT; };
|
||||||
1C87A0C42EDB8ED40081E450 /* CaseraUITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = CaseraUITests.xctestplan; sourceTree = "<group>"; };
|
1C87A0C42EDB8ED40081E450 /* CaseraUITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = CaseraUITests.xctestplan; sourceTree = "<group>"; };
|
||||||
1CBF1BED2ECD9768001BF56C /* CaseraUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CaseraUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
1CBF1BED2ECD9768001BF56C /* CaseraUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CaseraUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
4B07E04F794A4C1CAA8CCD5D /* PhotoViewerSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoViewerSheet.swift; sourceTree = "<group>"; };
|
4B07E04F794A4C1CAA8CCD5D /* PhotoViewerSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoViewerSheet.swift; sourceTree = "<group>"; };
|
||||||
@@ -85,6 +109,20 @@
|
|||||||
);
|
);
|
||||||
target = 1CBF1BEC2ECD9768001BF56C /* CaseraUITests */;
|
target = 1CBF1BEC2ECD9768001BF56C /* CaseraUITests */;
|
||||||
};
|
};
|
||||||
|
1C81F27B2EE416EF000739EA /* Exceptions for "CaseraQLPreview" folder in "CaseraQLPreview" target */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||||
|
membershipExceptions = (
|
||||||
|
Info.plist,
|
||||||
|
);
|
||||||
|
target = 1C81F2682EE416EE000739EA /* CaseraQLPreview */;
|
||||||
|
};
|
||||||
|
1C81F28D2EE41BB6000739EA /* Exceptions for "CaseraQLThumbnail" folder in "CaseraQLThumbnail" target */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||||
|
membershipExceptions = (
|
||||||
|
Info.plist,
|
||||||
|
);
|
||||||
|
target = 1C81F27F2EE41BB6000739EA /* CaseraQLThumbnail */;
|
||||||
|
};
|
||||||
1C87A67A2EDCC3100081E450 /* Exceptions for "iosApp" folder in "CaseraExtension" target */ = {
|
1C87A67A2EDCC3100081E450 /* Exceptions for "iosApp" folder in "CaseraExtension" target */ = {
|
||||||
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
|
||||||
membershipExceptions = (
|
membershipExceptions = (
|
||||||
@@ -125,6 +163,22 @@
|
|||||||
path = CaseraTests;
|
path = CaseraTests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
1C81F26C2EE416EE000739EA /* CaseraQLPreview */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
|
exceptions = (
|
||||||
|
1C81F27B2EE416EF000739EA /* Exceptions for "CaseraQLPreview" folder in "CaseraQLPreview" target */,
|
||||||
|
);
|
||||||
|
path = CaseraQLPreview;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
1C81F2832EE41BB6000739EA /* CaseraQLThumbnail */ = {
|
||||||
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
|
exceptions = (
|
||||||
|
1C81F28D2EE41BB6000739EA /* Exceptions for "CaseraQLThumbnail" folder in "CaseraQLThumbnail" target */,
|
||||||
|
);
|
||||||
|
path = CaseraQLThumbnail;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
1CBF1BEE2ECD9768001BF56C /* CaseraUITests */ = {
|
1CBF1BEE2ECD9768001BF56C /* CaseraUITests */ = {
|
||||||
isa = PBXFileSystemSynchronizedRootGroup;
|
isa = PBXFileSystemSynchronizedRootGroup;
|
||||||
exceptions = (
|
exceptions = (
|
||||||
@@ -167,6 +221,22 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
1C81F2662EE416EE000739EA /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
1C81F26B2EE416EE000739EA /* QuickLook.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
1C81F27D2EE41BB6000739EA /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
1C81F2822EE41BB6000739EA /* QuickLookThumbnailing.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
1CBF1BEA2ECD9768001BF56C /* Frameworks */ = {
|
1CBF1BEA2ECD9768001BF56C /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -189,6 +259,8 @@
|
|||||||
children = (
|
children = (
|
||||||
1C07893F2EBC218B00392B46 /* WidgetKit.framework */,
|
1C07893F2EBC218B00392B46 /* WidgetKit.framework */,
|
||||||
1C0789412EBC218B00392B46 /* SwiftUI.framework */,
|
1C0789412EBC218B00392B46 /* SwiftUI.framework */,
|
||||||
|
1C81F26A2EE416EE000739EA /* QuickLook.framework */,
|
||||||
|
1C81F2812EE41BB6000739EA /* QuickLookThumbnailing.framework */,
|
||||||
);
|
);
|
||||||
name = Frameworks;
|
name = Frameworks;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -212,6 +284,8 @@
|
|||||||
1C0789432EBC218B00392B46 /* Casera */,
|
1C0789432EBC218B00392B46 /* Casera */,
|
||||||
1C685CD32EC5539000A9669B /* CaseraTests */,
|
1C685CD32EC5539000A9669B /* CaseraTests */,
|
||||||
1CBF1BEE2ECD9768001BF56C /* CaseraUITests */,
|
1CBF1BEE2ECD9768001BF56C /* CaseraUITests */,
|
||||||
|
1C81F26C2EE416EE000739EA /* CaseraQLPreview */,
|
||||||
|
1C81F2832EE41BB6000739EA /* CaseraQLThumbnail */,
|
||||||
1C07893E2EBC218B00392B46 /* Frameworks */,
|
1C07893E2EBC218B00392B46 /* Frameworks */,
|
||||||
FA6022B7B844191C54E57EB4 /* Products */,
|
FA6022B7B844191C54E57EB4 /* Products */,
|
||||||
1C078A1B2EC1820B00392B46 /* Recovered References */,
|
1C078A1B2EC1820B00392B46 /* Recovered References */,
|
||||||
@@ -225,6 +299,8 @@
|
|||||||
1C07893D2EBC218B00392B46 /* CaseraExtension.appex */,
|
1C07893D2EBC218B00392B46 /* CaseraExtension.appex */,
|
||||||
1C685CD22EC5539000A9669B /* CaseraTests.xctest */,
|
1C685CD22EC5539000A9669B /* CaseraTests.xctest */,
|
||||||
1CBF1BED2ECD9768001BF56C /* CaseraUITests.xctest */,
|
1CBF1BED2ECD9768001BF56C /* CaseraUITests.xctest */,
|
||||||
|
1C81F2692EE416EE000739EA /* CaseraQLPreview.appex */,
|
||||||
|
1C81F2802EE41BB6000739EA /* CaseraQLThumbnail.appex */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -277,6 +353,50 @@
|
|||||||
productReference = 1C685CD22EC5539000A9669B /* CaseraTests.xctest */;
|
productReference = 1C685CD22EC5539000A9669B /* CaseraTests.xctest */;
|
||||||
productType = "com.apple.product-type.bundle.unit-test";
|
productType = "com.apple.product-type.bundle.unit-test";
|
||||||
};
|
};
|
||||||
|
1C81F2682EE416EE000739EA /* CaseraQLPreview */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 1C81F2782EE416EF000739EA /* Build configuration list for PBXNativeTarget "CaseraQLPreview" */;
|
||||||
|
buildPhases = (
|
||||||
|
1C81F2652EE416EE000739EA /* Sources */,
|
||||||
|
1C81F2662EE416EE000739EA /* Frameworks */,
|
||||||
|
1C81F2672EE416EE000739EA /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
fileSystemSynchronizedGroups = (
|
||||||
|
1C81F26C2EE416EE000739EA /* CaseraQLPreview */,
|
||||||
|
);
|
||||||
|
name = CaseraQLPreview;
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = CaseraQLPreview;
|
||||||
|
productReference = 1C81F2692EE416EE000739EA /* CaseraQLPreview.appex */;
|
||||||
|
productType = "com.apple.product-type.app-extension";
|
||||||
|
};
|
||||||
|
1C81F27F2EE41BB6000739EA /* CaseraQLThumbnail */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 1C81F28A2EE41BB6000739EA /* Build configuration list for PBXNativeTarget "CaseraQLThumbnail" */;
|
||||||
|
buildPhases = (
|
||||||
|
1C81F27C2EE41BB6000739EA /* Sources */,
|
||||||
|
1C81F27D2EE41BB6000739EA /* Frameworks */,
|
||||||
|
1C81F27E2EE41BB6000739EA /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
);
|
||||||
|
fileSystemSynchronizedGroups = (
|
||||||
|
1C81F2832EE41BB6000739EA /* CaseraQLThumbnail */,
|
||||||
|
);
|
||||||
|
name = CaseraQLThumbnail;
|
||||||
|
packageProductDependencies = (
|
||||||
|
);
|
||||||
|
productName = CaseraQLThumbnail;
|
||||||
|
productReference = 1C81F2802EE41BB6000739EA /* CaseraQLThumbnail.appex */;
|
||||||
|
productType = "com.apple.product-type.app-extension";
|
||||||
|
};
|
||||||
1CBF1BEC2ECD9768001BF56C /* CaseraUITests */ = {
|
1CBF1BEC2ECD9768001BF56C /* CaseraUITests */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 1CBF1BF52ECD9768001BF56C /* Build configuration list for PBXNativeTarget "CaseraUITests" */;
|
buildConfigurationList = 1CBF1BF52ECD9768001BF56C /* Build configuration list for PBXNativeTarget "CaseraUITests" */;
|
||||||
@@ -314,6 +434,8 @@
|
|||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
1C0789522EBC218D00392B46 /* PBXTargetDependency */,
|
1C0789522EBC218D00392B46 /* PBXTargetDependency */,
|
||||||
|
1C81F2762EE416EF000739EA /* PBXTargetDependency */,
|
||||||
|
1C81F2882EE41BB6000739EA /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
fileSystemSynchronizedGroups = (
|
fileSystemSynchronizedGroups = (
|
||||||
E822E6B231E7783DE992578C /* iosApp */,
|
E822E6B231E7783DE992578C /* iosApp */,
|
||||||
@@ -342,6 +464,12 @@
|
|||||||
CreatedOnToolsVersion = 26.1.1;
|
CreatedOnToolsVersion = 26.1.1;
|
||||||
TestTargetID = D4ADB376A7A4CFB73469E173;
|
TestTargetID = D4ADB376A7A4CFB73469E173;
|
||||||
};
|
};
|
||||||
|
1C81F2682EE416EE000739EA = {
|
||||||
|
CreatedOnToolsVersion = 26.1.1;
|
||||||
|
};
|
||||||
|
1C81F27F2EE41BB6000739EA = {
|
||||||
|
CreatedOnToolsVersion = 26.1.1;
|
||||||
|
};
|
||||||
1CBF1BEC2ECD9768001BF56C = {
|
1CBF1BEC2ECD9768001BF56C = {
|
||||||
CreatedOnToolsVersion = 26.1.1;
|
CreatedOnToolsVersion = 26.1.1;
|
||||||
TestTargetID = D4ADB376A7A4CFB73469E173;
|
TestTargetID = D4ADB376A7A4CFB73469E173;
|
||||||
@@ -369,6 +497,8 @@
|
|||||||
1C07893C2EBC218B00392B46 /* CaseraExtension */,
|
1C07893C2EBC218B00392B46 /* CaseraExtension */,
|
||||||
1C685CD12EC5539000A9669B /* CaseraTests */,
|
1C685CD12EC5539000A9669B /* CaseraTests */,
|
||||||
1CBF1BEC2ECD9768001BF56C /* CaseraUITests */,
|
1CBF1BEC2ECD9768001BF56C /* CaseraUITests */,
|
||||||
|
1C81F2682EE416EE000739EA /* CaseraQLPreview */,
|
||||||
|
1C81F27F2EE41BB6000739EA /* CaseraQLThumbnail */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
@@ -388,6 +518,20 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
1C81F2672EE416EE000739EA /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
1C81F27E2EE41BB6000739EA /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
1CBF1BEB2ECD9768001BF56C /* Resources */ = {
|
1CBF1BEB2ECD9768001BF56C /* Resources */ = {
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -441,6 +585,20 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
1C81F2652EE416EE000739EA /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
1C81F27C2EE41BB6000739EA /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
1CBF1BE92ECD9768001BF56C /* Sources */ = {
|
1CBF1BE92ECD9768001BF56C /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -463,6 +621,16 @@
|
|||||||
target = 1C07893C2EBC218B00392B46 /* CaseraExtension */;
|
target = 1C07893C2EBC218B00392B46 /* CaseraExtension */;
|
||||||
targetProxy = 1C0789512EBC218D00392B46 /* PBXContainerItemProxy */;
|
targetProxy = 1C0789512EBC218D00392B46 /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
|
1C81F2762EE416EF000739EA /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 1C81F2682EE416EE000739EA /* CaseraQLPreview */;
|
||||||
|
targetProxy = 1C81F2752EE416EF000739EA /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
|
1C81F2882EE41BB6000739EA /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
target = 1C81F27F2EE41BB6000739EA /* CaseraQLThumbnail */;
|
||||||
|
targetProxy = 1C81F2872EE41BB6000739EA /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
1CBF16012ECD8AE4001BF56C /* PBXTargetDependency */ = {
|
1CBF16012ECD8AE4001BF56C /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
target = D4ADB376A7A4CFB73469E173 /* Casera */;
|
target = D4ADB376A7A4CFB73469E173 /* Casera */;
|
||||||
@@ -622,6 +790,130 @@
|
|||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
1C81F2792EE416EF000739EA /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = V3PF3M6B6U;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = CaseraQLPreview/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = CaseraQLPreview;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 26.1;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.tt.casera.CaseraDev.CaseraQLPreview;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
1C81F27A2EE416EF000739EA /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = V3PF3M6B6U;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = CaseraQLPreview/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = CaseraQLPreview;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 26.1;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.tt.casera.CaseraDev.CaseraQLPreview;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
|
1C81F28B2EE41BB6000739EA /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = V3PF3M6B6U;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = CaseraQLThumbnail/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = CaseraQLThumbnail;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 26.1;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.tt.casera.CaseraDev.CaseraQLThumbnail;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
1C81F28C2EE41BB6000739EA /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
CODE_SIGN_IDENTITY = "Apple Development";
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEVELOPMENT_TEAM = V3PF3M6B6U;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = CaseraQLThumbnail/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = CaseraQLThumbnail;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 26.1;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = com.tt.casera.CaseraDev.CaseraQLThumbnail;
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
STRING_CATALOG_GENERATE_SYMBOLS = YES;
|
||||||
|
SWIFT_APPROACHABLE_CONCURRENCY = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
1CBF1BF62ECD9768001BF56C /* Debug */ = {
|
1CBF1BF62ECD9768001BF56C /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
@@ -852,6 +1144,24 @@
|
|||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
|
1C81F2782EE416EF000739EA /* Build configuration list for PBXNativeTarget "CaseraQLPreview" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
1C81F2792EE416EF000739EA /* Debug */,
|
||||||
|
1C81F27A2EE416EF000739EA /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
|
1C81F28A2EE41BB6000739EA /* Build configuration list for PBXNativeTarget "CaseraQLThumbnail" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
1C81F28B2EE41BB6000739EA /* Debug */,
|
||||||
|
1C81F28C2EE41BB6000739EA /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
1CBF1BF52ECD9768001BF56C /* Build configuration list for PBXNativeTarget "CaseraUITests" */ = {
|
1CBF1BF52ECD9768001BF56C /* Build configuration list for PBXNativeTarget "CaseraUITests" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
|
|||||||
@@ -39,6 +39,8 @@
|
|||||||
<array>
|
<array>
|
||||||
<string>remote-notification</string>
|
<string>remote-notification</string>
|
||||||
</array>
|
</array>
|
||||||
|
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||||
|
<false/>
|
||||||
<key>CFBundleDocumentTypes</key>
|
<key>CFBundleDocumentTypes</key>
|
||||||
<array>
|
<array>
|
||||||
<dict>
|
<dict>
|
||||||
@@ -63,9 +65,11 @@
|
|||||||
<string>Casera Contractor</string>
|
<string>Casera Contractor</string>
|
||||||
<key>UTTypeConformsTo</key>
|
<key>UTTypeConformsTo</key>
|
||||||
<array>
|
<array>
|
||||||
<string>public.json</string>
|
|
||||||
<string>public.data</string>
|
<string>public.data</string>
|
||||||
|
<string>public.content</string>
|
||||||
</array>
|
</array>
|
||||||
|
<key>UTTypeIconFiles</key>
|
||||||
|
<array/>
|
||||||
<key>UTTypeTagSpecification</key>
|
<key>UTTypeTagSpecification</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>public.filename-extension</key>
|
<key>public.filename-extension</key>
|
||||||
@@ -73,7 +77,7 @@
|
|||||||
<string>casera</string>
|
<string>casera</string>
|
||||||
</array>
|
</array>
|
||||||
<key>public.mime-type</key>
|
<key>public.mime-type</key>
|
||||||
<string>application/json</string>
|
<string>application/x-casera</string>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</array>
|
</array>
|
||||||
|
|||||||
Reference in New Issue
Block a user