54 lines
2.0 KiB
Swift
54 lines
2.0 KiB
Swift
import Foundation
|
|
|
|
/// Represents a shared card fetched from CloudKit for display in the App Clip.
|
|
struct SharedCardSnapshot: Sendable {
|
|
let recordName: String
|
|
let vCardData: String
|
|
let displayName: String
|
|
let role: String
|
|
let company: String
|
|
let photoData: Data?
|
|
|
|
init(
|
|
recordName: String,
|
|
vCardData: String,
|
|
displayName: String? = nil,
|
|
role: String? = nil,
|
|
company: String? = nil,
|
|
photoData: Data? = nil
|
|
) {
|
|
self.recordName = recordName
|
|
self.vCardData = vCardData
|
|
|
|
// Parse display fields from vCard
|
|
let lines = vCardData.components(separatedBy: .newlines)
|
|
let parsedDisplayName = Self.parseField("FN:", from: lines) ?? "Contact"
|
|
let parsedRole = Self.parseField("TITLE:", from: lines) ?? ""
|
|
let parsedCompany = Self.parseField("ORG:", from: lines)?
|
|
.components(separatedBy: ";").first ?? ""
|
|
let parsedPhotoData = Self.parsePhoto(from: lines)
|
|
|
|
let cleanedDisplayName = displayName?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
|
self.displayName = cleanedDisplayName.isEmpty ? parsedDisplayName : cleanedDisplayName
|
|
self.role = role ?? parsedRole
|
|
self.company = company ?? parsedCompany
|
|
self.photoData = photoData ?? parsedPhotoData
|
|
}
|
|
|
|
private static func parseField(_ prefix: String, from lines: [String]) -> String? {
|
|
lines.first { $0.hasPrefix(prefix) }?
|
|
.dropFirst(prefix.count)
|
|
.trimmingCharacters(in: .whitespaces)
|
|
}
|
|
|
|
private static func parsePhoto(from lines: [String]) -> Data? {
|
|
// Find line that starts with PHOTO; and contains base64 data
|
|
guard let photoLine = lines.first(where: { $0.hasPrefix("PHOTO;") }),
|
|
let base64Start = photoLine.range(of: ":")?.upperBound else {
|
|
return nil
|
|
}
|
|
let base64String = String(photoLine[base64Start...])
|
|
return Data(base64Encoded: base64String)
|
|
}
|
|
}
|