Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

- [*] My Store: A new button to share the current store is added on the top right of the screen. [https://github.com/woocommerce/woocommerce-ios/pull/9796]
- [*] Mobile Payments: The screen brightness is increased when showing the Scan to Pay view so the QR code can be scanned more easily [https://github.com/woocommerce/woocommerce-ios/pull/9807]
- [*] Mobile Payments: The Woo logo is added to the QR code on the Scan to Pay screen [https://github.com/woocommerce/woocommerce-ios/pull/9823]
- [*] Allow EU merchants to have better control of their privacy choices. A privacy choices banner will be shown the next time they open the app.

13.7
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation
import CoreImage.CIFilterBuiltins
import UIKit
import WooFoundation

struct ScanToPayViewModel {
private let paymentURL: URL?
Expand All @@ -10,19 +10,12 @@ struct ScanToPayViewModel {
}

func generateQRCodeImage() -> UIImage? {
guard let paymentURLString = paymentURL?.absoluteString else {
return nil
guard let logoImage = UIImage
.wooLogoImage()?
.withBackground(color: .black) else {
return paymentURL?.generateQRCode()
}

let context = CIContext()
let filter = CIFilter.qrCodeGenerator()
filter.message = Data(paymentURLString.utf8)

guard let outputImage = filter.outputImage,
let cgImage = context.createCGImage(outputImage, from: outputImage.extent) else {
return nil
}

return UIImage(cgImage: cgImage)
return paymentURL?.generateQRCode(combinedWith: logoImage)
}
}
12 changes: 12 additions & 0 deletions WooFoundation/WooFoundation.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
B97190D1292CF3BC0065E413 /* Result+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B97190D0292CF3BC0065E413 /* Result+Extensions.swift */; };
B987B06F284540D300C53CF6 /* CurrencyCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = B987B06E284540D300C53CF6 /* CurrencyCode.swift */; };
B99686DE2A13B38B00D1AF62 /* FullScreenCoverClearBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99686DD2A13B38B00D1AF62 /* FullScreenCoverClearBackgroundView.swift */; };
B99BC2122A1FAE5100E6008A /* CIImage+ImageCombination.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99BC2112A1FAE5100E6008A /* CIImage+ImageCombination.swift */; };
B99BC2142A1FAEBC00E6008A /* URL+QRCodeGeneration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99BC2132A1FAEBC00E6008A /* URL+QRCodeGeneration.swift */; };
B99BC2162A1FB21700E6008A /* UIImage+Background.swift in Sources */ = {isa = PBXBuildFile; fileRef = B99BC2152A1FB21700E6008A /* UIImage+Background.swift */; };
B9C9C63F283E703C001B879F /* WooFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B9C9C635283E703C001B879F /* WooFoundation.framework */; };
B9C9C659283E7195001B879F /* NSDecimalNumber+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C9C658283E7195001B879F /* NSDecimalNumber+Helpers.swift */; };
B9C9C65D283E71C8001B879F /* CurrencyFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C9C65B283E71C8001B879F /* CurrencyFormatter.swift */; };
Expand Down Expand Up @@ -84,6 +87,9 @@
B97190D0292CF3BC0065E413 /* Result+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Result+Extensions.swift"; sourceTree = "<group>"; };
B987B06E284540D300C53CF6 /* CurrencyCode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CurrencyCode.swift; sourceTree = "<group>"; };
B99686DD2A13B38B00D1AF62 /* FullScreenCoverClearBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenCoverClearBackgroundView.swift; sourceTree = "<group>"; };
B99BC2112A1FAE5100E6008A /* CIImage+ImageCombination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CIImage+ImageCombination.swift"; sourceTree = "<group>"; };
B99BC2132A1FAEBC00E6008A /* URL+QRCodeGeneration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "URL+QRCodeGeneration.swift"; sourceTree = "<group>"; };
B99BC2152A1FB21700E6008A /* UIImage+Background.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Background.swift"; sourceTree = "<group>"; };
B9AED558283E7553002A2668 /* Yosemite.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Yosemite.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B9AED55B283E755A002A2668 /* Hardware.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Hardware.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B9C9C635283E703C001B879F /* WooFoundation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = WooFoundation.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -252,6 +258,9 @@
68FBC5B228926B2C00A05461 /* Collection+Extensions.swift */,
03B8C3882914083F002235B1 /* Bundle+Woo.swift */,
B97190D0292CF3BC0065E413 /* Result+Extensions.swift */,
B99BC2112A1FAE5100E6008A /* CIImage+ImageCombination.swift */,
B99BC2132A1FAEBC00E6008A /* URL+QRCodeGeneration.swift */,
B99BC2152A1FB21700E6008A /* UIImage+Background.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -481,7 +490,9 @@
buildActionMask = 2147483647;
files = (
03B8C3892914083F002235B1 /* Bundle+Woo.swift in Sources */,
B99BC2122A1FAE5100E6008A /* CIImage+ImageCombination.swift in Sources */,
B9C9C659283E7195001B879F /* NSDecimalNumber+Helpers.swift in Sources */,
B99BC2162A1FB21700E6008A /* UIImage+Background.swift in Sources */,
26AF1F5328B8362800937BA9 /* UIColor+SemanticColors.swift in Sources */,
03597A9B28F87BFC005E4A98 /* WooCommerceComUTMProvider.swift in Sources */,
B9C9C663283E7296001B879F /* Logging.swift in Sources */,
Expand All @@ -502,6 +513,7 @@
26AF1F5528B8362800937BA9 /* UIColor+ColorStudio.swift in Sources */,
26AF1F5428B8362800937BA9 /* ColorStudio.swift in Sources */,
68FBC5B328926B2C00A05461 /* Collection+Extensions.swift in Sources */,
B99BC2142A1FAEBC00E6008A /* URL+QRCodeGeneration.swift in Sources */,
B99686DE2A13B38B00D1AF62 /* FullScreenCoverClearBackgroundView.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import CoreImage.CIFilterBuiltins

extension CIImage {
/// Combines the current image with the given image centered.
///
func combined(with image: CIImage) -> CIImage? {
guard let combinedFilter = CIFilter(name: "CISourceOverCompositing") else {
return nil
}

let centerTransform = CGAffineTransform(translationX: extent.midX - (image.extent.size.width / 2), y: extent.midY - (image.extent.size.height / 2))
combinedFilter.setValue(image.transformed(by: centerTransform), forKey: "inputImage")
combinedFilter.setValue(self, forKey: "inputBackgroundImage")

return combinedFilter.outputImage
}
}
28 changes: 28 additions & 0 deletions WooFoundation/WooFoundation/Extensions/UIImage+Background.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import UIKit

public extension UIImage {
/// Adds a background color to the given UIImage, setting also whether it should be opaque or not
///
func withBackground(color: UIColor, opaque: Bool = true) -> UIImage {
UIGraphicsBeginImageContextWithOptions(size, opaque, scale)

guard let currentContext = UIGraphicsGetCurrentContext(),
let image = cgImage else {
return self
}

defer { UIGraphicsEndImageContext() }

let rect = CGRect(origin: .zero, size: size)
currentContext.setFillColor(color.cgColor)
currentContext.fill(rect)

// Because the coordinate system in Core Graphics is different from that of UIKit,
// we need to flip the context vertically, and then translate it vertically
currentContext.scaleBy(x: 1, y: -1)
currentContext.translateBy(x: 0, y: -size.height)
currentContext.draw(image, in: rect)

return UIGraphicsGetImageFromCurrentImageContext() ?? self
}
}
39 changes: 39 additions & 0 deletions WooFoundation/WooFoundation/Extensions/URL+QRCodeGeneration.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import Foundation
import UIKit

public extension URL {
/// Returns a black and white QR UIImage code for this URL.
///
func generateQRCode() -> UIImage? {
guard let outputImage = generateQRCodeCIImage(),
let cgImage = CIContext().createCGImage(outputImage, from: outputImage.extent) else {
return nil
}

return UIImage(cgImage: cgImage)
}


/// Returns a black and white QR code for this URL, adding the passed image centered.
///
func generateQRCode(combinedWith image: UIImage) -> UIImage? {
guard let outputImage = generateQRCodeCIImage(),
let cgLogoImage = image.cgImage,
let combinedImage = outputImage.combined(with: CIImage(cgImage: cgLogoImage)),
let cgImage = CIContext().createCGImage(combinedImage, from: combinedImage.extent) else {
return nil
}

return UIImage(cgImage: cgImage)
}

/// Returns a black and white QR CIImage code for this URL.
///
private func generateQRCodeCIImage() -> CIImage? {
let filter = CIFilter.qrCodeGenerator()
filter.message = Data(absoluteString.utf8)

let qrTransform = CGAffineTransform(scaleX: 12, y: 12)
return filter.outputImage?.transformed(by: qrTransform)
}
}