Update navigation in CodeTypeSelectionView to conditionally present CreateQRCodeView or CreateCodeView based on selected data type, enhancing user experience and streamlining code flow.

main
v504 2 months ago
parent 29ee4ba2f2
commit 37881880ad

@ -99,11 +99,13 @@ struct CodeTypeSelectionView: View {
//
NavigationLink(
destination: CreateCodeView(
destination: selectedDataType == .qrcode ?
AnyView(CreateQRCodeView(selectedQRCodeType: selectedQRCodeType)) :
AnyView(CreateCodeView(
selectedDataType: selectedDataType,
selectedBarcodeType: selectedBarcodeType,
selectedQRCodeType: selectedQRCodeType
)
))
) {
HStack(spacing: 8) {
Text("下一步")

@ -0,0 +1,438 @@
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
var body: some View {
VStack(spacing: 0) {
inputAndPreviewSection
}
.navigationTitle(selectedQRCodeType.displayName)
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("创建") { createQRCode() }
.disabled(content.isEmpty)
.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 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("输入内容")
.font(.headline)
.foregroundColor(.primary)
Spacer()
}
//
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 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? {
guard !content.isEmpty 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:
return "mailto:\(content)"
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() {
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
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