|
|
import SwiftUI
|
|
|
import CoreData
|
|
|
import CoreImage
|
|
|
|
|
|
// MARK: - 二维码创建界面
|
|
|
struct CreateQRCodeView: View {
|
|
|
@Environment(\.dismiss) private var dismiss
|
|
|
@StateObject private var coreDataManager = CoreDataManager.shared
|
|
|
|
|
|
// 从类型选择界面传入的参数
|
|
|
let selectedQRCodeType: QRCodeType
|
|
|
|
|
|
// 通用内容输入
|
|
|
@State private var content = ""
|
|
|
@FocusState private var isContentFieldFocused: Bool
|
|
|
|
|
|
// Email相关字段
|
|
|
@State private var emailAddress = ""
|
|
|
@State private var emailSubject = ""
|
|
|
@State private var emailBody = ""
|
|
|
@State private var emailCc = ""
|
|
|
@State private var emailBcc = ""
|
|
|
@FocusState private var focusedEmailField: EmailInputView.EmailField?
|
|
|
|
|
|
// WiFi相关字段
|
|
|
@State private var wifiSSID = ""
|
|
|
@State private var wifiPassword = ""
|
|
|
@State private var wifiEncryptionType: WiFiInputView.WiFiEncryptionType = .wpa2
|
|
|
@FocusState private var focusedWiFiField: WiFiInputView.WiFiField?
|
|
|
|
|
|
// 联系人相关字段
|
|
|
@State private var contactFirstName = ""
|
|
|
@State private var contactLastName = ""
|
|
|
@State private var contactPhone = ""
|
|
|
@State private var contactEmail = ""
|
|
|
@State private var contactCompany = ""
|
|
|
@State private var contactTitle = ""
|
|
|
@State private var contactAddress = ""
|
|
|
@State private var contactWebsite = ""
|
|
|
@State private var contactNickname = ""
|
|
|
@State private var contactBirthday = Date()
|
|
|
@State private var contactNote = ""
|
|
|
@FocusState private var focusedContactField: ContactInputView.ContactField?
|
|
|
|
|
|
// 位置相关字段
|
|
|
@State private var locationLatitude = ""
|
|
|
@State private var locationLongitude = ""
|
|
|
@State private var locationName = ""
|
|
|
@FocusState private var focusedLocationField: LocationInputView.LocationField?
|
|
|
|
|
|
// 日历相关字段
|
|
|
@State private var eventTitle = ""
|
|
|
@State private var eventDescription = ""
|
|
|
@State private var eventLocation = ""
|
|
|
@State private var startDate = Date()
|
|
|
@State private var endDate = Date().addingTimeInterval(3600)
|
|
|
@FocusState private var focusedCalendarField: CalendarInputView.CalendarField?
|
|
|
|
|
|
// 社交平台相关字段
|
|
|
@State private var socialUsername = ""
|
|
|
@State private var socialMessage = ""
|
|
|
@FocusState private var focusedSocialField: SocialInputView.SocialField?
|
|
|
|
|
|
// 电话相关字段
|
|
|
@State private var phoneNumber = ""
|
|
|
@State private var phoneMessage = ""
|
|
|
@FocusState private var focusedPhoneField: PhoneInputView.PhoneField?
|
|
|
|
|
|
// URL相关字段
|
|
|
@State private var urlString = ""
|
|
|
@FocusState private var isURLFieldFocused: Bool
|
|
|
|
|
|
// 通用状态
|
|
|
@State private var showingAlert = false
|
|
|
@State private var alertMessage = ""
|
|
|
|
|
|
var body: some View {
|
|
|
VStack(spacing: 0) {
|
|
|
inputAndPreviewSection
|
|
|
}
|
|
|
.navigationTitle(selectedQRCodeType.displayName)
|
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
|
.toolbar {
|
|
|
ToolbarItem(placement: .navigationBarTrailing) {
|
|
|
Button("创建") { createQRCode() }
|
|
|
.disabled(!canCreateQRCode())
|
|
|
.font(.system(size: 16, weight: .semibold))
|
|
|
}
|
|
|
}
|
|
|
.alert("提示", isPresented: $showingAlert) {
|
|
|
Button("确定") { }
|
|
|
} message: { Text(alertMessage) }
|
|
|
.onAppear {
|
|
|
setupInitialFocus()
|
|
|
}
|
|
|
.onTapGesture {
|
|
|
hideKeyboard()
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// MARK: - UI Components
|
|
|
|
|
|
private var inputAndPreviewSection: some View {
|
|
|
ScrollView {
|
|
|
VStack(spacing: 24) {
|
|
|
// 内容输入区域
|
|
|
VStack(spacing: 16) {
|
|
|
// 使用InputComponentFactory动态选择输入组件
|
|
|
createInputComponentForType()
|
|
|
.padding(.horizontal, 20)
|
|
|
}
|
|
|
|
|
|
// 预览区域
|
|
|
#if DEBUG
|
|
|
if canCreateQRCode() {
|
|
|
VStack(spacing: 16) {
|
|
|
|
|
|
|
|
|
// 使用QRCodePreviewView组件
|
|
|
QRCodePreviewView(
|
|
|
qrCodeImage: generateQRCodeImage(),
|
|
|
formattedContent: formatContentForQRCodeType(),
|
|
|
qrCodeType: selectedQRCodeType
|
|
|
)
|
|
|
.padding(.horizontal, 20)
|
|
|
}
|
|
|
}
|
|
|
Spacer(minLength: 100)
|
|
|
#endif
|
|
|
}
|
|
|
.padding(.top, 20)
|
|
|
}
|
|
|
.background(Color(.systemGroupedBackground))
|
|
|
}
|
|
|
|
|
|
// MARK: - Helper Methods
|
|
|
|
|
|
private func createInputComponentForType() -> AnyView {
|
|
|
switch selectedQRCodeType {
|
|
|
case .mail:
|
|
|
let emailConfig = EmailInputConfig(
|
|
|
emailAddress: $emailAddress,
|
|
|
emailSubject: $emailSubject,
|
|
|
emailBody: $emailBody,
|
|
|
emailCc: $emailCc,
|
|
|
emailBcc: $emailBcc
|
|
|
)
|
|
|
return InputComponentFactory.createInputComponent(
|
|
|
for: selectedQRCodeType,
|
|
|
emailConfig: emailConfig
|
|
|
)
|
|
|
|
|
|
case .wifi:
|
|
|
let wifiConfig = WiFiInputConfig(
|
|
|
ssid: $wifiSSID,
|
|
|
password: $wifiPassword,
|
|
|
encryptionType: $wifiEncryptionType
|
|
|
)
|
|
|
return InputComponentFactory.createInputComponent(
|
|
|
for: selectedQRCodeType,
|
|
|
wifiConfig: wifiConfig
|
|
|
)
|
|
|
|
|
|
case .vcard, .mecard:
|
|
|
let contactConfig = ContactInputConfig(
|
|
|
firstName: $contactFirstName,
|
|
|
lastName: $contactLastName,
|
|
|
phone: $contactPhone,
|
|
|
email: $contactEmail,
|
|
|
company: $contactCompany,
|
|
|
title: $contactTitle,
|
|
|
address: $contactAddress,
|
|
|
website: $contactWebsite,
|
|
|
nickname: $contactNickname,
|
|
|
birthday: $contactBirthday,
|
|
|
note: $contactNote
|
|
|
)
|
|
|
return InputComponentFactory.createInputComponent(
|
|
|
for: selectedQRCodeType,
|
|
|
contactConfig: contactConfig
|
|
|
)
|
|
|
|
|
|
case .location:
|
|
|
let locationConfig = LocationInputConfig(
|
|
|
latitude: $locationLatitude,
|
|
|
longitude: $locationLongitude,
|
|
|
locationName: $locationName
|
|
|
)
|
|
|
return InputComponentFactory.createInputComponent(
|
|
|
for: selectedQRCodeType,
|
|
|
locationConfig: locationConfig
|
|
|
)
|
|
|
|
|
|
case .calendar:
|
|
|
let calendarConfig = CalendarInputConfig(
|
|
|
eventTitle: $eventTitle,
|
|
|
eventDescription: $eventDescription,
|
|
|
startDate: $startDate,
|
|
|
endDate: $endDate,
|
|
|
location: $eventLocation
|
|
|
)
|
|
|
return InputComponentFactory.createInputComponent(
|
|
|
for: selectedQRCodeType,
|
|
|
calendarConfig: calendarConfig
|
|
|
)
|
|
|
|
|
|
case .instagram, .facebook, .spotify, .twitter, .snapchat, .tiktok, .whatsapp, .viber:
|
|
|
let socialConfig = SocialInputConfig(
|
|
|
username: $socialUsername,
|
|
|
message: $socialMessage
|
|
|
)
|
|
|
return InputComponentFactory.createInputComponent(
|
|
|
for: selectedQRCodeType,
|
|
|
socialConfig: socialConfig
|
|
|
)
|
|
|
|
|
|
case .phone, .sms:
|
|
|
let phoneConfig = PhoneInputConfig(
|
|
|
phoneNumber: $phoneNumber,
|
|
|
phoneMessage: $phoneMessage
|
|
|
)
|
|
|
return InputComponentFactory.createInputComponent(
|
|
|
for: selectedQRCodeType,
|
|
|
phoneConfig: phoneConfig
|
|
|
)
|
|
|
|
|
|
case .url:
|
|
|
let urlConfig = URLInputConfig(
|
|
|
url: $urlString
|
|
|
)
|
|
|
return InputComponentFactory.createInputComponent(
|
|
|
for: selectedQRCodeType,
|
|
|
urlConfig: urlConfig
|
|
|
)
|
|
|
|
|
|
default:
|
|
|
let textConfig = TextInputConfig(
|
|
|
content: $content
|
|
|
)
|
|
|
return InputComponentFactory.createInputComponent(
|
|
|
for: selectedQRCodeType,
|
|
|
textConfig: textConfig
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private func setupInitialFocus() {
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
|
|
switch selectedQRCodeType {
|
|
|
case .mail:
|
|
|
focusedEmailField = .address
|
|
|
case .wifi:
|
|
|
focusedWiFiField = .ssid
|
|
|
case .vcard, .mecard:
|
|
|
focusedContactField = .firstName
|
|
|
case .location:
|
|
|
focusedLocationField = .latitude
|
|
|
case .calendar:
|
|
|
focusedCalendarField = .title
|
|
|
case .instagram, .facebook, .spotify, .twitter, .snapchat, .tiktok:
|
|
|
focusedSocialField = .username
|
|
|
case .phone, .sms:
|
|
|
focusedPhoneField = .phoneNumber
|
|
|
case .url:
|
|
|
isURLFieldFocused = true
|
|
|
default:
|
|
|
isContentFieldFocused = true
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private func hideKeyboard() {
|
|
|
switch selectedQRCodeType {
|
|
|
case .mail:
|
|
|
focusedEmailField = nil
|
|
|
case .wifi:
|
|
|
focusedWiFiField = nil
|
|
|
case .vcard, .mecard:
|
|
|
focusedContactField = nil
|
|
|
case .location:
|
|
|
focusedLocationField = nil
|
|
|
case .calendar:
|
|
|
focusedCalendarField = nil
|
|
|
case .instagram, .facebook, .spotify, .twitter, .snapchat, .tiktok:
|
|
|
focusedSocialField = nil
|
|
|
case .phone, .sms:
|
|
|
focusedPhoneField = nil
|
|
|
case .url:
|
|
|
isURLFieldFocused = false
|
|
|
default:
|
|
|
isContentFieldFocused = false
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private func getInputIcon() -> String {
|
|
|
switch selectedQRCodeType {
|
|
|
case .mail: return "envelope"
|
|
|
case .wifi: return "wifi"
|
|
|
case .vcard, .mecard: return "person"
|
|
|
case .location: return "location"
|
|
|
case .calendar: return "calendar"
|
|
|
case .instagram, .facebook, .spotify, .twitter, .snapchat, .tiktok, .whatsapp, .viber: return "globe"
|
|
|
case .phone, .sms: return "phone"
|
|
|
case .url: return "link"
|
|
|
default: return "textformat"
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private func canCreateQRCode() -> Bool {
|
|
|
switch selectedQRCodeType {
|
|
|
case .mail:
|
|
|
return !emailAddress.isEmpty && !emailSubject.isEmpty && !emailBody.isEmpty
|
|
|
case .wifi:
|
|
|
return !wifiSSID.isEmpty
|
|
|
case .vcard, .mecard:
|
|
|
return !contactFirstName.isEmpty || !contactLastName.isEmpty
|
|
|
case .location:
|
|
|
return !locationLatitude.isEmpty && !locationLongitude.isEmpty
|
|
|
case .calendar:
|
|
|
return !eventTitle.isEmpty
|
|
|
case .instagram, .facebook, .spotify, .twitter, .snapchat, .tiktok, .whatsapp, .viber:
|
|
|
return !socialUsername.isEmpty
|
|
|
case .phone, .sms:
|
|
|
return !phoneNumber.isEmpty
|
|
|
case .url:
|
|
|
return !urlString.isEmpty
|
|
|
default:
|
|
|
return !content.isEmpty
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private func getContentHint() -> String {
|
|
|
InputComponentFactory.getPlaceholderText(for: selectedQRCodeType)
|
|
|
}
|
|
|
|
|
|
private func generateQRCodeImage() -> UIImage? {
|
|
|
guard canCreateQRCode() else { return nil }
|
|
|
|
|
|
let formattedContent = formatContentForQRCodeType()
|
|
|
let data = formattedContent.data(using: .utf8)
|
|
|
let qrFilter = CIFilter.qrCodeGenerator()
|
|
|
qrFilter.setValue(data, forKey: "inputMessage")
|
|
|
qrFilter.setValue("H", forKey: "inputCorrectionLevel")
|
|
|
|
|
|
guard let outputImage = qrFilter.outputImage else { return nil }
|
|
|
|
|
|
let context = CIContext()
|
|
|
guard let cgImage = context.createCGImage(outputImage, from: outputImage.extent) else { return nil }
|
|
|
|
|
|
return UIImage(cgImage: cgImage)
|
|
|
}
|
|
|
|
|
|
private func formatContentForQRCodeType() -> String {
|
|
|
switch selectedQRCodeType {
|
|
|
case .text:
|
|
|
return content
|
|
|
case .url:
|
|
|
return urlString.hasPrefix("http") ? urlString : "https://\(urlString)"
|
|
|
case .mail:
|
|
|
var mailtoURL = "mailto:\(emailAddress)"
|
|
|
var queryParams: [String] = []
|
|
|
|
|
|
if !emailSubject.isEmpty {
|
|
|
queryParams.append("subject=\(emailSubject.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? emailSubject)")
|
|
|
}
|
|
|
|
|
|
if !emailBody.isEmpty {
|
|
|
queryParams.append("body=\(emailBody.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? emailBody)")
|
|
|
}
|
|
|
|
|
|
if !emailCc.isEmpty {
|
|
|
queryParams.append("cc=\(emailCc)")
|
|
|
}
|
|
|
|
|
|
if !emailBcc.isEmpty {
|
|
|
queryParams.append("bcc=\(emailBcc)")
|
|
|
}
|
|
|
|
|
|
if !queryParams.isEmpty {
|
|
|
mailtoURL += "?" + queryParams.joined(separator: "&")
|
|
|
}
|
|
|
|
|
|
return mailtoURL
|
|
|
case .phone:
|
|
|
return "tel:\(phoneNumber)"
|
|
|
case .sms:
|
|
|
let smsContent = phoneMessage.isEmpty ? "Hello" : phoneMessage
|
|
|
return "SMSTO:\(phoneNumber):\(smsContent)"
|
|
|
case .wifi:
|
|
|
return "WIFI:T:\(wifiEncryptionType.rawValue);S:\(wifiSSID);P:\(wifiPassword);;"
|
|
|
case .vcard:
|
|
|
var vcard = "BEGIN:VCARD\nVERSION:3.0\n"
|
|
|
|
|
|
// 姓名字段 (N和FN)
|
|
|
if !contactFirstName.isEmpty || !contactLastName.isEmpty {
|
|
|
let lastName = contactLastName.isEmpty ? "" : contactLastName
|
|
|
let firstName = contactFirstName.isEmpty ? "" : contactFirstName
|
|
|
vcard += "N:\(lastName);\(firstName);;;\n"
|
|
|
vcard += "FN:\(firstName) \(lastName)\n"
|
|
|
}
|
|
|
|
|
|
// 电话字段
|
|
|
if !contactPhone.isEmpty {
|
|
|
vcard += "TEL;TYPE=WORK,CELL:\(contactPhone)\n"
|
|
|
}
|
|
|
|
|
|
// 邮箱字段
|
|
|
if !contactEmail.isEmpty {
|
|
|
vcard += "EMAIL;TYPE=PREF,INTERNET:\(contactEmail)\n"
|
|
|
}
|
|
|
|
|
|
// 公司字段
|
|
|
if !contactCompany.isEmpty {
|
|
|
vcard += "ORG:\(contactCompany)\n"
|
|
|
}
|
|
|
|
|
|
// 职位字段
|
|
|
if !contactTitle.isEmpty {
|
|
|
vcard += "TITLE:\(contactTitle)\n"
|
|
|
}
|
|
|
|
|
|
// 地址字段
|
|
|
if !contactAddress.isEmpty {
|
|
|
vcard += "ADR;TYPE=WORK:;;\(contactAddress);;;;\n"
|
|
|
}
|
|
|
|
|
|
// 网站字段
|
|
|
if !contactWebsite.isEmpty {
|
|
|
vcard += "URL:\(contactWebsite)\n"
|
|
|
}
|
|
|
|
|
|
vcard += "END:VCARD"
|
|
|
return vcard
|
|
|
case .mecard:
|
|
|
var mecard = "MECARD:"
|
|
|
|
|
|
// 姓名字段
|
|
|
if !contactFirstName.isEmpty || !contactLastName.isEmpty {
|
|
|
let lastName = contactLastName.isEmpty ? "" : contactLastName
|
|
|
let firstName = contactFirstName.isEmpty ? "" : contactFirstName
|
|
|
mecard += "N:\(lastName),\(firstName);"
|
|
|
}
|
|
|
|
|
|
// 昵称字段
|
|
|
if !contactNickname.isEmpty {
|
|
|
mecard += "NICKNAME:\(contactNickname);"
|
|
|
}
|
|
|
|
|
|
// 电话字段
|
|
|
if !contactPhone.isEmpty {
|
|
|
mecard += "TEL:\(contactPhone);"
|
|
|
}
|
|
|
|
|
|
// 邮箱字段
|
|
|
if !contactEmail.isEmpty {
|
|
|
mecard += "EMAIL:\(contactEmail);"
|
|
|
}
|
|
|
|
|
|
// 公司字段
|
|
|
if !contactCompany.isEmpty {
|
|
|
mecard += "ORG:\(contactCompany);"
|
|
|
}
|
|
|
|
|
|
// 地址字段
|
|
|
if !contactAddress.isEmpty {
|
|
|
mecard += "ADR:\(contactAddress);"
|
|
|
}
|
|
|
|
|
|
// 网站字段
|
|
|
if !contactWebsite.isEmpty {
|
|
|
mecard += "URL:\(contactWebsite);"
|
|
|
}
|
|
|
|
|
|
// 生日字段
|
|
|
let dateFormatter = DateFormatter()
|
|
|
dateFormatter.dateFormat = "yyyyMMdd"
|
|
|
let birthdayString = dateFormatter.string(from: contactBirthday)
|
|
|
mecard += "BDAY:\(birthdayString);"
|
|
|
|
|
|
// 备注字段
|
|
|
if !contactNote.isEmpty {
|
|
|
mecard += "NOTE:\(contactNote);"
|
|
|
}
|
|
|
|
|
|
mecard += ";"
|
|
|
return mecard
|
|
|
case .location:
|
|
|
let coords = "\(locationLatitude),\(locationLongitude)"
|
|
|
return locationName.isEmpty ? "geo:\(coords)" : "geo:\(coords)?q=\(locationName)"
|
|
|
case .calendar:
|
|
|
let dateFormatter = DateFormatter()
|
|
|
dateFormatter.dateFormat = "yyyyMMdd'T'HHmmss'Z'"
|
|
|
dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
|
|
|
|
|
|
var ical = "BEGIN:VEVENT\n"
|
|
|
ical += "SUMMARY:\(eventTitle)\n"
|
|
|
if !eventDescription.isEmpty {
|
|
|
ical += "DESCRIPTION:\(eventDescription)\n"
|
|
|
}
|
|
|
if !eventLocation.isEmpty {
|
|
|
ical += "LOCATION:\(eventLocation)\n"
|
|
|
}
|
|
|
ical += "DTSTART:\(dateFormatter.string(from: startDate))\n"
|
|
|
ical += "DTEND:\(dateFormatter.string(from: endDate))\n"
|
|
|
ical += "END:VEVENT"
|
|
|
return ical
|
|
|
case .instagram:
|
|
|
return "instagram://user?username=\(socialUsername)"
|
|
|
case .facebook:
|
|
|
// 处理Facebook输入:支持用户名/ID或完整链接
|
|
|
let facebookId = extractFacebookId(from: socialUsername)
|
|
|
return "fb://profile/\(facebookId)"
|
|
|
case .spotify:
|
|
|
return "https://open.spotify.com/track/\(socialUsername)"
|
|
|
case .twitter:
|
|
|
return "twitter://user?screen_name=\(socialUsername)"
|
|
|
case .whatsapp:
|
|
|
return "whatsapp://send?phone=\(socialUsername)"
|
|
|
case .viber:
|
|
|
return "viber://add?number=\(socialUsername)"
|
|
|
case .snapchat:
|
|
|
return "https://snapchat.com/add/\(socialUsername)"
|
|
|
case .tiktok:
|
|
|
return "https://www.tiktok.com/@\(socialUsername)"
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// MARK: - 生成社交媒体内容
|
|
|
private func generateSocialMediaContent() -> String {
|
|
|
switch selectedQRCodeType {
|
|
|
case .instagram:
|
|
|
return "instagram://user?username=\(socialUsername)"
|
|
|
case .facebook:
|
|
|
// 处理Facebook输入:支持用户名/ID或完整链接
|
|
|
let facebookId = extractFacebookId(from: socialUsername)
|
|
|
return "fb://profile/\(facebookId)"
|
|
|
case .spotify:
|
|
|
return "https://open.spotify.com/track/\(socialUsername)"
|
|
|
case .twitter:
|
|
|
return "twitter://user?screen_name=\(socialUsername)"
|
|
|
case .whatsapp:
|
|
|
return "whatsapp://send?phone=\(socialUsername)"
|
|
|
case .viber:
|
|
|
return "viber://add?number=\(socialUsername)"
|
|
|
case .snapchat:
|
|
|
return "https://snapchat.com/add/\(socialUsername)"
|
|
|
case .tiktok:
|
|
|
return "https://www.tiktok.com/@\(socialUsername)"
|
|
|
default:
|
|
|
return socialUsername
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private func createQRCode() {
|
|
|
let context = coreDataManager.container.viewContext
|
|
|
let historyItem = HistoryItem(context: context)
|
|
|
historyItem.id = UUID()
|
|
|
historyItem.dataType = DataType.qrcode.rawValue
|
|
|
historyItem.dataSource = DataSource.created.rawValue
|
|
|
historyItem.createdAt = Date()
|
|
|
historyItem.isFavorite = false
|
|
|
historyItem.qrCodeType = selectedQRCodeType.rawValue
|
|
|
|
|
|
// 根据类型设置内容
|
|
|
switch selectedQRCodeType {
|
|
|
case .mail:
|
|
|
var mailContent = "邮箱: \(emailAddress)\n主题: \(emailSubject)\n正文: \(emailBody)"
|
|
|
if !emailCc.isEmpty {
|
|
|
mailContent += "\n抄送: \(emailCc)"
|
|
|
}
|
|
|
if !emailBcc.isEmpty {
|
|
|
mailContent += "\n密送: \(emailBcc)"
|
|
|
}
|
|
|
historyItem.content = mailContent
|
|
|
case .wifi:
|
|
|
historyItem.content = "WiFi: \(wifiSSID) (\(wifiEncryptionType.displayName))"
|
|
|
case .vcard, .mecard:
|
|
|
var contactContent = "联系人: "
|
|
|
if !contactFirstName.isEmpty || !contactLastName.isEmpty {
|
|
|
contactContent += "\(contactFirstName) \(contactLastName)"
|
|
|
}
|
|
|
if !contactNickname.isEmpty {
|
|
|
contactContent += " (\(contactNickname))"
|
|
|
}
|
|
|
if !contactPhone.isEmpty {
|
|
|
contactContent += "\n电话: \(contactPhone)"
|
|
|
}
|
|
|
if !contactEmail.isEmpty {
|
|
|
contactContent += "\n邮箱: \(contactEmail)"
|
|
|
}
|
|
|
if !contactCompany.isEmpty {
|
|
|
contactContent += "\n公司: \(contactCompany)"
|
|
|
}
|
|
|
if !contactTitle.isEmpty {
|
|
|
contactContent += "\n职位: \(contactTitle)"
|
|
|
}
|
|
|
if !contactAddress.isEmpty {
|
|
|
contactContent += "\n地址: \(contactAddress)"
|
|
|
}
|
|
|
if !contactWebsite.isEmpty {
|
|
|
contactContent += "\n网站: \(contactWebsite)"
|
|
|
}
|
|
|
if !contactNote.isEmpty {
|
|
|
contactContent += "\n备注: \(contactNote)"
|
|
|
}
|
|
|
historyItem.content = contactContent
|
|
|
case .location:
|
|
|
historyItem.content = "位置: \(locationLatitude), \(locationLongitude)"
|
|
|
case .calendar:
|
|
|
historyItem.content = "事件: \(eventTitle)"
|
|
|
case .instagram, .facebook, .spotify, .twitter, .snapchat, .tiktok, .whatsapp, .viber:
|
|
|
historyItem.content = generateSocialMediaContent()
|
|
|
case .phone, .sms:
|
|
|
historyItem.content = "电话: \(phoneNumber)"
|
|
|
case .url:
|
|
|
historyItem.content = "URL: \(urlString)"
|
|
|
default:
|
|
|
historyItem.content = content
|
|
|
}
|
|
|
|
|
|
do {
|
|
|
try context.save()
|
|
|
alertMessage = "二维码创建成功!"
|
|
|
showingAlert = true
|
|
|
// 创建成功后返回
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
|
|
dismiss()
|
|
|
}
|
|
|
} catch {
|
|
|
alertMessage = "保存失败:\(error.localizedDescription)"
|
|
|
showingAlert = true
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// MARK: - Facebook ID提取辅助函数
|
|
|
private func extractFacebookId(from input: String) -> String {
|
|
|
// 如果输入的是Facebook链接,提取用户名/ID
|
|
|
if input.hasPrefix("http") {
|
|
|
// 处理各种Facebook链接格式
|
|
|
let patterns = [
|
|
|
"https://www.facebook.com/",
|
|
|
"https://facebook.com/",
|
|
|
"http://www.facebook.com/",
|
|
|
"http://facebook.com/"
|
|
|
]
|
|
|
|
|
|
var cleanedInput = input
|
|
|
for pattern in patterns {
|
|
|
if cleanedInput.hasPrefix(pattern) {
|
|
|
cleanedInput = String(cleanedInput.dropFirst(pattern.count))
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 移除查询参数和路径
|
|
|
if let questionMarkIndex = cleanedInput.firstIndex(of: "?") {
|
|
|
cleanedInput = String(cleanedInput[..<questionMarkIndex])
|
|
|
}
|
|
|
if let slashIndex = cleanedInput.firstIndex(of: "/") {
|
|
|
cleanedInput = String(cleanedInput[..<slashIndex])
|
|
|
}
|
|
|
|
|
|
return cleanedInput.isEmpty ? "unknown" : cleanedInput
|
|
|
}
|
|
|
|
|
|
// 如果输入的不是链接,直接返回(可能是用户名或ID)
|
|
|
return input
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#Preview {
|
|
|
NavigationView {
|
|
|
CreateQRCodeView(selectedQRCodeType: .sms)
|
|
|
}
|
|
|
}
|