diff --git a/assets/images/edit2.svg b/assets/images/edit2.svg new file mode 100644 index 0000000..994daed --- /dev/null +++ b/assets/images/edit2.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/faceLogin.svg b/assets/images/faceLogin.svg new file mode 100644 index 0000000..ac6e2ec --- /dev/null +++ b/assets/images/faceLogin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/faceLogout.svg b/assets/images/faceLogout.svg new file mode 100644 index 0000000..9784ba1 --- /dev/null +++ b/assets/images/faceLogout.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/logLoading.svg b/assets/images/logLoading.svg new file mode 100644 index 0000000..8b83739 --- /dev/null +++ b/assets/images/logLoading.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/images/logSuccess.svg b/assets/images/logSuccess.svg new file mode 100644 index 0000000..09eec3e --- /dev/null +++ b/assets/images/logSuccess.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/tickmark3.png b/assets/images/tickmark3.png new file mode 100644 index 0000000..a354378 Binary files /dev/null and b/assets/images/tickmark3.png differ diff --git a/lib/screens/about_screen.dart b/lib/screens/about_screen.dart index fed0a31..da7eb08 100644 --- a/lib/screens/about_screen.dart +++ b/lib/screens/about_screen.dart @@ -7,66 +7,75 @@ class AboutScreen extends StatelessWidget { @override Widget build(BuildContext context) { - return SafeArea( - child: Scaffold( - body: AppBackground( - child: Column( - children: [ - /// -------------------- SETTINGS BAR -------------------- - SettingsBar( - selectedIndex: 0, - onTap: (_) {}, - showBackButton: true, - onBackTap: () => Navigator.pop(context), - iconPaths: const [], - ), + return Scaffold( + body: AppBackground( + child: SafeArea( + child: SingleChildScrollView( + child: Column( + children: [ + /// -------------------- SETTINGS BAR -------------------- + SettingsBar( + selectedIndex: 0, + onTap: (_) {}, + showBackButton: true, + onBackTap: () => Navigator.pop(context), + iconPaths: const [], + ), - const SizedBox(height: 12), + const SizedBox(height: 12), - /// -------------------- CENTER CONTENT -------------------- - /// - Expanded( - child: Center( - child: Align( - alignment: Alignment.topCenter, - child: Directionality( - textDirection: TextDirection.rtl, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - "عن الشركة", - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white, + /// -------------------- CENTER CONTENT -------------------- + /// + Center( + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 24.0, + vertical: 10, + ), + child: Align( + alignment: Alignment.topCenter, + child: Directionality( + textDirection: TextDirection.rtl, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + "عن الشركة", + style: TextStyle( + fontSize: 26, + fontWeight: FontWeight.bold, + color: Colors.white, + ), ), - ), - const SizedBox(height: 12), + const SizedBox(height: 12), - Container( - width: 200, - height: 1, - color: Color(0x8732C599), - ), - - const SizedBox(height: 14), - - const Text( - "نص", - style: TextStyle( - fontSize: 18, - color: Colors.white70, + Container( + width: 200, + height: 1, + color: const Color(0x8732C599), ), - ), - ], + + const SizedBox(height: 14), + + const Text( + "شركة كودا ذ.م.م هي شركة عراقية رائدة تقدم حلولاً متميزة في البرمجيات المخصصة والتطبيقات وإدارة الخوادم والمواقع، ومنظومات الاتصال وخدمات الأمن السيبراني. تأسست عام 2008 ولديها عقود واتفاقيات عديدة مع مؤسسات حكومية عراقية والقطاع الخاص.\n\nوسعت الشركة شراكاتها مع وكالات عالمية مثل CODACS الأمريكية و Laipac الكندية و Teltonika اللتوانية وWolf Team الصينية وLibelium الإسبانية وOdoo العالمية وغيرها. مما أتاح لها تقديم أحدث التقنيات والمنتجات المبتكرة لعملائها.\n\nتوفر كودا حلولاً برمجية مخصصة للمؤسسات الكبيرة والدوائر الحكومية، مما يسهم في تبسيط الإجراءات وتقديم الخدمات للمواطنين بشكل إلكتروني وفعال.\n\nكما تقدم كودا مجموعة واسعة من المنتجات والخدمات الحديثة، بما في ذلك الشاشات الإعلانية، والبوابات الذكية، والمواقف الذكية، والأقفال، والمباني الذكية، وأجهزة الكشك (الخدمة الإلكترونية الذاتية)، وأجهزة محمولة تخصصية، وحساسات، وأجهزة نداء واستغاثة.\n\nبفضل هذه المنتجات والخدمات المبتكرة، تعزز كودا مكانتها الرائدة في السوق المحلي والإقليمي، وتساهم في تطوير التكنولوجيا وتعزيز جودة الحياة في العراق .", + style: TextStyle( + fontSize: 18, + color: Colors.white70, + height: + 1.5, // Added line height for better readability + ), + ), + const SizedBox(height: 20), // Bottom padding + ], + ), ), ), ), ), - ), - ], + ], + ), ), ), ), diff --git a/lib/screens/attendence_screen.dart b/lib/screens/attendence_screen.dart index 3089069..285dcf2 100644 --- a/lib/screens/attendence_screen.dart +++ b/lib/screens/attendence_screen.dart @@ -3,7 +3,6 @@ import 'package:coda_project/screens/notifications_screen.dart'; import 'package:coda_project/screens/user_settings_screen.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import '../widgets/login_animation.dart'; import '../widgets/settings_bar.dart'; class AttendanceScreen extends StatelessWidget { @@ -17,45 +16,43 @@ class AttendanceScreen extends StatelessWidget { textDirection: TextDirection.ltr, child: Stack( children: [ - SizedBox(height: MediaQuery.of(context).size.height - - ), + SizedBox(height: MediaQuery.of(context).size.height), + /// ------------------------------ /// SETTINGS BAR (STATIC) /// ------------------------------ SafeArea( - child:SettingsBar( - selectedIndex: 0, - showBackButton: false, - iconPaths: [ - 'assets/images/user.svg', - 'assets/images/ball.svg', - ], - onTap: (index) { - if (index == 0) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => UserSettingsScreen(), - ), - ); - } else if (index == 1) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => NotificationsScreen(), - ), - ); - } - }, - ), + child: SettingsBar( + selectedIndex: 0, + showBackButton: false, + iconPaths: ['assets/images/user.svg', 'assets/images/ball.svg'], + onTap: (index) { + if (index == 0) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => UserSettingsScreen(), + ), + ); + } else if (index == 1) { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => NotificationsScreen(), + ), + ); + } + }, + ), ), /// ------------------------------ /// GREETING TEXT /// ------------------------------ Positioned( - top: screenHeight * 0.14, // moved down because settings bar now exists + top: + screenHeight * + 0.14, // moved down because settings bar now exists left: 0, right: 0, child: Center( @@ -65,9 +62,7 @@ class AttendanceScreen extends StatelessWidget { fontSize: 24, fontWeight: FontWeight.w600, color: Colors.white, - shadows: [ - Shadow(color: Color(0x42000000), blurRadius: 6), - ], + shadows: [Shadow(color: Color(0x42000000), blurRadius: 6)], ), ), ), @@ -77,7 +72,9 @@ class AttendanceScreen extends StatelessWidget { /// MAIN CARD AREA /// ------------------------------ Positioned( - top: screenHeight * 0.2, // pushed down because of settings bar + greeting + top: + screenHeight * + 0.2, // pushed down because of settings bar + greeting left: 0, right: 0, child: Center( @@ -110,7 +107,7 @@ class AttendanceScreen extends StatelessWidget { ), ), Container( - height: screenHeight * 0.5, + height: screenHeight * 0.5, width: screenWidth * 0.7, decoration: BoxDecoration( color: Color(0x92757575), @@ -139,13 +136,12 @@ class AttendanceScreen extends StatelessWidget { ), ], child: _FingerButton( - icon: "assets/images/login.svg", + icon: "assets/images/faceLogin.svg", label: "تسجيل الدخول", onTap: () { Navigator.of(context).push( MaterialPageRoute( - builder: (_) => OvalCameraCapturePage( - ), + builder: (_) => OvalCameraCapturePage(isLogin: true), ), ); }, @@ -180,15 +176,12 @@ class AttendanceScreen extends StatelessWidget { ), ], child: _FingerButton( - icon: "assets/images/logout.svg", + icon: "assets/images/faceLogout.svg", label: "تسجيل خروج", onTap: () { Navigator.of(context).push( MaterialPageRoute( - builder: (_) => LoginAnimationScreen( - isLogin: false, - isSuccess: true, - ), + builder: (_) => OvalCameraCapturePage(isLogin: false), ), ); }, @@ -258,7 +251,7 @@ class _FingerButton extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - SvgPicture.asset(icon, width: 62, height: 62), + SvgPicture.asset(icon, width: 75, height: 75), SizedBox(height: 10), Text( label, diff --git a/lib/screens/face_screen.dart b/lib/screens/face_screen.dart index 73913ab..18362d0 100644 --- a/lib/screens/face_screen.dart +++ b/lib/screens/face_screen.dart @@ -1,8 +1,11 @@ import 'package:camera/camera.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'dart:async'; class OvalCameraCapturePage extends StatefulWidget { - const OvalCameraCapturePage({super.key}); + final bool isLogin; + const OvalCameraCapturePage({super.key, this.isLogin = true}); @override State createState() => _OvalCameraCapturePageState(); @@ -12,6 +15,8 @@ class _OvalCameraCapturePageState extends State { CameraController? _cameraController; bool _isCameraInitialized = false; String? _errorMessage; + bool _isSuccess = false; + Timer? _timer; @override void initState() { @@ -27,7 +32,7 @@ class _OvalCameraCapturePageState extends State { // Get available cameras final cameras = await availableCameras(); - + // Check if cameras list is available if (cameras.isEmpty) { setState(() { @@ -64,16 +69,31 @@ class _OvalCameraCapturePageState extends State { ); 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; @@ -82,11 +102,10 @@ class _OvalCameraCapturePageState extends State { } } - - @override void dispose() { _cameraController?.dispose(); + _timer?.cancel(); super.dispose(); } @@ -95,88 +114,151 @@ class _OvalCameraCapturePageState extends State { 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, + 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, ), - 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), + SizedBox(height: 16), + Text( + _errorMessage!, + style: TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + textAlign: TextAlign.center, ), - child: Text("إعادة المحاولة"), - ), - ], + 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 + ) + : _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(), + 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 + ), ), ), - - - // // 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))), + ), + + // 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)), + ), ); } } @@ -194,11 +276,16 @@ class _OvalOverlayPainter extends CustomPainter { ); // Create a path for the whole screen - final screenPath = Path()..addRect(Rect.fromLTWH(0, 0, size.width, size.height)); + 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); + final overlayPath = Path.combine( + PathOperation.difference, + screenPath, + ovalPath, + ); // Draw the dimmed area outside the oval with gradient final gradient = LinearGradient( @@ -209,11 +296,12 @@ class _OvalOverlayPainter extends CustomPainter { 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; + 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 @@ -222,9 +310,10 @@ class _OvalOverlayPainter extends CustomPainter { 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)); + 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), @@ -237,9 +326,10 @@ class _OvalOverlayPainter extends CustomPainter { 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)); + 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), @@ -248,13 +338,14 @@ class _OvalOverlayPainter extends CustomPainter { } // Draw oval border - final borderPaint = Paint() - ..color = Colors.greenAccent - ..style = PaintingStyle.stroke - ..strokeWidth = 4; + final borderPaint = + Paint() + ..color = Colors.greenAccent + ..style = PaintingStyle.stroke + ..strokeWidth = 4; canvas.drawOval(ovalRect, borderPaint); } @override bool shouldRepaint(covariant CustomPainter oldDelegate) => false; -} \ No newline at end of file +} diff --git a/pubspec.lock b/pubspec.lock index 522c33c..7c55b1f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -29,7 +29,7 @@ packages: dependency: transitive description: name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63 url: "https://pub.dev" source: hosted version: "2.13.0" @@ -85,10 +85,10 @@ packages: dependency: transitive description: name: camera_web - sha256: "57f49a635c8bf249d07fb95eb693d7e4dda6796dedb3777f9127fb54847beba7" + sha256: "595f28c89d1fb62d77c73c633193755b781c6d2e0ebcd8dc25b763b514e6ba8f" url: "https://pub.dev" source: hosted - version: "0.3.5+3" + version: "0.3.5" characters: dependency: transitive description: @@ -133,10 +133,10 @@ packages: dependency: transitive description: name: cross_file - sha256: "701dcfc06da0882883a2657c445103380e53e647060ad8d9dfb710c100996608" + sha256: "942a4791cd385a68ccb3b32c71c427aba508a1bb949b86dff2adbe4049f16239" url: "https://pub.dev" source: hosted - version: "0.3.5+1" + version: "0.3.5" crypto: dependency: transitive description: @@ -189,10 +189,10 @@ packages: dependency: transitive description: name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc" url: "https://pub.dev" source: hosted - version: "1.3.3" + version: "1.3.2" ffi: dependency: transitive description: @@ -289,7 +289,7 @@ packages: source: hosted version: "0.15.6" http: - dependency: transitive + dependency: "direct main" description: name: http sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" @@ -324,10 +324,10 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec url: "https://pub.dev" source: hosted - version: "10.0.9" + version: "10.0.8" leak_tracker_flutter_testing: dependency: transitive description: @@ -641,10 +641,10 @@ packages: dependency: transitive description: name: vm_service - sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14" url: "https://pub.dev" source: hosted - version: "15.0.0" + version: "14.3.1" web: dependency: transitive description: @@ -678,5 +678,5 @@ packages: source: hosted version: "3.1.3" sdks: - dart: ">=3.8.0 <4.0.0" - flutter: ">=3.32.0" + dart: ">=3.7.0 <4.0.0" + flutter: ">=3.29.0"