From e421cdb176cb488927e65af81b2869e607369626 Mon Sep 17 00:00:00 2001 From: dankito Date: Sun, 15 Nov 2020 02:29:10 +0100 Subject: [PATCH] Implemented generating EPC QR code on iOS --- .../EpcQrCodeiOSApp.xcodeproj/project.pbxproj | 50 +++++++- .../EpcQrCodeiOSApp/ContentView.swift | 108 +++++++++++++++++- .../EpcQrCodeiOSApp/LabelledTextField.swift | 42 +++++++ .../de.lproj/LaunchScreen.strings | 1 + .../de.lproj/Localizable.strings | 8 ++ .../en.lproj/Localizable.strings | 8 ++ 6 files changed, 215 insertions(+), 2 deletions(-) create mode 100644 EpcQrCodeiOSApp/EpcQrCodeiOSApp/LabelledTextField.swift create mode 100644 EpcQrCodeiOSApp/EpcQrCodeiOSApp/de.lproj/LaunchScreen.strings create mode 100644 EpcQrCodeiOSApp/EpcQrCodeiOSApp/de.lproj/Localizable.strings create mode 100644 EpcQrCodeiOSApp/EpcQrCodeiOSApp/en.lproj/Localizable.strings diff --git a/EpcQrCodeiOSApp/EpcQrCodeiOSApp.xcodeproj/project.pbxproj b/EpcQrCodeiOSApp/EpcQrCodeiOSApp.xcodeproj/project.pbxproj index fa6e4d6..0831f14 100644 --- a/EpcQrCodeiOSApp/EpcQrCodeiOSApp.xcodeproj/project.pbxproj +++ b/EpcQrCodeiOSApp/EpcQrCodeiOSApp.xcodeproj/project.pbxproj @@ -3,10 +3,13 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ + 368A7CDD2560A48900252D96 /* LabelledTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 368A7CDC2560A48900252D96 /* LabelledTextField.swift */; }; + 368A7CEC2560A93500252D96 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 368A7CEE2560A93500252D96 /* Localizable.strings */; }; + 368A7CFA2560B2A000252D96 /* ZXingObjC in Frameworks */ = {isa = PBXBuildFile; productRef = 368A7CF92560B2A000252D96 /* ZXingObjC */; }; 7555FF7F242A565900829871 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF7E242A565900829871 /* AppDelegate.swift */; }; 7555FF81242A565900829871 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF80242A565900829871 /* SceneDelegate.swift */; }; 7555FF83242A565900829871 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* ContentView.swift */; }; @@ -51,6 +54,9 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 368A7CDC2560A48900252D96 /* LabelledTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelledTextField.swift; sourceTree = ""; }; + 368A7CED2560A93500252D96 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = ""; }; + 368A7CF12560A94C00252D96 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; 7555FF7B242A565900829871 /* EpcQrCodeiOSApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = EpcQrCodeiOSApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 7555FF7E242A565900829871 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7555FF80242A565900829871 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -74,6 +80,7 @@ buildActionMask = 2147483647; files = ( 7555FFB2242A642300829871 /* EpcQrCode.framework in Frameworks */, + 368A7CFA2560B2A000252D96 /* ZXingObjC in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -125,6 +132,8 @@ 7555FF89242A565B00829871 /* LaunchScreen.storyboard */, 7555FF8C242A565B00829871 /* Info.plist */, 7555FF86242A565B00829871 /* Preview Content */, + 368A7CDC2560A48900252D96 /* LabelledTextField.swift */, + 368A7CEE2560A93500252D96 /* Localizable.strings */, ); path = EpcQrCodeiOSApp; sourceTree = ""; @@ -181,6 +190,9 @@ dependencies = ( ); name = EpcQrCodeiOSApp; + packageProductDependencies = ( + 368A7CF92560B2A000252D96 /* ZXingObjC */, + ); productName = EpcQrCodeiOSApp; productReference = 7555FF7B242A565900829871 /* EpcQrCodeiOSApp.app */; productType = "com.apple.product-type.application"; @@ -251,8 +263,12 @@ knownRegions = ( en, Base, + de, ); mainGroup = 7555FF72242A565900829871; + packageReferences = ( + 368A7CF82560B2A000252D96 /* XCRemoteSwiftPackageReference "zxingify-objc" */, + ); productRefGroup = 7555FF7C242A565900829871 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -270,6 +286,7 @@ buildActionMask = 2147483647; files = ( 7555FF8B242A565B00829871 /* LaunchScreen.storyboard in Resources */, + 368A7CEC2560A93500252D96 /* Localizable.strings in Resources */, 7555FF88242A565B00829871 /* Preview Assets.xcassets in Resources */, 7555FF85242A565B00829871 /* Assets.xcassets in Resources */, ); @@ -316,6 +333,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 368A7CDD2560A48900252D96 /* LabelledTextField.swift in Sources */, 7555FF7F242A565900829871 /* AppDelegate.swift in Sources */, 7555FF81242A565900829871 /* SceneDelegate.swift in Sources */, 7555FF83242A565900829871 /* ContentView.swift in Sources */, @@ -354,6 +372,15 @@ /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ + 368A7CEE2560A93500252D96 /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 368A7CED2560A93500252D96 /* en */, + 368A7CF12560A94C00252D96 /* de */, + ); + name = Localizable.strings; + sourceTree = ""; + }; 7555FF89242A565B00829871 /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -369,6 +396,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -429,6 +457,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -643,6 +672,25 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 368A7CF82560B2A000252D96 /* XCRemoteSwiftPackageReference "zxingify-objc" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/zxingify/zxingify-objc"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 3.6.7; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 368A7CF92560B2A000252D96 /* ZXingObjC */ = { + isa = XCSwiftPackageProductDependency; + package = 368A7CF82560B2A000252D96 /* XCRemoteSwiftPackageReference "zxingify-objc" */; + productName = ZXingObjC; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 7555FF73242A565900829871 /* Project object */; } diff --git a/EpcQrCodeiOSApp/EpcQrCodeiOSApp/ContentView.swift b/EpcQrCodeiOSApp/EpcQrCodeiOSApp/ContentView.swift index 54e91a4..a962a45 100644 --- a/EpcQrCodeiOSApp/EpcQrCodeiOSApp/ContentView.swift +++ b/EpcQrCodeiOSApp/EpcQrCodeiOSApp/ContentView.swift @@ -1,13 +1,119 @@ import SwiftUI import EpcQrCode +import ZXingObjC struct ContentView: View { + + static private let ImageWidth: CGFloat = 350 + + static private let ImageHeight = Self.ImageWidth + + + @State private var receiver: String = "" + + @State private var iban: String = "" + + @State private var bic: String = "" + + @State private var amount: String = "" + + @State private var reference: String = "" + + + @State private var generatedQrCode: UIImage? = nil + + var body: some View { - Text(MppTest().showMessage()) + VStack { + Form { + Section { + LabelledTextField("Receiver", $receiver) + } + + Section { + LabelledTextField("IBAN", $iban) + + LabelledTextField("BIC", $bic) + } + + Section { + HStack { + Text("Amount") + + Spacer() + + TextField("", text: $amount) + .multilineTextAlignment(.trailing) + .keyboardType(.numberPad) + } + + VStack(alignment: .leading) { + Text("Reference") + + TextField("", text: $reference) + } + } + + Section { + Button(action: self.generateQRCode) { + HStack { + Spacer() + + Text("Generate") + + Spacer() + } + } + } + + if let generatedQrCode = generatedQrCode { + Section { + VStack(alignment: .center) { + Image(uiImage: generatedQrCode) + .resizable() + } + } + } + } + } + } + + + private func generateQRCode() { + let creator = EpcQrCodeCreator() + let param = CreatorParam(receiverName: receiver, iban: iban, bic: bic, amount: map(amount), reference: reference, noteToUser: nil, encoding: .utf8) + + let qrCodeContent = creator.generateAsString(param: param) + + self.generatedQrCode = generateQRCode(qrCodeContent) + } + + private func map(_ amount: String) -> KotlinDouble? { + if let double = Double(amount.replacingOccurrences(of: ",", with: ".")) { + return KotlinDouble(double: double) + } + + return nil + } + + private func generateQRCode(_ informationToEncode: String) -> UIImage? { + let writer = ZXQRCodeWriter() + + let hints = ZXEncodeHints() + hints.errorCorrectionLevel = ZXQRCodeErrorCorrectionLevel.errorCorrectionLevelM() + + if let result = try? writer.encode(informationToEncode, format: kBarcodeFormatQRCode, width: Int32(Self.ImageWidth), height: Int32(Self.ImageHeight), hints: hints) { + if let cgImage = ZXImage(matrix: result)?.cgimage { + return UIImage(cgImage: cgImage) + } + } + + return nil } } + struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() diff --git a/EpcQrCodeiOSApp/EpcQrCodeiOSApp/LabelledTextField.swift b/EpcQrCodeiOSApp/EpcQrCodeiOSApp/LabelledTextField.swift new file mode 100644 index 0000000..4ac98e1 --- /dev/null +++ b/EpcQrCodeiOSApp/EpcQrCodeiOSApp/LabelledTextField.swift @@ -0,0 +1,42 @@ +import SwiftUI + + +struct LabelledTextField: View { + + private let label: LocalizedStringKey + + private var value: Binding + + private let placeholder: LocalizedStringKey + + + init(_ label: LocalizedStringKey, _ value: Binding, _ placeholder: LocalizedStringKey = "") { + self.label = label + + self.value = value + + self.placeholder = placeholder + } + + + var body: some View { + HStack { + Text(label) + + Spacer() + + TextField(placeholder, text: value) + .multilineTextAlignment(.trailing) + } + } + +} + + +struct LabelledTextField_Previews: PreviewProvider { + + static var previews: some View { + LabelledTextField("Label", .constant("Value")) + } + +} diff --git a/EpcQrCodeiOSApp/EpcQrCodeiOSApp/de.lproj/LaunchScreen.strings b/EpcQrCodeiOSApp/EpcQrCodeiOSApp/de.lproj/LaunchScreen.strings new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/EpcQrCodeiOSApp/EpcQrCodeiOSApp/de.lproj/LaunchScreen.strings @@ -0,0 +1 @@ + diff --git a/EpcQrCodeiOSApp/EpcQrCodeiOSApp/de.lproj/Localizable.strings b/EpcQrCodeiOSApp/EpcQrCodeiOSApp/de.lproj/Localizable.strings new file mode 100644 index 0000000..b4f40ad --- /dev/null +++ b/EpcQrCodeiOSApp/EpcQrCodeiOSApp/de.lproj/Localizable.strings @@ -0,0 +1,8 @@ + +"Receiver" = "Empfänger"; +"IBAN" = "IBAN"; +"BIC" = "BIC"; +"Amount" = "Betrag"; +"Reference" = "Verwendungszweck"; + +"Generate" = "Erzeugen"; diff --git a/EpcQrCodeiOSApp/EpcQrCodeiOSApp/en.lproj/Localizable.strings b/EpcQrCodeiOSApp/EpcQrCodeiOSApp/en.lproj/Localizable.strings new file mode 100644 index 0000000..bdbbff5 --- /dev/null +++ b/EpcQrCodeiOSApp/EpcQrCodeiOSApp/en.lproj/Localizable.strings @@ -0,0 +1,8 @@ + +"Receiver" = "Receiver"; +"IBAN" = "IBAN"; +"BIC" = "BIC"; +"Amount" = "Amount"; +"Reference" = "Reference"; + +"Generate" = "Generate";