From dbb3450c32e243b63dbaf7e924f446f4eead99cc Mon Sep 17 00:00:00 2001 From: mohammad Date: Wed, 11 Sep 2024 16:04:54 +0300 Subject: [PATCH 1/4] new HourPicker --- lib/pages/common/hour_picker_dialog.dart | 78 ++++++++----------- .../bloc/visitor_password_bloc.dart | 25 ++++-- lib/utils/style.dart | 24 ++++++ pubspec.lock | 8 ++ pubspec.yaml | 2 +- 5 files changed, 81 insertions(+), 56 deletions(-) diff --git a/lib/pages/common/hour_picker_dialog.dart b/lib/pages/common/hour_picker_dialog.dart index 2c89b710..01a87720 100644 --- a/lib/pages/common/hour_picker_dialog.dart +++ b/lib/pages/common/hour_picker_dialog.dart @@ -1,7 +1,10 @@ + + import 'package:flutter/material.dart'; class HourPickerDialog extends StatefulWidget { final TimeOfDay initialTime; + const HourPickerDialog({super.key, required this.initialTime}); @override @@ -9,70 +12,50 @@ class HourPickerDialog extends StatefulWidget { } class _HourPickerDialogState extends State { - late int _selectedHour; - bool _isPm = false; + late String selectedHour; @override void initState() { super.initState(); - _selectedHour = widget.initialTime.hour > 12 - ? widget.initialTime.hour - 12 - : widget.initialTime.hour; - _isPm = widget.initialTime.period == DayPeriod.pm; + // Initialize the selectedHour with the initial time passed to the dialog + selectedHour = widget.initialTime.hour.toString().padLeft(2, '0') + ':00'; } @override Widget build(BuildContext context) { return AlertDialog( title: const Text('Select Hour'), - content: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - DropdownButton( - value: _selectedHour, - items: List.generate(12, (index) { - int displayHour = index + 1; - return DropdownMenuItem( - value: displayHour, - child: Text(displayHour.toString()), - ); - }), - onChanged: (value) { - setState(() { - _selectedHour = value!; - }); - }, - ), - SizedBox(width: 16.0), - DropdownButton( - value: _isPm, - items: const [ - DropdownMenuItem( - value: false, - child: Text('AM'), - ), - DropdownMenuItem( - value: true, - child: Text('PM'), - ), - ], - onChanged: (value) { - setState(() { - _isPm = value!; - }); - }, - ), - ], + content: DropdownButton( + value: selectedHour, // Show the currently selected hour + items: List.generate(24, (index) { + String hour = index.toString().padLeft(2, '0'); + return DropdownMenuItem( + value: '$hour:00', + child: Text('$hour:00'), + ); + }), + onChanged: (String? newValue) { + if (newValue != null) { + setState(() { + selectedHour = newValue; // Update the selected hour without closing the dialog + }); + } + }, ), actions: [ TextButton( - onPressed: () => Navigator.of(context).pop(null), + onPressed: () => Navigator.of(context).pop(null), // Close the dialog without selection child: const Text('Cancel'), ), TextButton( onPressed: () { - int hour = _isPm ? _selectedHour + 12 : _selectedHour; - Navigator.of(context).pop(TimeOfDay(hour: hour, minute: 0)); + // Close the dialog and return the selected time + Navigator.of(context).pop( + TimeOfDay( + hour: int.parse(selectedHour.split(':')[0]), + minute: 0, + ), + ); }, child: const Text('OK'), ), @@ -86,6 +69,7 @@ Future showHourPicker({ required TimeOfDay initialTime, }) { return showDialog( + barrierDismissible: false, context: context, builder: (context) => HourPickerDialog(initialTime: initialTime), ); diff --git a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart index 02f5ef0a..ae0eda30 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart @@ -2,6 +2,7 @@ import 'dart:math'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'package:intl/intl.dart'; import 'package:syncrow_web/pages/common/custom_dialog.dart'; import 'package:syncrow_web/pages/common/hour_picker_dialog.dart'; @@ -14,6 +15,7 @@ import 'package:syncrow_web/services/access_mang_api.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/snack_bar.dart'; +import 'package:syncrow_web/utils/style.dart'; class VisitorPasswordBloc extends Bloc { VisitorPasswordBloc() : super(VisitorPasswordInitial()) { @@ -32,9 +34,9 @@ class VisitorPasswordBloc extends Bloc(selectTimeOfLinePassword); on(changeTime); } + final TextEditingController userNameController = TextEditingController(); final TextEditingController emailController = TextEditingController(); - final TextEditingController deviceNameController = TextEditingController(); final TextEditingController deviceIdController = TextEditingController(); final TextEditingController unitNameController = TextEditingController(); @@ -377,19 +379,26 @@ class VisitorPasswordBloc extends Bloc expirationTimeTimeStamp!) { - CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.'); + showCustomToast( + message: "Effective Time cannot be later than Expiration Time.", + gravity: ToastGravity.CENTER, + textColor: Colors.white, + fontSize: 16.0, + ); } else { - effectiveTime = - selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds + effectiveTime = selectedDateTime.toString().split('.').first; effectiveTimeTimeStamp = selectedTimestamp; } } else { if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) { - CustomSnackBar.displaySnackBar( - 'Expiration Time cannot be earlier than Effective Time.'); + showCustomToast( + message: 'Expiration Time cannot be earlier than Effective Time.', + gravity: ToastGravity.CENTER, + textColor: Colors.white, + fontSize: 16.0, + ); } else { - expirationTime = - selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds + expirationTime = selectedDateTime.toString().split('.').first; expirationTimeTimeStamp = selectedTimestamp; } } diff --git a/lib/utils/style.dart b/lib/utils/style.dart index 3f31f9d7..33a850a7 100644 --- a/lib/utils/style.dart +++ b/lib/utils/style.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:fluttertoast/fluttertoast.dart'; import 'color_manager.dart'; InputDecoration? textBoxDecoration({bool suffixIcon = false}) => @@ -41,3 +42,26 @@ BoxDecoration containerDecoration = BoxDecoration( ], color: ColorsManager.boxColor, borderRadius: const BorderRadius.all(Radius.circular(10))); + + +/// A function to display a customizable toast message +void showCustomToast({ + required String message, + ToastGravity gravity = ToastGravity.BOTTOM, + Color textColor = Colors.white, + Toast toastLength = Toast.LENGTH_SHORT, + int timeInSecForIosWeb = 2, + double fontSize = 16.0, +}) { + Fluttertoast.showToast( + msg: message, + webBgColor: "linear-gradient(to right, #dc1c13, #dc1c13)", + webPosition:'right' , + toastLength: toastLength, + webShowClose: true, + gravity: gravity, + timeInSecForIosWeb: timeInSecForIosWeb, + textColor: textColor, + fontSize: fontSize, + ); +} diff --git a/pubspec.lock b/pubspec.lock index 8b9df6d6..e358cdbf 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -232,6 +232,14 @@ packages: description: flutter source: sdk version: "0.0.0" + fluttertoast: + dependency: "direct main" + description: + name: fluttertoast + sha256: "95f349437aeebe524ef7d6c9bde3e6b4772717cf46a0eb6a3ceaddc740b297cc" + url: "https://pub.dev" + source: hosted + version: "8.2.8" get_it: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index d187cf1a..14210eb5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -49,7 +49,7 @@ dependencies: intl: ^0.19.0 dropdown_search: ^5.0.6 flutter_dotenv: ^5.1.0 - + fluttertoast: ^8.2.8 dev_dependencies: flutter_test: From 0ac3e79c3057aa95c924c5eb7b3b0b9e0d088a12 Mon Sep 17 00:00:00 2001 From: mohammad Date: Thu, 12 Sep 2024 14:18:53 +0300 Subject: [PATCH 2/4] new HourPicker --- .../bloc/visitor_password_bloc.dart | 18 ++++----------- .../view/visitor_password_dialog.dart | 3 +++ lib/utils/style.dart | 23 ------------------- pubspec.lock | 8 ------- pubspec.yaml | 1 - 5 files changed, 8 insertions(+), 45 deletions(-) diff --git a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart index ae0eda30..4982c7f1 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart @@ -2,7 +2,6 @@ import 'dart:math'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'package:intl/intl.dart'; import 'package:syncrow_web/pages/common/custom_dialog.dart'; import 'package:syncrow_web/pages/common/hour_picker_dialog.dart'; @@ -53,6 +52,7 @@ class VisitorPasswordBloc extends Bloc expirationTimeTimeStamp!) { - showCustomToast( - message: "Effective Time cannot be later than Expiration Time.", - gravity: ToastGravity.CENTER, - textColor: Colors.white, - fontSize: 16.0, - ); + accessPeriodValidate="Effective Time cannot be later than Expiration Time."; } else { + accessPeriodValidate=''; effectiveTime = selectedDateTime.toString().split('.').first; effectiveTimeTimeStamp = selectedTimestamp; } } else { if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) { - showCustomToast( - message: 'Expiration Time cannot be earlier than Effective Time.', - gravity: ToastGravity.CENTER, - textColor: Colors.white, - fontSize: 16.0, - ); + accessPeriodValidate= 'Expiration Time cannot be earlier than Effective Time.'; } else { + accessPeriodValidate=''; expirationTime = selectedDateTime.toString().split('.').first; expirationTimeTimeStamp = selectedTimestamp; } diff --git a/lib/pages/visitor_password/view/visitor_password_dialog.dart b/lib/pages/visitor_password/view/visitor_password_dialog.dart index ad11b30f..1f014352 100644 --- a/lib/pages/visitor_password/view/visitor_password_dialog.dart +++ b/lib/pages/visitor_password/view/visitor_password_dialog.dart @@ -404,6 +404,9 @@ class VisitorPasswordDialog extends StatelessWidget { ? visitorBloc.expirationTime : visitorBloc.endTimeAccess.toString(), icon: Assets.calendarIcon), + const SizedBox(height: 10,), + Text(visitorBloc.accessPeriodValidate, + style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: ColorsManager.red),), const SizedBox( height: 20, ), diff --git a/lib/utils/style.dart b/lib/utils/style.dart index 33a850a7..bda3665f 100644 --- a/lib/utils/style.dart +++ b/lib/utils/style.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:fluttertoast/fluttertoast.dart'; import 'color_manager.dart'; InputDecoration? textBoxDecoration({bool suffixIcon = false}) => @@ -43,25 +42,3 @@ BoxDecoration containerDecoration = BoxDecoration( color: ColorsManager.boxColor, borderRadius: const BorderRadius.all(Radius.circular(10))); - -/// A function to display a customizable toast message -void showCustomToast({ - required String message, - ToastGravity gravity = ToastGravity.BOTTOM, - Color textColor = Colors.white, - Toast toastLength = Toast.LENGTH_SHORT, - int timeInSecForIosWeb = 2, - double fontSize = 16.0, -}) { - Fluttertoast.showToast( - msg: message, - webBgColor: "linear-gradient(to right, #dc1c13, #dc1c13)", - webPosition:'right' , - toastLength: toastLength, - webShowClose: true, - gravity: gravity, - timeInSecForIosWeb: timeInSecForIosWeb, - textColor: textColor, - fontSize: fontSize, - ); -} diff --git a/pubspec.lock b/pubspec.lock index e358cdbf..8b9df6d6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -232,14 +232,6 @@ packages: description: flutter source: sdk version: "0.0.0" - fluttertoast: - dependency: "direct main" - description: - name: fluttertoast - sha256: "95f349437aeebe524ef7d6c9bde3e6b4772717cf46a0eb6a3ceaddc740b297cc" - url: "https://pub.dev" - source: hosted - version: "8.2.8" get_it: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 14210eb5..8b327340 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -49,7 +49,6 @@ dependencies: intl: ^0.19.0 dropdown_search: ^5.0.6 flutter_dotenv: ^5.1.0 - fluttertoast: ^8.2.8 dev_dependencies: flutter_test: From 28ec5beac9ed02ff3c695a2449b961ac681ba6a9 Mon Sep 17 00:00:00 2001 From: Abdullah Alassaf Date: Thu, 12 Sep 2024 14:47:15 +0300 Subject: [PATCH 3/4] Hide the sidebar --- .../access_management/view/access_management.dart | 2 +- .../all_devices/view/device_managment_page.dart | 4 +--- lib/pages/home/view/home_page_mobile.dart | 11 ++++------- lib/pages/home/view/home_page_web.dart | 2 +- .../visitor_password/bloc/visitor_password_bloc.dart | 10 ++++------ lib/web_layout/web_scaffold.dart | 6 +++--- 6 files changed, 14 insertions(+), 21 deletions(-) diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index f66c8a99..89bc7032 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -30,7 +30,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { final padding = isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15); return WebScaffold( - enableMenuSideba: false, + enableMenuSidebar: false, appBarTitle: FittedBox( child: Text( 'Access Management', diff --git a/lib/pages/device_managment/all_devices/view/device_managment_page.dart b/lib/pages/device_managment/all_devices/view/device_managment_page.dart index 93480ae5..8265cd81 100644 --- a/lib/pages/device_managment/all_devices/view/device_managment_page.dart +++ b/lib/pages/device_managment/all_devices/view/device_managment_page.dart @@ -21,13 +21,11 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout { ), ), rightBody: const NavigateHomeGridView(), - enableMenuSideba: isLargeScreenSize(context), scaffoldBody: BlocBuilder( builder: (context, state) { if (state is DeviceManagementLoading) { return const Center(child: CircularProgressIndicator()); - } else if (state is DeviceManagementLoaded || - state is DeviceManagementFiltered) { + } else if (state is DeviceManagementLoaded || state is DeviceManagementFiltered) { final devices = state is DeviceManagementLoaded ? state.devices : (state as DeviceManagementFiltered).filteredDevices; diff --git a/lib/pages/home/view/home_page_mobile.dart b/lib/pages/home/view/home_page_mobile.dart index e8371cf2..560ef0d5 100644 --- a/lib/pages/home/view/home_page_mobile.dart +++ b/lib/pages/home/view/home_page_mobile.dart @@ -18,7 +18,7 @@ class HomeMobilePage extends StatelessWidget { canPop: false, onPopInvoked: (didPop) => false, child: WebScaffold( - enableMenuSideba: false, + enableMenuSidebar: false, appBarTitle: Row( children: [ SvgPicture.asset( @@ -41,8 +41,7 @@ class HomeMobilePage extends StatelessWidget { SizedBox(height: size.height * 0.05), const Text( 'ACCESS YOUR APPS', - style: - TextStyle(fontSize: 20, fontWeight: FontWeight.w700), + style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700), ), const SizedBox(height: 30), Expanded( @@ -52,8 +51,7 @@ class HomeMobilePage extends StatelessWidget { width: size.width * 0.68, child: GridView.builder( itemCount: 8, - gridDelegate: - const SliverGridDelegateWithFixedCrossAxisCount( + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 20.0, mainAxisSpacing: 20.0, @@ -65,8 +63,7 @@ class HomeMobilePage extends StatelessWidget { active: homeItems[index]['active'], name: homeItems[index]['title'], img: homeItems[index]['icon'], - onTap: () => - homeBloc.homeItems[index].onPress(context), + onTap: () => homeBloc.homeItems[index].onPress(context), ); }, ), diff --git a/lib/pages/home/view/home_page_web.dart b/lib/pages/home/view/home_page_web.dart index c1fc54f9..cb806dfc 100644 --- a/lib/pages/home/view/home_page_web.dart +++ b/lib/pages/home/view/home_page_web.dart @@ -20,7 +20,7 @@ class HomeWebPage extends StatelessWidget { builder: (context, state) { final homeBloc = BlocProvider.of(context); return WebScaffold( - enableMenuSideba: false, + enableMenuSidebar: false, appBarTitle: Row( children: [ SvgPicture.asset( diff --git a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart index 4982c7f1..151d6d1f 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart @@ -14,7 +14,6 @@ import 'package:syncrow_web/services/access_mang_api.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/snack_bar.dart'; -import 'package:syncrow_web/utils/style.dart'; class VisitorPasswordBloc extends Bloc { VisitorPasswordBloc() : super(VisitorPasswordInitial()) { @@ -379,17 +378,17 @@ class VisitorPasswordBloc extends Bloc expirationTimeTimeStamp!) { - accessPeriodValidate="Effective Time cannot be later than Expiration Time."; + accessPeriodValidate = "Effective Time cannot be later than Expiration Time."; } else { - accessPeriodValidate=''; + accessPeriodValidate = ''; effectiveTime = selectedDateTime.toString().split('.').first; effectiveTimeTimeStamp = selectedTimestamp; } } else { if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) { - accessPeriodValidate= 'Expiration Time cannot be earlier than Effective Time.'; + accessPeriodValidate = 'Expiration Time cannot be earlier than Effective Time.'; } else { - accessPeriodValidate=''; + accessPeriodValidate = ''; expirationTime = selectedDateTime.toString().split('.').first; expirationTimeTimeStamp = selectedTimestamp; } @@ -449,7 +448,6 @@ class VisitorPasswordBloc extends Bloc[ TextButton( onPressed: () { - Navigator.of(context).pop(true); }, child: const Text('OK'), diff --git a/lib/web_layout/web_scaffold.dart b/lib/web_layout/web_scaffold.dart index b4edd764..c1d6075f 100644 --- a/lib/web_layout/web_scaffold.dart +++ b/lib/web_layout/web_scaffold.dart @@ -6,7 +6,7 @@ import 'package:syncrow_web/web_layout/web_app_bar.dart'; import 'menu_sidebar.dart'; class WebScaffold extends StatelessWidget with HelperResponsiveLayout { - final bool enableMenuSideba; + final bool enableMenuSidebar; final Widget? appBarTitle; final Widget? centerBody; final Widget? rightBody; @@ -17,7 +17,7 @@ class WebScaffold extends StatelessWidget with HelperResponsiveLayout { this.centerBody, this.rightBody, this.scaffoldBody, - this.enableMenuSideba = true, + this.enableMenuSidebar = false, }); @override Widget build(BuildContext context) { @@ -49,7 +49,7 @@ class WebScaffold extends StatelessWidget with HelperResponsiveLayout { Expanded( child: Row( children: [ - if (enableMenuSideba && !isSmall) const MenuSidebar(), + if (enableMenuSidebar && !isSmall) const MenuSidebar(), Expanded(flex: 5, child: scaffoldBody!) ], ), From 7c97d01ddbd1c3804d8dfa8652eb8afd107eea75 Mon Sep 17 00:00:00 2001 From: mohammad Date: Thu, 12 Sep 2024 14:54:04 +0300 Subject: [PATCH 4/4] Authorizer search field & Date-Time Filters & Update Table View Columns --- .../access_management/bloc/access_bloc.dart | 131 +++++++++++------- .../access_management/bloc/access_event.dart | 2 + .../model/password_model.dart | 18 ++- .../view/access_management.dart | 37 +++-- .../auth/view/forget_password_web_page.dart | 18 +-- .../bloc/visitor_password_bloc.dart | 9 +- lib/services/access_mang_api.dart | 1 + 7 files changed, 136 insertions(+), 80 deletions(-) diff --git a/lib/pages/access_management/bloc/access_bloc.dart b/lib/pages/access_management/bloc/access_bloc.dart index 94b0992f..4b7e499c 100644 --- a/lib/pages/access_management/bloc/access_bloc.dart +++ b/lib/pages/access_management/bloc/access_bloc.dart @@ -3,25 +3,27 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/access_management/bloc/access_event.dart'; import 'package:syncrow_web/pages/access_management/bloc/access_state.dart'; import 'package:syncrow_web/pages/access_management/model/password_model.dart'; +import 'package:syncrow_web/pages/common/hour_picker_dialog.dart'; import 'package:syncrow_web/services/access_mang_api.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/app_enum.dart'; import 'package:syncrow_web/utils/snack_bar.dart'; class AccessBloc extends Bloc { AccessBloc() : super((AccessInitial())) { on(_onFetchTableData); - // on(selectFilterTap); on(selectTime); on(_filterData); on(resetSearch); on(onTabChanged); } + String startTime = 'Start Date'; String endTime = 'End Date'; - int? effectiveTimeTimeStamp; int? expirationTimeTimeStamp; TextEditingController passwordName = TextEditingController(); + TextEditingController emailAuthorizer = TextEditingController(); List filteredData = []; List data = []; @@ -62,57 +64,61 @@ class AccessBloc extends Bloc { } } - Future selectTime(SelectTime event, Emitter emit) async { + + Future selectTime(SelectTime event, Emitter emit,) async { emit(AccessLoaded()); final DateTime? picked = await showDatePicker( context: event.context, initialDate: DateTime.now(), - firstDate: DateTime(2015, 8), - lastDate: DateTime(2101), + firstDate: DateTime.now().add(const Duration(days: -5095)), + lastDate: DateTime.now().add(const Duration(days: 2095)), ); if (picked != null) { - final selectedDateTime = DateTime( - picked.year, - picked.month, - picked.day, + final TimeOfDay? timePicked = await showHourPicker( + context: event.context, + initialTime: TimeOfDay.now(), ); - final selectedTimestamp = DateTime( - selectedDateTime.year, - selectedDateTime.month, - selectedDateTime.day, - selectedDateTime.hour, - selectedDateTime.minute, - ).millisecondsSinceEpoch ~/ - 1000; // Divide by 1000 to remove milliseconds - if (event.isStart) { - if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) { - CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.'); + + if (timePicked != null) { + final DateTime selectedDateTime = DateTime( + picked.year, + picked.month, + picked.day, + timePicked.hour, + timePicked.minute, + ); + final int selectedTimestamp = selectedDateTime.millisecondsSinceEpoch ~/ 1000; + if (event.isStart) { + if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) { + CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.'); + } else { + startTime = selectedDateTime.toString().split('.').first; + effectiveTimeTimeStamp = selectedTimestamp; + } } else { - startTime = - selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds - effectiveTimeTimeStamp = selectedTimestamp; - } - } else { - if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) { - CustomSnackBar.displaySnackBar('Expiration Time cannot be earlier than Effective Time.'); - } else { - endTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds - expirationTimeTimeStamp = selectedTimestamp; + if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) { + CustomSnackBar.displaySnackBar('Expiration Time cannot be earlier than Effective Time.'); + } else { + endTime = selectedDateTime.toString().split('.').first; + expirationTimeTimeStamp = selectedTimestamp; + } } } } emit(ChangeTimeState()); + } + Future _filterData(FilterDataEvent event, Emitter emit) async { emit(AccessLoaded()); try { + print(event.emailAuthorizer?.toLowerCase()); // Convert search text to lower case for case-insensitive search final searchText = event.passwordName?.toLowerCase() ?? ''; - + final searchEmailText = event.emailAuthorizer?.toLowerCase() ?? ''; filteredData = data.where((item) { bool matchesCriteria = true; - // Convert timestamp to DateTime and extract date component DateTime effectiveDate = DateTime.fromMillisecondsSinceEpoch(int.parse(item.effectiveTime.toString()) * 1000) @@ -122,9 +128,8 @@ class AccessBloc extends Bloc { DateTime.fromMillisecondsSinceEpoch(int.parse(item.invalidTime.toString()) * 1000) .toUtc() .toLocal(); - DateTime effectiveDateOnly = - DateTime(effectiveDate.year, effectiveDate.month, effectiveDate.day); - DateTime invalidDateOnly = DateTime(invalidDate.year, invalidDate.month, invalidDate.day); + DateTime effectiveDateAndTime = DateTime(effectiveDate.year, effectiveDate.month, effectiveDate.day,effectiveDate.hour,effectiveDate.minute); + DateTime invalidDateAndTime = DateTime(invalidDate.year, invalidDate.month, invalidDate.day,invalidDate.hour,invalidDate.minute); // Filter by password name, making the search case-insensitive if (searchText.isNotEmpty) { @@ -133,36 +138,51 @@ class AccessBloc extends Bloc { matchesCriteria = false; } } - - // Filter by start date only - if (event.startTime != null && event.endTime == null) { - DateTime startDateOnly = - DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal(); - startDateOnly = DateTime(startDateOnly.year, startDateOnly.month, startDateOnly.day); - if (effectiveDateOnly.isBefore(startDateOnly)) { + if (searchEmailText.isNotEmpty) { + final bool matchesName = item.authorizerEmail.toString().toLowerCase().contains(searchEmailText); + if (!matchesName) { + matchesCriteria = false; + } + } + // Filter by start date only + if (event.startTime != null && event.endTime == null) { + DateTime startDateTime = + DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal(); + startDateTime = DateTime( + startDateTime.year, + startDateTime.month, + startDateTime.day, + startDateTime.hour, + startDateTime.minute); + if (effectiveDateAndTime.isBefore(startDateTime)) { matchesCriteria = false; } } - // Filter by end date only if (event.endTime != null && event.startTime == null) { - DateTime endDateOnly = + DateTime startDateTime = DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal(); - endDateOnly = DateTime(endDateOnly.year, endDateOnly.month, endDateOnly.day); - if (invalidDateOnly.isAfter(endDateOnly)) { + startDateTime = DateTime( + startDateTime.year, + startDateTime.month, + startDateTime.day, + startDateTime.hour, + startDateTime.minute + ); + if (invalidDateAndTime.isAfter(startDateTime)) { matchesCriteria = false; } } // Filter by both start date and end date if (event.startTime != null && event.endTime != null) { - DateTime startDateOnly = + DateTime startDateTime = DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal(); - DateTime endDateOnly = + DateTime endDateTime = DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal(); - startDateOnly = DateTime(startDateOnly.year, startDateOnly.month, startDateOnly.day); - endDateOnly = DateTime(endDateOnly.year, endDateOnly.month, endDateOnly.day); - if (effectiveDateOnly.isBefore(startDateOnly) || invalidDateOnly.isAfter(endDateOnly)) { + startDateTime = DateTime(startDateTime.year, startDateTime.month, startDateTime.day,startDateTime.hour,startDateTime.minute); + endDateTime = DateTime(endDateTime.year, endDateTime.month, endDateTime.day,endDateTime.hour,endDateTime.minute); + if (effectiveDateAndTime.isBefore(startDateTime) || invalidDateAndTime.isAfter(endDateTime)) { matchesCriteria = false; } } @@ -186,12 +206,12 @@ class AccessBloc extends Bloc { } - resetSearch(ResetSearch event, Emitter emit) async { emit(AccessLoaded()); startTime = 'Start Time'; endTime = 'End Time'; passwordName.clear(); + emailAuthorizer.clear(); selectedIndex = 0; effectiveTimeTimeStamp = null; expirationTimeTimeStamp = null; @@ -200,9 +220,11 @@ class AccessBloc extends Bloc { String timestampToDate(dynamic timestamp) { DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000); - return "${dateTime.year}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.day.toString().padLeft(2, '0')}"; + return "${dateTime.year}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.day.toString().padLeft(2, '0')} " + " ${dateTime.hour.toString().padLeft(2, '0')}:${dateTime.minute.toString().padLeft(2, '0')}"; } + Future onTabChanged(TabChangedEvent event, Emitter emit) async { try { emit(AccessLoaded()); @@ -227,6 +249,7 @@ class AccessBloc extends Bloc { add(FilterDataEvent( selectedTabIndex: selectedIndex, passwordName: passwordName.text.toLowerCase(), + emailAuthorizer: emailAuthorizer.text.toLowerCase(), startTime: effectiveTimeTimeStamp, endTime: expirationTimeTimeStamp)); emit(TableLoaded(filteredData)); @@ -234,4 +257,6 @@ class AccessBloc extends Bloc { emit(FailedState(e.toString())); } } + } + diff --git a/lib/pages/access_management/bloc/access_event.dart b/lib/pages/access_management/bloc/access_event.dart index 1bd7dbd3..4ef71ea6 100644 --- a/lib/pages/access_management/bloc/access_event.dart +++ b/lib/pages/access_management/bloc/access_event.dart @@ -28,12 +28,14 @@ class SelectTime extends AccessEvent { class FilterDataEvent extends AccessEvent { final String? passwordName; + final String? emailAuthorizer; final int? startTime; final int? endTime; final int selectedTabIndex; // Add this field const FilterDataEvent({ this.passwordName, + this.emailAuthorizer, this.startTime, this.endTime, required this.selectedTabIndex, // Initialize this field diff --git a/lib/pages/access_management/model/password_model.dart b/lib/pages/access_management/model/password_model.dart index 50c03090..0ce4426a 100644 --- a/lib/pages/access_management/model/password_model.dart +++ b/lib/pages/access_management/model/password_model.dart @@ -6,10 +6,13 @@ class PasswordModel { final dynamic effectiveTime; final dynamic passwordCreated; final dynamic createdTime; - final dynamic passwordName; // New field + final dynamic passwordName; final AccessStatus passwordStatus; final AccessType passwordType; final dynamic deviceUuid; + final dynamic authorizerEmail; + final dynamic authorizerDate; + final dynamic deviceName; PasswordModel({ this.passwordId, @@ -17,10 +20,13 @@ class PasswordModel { this.effectiveTime, this.passwordCreated, this.createdTime, - this.passwordName, // New field + this.passwordName, required this.passwordStatus, required this.passwordType, this.deviceUuid, + this.authorizerEmail, + this.authorizerDate, + this.deviceName, }); factory PasswordModel.fromJson(Map json) { @@ -34,6 +40,9 @@ class PasswordModel { passwordStatus: AccessStatusExtension.fromString(json['passwordStatus']), passwordType: AccessTypeExtension.fromString(json['passwordType']), deviceUuid: json['deviceUuid'], + authorizerEmail: json['authorizerEmail'], + authorizerDate: json['authorizerDate'], + deviceName: json['deviceName'], ); } @@ -44,10 +53,13 @@ class PasswordModel { 'effectiveTime': effectiveTime, 'passwordCreated': passwordCreated, 'createdTime': createdTime, - 'passwodName': passwordName, // New field + 'passwordName': passwordName, // New field 'passwordStatus': passwordStatus, 'passwordType': passwordType, 'deviceUuid': deviceUuid, + 'authorizerEmail': authorizerEmail, + 'authorizerDate': authorizerDate, + 'deviceName': deviceName, }; } } diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index f66c8a99..b8c89453 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -24,6 +24,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { @override Widget build(BuildContext context) { + final isLargeScreen = isLargeScreenSize(context); final isSmallScreen = isSmallScreenSize(context); final isHalfMediumScreen = isHafMediumScreenSize(context); @@ -85,7 +86,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { _buildVisitorAdminPasswords(context, accessBloc), const SizedBox(height: 20), Expanded( - child: DynamicTable( + child: DynamicTable( tableName: 'AccessManagement', uuidIndex: 1, withSelectAll: true, @@ -96,7 +97,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { headers: const [ 'Name', 'Access Type', - 'Access Period', + 'Access Start', + 'Access End', 'Accessible Device', 'Authorizer', 'Authorization Date & Time', @@ -106,10 +108,11 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { return [ item.passwordName, item.passwordType.value, - ('${accessBloc.timestampToDate(item.effectiveTime)} - ${accessBloc.timestampToDate(item.invalidTime)}'), - item.deviceUuid.toString(), - '', - '', + accessBloc.timestampToDate(item.effectiveTime), + accessBloc.timestampToDate(item.invalidTime), + item.deviceName.toString(), + item.authorizerEmail.toString(), + accessBloc.timestampToDate(item.invalidTime), item.passwordStatus.value, ]; }).toList(), @@ -166,6 +169,8 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { } Row _buildNormalSearchWidgets(BuildContext context, AccessBloc accessBloc) { + TimeOfDay _selectedTime = TimeOfDay.now(); + return Row( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.end, @@ -182,6 +187,17 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { ), ), const SizedBox(width: 15), + SizedBox( + width: 250, + child: CustomWebTextField( + controller: accessBloc.emailAuthorizer, + height: 43, + isRequired: false, + textFieldName: 'Authorizer', + description: '', + ), + ), + const SizedBox(width: 15), SizedBox( child: DateTimeWebWidget( icon: Assets.calendarIcon, @@ -189,7 +205,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { title: 'Access Time', size: MediaQuery.of(context).size, endTime: () { - accessBloc.add(SelectTime(context: context, isStart: false)); + accessBloc.add(SelectTime(context: context, isStart: false)); }, startTime: () { accessBloc.add(SelectTime(context: context, isStart: true)); @@ -202,6 +218,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { SearchResetButtons( onSearch: () { accessBloc.add(FilterDataEvent( + emailAuthorizer:accessBloc.emailAuthorizer.text.toLowerCase() , selectedTabIndex: BlocProvider.of(context).selectedIndex, passwordName: accessBloc.passwordName.text.toLowerCase(), startTime: accessBloc.effectiveTimeTimeStamp, @@ -247,10 +264,12 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { SearchResetButtons( onSearch: () { accessBloc.add(FilterDataEvent( + emailAuthorizer:accessBloc.emailAuthorizer.text.toLowerCase() , selectedTabIndex: BlocProvider.of(context).selectedIndex, passwordName: accessBloc.passwordName.text.toLowerCase(), startTime: accessBloc.effectiveTimeTimeStamp, - endTime: accessBloc.expirationTimeTimeStamp)); + endTime: accessBloc.expirationTimeTimeStamp + )); }, onReset: () { accessBloc.add(ResetSearch()); @@ -259,4 +278,6 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { ], ); } + + } diff --git a/lib/pages/auth/view/forget_password_web_page.dart b/lib/pages/auth/view/forget_password_web_page.dart index d391776e..e89b9361 100644 --- a/lib/pages/auth/view/forget_password_web_page.dart +++ b/lib/pages/auth/view/forget_password_web_page.dart @@ -209,23 +209,17 @@ class ForgetPasswordWebPage extends StatelessWidget { decoration: textBoxDecoration()!.copyWith( hintText: 'Enter Code', - hintStyle: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - color: - ColorsManager.grayColor, - fontWeight: - FontWeight.w400), + hintStyle: Theme.of(context).textTheme + .bodySmall!.copyWith( + color: ColorsManager.grayColor, + fontWeight: FontWeight.w400), suffixIcon: SizedBox( width: 100, child: Center( child: InkWell( onTap: state is TimerState && - !state - .isButtonEnabled && - state.remainingTime != - 1 + !state.isButtonEnabled && + state.remainingTime != 1 ? null : () { if (forgetBloc.forgetEmailKey.currentState!.validate()||forgetBloc.forgetRegionKey.currentState!.validate()) { diff --git a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart index 02f5ef0a..317a08a9 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart @@ -75,13 +75,12 @@ class VisitorPasswordBloc extends Bloc selectTimeVisitorPassword( SelectTimeVisitorPassword event, - Emitter emit, - ) async { + Emitter emit,) async { final DateTime? picked = await showDatePicker( context: event.context, initialDate: DateTime.now(), firstDate: DateTime(2015, 8), - lastDate: DateTime(3101), + lastDate: DateTime.now().add(const Duration(days: 5095)), ); if (picked != null) { @@ -352,13 +351,15 @@ class VisitorPasswordBloc extends Bloc jsonData = json; List passwordList = jsonData.map((jsonItem) { return PasswordModel.fromJson(jsonItem);