Add email input fields and validation to CreateQRCodeView for enhanced QR code generation

main
v504 2 months ago
parent 37881880ad
commit d5fef06e76

@ -17,6 +17,19 @@ struct CreateQRCodeView: View {
//
@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: EmailField?
// Email
private enum EmailField: Hashable {
case address, subject, body, cc, bcc
}
var body: some View {
VStack(spacing: 0) {
inputAndPreviewSection
@ -26,7 +39,7 @@ struct CreateQRCodeView: View {
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("创建") { createQRCode() }
.disabled(content.isEmpty)
.disabled(!canCreateQRCode())
.font(.system(size: 16, weight: .semibold))
}
}
@ -36,18 +49,159 @@ struct CreateQRCodeView: View {
.onAppear {
//
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
if selectedQRCodeType == .mail {
focusedEmailField = .address
} else {
isContentFieldFocused = true
}
}
}
.onTapGesture {
//
if selectedQRCodeType == .mail {
focusedEmailField = nil
} else {
isContentFieldFocused = false
}
}
}
// 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 {
ScrollView {
@ -78,14 +232,18 @@ struct CreateQRCodeView: View {
//
VStack(spacing: 16) {
HStack {
Text("输入内容")
Text(selectedQRCodeType == .mail ? "邮件信息" : "输入内容")
.font(.headline)
.foregroundColor(.primary)
Spacer()
}
//
if selectedQRCodeType == .mail {
// Email
emailInputSection
} else {
//
VStack(spacing: 8) {
ZStack {
//
@ -135,7 +293,7 @@ struct CreateQRCodeView: View {
// -
HStack {
Spacer()
Spacer() // Pushes content to the right
VStack(alignment: .trailing, spacing: 4) {
//
@ -144,7 +302,6 @@ struct CreateQRCodeView: View {
Image(systemName: "exclamationmark.triangle")
.font(.caption)
.foregroundColor(.orange)
Text("已达到最大字符数")
.font(.caption)
.foregroundColor(.orange)
@ -154,7 +311,6 @@ struct CreateQRCodeView: View {
Image(systemName: "info.circle")
.font(.caption)
.foregroundColor(.blue)
Text("接近字符限制")
.font(.caption)
.foregroundColor(.blue)
@ -169,10 +325,11 @@ struct CreateQRCodeView: View {
}
}
}
}
.padding(.horizontal, 20)
//
if !content.isEmpty {
if selectedQRCodeType == .mail ? (!emailAddress.isEmpty && !emailSubject.isEmpty && !emailBody.isEmpty) : !content.isEmpty {
VStack(spacing: 16) {
HStack {
Text("预览")
@ -180,20 +337,13 @@ struct CreateQRCodeView: View {
.foregroundColor(.primary)
Spacer()
Button(action: {
//
}) {
Image(systemName: "square.and.arrow.up")
.font(.system(size: 16))
.foregroundColor(.blue)
}
}
//
VStack(spacing: 16) {
//
if let qrCodeImage = generateQRCodeImage() {
Image(uiImage: qrCodeImage)
if let qrImage = generateQRCodeImage() {
Image(uiImage: qrImage)
.interpolation(.none)
.resizable()
.scaledToFit()
@ -245,10 +395,19 @@ struct CreateQRCodeView: View {
.background(Color(.systemGroupedBackground))
}
// MARK: - Helper Methods
private func canCreateQRCode() -> Bool {
switch selectedQRCodeType {
case .mail:
// Email
return !emailAddress.isEmpty && !emailSubject.isEmpty && !emailBody.isEmpty
default:
//
return !content.isEmpty
}
}
private func getCharacterCountColor() -> Color {
if content.count >= 150 {
return .orange
@ -266,7 +425,7 @@ struct CreateQRCodeView: View {
case .url:
return "输入网址https://www.example.com"
case .mail:
return "输入邮箱地址user@example.com"
return "填写邮件信息,邮箱地址、主题、正文为必填项"
case .phone:
return "输入电话号码,如:+86 138 0013 8000"
case .sms:
@ -303,46 +462,55 @@ struct CreateQRCodeView: View {
private func getPlaceholderText() -> String {
switch selectedQRCodeType {
case .text:
return "输入文本内容"
return "输入任意文本内容..."
case .url:
return "输入网址"
return "输入网址..."
case .mail:
return "输入邮箱地址"
return "输入邮件内容..."
case .phone:
return "输入电话号码"
return "输入电话号码..."
case .sms:
return "输入短信内容"
return "输入短信内容..."
case .wifi:
return "输入WiFi信息"
return "输入WiFi信息..."
case .vcard:
return "输入联系人信息"
return "输入联系人信息..."
case .mecard:
return "输入联系人信息"
return "输入联系人信息..."
case .location:
return "输入地理位置坐标"
return "输入地理位置..."
case .calendar:
return "输入日历事件信息"
return "输入日历事件信息..."
case .instagram:
return "输入Instagram信息"
return "输入Instagram信息..."
case .facebook:
return "输入Facebook信息"
return "输入Facebook信息..."
case .spotify:
return "输入Spotify链接"
return "输入Spotify信息..."
case .twitter:
return "输入Twitter信息"
return "输入Twitter信息..."
case .whatsapp:
return "输入WhatsApp消息"
return "输入WhatsApp信息..."
case .viber:
return "输入Viber消息"
return "输入Viber信息..."
case .snapchat:
return "输入Snapchat用户名"
return "输入Snapchat信息..."
case .tiktok:
return "输入TikTok信息"
return "输入TikTok信息..."
}
}
private func generateQRCodeImage() -> UIImage? {
guard !content.isEmpty 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()
@ -369,7 +537,30 @@ struct CreateQRCodeView: View {
case .url:
return content.hasPrefix("http") ? content : "https://\(content)"
case .mail:
return "mailto:\(content)"
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:\(content)"
case .sms:
@ -404,18 +595,30 @@ struct CreateQRCodeView: View {
}
private func createQRCode() {
guard !content.isEmpty else { return }
let context = coreDataManager.container.viewContext
let historyItem = HistoryItem(context: context)
historyItem.id = UUID()
historyItem.content = content
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
default:
historyItem.content = content
}
do {
try context.save()
alertMessage = "二维码创建成功!"
@ -433,6 +636,6 @@ struct CreateQRCodeView: View {
#Preview {
NavigationView {
CreateQRCodeView(selectedQRCodeType: .text)
CreateQRCodeView(selectedQRCodeType: .mail)
}
}

@ -0,0 +1,642 @@
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 = ""
@State private var showingAlert = false
@State private var alertMessage = ""
// 输入焦点,确保进入页面自动弹出键盘
@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: EmailField?
// Email字段枚举
private enum EmailField: Hashable {
case address, subject, body, cc, bcc
}
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 {
// 稍延迟以确保进入页面时自动聚焦
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
isContentFieldFocused = true
}
}
.onTapGesture {
// 点击外部关闭键盘
isContentFieldFocused = false
}
}
// 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 {
ScrollView {
VStack(spacing: 24) {
// 输入提示
VStack(spacing: 12) {
HStack {
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)
// 内容输入区域
VStack(spacing: 16) {
HStack {
Text(selectedQRCodeType == .mail ? "邮件信息" : "输入内容")
.font(.headline)
.foregroundColor(.primary)
Spacer()
}
if selectedQRCodeType == .mail {
// Email专用输入界面
emailInputSection
} else {
// 通用输入界面
VStack(spacing: 8) {
ZStack {
// 输入框主体
TextEditor(text: $content)
.frame(minHeight: 120)
.padding(8)
.background(Color(.systemBackground))
.cornerRadius(8)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(isContentFieldFocused ? Color.blue : Color(.systemGray4), lineWidth: 1)
)
.focused($isContentFieldFocused)
.onChange(of: content) { newValue in
// 限制最大字符数为150
if newValue.count > 150 {
content = String(newValue.prefix(150))
}
}
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Spacer()
Button("完成") {
isContentFieldFocused = false
}
.foregroundColor(.blue)
.font(.system(size: 16, weight: .medium))
}
}
// 占位符文本 - 左上角对齐
if content.isEmpty && !isContentFieldFocused {
VStack {
HStack {
Text(getPlaceholderText())
.foregroundColor(.secondary)
.font(.body)
Spacer()
}
Spacer()
}
.padding(16)
.allowsHitTesting(false)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
}
}
// 字符计数和限制提示 - 输入框底下
HStack {
Spacer()
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 !content.isEmpty {
VStack(spacing: 16) {
HStack {
Text("预览")
.font(.headline)
.foregroundColor(.primary)
Spacer()
Button(action: {
// 可以添加分享功能
}) {
Image(systemName: "square.and.arrow.up")
.font(.system(size: 16))
.foregroundColor(.blue)
}
}
VStack(spacing: 16) {
// 二维码图片
if let qrCodeImage = generateQRCodeImage() {
Image(uiImage: qrCodeImage)
.interpolation(.none)
.resizable()
.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)
}
.padding(.top, 20)
}
.background(Color(.systemGroupedBackground))
}
// MARK: - Helper Methods
private func canCreateQRCode() -> Bool {
switch selectedQRCodeType {
case .mail:
// Email类型邮箱地址、主题、正文为必填
return !emailAddress.isEmpty && !emailSubject.isEmpty && !emailBody.isEmpty
default:
// 其他类型:内容不能为空
return !content.isEmpty
}
}
private func getCharacterCountColor() -> Color {
if content.count >= 150 {
return .orange
} else if content.count >= 140 {
return .blue
} else {
return .secondary
}
}
private func getContentHint() -> String {
switch selectedQRCodeType {
case .text:
return "输入任意文本内容"
case .url:
return "输入网址https://www.example.com"
case .mail:
return "输入邮箱地址user@example.com"
case .phone:
return "输入电话号码,如:+86 138 0013 8000"
case .sms:
return "输入短信内容Hello World"
case .wifi:
return "输入WiFi信息SSID:MyWiFi,Password:12345678"
case .vcard:
return "输入联系人信息"
case .mecard:
return "输入联系人信息(简化版)"
case .location:
return "输入地理位置40.7128,-74.0060"
case .calendar:
return "输入日历事件信息"
case .instagram:
return "输入Instagram用户名或链接"
case .facebook:
return "输入Facebook用户名或链接"
case .spotify:
return "输入Spotify歌曲或播放列表链接"
case .twitter:
return "输入Twitter用户名或链接"
case .whatsapp:
return "输入WhatsApp消息内容"
case .viber:
return "输入Viber消息内容"
case .snapchat:
return "输入Snapchat用户名"
case .tiktok:
return "输入TikTok用户名或链接"
}
}
private func getPlaceholderText() -> String {
switch selectedQRCodeType {
case .text:
return "输入文本内容"
case .url:
return "输入网址"
case .mail:
return "输入邮箱地址"
case .phone:
return "输入电话号码"
case .sms:
return "输入短信内容"
case .wifi:
return "输入WiFi信息"
case .vcard:
return "输入联系人信息"
case .mecard:
return "输入联系人信息"
case .location:
return "输入地理位置坐标"
case .calendar:
return "输入日历事件信息"
case .instagram:
return "输入Instagram信息"
case .facebook:
return "输入Facebook信息"
case .spotify:
return "输入Spotify链接"
case .twitter:
return "输入Twitter信息"
case .whatsapp:
return "输入WhatsApp消息"
case .viber:
return "输入Viber消息"
case .snapchat:
return "输入Snapchat用户名"
case .tiktok:
return "输入TikTok信息"
}
}
private func generateQRCodeImage() -> UIImage? {
// 根据二维码类型检查内容是否为空
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 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 }
// 转换为UIImage
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 content.hasPrefix("http") ? content : "https://\(content)"
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:\(content)"
case .sms:
return "sms:\(content)"
case .wifi:
return "WIFI:T:WPA;S:\(content);P:password;;"
case .vcard:
return "BEGIN:VCARD\nVERSION:3.0\nFN:\(content)\nEND:VCARD"
case .mecard:
return "MECARD:N:\(content);;"
case .location:
return "geo:\(content)"
case .calendar:
return "BEGIN:VEVENT\nSUMMARY:\(content)\nEND:VEVENT"
case .instagram:
return "https://instagram.com/\(content)"
case .facebook:
return "https://facebook.com/\(content)"
case .spotify:
return content.hasPrefix("http") ? content : "https://open.spotify.com/track/\(content)"
case .twitter:
return "https://twitter.com/\(content)"
case .whatsapp:
return "https://wa.me/\(content)"
case .viber:
return "viber://chat?number=\(content)"
case .snapchat:
return "https://snapchat.com/add/\(content)"
case .tiktok:
return "https://tiktok.com/@\(content)"
}
}
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:
historyItem.content = "邮箱: \(emailAddress)\n主题: \(emailSubject)\n正文: \(emailBody)"
if !emailCc.isEmpty {
historyItem.content += "\n抄送: \(emailCc)"
}
if !emailBcc.isEmpty {
historyItem.content += "\n密送: \(emailBcc)"
}
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
}
}
}
#Preview {
NavigationView {
CreateQRCodeView(selectedQRCodeType: .text)
}
}
Loading…
Cancel
Save