diff --git a/bitchat/Views/VerificationViews.swift b/bitchat/Views/VerificationViews.swift index 5042532e..ee9191e7 100644 --- a/bitchat/Views/VerificationViews.swift +++ b/bitchat/Views/VerificationViews.swift @@ -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() } } -