diff --git a/assets/langs/ar-SA.json b/assets/langs/ar-SA.json index e8892a8..097512f 100644 --- a/assets/langs/ar-SA.json +++ b/assets/langs/ar-SA.json @@ -52,6 +52,7 @@ "confirm": "تؤكد", "passwordChangedSuccessfully": "تم تغيير الرقم السري بنجاح", "itemsForSale": "سلع للبيع", + "attendanceDetails": "تفاصيل الحضور", "doNotUseRecentPassword": "لا تستخدم كلمة مرور حديثة", "atLeastOneLowercase": "حرف صغير واحد على الأقل", "atLeastOneUppercase": "حرف كبير واحد على الأقل", diff --git a/assets/langs/en-US.json b/assets/langs/en-US.json index f5b9b44..7f43f72 100644 --- a/assets/langs/en-US.json +++ b/assets/langs/en-US.json @@ -66,6 +66,7 @@ "whatsapp": "Whatsapp", "reject": "Reject", "approve": "Approve", + "attendanceDetails": "Attendence Details", "msg": "Hello {} in the {} world ", "msg_named": "{} are written in the {lang} language", "clickMe": "Click me", diff --git a/lib/classes/colors.dart b/lib/classes/colors.dart index 0d80b05..03ac3fb 100644 --- a/lib/classes/colors.dart +++ b/lib/classes/colors.dart @@ -26,4 +26,13 @@ class MyColors { static const Color white = Color(0xffffffff); static const Color green = Color(0xffffffff); static const Color borderColor = Color(0xffE8E8E8); + static const Color grey67Color = Color(0xff676767); + static const Color whiteColor = Color(0xFFEEEEEE); + static const Color greenColor = Color(0xff1FA269); + static const Color lightGreenColor = Color(0xff2AB2AB); + static const Color darkGreyColor = Color(0xff464646); + static const Color greyA5Color = Color(0xffA5A5A5); + static const Color blackColor = Color(0xff000014); + static const Color grey3AColor = Color(0xff2E303A); + static const Color darkColor = Color(0xff000015); } diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 3eba985..cf5ff4d 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -8,6 +8,8 @@ import 'package:mohem_flutter_app/ui/login/verify_last_login_screen.dart'; import 'package:mohem_flutter_app/ui/login/verify_login_screen.dart'; import 'package:mohem_flutter_app/ui/work_list/missing_swipe/missing_swipe_screen.dart'; import 'package:mohem_flutter_app/ui/work_list/work_list_screen.dart'; +import 'package:mohem_flutter_app/ui/bottom_sheets/attendence_details_bottom_sheet.dart'; +import 'package:mohem_flutter_app/ui/attendance/monthly_attendance.dart'; class AppRoutes { static const String splash = "/splash"; @@ -23,10 +25,18 @@ class AppRoutes { static const String todayAttendance = "/todayAttendance"; static const String initialRoute = login; + //Work List static const String workList = "/workList"; static const String missingSwipe = "/missingSwipe"; + //Attendance + static const String attendance = "/attendance"; + static const String monthlyAttendance = "/monthlyAttendance"; + + //Bottom Sheet + static const String attendanceDetailsBottomSheet = "/attendanceDetailsBottomSheet"; + static final Map routes = { login: (context) => LoginScreen(), verifyLogin: (context) => VerifyLoginScreen(), @@ -36,8 +46,15 @@ class AppRoutes { forgotPassword: (context) => ForgotPasswordScreen(), todayAttendance: (context) => TodayAttendanceScreen(), + //Work List workList: (context) => WorkListScreen(), missingSwipe: (context) => MissingSwipeScreen(), + + //Attendance + monthlyAttendance: (context) => MonthlyAttendance(), + + //Bottom Sheet + attendanceDetailsBottomSheet: (context) => AttendenceDetailsBottomSheet(), }; } diff --git a/lib/extensions/string_extensions.dart b/lib/extensions/string_extensions.dart index 2db6135..6a0adbc 100644 --- a/lib/extensions/string_extensions.dart +++ b/lib/extensions/string_extensions.dart @@ -69,9 +69,9 @@ extension EmailValidator on String { style: TextStyle(height: 1, color: color ?? MyColors.darkTextColor, fontSize: 22, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), ); - Widget toText24({Color? color, bool isBold = false, bool considerHeight = true}) => Text( + Widget toText24({Color? color, bool isBold = false}) => Text( this, - style: TextStyle(height: considerHeight ? 23 / 24 : null, color: color ?? MyColors.darkTextColor, fontSize: 24, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), + style: TextStyle(height: 23 / 24, color: color ?? MyColors.darkTextColor, fontSize: 24, letterSpacing: -1.44, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), ); Widget toText32({Color? color, bool isBold = false}) => Text( @@ -79,6 +79,11 @@ extension EmailValidator on String { style: TextStyle(height: 32 / 32, color: color ?? MyColors.darkTextColor, fontSize: 32, letterSpacing: -1.92, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), ); + Widget toText44({Color? color, bool isBold = false}) => Text( + this, + style: TextStyle(height: 32 / 32, color: color ?? MyColors.darkTextColor, fontSize: 44, letterSpacing: -2.64, fontWeight: isBold ? FontWeight.bold : FontWeight.w600), + ); + Widget toSectionHeading({String upperHeading = "", String lowerHeading = ""}) { String upper = ""; String lower = ""; diff --git a/lib/extensions/widget_extensions.dart b/lib/extensions/widget_extensions.dart index 5169f19..31f8374 100644 --- a/lib/extensions/widget_extensions.dart +++ b/lib/extensions/widget_extensions.dart @@ -9,6 +9,8 @@ extension WidgetExtensions on Widget { Widget get center => Center(child: this); + Widget get expanded => Expanded(child: this); + Widget paddingAll(double _value) => Padding(padding: EdgeInsets.all(_value), child: this); Widget paddingOnly({double left = 0.0, double right = 0.0, double top = 0.0, double bottom = 0.0}) => diff --git a/lib/ui/attendance/monthly_attendance.dart b/lib/ui/attendance/monthly_attendance.dart new file mode 100644 index 0000000..ff370a3 --- /dev/null +++ b/lib/ui/attendance/monthly_attendance.dart @@ -0,0 +1,671 @@ +import 'package:easy_localization/src/public_ext.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/painting.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/widgets/circular_step_progress_bar.dart'; +import 'package:syncfusion_flutter_calendar/calendar.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:pie_chart/pie_chart.dart'; + +class MonthlyAttendance extends StatefulWidget { + MonthlyAttendance({Key? key}) : super(key: key); + + @override + _MonthlyAttendanceState createState() { + return _MonthlyAttendanceState(); + } +} + +class _MonthlyAttendanceState extends State { + bool isPresent = true; + bool isAbsent = true; + bool isMissingDays = true; + bool isOffDays = true; + + @override + void initState() { + super.initState(); + } + + Map dataMap = { + "Present": 65, + "Absent": 35, + }; + + final List _colorList = [Color(0xff2AB2AB), Color(0xff202529)]; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: MyColors.white, + leading: IconButton( + icon: const Icon( + Icons.arrow_back_ios, + color: MyColors.backgroundBlackColor, + ), + onPressed: () => Navigator.pop(context), + ), + ), + backgroundColor: Colors.white, + body: ListView( + scrollDirection: Axis.vertical, + children: [ + Column( + children: [ + 20.height, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Attendance".toText24(isBold: true, color: MyColors.darkIconColor), + Row( + children: [ + "June 13, 2021".toText16(color: MyColors.greyACColor), + const Icon(Icons.keyboard_arrow_down_rounded, color: MyColors.greyACColor), + ], + ).onPress(() { + showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2021), + lastDate: DateTime(2025), + builder: (context, child) { + return Theme( + data: ThemeData.dark().copyWith( + colorScheme: const ColorScheme.dark( + primary: MyColors.lightGreenColor, + onPrimary: MyColors.white, + surface: MyColors.lightGreenColor, + onSurface: MyColors.darkTextColor, + ), + dialogBackgroundColor: Colors.white, + ), + child: child!, + ); + }, + ); + }) + ], + ).paddingOnly(left: 21, right: 21), + 18.height, + AspectRatio(aspectRatio: 333 / 270, child: calenderWidget()).paddingOnly(left: 21, right: 21), + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + optionUI("Schedule\nDays", "16"), + 6.width, + optionUI("Off\nDays", "0"), + 6.width, + optionUI("Non\nAnalyzed", "0"), + 6.width, + optionUI("Shortage\nHour", "6"), + ], + ).paddingOnly(left: 21, right: 21), + 35.height, + Container( + width: double.infinity, + height: 227, + decoration: BoxDecoration( + color: Colors.white, + borderRadius: const BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), + boxShadow: [ + BoxShadow( + offset: const Offset(0, 2), + blurRadius: 26, + color: MyColors.darkColor.withOpacity(0.1), + ), + ], + ), + child: Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + children: [ + "Attendance".toText12(isBold: true, color: MyColors.grey3AColor), + "Stats".toText24(isBold: true, color: MyColors.grey3AColor), + ], + ).paddingOnly(left: 21, top: 29, bottom: 36), + Row( + children: [ + Container( + height: 9, + width: 9, + decoration: BoxDecoration( + color: MyColors.lightGreenColor, + borderRadius: BorderRadius.circular(100), + ), + ), + Container( + margin: const EdgeInsets.only(left: 5, right: 5), + child: "PRESENT 16".toText16(isBold: true, color: MyColors.lightGreenColor), + ), + ], + ).paddingOnly(left: 21, right: 23), + 8.height, + Row( + children: [ + Container( + height: 9, + width: 9, + decoration: BoxDecoration( + color: MyColors.backgroundBlackColor, + borderRadius: BorderRadius.circular(100), + ), + ), + Container( + margin: const EdgeInsets.only(left: 5, right: 5), + child: "ABSENT 04".toText16( + isBold: true, + color: MyColors.backgroundBlackColor, + ), + ) + ], + ).paddingOnly(left: 21, top: 8), + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: 169, + height: 170, + child: PieChart( + dataMap: dataMap, + animationDuration: const Duration(milliseconds: 800), + chartLegendSpacing: 0, + chartRadius: MediaQuery.of(context).size.width / 5.2, + colorList: _colorList, + initialAngleInDegree: 0, + chartType: ChartType.ring, + ringStrokeWidth: 80, + legendOptions: const LegendOptions( + showLegendsInRow: false, + showLegends: false, + ), + chartValuesOptions: const ChartValuesOptions( + showChartValueBackground: false, + showChartValues: true, + showChartValuesInPercentage: true, + showChartValuesOutside: false, + decimalPlaces: 1, + chartValueStyle: TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + color: MyColors.white, + )), + ), + ), + ], + ).paddingOnly(left: 65, top: 27, right: 21, bottom: 28), + ], + ), + ), + ], + ), + ], + ), + ); + } + + Widget optionUI(String title, String value) { + return AspectRatio( + aspectRatio: 1 / 1, + child: Container( + padding: const EdgeInsets.only(top: 10, left: 8, right: 8, bottom: 10), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(12), + boxShadow: [ + BoxShadow( + offset: const Offset(0, 1), + blurRadius: 15, + color: MyColors.darkColor.withOpacity(0.1), + ), + ], + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [title.toText10(color: MyColors.darkTextColor).expanded, value.toText20(color: MyColors.darkTextColor)], + ), + ), + ).expanded; + } + + Widget calenderWidget() { + return SfCalendar( + view: CalendarView.month, + headerHeight: 0, + todayHighlightColor: MyColors.grey3AColor, + viewHeaderStyle: const ViewHeaderStyle( + dayTextStyle: TextStyle(color: MyColors.grey3AColor, fontSize: 13, fontWeight: FontWeight.w600), + ), + monthCellBuilder: (cxt, build) { + int val = build.date.day % 4; + isPresent = val == 0; + isAbsent = val == 1; + isMissingDays = val == 2; + isOffDays = val == 3; + if (isPresent) { + return Container( + margin: const EdgeInsets.all(4), + decoration: BoxDecoration( + gradient: const LinearGradient( + transform: GradientRotation(.46), + begin: Alignment.topRight, + end: Alignment.bottomLeft, + colors: [MyColors.gradiantEndColor, MyColors.gradiantStartColor], + ), + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + offset: const Offset(0, 2), + blurRadius: 26, + color: MyColors.blackColor.withOpacity(0.100), + ), + ], + ), + alignment: Alignment.center, + child: Text( + "${build.date.day}", + style: const TextStyle( + fontSize: 13, + fontWeight: FontWeight.w500, + color: MyColors.white, + ), + ), + ); + } else if (isAbsent) { + return Container( + margin: const EdgeInsets.all(4), + decoration: BoxDecoration( + color: MyColors.backgroundBlackColor, + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + offset: const Offset(0, 2), + blurRadius: 26, + color: MyColors.blackColor.withOpacity(0.100), + ), + ], + ), + alignment: Alignment.center, + child: Text( + "${build.date.day}", + style: const TextStyle( + fontSize: 13, + fontWeight: FontWeight.w500, + color: MyColors.white, + ), + ), + ); + } else if (isMissingDays) { + return Container( + margin: const EdgeInsets.all(4), + decoration: BoxDecoration( + border: Border.all(color: MyColors.backgroundBlackColor, width: 2.0, style: BorderStyle.solid), //Border.all + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + offset: const Offset(0, 2), + blurRadius: 26, + color: MyColors.blackColor.withOpacity(0.100), + ), + ], + ), + alignment: Alignment.center, + child: Text( + "${build.date.day}", + style: const TextStyle( + fontSize: 13, + fontWeight: FontWeight.w500, + color: Color(0xff1F2428), + ), + ), + ); + } else if (isOffDays) { + return Container( + margin: const EdgeInsets.all(4), + decoration: BoxDecoration( + color: MyColors.greyACColor.withOpacity(.12), + shape: BoxShape.circle, + ), + alignment: Alignment.center, + child: Text( + "${build.date.day}", + style: const TextStyle( + fontSize: 13, + fontWeight: FontWeight.w500, + color: MyColors.greyA5Color, + ), + ), + ); + } else { + return Container(); + } + }, + monthViewSettings: const MonthViewSettings( + dayFormat: 'EEE', + showTrailingAndLeadingDates: false, + appointmentDisplayMode: MonthAppointmentDisplayMode.appointment, + showAgenda: false, + navigationDirection: MonthNavigationDirection.horizontal, + monthCellStyle: MonthCellStyle( + textStyle: TextStyle( + fontStyle: FontStyle.normal, + fontSize: 13, + color: Colors.white, + ), + ), + ), + showNavigationArrow: false, + showDatePickerButton: false, + showCurrentTimeIndicator: false, + showWeekNumber: false, + cellBorderColor: Colors.white, + selectionDecoration: BoxDecoration( + border: Border.all(color: MyColors.white, width: 10), + borderRadius: const BorderRadius.all(Radius.circular(100)), + shape: BoxShape.circle, + ), + dataSource: MeetingDataSource(_getDataSource()), + onTap: calendarTapped, + ); + } + + void calendarTapped(CalendarTapDetails details) { + showModalBottomSheet( + context: context, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(25)), + isScrollControlled: true, + backgroundColor: MyColors.backgroundBlackColor, + builder: (_) { + return DraggableScrollableSheet( + maxChildSize: 0.9, + expand: false, + builder: (_, controller) { + return Column( + children: [ + Container( + width: 75, + height: 7, + margin: const EdgeInsets.symmetric(vertical: 10), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + color: MyColors.darkGreyColor, + ), + ), + Expanded( + child: ListView.builder( + controller: controller, + itemCount: 1, + itemBuilder: (_, i) => Container( + decoration: const BoxDecoration( + borderRadius: BorderRadius.vertical( + top: Radius.circular(35.0), + ), + color: MyColors.backgroundBlackColor, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column(children: [ + "June 13, 2021".toText24(isBold: true, color: Colors.white), + LocaleKeys.attendanceDetails.tr().toText16(color: MyColors.lightGreyEFColor), + 21.height, + ]).paddingOnly(top: 25, left: 21, right: 21, bottom: 10), + Center( + child: CircularStepProgressBar( + totalSteps: 16 * 4, + currentStep: 16, + width: 210, + height: 210, + selectedColor: MyColors.gradiantEndColor, + unselectedColor: MyColors.grey70Color, + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + "99%".toText44(color: Colors.white, isBold: true), + "Completed".tr().toText11(color: MyColors.greyACColor), + 19.height, + "Shift Time".tr().toText11(color: MyColors.greyACColor), + "08:00 - 17:00".toText22(color: Colors.white, isBold: true), + ], + ), + ), + ), + ), + Container( + padding: const EdgeInsets.only(top: 20, bottom: 20), + ), + Stack( + children: [ + Container( + height: 5, + padding: const EdgeInsets.only(top: 24, bottom: 24), + color: MyColors.backgroundBlackColor, + ), + Container( + width: double.infinity, + decoration: const BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: Colors.white), + padding: const EdgeInsets.only(left: 21, right: 21, top: 28, bottom: 24), + child: Column( + children: [ + Row( + children: [ + Container( + margin: const EdgeInsets.only(right: 30, left: 15), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Actual Check In ".tr().toText11( + color: MyColors.grey67Color, + ), + 8.height, + "08:27".toText22(color: Colors.black, isBold: true), + ], + ), + ), + 40.width, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Actual Check Out".tr().toText11( + color: MyColors.grey67Color, + ), + 8.height, + "18:20".toText22(color: Colors.black, isBold: true), + ], + ), + ], + ), + 25.height, + const Divider( + height: 1, + thickness: 1, + color: MyColors.whiteColor, + ), + 25.height, + Row( + children: [ + Container( + margin: const EdgeInsets.only(right: 30, left: 15), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Approved Check In".tr().toText11( + color: MyColors.grey67Color, + ), + 8.height, + "09:27".toText22(color: MyColors.greenColor, isBold: true), + ], + ), + ), + 30.width, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Approved Check Out".tr().toText11( + color: MyColors.grey67Color, + ), + 8.height, + "18:20".toText22(color: MyColors.greenColor, isBold: true), + ], + ), + ], + ), + 25.height, + const Divider( + height: 1, + thickness: 1, + color: MyColors.whiteColor, + ), + 25.height, + Row( + children: [ + Container( + margin: const EdgeInsets.only(right: 30, left: 15), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Late In".tr().toText11( + color: MyColors.grey67Color, + ), + 8.height, + "00:27".toText22(color: MyColors.redColor, isBold: true), + ], + ), + ), + 80.width, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Excess".tr().toText11( + color: MyColors.grey67Color, + ), + 8.height, + "00:00".toText22(color: Colors.black, isBold: true), + ], + ), + ], + ), + 25.height, + const Divider( + height: 1, + thickness: 1, + color: MyColors.whiteColor, + ), + 25.height, + Row( + children: [ + Container( + margin: const EdgeInsets.only(right: 30, left: 15), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Shortage".tr().toText11( + color: MyColors.grey67Color, + ), + 8.height, + "00:00".toText22(color: Colors.black, isBold: true), + ], + ), + ), + 80.width, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + "Early Out".tr().toText11( + color: MyColors.grey67Color, + ), + 8.height, + "00:00".toText22(color: Colors.black, isBold: true), + ], + ), + ], + ), + ], + ), + ), + ], + ), + ], + ), + ), + ), + ), + ], + ); + }, + ); + }, + ); + } + + List _getDataSource() { + final List meetings = []; + + // _events.forEach((key, value) { + // final DateTime startTime = DateTime(key.year, key.month, key.day, 21, 0, 0); + // final DateTime endTime = DateTime(key.year, key.month, key.day, 22, 0, 0); + // meetings.add(Meeting("", startTime, endTime, MyColors.backgroundBlackColor, false)); + // }); + return meetings; + } +} + +class MeetingDataSource extends CalendarDataSource { + MeetingDataSource(List source) { + appointments = source; + } + + @override + DateTime getStartTime(int index) { + return _getMeetingData(index).from; + } + + @override + DateTime getEndTime(int index) { + return _getMeetingData(index).to; + } + + @override + String getSubject(int index) { + return _getMeetingData(index).eventName; + } + + @override + Color getColor(int index) { + return _getMeetingData(index).background; + } + + @override + bool isAllDay(int index) { + return _getMeetingData(index).isAllDay; + } + + Meeting _getMeetingData(int index) { + final dynamic meeting = appointments; + Meeting meetingData; + if (meeting is Meeting) { + meetingData = meeting; + } + return meeting; + } +} + +class Meeting { + Meeting(this.eventName, this.from, this.to, this.background, this.isAllDay); + + String eventName; + DateTime from; + DateTime to; + Color background; + bool isAllDay; +} diff --git a/lib/ui/bottom_sheets/attendence_details_bottom_sheet.dart b/lib/ui/bottom_sheets/attendence_details_bottom_sheet.dart new file mode 100644 index 0000000..4c42d6c --- /dev/null +++ b/lib/ui/bottom_sheets/attendence_details_bottom_sheet.dart @@ -0,0 +1,228 @@ +import 'package:easy_localization/src/public_ext.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/widgets/circular_step_progress_bar.dart'; + +class AttendenceDetailsBottomSheet extends StatefulWidget { + + AttendenceDetailsBottomSheet({Key? key}) : super(key: key); + + @override + _AttendenceDetailsBottomSheetState createState() => _AttendenceDetailsBottomSheetState(); +} + +class _AttendenceDetailsBottomSheetState extends State { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + bottomSheet:BottomSheet( + + onClosing: () => print("not getting called"), + builder: (_) => Container( + color: Colors.red, + height: MediaQuery.of(context).size.height*0.9, + child: Column( + children: [ + Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.vertical( top: Radius.circular(25.0),), + color: MyColors.backgroundBlackColor, + ), + margin:EdgeInsets.only(top: 45) , + padding: EdgeInsets.only(left: 11, right: 11, bottom: 21), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Padding( + padding: const EdgeInsets.all(10), + child: Container( + margin:EdgeInsets.only(top: 5) , + decoration: BoxDecoration( + borderRadius: BorderRadius.all(Radius.circular(35.0),), + color: Color(0xff464646), + ), + width: 80, + height: 6, + ), + ), + ), + Container( + padding: EdgeInsets.only(top: 25,left: 11, right: 11, bottom: 10), + child: Column(children: [ + "June 13, 2021".toText24(isBold: true, color: Colors.white), + LocaleKeys.attendanceDetails.tr().toText16(color: Color(0xffACACAC)), + // LocaleKeys.timeLeftToday.tr().toText16(color: Color(0xffACACAC)), + 21.height, + ] ), + ), + Center( + child: CircularStepProgressBar( + totalSteps: 16 * 4, + currentStep: 16, + width: 210, + height: 210, + selectedColor: MyColors.gradiantEndColor, + unselectedColor: MyColors.grey70Color, + child: Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + "99%".toText32(color: Colors.white, isBold: true), + "Completed".tr().toText12(color: MyColors.greyACColor), + 19.height, + "Shift Time".tr().toText12(color: MyColors.greyACColor), + "08:00 - 17:00".toText22(color: Colors.white, isBold: true), + ], + ), + ), + ), + ), + ], + ), + ), + Stack( + children: [ + Container( + height: 32, + // padding: EdgeInsets.only(top: 24, bottom: 24), + color: MyColors.backgroundBlackColor, + ), + Container( + width: double.infinity, + decoration: BoxDecoration(borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), color: Colors.white), + margin: EdgeInsets.only(top: 10), + padding: EdgeInsets.only(left: 21, right: 21, top: 24, bottom: 24), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceAround, + children:[ + Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + "Actual Check In ".tr().toText12(color: MyColors.black), + ], + ), + SizedBox(height: 8,), + Row( + children: [ + "08:27".toText22(color: Colors.black, isBold: true), + ], + ), + SizedBox(height: 30,), + Row( + children: [ + "Approved Check In".tr().toText12(color: MyColors.black), + ], + ), + SizedBox(height: 8,), + Row( + children: [ + "09:27".toText22(color: Color(0xff1FA269), isBold: true), + ], + ), + SizedBox(height: 30,), + Row( + children: [ + "Late In".tr().toText12(color: MyColors.black), + ], + ), + SizedBox(height: 8,), + Row( + children: [ + "00:27".toText22(color: Color(0xffD02127), isBold: true), + ], + ), + SizedBox(height: 30,), + Row( + children: [ "Shortage".tr().toText12(color: MyColors.black), + ] ), + SizedBox(height: 8,), + Row( + children: [ + "00:00".toText22(color: Colors.black, isBold: true),], + ), + ], + ), + ], + ), + Row( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + "Actual Check Out".tr().toText12(color: MyColors.black), + ], + ), + SizedBox(height: 8,), + Row( + children: [ + "18:20".toText22(color: Colors.black, isBold: true),], + ), + SizedBox(height: 30,), + Row( + children: [ "Approved Check Out".tr().toText12(color: MyColors.black), + ], + ), + SizedBox(height: 8,), + Row( + children: [ + "18:20".toText22(color: Color(0xff1FA269), isBold: true),], + ), + SizedBox(height: 30,), + Row( + children: ["Excess".tr().toText12(color: MyColors.black), + ], + ), + SizedBox(height: 8,), + Row( + children: [ + "00:00".toText22(color: Colors.black, isBold: true),], + ), + SizedBox(height: 30,), + Row( + children: ["Early Out".tr().toText12(color: MyColors.black), + ], + ), + SizedBox(height: 8,), + Row( + children: [ + "00:00".toText22(color: Colors.black, isBold: true),], + ), + ], + ), + ], + ), + ] ), + ), + ]), + ], + ), + ) + )); + + } + + +} diff --git a/lib/ui/landing/dashboard.dart b/lib/ui/landing/dashboard.dart new file mode 100644 index 0000000..feb405d --- /dev/null +++ b/lib/ui/landing/dashboard.dart @@ -0,0 +1,478 @@ +import 'package:easy_localization/src/public_ext.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:mohem_flutter_app/classes/colors.dart'; +import 'package:mohem_flutter_app/config/routes.dart'; +import 'package:mohem_flutter_app/extensions/int_extensions.dart'; +import 'package:mohem_flutter_app/extensions/string_extensions.dart'; +import 'package:mohem_flutter_app/extensions/widget_extensions.dart'; +import 'package:mohem_flutter_app/generated/locale_keys.g.dart'; +import 'package:mohem_flutter_app/widgets/circular_avatar.dart'; +import 'package:mohem_flutter_app/widgets/circular_step_progress_bar.dart'; + + + + +class Dashboard extends StatefulWidget { + Dashboard({Key? key}) : super(key: key); + + @override + _DashboardState createState() { + return _DashboardState(); + } +} + +class _DashboardState extends State { + @override + void initState() { + super.initState(); + } + + @override + void dispose() { + super.dispose(); + } + + @override + Widget build(BuildContext context) { + List names = [ + LocaleKeys.workList.tr(), + LocaleKeys.missingSwipes.tr(), + LocaleKeys.leaveBalance.tr(), + LocaleKeys.ticketBalance.tr() + ]; + List namesInt = [118, 02, 18.5, 03]; + List namesColor = [0xff125765, 0xff239D8F, 0xff2BB8A8, 0xff1D92AA]; + + List namesT = [ + LocaleKeys.monthlyAttendance.tr(), + LocaleKeys.workFromHome.tr(), + LocaleKeys.ticketRequest.tr(), + LocaleKeys.monthlyAttendance.tr() + ]; + List iconT = [ + "assets/images/monthly_attendance.svg", + "assets/images/work_from_home.svg", + "assets/images/ticket_request.svg", + "assets/images/work_from_home.svg" + ]; + + List namesD = [ + "Nostalgia Perfume Perfume", + "Al Nafoura", + "AlJadi", + "Nostalgia Perfume" + ]; + + return Scaffold( + body: Column( + children: [ + Row( + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + CircularAvatar( + width: 34, + height: 34, + url: + "https://cdn4.iconfinder.com/data/icons/professions-2-2/151/89-512.png", + ), + 8.width, + SvgPicture.asset("assets/images/side_nav.svg"), + ], + ).onPress(() {}), + Expanded( + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + //AppLogo(), + 8.width, + LocaleKeys.mohemm.tr().toText14() + ], + ), + ), + SizedBox( + width: 36, + height: 36, + child: Stack( + alignment: Alignment.centerLeft, + children: [ + SvgPicture.asset("assets/images/announcements.svg"), + Positioned( + right: 0, + top: 0, + child: Container( + padding: const EdgeInsets.only(left: 5, right: 5), + decoration: BoxDecoration( + color: MyColors.redColor, + borderRadius: BorderRadius.circular(17)), + child: "3".toText12(color: Colors.white), + ), + ) + ], + ), + ) + ], + ).paddingOnly(left: 21, right: 21, top: 48, bottom: 7), + Expanded( + child: ListView( + padding: EdgeInsets.zero, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LocaleKeys.goodMorning + .tr() + .toText14(color: MyColors.grey77Color), + "Mahmoud Shrouf".toText24(isBold: true), + 16.height, + Row( + children: [ + Expanded( + child: AspectRatio( + aspectRatio: 159 / 159, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(15), + gradient: const LinearGradient( + transform: GradientRotation(.46), + begin: Alignment.topRight, + end: Alignment.bottomRight, + colors: [ + MyColors.gradiantEndColor, + MyColors.gradiantStartColor, + ]), + ), + child: Stack( + alignment: Alignment.center, + children: [ + SvgPicture.asset("assets/images/"), + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + LocaleKeys.markAttendance + .tr() + .toText14( + color: Colors.white, + isBold: true), + 9.height, + "07:55:12".toText14( + color: Colors.white, + isBold: true), + LocaleKeys.timeLeftToday + .tr() + .toText12(color: Colors.white), + 9.height, + const ClipRRect( + borderRadius: BorderRadius.all( + Radius.circular(20), + ), + child: LinearProgressIndicator( + value: 0.7, + minHeight: 8, + valueColor: + const AlwaysStoppedAnimation< + Color>(Colors.white), + backgroundColor: + const Color(0xff196D73), + ), + ), + ], + ).paddingOnly( + top: 12, right: 15, left: 12), + ), + Row( + children: [ + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + LocaleKeys.checkIn + .tr() + .toText12( + color: Colors.white), + "09:00".toText14( + color: Colors.white, + isBold: true), + 4.height + ], + ).paddingOnly(left: 12), + ), + Container( + width: 45, + height: 45, + padding: const EdgeInsets.only( + left: 14, right: 14), + decoration: const BoxDecoration( + color: Color(0xff259EA4), + borderRadius: BorderRadius.only( + bottomRight: + Radius.circular(15), + ), + ), + child: SvgPicture.asset( + "assets/images/stop.svg"), + ), + ], + ), + ], + ), + ], + ), + ).onPress(() { + Navigator.pushNamed( + context, AppRoutes.todayAttendance); + }), + ), + ), + 9.width, + Expanded( + child: GridView.builder( + shrinkWrap: true, + primary: false, + physics: const NeverScrollableScrollPhysics(), + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + childAspectRatio: 2 / 2, + crossAxisSpacing: 9, + mainAxisSpacing: 9), + padding: EdgeInsets.zero, + itemCount: 4, + itemBuilder: (BuildContext context, int index) { + return Container( + decoration: BoxDecoration( + color: Color(namesColor[index]), + borderRadius: BorderRadius.circular(10), + ), + child: Column( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + names[index].toText12(color: Colors.white), + Row( + children: [ + Expanded( + child: namesInt[index] + .toStringAsFixed(1) + .toText16( + color: Colors.white, + isBold: true), + ), + SvgPicture.asset( + "assets/images/arrow_next.svg", + color: Colors.white) + ], + ) + ], + ).paddingOnly( + left: 10, right: 10, bottom: 6, top: 6), + ).onPress(() { + Navigator.pushNamed( + context, AppRoutes.workList); + }); + }, + ), + ), + ], + ), + 20.height, + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + "Other".tr().toText12(), + LocaleKeys.services.tr().toText24(isBold: true), + ], + ), + ), + LocaleKeys.viewAllServices + .tr() + .toText12(isUnderLine: true), + ], + ), + ], + ).paddingOnly(left: 21, right: 21, top: 7), + SizedBox( + height: 105 + 26, + child: ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only( + left: 21, right: 21, top: 13, bottom: 13), + scrollDirection: Axis.horizontal, + itemBuilder: (cxt, index) { + return AspectRatio( + aspectRatio: 105 / 105, + child: Container( + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(15), + boxShadow: [ + BoxShadow( + color: + const Color(0xff000000).withOpacity(.05), + blurRadius: 26, + offset: const Offset(0, -3), + ), + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SvgPicture.asset(iconT[index]), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Expanded( + child: + namesT[index].toText11(isBold: true), + ), + SvgPicture.asset( + "assets/images/arrow_next.svg") + .paddingOnly(bottom: 4) + ], + ) + ], + ).paddingOnly( + left: 10, right: 10, bottom: 10, top: 12), + ), + ); + }, + separatorBuilder: (cxt, index) => 9.width, + itemCount: 4), + ), + 8.height, + Container( + width: double.infinity, + padding: EdgeInsets.only(top: 31), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.only( + topRight: Radius.circular(50), + topLeft: Radius.circular(50)), + border: + Border.all(color: MyColors.lightGreyEDColor, width: 1), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + LocaleKeys.offers.tr().toText12(), + Row( + children: [ + LocaleKeys.discounts + .tr() + .toText24(isBold: true), + 6.width, + Container( + padding: const EdgeInsets.only( + left: 8, right: 8), + decoration: BoxDecoration( + color: MyColors.yellowColor, + borderRadius: + BorderRadius.circular(10), + ), + child: LocaleKeys.newString + .tr() + .toText10(isBold: true)), + ], + ), + ], + ), + ), + LocaleKeys.viewAllOffers + .tr() + .toText12(isUnderLine: true), + ], + ).paddingOnly(left: 21, right: 21).onPress(() { + Navigator.pushNamed( + context, AppRoutes.monthlyAttendance); + }), + SizedBox( + height: 103 + 33, + child: ListView.separated( + shrinkWrap: true, + physics: const BouncingScrollPhysics(), + padding: const EdgeInsets.only( + left: 21, right: 21, top: 13), + scrollDirection: Axis.horizontal, + itemBuilder: (cxt, index) { + return SizedBox( + width: 73, + child: Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Container( + width: 73, + height: 73, + decoration: BoxDecoration( + borderRadius: const BorderRadius.all( + Radius.circular(100), + ), + border: Border.all( + color: MyColors.lightGreyEDColor, + width: 1), + ), + child: ClipRRect( + borderRadius: const BorderRadius.all( + Radius.circular(50), + ), + child: Image.network( + "https://play-lh.googleusercontent.com/NPo88ojmhah4HDiposucJmfQIop4z4xc8kqJK9ITO9o-yCab2zxIp7PPB_XPj2iUojo", + fit: BoxFit.cover, + ), + ), + ), + 4.height, + Expanded( + child: namesD[6 % (index + 1)].toText12( + isCenter: true, maxLine: 2)), + ], + ), + ); + }, + separatorBuilder: (cxt, index) => 8.width, + itemCount: 6), + ), + ], + ), + ) + ], + ), + ) + ], + ), + ); + } + + + + +} diff --git a/pubspec.yaml b/pubspec.yaml index d38cc5a..25af120 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,6 +59,10 @@ dependencies: geolocator: any # flutter_compass: ^0.6.1 google_maps_flutter_web: ^0.3.2 + syncfusion_flutter_calendar: ^19.4.48 + flutter_calendar_carousel: ^2.1.0 + pie_chart: ^5.1.0 + dev_dependencies: