feat: import Chinese-localized Buzz source snapshot
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
Signed-off-by: cls_宁波本机 <908705107@qq.com>
This commit is contained in:
@@ -0,0 +1,282 @@
|
||||
part of '../pairing_qr_scanner.dart';
|
||||
|
||||
const _fallbackScannerOpenDuration = Duration(milliseconds: 420);
|
||||
const _fallbackScannerCloseDuration = Duration(milliseconds: 320);
|
||||
const _fallbackScannerSheetPeekHeight = 112.0;
|
||||
const _fallbackScannerSheetCornerRadius = 32.0;
|
||||
const _fallbackScannerDrawerCurve = Cubic(0.32, 0.72, 0, 1);
|
||||
|
||||
/// Reveals the scanner behind the current app surface on standard devices.
|
||||
///
|
||||
/// The app surface moves down as a rounded sheet instead of navigating to a
|
||||
/// separate scanner page. This is used by Android and iPhones without a
|
||||
/// Dynamic Island.
|
||||
class FallbackPairingQrScanner extends HookWidget {
|
||||
const FallbackPairingQrScanner({
|
||||
required this.appSurface,
|
||||
required this.onClosed,
|
||||
super.key,
|
||||
});
|
||||
|
||||
/// The current Buzz screen that moves down to reveal the camera.
|
||||
final Widget appSurface;
|
||||
|
||||
/// Called after the app surface has returned, with a scanned value if any.
|
||||
final ValueChanged<String?> onClosed;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final controller = useMemoized(MobileScannerController.new);
|
||||
final animation = useAnimationController(
|
||||
duration: _fallbackScannerOpenDuration,
|
||||
reverseDuration: _fallbackScannerCloseDuration,
|
||||
);
|
||||
final isClosing = useRef(false);
|
||||
final reduceMotion = MediaQuery.disableAnimationsOf(context);
|
||||
|
||||
useEffect(
|
||||
() => () {
|
||||
unawaited(controller.dispose());
|
||||
},
|
||||
[controller],
|
||||
);
|
||||
|
||||
useEffect(() {
|
||||
if (reduceMotion) {
|
||||
animation.value = 1;
|
||||
} else {
|
||||
unawaited(animation.forward());
|
||||
}
|
||||
return null;
|
||||
}, [animation, reduceMotion]);
|
||||
|
||||
Future<void> closeScanner([String? result]) async {
|
||||
if (isClosing.value) {
|
||||
return;
|
||||
}
|
||||
isClosing.value = true;
|
||||
|
||||
if (reduceMotion) {
|
||||
animation.value = 0;
|
||||
await WidgetsBinding.instance.endOfFrame;
|
||||
} else {
|
||||
await animation.reverse();
|
||||
}
|
||||
|
||||
if (context.mounted) {
|
||||
onClosed(result);
|
||||
}
|
||||
}
|
||||
|
||||
void handleDetection(BarcodeCapture capture) {
|
||||
if (isClosing.value) {
|
||||
return;
|
||||
}
|
||||
final value = _firstScannedValue(capture);
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
unawaited(closeScanner(value));
|
||||
}
|
||||
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvokedWithResult: (didPop, _) {
|
||||
if (!didPop) {
|
||||
unawaited(closeScanner());
|
||||
}
|
||||
},
|
||||
child: AnnotatedRegion<SystemUiOverlayStyle>(
|
||||
value: SystemUiOverlayStyle.light,
|
||||
child: Material(
|
||||
key: const ValueKey('fallback-qr-scanner-reveal'),
|
||||
color: Colors.black,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final viewport = constraints.biggest;
|
||||
final sheetTravel = math.max(
|
||||
0.0,
|
||||
viewport.height - _fallbackScannerSheetPeekHeight,
|
||||
);
|
||||
|
||||
return Stack(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
children: [
|
||||
Positioned.fill(
|
||||
child: Semantics(
|
||||
button: true,
|
||||
label: context.l10n.closeQrScanner,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: closeScanner,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
_QrScannerCamera(
|
||||
controller: controller,
|
||||
onDetect: handleDetection,
|
||||
),
|
||||
const IgnorePointer(
|
||||
child: _FallbackQrScannerViewfinder(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
AnimatedBuilder(
|
||||
animation: animation,
|
||||
child: appSurface,
|
||||
builder: (context, child) {
|
||||
final progress = _fallbackScannerDrawerCurve.transform(
|
||||
animation.value.clamp(0.0, 1.0),
|
||||
);
|
||||
final offset = sheetTravel * progress;
|
||||
final radius =
|
||||
_fallbackScannerSheetCornerRadius * progress;
|
||||
|
||||
return Positioned(
|
||||
top: offset,
|
||||
left: 0,
|
||||
right: 0,
|
||||
height: viewport.height,
|
||||
child: Semantics(
|
||||
button: true,
|
||||
label: context.l10n.closeQrScanner,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: closeScanner,
|
||||
child: ClipRRect(
|
||||
key: const ValueKey(
|
||||
'fallback-qr-scanner-app-sheet',
|
||||
),
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(radius),
|
||||
),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
AbsorbPointer(child: child),
|
||||
if (progress > 0)
|
||||
Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: Grid.twelve,
|
||||
),
|
||||
child: Opacity(
|
||||
opacity: progress,
|
||||
child: Container(
|
||||
width: Grid.md,
|
||||
height: Grid.half,
|
||||
decoration: BoxDecoration(
|
||||
color: context
|
||||
.colors
|
||||
.onSurfaceVariant
|
||||
.withValues(alpha: 0.45),
|
||||
borderRadius:
|
||||
BorderRadius.circular(
|
||||
Grid.half,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _FallbackQrScannerViewfinder extends StatelessWidget {
|
||||
const _FallbackQrScannerViewfinder();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
final size = math.min(
|
||||
constraints.maxWidth - (Grid.xl * 2),
|
||||
constraints.maxHeight - 240,
|
||||
);
|
||||
|
||||
return Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
CustomPaint(
|
||||
painter: _FallbackQrScannerViewfinderPainter(
|
||||
viewfinderSize: math.max(0, size),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: Transform.translate(
|
||||
offset: Offset(0, (size / 2) + Grid.md),
|
||||
child: Text(
|
||||
context.l10n.scanQrCodeShort,
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _FallbackQrScannerViewfinderPainter extends CustomPainter {
|
||||
const _FallbackQrScannerViewfinderPainter({required this.viewfinderSize});
|
||||
|
||||
final double viewfinderSize;
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final rect = Rect.fromCenter(
|
||||
center: size.center(Offset.zero),
|
||||
width: viewfinderSize,
|
||||
height: viewfinderSize,
|
||||
);
|
||||
final roundedRect = RRect.fromRectAndRadius(
|
||||
rect,
|
||||
const Radius.circular(40),
|
||||
);
|
||||
|
||||
canvas.saveLayer(Offset.zero & size, Paint());
|
||||
canvas.drawRect(
|
||||
Offset.zero & size,
|
||||
Paint()..color = Colors.black.withValues(alpha: 0.6),
|
||||
);
|
||||
canvas.drawRRect(roundedRect, Paint()..blendMode = BlendMode.clear);
|
||||
canvas.restore();
|
||||
canvas.drawRRect(
|
||||
roundedRect,
|
||||
Paint()
|
||||
..color = Colors.white
|
||||
..style = PaintingStyle.stroke
|
||||
..strokeWidth = 3,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_FallbackQrScannerViewfinderPainter oldDelegate) {
|
||||
return oldDelegate.viewfinderSize != viewfinderSize;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user