commit 96774c21008b594cdb1a3a949fffc26b2c2b5829
parent 4fb00bd5819f077ca046638a6d62d9075f698b22
Author: Marc Stibane <marc@taler.net>
Date: Sat, 31 Oct 2026 17:46:17 +0100
separate QR generation from view
Diffstat:
4 files changed, 49 insertions(+), 51 deletions(-)
diff --git a/TalerCommon/HelperViews/QRGeneratorView.swift b/TalerCommon/HelperViews/QRGeneratorView.swift
@@ -21,14 +21,26 @@
*/
import SwiftUI
+public func QRCode(from text: String) -> UIImage? {
+ guard let filter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
+ let data = text.data(using: .utf8, allowLossyConversion: false)
+ filter.setValue(data, forKey: "inputMessage")
+ filter.setValue("Q", forKey: "inputCorrectionLevel") // 4 levels: L M Q H
+ guard let ciimage = filter.outputImage else { return nil }
+ let transform = CGAffineTransform(scaleX: 10, y: 10)
+ let scaledCIImage = ciimage.transformed(by: transform)
+ // a UIImage(ciImage:) has no bitmap representation, so pngData() would return nil
+ guard let cgImage = CIContext().createCGImage(scaledCIImage,
+ from: scaledCIImage.extent) else { return nil }
+ return UIImage(cgImage: cgImage)
+}
+// MARK: -
struct QRGeneratorView: View {
let text: String
let size: CGFloat
let logo: Image?
let logoSize: CGFloat
- @Binding var image: UIImage?
-
- @State private var failed = false
+ let image: UIImage?
// a QR code which cannot be generated must not look like an empty area to scan
private var failedText: Text {
@@ -49,40 +61,14 @@ struct QRGeneratorView: View {
.scaledToFit()
.frame(width: logoSize * 2, height: logoSize)
}
- } else if failed {
+ } else {
failedText
.talerFont(.title2)
.frame(width: size, height: size)
- } else {
- EmptyView()
}
}
.accessibilityElement(children: .combine)
- .accessibilityLabel(failed ? failedText : Text("QR Code", comment: "a11y"))
- .onAppear {
-// if let uiImage = getQRCode(text: text) {
- if let data = getQRCodeData(text: text),
- let uiImage = UIImage(data: data) {
- image = uiImage
- } else {
- failed = true
- }
- }
- }
-
-// func getQRCode(text: String) -> UIImage? {
- func getQRCodeData(text: String) -> Data? {
- guard let filter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
- let data = text.data(using: .utf8, allowLossyConversion: false)
- filter.setValue(data, forKey: "inputMessage")
- filter.setValue("Q", forKey: "inputCorrectionLevel") // 4 levels: L M Q H
- guard let ciimage = filter.outputImage else { return nil }
- let transform = CGAffineTransform(scaleX: 10, y: 10)
- let scaledCIImage = ciimage.transformed(by: transform)
- // a UIImage(ciImage:) has no bitmap representation, so pngData() would return nil
- guard let cgImage = CIContext().createCGImage(scaledCIImage, from: scaledCIImage.extent)
- else { return nil }
- return UIImage(cgImage: cgImage).pngData()
+ .accessibilityLabel(image == nil ? failedText : Text("QR Code", comment: "a11y"))
}
}
diff --git a/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift b/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift
@@ -82,7 +82,9 @@ struct QRCodeDetailView: View {
GradientBorder(size: size + 20.0,
color: WalletColors().primaryAccent,
background: WalletColors().backgroundColor)
- QRGeneratorView(text: talerURI, size: size, logo: logo, logoSize: logoSize, image: $qrImage)
+ QRGeneratorView(text: talerURI, size: size,
+ logo: logo, logoSize: logoSize,
+ image: qrImage)
.frame(maxWidth: .infinity, alignment: .center)
}
if #available(iOS 17.7, *) {
@@ -105,6 +107,9 @@ struct QRCodeDetailView: View {
}
.task(id: controller.currencyTicker) { await currencyTickerChanged() }
.task {
+ if let image = QRCode(from: talerURI) {
+ qrImage = image
+ }
withAnimation {
if #available(iOS 17.7, *) {
showQRcode = showQRauto17
diff --git a/TalerWallet1/Views/OIM/OIMp2pReadyView.swift b/TalerWallet1/Views/OIM/OIMp2pReadyView.swift
@@ -27,7 +27,7 @@ struct OIMp2pReadyView: View {
// let _ = Self._printChanges()
OIMbackground() {
- VStack {
+ Group {
if let transactionId {
if talerTX.isPendingReady {
let details = talerTX.detailsToShow()
@@ -35,14 +35,21 @@ struct OIMp2pReadyView: View {
if keys.contains(TALERURI) {
if let talerURI = details[TALERURI] {
if talerURI.count > 10 {
- Group {
+ VStack {
Spacer()
let size = 240.0
- QRGeneratorView(text: talerURI, size: size, logo: nil, logoSize: size / 4, image: $qrImage)
+ QRGeneratorView(text: talerURI, size: size,
+ logo: nil, logoSize: size / 4,
+ image: qrImage)
.frame(maxWidth: .infinity, alignment: .center)
.accessibilityLabel(Text("QR Code", comment: "a11y"))
Spacer()
}
+ .task {
+ if let image = QRCode(from: talerURI) {
+ qrImage = image
+ }
+ }
}
}
}
diff --git a/TalerWallet1/Views/Transactions/QRcodesForPayto.swift b/TalerWallet1/Views/Transactions/QRcodesForPayto.swift
@@ -29,27 +29,27 @@ struct QRcodeCopyShare: View {
}
var body: some View {
-// Text(spec.type)
+ let textToShare = textToShare()
if let qrCodes = option.qrCodes {
ForEach(qrCodes, id: \.self) { qrCodeSpec in
let logo = qrCodeSpec.type == "spc" ? Image(SWISS_QR) : nil
let size = 276.0 // 46x46mm, swiss flag = 7x7mm plus border 276*9/46 = 54
- QRGeneratorView(text: qrCodeSpec.qrContent, size: size,
- logo: logo, logoSize: size * 9 / 46,
- image: $qrImage)
- .frame(maxWidth: .infinity, alignment: .center)
- .listRowSeparator(.hidden)
- }
- }
- if let textToShare = textToShare() {
- HStack {
-// Text(verbatim: "|") // only reason for this leading-aligned text is to get a nice full length listRowSeparator
-// .accessibilityHidden(true)
-// .foregroundColor(Color.clear)
-// Spacer()
- CopyShare(stack.push(), textToShare, image: qrImage)
- .disabled(false)
+ let image = QRCode(from: qrCodeSpec.qrContent)
+ if let image {
+ QRGeneratorView(text: qrCodeSpec.qrContent, size: size,
+ logo: logo, logoSize: size * 9 / 46,
+ image: image)
+ .frame(maxWidth: .infinity, alignment: .center)
+ .listRowSeparator(.hidden)
+ }
+ if let textToShare {
+ CopyShare(stack.push(), textToShare, image: image)
+ .disabled(false)
+ }
}
+ } else if let textToShare {
+ CopyShare(stack.push(), textToShare)
+ .disabled(false)
}
}
}