Files
finger_print_app/lib/screens/face_screen.dart
Daniah Ayad Al-sultani d5d07a901e 22222
2026-01-13 14:17:59 +03:00

352 lines
12 KiB
Dart

import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'dart:async';
class OvalCameraCapturePage extends StatefulWidget {
final bool isLogin;
const OvalCameraCapturePage({super.key, this.isLogin = true});
@override
State<OvalCameraCapturePage> createState() => _OvalCameraCapturePageState();
}
class _OvalCameraCapturePageState extends State<OvalCameraCapturePage> {
CameraController? _cameraController;
bool _isCameraInitialized = false;
String? _errorMessage;
bool _isSuccess = false;
Timer? _timer;
@override
void initState() {
super.initState();
_initializeCamera();
}
Future<void> _initializeCamera() async {
try {
// Dispose existing controller if any
await _cameraController?.dispose();
_cameraController = null;
// Get available cameras
final cameras = await availableCameras();
// Check if cameras list is available
if (cameras.isEmpty) {
setState(() {
_errorMessage = "لا توجد كاميرات متاحة";
_isCameraInitialized = false;
});
return;
}
// Try to find front camera, fallback to first available camera
CameraDescription? selectedCamera;
try {
selectedCamera = cameras.firstWhere(
(cam) => cam.lensDirection == CameraLensDirection.front,
);
} catch (e) {
// If no front camera found, use the first available camera
if (cameras.isNotEmpty) {
selectedCamera = cameras.first;
} else {
setState(() {
_errorMessage = "لا توجد كاميرات متاحة";
_isCameraInitialized = false;
});
return;
}
}
_cameraController = CameraController(
selectedCamera,
ResolutionPreset.medium,
enableAudio: false,
imageFormatGroup: ImageFormatGroup.jpeg,
);
await _cameraController!.initialize();
if (!mounted) return;
setState(() {
_isCameraInitialized = true;
_errorMessage = null;
});
_timer = Timer(const Duration(seconds: 3), () {
if (mounted) {
setState(() {
_isSuccess = true;
});
// Auto-close after 2 seconds
Future.delayed(const Duration(seconds: 2), () {
if (mounted) {
Navigator.of(context).pop();
}
});
}
});
} catch (e) {
if (!mounted) return;
setState(() {
_errorMessage = "خطأ في تهيئة الكاميرا: $e";
_isCameraInitialized = false;
});
print("Error initializing camera: $e");
}
}
@override
void dispose() {
_cameraController?.dispose();
_timer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xff000000),
body:
_errorMessage != null
? Center(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(
Icons.camera_alt_outlined,
size: 64,
color: Colors.white70,
),
SizedBox(height: 16),
Text(
_errorMessage!,
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
),
SizedBox(height: 24),
ElevatedButton(
onPressed: _initializeCamera,
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xffE8001A),
foregroundColor: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: 32,
vertical: 12,
),
),
child: Text("إعادة المحاولة"),
),
],
),
),
)
: _isCameraInitialized && _cameraController != null
? Stack(
children: [
SizedBox(height: MediaQuery.of(context).size.height),
// Camera Preview
Positioned(
child: Center(child: CameraPreview(_cameraController!)),
),
// Oval overlay with dimmed background
Positioned.fill(
child: CustomPaint(painter: _OvalOverlayPainter()),
),
// Top Text
Positioned(
top: 100,
left: 0,
right: 0,
child: Center(
child: Text(
widget.isLogin ? "تسجيل الدخول" : "تسجيل خروج",
style: TextStyle(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold,
fontFamily:
'Cairo', // Assuming Cairo font based on Arabic text
),
),
),
),
// Bottom Text and Logo
Positioned(
bottom: 80,
left: 0,
right: 0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
_isSuccess
? (widget.isLogin
? "تم تسجيل دخولك بنجاح"
: "تم تسجيل خروجك بنجاح")
: (widget.isLogin
? "يتم تسجيل الدخول ..."
: "يتم تسجيل الخروج ..."),
style: const TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(height: 20),
// Logo
SizedBox(
height: _isSuccess ? 80 : 60,
width: _isSuccess ? 80 : 60,
child: SvgPicture.asset(
_isSuccess
? 'assets/images/logSuccess.svg'
: 'assets/images/logLoading.svg',
// ignore: deprecated_member_use
color: Colors.white,
fit: BoxFit.contain,
),
),
],
),
),
// // Capture button
// Positioned(
// bottom: 60,
// left: 0,
// right: 0,
// child: Center(
// child: GestureDetector(
// onTap: (){},
// child: Container(
// width: 72,
// height: 72,
// decoration: BoxDecoration(
// shape: BoxShape.circle,
// color: Colors.white,
// boxShadow: [
// BoxShadow(
// color: Colors.black26,
// blurRadius: 8,
// offset: Offset(0, 4),
// ),
// ],
// ),
// child: Icon(Icons.camera_alt, color: Color(0xffE8001A), size: 36),
// ),
// ),
// ),
// ),
],
)
: Center(
child: CircularProgressIndicator(color: Color(0xffE8001A)),
),
);
}
}
class _OvalOverlayPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
final width = size.width * 0.75;
final height = size.height * 0.4;
final center = Offset(size.width / 2, size.height / 2);
final ovalRect = Rect.fromCenter(
center: center,
width: width,
height: height,
);
// Create a path for the whole screen
final screenPath =
Path()..addRect(Rect.fromLTWH(0, 0, size.width, size.height));
// Create a path for the oval
final ovalPath = Path()..addOval(ovalRect);
// Subtract the oval from the screen path
final overlayPath = Path.combine(
PathOperation.difference,
screenPath,
ovalPath,
);
// Draw the dimmed area outside the oval with gradient
final gradient = LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Color.fromARGB(255, 41, 41, 41), // top dark gray
Color.fromARGB(255, 0, 20, 15), // bottom deep green
],
);
final paint =
Paint()
..shader = gradient.createShader(
Rect.fromLTWH(0, 0, size.width, size.height),
)
..style = PaintingStyle.fill;
canvas.drawPath(overlayPath, paint);
// Draw glowing circles effect (like AppBackground) - drawn after overlay
// Top circle - positioned similar to AppBackground (top: -250, left: 100, right: -200)
final topCircleCenter = Offset(size.width * 0.3, -250);
final topCircleRadius = 150.0;
// Draw multiple circles with different opacities for spread effect (spreadRadius: 160)
for (int i = 0; i < 5; i++) {
final spreadPaint =
Paint()
..color = Color.fromARGB(69 ~/ (i + 1), 62, 254, 190)
..maskFilter = MaskFilter.blur(BlurStyle.normal, 140 - (i * 20));
canvas.drawCircle(
topCircleCenter,
topCircleRadius + (i * 30),
spreadPaint,
);
}
// Bottom circle - positioned similar to AppBackground (bottom: 100, left: -140, right: -120)
final bottomCircleCenter = Offset(size.width * 0.2, size.height + 100);
final bottomCircleRadius = 160.0;
// Draw multiple circles with different opacities for spread effect (spreadRadius: 60)
for (int i = 0; i < 5; i++) {
final spreadPaint =
Paint()
..color = Color.fromARGB(83 ~/ (i + 1), 62, 254, 190)
..maskFilter = MaskFilter.blur(BlurStyle.normal, 180 - (i * 25));
canvas.drawCircle(
bottomCircleCenter,
bottomCircleRadius + (i * 40),
spreadPaint,
);
}
// Draw oval border
final borderPaint =
Paint()
..color = Colors.greenAccent
..style = PaintingStyle.stroke
..strokeWidth = 4;
canvas.drawOval(ovalRect, borderPaint);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => false;
}