Add instant payment collection flow aligned with Android.

Implement收款详情与收款记录 pages with pay-code API, QR generation, amount setting, and record grouping so merchants can collect payments from the home quick action.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-07 09:29:03 +08:00
parent 731de7d7f0
commit d8329d19fd
17 changed files with 1548 additions and 1 deletions

View File

@ -0,0 +1,37 @@
//
// PhotoLibrarySaver.swift
// suixinkan
//
import Photos
import UIKit
/// 使
enum PhotoLibrarySaver {
///
static func saveImage(_ image: UIImage) async -> Bool {
let status = await requestAuthorizationIfNeeded()
guard status == .authorized || status == .limited else {
return false
}
return await withCheckedContinuation { continuation in
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAsset(from: image)
}, completionHandler: { success, _ in
continuation.resume(returning: success)
})
}
}
private static func requestAuthorizationIfNeeded() async -> PHAuthorizationStatus {
let current = PHPhotoLibrary.authorizationStatus(for: .addOnly)
switch current {
case .notDetermined:
return await PHPhotoLibrary.requestAuthorization(for: .addOnly)
default:
return current
}
}
}

View File

@ -0,0 +1,59 @@
//
// QRCodeGenerator.swift
// suixinkan
//
import CoreImage
import UIKit
/// Android `QrCodeUtils.generateStyledQrBitmap`
enum QRCodeGenerator {
private static let defaultPixelSize = 580
private static let defaultCornerRadius: CGFloat = 24
///
static func generateStyledQRCode(
content: String,
pixelSize: Int = defaultPixelSize,
backgroundColor: UIColor = AppColor.inputBackground,
cornerRadius: CGFloat = defaultCornerRadius
) -> UIImage? {
guard !content.isEmpty,
let qrImage = makeQRCodeImage(from: content, pixelSize: pixelSize) else {
return nil
}
let size = CGSize(width: pixelSize, height: pixelSize)
let format = UIGraphicsImageRendererFormat()
format.scale = 1
let renderer = UIGraphicsImageRenderer(size: size, format: format)
return renderer.image { context in
let rect = CGRect(origin: .zero, size: size)
let path = UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius)
backgroundColor.setFill()
path.fill()
context.cgContext.saveGState()
path.addClip()
qrImage.draw(in: rect)
context.cgContext.restoreGState()
}
}
private static func makeQRCodeImage(from content: String, pixelSize: Int) -> UIImage? {
guard let filter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
let data = Data(content.utf8)
filter.setValue(data, forKey: "inputMessage")
filter.setValue("M", forKey: "inputCorrectionLevel")
guard let outputImage = filter.outputImage else { return nil }
let scale = CGFloat(pixelSize) / outputImage.extent.width
let scaledImage = outputImage.transformed(by: CGAffineTransform(scaleX: scale, y: scale))
let context = CIContext()
guard let cgImage = context.createCGImage(scaledImage, from: scaledImage.extent) else {
return nil
}
return UIImage(cgImage: cgImage)
}
}