qr_scanner_fast 0.0.2
qr_scanner_fast: ^0.0.2 copied to clipboard
A low-latency hybrid QR scanner that races ZXing with an ML Kit fallback.
import 'package:flutter/material.dart';
import 'package:qr_scanner_fast/qr_scanner_fast.dart';
void main() => runApp(const ExampleApp());
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) => MaterialApp(
debugShowCheckedModeBanner: false,
title: 'QR Scanner Fast',
theme: ThemeData.dark(useMaterial3: true),
home: const ScannerPage(),
);
}
class ScannerPage extends StatefulWidget {
const ScannerPage({super.key});
@override
State<ScannerPage> createState() => _ScannerPageState();
}
class _ScannerPageState extends State<ScannerPage> {
final _controller = QrScannerFastController();
QrScanResult? _result;
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => Scaffold(
backgroundColor: Colors.black,
body: Stack(
fit: StackFit.expand,
children: [
QrScannerFast(
controller: _controller,
config: const QrScannerFastConfig(
fallbackDelay: Duration(milliseconds: 120),
frameSampleRate: 1,
snapshotFrameSampleRate: 4,
snapshotBufferSize: 6,
minimumSnapshotSharpness: 3.5,
frameInterval: Duration(milliseconds: 45),
mlKitFrameInterval: Duration(milliseconds: 250),
maxZxingDimension: 720,
stopAfterDetection: true,
tryInverted: false,
),
onDetect: (result) => setState(() => _result = result),
onError: (error, stackTrace) => debugPrint('Scanner error: $error'),
),
SafeArea(
child: Padding(
padding: const EdgeInsets.all(18),
child: Column(
children: [
Row(
children: [
const Expanded(
child: Text(
'QR Scanner Fast',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700,
),
),
),
AnimatedBuilder(
animation: _controller,
builder: (context, _) => IconButton.filledTonal(
tooltip: 'Flash',
onPressed: _controller.toggleTorch,
icon: Icon(
_controller.torchEnabled
? Icons.flash_on
: Icons.flash_off,
),
),
),
],
),
const Spacer(),
const Text(
'Arahkan kamera ke QR. Seluruh frame dipindai,\ntermasuk area di luar kotak panduan.',
textAlign: TextAlign.center,
),
const SizedBox(height: 18),
if (_result case final result?)
Card(
color: const Color(0xEE18231E),
child: Padding(
padding: const EdgeInsets.all(18),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
result.rawValue,
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 16),
),
const SizedBox(height: 8),
Text(
'Terdeteksi oleh ${result.engine.name}',
style: const TextStyle(color: Colors.greenAccent),
),
const SizedBox(height: 12),
FilledButton.icon(
onPressed: () async {
setState(() => _result = null);
await _controller.start();
},
icon: const Icon(Icons.qr_code_scanner),
label: const Text('Scan lagi'),
),
],
),
),
),
],
),
),
),
],
),
);
}