١١١١١

This commit is contained in:
Mohammed Al-Samarraie
2026-01-08 16:18:37 +03:00
parent eff4ac4342
commit 4df24f5d8d
7 changed files with 361 additions and 16 deletions

View File

@@ -0,0 +1,260 @@
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
class OvalCameraCapturePage extends StatefulWidget {
const OvalCameraCapturePage({super.key});
@override
State<OvalCameraCapturePage> createState() => _OvalCameraCapturePageState();
}
class _OvalCameraCapturePageState extends State<OvalCameraCapturePage> {
CameraController? _cameraController;
bool _isCameraInitialized = false;
String? _errorMessage;
@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;
});
} catch (e) {
if (!mounted) return;
setState(() {
_errorMessage = "خطأ في تهيئة الكاميرا: $e";
_isCameraInitialized = false;
});
print("Error initializing camera: $e");
}
}
@override
void dispose() {
_cameraController?.dispose();
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(),
),
),
// // 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;
}