taler-ios

iOS apps for GNU Taler (wallet)
Log | Files | Refs | README | LICENSE

commit 393c28b9fcaabca2901b5e29de16d8d2e0c61a34
parent 105c71b29ac1b2268460af09cb27f9deaaa5caa4
Author: Marc Stibane <marc@taler.net>
Date:   Tue,  9 Sep 2025 16:21:13 +0200

share image (QR)

Diffstat:
MTalerWallet1/Views/HelperViews/CopyShare.swift | 32++++++++++++++++++++++----------
MTalerWallet1/Views/HelperViews/QRCodeDetailView.swift | 5+++--
MTalerWallet1/Views/HelperViews/QRGeneratorView.swift | 34++++++++++++++++++++--------------
MTalerWallet1/Views/OIM/OIMp2pReadyView.swift | 3++-
MTalerWallet1/Views/Sheets/ShareSheet.swift | 10++++++++--
MTalerWallet1/Views/Transactions/QRcodesForPayto.swift | 38++++++++++++++++++++++++--------------
6 files changed, 79 insertions(+), 43 deletions(-)

diff --git a/TalerWallet1/Views/HelperViews/CopyShare.swift b/TalerWallet1/Views/HelperViews/CopyShare.swift @@ -12,20 +12,23 @@ import SymLog struct CopyButton: View { private let symLog = SymLogV(0) let textToCopy: String + let image: UIImage? let vertical: Bool let title: String? @Environment(\.isEnabled) private var isEnabled: Bool @EnvironmentObject private var controller: Controller - init(textToCopy: String, vertical: Bool) { + init(textToCopy: String, vertical: Bool, image: UIImage? = nil) { self.textToCopy = textToCopy + self.image = image self.vertical = vertical self.title = nil } - init(textToCopy: String, title: String) { + init(textToCopy: String, title: String, image: UIImage? = nil) { self.textToCopy = textToCopy + self.image = image self.vertical = false self.title = title } @@ -33,8 +36,13 @@ struct CopyButton: View { func copyAction() -> Void { symLog.log(textToCopy) controller.hapticFeedback(.medium) - UIPasteboard.general.setValue(textToCopy, - forPasteboardType: UTType.plainText.identifier) + let strings = [UTType.plainText.identifier : textToCopy] + var items: [[String : Any]] = [strings] + if let image { + let images = [UTType.image.identifier : image] + items.append(images) + } + UIPasteboard.general.setItems(items) } var body: some View { @@ -65,14 +73,17 @@ struct CopyButton: View { struct ShareButton: View { private let symLog = SymLogV(0) let textToShare: String + let image: UIImage? let title: String - init(textToShare: String) { + init(textToShare: String, image: UIImage? = nil) { self.textToShare = textToShare + self.image = image self.title = String(localized: "Share") } - init(textToShare: String, title: String) { + init(textToShare: String, title: String, image: UIImage? = nil) { self.textToShare = textToShare + self.image = image self.title = title } @@ -82,7 +93,7 @@ struct ShareButton: View { func shareAction() -> Void { symLog.log(textToShare) controller.hapticFeedback(.soft) - ShareSheet.shareSheet(textToShare: textToShare) + ShareSheet.shareSheet(textToShare: textToShare, image: image) } var body: some View { @@ -103,12 +114,13 @@ struct CopyShare: View { @Environment(\.isEnabled) private var isEnabled: Bool let textToCopy: String + let image: UIImage? var body: some View { HStack { - CopyButton(textToCopy: textToCopy, vertical: false) + CopyButton(textToCopy: textToCopy, vertical: false, image: image) .buttonStyle(TalerButtonStyle(type: .bordered)) - ShareButton(textToShare: textToCopy) + ShareButton(textToShare: textToCopy, image: image) .buttonStyle(TalerButtonStyle(type: .bordered)) } // two buttons } @@ -116,6 +128,6 @@ struct CopyShare: View { // MARK: - struct CopyShare_Previews: PreviewProvider { static var previews: some View { - CopyShare(textToCopy: "Hallö") + CopyShare(textToCopy: "Hallö", image: nil) } } diff --git a/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift b/TalerWallet1/Views/HelperViews/QRCodeDetailView.swift @@ -23,6 +23,7 @@ struct QRCodeDetailView: View { @State private var showQRcode = false @State private var currencyInfo: CurrencyInfo? + @State private var qrImage: UIImage? = nil private func currencyTickerChanged() async { if let scope { @@ -67,7 +68,7 @@ struct QRCodeDetailView: View { let scanLong = incoming ? (requesting(amountStr.0), requesting(amountStr.1)) : (sending(amountStr.0), sending(amountStr.1)) let size = 240.0 - let qrView = QRGeneratorView(text: talerURI, size: size) + let qrView = QRGeneratorView(text: talerURI, size: size, image: $qrImage) .frame(maxWidth: .infinity, alignment: .center) .accessibilityLabel(Text("QR Code", comment: "a11y")) if #available(iOS 17.7, *) { @@ -82,7 +83,7 @@ struct QRCodeDetailView: View { withAnimation { showQRcode = true } }.buttonStyle(TalerButtonStyle(type: .prominent)) } - CopyShare(textToCopy: talerCopyShare) + CopyShare(textToCopy: talerCopyShare, image: qrImage) .disabled(false) // .padding(.bottom) .listRowSeparator(.hidden) diff --git a/TalerWallet1/Views/HelperViews/QRGeneratorView.swift b/TalerWallet1/Views/HelperViews/QRGeneratorView.swift @@ -24,11 +24,12 @@ import SwiftUI struct QRGeneratorView: View { let text: String let size: CGFloat + @Binding var image: UIImage? var body: some View { - if let data = getQRCodeData(text: text) { - if let uiImage = UIImage(data: data) { - Image(uiImage: uiImage) + VStack { + if let image { + Image(uiImage: image) .interpolation(.none) .resizable() .scaledToFit() @@ -36,11 +37,17 @@ struct QRGeneratorView: View { } else { EmptyView() } - } else { - EmptyView() + }.onAppear { +// if let uiImage = getQRCode(text: text) { + if let data = getQRCodeData(text: text) { + if let uiImage = UIImage(data: data) { + image = uiImage + } + } } } +// func getQRCode(text: String) -> UIImage? { func getQRCodeData(text: String) -> Data? { guard let filter = CIFilter(name: "CIQRCodeGenerator") else { return nil } let data = text.data(using: .ascii, allowLossyConversion: false) @@ -53,12 +60,11 @@ struct QRGeneratorView: View { } } -struct QRGeneratorView_Previews: PreviewProvider { - static var previews: some View { - VStack { - QRGeneratorView(text: "Hello World!", size: 200) - QRGeneratorView(text: "taler://pay-pull/exchange.demo.taler.net/7J7SNHYMCCAZ1ARY9YCB5Z9FTY0YZP8F2KDRXV94KZCQ6WAVMTX0", - size: 200) - } - } -} +//#Preview { // 'Previewable()' is only available in iOS 17.0 or newer +// @Previewable @State var image: UIImage? +// VStack { +// QRGeneratorView(text: "Hello World!", size: 200, image: $image) +// QRGeneratorView(text: "taler://pay-pull/exchange.demo.taler.net/7J7SNHYMCCAZ1ARY9YCB5Z9FTY0YZP8F2KDRXV94KZCQ6WAVMTX0", +// size: 200, image: $image) +// } +//} diff --git a/TalerWallet1/Views/OIM/OIMp2pReadyView.swift b/TalerWallet1/Views/OIM/OIMp2pReadyView.swift @@ -21,6 +21,7 @@ struct OIMp2pReadyView: View { @State private var sending = false // user tapped on Send @State private var appeared = false + @State private var qrImage: UIImage? = nil var body: some View { // let _ = Self._printChanges() @@ -37,7 +38,7 @@ struct OIMp2pReadyView: View { Group { Spacer() let size = 240.0 - QRGeneratorView(text: talerURI, size: size) + QRGeneratorView(text: talerURI, size: size, image: $qrImage) .frame(maxWidth: .infinity, alignment: .center) .accessibilityLabel(Text("QR Code", comment: "a11y")) Spacer() diff --git a/TalerWallet1/Views/Sheets/ShareSheet.swift b/TalerWallet1/Views/Sheets/ShareSheet.swift @@ -23,14 +23,20 @@ import SymLog public class ShareSheet: ObservableObject { - @MainActor static func shareSheet(textToShare: String) { + @MainActor + static func shareSheet(textToShare: String, image: UIImage?) { let plainString: String? if #available(iOS 18.3, *) { plainString = textToShare.removingPercentEncoding } else { plainString = textToShare } - let activityView = UIActivityViewController(activityItems: [plainString as Any], applicationActivities: nil) +// var strings + var items: [Any] = [plainString as Any] + if let image { + items.append(image as Any) + } + let activityView = UIActivityViewController(activityItems: items, applicationActivities: nil) let allScenes = UIApplication.shared.connectedScenes let scene = allScenes.first { $0.activationState == .foregroundActive } diff --git a/TalerWallet1/Views/Transactions/QRcodesForPayto.swift b/TalerWallet1/Views/Transactions/QRcodesForPayto.swift @@ -9,6 +9,29 @@ import SwiftUI import OrderedCollections import taler_swift +struct QRcodeCopyShare: View { + let spec: QrCodeSpec + + @State private var qrImage: UIImage? = nil + + var body: some View { + Text(spec.type) + let size = 200.0 + QRGeneratorView(text: spec.qrContent, size: size, image: $qrImage) + .frame(maxWidth: .infinity, alignment: .center) + .accessibilityLabel(Text("QR Code", comment: "a11y")) + .listRowSeparator(.hidden) + 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(textToCopy: spec.qrContent, image: qrImage) + .disabled(false) + }.listRowSeparator(.automatic) + } +} + struct QRcodesForPayto: View { let stack: CallStack @Binding var qrCodeSpecs: [QrCodeSpec] @@ -23,20 +46,7 @@ struct QRcodesForPayto: View { .listRowSeparator(.hidden) } ForEach(qrCodeSpecs, id: \.self) { spec in - let size = 200.0 - Text(spec.type) - QRGeneratorView(text: spec.qrContent, size: size) - .frame(maxWidth: .infinity, alignment: .center) - .accessibilityLabel(Text("QR Code", comment: "a11y")) - .listRowSeparator(.hidden) - 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(textToCopy: spec.qrContent) - .disabled(false) - }.listRowSeparator(.automatic) + QRcodeCopyShare(spec: spec) } } .navigationTitle(navTitle)