Refactor QR scan and share and add QRS support

This commit is contained in:
世界
2026-01-02 16:27:26 +08:00
parent 313cb5d213
commit 52db9bbb39
23 changed files with 1115 additions and 1411 deletions
@@ -27,36 +27,42 @@
#if os(iOS)
private var iOSBody: some View {
NavigationStackCompat {
QRScannerControllerView(controller: controller)
.ignoresSafeArea()
.navigationTitle("Scan QR Code")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") { dismiss() }
}
ToolbarItem(placement: .primaryAction) {
Menu {
if controller.availableCameras.count > 1 {
Menu("Camera") {
ForEach(controller.availableCameras, id: \.uniqueID) { camera in
Button {
controller.selectCamera(camera)
} label: {
if camera.uniqueID == controller.selectedCamera?.uniqueID {
Label(camera.localizedName, systemImage: "checkmark")
} else {
Text(camera.localizedName)
}
ZStack {
QRScannerControllerView(controller: controller)
.ignoresSafeArea()
if controller.qrsMode {
qrsProgressOverlay
}
}
.navigationTitle("Scan QR Code")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") { dismiss() }
}
ToolbarItem(placement: .primaryAction) {
Menu {
if controller.availableCameras.count > 1 {
Menu("Camera") {
ForEach(controller.availableCameras, id: \.uniqueID) { camera in
Button {
controller.selectCamera(camera)
} label: {
if camera.uniqueID == controller.selectedCamera?.uniqueID {
Label(camera.localizedName, systemImage: "checkmark")
} else {
Text(camera.localizedName)
}
}
}
}
} label: {
Image(systemName: "ellipsis.circle")
}
} label: {
Image(systemName: "ellipsis.circle")
}
}
}
}
.alert($alert)
.onAppear {
@@ -68,8 +74,14 @@
#if os(macOS)
private var macOSBody: some View {
VStack(spacing: 0) {
QRScannerControllerView(controller: controller)
.frame(minWidth: 400, minHeight: 300)
ZStack {
QRScannerControllerView(controller: controller)
if controller.qrsMode {
qrsProgressOverlay
}
}
.frame(minWidth: 400, minHeight: 300)
Divider()
@@ -102,11 +114,29 @@
}
#endif
private var qrsProgressOverlay: some View {
ZStack {
Color.black.opacity(0.5)
.ignoresSafeArea()
let k = controller.decoder?.k ?? 0
let framesScanned = controller.framesScanned
let scanProgress = k > 0 ? min(1.0, Double(framesScanned) / Double(k) / 1.2) : 0
CircularProgressView(
progress: scanProgress,
total: k
)
}
}
private func handleScanResult(_ result: Result<QRScanResult, QRScanError>) {
switch result {
case let .success(scanResult):
dismiss()
onScan(scanResult)
Task { @MainActor in
onScan(scanResult)
}
case let .failure(error):
switch error {
case .permissionDenied:
@@ -124,4 +154,38 @@
}
}
private struct CircularProgressView: View {
let progress: Double
let total: Int
private let size: CGFloat = 96
private let lineWidth: CGFloat = 8
var body: some View {
ZStack {
Circle()
.stroke(Color.white.opacity(0.3), lineWidth: lineWidth)
.frame(width: size, height: size)
Circle()
.trim(from: 0, to: progress)
.stroke(Color.white, style: StrokeStyle(lineWidth: lineWidth, lineCap: .round))
.frame(width: size, height: size)
.rotationEffect(.degrees(-90))
.animation(.easeInOut(duration: 0.2), value: progress)
if total > 0 {
Text("\(min(99, Int(progress * 100)))%")
.font(.system(size: 20, weight: .semibold))
.foregroundStyle(.white)
}
Text("QRS")
.font(.system(size: 32, weight: .bold))
.foregroundStyle(.white)
.offset(y: -size / 2 - 40)
}
}
}
#endif