Refactor CreateQRCodeView to support multiple QR code types with dynamic input handling; introduced new fields for WiFi, contact, location, calendar, social media, and phone inputs. Enhanced initial focus setup and input validation for improved user experience and modularity.

main
v504 2 months ago
parent 4e57ba1abd
commit 972774adb1

@ -102,7 +102,8 @@ struct InputComponentFactory {
eventDescription: eventDescription, eventDescription: eventDescription,
startDate: startDate, startDate: startDate,
endDate: endDate, endDate: endDate,
location: location location: location,
focusedField: focusedCalendarField
) )
) )
@ -150,7 +151,7 @@ struct InputComponentFactory {
} }
// //
private static func getPlaceholderText(for qrCodeType: QRCodeType) -> String { static func getPlaceholderText(for qrCodeType: QRCodeType) -> String {
switch qrCodeType { switch qrCodeType {
case .text: case .text:
return "输入任意文本内容..." return "输入任意文本内容..."

@ -10,11 +10,8 @@ struct CreateQRCodeView: View {
// //
let selectedQRCodeType: QRCodeType let selectedQRCodeType: QRCodeType
//
@State private var content = "" @State private var content = ""
@State private var showingAlert = false
@State private var alertMessage = ""
//
@FocusState private var isContentFieldFocused: Bool @FocusState private var isContentFieldFocused: Bool
// Email // Email
@ -23,12 +20,56 @@ struct CreateQRCodeView: View {
@State private var emailBody = "" @State private var emailBody = ""
@State private var emailCc = "" @State private var emailCc = ""
@State private var emailBcc = "" @State private var emailBcc = ""
@FocusState private var focusedEmailField: EmailField? @FocusState private var focusedEmailField: EmailInputView.EmailField?
// Email // WiFi
private enum EmailField: Hashable { @State private var wifiSSID = ""
case address, subject, body, cc, bcc @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 = ""
@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 { var body: some View {
VStack(spacing: 0) { VStack(spacing: 0) {
@ -47,345 +88,92 @@ struct CreateQRCodeView: View {
Button("确定") { } Button("确定") { }
} message: { Text(alertMessage) } } message: { Text(alertMessage) }
.onAppear { .onAppear {
// setupInitialFocus()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
if selectedQRCodeType == .mail {
focusedEmailField = .address
} else {
isContentFieldFocused = true
}
}
} }
.onTapGesture { .onTapGesture {
// hideKeyboard()
if selectedQRCodeType == .mail {
focusedEmailField = nil
} else {
isContentFieldFocused = false
}
} }
} }
// MARK: - UI Components // MARK: - UI Components
private var emailInputSection: some View {
VStack(spacing: 16) {
// Email ()
VStack(alignment: .leading, spacing: 8) {
HStack {
Text("邮箱地址")
.font(.subheadline)
.foregroundColor(.primary)
Text("*")
.foregroundColor(.red)
Spacer()
}
TextField("user@example.com", text: $emailAddress)
.textFieldStyle(RoundedBorderTextFieldStyle())
.keyboardType(.emailAddress)
.autocapitalization(.none)
.focused($focusedEmailField, equals: .address)
}
// ()
VStack(alignment: .leading, spacing: 8) {
HStack {
Text("主题")
.font(.subheadline)
.foregroundColor(.primary)
Text("*")
.foregroundColor(.red)
Spacer()
}
TextField("邮件主题", text: $emailSubject)
.textFieldStyle(RoundedBorderTextFieldStyle())
.focused($focusedEmailField, equals: .subject)
}
// ()
VStack(alignment: .leading, spacing: 8) {
HStack {
Text("正文")
.font(.subheadline)
.foregroundColor(.primary)
Text("*")
.foregroundColor(.red)
Spacer()
}
ZStack {
TextEditor(text: $emailBody)
.frame(minHeight: 120)
.padding(8)
.background(Color(.systemBackground))
.cornerRadius(8)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(focusedEmailField == .body ? Color.blue : Color(.systemGray4), lineWidth: 1)
)
.focused($focusedEmailField, equals: .body)
.onChange(of: emailBody) { newValue in
// 1200
if newValue.count > 1200 {
emailBody = String(newValue.prefix(1200))
}
}
//
if emailBody.isEmpty && focusedEmailField != .body {
VStack {
HStack {
Text("输入邮件正文内容...")
.foregroundColor(.secondary)
.font(.body)
Spacer()
}
Spacer()
}
.padding(16)
.allowsHitTesting(false)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
}
}
//
HStack {
Spacer()
Text("\(emailBody.count)/1200")
.font(.caption)
.foregroundColor(emailBody.count >= 1200 ? .orange : .secondary)
}
}
// CC ()
VStack(alignment: .leading, spacing: 8) {
HStack {
Text("抄送地址")
.font(.subheadline)
.foregroundColor(.primary)
Spacer()
}
TextField("cc@example.com", text: $emailCc)
.textFieldStyle(RoundedBorderTextFieldStyle())
.keyboardType(.emailAddress)
.autocapitalization(.none)
.focused($focusedEmailField, equals: .cc)
}
// BCC ()
VStack(alignment: .leading, spacing: 8) {
HStack {
Text("密送地址")
.font(.subheadline)
.foregroundColor(.primary)
Spacer()
}
TextField("bcc@example.com", text: $emailBcc)
.textFieldStyle(RoundedBorderTextFieldStyle())
.keyboardType(.emailAddress)
.autocapitalization(.none)
.focused($focusedEmailField, equals: .bcc)
}
}
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Spacer()
Button("完成") {
focusedEmailField = nil
}
.foregroundColor(.blue)
.font(.system(size: 16, weight: .medium))
}
}
}
private var inputAndPreviewSection: some View { private var inputAndPreviewSection: some View {
ScrollView { ScrollView {
VStack(spacing: 24) { VStack(spacing: 24) {
// //
VStack(spacing: 12) { InputHintView.info(
HStack { hint: getContentHint()
Image(systemName: "info.circle") )
.font(.caption)
.foregroundColor(.blue)
Text(getContentHint())
.font(.caption)
.foregroundColor(.secondary)
.lineLimit(nil)
Spacer()
}
.padding(.horizontal, 12)
.padding(.vertical, 8)
.background(
RoundedRectangle(cornerRadius: 8)
.fill(Color.blue.opacity(0.1))
)
}
.padding(.horizontal, 20) .padding(.horizontal, 20)
// //
VStack(spacing: 16) { VStack(spacing: 16) {
HStack { InputTitleView.required(
Text(selectedQRCodeType == .mail ? "邮件信息" : "输入内容") selectedQRCodeType == .mail ? "邮件信息" : "输入内容",
.font(.headline) icon: getInputIcon()
.foregroundColor(.primary) )
.padding(.horizontal, 20)
Spacer()
}
if selectedQRCodeType == .mail { // 使InputComponentFactory
// Email InputComponentFactory.createInputComponent(
emailInputSection for: selectedQRCodeType,
} else { content: $content,
// emailAddress: $emailAddress,
VStack(spacing: 8) { emailSubject: $emailSubject,
ZStack { emailBody: $emailBody,
// emailCc: $emailCc,
TextEditor(text: $content) emailBcc: $emailBcc,
.frame(minHeight: 120) focusedEmailField: _focusedEmailField,
.padding(8) isContentFieldFocused: _isContentFieldFocused,
.background(Color(.systemBackground)) ssid: $wifiSSID,
.cornerRadius(8) password: $wifiPassword,
.overlay( encryptionType: $wifiEncryptionType,
RoundedRectangle(cornerRadius: 8) focusedWiFiField: _focusedWiFiField,
.stroke(isContentFieldFocused ? Color.blue : Color(.systemGray4), lineWidth: 1) firstName: $contactFirstName,
) lastName: $contactLastName,
.focused($isContentFieldFocused) phone: $contactPhone,
.onChange(of: content) { newValue in email: $contactEmail,
// 150 company: $contactCompany,
if newValue.count > 150 { title: $contactTitle,
content = String(newValue.prefix(150)) address: $contactAddress,
} website: $contactWebsite,
} focusedContactField: _focusedContactField,
.toolbar { latitude: $locationLatitude,
ToolbarItemGroup(placement: .keyboard) { longitude: $locationLongitude,
Spacer() locationName: $locationName,
Button("完成") { focusedLocationField: _focusedLocationField,
isContentFieldFocused = false eventTitle: $eventTitle,
} eventDescription: $eventDescription,
.foregroundColor(.blue) startDate: $startDate,
.font(.system(size: 16, weight: .medium)) endDate: $endDate,
} location: $eventLocation,
} focusedCalendarField: _focusedCalendarField,
username: $socialUsername,
// - message: $socialMessage,
if content.isEmpty && !isContentFieldFocused { focusedSocialField: _focusedSocialField,
VStack { phoneNumber: $phoneNumber,
HStack { phoneMessage: $phoneMessage,
Text(getPlaceholderText()) focusedPhoneField: _focusedPhoneField,
.foregroundColor(.secondary) url: $urlString,
.font(.body) isUrlFieldFocused: _isURLFieldFocused
Spacer() )
} .padding(.horizontal, 20)
Spacer()
}
.padding(16)
.allowsHitTesting(false)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
}
}
// -
HStack {
Spacer() // Pushes content to the right
VStack(alignment: .trailing, spacing: 4) {
//
if content.count >= 150 {
HStack(spacing: 4) {
Image(systemName: "exclamationmark.triangle")
.font(.caption)
.foregroundColor(.orange)
Text("已达到最大字符数")
.font(.caption)
.foregroundColor(.orange)
}
} else if content.count >= 140 {
HStack(spacing: 4) {
Image(systemName: "info.circle")
.font(.caption)
.foregroundColor(.blue)
Text("接近字符限制")
.font(.caption)
.foregroundColor(.blue)
}
}
//
Text("\(content.count)/150")
.font(.caption)
.foregroundColor(getCharacterCountColor())
}
}
}
}
} }
.padding(.horizontal, 20)
// //
if selectedQRCodeType == .mail ? (!emailAddress.isEmpty && !emailSubject.isEmpty && !emailBody.isEmpty) : !content.isEmpty { if canCreateQRCode() {
VStack(spacing: 16) { VStack(spacing: 16) {
HStack { InputTitleView.required("预览", icon: "eye")
Text("预览") .padding(.horizontal, 20)
.font(.headline)
.foregroundColor(.primary)
Spacer()
}
// // 使QRCodePreviewView
VStack(spacing: 16) { QRCodePreviewView(
// qrCodeImage: generateQRCodeImage(),
if let qrImage = generateQRCodeImage() { formattedContent: formatContentForQRCodeType(),
Image(uiImage: qrImage) qrCodeType: selectedQRCodeType
.interpolation(.none) )
.resizable() .padding(.horizontal, 20)
.scaledToFit()
.frame(width: 200, height: 200)
.background(Color.white)
.cornerRadius(12)
.shadow(color: .black.opacity(0.1), radius: 8, x: 0, y: 4)
}
//
VStack(alignment: .leading, spacing: 8) {
HStack {
Text("内容")
.font(.caption)
.foregroundColor(.secondary)
Spacer()
Text(selectedQRCodeType.displayName)
.font(.caption)
.padding(.horizontal, 6)
.padding(.vertical, 2)
.background(Color.orange.opacity(0.1))
.foregroundColor(.orange)
.cornerRadius(4)
}
Text(formatContentForQRCodeType())
.font(.body)
.foregroundColor(.primary)
.textSelection(.enabled)
}
.padding()
.background(Color(.systemGray6))
.cornerRadius(8)
}
.padding()
.background(Color(.systemBackground))
.cornerRadius(12)
.shadow(color: .black.opacity(0.05), radius: 4, x: 0, y: 2)
} }
.padding(.horizontal, 20)
} }
Spacer(minLength: 100) Spacer(minLength: 100)
@ -397,133 +185,106 @@ struct CreateQRCodeView: View {
// MARK: - Helper Methods // MARK: - Helper Methods
private func canCreateQRCode() -> Bool { private func setupInitialFocus() {
switch selectedQRCodeType { DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
case .mail: switch selectedQRCodeType {
// Email case .mail:
return !emailAddress.isEmpty && !emailSubject.isEmpty && !emailBody.isEmpty focusedEmailField = .address
default: case .wifi:
// focusedWiFiField = .ssid
return !content.isEmpty case .vcard, .mecard:
} focusedContactField = .firstName
} case .location:
focusedLocationField = .latitude
private func getCharacterCountColor() -> Color { case .calendar:
if content.count >= 150 { focusedCalendarField = .title
return .orange case .instagram, .facebook, .spotify, .twitter, .snapchat, .tiktok:
} else if content.count >= 140 { focusedSocialField = .username
return .blue case .phone, .sms:
} else { focusedPhoneField = .phoneNumber
return .secondary case .url:
isURLFieldFocused = true
default:
isContentFieldFocused = true
}
} }
} }
private func getContentHint() -> String { private func hideKeyboard() {
switch selectedQRCodeType { switch selectedQRCodeType {
case .text:
return "输入任意文本内容"
case .url:
return "输入网址https://www.example.com"
case .mail: case .mail:
return "填写邮件信息,邮箱地址、主题、正文为必填项" focusedEmailField = nil
case .phone:
return "输入电话号码,如:+86 138 0013 8000"
case .sms:
return "输入短信内容Hello World"
case .wifi: case .wifi:
return "输入WiFi信息SSID:MyWiFi,Password:12345678" focusedWiFiField = nil
case .vcard: case .vcard, .mecard:
return "输入联系人信息" focusedContactField = nil
case .mecard:
return "输入联系人信息(简化版)"
case .location: case .location:
return "输入地理位置40.7128,-74.0060" focusedLocationField = nil
case .calendar: case .calendar:
return "输入日历事件信息" focusedCalendarField = nil
case .instagram: case .instagram, .facebook, .spotify, .twitter, .snapchat, .tiktok:
return "输入Instagram用户名或链接" focusedSocialField = nil
case .facebook: case .phone, .sms:
return "输入Facebook用户名或链接" focusedPhoneField = nil
case .spotify: case .url:
return "输入Spotify歌曲或播放列表链接" isURLFieldFocused = false
case .twitter: default:
return "输入Twitter用户名或链接" isContentFieldFocused = false
case .whatsapp:
return "输入WhatsApp消息内容"
case .viber:
return "输入Viber消息内容"
case .snapchat:
return "输入Snapchat用户名"
case .tiktok:
return "输入TikTok用户名或链接"
} }
} }
private func getPlaceholderText() -> String { 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: return "globe"
case .phone, .sms: return "phone"
case .url: return "link"
default: return "textformat"
}
}
private func canCreateQRCode() -> Bool {
switch selectedQRCodeType { switch selectedQRCodeType {
case .text:
return "输入任意文本内容..."
case .url:
return "输入网址..."
case .mail: case .mail:
return "输入邮件内容..." return !emailAddress.isEmpty && !emailSubject.isEmpty && !emailBody.isEmpty
case .phone:
return "输入电话号码..."
case .sms:
return "输入短信内容..."
case .wifi: case .wifi:
return "输入WiFi信息..." return !wifiSSID.isEmpty
case .vcard: case .vcard, .mecard:
return "输入联系人信息..." return !contactFirstName.isEmpty || !contactLastName.isEmpty
case .mecard:
return "输入联系人信息..."
case .location: case .location:
return "输入地理位置..." return !locationLatitude.isEmpty && !locationLongitude.isEmpty
case .calendar: case .calendar:
return "输入日历事件信息..." return !eventTitle.isEmpty
case .instagram: case .instagram, .facebook, .spotify, .twitter, .snapchat, .tiktok:
return "输入Instagram信息..." return !socialUsername.isEmpty
case .facebook: case .phone, .sms:
return "输入Facebook信息..." return !phoneNumber.isEmpty
case .spotify: case .url:
return "输入Spotify信息..." return !urlString.isEmpty
case .twitter: default:
return "输入Twitter信息..." return !content.isEmpty
case .whatsapp:
return "输入WhatsApp信息..."
case .viber:
return "输入Viber信息..."
case .snapchat:
return "输入Snapchat信息..."
case .tiktok:
return "输入TikTok信息..."
} }
} }
private func getContentHint() -> String {
InputComponentFactory.getPlaceholderText(for: selectedQRCodeType)
}
private func generateQRCodeImage() -> UIImage? { private func generateQRCodeImage() -> UIImage? {
// guard canCreateQRCode() else { return nil }
let hasContent: Bool
switch selectedQRCodeType {
case .mail:
hasContent = !emailAddress.isEmpty && !emailSubject.isEmpty && !emailBody.isEmpty
default:
hasContent = !content.isEmpty
}
guard hasContent else { return nil }
//
let formattedContent = formatContentForQRCodeType() let formattedContent = formatContentForQRCodeType()
//
let data = formattedContent.data(using: .utf8) let data = formattedContent.data(using: .utf8)
let qrFilter = CIFilter.qrCodeGenerator() let qrFilter = CIFilter.qrCodeGenerator()
qrFilter.setValue(data, forKey: "inputMessage") qrFilter.setValue(data, forKey: "inputMessage")
qrFilter.setValue("H", forKey: "inputCorrectionLevel") // qrFilter.setValue("H", forKey: "inputCorrectionLevel")
guard let outputImage = qrFilter.outputImage else { return nil } guard let outputImage = qrFilter.outputImage else { return nil }
// UIImage
let context = CIContext() let context = CIContext()
guard let cgImage = context.createCGImage(outputImage, from: outputImage.extent) else { return nil } guard let cgImage = context.createCGImage(outputImage, from: outputImage.extent) else { return nil }
@ -535,7 +296,7 @@ struct CreateQRCodeView: View {
case .text: case .text:
return content return content
case .url: case .url:
return content.hasPrefix("http") ? content : "https://\(content)" return urlString.hasPrefix("http") ? urlString : "https://\(urlString)"
case .mail: case .mail:
var mailtoURL = "mailto:\(emailAddress)" var mailtoURL = "mailto:\(emailAddress)"
var queryParams: [String] = [] var queryParams: [String] = []
@ -562,35 +323,97 @@ struct CreateQRCodeView: View {
return mailtoURL return mailtoURL
case .phone: case .phone:
return "tel:\(content)" return "tel:\(phoneNumber)"
case .sms: case .sms:
return "sms:\(content)" let smsContent = phoneMessage.isEmpty ? "Hello" : phoneMessage
return "sms:\(phoneNumber):\(smsContent)"
case .wifi: case .wifi:
return "WIFI:T:WPA;S:\(content);P:password;;" return "WIFI:T:\(wifiEncryptionType.rawValue);S:\(wifiSSID);P:\(wifiPassword);;"
case .vcard: case .vcard:
return "BEGIN:VCARD\nVERSION:3.0\nFN:\(content)\nEND:VCARD" var vcard = "BEGIN:VCARD\nVERSION:3.0\n"
if !contactFirstName.isEmpty || !contactLastName.isEmpty {
vcard += "FN:\(contactFirstName) \(contactLastName)\n"
}
if !contactPhone.isEmpty {
vcard += "TEL:\(contactPhone)\n"
}
if !contactEmail.isEmpty {
vcard += "EMAIL:\(contactEmail)\n"
}
if !contactCompany.isEmpty {
vcard += "ORG:\(contactCompany)\n"
}
if !contactTitle.isEmpty {
vcard += "TITLE:\(contactTitle)\n"
}
if !contactAddress.isEmpty {
vcard += "ADR:\(contactAddress)\n"
}
if !contactWebsite.isEmpty {
vcard += "URL:\(contactWebsite)\n"
}
vcard += "END:VCARD"
return vcard
case .mecard: case .mecard:
return "MECARD:N:\(content);;" var mecard = "MECARD:"
if !contactFirstName.isEmpty || !contactLastName.isEmpty {
mecard += "N:\(contactLastName),\(contactFirstName);"
}
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);"
}
mecard += ";"
return mecard
case .location: case .location:
return "geo:\(content)" let coords = "\(locationLatitude),\(locationLongitude)"
return locationName.isEmpty ? "geo:\(coords)" : "geo:\(coords)?q=\(locationName)"
case .calendar: case .calendar:
return "BEGIN:VEVENT\nSUMMARY:\(content)\nEND:VEVENT" 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: case .instagram:
return "https://instagram.com/\(content)" return "https://instagram.com/\(socialUsername)"
case .facebook: case .facebook:
return "https://facebook.com/\(content)" return "https://facebook.com/\(socialUsername)"
case .spotify: case .spotify:
return content.hasPrefix("http") ? content : "https://open.spotify.com/track/\(content)" return socialUsername.hasPrefix("http") ? socialUsername : "https://open.spotify.com/track/\(socialUsername)"
case .twitter: case .twitter:
return "https://twitter.com/\(content)" return "https://twitter.com/\(socialUsername)"
case .whatsapp: case .whatsapp:
return "https://wa.me/\(content)" let message = socialMessage.isEmpty ? "Hello" : socialMessage
return "https://wa.me/\(socialUsername)?text=\(message.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? message)"
case .viber: case .viber:
return "viber://chat?number=\(content)" let message = socialMessage.isEmpty ? "Hello" : socialMessage
return "viber://chat?number=\(socialUsername)&text=\(message.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? message)"
case .snapchat: case .snapchat:
return "https://snapchat.com/add/\(content)" return "https://snapchat.com/add/\(socialUsername)"
case .tiktok: case .tiktok:
return "https://tiktok.com/@\(content)" return "https://tiktok.com/@\(socialUsername)"
} }
} }
@ -615,6 +438,20 @@ struct CreateQRCodeView: View {
mailContent += "\n密送: \(emailBcc)" mailContent += "\n密送: \(emailBcc)"
} }
historyItem.content = mailContent historyItem.content = mailContent
case .wifi:
historyItem.content = "WiFi: \(wifiSSID) (\(wifiEncryptionType.displayName))"
case .vcard, .mecard:
historyItem.content = "联系人: \(contactFirstName) \(contactLastName)"
case .location:
historyItem.content = "位置: \(locationLatitude), \(locationLongitude)"
case .calendar:
historyItem.content = "事件: \(eventTitle)"
case .instagram, .facebook, .spotify, .twitter, .snapchat, .tiktok:
historyItem.content = "\(selectedQRCodeType.displayName): \(socialUsername)"
case .phone, .sms:
historyItem.content = "电话: \(phoneNumber)"
case .url:
historyItem.content = "URL: \(urlString)"
default: default:
historyItem.content = content historyItem.content = content
} }

@ -169,7 +169,6 @@ struct QRCodeDetailView: View {
// MARK: - // MARK: -
private var originalContentSection: some View { private var originalContentSection: some View {
#if DEBUG
VStack(alignment: .leading, spacing: 12) { VStack(alignment: .leading, spacing: 12) {
HStack { HStack {
Image(systemName: "doc.text") Image(systemName: "doc.text")
@ -200,9 +199,6 @@ struct QRCodeDetailView: View {
.background(Color(.systemBackground)) .background(Color(.systemBackground))
.cornerRadius(12) .cornerRadius(12)
.shadow(radius: 2) .shadow(radius: 2)
#else
EmptyView()
#endif
} }
// MARK: - // MARK: -

Loading…
Cancel
Save