|
|
|
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
|
|
|
|
|
|
|
import UIKit
|
|
|
|
|
|
|
|
enum QRCode {
|
|
|
|
/// Generates a QRCode for the give string
|
|
|
|
///
|
|
|
|
/// **Note:** If the `hasBackground` value is true then the QRCode will be black and white and
|
|
|
|
/// the `withRenderingMode(.alwaysTemplate)` won't work correctly on some iOS versions (eg. iOS 16)
|
|
|
|
static func generate(for string: String, hasBackground: Bool) -> UIImage {
|
|
|
|
let data = string.data(using: .utf8)
|
|
|
|
var qrCodeAsCIImage: CIImage
|
|
|
|
let filter1 = CIFilter(name: "CIQRCodeGenerator")! // stringlint:disable
|
|
|
|
filter1.setValue(data, forKey: "inputMessage")
|
|
|
|
qrCodeAsCIImage = filter1.outputImage!
|
|
|
|
|
|
|
|
guard !hasBackground else {
|
|
|
|
let filter2 = CIFilter(name: "CIFalseColor")! // stringlint:disable
|
|
|
|
filter2.setValue(qrCodeAsCIImage, forKey: "inputImage")
|
|
|
|
filter2.setValue(CIColor(color: .black), forKey: "inputColor0")
|
|
|
|
filter2.setValue(CIColor(color: .white), forKey: "inputColor1")
|
|
|
|
qrCodeAsCIImage = filter2.outputImage!
|
|
|
|
|
|
|
|
let scaledQRCodeAsCIImage = qrCodeAsCIImage.transformed(by: CGAffineTransform(scaleX: 6.4, y: 6.4))
|
|
|
|
return UIImage(ciImage: scaledQRCodeAsCIImage)
|
|
|
|
}
|
|
|
|
|
|
|
|
let filter2 = CIFilter(name: "CIColorInvert")! // stringlint:disable
|
|
|
|
filter2.setValue(qrCodeAsCIImage, forKey: "inputImage")
|
|
|
|
qrCodeAsCIImage = filter2.outputImage!
|
|
|
|
let filter3 = CIFilter(name: "CIMaskToAlpha")! // stringlint:disable
|
|
|
|
filter3.setValue(qrCodeAsCIImage, forKey: "inputImage")
|
|
|
|
qrCodeAsCIImage = filter3.outputImage!
|
|
|
|
|
|
|
|
let scaledQRCodeAsCIImage = qrCodeAsCIImage.transformed(by: CGAffineTransform(scaleX: 6.4, y: 6.4))
|
|
|
|
|
|
|
|
// Note: It looks like some internal method was changed in iOS 16.0 where images
|
|
|
|
// generated from a CIImage don't have the same color information as normal images
|
|
|
|
// as a result tinting using the `alwaysTemplate` rendering mode won't work - to
|
|
|
|
// work around this we convert the image to data and then back into an image
|
|
|
|
let imageData: Data = UIImage(ciImage: scaledQRCodeAsCIImage).pngData()!
|
|
|
|
return UIImage(data: imageData)!
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
import SwiftUI
|
|
|
|
import SessionUIKit
|
|
|
|
|
|
|
|
struct QRCodeView: View {
|
|
|
|
let string: String
|
|
|
|
let hasBackground: Bool
|
|
|
|
let logo: String?
|
|
|
|
let themeStyle: UIUserInterfaceStyle
|
|
|
|
var backgroundThemeColor: ThemeValue {
|
|
|
|
switch themeStyle {
|
|
|
|
case .light:
|
|
|
|
return .backgroundSecondary
|
|
|
|
default:
|
|
|
|
return .textPrimary
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var qrCodeThemeColor: ThemeValue {
|
|
|
|
switch themeStyle {
|
|
|
|
case .light:
|
|
|
|
return .textPrimary
|
|
|
|
default:
|
|
|
|
return .backgroundPrimary
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static private var cornerRadius: CGFloat = 10
|
|
|
|
static private var logoSize: CGFloat = 66
|
|
|
|
|
|
|
|
var body: some View {
|
|
|
|
ZStack(alignment: .center) {
|
|
|
|
ZStack(alignment: .center) {
|
|
|
|
RoundedRectangle(cornerRadius: Self.cornerRadius)
|
|
|
|
.fill(themeColor: backgroundThemeColor)
|
|
|
|
|
|
|
|
Image(uiImage: QRCode.generate(for: string, hasBackground: hasBackground))
|
|
|
|
.resizable()
|
|
|
|
.renderingMode(.template)
|
|
|
|
.foregroundColor(themeColor: qrCodeThemeColor)
|
|
|
|
.scaledToFit()
|
|
|
|
.frame(
|
|
|
|
maxWidth: .infinity,
|
|
|
|
maxHeight: .infinity
|
|
|
|
)
|
|
|
|
.padding(.vertical, Values.smallSpacing)
|
|
|
|
|
|
|
|
if let logo = logo {
|
|
|
|
ZStack(alignment: .center) {
|
|
|
|
Rectangle()
|
|
|
|
.fill(themeColor: backgroundThemeColor)
|
|
|
|
|
|
|
|
Image(logo)
|
|
|
|
.resizable()
|
|
|
|
.renderingMode(.template)
|
|
|
|
.foregroundColor(themeColor: qrCodeThemeColor)
|
|
|
|
.scaledToFit()
|
|
|
|
.frame(
|
|
|
|
maxWidth: .infinity,
|
|
|
|
maxHeight: .infinity
|
|
|
|
)
|
|
|
|
.padding(.all, 4)
|
|
|
|
}
|
|
|
|
.frame(
|
|
|
|
width: Self.logoSize,
|
|
|
|
height: Self.logoSize
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.frame(
|
|
|
|
maxWidth: 400,
|
|
|
|
maxHeight: 400
|
|
|
|
)
|
|
|
|
}
|
|
|
|
.frame(maxWidth: .infinity)
|
|
|
|
}
|
|
|
|
}
|