136 lines
3.7 KiB
Dart
136 lines
3.7 KiB
Dart
import 'package:autosos_flutter/util/toast.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:go_router/go_router.dart';
|
||
import 'package:mobile_scanner/mobile_scanner.dart';
|
||
import 'package:permission_handler/permission_handler.dart';
|
||
|
||
/// 扫码页(对应 Android ScanActivity + zxing)
|
||
class QrScanPage extends StatefulWidget {
|
||
const QrScanPage({super.key});
|
||
|
||
@override
|
||
State<QrScanPage> createState() => _QrScanPageState();
|
||
}
|
||
|
||
class _QrScanPageState extends State<QrScanPage> {
|
||
final MobileScannerController _controller = MobileScannerController(
|
||
detectionSpeed: DetectionSpeed.normal,
|
||
facing: CameraFacing.back,
|
||
);
|
||
bool _handled = false;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_checkPermission();
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_controller.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
Future<void> _checkPermission() async {
|
||
final cam = await Permission.camera.request();
|
||
if (!cam.isGranted) {
|
||
if (mounted) {
|
||
Toast.error('未授予相机权限');
|
||
context.pop();
|
||
}
|
||
}
|
||
}
|
||
|
||
void _onDetect(BarcodeCapture capture) {
|
||
if (_handled) return;
|
||
for (final b in capture.barcodes) {
|
||
final v = b.rawValue;
|
||
if (v == null || v.isEmpty) continue;
|
||
_handled = true;
|
||
_controller.stop();
|
||
context.pop(v);
|
||
return;
|
||
}
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
backgroundColor: Colors.black,
|
||
appBar: AppBar(
|
||
backgroundColor: Colors.black,
|
||
title: const Text('扫一扫'),
|
||
iconTheme: const IconThemeData(color: Colors.white),
|
||
actions: [
|
||
IconButton(
|
||
icon: const Icon(Icons.flash_on),
|
||
onPressed: () => _controller.toggleTorch(),
|
||
),
|
||
IconButton(
|
||
icon: const Icon(Icons.cameraswitch),
|
||
onPressed: () => _controller.switchCamera(),
|
||
),
|
||
],
|
||
),
|
||
body: Stack(
|
||
children: [
|
||
MobileScanner(
|
||
controller: _controller,
|
||
onDetect: _onDetect,
|
||
errorBuilder: (ctx, err, child) {
|
||
return Center(
|
||
child: Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
children: [
|
||
const Icon(
|
||
Icons.error_outline,
|
||
color: Colors.white,
|
||
size: 48,
|
||
),
|
||
const SizedBox(height: 8),
|
||
Text(
|
||
'相机错误:${err.errorCode.name}',
|
||
style: const TextStyle(color: Colors.white),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
},
|
||
),
|
||
// 扫描框
|
||
Center(
|
||
child: Container(
|
||
width: 240,
|
||
height: 240,
|
||
decoration: BoxDecoration(
|
||
border: Border.all(color: Colors.red, width: 2),
|
||
borderRadius: BorderRadius.circular(12),
|
||
),
|
||
),
|
||
),
|
||
// 顶部提示
|
||
Positioned(
|
||
top: 16,
|
||
left: 0,
|
||
right: 0,
|
||
child: Center(
|
||
child: Container(
|
||
padding:
|
||
const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||
decoration: BoxDecoration(
|
||
color: Colors.black54,
|
||
borderRadius: BorderRadius.circular(20),
|
||
),
|
||
child: const Text(
|
||
'将二维码/条码放入框内,自动扫描',
|
||
style: TextStyle(color: Colors.white, fontSize: 12),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|