mirror of
https://gitee.com/dromara/MaxKey.git
synced 2025-12-06 17:08:29 +08:00
146 lines
4.2 KiB
Dart
146 lines
4.2 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:go_router/go_router.dart';
|
|
import 'package:mobile_scanner/mobile_scanner.dart';
|
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|
|
|
class ScanPage extends StatelessWidget {
|
|
const ScanPage({super.key, required this.title});
|
|
|
|
final String title;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: AppBar(title: Text(title)),
|
|
body: ScanView(
|
|
resultHandler: (capture, resumeScanner) {
|
|
context.pop(capture.barcodes.first.rawValue);
|
|
},
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
typedef ScanViewResultHandler = void Function(
|
|
BarcodeCapture capture,
|
|
void Function() resumeScanner,
|
|
);
|
|
|
|
class ScanView extends StatefulWidget {
|
|
const ScanView({super.key, required this.resultHandler});
|
|
|
|
/// handle the QR code result.
|
|
///
|
|
/// The scanner will stop each time the result is complete.
|
|
/// Process the result here and then resume the scanner by calling `resumeScanner`.
|
|
final ScanViewResultHandler resultHandler;
|
|
|
|
@override
|
|
State<ScanView> createState() => _ScanViewState();
|
|
}
|
|
|
|
class _ScanViewState extends State<ScanView> with WidgetsBindingObserver {
|
|
final scannerController = MobileScannerController(
|
|
formats: [BarcodeFormat.qrCode],
|
|
);
|
|
|
|
StreamSubscription? subscription;
|
|
|
|
bool hasResult = false;
|
|
|
|
void resumeScanner() {
|
|
hasResult = false;
|
|
scannerController.start();
|
|
}
|
|
|
|
void handleQRcode(BarcodeCapture capture) {
|
|
if (hasResult) return;
|
|
hasResult = true;
|
|
|
|
scannerController.stop().then((_) {
|
|
widget.resultHandler(capture, resumeScanner);
|
|
});
|
|
}
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
// Start listening to lifecycle changes.
|
|
WidgetsBinding.instance.addObserver(this);
|
|
|
|
// Start listening to the barcode events.
|
|
subscription = scannerController.barcodes.listen(handleQRcode);
|
|
|
|
// Finally, start the scanner itself.
|
|
scannerController.start();
|
|
}
|
|
|
|
@override
|
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
|
// If the controller is not ready, do not try to start or stop it.
|
|
// Permission dialogs can trigger lifecycle changes before the controller is ready.
|
|
if (!scannerController.value.isInitialized) return;
|
|
|
|
switch (state) {
|
|
case AppLifecycleState.detached:
|
|
case AppLifecycleState.hidden:
|
|
case AppLifecycleState.paused:
|
|
return;
|
|
case AppLifecycleState.resumed:
|
|
// Restart the scanner when the app is resumed.
|
|
// Don't forget to resume listening to the barcode events.
|
|
subscription = scannerController.barcodes.listen(handleQRcode);
|
|
scannerController.start();
|
|
break;
|
|
case AppLifecycleState.inactive:
|
|
// Stop the scanner when the app is paused.
|
|
// Also stop the barcode events subscription.
|
|
subscription?.cancel();
|
|
subscription = null;
|
|
scannerController.stop();
|
|
break;
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MobileScanner(
|
|
controller: scannerController,
|
|
errorBuilder: (context, error, _) {
|
|
final scheme = Theme.of(context).colorScheme;
|
|
return ColoredBox(
|
|
color: scheme.surface,
|
|
child: Center(
|
|
child: switch (error.errorCode) {
|
|
MobileScannerErrorCode.controllerAlreadyInitialized ||
|
|
MobileScannerErrorCode.controllerDisposed ||
|
|
MobileScannerErrorCode.controllerUninitialized ||
|
|
MobileScannerErrorCode.genericError ||
|
|
MobileScannerErrorCode.unsupported =>
|
|
Icon(Icons.error, color: scheme.error),
|
|
MobileScannerErrorCode.permissionDenied => Text(
|
|
AppLocalizations.of(context)!.scanPagePermissionDeniedMsg,
|
|
textAlign: TextAlign.center,
|
|
),
|
|
},
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
|
|
@override
|
|
void dispose() async {
|
|
// Stop listening to lifecycle changes.
|
|
WidgetsBinding.instance.removeObserver(this);
|
|
// Stop listening to the barcode events.
|
|
subscription?.cancel();
|
|
subscription = null;
|
|
super.dispose();
|
|
// Finally, dispose the controller.
|
|
scannerController.dispose();
|
|
}
|
|
}
|