QR: render actual QR images with CoreImage; add copy button; keep scanner placeholder for now

This commit is contained in:
jack
2025-08-24 18:13:55 +02:00
parent e86dbc8d38
commit 921b9f1be6
+79 -7
View File
@@ -1,17 +1,36 @@
import SwiftUI
import CoreImage
import CoreImage.CIFilterBuiltins
#if os(iOS)
import UIKit
#else
import AppKit
#endif
/// Placeholder view to display the user's verification QR payload as text.
struct MyQRView: View {
let qrString: String
var body: some View {
VStack(spacing: 12) {
Text("Scan to verify me")
.font(.system(size: 16, weight: .bold, design: .monospaced))
// Placeholder box where a future QR image will go
RoundedRectangle(cornerRadius: 8)
.stroke(Color.gray.opacity(0.5), lineWidth: 1)
.frame(width: 220, height: 220)
.overlay(Text("QR PREVIEW\ncoming soon").font(.system(size: 12, design: .monospaced)).multilineTextAlignment(.center).foregroundColor(.gray))
QRCodeImage(data: qrString, size: 240)
.accessibilityLabel("verification QR code")
HStack(spacing: 8) {
Button("Copy Link") {
#if os(iOS)
UIPasteboard.general.string = qrString
#else
NSPasteboard.general.clearContents()
NSPasteboard.general.setString(qrString, forType: .string)
#endif
}
.buttonStyle(.bordered)
}
ScrollView {
Text(qrString)
.font(.system(size: 10, design: .monospaced))
@@ -19,12 +38,66 @@ struct MyQRView: View {
.padding(8)
.background(Color.gray.opacity(0.1))
.cornerRadius(6)
}.frame(maxHeight: 120)
}
.frame(maxHeight: 120)
}
.padding()
}
}
// Render a QR code image for a given string using CoreImage
struct QRCodeImage: View {
let data: String
let size: CGFloat
private let context = CIContext()
private let filter = CIFilter.qrCodeGenerator()
var body: some View {
Group {
if let image = generateImage() {
ImageWrapper(image: image)
.interpolation(.none)
.resizable()
.frame(width: size, height: size)
} else {
RoundedRectangle(cornerRadius: 8)
.stroke(Color.gray.opacity(0.5), lineWidth: 1)
.frame(width: size, height: size)
.overlay(
Text("QR unavailable")
.font(.system(size: 12, design: .monospaced))
.foregroundColor(.gray)
)
}
}
}
private func generateImage() -> CGImage? {
let inputData = Data(data.utf8)
filter.message = inputData
filter.correctionLevel = "M"
guard let outputImage = filter.outputImage else { return nil }
let scale = max(1, Int(size / 32))
let transformed = outputImage.transformed(by: CGAffineTransform(scaleX: CGFloat(scale), y: CGFloat(scale)))
return context.createCGImage(transformed, from: transformed.extent)
}
}
// Platform-specific wrapper to display CGImage in SwiftUI
struct ImageWrapper: View {
let image: CGImage
var body: some View {
#if os(iOS)
let ui = UIImage(cgImage: image)
return Image(uiImage: ui)
#else
let ns = NSImage(cgImage: image, size: .zero)
return Image(nsImage: ns)
#endif
}
}
/// Placeholder scanner UI; real camera scanning will be added later.
struct QRScanView: View {
@State private var input = ""
@@ -52,4 +125,3 @@ struct QRScanView: View {
.padding()
}
}