mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Add adaptive community QR scanner (#2739)
## Summary - Expand the pairing scanner from the Dynamic Island on supported iPhones - Reveal the camera behind the pairing UI on Android and standard iPhones - Preserve tap-to-dismiss and reduced-motion behavior ## Testing - `just mobile-check` - `just mobile-test` - iOS `RunnerTests`
This commit is contained in:
@@ -6,6 +6,7 @@ import UserNotifications
|
||||
@main
|
||||
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
|
||||
private var mediaUploadChannel: FlutterMethodChannel?
|
||||
private var qrScannerChannel: FlutterMethodChannel?
|
||||
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
@@ -24,6 +25,63 @@ import UserNotifications
|
||||
mediaUploadChannel?.setMethodCallHandler { [weak self] call, result in
|
||||
self?.handleMediaUploadMethodCall(call, result: result)
|
||||
}
|
||||
qrScannerChannel = FlutterMethodChannel(
|
||||
name: "buzz/qr_scanner",
|
||||
binaryMessenger: engineBridge.applicationRegistrar.messenger()
|
||||
)
|
||||
qrScannerChannel?.setMethodCallHandler { call, result in
|
||||
Self.handleQrScannerMethodCall(call, result: result)
|
||||
}
|
||||
}
|
||||
|
||||
private static func handleQrScannerMethodCall(
|
||||
_ call: FlutterMethodCall,
|
||||
result: @escaping FlutterResult
|
||||
) {
|
||||
switch call.method {
|
||||
case "usesDynamicIslandQrScannerPortal":
|
||||
result(
|
||||
UIDevice.current.userInterfaceIdiom == .phone
|
||||
&& usesDynamicIslandQrScannerPortal(
|
||||
safeAreaTopInset: activeWindowSafeAreaTopInset()
|
||||
)
|
||||
)
|
||||
case "setDynamicIslandScannerStatusBarHidden":
|
||||
guard let hidden = call.arguments as? Bool else {
|
||||
result(
|
||||
FlutterError(
|
||||
code: "invalid_arguments",
|
||||
message: "Expected a Bool status-bar visibility value.",
|
||||
details: nil
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
UIApplication.shared.setStatusBarHidden(hidden, with: .fade)
|
||||
result(nil)
|
||||
case "performDynamicIslandQrScanSuccessHaptic":
|
||||
let generator = UINotificationFeedbackGenerator()
|
||||
generator.prepare()
|
||||
generator.notificationOccurred(.success)
|
||||
result(nil)
|
||||
default:
|
||||
result(FlutterMethodNotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
static func usesDynamicIslandQrScannerPortal(
|
||||
safeAreaTopInset: CGFloat
|
||||
) -> Bool {
|
||||
safeAreaTopInset > 50
|
||||
}
|
||||
|
||||
private static func activeWindowSafeAreaTopInset() -> CGFloat {
|
||||
UIApplication.shared.connectedScenes
|
||||
.compactMap { $0 as? UIWindowScene }
|
||||
.filter { $0.activationState == .foregroundActive }
|
||||
.flatMap(\.windows)
|
||||
.first(where: \.isKeyWindow)?
|
||||
.safeAreaInsets.top ?? 0
|
||||
}
|
||||
|
||||
private func handleMediaUploadMethodCall(
|
||||
|
||||
@@ -6,6 +6,28 @@ import XCTest
|
||||
|
||||
class RunnerTests: XCTestCase {
|
||||
|
||||
func testDynamicIslandQrScannerRecognizesTallSafeAreas() {
|
||||
for safeAreaTopInset in [51, 59, 62] {
|
||||
XCTAssertTrue(
|
||||
AppDelegate.usesDynamicIslandQrScannerPortal(
|
||||
safeAreaTopInset: CGFloat(safeAreaTopInset)
|
||||
),
|
||||
"\(safeAreaTopInset)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func testDynamicIslandQrScannerRejectsStandardSafeAreas() {
|
||||
for safeAreaTopInset in [0, 44, 47, 50] {
|
||||
XCTAssertFalse(
|
||||
AppDelegate.usesDynamicIslandQrScannerPortal(
|
||||
safeAreaTopInset: CGFloat(safeAreaTopInset)
|
||||
),
|
||||
"\(safeAreaTopInset)"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func testClipboardImageDataPrefersOriginalPngBytes() throws {
|
||||
let pasteboard = try XCTUnwrap(
|
||||
UIPasteboard(name: UIPasteboard.Name(UUID().uuidString), create: true)
|
||||
|
||||
Reference in New Issue
Block a user