barcode_qr_scanner 0.2.2
barcode_qr_scanner: ^0.2.2 copied to clipboard
Flutter barkod ve QR kod okuma paketi. Android ML Kit ve iOS AVFoundation desteği, çoklu tarama ve tekrar filtresi.
example/lib/main.dart
import 'package:barcode_qr_scanner/barcode_qr_scanner.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Barcode QR Scanner Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: const ScannerPage(),
);
}
}
class ScannerPage extends StatefulWidget {
const ScannerPage({super.key});
@override
State<ScannerPage> createState() => _ScannerPageState();
}
class _ScannerPageState extends State<ScannerPage> {
final _controller = CodeScannerController();
final _scannedCodes = <ScanResult>[];
ScanMode _scanMode = ScanMode.single;
PermissionStatus? _cameraStatus;
@override
void initState() {
super.initState();
_checkPermission();
}
Future<void> _checkPermission() async {
final status = await Permission.camera.status;
setState(() => _cameraStatus = status);
}
Future<void> _requestPermission() async {
final status = await Permission.camera.request();
setState(() => _cameraStatus = status);
}
Future<void> _openSettings() async {
await openAppSettings();
await _checkPermission();
}
void _onDetect(ScanResult result) {
setState(() => _scannedCodes.insert(0, result));
}
void _clearResults() {
setState(_scannedCodes.clear);
_controller.resetDuplicateFilter();
_controller.resume();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Barkod / QR Tarayıcı'),
actions: [
if (_cameraStatus?.isGranted ?? false) ...[
PopupMenuButton<ScanMode>(
initialValue: _scanMode,
onSelected: (mode) => setState(() => _scanMode = mode),
itemBuilder: (context) => const [
PopupMenuItem(
value: ScanMode.continuous,
child: Text('Çoklu tarama'),
),
PopupMenuItem(
value: ScanMode.single,
child: Text('Tek tarama'),
),
],
),
IconButton(
icon: const Icon(Icons.flash_on),
onPressed: () => _controller.toggleTorch(),
),
],
],
),
body: _buildBody(),
);
}
Widget _buildBody() {
if (_cameraStatus == null) {
return const Center(child: CircularProgressIndicator());
}
if (_cameraStatus!.isGranted) {
return Column(
children: [
Expanded(
flex: 3,
child: Stack(
children: [
CodeScannerView(
controller: _controller,
scanMode: _scanMode,
duplicateFilter: DuplicateFilter.session,
onDetect: _onDetect,
),
Positioned(
bottom: 16,
left: 16,
right: 16,
child: Text(
_scanMode == ScanMode.continuous
? 'Çoklu mod: her kod bir kez okunur'
: 'Tek mod: ilk okumada durur',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Colors.white,
shadows: const [
Shadow(blurRadius: 8, color: Colors.black54),
],
),
),
),
],
),
),
Expanded(
flex: 2,
child: _buildResultList(),
),
],
);
}
return _buildPermissionDenied();
}
Widget _buildResultList() {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(16, 12, 16, 8),
child: Row(
children: [
Text(
'Okunanlar (${_scannedCodes.length})',
style: Theme.of(context).textTheme.titleMedium,
),
const Spacer(),
if (_scannedCodes.isNotEmpty)
TextButton(
onPressed: _clearResults,
child: const Text('Temizle'),
),
],
),
),
Expanded(
child: _scannedCodes.isEmpty
? const Center(child: Text('Henüz kod okunmadı'))
: ListView.builder(
itemCount: _scannedCodes.length,
itemBuilder: (context, index) {
final result = _scannedCodes[index];
return ListTile(
leading: const Icon(Icons.qr_code_scanner),
title: Text(result.rawValue),
subtitle: Text(result.format.name),
);
},
),
),
],
);
}
Widget _buildPermissionDenied() {
final permanentlyDenied = _cameraStatus!.isPermanentlyDenied;
return Center(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.camera_alt_outlined, size: 64),
const SizedBox(height: 16),
Text(
permanentlyDenied
? 'Kamera izni kalıcı olarak reddedildi.'
: 'Tarama için kamera izni gerekli.',
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 24),
FilledButton(
onPressed: permanentlyDenied ? _openSettings : _requestPermission,
child: Text(permanentlyDenied ? 'Ayarları Aç' : 'İzin Ver'),
),
],
),
),
);
}
}