inventory_mobile/lib/screens/user/scan/scan_user.dart
2025-12-15 15:35:35 +08:00

141 lines
4.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:inventory_system/screens/user/scan/scan_result_user.dart';
import 'package:inventory_system/screens/title_bar.dart';
import 'package:inventory_system/screens/nav_bar.dart';
import 'package:inventory_system/screens/bottom_nav_bar.dart';
class ScanUserScreen extends StatefulWidget {
const ScanUserScreen({super.key});
@override
State<ScanUserScreen> createState() => _ScanUserScreenState();
}
class _ScanUserScreenState extends State<ScanUserScreen> {
int _selectedIndex = 1;
bool _isProcessing = false;
void _onDetect(BarcodeCapture capture) async {
if (_isProcessing) return;
final codes = capture.barcodes;
if (codes.isEmpty) return;
final value = codes.first.rawValue;
if (value == null || value.isEmpty) return;
_isProcessing = true;
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ScanResultUserScreen(scannedCode: value.trim()),
),
);
// brief debounce to avoid flood
await Future.delayed(const Duration(milliseconds: 500));
_isProcessing = false;
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFFF5F5F7),
appBar: const TitleBar(title: 'Scan Item (User)'),
drawer: const NavBar(isAdmin: false, selectedScreen: AppScreen.scan),
body: Stack(
fit: StackFit.expand,
children: [
// 1. Add Padding around the camera view
Padding(
padding: const EdgeInsets.all(38.38), // Adjust the padding as you need
child: ClipRRect(
// 2. (Optional) Add rounded corners to the camera view
borderRadius: BorderRadius.circular(24.0),
child: MobileScanner(
fit: BoxFit.cover, // Use BoxFit.cover for a better aspect ratio
onDetect: _onDetect,
),
),
),
_ScannerOverlay(),
Positioned(
bottom: 16,
left: 0,
right: 0,
child: Text(
'Place the code inside the frame',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 16,
fontWeight: FontWeight.bold,
shadows: [
Shadow(
blurRadius: 10.0,
color: Colors.black.withOpacity(0.5),
offset: const Offset(0, 0),
),
],
),
),
),
],
),
bottomNavigationBar: BottomNavBar(
selectedIndex: _selectedIndex,
onItemTapped: (index) {
setState(() => _selectedIndex = index);
if (index == 0) {
Navigator.pop(context);
}
},
),
);
}
}
class _ScannerOverlay extends StatelessWidget {
@override
Widget build(BuildContext context) {
return IgnorePointer(
child: CustomPaint(
painter: _OverlayPainter(),
size: Size.infinite,
),
);
}
}
class _OverlayPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final paint = Paint()
..color = Colors.white
..style = PaintingStyle.stroke
..strokeWidth = 3;
final double padding = 48;
final rect = RRect.fromRectAndRadius(
Rect.fromLTWH(padding, padding, size.width - padding * 2, size.height - padding * 2),
const Radius.circular(12),
);
final bg = Paint()..color = Colors.black.withOpacity(0.5);
final clearPaint = Paint()..blendMode = BlendMode.clear;
final path = Path()..addRRect(rect);
canvas.saveLayer(Offset.zero & size, Paint());
canvas.drawRect(Offset.zero & size, bg);
canvas.drawPath(path, clearPaint);
canvas.restore();
canvas.drawRRect(rect, paint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}