|
|
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) {
|
|
|
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 {
|
|
|
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() // 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 {
|
|
|
VStack(spacing: 16) {
|
|
|
HStack {
|
|
|
Text("预览")
|
|
|
.font(.headline)
|
|
|
.foregroundColor(.primary)
|
|
|
|
|
|
Spacer()
|
|
|
}
|
|
|
|
|
|
// 二维码预览卡片
|
|
|
VStack(spacing: 16) {
|
|
|
// 二维码图片
|
|
|
if let qrImage = generateQRCodeImage() {
|
|
|
Image(uiImage: qrImage)
|
|
|
.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 "填写邮件信息,邮箱地址、主题、正文为必填项"
|
|
|
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:
|
|
|
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 = "二维码创建成功!"
|
|
|
showingAlert = true
|
|
|
// 创建成功后返回
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
|
|
dismiss()
|
|
|
}
|
|
|
} catch {
|
|
|
alertMessage = "保存失败:\(error.localizedDescription)"
|
|
|
showingAlert = true
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#Preview {
|
|
|
NavigationView {
|
|
|
CreateQRCodeView(selectedQRCodeType: .mail)
|
|
|
}
|
|
|
}
|