import SwiftUI import QRCode import CoreData // MARK: - 自定义二维码样式界面 struct QRCodeStyleView: View { let qrCodeContent: String @Environment(\.dismiss) private var dismiss @StateObject private var coreDataManager = CoreDataManager.shared // 颜色选择 @State private var selectedForegroundColor: QRCodeColor = .black @State private var selectedBackgroundColor: QRCodeColor = .white // 点类型选择 @State private var selectedDotType: QRCodeDotType = .square // 眼睛类型选择 @State private var selectedEyeType: QRCodeEyeType = .square // Logo选择 @State private var selectedLogo: QRCodeLogo? = nil // 生成的二维码图片 @State private var qrCodeImage: UIImage? @State private var isLoading = false // 创建QRCode文档 private func createQRCodeDocument() -> QRCode.Document { let d = try! QRCode.Document(engine: QRCodeEngineExternal()) // 使用传入的二维码内容 d.utf8String = qrCodeContent // 设置背景色 d.design.backgroundColor(selectedBackgroundColor.cgColor) // 设置眼睛样式 d.design.style.eye = QRCode.FillStyle.Solid(selectedForegroundColor.cgColor) d.design.style.eyeBackground = selectedBackgroundColor.cgColor // 设置点样式 d.design.shape.onPixels = selectedDotType.pixelShape d.design.style.onPixels = QRCode.FillStyle.Solid(selectedForegroundColor.cgColor) d.design.style.onPixelsBackground = selectedBackgroundColor.cgColor d.design.shape.offPixels = selectedDotType.pixelShape d.design.style.offPixels = QRCode.FillStyle.Solid(selectedBackgroundColor.cgColor) d.design.style.offPixelsBackground = selectedBackgroundColor.cgColor // 设置眼睛形状 d.design.shape.eye = selectedEyeType.eyeShape // 如果有选择的Logo,设置背景图片 if let selectedLogo = selectedLogo { // 这里可以添加Logo图片设置 // d.design.style.background = QRCode.FillStyle.Image(selectedLogo.image) } return d } var body: some View { VStack(spacing: 0) { // 二维码预览区域 qrCodePreviewSection // 样式选择区域 styleSelectionSection } .navigationTitle("自定义样式") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button("保存") { saveQRCode() } .font(.system(size: 16, weight: .semibold)) } } .onAppear { } } // MARK: - 二维码预览区域 private var qrCodePreviewSection: some View { VStack(spacing: 16) { QRCodeDocumentUIView(document: createQRCodeDocument()) .frame(width: 300, height: 300) } .padding() .background(Color(.systemBackground)) } // MARK: - 样式选择区域 private var styleSelectionSection: some View { ScrollView { VStack(spacing: 24) { // 前景色选择 colorSelectionSection( title: "前景色", colors: QRCodeColor.foregroundColors, selectedColor: $selectedForegroundColor ) // 背景色选择 colorSelectionSection( title: "背景色", colors: QRCodeColor.backgroundColors, selectedColor: $selectedBackgroundColor ) // 点类型选择 dotTypeSelectionSection // 眼睛类型选择 eyeTypeSelectionSection // Logo选择 logoSelectionSection } .padding() } .background(Color(.systemGroupedBackground)) } // MARK: - 颜色选择区域 private func colorSelectionSection( title: String, colors: [QRCodeColor], selectedColor: Binding ) -> some View { VStack(alignment: .leading, spacing: 12) { Text(title) .font(.headline) .foregroundColor(.primary) LazyVGrid(columns: Array(repeating: GridItem(.flexible()), count: 6), spacing: 12) { ForEach(colors, id: \.self) { color in Button(action: { selectedColor.wrappedValue = color }) { RoundedRectangle(cornerRadius: 8) .fill(color.color) .frame(height: 40) .overlay( RoundedRectangle(cornerRadius: 8) .stroke(selectedColor.wrappedValue == color ? Color.blue : Color.clear, lineWidth: 3) ) } } } } } // MARK: - 点类型选择区域 private var dotTypeSelectionSection: some View { VStack(alignment: .leading, spacing: 12) { Text("点类型") .font(.headline) .foregroundColor(.primary) ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: 12) { ForEach(QRCodeDotType.allCases, id: \.self) { dotType in Button(action: { selectedDotType = dotType }) { VStack(spacing: 8) { if let image = loadImage(named: dotType.thumbnailName) { Image(uiImage: image) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 40, height: 40) .background(Color.white) .cornerRadius(8) } else { RoundedRectangle(cornerRadius: 8) .fill(Color.gray.opacity(0.3)) .frame(width: 40, height: 40) .overlay( Text("?") .font(.caption) .foregroundColor(.secondary) ) } Text(dotType.displayName) .font(.caption) .foregroundColor(.primary) } .padding(8) .background( RoundedRectangle(cornerRadius: 12) .fill(selectedDotType == dotType ? Color.blue.opacity(0.1) : Color.clear) .overlay( RoundedRectangle(cornerRadius: 12) .stroke(selectedDotType == dotType ? Color.blue : Color.clear, lineWidth: 2) ) ) } } } .padding(.horizontal) } } } // MARK: - 眼睛类型选择区域 private var eyeTypeSelectionSection: some View { VStack(alignment: .leading, spacing: 12) { Text("眼睛类型") .font(.headline) .foregroundColor(.primary) ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: 12) { ForEach(QRCodeEyeType.allCases, id: \.self) { eyeType in Button(action: { selectedEyeType = eyeType }) { VStack(spacing: 8) { if let image = loadImage(named: eyeType.thumbnailName) { Image(uiImage: image) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 40, height: 40) .background(Color.white) .cornerRadius(8) } else { RoundedRectangle(cornerRadius: 8) .fill(Color.gray.opacity(0.3)) .frame(width: 40, height: 40) .overlay( Text("?") .font(.caption) .foregroundColor(.secondary) ) } Text(eyeType.displayName) .font(.caption) .foregroundColor(.primary) } .padding(8) .background( RoundedRectangle(cornerRadius: 12) .fill(selectedEyeType == eyeType ? Color.blue.opacity(0.1) : Color.clear) .overlay( RoundedRectangle(cornerRadius: 12) .stroke(selectedEyeType == eyeType ? Color.blue : Color.clear, lineWidth: 2) ) ) } } } .padding(.horizontal) } } } // MARK: - Logo选择区域 private var logoSelectionSection: some View { VStack(alignment: .leading, spacing: 12) { Text("Logo") .font(.headline) .foregroundColor(.primary) ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: 12) { // 无Logo选项 Button(action: { selectedLogo = nil }) { VStack(spacing: 8) { RoundedRectangle(cornerRadius: 8) .fill(Color.gray.opacity(0.3)) .frame(width: 40, height: 40) .overlay( Text("无") .font(.caption) .foregroundColor(.secondary) ) Text("无Logo") .font(.caption) .foregroundColor(.primary) } .padding(8) .background( RoundedRectangle(cornerRadius: 12) .fill(selectedLogo == nil ? Color.blue.opacity(0.1) : Color.clear) .overlay( RoundedRectangle(cornerRadius: 12) .stroke(selectedLogo == nil ? Color.blue : Color.clear, lineWidth: 2) ) ) } // Logo选项 ForEach(QRCodeLogo.allCases, id: \.self) { logo in Button(action: { selectedLogo = logo }) { VStack(spacing: 8) { if let image = loadImage(named: logo.thumbnailName) { Image(uiImage: image) .resizable() .aspectRatio(contentMode: .fit) .frame(width: 40, height: 40) .background(Color.white) .cornerRadius(8) } else { RoundedRectangle(cornerRadius: 8) .fill(Color.gray.opacity(0.3)) .frame(width: 40, height: 40) .overlay( Text("?") .font(.caption) .foregroundColor(.secondary) ) } Text(logo.displayName) .font(.caption) .foregroundColor(.primary) } .padding(8) .background( RoundedRectangle(cornerRadius: 12) .fill(selectedLogo == logo ? Color.blue.opacity(0.1) : Color.clear) .overlay( RoundedRectangle(cornerRadius: 12) .stroke(selectedLogo == logo ? Color.blue : Color.clear, lineWidth: 2) ) ) } } } .padding(.horizontal) } } } // MARK: - 保存二维码 private func saveQRCode() { guard let qrCodeImage = qrCodeImage else { return } // 保存到相册 UIImageWriteToSavedPhotosAlbum(qrCodeImage, nil, nil, nil) // 保存到历史记录 saveToHistory() dismiss() } // MARK: - 保存到历史记录 private func saveToHistory() { 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 = "custom" historyItem.content = qrCodeContent do { try context.save() } catch { print("保存到历史记录失败:\(error.localizedDescription)") } } // MARK: - 辅助函数 private func loadImage(named name: String) -> UIImage? { // 方法1: 尝试从Bundle中直接加载 if let image = UIImage(named: name) { return image } // 方法2: 尝试从Resources子目录加载 let subdirectories = ["dots", "eyes", "logos"] for subdirectory in subdirectories { if let path = Bundle.main.path(forResource: name, ofType: "png", inDirectory: "Resources/\(subdirectory)") { return UIImage(contentsOfFile: path) } } // 方法3: 尝试从Bundle的Resources目录加载 if let bundlePath = Bundle.main.path(forResource: "Resources", ofType: nil) { for subdirectory in subdirectories { if let imagePath = Bundle.main.path(forResource: name, ofType: "png", inDirectory: subdirectory) { return UIImage(contentsOfFile: imagePath) } } } // 方法4: 尝试从Assets.xcassets加载 if let image = UIImage(named: name, in: Bundle.main, with: nil) { return image } // 方法5: 尝试从Bundle根目录加载 if let path = Bundle.main.path(forResource: name, ofType: "png") { return UIImage(contentsOfFile: path) } return nil } } // MARK: - 预览 #Preview { QRCodeStyleView(qrCodeContent: "https://www.example.com") }