fingerprint/lib/presentation/widgets/camera_preview_widget.dart
Aastha Shrivastava 3132b7e8cd first commit
2026-01-17 12:54:01 +05:30

201 lines
6.2 KiB
Dart

import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../../domain/entities/quality_status.dart';
import '../providers/display_config_provider.dart';
import 'fingerprint_guide_painter.dart';
class CameraPreviewWidget extends ConsumerWidget {
final CameraController? controller;
final QualityStatus? qualityStatus;
final int consecutivePasses;
final bool canCapture;
const CameraPreviewWidget({
super.key,
required this.controller,
this.qualityStatus,
this.consecutivePasses = 0,
this.canCapture = false,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final config = ref.watch(displayConfigProvider);
// If controller is null or not initialized, show Simulation/Placeholder
final bool showCamera =
controller != null && controller!.value.isInitialized;
final qs = qualityStatus;
final isFocusGood = qs?.isFocusGood ?? false;
final isLightingGood = qs?.isLightingGood ?? false;
final isPositionGood = qs?.isPositionGood ?? false;
final overallGood = qs?.canCapture ?? false;
return Stack(
fit: StackFit.expand,
children: [
if (showCamera)
_buildCoveredCameraPreview(context, controller!)
else
Container(
color: Colors.grey.shade900,
child: const Center(
child: Text(
"Camera Unavailable\n(Simulation Mode)",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white54, fontSize: 16),
),
),
),
// Fingerprint Guide (Painter)
if (config.showGuide)
CustomPaint(
painter: FingerprintGuidePainter(isGoodQuality: overallGood),
child: Container(),
),
// Icon (Center Guide)
if (config.showGuide)
Center(
child: Icon(
Icons.fingerprint,
color: overallGood
? Colors.greenAccent
: Colors.white.withValues(alpha: 0.3),
size: 100,
),
),
// Quality Indicators (Top)
if (config.showQualityIndicators)
Positioned(
top: 60,
left: 0,
right: 0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_buildStatusIcon(
Icons.center_focus_strong,
"Focus",
isFocusGood,
),
_buildStatusIcon(Icons.wb_sunny, "Light", isLightingGood),
_buildStatusIcon(Icons.crop_free, "Position", isPositionGood),
],
),
),
// Status Text (Bottom)
if (config.showStatusText)
Positioned(
bottom: 120, // Above FAB
left: 20,
right: 20,
child: Column(
children: [
if (overallGood && !canCapture)
Text(
"Hold Steady... $consecutivePasses/5",
style: const TextStyle(
color: Colors.yellowAccent,
fontSize: 20,
fontWeight: FontWeight.bold,
shadows: [Shadow(blurRadius: 4, color: Colors.black)],
),
)
else if (canCapture)
const Text(
"READY TO CAPTURE",
style: TextStyle(
color: Colors.greenAccent,
fontSize: 20,
fontWeight: FontWeight.bold,
shadows: [Shadow(blurRadius: 4, color: Colors.black)],
),
)
else
const Text(
"Adjust Finger",
style: TextStyle(
color: Colors.white,
fontSize: 18,
shadows: [Shadow(blurRadius: 4, color: Colors.black)],
),
),
const SizedBox(height: 8),
if (qs != null && config.showDebugInfo)
Text(
"Blur: ${qs.blurScore.toStringAsFixed(0)} | Bright: ${qs.brightness.toStringAsFixed(0)}",
style: const TextStyle(color: Colors.grey, fontSize: 12),
),
],
),
),
],
);
}
Widget _buildCoveredCameraPreview(
BuildContext context,
CameraController controller,
) {
final size = MediaQuery.of(context).size;
double scale = 1.0;
final double screenRatio = size.aspectRatio;
final double cameraRatio = controller.value.aspectRatio;
// Calculate effective camera ratio displayed (swapped if portrait)
// We assume if screen is portrait, camera preview is also rendered in portrait mode (1/ratio)
// by the CameraPreview widget.
final double effectiveCameraRatio = (size.width < size.height)
? (1 / cameraRatio)
: cameraRatio;
if (screenRatio > effectiveCameraRatio) {
// Screen is wider than camera preview
scale = screenRatio / effectiveCameraRatio;
} else {
// Screen is taller than camera preview
scale = effectiveCameraRatio / screenRatio;
}
return Transform.scale(
scale: scale,
alignment: Alignment.center,
child: Center(child: CameraPreview(controller)),
);
}
Widget _buildStatusIcon(IconData icon, String label, bool isGood) {
return Column(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: isGood
? Colors.green.withValues(alpha: 0.8)
: Colors.red.withValues(alpha: 0.8),
shape: BoxShape.circle,
),
child: Icon(icon, color: Colors.white, size: 24),
),
const SizedBox(height: 4),
Text(
label,
style: const TextStyle(
color: Colors.white,
fontSize: 12,
shadows: [Shadow(blurRadius: 2, color: Colors.black)],
),
),
],
);
}
}