Step 7: request ZEC QR Code

This commit is contained in:
Francisco Gindre 2021-02-24 23:09:21 -03:00
parent c4bea8c3f1
commit dbdeb8bcc7
9 changed files with 187 additions and 6 deletions

View File

@ -344,4 +344,35 @@ We can do this and many more things with the `DerivationTool` class of the Zcash
Unfortunately this screen is really helpful. we need to get some QR code so that the user can scan the address! We will see that on the next step
## Tag: `step-7-request-zec-qr-code`
On this step we are just going to request zec in a decent way that's useful to our customers. For that we will have to create a QR Code Image and display in on screen. Fortunately our ECC Wallet App already does this and we are going to borrow some code from it.
The first thing we need is a QR Code generator. iOS already does that pretty well, but the API is somewhat rough. So we created this helper class called `QRCodeGenerator`
We are going to add this snippet to the `RequestZec` screen struct
````
// This Generates the QR Image
var qrImage: Image {
if let zAddr = self.zAddress, let img = QRCodeGenerator.generate(from: zAddr) {
return Image(img, scale: 1, label: Text(String(format:NSLocalizedString("QR Code for %@", comment: ""),"\(zAddr)") ))
} else {
return Image("zebra_profile")
}
}
````
and also this one to the body of the view so that the qr code is show. or a nice zebra placeholder otherwise
````
QRCodeContainer(qrImage: qrImage,
badge: Image("QR-zcashlogo"))
.frame(width: qrSize, height: qrSize, alignment: .center)
.layoutPriority(1)
````
We borrowed some nice assets from the wallet too! A cool zebra, and a nice shield for our QR code.
And that's it! Customers will be able to scan our Zcash Sapling Address!
Our next step will be receiving the transactions.

View File

@ -15,6 +15,8 @@
0D08DEAA25E70D8400E08533 /* SettingsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D08DEA925E70D8400E08533 /* SettingsScreen.swift */; };
0D08DEAD25E71D4500E08533 /* RequestZec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D08DEAC25E71D4500E08533 /* RequestZec.swift */; };
0D08DEB025E732C900E08533 /* Zboto.otf in Resources */ = {isa = PBXBuildFile; fileRef = 0D08DEAF25E732C900E08533 /* Zboto.otf */; };
0D08DEB325E7397A00E08533 /* QRCodeGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D08DEB225E7397A00E08533 /* QRCodeGenerator.swift */; };
0D08DEB625E73B7000E08533 /* QRCodeContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D08DEB525E73B7000E08533 /* QRCodeContainer.swift */; };
0D475B2125E3ED600067978E /* CombineSynchronizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D475B2025E3ED600067978E /* CombineSynchronizer.swift */; };
0D475B2725E3EEE10067978E /* DetailModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D475B2625E3EEE10067978E /* DetailModel.swift */; };
0D475B2A25E3F04C0067978E /* String+Zcash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0D475B2925E3F04C0067978E /* String+Zcash.swift */; };
@ -51,6 +53,8 @@
0D08DEA925E70D8400E08533 /* SettingsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsScreen.swift; sourceTree = "<group>"; };
0D08DEAC25E71D4500E08533 /* RequestZec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestZec.swift; sourceTree = "<group>"; };
0D08DEAF25E732C900E08533 /* Zboto.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Zboto.otf; sourceTree = "<group>"; };
0D08DEB225E7397A00E08533 /* QRCodeGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRCodeGenerator.swift; sourceTree = "<group>"; };
0D08DEB525E73B7000E08533 /* QRCodeContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QRCodeContainer.swift; sourceTree = "<group>"; };
0D475B2025E3ED600067978E /* CombineSynchronizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CombineSynchronizer.swift; sourceTree = "<group>"; };
0D475B2625E3EEE10067978E /* DetailModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailModel.swift; sourceTree = "<group>"; };
0D475B2925E3F04C0067978E /* String+Zcash.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Zcash.swift"; sourceTree = "<group>"; };
@ -173,8 +177,9 @@
0D5051A625E059D800E7A697 /* UI Elements */ = {
isa = PBXGroup;
children = (
0D475B2925E3F04C0067978E /* String+Zcash.swift */,
0D08DEB525E73B7000E08533 /* QRCodeContainer.swift */,
0D5051C325E079DE00E7A697 /* ZcashButton.swift */,
0D475B2925E3F04C0067978E /* String+Zcash.swift */,
0D5051C025E0797C00E7A697 /* ZcashButtonBackground.swift */,
0D50519925E0591B00E7A697 /* ZcashBackground.swift */,
0D50519C25E0596B00E7A697 /* ZcashTextField.swift */,
@ -190,6 +195,7 @@
0D5051B825E076C200E7A697 /* Utils */ = {
isa = PBXGroup;
children = (
0D08DEB225E7397A00E08533 /* QRCodeGenerator.swift */,
0D475B2F25E3F34E0067978E /* SimpleLogger.swift */,
0D475B2C25E3F2E50067978E /* BalanceUtils.swift */,
0D5051BA25E0775800E7A697 /* UIResponder+Current.swift */,
@ -346,9 +352,11 @@
0D5051C425E079DE00E7A697 /* ZcashButton.swift in Sources */,
0D5051AE25E066E300E7A697 /* ZcashLogo.swift in Sources */,
0D50519D25E0596B00E7A697 /* ZcashTextField.swift in Sources */,
0D08DEB325E7397A00E08533 /* QRCodeGenerator.swift in Sources */,
0D5051BB25E0775800E7A697 /* UIResponder+Current.swift in Sources */,
0D5051A325E0599800E7A697 /* ZcashSymbol.swift in Sources */,
0D50519725E0583500E7A697 /* Colors.swift in Sources */,
0D08DEB625E73B7000E08533 /* QRCodeContainer.swift in Sources */,
0D5051A425E0599800E7A697 /* Ring.swift in Sources */,
0D08DE7025E6CA6800E08533 /* AlertType.swift in Sources */,
0D5051A225E0599800E7A697 /* Baseline.swift in Sources */,

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "QR-zcashlogo.pdf",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "zebra_profile.pdf",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,37 @@
//
// QRCodeContainer.swift
// wallet
//
// Created by Francisco Gindre on 1/3/20.
// Copyright © 2020 Francisco Gindre. All rights reserved.
//
import SwiftUI
struct QRCodeContainer: View {
var qrImage: Image
var badge: Image
var body: some View {
ZStack {
qrImage
.resizable()
.aspectRatio(contentMode: .fit)
badge
.resizable()
.frame(width: 64, height: 64)
}
}
}
struct QRCodeContainer_Previews: PreviewProvider {
static var previews: some View {
ZStack {
ZcashBackground()
QRCodeContainer(qrImage: Image("QrCode"),
badge: Image("QR-zcashlogo"))
.frame(width: 285, height: 285)
}
}
}

View File

@ -0,0 +1,51 @@
//
// QRCodeGenerator.swift
// wallet
//
// Created by Francisco Gindre on 2/3/20.
// Copyright © 2020 MIT License
//
import Foundation
import Combine
import CoreImage
import CoreImage.CIFilterBuiltins
import SwiftUI
class QRCodeGenerator {
enum QRCodeError: Error {
case failedToGenerate
}
static func generate(from string: String) -> Future<CGImage,QRCodeError> {
Future<CGImage,QRCodeError>() { promise in
DispatchQueue.global().async {
guard let image = generate(from: string) else {
promise(.failure(QRCodeGenerator.QRCodeError.failedToGenerate))
return
}
return promise(.success(image))
}
}
}
static func generate(from string: String, scale: CGFloat = 5) -> CGImage? {
let data = string.data(using: String.Encoding.utf8)
let context = CIContext()
let filter = CoreImage.CIFilter.qrCodeGenerator()
filter.setValue(data, forKey: "inputMessage")
let transform = CGAffineTransform(scaleX: scale, y: scale)
guard let output = filter.outputImage?.transformed(by: transform) else {
return nil
}
return context.createCGImage(output, from: output.extent)
}
}

View File

@ -11,14 +11,23 @@ struct RequestZec: View {
@EnvironmentObject var model: ZcashPoSModel
@State var zAddress: String? = nil
@State var alertType: AlertType? = nil
// This Generates the QR Image
var qrImage: Image {
if let zAddr = self.zAddress, let img = QRCodeGenerator.generate(from: zAddr) {
return Image(img, scale: 1, label: Text(String(format:NSLocalizedString("QR Code for %@", comment: ""),"\(zAddr)") ))
} else {
return Image("zebra_profile")
}
}
var body: some View {
ZStack {
ZcashBackground()
VStack(alignment: .center, spacing: 40){
Text("To This address:")
.foregroundColor(.white)
Text(zAddress ?? "Error Deriving Address")
.foregroundColor(.white)
QRCodeContainer(qrImage: qrImage,
badge: Image("QR-zcashlogo"))
.frame(width: 150, height: 150, alignment: .center)
.layoutPriority(1)
Text("$\(model.request.amount.toZecAmount())")
.lineLimit(1)
@ -29,10 +38,13 @@ struct RequestZec: View {
)
Text("Append Memo With this Code")
.foregroundColor(.white)
.font(.title2)
Text(model.request.code)
.foregroundColor(.white)
.font(.title)
.font(.system(size: 72))
}
}.navigationTitle("Pay with ZEC")
.onAppear() {