From bfaa26f4ca779e4568f954d2e111f1c66f10c809 Mon Sep 17 00:00:00 2001 From: Matthew <6657488+reez@users.noreply.github.com> Date: Thu, 28 Sep 2023 11:11:42 -0500 Subject: [PATCH] view: add qrcodeview --- Sources/BitcoinUI/QRCodeView.swift | 79 ++++++++++++++++++++++++++++++ Sources/BitcoinUI/Utilities.swift | 12 +++++ 2 files changed, 91 insertions(+) create mode 100644 Sources/BitcoinUI/QRCodeView.swift diff --git a/Sources/BitcoinUI/QRCodeView.swift b/Sources/BitcoinUI/QRCodeView.swift new file mode 100644 index 0000000..80f9232 --- /dev/null +++ b/Sources/BitcoinUI/QRCodeView.swift @@ -0,0 +1,79 @@ +// +// QRCodeView.swift +// +// +// Created by Matthew Ramsden on 9/28/23. +// + +import SwiftUI +import CoreImage.CIFilterBuiltins + +enum QRCodeType { + case bitcoin(String) + case lightning(String) + + var qrString: String { + switch self { + case .bitcoin(let address): + return "bitcoin:\(address)" + case .lightning(let invoice): + return "lightning:\(invoice)" + } + } +} + +struct QRCodeView: View { + @State private var viewState = CGSize.zero + let screenBounds = UIScreen.main.bounds + var qrCodeType: QRCodeType + + var body: some View { + Image(uiImage: generateQRCode(from: qrCodeType.qrString)) + .interpolation(.none) + .resizable() + .scaledToFit() + .padding() + .applyFidgetEffect(viewState: $viewState) + .gesture(dragGesture()) + } + + private func generateQRCode(from string: String) -> UIImage { + let context = CIContext() + let filter = CIFilter.qrCodeGenerator() + let data = Data(string.utf8) + filter.setValue(data, forKey: "inputMessage") + + if let outputImage = filter.outputImage { + if let cgimg = context.createCGImage(outputImage, from: outputImage.extent) { + return UIImage(cgImage: cgimg) + } + } + return UIImage(systemName: "xmark.circle") ?? UIImage() + } + + private func dragGesture() -> some Gesture { + DragGesture() + .onChanged(handleDragChanged(_:)) + .onEnded(handleDragEnded(_:)) + } + + private func handleDragChanged(_ value: DragGesture.Value) { + let translation = value.translation + let multiplier: CGFloat = 0.05 + viewState.width = -translation.width * multiplier + viewState.height = -translation.height * multiplier + } + + private func handleDragEnded(_ value: DragGesture.Value) { + withAnimation { + self.viewState = .zero + } + } +} + +#Preview { + QRCodeView(qrCodeType: .bitcoin("bitcoinqrcode")) +} +#Preview { + QRCodeView(qrCodeType: .lightning("lightingqrcode")) +} diff --git a/Sources/BitcoinUI/Utilities.swift b/Sources/BitcoinUI/Utilities.swift index 4ee99aa..23984e2 100644 --- a/Sources/BitcoinUI/Utilities.swift +++ b/Sources/BitcoinUI/Utilities.swift @@ -6,6 +6,7 @@ // import Foundation +import SwiftUI extension CGFloat { @@ -20,3 +21,14 @@ extension CGFloat { } } + +extension View { + func applyFidgetEffect(viewState: Binding) -> some View { + self + .offset(x: -viewState.wrappedValue.width, y: -viewState.wrappedValue.height) + .rotation3DEffect( + .degrees(viewState.wrappedValue.width), + axis: (x: 0, y: 1, z: 0) + ) + } +}