1283 lines
47 KiB
Dart
1283 lines
47 KiB
Dart
// // import 'package:coda_project/presentation/screens/face_screen2.dart';
|
|
// // import 'package:coda_project/presentation/screens/notifications_screen.dart';
|
|
// // import 'package:coda_project/presentation/screens/user_settings_screen.dart';
|
|
// // import 'package:flutter/material.dart';
|
|
// // import 'package:flutter_svg/flutter_svg.dart';
|
|
// // import '../widgets/settings_bar.dart';
|
|
// // import '../../core/di/injection_container.dart';
|
|
// // import '../../domain/models/attendance_login_request.dart';
|
|
// // import '../../domain/models/attendance_logout_request.dart';
|
|
// // import '../../domain/usecases/attendance_login_usecase.dart';
|
|
// // import '../../domain/usecases/attendance_logout_usecase.dart';
|
|
// // import '../../data/datasources/user_local_data_source.dart';
|
|
// // import '../../data/datasources/attendance_remote_data_source.dart';
|
|
|
|
// // class AttendanceScreen extends StatelessWidget {
|
|
// // const AttendanceScreen({super.key});
|
|
|
|
// // @override
|
|
// // Widget build(BuildContext context) {
|
|
// // final screenWidth = MediaQuery.sizeOf(context).width;
|
|
// // final screenHeight = MediaQuery.sizeOf(context).height;
|
|
// // return Directionality(
|
|
// // textDirection: TextDirection.ltr,
|
|
// // child: Stack(
|
|
// // children: [
|
|
// // 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(),
|
|
// // ),
|
|
// // );
|
|
// // }
|
|
// // },
|
|
// // ),
|
|
// // ),
|
|
|
|
// // /// ------------------------------
|
|
// // /// GREETING TEXT
|
|
// // /// ------------------------------
|
|
// // Positioned(
|
|
// // top:
|
|
// // screenHeight *
|
|
// // 0.14, // moved down because settings bar now exists
|
|
// // left: 0,
|
|
// // right: 0,
|
|
// // child: Center(
|
|
// // child: Text(
|
|
// // "صباح الخير, محمد",
|
|
// // style: TextStyle(
|
|
// // fontSize: 24,
|
|
// // fontWeight: FontWeight.w600,
|
|
// // color: Colors.white,
|
|
// // shadows: [Shadow(color: Color(0x42000000), blurRadius: 6)],
|
|
// // ),
|
|
// // ),
|
|
// // ),
|
|
// // ),
|
|
|
|
// // /// ------------------------------
|
|
// // /// MAIN CARD AREA
|
|
// // /// ------------------------------
|
|
// // Positioned(
|
|
// // top:
|
|
// // screenHeight *
|
|
// // 0.2, // pushed down because of settings bar + greeting
|
|
// // left: 0,
|
|
// // right: 0,
|
|
// // child: Center(
|
|
// // child: Padding(
|
|
// // padding: EdgeInsets.symmetric(vertical: screenHeight * 0.05),
|
|
// // child: Stack(
|
|
// // children: [
|
|
// // Container(
|
|
// // height: screenHeight * 0.5,
|
|
// // width: screenWidth * 0.7,
|
|
// // decoration: BoxDecoration(
|
|
// // borderRadius: BorderRadius.circular(32),
|
|
// // boxShadow: [
|
|
// // BoxShadow(
|
|
// // color: Color(0x1F2B2B2B),
|
|
// // blurRadius: 5,
|
|
// // offset: Offset(10, -10),
|
|
// // ),
|
|
// // BoxShadow(
|
|
// // color: Color(0xABCECECE),
|
|
// // blurRadius: 5,
|
|
// // offset: Offset(-2, 5),
|
|
// // ),
|
|
// // BoxShadow(
|
|
// // color: Color.fromARGB(148, 2, 70, 35),
|
|
// // blurRadius: 80,
|
|
// // offset: Offset(0, 10),
|
|
// // ),
|
|
// // ],
|
|
// // ),
|
|
// // ),
|
|
// // Container(
|
|
// // height: screenHeight * 0.5,
|
|
// // width: screenWidth * 0.7,
|
|
// // decoration: BoxDecoration(
|
|
// // color: Color(0x92757575),
|
|
// // borderRadius: BorderRadius.circular(32),
|
|
// // ),
|
|
// // ),
|
|
// // ],
|
|
// // ),
|
|
// // ),
|
|
// // ),
|
|
// // ),
|
|
|
|
// // /// ------------------------------
|
|
// // /// LOGIN BUTTON
|
|
// // /// ------------------------------
|
|
// // Positioned(
|
|
// // top: screenHeight * 0.21,
|
|
// // left: screenWidth * 0.05,
|
|
// // child: _ShadowedCard(
|
|
// // shadow: [
|
|
// // BoxShadow(
|
|
// // color: Color(0x62000000),
|
|
// // blurRadius: 10,
|
|
// // spreadRadius: 5,
|
|
// // offset: Offset(5, 5),
|
|
// // ),
|
|
// // ],
|
|
// // child: _FingerButton(
|
|
// // icon: "assets/images/faceLogin.svg",
|
|
// // label: "تسجيل الدخول",
|
|
// // onTap: () async {
|
|
// // final employeeId =
|
|
// // await sl<UserLocalDataSource>().getCachedEmployeeId();
|
|
// // print("ATTENDANCE_SCREEN: Retrieved EmployeeId: $employeeId");
|
|
// // if (employeeId == null) {
|
|
// // if (context.mounted) {
|
|
// // ScaffoldMessenger.of(context).showSnackBar(
|
|
// // const SnackBar(
|
|
// // content: Text('خطأ: لم يتم العثور على رقم الموظف'),
|
|
// // ),
|
|
// // );
|
|
// // }
|
|
// // return;
|
|
// // }
|
|
|
|
// // // ------------------------------
|
|
// // // ACTIVE SESSION CHECK (LOGIN)
|
|
// // // ------------------------------
|
|
// // try {
|
|
// // // Optional: Show a loading dialog if it takes too long
|
|
// // final hasActive = await sl<AttendanceRemoteDataSource>()
|
|
// // .hasActiveLogin(employeeId: employeeId);
|
|
|
|
// // if (hasActive) {
|
|
// // if (context.mounted) {
|
|
// // ScaffoldMessenger.of(context).showSnackBar(
|
|
// // const SnackBar(content: Text('أنت مسجل دخول بالفعل')),
|
|
// // );
|
|
// // }
|
|
// // return;
|
|
// // }
|
|
// // } catch (e) {
|
|
// // if (context.mounted) {
|
|
// // ScaffoldMessenger.of(context).showSnackBar(
|
|
// // SnackBar(content: Text('فشل التحقق من الجلسة: $e')),
|
|
// // );
|
|
// // }
|
|
// // return;
|
|
// // }
|
|
|
|
// // if (context.mounted) {
|
|
// // Navigator.of(context).push(
|
|
// // MaterialPageRoute(
|
|
// // builder:
|
|
// // (_) => OvalCameraCapturePage(
|
|
// // isLogin: true,
|
|
// // onCapture: (imageFile) async {
|
|
// // final loginUseCase =
|
|
// // sl<AttendanceLoginUsecase>();
|
|
// // await loginUseCase(
|
|
// // AttendanceLoginRequest(
|
|
// // employeeId: employeeId,
|
|
// // faceImage: imageFile,
|
|
// // ),
|
|
// // );
|
|
// // },
|
|
// // checkIfLoggedIn: () {},
|
|
// // ),
|
|
// // ),
|
|
// // );
|
|
// // }
|
|
// // },
|
|
// // ),
|
|
// // ),
|
|
// // ),
|
|
|
|
// // /// ------------------------------
|
|
// // /// LOGOUT BUTTON
|
|
// // /// ------------------------------
|
|
// // Positioned(
|
|
// // bottom: screenHeight * 0.2,
|
|
// // right: screenWidth * 0.1,
|
|
// // child: _ShadowedCard(
|
|
// // shadow: [
|
|
// // BoxShadow(
|
|
// // color: Color(0xABCECECE),
|
|
// // blurRadius: 5,
|
|
// // spreadRadius: 3,
|
|
// // offset: Offset(-6, -6),
|
|
// // ),
|
|
// // BoxShadow(
|
|
// // color: Color(0x92014221),
|
|
// // blurRadius: 10,
|
|
// // offset: Offset(-5, -5),
|
|
// // ),
|
|
// // BoxShadow(
|
|
// // color: Color(0x7D1A1A1A),
|
|
// // blurRadius: 10,
|
|
// // spreadRadius: 3,
|
|
// // offset: Offset(5, 5),
|
|
// // ),
|
|
// // ],
|
|
// // child: _FingerButton(
|
|
// // icon: "assets/images/faceLogout.svg",
|
|
// // label: "تسجيل خروج",
|
|
// // onTap: () async {
|
|
// // final employeeId =
|
|
// // await sl<UserLocalDataSource>().getCachedEmployeeId();
|
|
// // if (employeeId == null) {
|
|
// // if (context.mounted) {
|
|
// // ScaffoldMessenger.of(context).showSnackBar(
|
|
// // const SnackBar(
|
|
// // content: Text('خطأ: لم يتم العثور على رقم الموظف'),
|
|
// // ),
|
|
// // );
|
|
// // }
|
|
// // return;
|
|
// // }
|
|
|
|
// // // ------------------------------
|
|
// // // ACTIVE SESSION CHECK (LOGOUT)
|
|
// // // ------------------------------
|
|
// // try {
|
|
// // final hasActive = await sl<AttendanceRemoteDataSource>()
|
|
// // .hasActiveLogin(employeeId: employeeId);
|
|
|
|
// // if (!hasActive) {
|
|
// // if (context.mounted) {
|
|
// // ScaffoldMessenger.of(context).showSnackBar(
|
|
// // const SnackBar(
|
|
// // content: Text(
|
|
// // 'لا يوجد تسجيل دخول فعال لتسجيل الخروج',
|
|
// // ),
|
|
// // ),
|
|
// // );
|
|
// // }
|
|
// // return;
|
|
// // }
|
|
// // } catch (e) {
|
|
// // if (context.mounted) {
|
|
// // ScaffoldMessenger.of(context).showSnackBar(
|
|
// // SnackBar(content: Text('فشل التحقق من الجلسة: $e')),
|
|
// // );
|
|
// // }
|
|
// // return;
|
|
// // }
|
|
|
|
// // if (context.mounted) {
|
|
// // Navigator.of(context).push(
|
|
// // MaterialPageRoute(
|
|
// // builder:
|
|
// // (_) => OvalCameraCapturePage(
|
|
// // isLogin: false,
|
|
// // onCapture: (imageFile) async {
|
|
// // final logoutUseCase =
|
|
// // sl<AttendanceLogoutUseCase>();
|
|
// // await logoutUseCase(
|
|
// // AttendanceLogoutRequest(
|
|
// // employeeId: employeeId,
|
|
// // faceImage: imageFile,
|
|
// // ),
|
|
// // );
|
|
// // },
|
|
// // checkIfLoggedIn: () {},
|
|
// // ),
|
|
// // ),
|
|
// // );
|
|
// // }
|
|
// // },
|
|
// // ),
|
|
// // ),
|
|
// // ),
|
|
// // ],
|
|
// // ),
|
|
// // );
|
|
// // }
|
|
// // }
|
|
|
|
// // /// ---------------------------------------------
|
|
// // /// SHADOW WRAPPER
|
|
// // /// ---------------------------------------------
|
|
|
|
// // class _ShadowedCard extends StatelessWidget {
|
|
// // final Widget child;
|
|
// // final List<BoxShadow> shadow;
|
|
|
|
// // const _ShadowedCard({required this.child, required this.shadow});
|
|
|
|
// // @override
|
|
// // Widget build(BuildContext context) {
|
|
// // return Stack(
|
|
// // children: [
|
|
// // Container(
|
|
// // height: 160,
|
|
// // width: 160,
|
|
// // decoration: BoxDecoration(
|
|
// // borderRadius: BorderRadius.circular(32),
|
|
// // boxShadow: shadow,
|
|
// // ),
|
|
// // ),
|
|
// // child,
|
|
// // ],
|
|
// // );
|
|
// // }
|
|
// // }
|
|
|
|
// // /// ---------------------------------------------
|
|
// // /// BUTTON WIDGET
|
|
// // /// ---------------------------------------------
|
|
|
|
// // class _FingerButton extends StatelessWidget {
|
|
// // final String icon;
|
|
// // final String label;
|
|
// // final VoidCallback onTap;
|
|
|
|
// // const _FingerButton({
|
|
// // required this.icon,
|
|
// // required this.label,
|
|
// // required this.onTap,
|
|
// // });
|
|
|
|
// // @override
|
|
// // Widget build(BuildContext context) {
|
|
// // return GestureDetector(
|
|
// // onTap: onTap,
|
|
// // child: Container(
|
|
// // height: 160,
|
|
// // width: 160,
|
|
// // decoration: BoxDecoration(
|
|
// // color: Color(0xFFEAFBF3),
|
|
// // borderRadius: BorderRadius.circular(32),
|
|
// // ),
|
|
// // child: Column(
|
|
// // mainAxisAlignment: MainAxisAlignment.center,
|
|
// // children: [
|
|
// // SvgPicture.asset(icon, width: 75, height: 75),
|
|
// // SizedBox(height: 10),
|
|
// // Text(
|
|
// // label,
|
|
// // style: TextStyle(
|
|
// // fontSize: 18,
|
|
// // fontWeight: FontWeight.w600,
|
|
// // color: Colors.black,
|
|
// // ),
|
|
// // ),
|
|
// // ],
|
|
// // ),
|
|
// // ),
|
|
// // );
|
|
// // }
|
|
// // }
|
|
|
|
// import 'package:coda_project/presentation/screens/face_screen2.dart';
|
|
// import 'package:coda_project/presentation/screens/notifications_screen.dart';
|
|
// import 'package:coda_project/presentation/screens/user_settings_screen.dart';
|
|
// import 'package:flutter/material.dart';
|
|
// import 'package:flutter_svg/flutter_svg.dart';
|
|
// import '../widgets/settings_bar.dart';
|
|
// import '../../core/di/injection_container.dart';
|
|
// import '../../domain/models/attendance_login_request.dart';
|
|
// import '../../domain/models/attendance_logout_request.dart';
|
|
// import '../../domain/usecases/attendance_login_usecase.dart';
|
|
// import '../../domain/usecases/attendance_logout_usecase.dart';
|
|
// import '../../data/datasources/user_local_data_source.dart';
|
|
// import '../../data/datasources/attendance_remote_data_source.dart';
|
|
|
|
// class AttendanceScreen extends StatefulWidget {
|
|
// const AttendanceScreen({super.key});
|
|
|
|
// @override
|
|
// State<AttendanceScreen> createState() => _AttendanceScreenState();
|
|
// }
|
|
|
|
// class _AttendanceScreenState extends State<AttendanceScreen> {
|
|
// String _userName = '';
|
|
|
|
// @override
|
|
// void initState() {
|
|
// super.initState();
|
|
// _loadUserName();
|
|
// }
|
|
|
|
// Future<void> _loadUserName() async {
|
|
// final name = await sl<UserLocalDataSource>().getCachedFullName();
|
|
// if (mounted) {
|
|
// setState(() {
|
|
// _userName = name ?? 'مستخدم';
|
|
// });
|
|
// }
|
|
// }
|
|
|
|
// @override
|
|
// Widget build(BuildContext context) {
|
|
// final screenWidth = MediaQuery.sizeOf(context).width;
|
|
// final screenHeight = MediaQuery.sizeOf(context).height;
|
|
// return Directionality(
|
|
// textDirection: TextDirection.ltr,
|
|
// child: Stack(
|
|
// children: [
|
|
// 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) => const UserSettingsScreen(),
|
|
// ),
|
|
// );
|
|
// } else if (index == 1) {
|
|
// Navigator.push(
|
|
// context,
|
|
// MaterialPageRoute(
|
|
// builder: (context) => const NotificationsScreen(),
|
|
// ),
|
|
// );
|
|
// }
|
|
// },
|
|
// ),
|
|
// ),
|
|
|
|
// /// ------------------------------
|
|
// /// GREETING TEXT
|
|
// /// ------------------------------
|
|
// Positioned(
|
|
// top: screenHeight * 0.14,
|
|
// left: 0,
|
|
// right: 0,
|
|
// child: Center(
|
|
// child: Text(
|
|
// "صباح الخير $_userName",
|
|
// style: TextStyle(
|
|
// fontSize: 24,
|
|
// fontWeight: FontWeight.w600,
|
|
// color: Colors.white,
|
|
// shadows: [Shadow(color: Color(0x42000000), blurRadius: 6)],
|
|
// ),
|
|
// ),
|
|
// ),
|
|
// ),
|
|
|
|
// /// ------------------------------
|
|
// /// MAIN CARD AREA
|
|
// /// ------------------------------
|
|
// Positioned(
|
|
// top: screenHeight * 0.2,
|
|
// left: 0,
|
|
// right: 0,
|
|
// child: Center(
|
|
// child: Padding(
|
|
// padding: EdgeInsets.symmetric(vertical: screenHeight * 0.05),
|
|
// child: Stack(
|
|
// children: [
|
|
// Container(
|
|
// height: screenHeight * 0.5,
|
|
// width: screenWidth * 0.7,
|
|
// decoration: BoxDecoration(
|
|
// borderRadius: BorderRadius.circular(32),
|
|
// boxShadow: [
|
|
// const BoxShadow(
|
|
// color: Color(0x1F2B2B2B),
|
|
// blurRadius: 5,
|
|
// offset: Offset(10, -10),
|
|
// ),
|
|
// const BoxShadow(
|
|
// color: Color(0xABCECECE),
|
|
// blurRadius: 5,
|
|
// offset: Offset(-2, 5),
|
|
// ),
|
|
// BoxShadow(
|
|
// color: const Color.fromARGB(148, 2, 70, 35),
|
|
// blurRadius: 80,
|
|
// offset: const Offset(0, 10),
|
|
// ),
|
|
// ],
|
|
// ),
|
|
// ),
|
|
// Container(
|
|
// height: screenHeight * 0.5,
|
|
// width: screenWidth * 0.7,
|
|
// decoration: BoxDecoration(
|
|
// color: const Color(0x92757575),
|
|
// borderRadius: BorderRadius.circular(32),
|
|
// ),
|
|
// ),
|
|
// ],
|
|
// ),
|
|
// ),
|
|
// ),
|
|
// ),
|
|
|
|
// /// ------------------------------
|
|
// /// LOGIN BUTTON
|
|
// /// ------------------------------
|
|
// Positioned(
|
|
// top: screenHeight * 0.21,
|
|
// left: screenWidth * 0.05,
|
|
// child: _ShadowedCard(
|
|
// shadow: [
|
|
// const BoxShadow(
|
|
// color: Color(0x62000000),
|
|
// blurRadius: 10,
|
|
// spreadRadius: 5,
|
|
// offset: Offset(5, 5),
|
|
// ),
|
|
// ],
|
|
// child: _FingerButton(
|
|
// icon: "assets/images/faceLogin.svg",
|
|
// label: "تسجيل الدخول",
|
|
// onTap: () async {
|
|
// final employeeId =
|
|
// await sl<UserLocalDataSource>().getCachedEmployeeId();
|
|
// print("ATTENDANCE_SCREEN: Retrieved EmployeeId: $employeeId");
|
|
// if (employeeId == null) {
|
|
// if (context.mounted) {
|
|
// ScaffoldMessenger.of(context).showSnackBar(
|
|
// const SnackBar(
|
|
// content: Text('خطأ: لم يتم العثور على رقم الموظف'),
|
|
// ),
|
|
// );
|
|
// }
|
|
// return;
|
|
// }
|
|
|
|
// // ACTIVE SESSION CHECK (LOGIN)
|
|
// try {
|
|
// final hasActive = await sl<AttendanceRemoteDataSource>()
|
|
// .hasActiveLogin(employeeId: employeeId);
|
|
|
|
// if (hasActive) {
|
|
// if (context.mounted) {
|
|
// showDialog(
|
|
// context: context,
|
|
// builder:
|
|
// (_) => AlertDialog(
|
|
// title: const Text(
|
|
// 'تنبيه',
|
|
// textAlign: TextAlign.center,
|
|
// ),
|
|
// content: const Text(
|
|
// 'أنت مسجل دخول بالفعل، لا يمكنك تسجيل الدخول مرة أخرى.',
|
|
// textAlign: TextAlign.center,
|
|
// ),
|
|
// actions: [
|
|
// TextButton(
|
|
// onPressed:
|
|
// () => Navigator.of(context).pop(),
|
|
// child: const Text('حسناً'),
|
|
// ),
|
|
// ],
|
|
// ),
|
|
// );
|
|
// }
|
|
// return;
|
|
// }
|
|
// } catch (e) {
|
|
// if (context.mounted) {
|
|
// ScaffoldMessenger.of(context).showSnackBar(
|
|
// SnackBar(content: Text('فشل التحقق من الجلسة: $e')),
|
|
// );
|
|
// }
|
|
// return;
|
|
// }
|
|
|
|
// if (context.mounted) {
|
|
// final result = await Navigator.of(context).push(
|
|
// MaterialPageRoute(
|
|
// builder:
|
|
// (_) => OvalCameraCapturePage(
|
|
// isLogin: true,
|
|
// onCapture: (
|
|
// imageFile, {
|
|
// required bool localAuth,
|
|
// }) async {
|
|
// final loginUseCase =
|
|
// sl<AttendanceLoginUsecase>();
|
|
|
|
// await loginUseCase(
|
|
// AttendanceLoginRequest(
|
|
// employeeId: employeeId,
|
|
// faceImage: imageFile,
|
|
// localAuth: localAuth, // ✅ NEW FIELD
|
|
// ),
|
|
// );
|
|
// },
|
|
// ),
|
|
// ),
|
|
// );
|
|
|
|
// if (!context.mounted) return;
|
|
|
|
// if (result == "local_auth_failed") {
|
|
// ScaffoldMessenger.of(context).showSnackBar(
|
|
// const SnackBar(
|
|
// content: Text("فشل التحقق بالبصمة أو رمز القفل"),
|
|
// ),
|
|
// );
|
|
// } else if (result == "retry_failed") {
|
|
// ScaffoldMessenger.of(context).showSnackBar(
|
|
// const SnackBar(
|
|
// content: Text("فشل تسجيل الحضور بعد التحقق المحلي"),
|
|
// ),
|
|
// );
|
|
// } else if (result == "retry_missing_file") {
|
|
// ScaffoldMessenger.of(context).showSnackBar(
|
|
// const SnackBar(
|
|
// content: Text("تعذر إعادة المحاولة. حاول مرة أخرى."),
|
|
// ),
|
|
// );
|
|
// }
|
|
// }
|
|
// },
|
|
// ),
|
|
// ),
|
|
// ),
|
|
|
|
// /// ------------------------------
|
|
// /// LOGOUT BUTTON
|
|
// /// ------------------------------
|
|
// Positioned(
|
|
// bottom: screenHeight * 0.2,
|
|
// right: screenWidth * 0.1,
|
|
// child: _ShadowedCard(
|
|
// shadow: const [
|
|
// BoxShadow(
|
|
// color: Color(0xABCECECE),
|
|
// blurRadius: 5,
|
|
// spreadRadius: 3,
|
|
// offset: Offset(-6, -6),
|
|
// ),
|
|
// BoxShadow(
|
|
// color: Color(0x92014221),
|
|
// blurRadius: 10,
|
|
// offset: Offset(-5, -5),
|
|
// ),
|
|
// BoxShadow(
|
|
// color: Color(0x7D1A1A1A),
|
|
// blurRadius: 10,
|
|
// spreadRadius: 3,
|
|
// offset: Offset(5, 5),
|
|
// ),
|
|
// ],
|
|
// child: _FingerButton(
|
|
// icon: "assets/images/faceLogout.svg",
|
|
// label: "تسجيل خروج",
|
|
// onTap: () async {
|
|
// final employeeId =
|
|
// await sl<UserLocalDataSource>().getCachedEmployeeId();
|
|
// if (employeeId == null) {
|
|
// if (context.mounted) {
|
|
// ScaffoldMessenger.of(context).showSnackBar(
|
|
// const SnackBar(
|
|
// content: Text('خطأ: لم يتم العثور على رقم الموظف'),
|
|
// ),
|
|
// );
|
|
// }
|
|
// return;
|
|
// }
|
|
|
|
// // ACTIVE SESSION CHECK (LOGOUT)
|
|
// try {
|
|
// final hasActive = await sl<AttendanceRemoteDataSource>()
|
|
// .hasActiveLogin(employeeId: employeeId);
|
|
|
|
// if (!hasActive) {
|
|
// if (context.mounted) {
|
|
// showDialog(
|
|
// context: context,
|
|
// builder:
|
|
// (_) => AlertDialog(
|
|
// title: const Text(
|
|
// 'تنبيه',
|
|
// textAlign: TextAlign.center,
|
|
// ),
|
|
// content: const Text(
|
|
// 'لا يوجد تسجيل دخول فعال لتسجيل الخروج.',
|
|
// textAlign: TextAlign.center,
|
|
// ),
|
|
// actions: [
|
|
// TextButton(
|
|
// onPressed:
|
|
// () => Navigator.of(context).pop(),
|
|
// child: const Text('حسناً'),
|
|
// ),
|
|
// ],
|
|
// ),
|
|
// );
|
|
// }
|
|
// return;
|
|
// }
|
|
// } catch (e) {
|
|
// if (context.mounted) {
|
|
// ScaffoldMessenger.of(context).showSnackBar(
|
|
// SnackBar(content: Text('فشل التحقق من الجلسة: $e')),
|
|
// );
|
|
// }
|
|
// return;
|
|
// }
|
|
|
|
// if (context.mounted) {
|
|
// Navigator.of(context).push(
|
|
// MaterialPageRoute(
|
|
// builder:
|
|
// (_) => OvalCameraCapturePage(
|
|
// isLogin: false,
|
|
// onCapture: (imageFile) async {
|
|
// final logoutUseCase =
|
|
// sl<AttendanceLogoutUseCase>();
|
|
// await logoutUseCase(
|
|
// AttendanceLogoutRequest(
|
|
// employeeId: employeeId,
|
|
// faceImage: imageFile,
|
|
// ),
|
|
// );
|
|
// },
|
|
// ),
|
|
// ),
|
|
// );
|
|
// }
|
|
// },
|
|
// ),
|
|
// ),
|
|
// ),
|
|
// ],
|
|
// ),
|
|
// );
|
|
// }
|
|
// }
|
|
|
|
// /// ---------------------------------------------
|
|
// /// SHADOW WRAPPER
|
|
// /// ---------------------------------------------
|
|
|
|
// class _ShadowedCard extends StatelessWidget {
|
|
// final Widget child;
|
|
// final List<BoxShadow> shadow;
|
|
|
|
// const _ShadowedCard({required this.child, required this.shadow});
|
|
|
|
// @override
|
|
// Widget build(BuildContext context) {
|
|
// return Stack(
|
|
// children: [
|
|
// Container(
|
|
// height: 160,
|
|
// width: 160,
|
|
// decoration: BoxDecoration(
|
|
// borderRadius: BorderRadius.circular(32),
|
|
// boxShadow: shadow,
|
|
// ),
|
|
// ),
|
|
// child,
|
|
// ],
|
|
// );
|
|
// }
|
|
// }
|
|
|
|
// /// ---------------------------------------------
|
|
// /// BUTTON WIDGET
|
|
// /// ---------------------------------------------
|
|
|
|
// class _FingerButton extends StatelessWidget {
|
|
// final String icon;
|
|
// final String label;
|
|
// final VoidCallback onTap;
|
|
|
|
// const _FingerButton({
|
|
// required this.icon,
|
|
// required this.label,
|
|
// required this.onTap,
|
|
// });
|
|
|
|
// @override
|
|
// Widget build(BuildContext context) {
|
|
// return GestureDetector(
|
|
// onTap: onTap,
|
|
// child: Container(
|
|
// height: 160,
|
|
// width: 160,
|
|
// decoration: BoxDecoration(
|
|
// color: const Color(0xFFEAFBF3),
|
|
// borderRadius: BorderRadius.circular(32),
|
|
// ),
|
|
// child: Column(
|
|
// mainAxisAlignment: MainAxisAlignment.center,
|
|
// children: [
|
|
// SvgPicture.asset(icon, width: 75, height: 75),
|
|
// const SizedBox(height: 10),
|
|
// Text(
|
|
// label,
|
|
// style: const TextStyle(
|
|
// fontSize: 18,
|
|
// fontWeight: FontWeight.w600,
|
|
// color: Colors.black,
|
|
// ),
|
|
// ),
|
|
// ],
|
|
// ),
|
|
// ),
|
|
// );
|
|
// }
|
|
// }
|
|
|
|
import 'package:coda_project/presentation/screens/face_screen2.dart';
|
|
import 'package:coda_project/presentation/screens/notifications_screen.dart';
|
|
import 'package:coda_project/presentation/screens/user_settings_screen.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_svg/flutter_svg.dart';
|
|
|
|
import '../widgets/settings_bar.dart';
|
|
|
|
import '../../core/di/injection_container.dart';
|
|
import '../../domain/models/attendance_login_request.dart';
|
|
import '../../domain/models/attendance_logout_request.dart';
|
|
import '../../domain/usecases/attendance_login_usecase.dart';
|
|
import '../../domain/usecases/attendance_logout_usecase.dart';
|
|
import '../../data/datasources/user_local_data_source.dart';
|
|
import '../../data/datasources/attendance_remote_data_source.dart';
|
|
|
|
class AttendanceScreen extends StatefulWidget {
|
|
const AttendanceScreen({super.key});
|
|
|
|
@override
|
|
State<AttendanceScreen> createState() => _AttendanceScreenState();
|
|
}
|
|
|
|
class _AttendanceScreenState extends State<AttendanceScreen> {
|
|
String _userName = '';
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_loadUserName();
|
|
}
|
|
|
|
Future<void> _loadUserName() async {
|
|
final name = await sl<UserLocalDataSource>().getCachedFullName();
|
|
if (mounted) {
|
|
setState(() {
|
|
_userName = name ?? 'مستخدم';
|
|
});
|
|
}
|
|
}
|
|
|
|
void _showResultSnack(String message) {
|
|
if (!mounted) return;
|
|
ScaffoldMessenger.of(
|
|
context,
|
|
).showSnackBar(SnackBar(content: Text(message)));
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final screenWidth = MediaQuery.sizeOf(context).width;
|
|
final screenHeight = MediaQuery.sizeOf(context).height;
|
|
|
|
return Directionality(
|
|
textDirection: TextDirection.ltr,
|
|
child: Stack(
|
|
children: [
|
|
SizedBox(height: MediaQuery.of(context).size.height),
|
|
|
|
/// SETTINGS BAR
|
|
SafeArea(
|
|
child: SettingsBar(
|
|
selectedIndex: 0,
|
|
showBackButton: false,
|
|
iconPaths: const [
|
|
'assets/images/user.svg',
|
|
'assets/images/ball.svg',
|
|
],
|
|
onTap: (index) {
|
|
if (index == 0) {
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (_) => const UserSettingsScreen(),
|
|
),
|
|
);
|
|
} else if (index == 1) {
|
|
Navigator.push(
|
|
context,
|
|
MaterialPageRoute(
|
|
builder: (_) => const NotificationsScreen(),
|
|
),
|
|
);
|
|
}
|
|
},
|
|
),
|
|
),
|
|
|
|
/// GREETING
|
|
Positioned(
|
|
top: screenHeight * 0.14,
|
|
left: 0,
|
|
right: 0,
|
|
child: Center(
|
|
child: Text(
|
|
"صباح الخير $_userName",
|
|
style: const TextStyle(
|
|
fontSize: 24,
|
|
fontWeight: FontWeight.w600,
|
|
color: Colors.white,
|
|
shadows: [Shadow(color: Color(0x42000000), blurRadius: 6)],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
|
|
/// MAIN CARD AREA
|
|
Positioned(
|
|
top: screenHeight * 0.2,
|
|
left: 0,
|
|
right: 0,
|
|
child: Center(
|
|
child: Padding(
|
|
padding: EdgeInsets.symmetric(vertical: screenHeight * 0.05),
|
|
child: Stack(
|
|
children: [
|
|
Container(
|
|
height: screenHeight * 0.5,
|
|
width: screenWidth * 0.7,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(32),
|
|
boxShadow: [
|
|
const BoxShadow(
|
|
color: Color(0x1F2B2B2B),
|
|
blurRadius: 5,
|
|
offset: Offset(10, -10),
|
|
),
|
|
const BoxShadow(
|
|
color: Color(0xABCECECE),
|
|
blurRadius: 5,
|
|
offset: Offset(-2, 5),
|
|
),
|
|
BoxShadow(
|
|
color: const Color.fromARGB(148, 2, 70, 35),
|
|
blurRadius: 80,
|
|
offset: const Offset(0, 10),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Container(
|
|
height: screenHeight * 0.5,
|
|
width: screenWidth * 0.7,
|
|
decoration: BoxDecoration(
|
|
color: const Color(0x92757575),
|
|
borderRadius: BorderRadius.circular(32),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
|
|
/// LOGIN BUTTON
|
|
Positioned(
|
|
top: screenHeight * 0.21,
|
|
left: screenWidth * 0.05,
|
|
child: _ShadowedCard(
|
|
shadow: const [
|
|
BoxShadow(
|
|
color: Color(0x62000000),
|
|
blurRadius: 10,
|
|
spreadRadius: 5,
|
|
offset: Offset(5, 5),
|
|
),
|
|
],
|
|
child: _FingerButton(
|
|
icon: "assets/images/faceLogin.svg",
|
|
label: "تسجيل الدخول",
|
|
onTap: () async {
|
|
final employeeId =
|
|
await sl<UserLocalDataSource>().getCachedEmployeeId();
|
|
|
|
if (employeeId == null) {
|
|
_showResultSnack('خطأ: لم يتم العثور على رقم الموظف');
|
|
return;
|
|
}
|
|
|
|
// ACTIVE SESSION CHECK (LOGIN)
|
|
try {
|
|
final hasActive = await sl<AttendanceRemoteDataSource>()
|
|
.hasActiveLogin(employeeId: employeeId);
|
|
|
|
if (hasActive) {
|
|
if (!mounted) return;
|
|
showDialog(
|
|
context: context,
|
|
builder:
|
|
(_) => AlertDialog(
|
|
title: const Text(
|
|
'تنبيه',
|
|
textAlign: TextAlign.center,
|
|
),
|
|
content: const Text(
|
|
'أنت مسجل دخول بالفعل، لا يمكنك تسجيل الدخول مرة أخرى.',
|
|
textAlign: TextAlign.center,
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
child: const Text('حسناً'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
return;
|
|
}
|
|
} catch (e) {
|
|
_showResultSnack('فشل التحقق من الجلسة: $e');
|
|
return;
|
|
}
|
|
|
|
if (!mounted) return;
|
|
|
|
final result = await Navigator.of(context).push(
|
|
MaterialPageRoute(
|
|
builder:
|
|
(_) => OvalCameraCapturePage(
|
|
isLogin: true,
|
|
onCapture: (
|
|
imageFile, {
|
|
required bool localAuth,
|
|
}) async {
|
|
final loginUseCase = sl<AttendanceLoginUsecase>();
|
|
|
|
await loginUseCase(
|
|
AttendanceLoginRequest(
|
|
employeeId: employeeId,
|
|
faceImage: imageFile,
|
|
localAuth: localAuth, // ✅
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
);
|
|
|
|
if (!mounted) return;
|
|
|
|
if (result == "local_auth_failed") {
|
|
_showResultSnack("فشل التحقق بالبصمة أو رمز القفل");
|
|
} else if (result == "retry_failed") {
|
|
_showResultSnack("فشل تسجيل الحضور بعد التحقق المحلي");
|
|
} else if (result == "retry_missing_file") {
|
|
_showResultSnack("تعذر إعادة المحاولة. حاول مرة أخرى.");
|
|
}
|
|
},
|
|
),
|
|
),
|
|
),
|
|
|
|
/// LOGOUT BUTTON
|
|
Positioned(
|
|
bottom: screenHeight * 0.2,
|
|
right: screenWidth * 0.1,
|
|
child: _ShadowedCard(
|
|
shadow: const [
|
|
BoxShadow(
|
|
color: Color(0xABCECECE),
|
|
blurRadius: 5,
|
|
spreadRadius: 3,
|
|
offset: Offset(-6, -6),
|
|
),
|
|
BoxShadow(
|
|
color: Color(0x92014221),
|
|
blurRadius: 10,
|
|
offset: Offset(-5, -5),
|
|
),
|
|
BoxShadow(
|
|
color: Color(0x7D1A1A1A),
|
|
blurRadius: 10,
|
|
spreadRadius: 3,
|
|
offset: Offset(5, 5),
|
|
),
|
|
],
|
|
child: _FingerButton(
|
|
icon: "assets/images/faceLogout.svg",
|
|
label: "تسجيل خروج",
|
|
onTap: () async {
|
|
final employeeId =
|
|
await sl<UserLocalDataSource>().getCachedEmployeeId();
|
|
|
|
if (employeeId == null) {
|
|
_showResultSnack('خطأ: لم يتم العثور على رقم الموظف');
|
|
return;
|
|
}
|
|
|
|
// ACTIVE SESSION CHECK (LOGOUT)
|
|
try {
|
|
final hasActive = await sl<AttendanceRemoteDataSource>()
|
|
.hasActiveLogin(employeeId: employeeId);
|
|
|
|
if (!hasActive) {
|
|
if (!mounted) return;
|
|
showDialog(
|
|
context: context,
|
|
builder:
|
|
(_) => AlertDialog(
|
|
title: const Text(
|
|
'تنبيه',
|
|
textAlign: TextAlign.center,
|
|
),
|
|
content: const Text(
|
|
'لا يوجد تسجيل دخول فعال لتسجيل الخروج.',
|
|
textAlign: TextAlign.center,
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
child: const Text('حسناً'),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
return;
|
|
}
|
|
} catch (e) {
|
|
_showResultSnack('فشل التحقق من الجلسة: $e');
|
|
return;
|
|
}
|
|
|
|
if (!mounted) return;
|
|
|
|
final result = await Navigator.of(context).push(
|
|
MaterialPageRoute(
|
|
builder:
|
|
(_) => OvalCameraCapturePage(
|
|
isLogin: false,
|
|
onCapture: (
|
|
imageFile, {
|
|
required bool localAuth,
|
|
}) async {
|
|
final logoutUseCase =
|
|
sl<AttendanceLogoutUseCase>();
|
|
|
|
await logoutUseCase(
|
|
AttendanceLogoutRequest(
|
|
employeeId: employeeId,
|
|
faceImage: imageFile,
|
|
localAuth: localAuth, // ✅
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
);
|
|
|
|
if (!mounted) return;
|
|
|
|
if (result == "local_auth_failed") {
|
|
_showResultSnack("فشل التحقق بالبصمة أو رمز القفل");
|
|
} else if (result == "retry_failed") {
|
|
_showResultSnack("فشل تسجيل الخروج بعد التحقق المحلي");
|
|
} else if (result == "retry_missing_file") {
|
|
_showResultSnack("تعذر إعادة المحاولة. حاول مرة أخرى.");
|
|
}
|
|
},
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// SHADOW WRAPPER
|
|
class _ShadowedCard extends StatelessWidget {
|
|
final Widget child;
|
|
final List<BoxShadow> shadow;
|
|
|
|
const _ShadowedCard({required this.child, required this.shadow});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Stack(
|
|
children: [
|
|
Container(
|
|
height: 160,
|
|
width: 160,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(32),
|
|
boxShadow: shadow,
|
|
),
|
|
),
|
|
child,
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
/// BUTTON WIDGET
|
|
class _FingerButton extends StatelessWidget {
|
|
final String icon;
|
|
final String label;
|
|
final VoidCallback onTap;
|
|
|
|
const _FingerButton({
|
|
required this.icon,
|
|
required this.label,
|
|
required this.onTap,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return GestureDetector(
|
|
onTap: onTap,
|
|
child: Container(
|
|
height: 160,
|
|
width: 160,
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFFEAFBF3),
|
|
borderRadius: BorderRadius.circular(32),
|
|
),
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: [
|
|
SvgPicture.asset(icon, width: 75, height: 75),
|
|
const SizedBox(height: 10),
|
|
Text(
|
|
label,
|
|
style: const TextStyle(
|
|
fontSize: 18,
|
|
fontWeight: FontWeight.w600,
|
|
color: Colors.black,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|