From adf19818e7d98691b039a7cc13dc8974cb1d05e6 Mon Sep 17 00:00:00 2001 From: ashrafzarkanisala Date: Wed, 28 Aug 2024 20:52:09 +0300 Subject: [PATCH 001/158] push fixes --- .../view/access_management.dart | 104 ++++++++++-------- lib/pages/common/custom_table.dart | 26 +++-- .../ac/view/control_list/current_temp.dart | 20 ++-- .../bloc/device_managment_bloc.dart | 5 +- .../view/device_managment_page.dart | 4 + .../widgets/device_managment_body.dart | 4 +- .../widgets/device_search_filters.dart | 2 +- .../shared/navigate_home_grid_view.dart | 33 ++++++ .../responsive_layout_helper.dart | 13 ++- 9 files changed, 140 insertions(+), 71 deletions(-) create mode 100644 lib/pages/device_managment/shared/navigate_home_grid_view.dart diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index a63b02a3..57ef46da 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:go_router/go_router.dart'; import 'package:syncrow_web/pages/access_management/bloc/access_bloc.dart'; import 'package:syncrow_web/pages/access_management/bloc/access_event.dart'; import 'package:syncrow_web/pages/access_management/bloc/access_state.dart'; @@ -9,11 +7,11 @@ import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/pages/common/custom_table.dart'; import 'package:syncrow_web/pages/common/date_time_widget.dart'; import 'package:syncrow_web/pages/common/text_field/custom_web_textfield.dart'; +import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart'; import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/app_enum.dart'; -import 'package:syncrow_web/utils/constants/routes_const.dart'; import 'package:syncrow_web/utils/style.dart'; import 'package:syncrow_web/web_layout/web_scaffold.dart'; @@ -38,30 +36,18 @@ class AccessManagementPage extends StatelessWidget { children: [ Text( 'Physical Access', - style: Theme.of(context).textTheme.headlineMedium!.copyWith(color: Colors.white), - ), - Row( - children: [ - InkWell( - onTap: () { - context.go(RoutesConst.home); - }, - child: SvgPicture.asset( - height: 20, - width: 20, - Assets.grid, - ), - ), - const SizedBox( - width: 10, - ) - ], + style: Theme.of(context) + .textTheme + .headlineMedium! + .copyWith(color: Colors.white), ), + const NavigateHomeGridView(), ], ), ], scaffoldBody: BlocProvider( - create: (BuildContext context) => AccessBloc()..add(FetchTableData()), + create: (BuildContext context) => + AccessBloc()..add(FetchTableData()), child: BlocConsumer( listener: (context, state) {}, builder: (context, state) { @@ -82,11 +68,15 @@ class AccessManagementPage extends StatelessWidget { child: Flexible( child: ListView.builder( scrollDirection: Axis.horizontal, - itemCount: BlocProvider.of(context).tabs.length, + itemCount: + BlocProvider.of(context) + .tabs + .length, shrinkWrap: true, itemBuilder: (context, index) { final isSelected = index == - BlocProvider.of(context).selectedIndex; + BlocProvider.of(context) + .selectedIndex; return InkWell( onTap: () { BlocProvider.of(context) @@ -96,25 +86,36 @@ class AccessManagementPage extends StatelessWidget { decoration: BoxDecoration( color: ColorsManager.boxColor, border: Border.all( - color: isSelected ? Colors.blue : Colors.transparent, + color: isSelected + ? Colors.blue + : Colors.transparent, width: 2.0, ), borderRadius: index == 0 ? const BorderRadius.only( - topLeft: Radius.circular(10), - bottomLeft: Radius.circular(10)) + topLeft: + Radius.circular(10), + bottomLeft: + Radius.circular(10)) : index == 3 ? const BorderRadius.only( - topRight: Radius.circular(10), - bottomRight: Radius.circular(10)) + topRight: + Radius.circular(10), + bottomRight: + Radius.circular(10)) : null, ), - padding: const EdgeInsets.only(left: 10, right: 10), + padding: const EdgeInsets.only( + left: 10, right: 10), child: Center( child: Text( - BlocProvider.of(context).tabs[index], + BlocProvider.of( + context) + .tabs[index], style: TextStyle( - color: isSelected ? Colors.blue : Colors.black, + color: isSelected + ? Colors.blue + : Colors.black, ), ), ), @@ -150,13 +151,19 @@ class AccessManagementPage extends StatelessWidget { title: 'Access Time', size: size, endTime: () { - accessBloc.add(SelectTime(context: context, isStart: false)); + accessBloc.add(SelectTime( + context: context, isStart: false)); }, startTime: () { - accessBloc.add(SelectTime(context: context, isStart: true)); + accessBloc.add(SelectTime( + context: context, isStart: true)); }, - firstString: BlocProvider.of(context).startTime, - secondString: BlocProvider.of(context).endTime, + firstString: + BlocProvider.of(context) + .startTime, + secondString: + BlocProvider.of(context) + .endTime, ), const SizedBox( width: 15, @@ -168,13 +175,17 @@ class AccessManagementPage extends StatelessWidget { child: DefaultButton( onPressed: () { accessBloc.add(FilterDataEvent( - selectedTabIndex: BlocProvider.of( - context) + selectedTabIndex: BlocProvider + .of( + context) .selectedIndex, // Pass the selected tab index - passwordName: - accessBloc.passwordName.text.toLowerCase(), - startTime: accessBloc.effectiveTimeTimeStamp, - endTime: accessBloc.expirationTimeTimeStamp)); + passwordName: accessBloc + .passwordName.text + .toLowerCase(), + startTime: accessBloc + .effectiveTimeTimeStamp, + endTime: accessBloc + .expirationTimeTimeStamp)); }, borderRadius: 9, child: const Text('Search'))), @@ -190,7 +201,8 @@ class AccessManagementPage extends StatelessWidget { onPressed: () { accessBloc.add(ResetSearch()); }, - backgroundColor: ColorsManager.whiteColors, + backgroundColor: + ColorsManager.whiteColors, borderRadius: 9, child: Text( 'Reset', @@ -227,7 +239,8 @@ class AccessManagementPage extends StatelessWidget { }); }, borderRadius: 8, - child: const Text('+ Create Visitor Password ')), + child: const Text( + '+ Create Visitor Password ')), ), const SizedBox( width: 10, @@ -237,7 +250,8 @@ class AccessManagementPage extends StatelessWidget { decoration: containerDecoration, child: DefaultButton( borderRadius: 8, - backgroundColor: ColorsManager.whiteColors, + backgroundColor: + ColorsManager.whiteColors, child: Text( 'Admin Password', style: Theme.of(context) diff --git a/lib/pages/common/custom_table.dart b/lib/pages/common/custom_table.dart index fdeff6b6..76ec2613 100644 --- a/lib/pages/common/custom_table.dart +++ b/lib/pages/common/custom_table.dart @@ -65,11 +65,14 @@ class _DynamicTableState extends State { child: Column( children: [ Container( - decoration: widget.headerDecoration ?? BoxDecoration(color: Colors.grey[200]), + decoration: widget.headerDecoration ?? + BoxDecoration(color: Colors.grey[200]), child: Row( children: [ if (widget.withCheckBox) _buildSelectAllCheckbox(), - ...widget.headers.map((header) => _buildTableHeaderCell(header)).toList(), + ...widget.headers + .map((header) => _buildTableHeaderCell(header)) + .toList(), ], ), ), @@ -93,7 +96,8 @@ class _DynamicTableState extends State { style: Theme.of(context) .textTheme .bodySmall! - .copyWith(color: ColorsManager.grayColor), + .copyWith( + color: ColorsManager.grayColor), ) ], ), @@ -113,10 +117,12 @@ class _DynamicTableState extends State { return Row( children: [ if (widget.withCheckBox) - _buildRowCheckbox(index, widget.size.height * 0.10), + _buildRowCheckbox( + index, widget.size.height * 0.10), ...row - .map((cell) => - _buildTableCell(cell.toString(), widget.size.height * 0.10)) + .map((cell) => _buildTableCell( + cell.toString(), + widget.size.height * 0.10)) .toList(), ], ); @@ -222,7 +228,7 @@ class _DynamicTableState extends State { statusColor = ColorsManager.red; break; default: - statusColor = Colors.black; // Default color + statusColor = Colors.black; } return Expanded( @@ -241,9 +247,11 @@ class _DynamicTableState extends State { child: Text( content, style: TextStyle( - color: batteryLevel != null && batteryLevel < 20 + color: (batteryLevel != null && batteryLevel < 20) ? ColorsManager.red - : statusColor, // Use the passed color or default to black + : (batteryLevel != null && batteryLevel > 20) + ? ColorsManager.green + : statusColor, fontSize: 10, fontWeight: FontWeight.w400), ), diff --git a/lib/pages/device_managment/ac/view/control_list/current_temp.dart b/lib/pages/device_managment/ac/view/control_list/current_temp.dart index fc00479b..2cf35228 100644 --- a/lib/pages/device_managment/ac/view/control_list/current_temp.dart +++ b/lib/pages/device_managment/ac/view/control_list/current_temp.dart @@ -116,16 +116,20 @@ class _CurrentTempState extends State { description: '°C', descriptionColor: ColorsManager.dialogBlueTitle, onIncrement: () { - setState(() { - _adjustedValue++; - }); - _onValueChanged(_adjustedValue); + if (_adjustedValue < 30) { + setState(() { + _adjustedValue++; + }); + _onValueChanged(_adjustedValue); + } }, onDecrement: () { - setState(() { - _adjustedValue--; - }); - _onValueChanged(_adjustedValue); + if (_adjustedValue > 20) { + setState(() { + _adjustedValue--; + }); + _onValueChanged(_adjustedValue); + } }), ], ), diff --git a/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart b/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart index edb02cb9..6ac40419 100644 --- a/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart +++ b/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart @@ -150,13 +150,14 @@ class DeviceManagementBloc false); return matchesCommunity && matchesUnit && matchesProductName; }).toList(); - + _selectedDevices = []; emit(DeviceManagementFiltered( filteredDevices: filteredDevices, - selectedIndex: _selectedIndex, + selectedIndex: 0, onlineCount: _onlineCount, offlineCount: _offlineCount, lowBatteryCount: _lowBatteryCount, + selectedDevice: null, )); } } 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 c56a661f..bc01871a 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 @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_managment_bloc.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/widgets/device_managment_body.dart'; +import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart'; import 'package:syncrow_web/web_layout/web_scaffold.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; @@ -17,6 +18,9 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout { 'Device Management', style: Theme.of(context).textTheme.headlineLarge, ), + appBarBody: const [ + NavigateHomeGridView(), + ], enableMenuSideba: isLargeScreenSize(context), scaffoldBody: BlocBuilder( builder: (context, state) { diff --git a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart index 3fb8b300..383d6685 100644 --- a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart +++ b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart @@ -45,7 +45,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { } final tabs = [ - 'All (${devices.length})', + 'All', 'Online ($onlineCount)', 'Offline ($offlineCount)', 'Low Battery ($lowBatteryCount)', @@ -144,7 +144,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { device.room?.name ?? '', device.batteryLevel != null ? '${device.batteryLevel}%' - : '', + : '-', formatDateTime(DateTime.fromMillisecondsSinceEpoch( (device.createTime ?? 0) * 1000)), device.online == true ? 'Online' : 'Offline', diff --git a/lib/pages/device_managment/all_devices/widgets/device_search_filters.dart b/lib/pages/device_managment/all_devices/widgets/device_search_filters.dart index 7af6293e..e2d43b1a 100644 --- a/lib/pages/device_managment/all_devices/widgets/device_search_filters.dart +++ b/lib/pages/device_managment/all_devices/widgets/device_search_filters.dart @@ -28,7 +28,7 @@ class _DeviceSearchFiltersState extends State @override Widget build(BuildContext context) { - return isLargeScreenSize(context) + return isExtraLargeScreenSize(context) ? Row( children: [ _buildSearchField("Community", communityController, 200), diff --git a/lib/pages/device_managment/shared/navigate_home_grid_view.dart b/lib/pages/device_managment/shared/navigate_home_grid_view.dart new file mode 100644 index 00000000..7969e2b0 --- /dev/null +++ b/lib/pages/device_managment/shared/navigate_home_grid_view.dart @@ -0,0 +1,33 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:go_router/go_router.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; +import 'package:syncrow_web/utils/constants/routes_const.dart'; + +class NavigateHomeGridView extends StatelessWidget { + const NavigateHomeGridView({ + super.key, + }); + + @override + Widget build(BuildContext context) { + return Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + InkWell( + onTap: () { + context.go(RoutesConst.home); + }, + child: SvgPicture.asset( + height: 20, + width: 20, + Assets.grid, + ), + ), + const SizedBox( + width: 10, + ) + ], + ); + } +} diff --git a/lib/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart b/lib/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart index d64a5144..ba11583c 100644 --- a/lib/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart +++ b/lib/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart @@ -2,15 +2,20 @@ import 'package:flutter/material.dart'; mixin HelperResponsiveLayout { bool isSmallScreenSize(BuildContext context) { - return MediaQuery.of(context).size.width < 700; + return MediaQuery.of(context).size.width < 600; } bool isMediumScreenSize(BuildContext context) { - return MediaQuery.of(context).size.width >= 700 && - MediaQuery.of(context).size.width < 1400; + return MediaQuery.of(context).size.width >= 600 && + MediaQuery.of(context).size.width < 1024; } bool isLargeScreenSize(BuildContext context) { - return MediaQuery.of(context).size.width >= 1400; + return MediaQuery.of(context).size.width >= 1024 && + MediaQuery.of(context).size.width < 1440; + } + + bool isExtraLargeScreenSize(BuildContext context) { + return MediaQuery.of(context).size.width >= 1440; } } From 5f8957c9c19e1b0057aff8f7b380fdbd599b776f Mon Sep 17 00:00:00 2001 From: ashrafzarkanisala Date: Wed, 28 Aug 2024 21:02:51 +0300 Subject: [PATCH 002/158] push bug fixes --- lib/pages/common/custom_table.dart | 2 ++ lib/pages/common/text_field/custom_text_field.dart | 5 +++-- .../all_devices/view/device_managment_page.dart | 8 +++++--- .../all_devices/widgets/device_managment_body.dart | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/pages/common/custom_table.dart b/lib/pages/common/custom_table.dart index 76ec2613..5308e450 100644 --- a/lib/pages/common/custom_table.dart +++ b/lib/pages/common/custom_table.dart @@ -196,6 +196,7 @@ class _DynamicTableState extends State { fontSize: 13, color: Color(0xFF999999), ), + maxLines: 2, ), ), ), @@ -254,6 +255,7 @@ class _DynamicTableState extends State { : statusColor, fontSize: 10, fontWeight: FontWeight.w400), + maxLines: 2, ), ), ); diff --git a/lib/pages/common/text_field/custom_text_field.dart b/lib/pages/common/text_field/custom_text_field.dart index 587a1f4f..481102dc 100644 --- a/lib/pages/common/text_field/custom_text_field.dart +++ b/lib/pages/common/text_field/custom_text_field.dart @@ -15,7 +15,7 @@ class StatefulTextField extends StatefulWidget { final String hintText; final double width; final double elevation; - final TextEditingController controller; + final TextEditingController controller; @override State createState() => _StatefulTextFieldState(); @@ -26,7 +26,7 @@ class _StatefulTextFieldState extends State { Widget build(BuildContext context) { return CustomTextField( title: widget.title, - controller: widget.controller, + controller: widget.controller, hintText: widget.hintText, width: widget.width, elevation: widget.elevation, @@ -69,6 +69,7 @@ class CustomTextField extends StatelessWidget { borderRadius: BorderRadius.circular(8), child: Container( width: width, + height: 45, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), 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 bc01871a..7496cf08 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 @@ -14,9 +14,11 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout { return BlocProvider( create: (context) => DeviceManagementBloc()..add(FetchDevices()), child: WebScaffold( - appBarTitle: Text( - 'Device Management', - style: Theme.of(context).textTheme.headlineLarge, + appBarTitle: FittedBox( + child: Text( + 'Device Management', + style: Theme.of(context).textTheme.headlineLarge, + ), ), appBarBody: const [ NavigateHomeGridView(), diff --git a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart index 383d6685..36ccf4f2 100644 --- a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart +++ b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart @@ -76,7 +76,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { const SizedBox(height: 12), Container( height: 43, - width: isSmallScreenSize(context) ? double.infinity : 100, + width: 100, decoration: containerDecoration, child: Center( child: DefaultButton( From 95b1e2c9324be0d71bbcb886a14a344b62699f8b Mon Sep 17 00:00:00 2001 From: ashrafzarkanisala Date: Thu, 29 Aug 2024 12:55:37 +0300 Subject: [PATCH 003/158] fixes bugs and re add checkboxes theme --- lib/core/theme/app_theme.dart | 1 - lib/main.dart | 40 ++++++++++++++++- .../common/text_field/custom_text_field.dart | 2 +- .../ac/view/ac_device_control.dart | 5 ++- .../view/device_managment_page.dart | 2 +- .../widgets/device_managment_body.dart | 2 +- .../model/ceiling_sensor_model.dart | 23 ++++++++-- .../view/ceiling_sensor_controls.dart | 19 ++++---- .../door_lock/view/door_lock_status_view.dart | 4 +- .../gateway/view/gateway_view.dart | 5 ++- .../view/living_room_device_control.dart | 5 ++- .../shared/device_control_dialog.dart | 2 +- .../sensors_widgets/presence_space_type.dart | 23 +++++++--- .../sensors_widgets/presense_nobody_time.dart | 45 +++++++++++++------ .../extension/build_context_x.dart | 0 15 files changed, 133 insertions(+), 45 deletions(-) delete mode 100644 lib/core/theme/app_theme.dart rename lib/{core => utils}/extension/build_context_x.dart (100%) diff --git a/lib/core/theme/app_theme.dart b/lib/core/theme/app_theme.dart deleted file mode 100644 index 8b137891..00000000 --- a/lib/core/theme/app_theme.dart +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lib/main.dart b/lib/main.dart index 90c643cc..a94c79c3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -15,7 +15,8 @@ Future main() async { initialSetup(); String checkToken = await AuthBloc.getTokenAndValidate(); GoRouter router = GoRouter( - initialLocation: checkToken == 'Success' ? RoutesConst.home : RoutesConst.auth, + initialLocation: + checkToken == 'Success' ? RoutesConst.home : RoutesConst.auth, routes: AppRoutes.getRoutes(), ); runApp(MyApp( @@ -54,7 +55,9 @@ class MyApp extends StatelessWidget { fontFamily: 'Aftika', textTheme: const TextTheme( bodySmall: TextStyle( - fontSize: 13, color: ColorsManager.whiteColors, fontWeight: FontWeight.bold), + fontSize: 13, + color: ColorsManager.whiteColors, + fontWeight: FontWeight.bold), bodyMedium: TextStyle(color: Colors.black87, fontSize: 14), bodyLarge: TextStyle(fontSize: 16, color: Colors.white), headlineSmall: TextStyle(color: Colors.black87, fontSize: 18), @@ -65,7 +68,40 @@ class MyApp extends StatelessWidget { fontWeight: FontWeight.bold, ), ), + colorScheme: ColorScheme.fromSeed( + seedColor: ColorsManager.blueColor, + primary: ColorsManager.blueColor, + onSurface: Colors.grey.shade400, + ), + switchTheme: SwitchThemeData( + thumbColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.selected)) { + return ColorsManager.blueColor; + } + return ColorsManager.whiteColors; + }), + trackColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.selected)) { + return ColorsManager.blueColor.withOpacity(0.5); + } + return ColorsManager.whiteColors; + }), + ), + checkboxTheme: CheckboxThemeData( + fillColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.selected)) { + return ColorsManager.blueColor; + } + return Colors.grey.shade200; + }), + checkColor: WidgetStateProperty.all(Colors.white), + side: const BorderSide(color: ColorsManager.whiteColors), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4), + ), + ), ), + routeInformationProvider: router.routeInformationProvider, routerDelegate: router.routerDelegate, routeInformationParser: router.routeInformationParser, diff --git a/lib/pages/common/text_field/custom_text_field.dart b/lib/pages/common/text_field/custom_text_field.dart index 481102dc..2a379982 100644 --- a/lib/pages/common/text_field/custom_text_field.dart +++ b/lib/pages/common/text_field/custom_text_field.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:syncrow_web/core/extension/build_context_x.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; class StatefulTextField extends StatefulWidget { const StatefulTextField({ diff --git a/lib/pages/device_managment/ac/view/ac_device_control.dart b/lib/pages/device_managment/ac/view/ac_device_control.dart index 5c49ecfa..63d1799d 100644 --- a/lib/pages/device_managment/ac/view/ac_device_control.dart +++ b/lib/pages/device_managment/ac/view/ac_device_control.dart @@ -18,6 +18,7 @@ class AcDeviceControl extends StatelessWidget with HelperResponsiveLayout { @override Widget build(BuildContext context) { + final isExtraLarge = isExtraLargeScreenSize(context); final isLarge = isLargeScreenSize(context); final isMedium = isMediumScreenSize(context); return BlocProvider( @@ -31,7 +32,7 @@ class AcDeviceControl extends StatelessWidget with HelperResponsiveLayout { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: isLarge + crossAxisCount: isLarge || isExtraLarge ? 3 : isMedium ? 2 @@ -74,7 +75,7 @@ class AcDeviceControl extends StatelessWidget with HelperResponsiveLayout { } else if (state is AcsLoadingState) { return const Center(child: CircularProgressIndicator()); } else { - return const Center(child: Text('Error fetching status')); + return const Center(child: Text('Error fetching status')); } }, ), 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 7496cf08..04315651 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 @@ -36,7 +36,7 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout { return DeviceManagementBody(devices: devices); } else { - return const Center(child: Text('No Devices Found')); + return const Center(child: Text('Error fetching Devices')); } }, ), diff --git a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart index 36ccf4f2..9b5fcc8d 100644 --- a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart +++ b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_web/core/extension/build_context_x.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/pages/common/custom_table.dart'; import 'package:syncrow_web/pages/common/filter/filter_widget.dart'; diff --git a/lib/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart b/lib/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart index e8118168..528de1e6 100644 --- a/lib/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart +++ b/lib/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart @@ -10,6 +10,7 @@ class CeilingSensorModel { String bodyMovement; String noBodyTime; int maxDistance; + String spaceType; CeilingSensorModel({ required this.presenceState, @@ -20,6 +21,7 @@ class CeilingSensorModel { required this.bodyMovement, required this.noBodyTime, required this.maxDistance, + required this.spaceType, }); factory CeilingSensorModel.fromJson(List jsonList) { @@ -31,6 +33,7 @@ class CeilingSensorModel { String _bodyMovement = 'none'; String _noBodyTime = 'none'; int _maxDis = 0; + String _spaceType = 'none'; try { for (var status in jsonList) { @@ -38,17 +41,26 @@ class CeilingSensorModel { case 'presence_state': _presenceState = status.value ?? 'none'; break; + case 'scene': + _spaceType = status.value ?? 'none'; + break; case 'sensitivity': - _sensitivity = status.value is int ? status.value : int.tryParse(status.value ?? '1') ?? 1; + _sensitivity = status.value is int + ? status.value + : int.tryParse(status.value ?? '1') ?? 1; break; case 'checking_result': _checkingResult = status.value ?? ''; break; case 'presence_range': - _presenceRange = status.value is int ? status.value : int.tryParse(status.value ?? '0') ?? 0; + _presenceRange = status.value is int + ? status.value + : int.tryParse(status.value ?? '0') ?? 0; break; case 'sports_para': - _sportsPara = status.value is int ? status.value : int.tryParse(status.value ?? '0') ?? 0; + _sportsPara = status.value is int + ? status.value + : int.tryParse(status.value ?? '0') ?? 0; break; case 'body_movement': _bodyMovement = status.value ?? ''; @@ -57,7 +69,9 @@ class CeilingSensorModel { _noBodyTime = status.value ?? 'none'; break; case 'moving_max_dis': - _maxDis = status.value is int ? status.value : int.tryParse(status.value ?? '0') ?? 0; + _maxDis = status.value is int + ? status.value + : int.tryParse(status.value ?? '0') ?? 0; break; } } @@ -74,6 +88,7 @@ class CeilingSensorModel { bodyMovement: _bodyMovement, noBodyTime: _noBodyTime, maxDistance: _maxDis, + spaceType: _spaceType, ); } } diff --git a/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart b/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart index 2bb7eb76..4c00dd69 100644 --- a/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart +++ b/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart @@ -24,6 +24,7 @@ class CeilingSensorControls extends StatelessWidget @override Widget build(BuildContext context) { + final isExtraLarge = isExtraLargeScreenSize(context); final isLarge = isLargeScreenSize(context); final isMedium = isMediumScreenSize(context); return BlocProvider( @@ -35,8 +36,8 @@ class CeilingSensorControls extends StatelessWidget state is CeilingReportsLoadingState) { return const Center(child: CircularProgressIndicator()); } else if (state is CeilingUpdateState) { - return _buildGridView( - context, state.ceilingSensorModel, isLarge, isMedium); + return _buildGridView(context, state.ceilingSensorModel, + isExtraLarge, isLarge, isMedium); } else if (state is CeilingReportsState) { return ReportsTable( report: state.deviceReport, @@ -58,7 +59,8 @@ class CeilingSensorControls extends StatelessWidget ); } else if (state is CeilingReportsFailedState) { final model = context.read().deviceStatus; - return _buildGridView(context, model, isLarge, isMedium); + return _buildGridView( + context, model, isExtraLarge, isLarge, isMedium); } return const Center(child: Text('Error fetching status')); }, @@ -67,13 +69,13 @@ class CeilingSensorControls extends StatelessWidget } Widget _buildGridView(BuildContext context, CeilingSensorModel model, - bool isLarge, bool isMedium) { + bool isExtraLarge, bool isLarge, bool isMedium) { return GridView( padding: const EdgeInsets.symmetric(horizontal: 50), shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: isLarge + crossAxisCount: isLarge || isExtraLarge ? 3 : isMedium ? 2 @@ -96,8 +98,8 @@ class CeilingSensorControls extends StatelessWidget postfix: 'm', description: 'Detection Range', ), - const PresenceSpaceType( - listOfIcons: [ + PresenceSpaceType( + listOfIcons: const [ Assets.office, Assets.parlour, Assets.dyi, @@ -105,6 +107,7 @@ class CeilingSensorControls extends StatelessWidget Assets.bedroom, ], description: 'Space Type', + value: model.spaceType, ), PresenceUpdateData( value: model.sensitivity.toDouble(), @@ -138,7 +141,7 @@ class CeilingSensorControls extends StatelessWidget PresenceNoBodyTime( value: model.noBodyTime, title: 'Nobody Time:', - // description: 'hr', + description: '', action: (String value) => context.read().add( CeilingChangeValueEvent( code: 'nobody_time', diff --git a/lib/pages/device_managment/door_lock/view/door_lock_status_view.dart b/lib/pages/device_managment/door_lock/view/door_lock_status_view.dart index 12db871f..536b0d97 100644 --- a/lib/pages/device_managment/door_lock/view/door_lock_status_view.dart +++ b/lib/pages/device_managment/door_lock/view/door_lock_status_view.dart @@ -34,9 +34,9 @@ class DoorLockView extends StatelessWidget { } else if (state is UpdateState) { return _buildStatusControls(context, state.smartDoorModel); } else if (state is DoorLockControlError) { - return Center(child: Text(state.message)); + return const SizedBox(); } else { - return const Center(child: CircularProgressIndicator()); + return const Center(child: Text('Error fetching status')); } }, ), diff --git a/lib/pages/device_managment/gateway/view/gateway_view.dart b/lib/pages/device_managment/gateway/view/gateway_view.dart index 4f14161e..9fbe8cb9 100644 --- a/lib/pages/device_managment/gateway/view/gateway_view.dart +++ b/lib/pages/device_managment/gateway/view/gateway_view.dart @@ -14,6 +14,7 @@ class GateWayControls extends StatelessWidget with HelperResponsiveLayout { @override Widget build(BuildContext context) { + final isExtraLarge = isExtraLargeScreenSize(context); final isLarge = isLargeScreenSize(context); final isMedium = isMediumScreenSize(context); @@ -29,7 +30,7 @@ class GateWayControls extends StatelessWidget with HelperResponsiveLayout { shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: isLarge + crossAxisCount: isLarge || isExtraLarge ? 3 : isMedium ? 2 @@ -45,7 +46,7 @@ class GateWayControls extends StatelessWidget with HelperResponsiveLayout { }, ); } else { - return const Center(child: Text('Error fetching devices')); + return const Center(child: Text('Error fetching status')); } }, ), diff --git a/lib/pages/device_managment/living_room_switch/view/living_room_device_control.dart b/lib/pages/device_managment/living_room_switch/view/living_room_device_control.dart index 60e656ad..1c9d05ca 100644 --- a/lib/pages/device_managment/living_room_switch/view/living_room_device_control.dart +++ b/lib/pages/device_managment/living_room_switch/view/living_room_device_control.dart @@ -24,7 +24,7 @@ class LivingRoomDeviceControl extends StatelessWidget return _buildStatusControls(context, state.status); } else if (state is LivingRoomDeviceManagementError || state is LivingRoomControlError) { - return Center(child: Text(state.toString())); + return const Center(child: Text('Error fetching status')); } else { return const Center(child: CircularProgressIndicator()); } @@ -35,6 +35,7 @@ class LivingRoomDeviceControl extends StatelessWidget Widget _buildStatusControls( BuildContext context, LivingRoomStatusModel status) { + final isExtraLarge = isExtraLargeScreenSize(context); final isLarge = isLargeScreenSize(context); final isMedium = isMediumScreenSize(context); return GridView( @@ -42,7 +43,7 @@ class LivingRoomDeviceControl extends StatelessWidget shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: isLarge + crossAxisCount: isLarge || isExtraLarge ? 3 : isMedium ? 2 diff --git a/lib/pages/device_managment/shared/device_control_dialog.dart b/lib/pages/device_managment/shared/device_control_dialog.dart index d115f57e..cde54047 100644 --- a/lib/pages/device_managment/shared/device_control_dialog.dart +++ b/lib/pages/device_managment/shared/device_control_dialog.dart @@ -1,7 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:syncrow_web/core/extension/build_context_x.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/helper/route_controls_based_code.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart'; diff --git a/lib/pages/device_managment/shared/sensors_widgets/presence_space_type.dart b/lib/pages/device_managment/shared/sensors_widgets/presence_space_type.dart index 185144e1..5b14452a 100644 --- a/lib/pages/device_managment/shared/sensors_widgets/presence_space_type.dart +++ b/lib/pages/device_managment/shared/sensors_widgets/presence_space_type.dart @@ -1,6 +1,7 @@ +import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:syncrow_web/core/extension/build_context_x.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart'; import 'package:syncrow_web/utils/color_manager.dart'; @@ -9,10 +10,12 @@ class PresenceSpaceType extends StatelessWidget { super.key, required this.listOfIcons, required this.description, + required this.value, }); final List listOfIcons; final String description; + final String value; @override Widget build(BuildContext context) { @@ -36,10 +39,20 @@ class PresenceSpaceType extends StatelessWidget { runSpacing: 8, spacing: 16, children: [ - ...listOfIcons.map((icon) => SvgPicture.asset( - icon, - width: 40, - height: 40, + ...listOfIcons.map((icon) => Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(100), + border: Border.all( + color: icon.contains(value) + ? ColorsManager.blueColor + : Colors.transparent, + ), + ), + child: SvgPicture.asset( + icon, + width: 40, + height: 40, + ), )), ], ), diff --git a/lib/pages/device_managment/shared/sensors_widgets/presense_nobody_time.dart b/lib/pages/device_managment/shared/sensors_widgets/presense_nobody_time.dart index 6d37ec3a..4e64ee1e 100644 --- a/lib/pages/device_managment/shared/sensors_widgets/presense_nobody_time.dart +++ b/lib/pages/device_managment/shared/sensors_widgets/presense_nobody_time.dart @@ -23,6 +23,8 @@ class PresenceNoBodyTime extends StatefulWidget { class _PresenceUpdateDataState extends State { late String _currentValue; + late String _numericValue; + late String _unit; final List nobodyTimeRange = [ 'none', @@ -40,29 +42,45 @@ class _PresenceUpdateDataState extends State { void initState() { super.initState(); _currentValue = widget.value; + _numericValue = _extractNumericValue(_currentValue); + _unit = _extractUnit(_currentValue); + } + + String _extractNumericValue(String value) { + if (value == 'none') return '0'; + return value.replaceAll(RegExp(r'[a-zA-Z]'), '').trim(); + } + + String _extractUnit(String value) { + if (value == 'none') return ''; + if (value.endsWith('s')) return 's'; + if (value.endsWith('min')) return 'min'; + if (value.endsWith('hour')) return 'hr'; + return ''; } void _onValueChanged(String newValue) { + setState(() { + _currentValue = newValue; + _numericValue = _extractNumericValue(newValue); + _unit = _extractUnit(newValue); + }); widget.action(newValue); } void _incrementValue() { int currentIndex = nobodyTimeRange.indexOf(_currentValue); if (currentIndex < nobodyTimeRange.length - 1) { - setState(() { - _currentValue = nobodyTimeRange[currentIndex + 1]; - }); - _onValueChanged(_currentValue); + String newValue = nobodyTimeRange[currentIndex + 1]; + _onValueChanged(newValue); } } void _decrementValue() { int currentIndex = nobodyTimeRange.indexOf(_currentValue); if (currentIndex > 0) { - setState(() { - _currentValue = nobodyTimeRange[currentIndex - 1]; - }); - _onValueChanged(_currentValue); + String newValue = nobodyTimeRange[currentIndex - 1]; + _onValueChanged(newValue); } } @@ -81,11 +99,12 @@ class _PresenceUpdateDataState extends State { fontSize: 10), ), IncrementDecrementWidget( - value: _currentValue, - description: widget.description ?? '', - descriptionColor: ColorsManager.blackColor, - onIncrement: _incrementValue, - onDecrement: _decrementValue), + value: _numericValue, + description: _unit, + descriptionColor: ColorsManager.blackColor, + onIncrement: _incrementValue, + onDecrement: _decrementValue, + ), ], ), ); diff --git a/lib/core/extension/build_context_x.dart b/lib/utils/extension/build_context_x.dart similarity index 100% rename from lib/core/extension/build_context_x.dart rename to lib/utils/extension/build_context_x.dart From 6e183dba9fc92097ab47a4c2e8446e65f9082c51 Mon Sep 17 00:00:00 2001 From: Abdullah Alassaf Date: Thu, 29 Aug 2024 16:23:25 +0300 Subject: [PATCH 004/158] Bug fixes --- .../access_management/bloc/access_bloc.dart | 1 - .../view/access_management.dart | 138 +++++++----------- lib/pages/auth/bloc/auth_event.dart | 4 +- lib/pages/auth/bloc/auth_state.dart | 9 +- lib/pages/auth/view/forget_password_page.dart | 4 +- lib/pages/auth/view/login_mobile_page.dart | 80 ++++------ lib/pages/auth/view/login_web_page.dart | 4 +- .../helper/route_controls_based_code.dart | 2 +- .../bloc/living_room_bloc.dart | 19 +-- .../bloc/living_room_event.dart | 0 .../bloc/living_room_state.dart | 0 .../helper/living_room_helper.dart | 7 +- .../models/living_room_model.dart | 0 .../view/living_room_device_control.dart | 19 +-- .../widgets/cieling_light.dart | 8 +- .../widgets/living_toggle_widget.dart | 2 +- .../widgets/spot_light.dart | 8 +- .../widgets/wall_light.dart | 8 +- .../view/wall_sensor_conrtols.dart | 37 +++-- lib/pages/home/bloc/home_bloc.dart | 3 +- lib/pages/home/bloc/home_state.dart | 7 - lib/pages/home/view/home_page.dart | 2 +- lib/pages/home/view/home_page_mobile.dart | 87 +++++------ lib/pages/home/view/home_page_web.dart | 120 ++++++++------- .../bloc/visitor_password_bloc.dart | 8 +- .../view/visitor_password_dialog.dart | 1 - lib/services/access_mang_api.dart | 7 - lib/utils/constants/routes_const.dart | 2 +- 28 files changed, 236 insertions(+), 351 deletions(-) rename lib/pages/device_managment/{living_room_switch => three_gang_switch}/bloc/living_room_bloc.dart (82%) rename lib/pages/device_managment/{living_room_switch => three_gang_switch}/bloc/living_room_event.dart (100%) rename lib/pages/device_managment/{living_room_switch => three_gang_switch}/bloc/living_room_state.dart (100%) rename lib/pages/device_managment/{living_room_switch => three_gang_switch}/helper/living_room_helper.dart (65%) rename lib/pages/device_managment/{living_room_switch => three_gang_switch}/models/living_room_model.dart (100%) rename lib/pages/device_managment/{living_room_switch => three_gang_switch}/view/living_room_device_control.dart (76%) rename lib/pages/device_managment/{living_room_switch => three_gang_switch}/widgets/cieling_light.dart (89%) rename lib/pages/device_managment/{living_room_switch => three_gang_switch}/widgets/living_toggle_widget.dart (95%) rename lib/pages/device_managment/{living_room_switch => three_gang_switch}/widgets/spot_light.dart (89%) rename lib/pages/device_managment/{living_room_switch => three_gang_switch}/widgets/wall_light.dart (89%) diff --git a/lib/pages/access_management/bloc/access_bloc.dart b/lib/pages/access_management/bloc/access_bloc.dart index 473d19bd..fb66408a 100644 --- a/lib/pages/access_management/bloc/access_bloc.dart +++ b/lib/pages/access_management/bloc/access_bloc.dart @@ -4,7 +4,6 @@ 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/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'; diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index 57ef46da..76c2d26e 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -36,18 +36,14 @@ class AccessManagementPage extends StatelessWidget { children: [ Text( 'Physical Access', - style: Theme.of(context) - .textTheme - .headlineMedium! - .copyWith(color: Colors.white), + style: Theme.of(context).textTheme.headlineMedium!.copyWith(color: Colors.white), ), const NavigateHomeGridView(), ], ), ], scaffoldBody: BlocProvider( - create: (BuildContext context) => - AccessBloc()..add(FetchTableData()), + create: (BuildContext context) => AccessBloc()..add(FetchTableData()), child: BlocConsumer( listener: (context, state) {}, builder: (context, state) { @@ -56,7 +52,7 @@ class AccessManagementPage extends StatelessWidget { return state is AccessLoaded ? const Center(child: CircularProgressIndicator()) : Container( - padding: EdgeInsets.all(30), + padding: const EdgeInsets.all(30), height: size.height, width: size.width, child: Column( @@ -65,64 +61,47 @@ class AccessManagementPage extends StatelessWidget { Container( decoration: containerDecoration, height: size.height * 0.05, - child: Flexible( - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: BlocProvider.of(context).tabs.length, + shrinkWrap: true, + itemBuilder: (context, index) { + final isSelected = + index == BlocProvider.of(context).selectedIndex; + return InkWell( + onTap: () { BlocProvider.of(context) - .tabs - .length, - shrinkWrap: true, - itemBuilder: (context, index) { - final isSelected = index == - BlocProvider.of(context) - .selectedIndex; - return InkWell( - onTap: () { - BlocProvider.of(context) - .add(TabChangedEvent(index)); - }, - child: Container( - decoration: BoxDecoration( - color: ColorsManager.boxColor, - border: Border.all( - color: isSelected - ? Colors.blue - : Colors.transparent, - width: 2.0, - ), - borderRadius: index == 0 - ? const BorderRadius.only( - topLeft: - Radius.circular(10), - bottomLeft: - Radius.circular(10)) - : index == 3 - ? const BorderRadius.only( - topRight: - Radius.circular(10), - bottomRight: - Radius.circular(10)) - : null, + .add(TabChangedEvent(index)); + }, + child: Container( + decoration: BoxDecoration( + color: ColorsManager.boxColor, + border: Border.all( + color: isSelected ? Colors.blue : Colors.transparent, + width: 2.0, ), - padding: const EdgeInsets.only( - left: 10, right: 10), - child: Center( - child: Text( - BlocProvider.of( - context) - .tabs[index], - style: TextStyle( - color: isSelected - ? Colors.blue - : Colors.black, - ), + borderRadius: index == 0 + ? const BorderRadius.only( + topLeft: Radius.circular(10), + bottomLeft: Radius.circular(10)) + : index == 3 + ? const BorderRadius.only( + topRight: Radius.circular(10), + bottomRight: Radius.circular(10)) + : null, + ), + padding: const EdgeInsets.only(left: 10, right: 10), + child: Center( + child: Text( + BlocProvider.of(context).tabs[index], + style: TextStyle( + color: isSelected ? Colors.blue : Colors.black, ), ), ), - ); - }, - ), + ), + ); + }, ), ), const SizedBox( @@ -151,19 +130,13 @@ class AccessManagementPage extends StatelessWidget { title: 'Access Time', size: size, endTime: () { - accessBloc.add(SelectTime( - context: context, isStart: false)); + accessBloc.add(SelectTime(context: context, isStart: false)); }, startTime: () { - accessBloc.add(SelectTime( - context: context, isStart: true)); + accessBloc.add(SelectTime(context: context, isStart: true)); }, - firstString: - BlocProvider.of(context) - .startTime, - secondString: - BlocProvider.of(context) - .endTime, + firstString: BlocProvider.of(context).startTime, + secondString: BlocProvider.of(context).endTime, ), const SizedBox( width: 15, @@ -175,17 +148,13 @@ class AccessManagementPage extends StatelessWidget { child: DefaultButton( onPressed: () { accessBloc.add(FilterDataEvent( - selectedTabIndex: BlocProvider - .of( - context) + selectedTabIndex: BlocProvider.of( + context) .selectedIndex, // Pass the selected tab index - passwordName: accessBloc - .passwordName.text - .toLowerCase(), - startTime: accessBloc - .effectiveTimeTimeStamp, - endTime: accessBloc - .expirationTimeTimeStamp)); + passwordName: + accessBloc.passwordName.text.toLowerCase(), + startTime: accessBloc.effectiveTimeTimeStamp, + endTime: accessBloc.expirationTimeTimeStamp)); }, borderRadius: 9, child: const Text('Search'))), @@ -201,8 +170,7 @@ class AccessManagementPage extends StatelessWidget { onPressed: () { accessBloc.add(ResetSearch()); }, - backgroundColor: - ColorsManager.whiteColors, + backgroundColor: ColorsManager.whiteColors, borderRadius: 9, child: Text( 'Reset', @@ -239,8 +207,7 @@ class AccessManagementPage extends StatelessWidget { }); }, borderRadius: 8, - child: const Text( - '+ Create Visitor Password ')), + child: const Text('+ Create Visitor Password ')), ), const SizedBox( width: 10, @@ -250,8 +217,7 @@ class AccessManagementPage extends StatelessWidget { decoration: containerDecoration, child: DefaultButton( borderRadius: 8, - backgroundColor: - ColorsManager.whiteColors, + backgroundColor: ColorsManager.whiteColors, child: Text( 'Admin Password', style: Theme.of(context) diff --git a/lib/pages/auth/bloc/auth_event.dart b/lib/pages/auth/bloc/auth_event.dart index a8786cbc..0026554c 100644 --- a/lib/pages/auth/bloc/auth_event.dart +++ b/lib/pages/auth/bloc/auth_event.dart @@ -1,5 +1,4 @@ import 'package:equatable/equatable.dart'; -import 'package:flutter/material.dart'; abstract class AuthEvent extends Equatable { const AuthEvent(); @@ -47,8 +46,7 @@ class StopTimerEvent extends AuthEvent {} class UpdateTimerEvent extends AuthEvent { final int remainingTime; final bool isButtonEnabled; - const UpdateTimerEvent( - {required this.remainingTime, required this.isButtonEnabled}); + const UpdateTimerEvent({required this.remainingTime, required this.isButtonEnabled}); } class ChangePasswordEvent extends AuthEvent {} diff --git a/lib/pages/auth/bloc/auth_state.dart b/lib/pages/auth/bloc/auth_state.dart index 8f2f6bd5..f3a95157 100644 --- a/lib/pages/auth/bloc/auth_state.dart +++ b/lib/pages/auth/bloc/auth_state.dart @@ -56,8 +56,7 @@ class TimerState extends AuthState { final bool isButtonEnabled; final int remainingTime; - const TimerState( - {required this.isButtonEnabled, required this.remainingTime}); + const TimerState({required this.isButtonEnabled, required this.remainingTime}); @override List get props => [isButtonEnabled, remainingTime]; @@ -65,12 +64,12 @@ class TimerState extends AuthState { class AuthError extends AuthState { final String message; - String? code; - AuthError({required this.message, this.code}); + final String? code; + const AuthError({required this.message, this.code}); } class AuthTokenError extends AuthError { - AuthTokenError({required super.message, super.code}); + const AuthTokenError({required super.message, super.code}); } class AuthSuccess extends AuthState {} diff --git a/lib/pages/auth/view/forget_password_page.dart b/lib/pages/auth/view/forget_password_page.dart index 63b4d0f9..0ab2c2df 100644 --- a/lib/pages/auth/view/forget_password_page.dart +++ b/lib/pages/auth/view/forget_password_page.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:syncrow_web/pages/auth/view/forget_password_mobile_page.dart'; import 'package:syncrow_web/pages/auth/view/forget_password_web_page.dart'; import 'package:syncrow_web/utils/responsive_layout.dart'; @@ -9,7 +8,6 @@ class ForgetPasswordPage extends StatelessWidget { @override Widget build(BuildContext context) { return const ResponsiveLayout( - desktopBody: ForgetPasswordWebPage(), - mobileBody: ForgetPasswordWebPage()); + desktopBody: ForgetPasswordWebPage(), mobileBody: ForgetPasswordWebPage()); } } diff --git a/lib/pages/auth/view/login_mobile_page.dart b/lib/pages/auth/view/login_mobile_page.dart index 1413db5d..1a5c8358 100644 --- a/lib/pages/auth/view/login_mobile_page.dart +++ b/lib/pages/auth/view/login_mobile_page.dart @@ -1,8 +1,8 @@ -import 'dart:ui'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:go_router/go_router.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_event.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_state.dart'; @@ -11,7 +11,7 @@ import 'package:syncrow_web/pages/auth/view/forget_password_page.dart'; import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; -import 'package:syncrow_web/pages/home/view/home_page.dart'; +import 'package:syncrow_web/utils/constants/routes_const.dart'; import 'package:syncrow_web/utils/style.dart'; class LoginMobilePage extends StatelessWidget { @@ -25,10 +25,7 @@ class LoginMobilePage extends StatelessWidget { listener: (context, state) { if (state is LoginSuccess) { // Navigate to home screen after successful login - Navigator.pushReplacement( - context, - MaterialPageRoute(builder: (context) => HomePage()), - ); + context.go(RoutesConst.home, extra: {'clearHistory': true}); } else if (state is LoginFailure) { // Show error message ScaffoldMessenger.of(context).showSnackBar( @@ -52,8 +49,6 @@ class LoginMobilePage extends StatelessWidget { Widget _buildLoginForm(BuildContext context) { final loginBloc = BlocProvider.of(context); - final TextEditingController _usernameController = TextEditingController(); - final TextEditingController _passwordController = TextEditingController(); return Center( child: Stack( children: [ @@ -102,11 +97,8 @@ class LoginMobilePage extends StatelessWidget { padding: EdgeInsets.all(20), decoration: BoxDecoration( color: Colors.white.withOpacity(0.1), - borderRadius: - const BorderRadius.all(Radius.circular(30)), - border: Border.all( - color: - ColorsManager.graysColor.withOpacity(0.2))), + borderRadius: const BorderRadius.all(Radius.circular(30)), + border: Border.all(color: ColorsManager.graysColor.withOpacity(0.2))), child: Form( key: loginBloc.loginFormKey, child: Column( @@ -117,9 +109,7 @@ class LoginMobilePage extends StatelessWidget { const Text( 'Login', style: TextStyle( - color: Colors.white, - fontSize: 24, - fontWeight: FontWeight.bold), + color: Colors.white, fontSize: 24, fontWeight: FontWeight.bold), ), const SizedBox(height: 30), Column( @@ -148,8 +138,7 @@ class LoginMobilePage extends StatelessWidget { ), isDense: true, style: const TextStyle(color: Colors.black), - items: loginBloc.regionList! - .map((RegionModel region) { + items: loginBloc.regionList!.map((RegionModel region) { return DropdownMenuItem( value: region.name, child: Text(region.name), @@ -173,8 +162,8 @@ class LoginMobilePage extends StatelessWidget { child: TextFormField( validator: loginBloc.validateEmail, controller: loginBloc.loginEmailController, - decoration: textBoxDecoration()! - .copyWith(hintText: 'Enter your email'), + decoration: + textBoxDecoration()!.copyWith(hintText: 'Enter your email'), style: const TextStyle(color: Colors.black), ), ), @@ -194,8 +183,7 @@ class LoginMobilePage extends StatelessWidget { validator: loginBloc.validatePassword, obscureText: loginBloc.obscureText, keyboardType: TextInputType.visiblePassword, - controller: - loginBloc.loginPasswordController, + controller: loginBloc.loginPasswordController, decoration: textBoxDecoration()!.copyWith( hintText: 'At least 8 characters', ), @@ -213,16 +201,13 @@ class LoginMobilePage extends StatelessWidget { children: [ InkWell( onTap: () { - Navigator.of(context) - .push(MaterialPageRoute( - builder: (context) => - const ForgetPasswordPage(), + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => const ForgetPasswordPage(), )); }, child: Text( "Forgot Password?", - style: - Theme.of(context).textTheme.bodySmall, + style: Theme.of(context).textTheme.bodySmall, ), ), ], @@ -233,15 +218,13 @@ class LoginMobilePage extends StatelessWidget { Transform.scale( scale: 1.2, // Adjust the scale as needed child: Checkbox( - fillColor: MaterialStateProperty.all( - Colors.white), + fillColor: MaterialStateProperty.all(Colors.white), activeColor: Colors.white, value: loginBloc.isChecked, checkColor: Colors.black, shape: const CircleBorder(), onChanged: (bool? newValue) { - loginBloc.add( - CheckBoxEvent(newValue: newValue)); + loginBloc.add(CheckBoxEvent(newValue: newValue)); }, ), ), @@ -250,37 +233,30 @@ class LoginMobilePage extends StatelessWidget { child: RichText( text: TextSpan( text: 'Agree to ', - style: - const TextStyle(color: Colors.white), + style: const TextStyle(color: Colors.white), children: [ TextSpan( text: '(Terms of Service)', - style: const TextStyle( - color: Colors.black), + style: const TextStyle(color: Colors.black), recognizer: TapGestureRecognizer() ..onTap = () { - loginBloc.launchURL( - 'https://example.com/terms'); + loginBloc.launchURL('https://example.com/terms'); }, ), TextSpan( text: ' (Legal Statement)', - style: const TextStyle( - color: Colors.black), + style: const TextStyle(color: Colors.black), recognizer: TapGestureRecognizer() ..onTap = () { - loginBloc.launchURL( - 'https://example.com/legal'); + loginBloc.launchURL('https://example.com/legal'); }, ), TextSpan( text: ' (Privacy Statement)', - style: const TextStyle( - color: Colors.black), + style: const TextStyle(color: Colors.black), recognizer: TapGestureRecognizer() ..onTap = () { - loginBloc.launchURL( - 'https://example.com/privacy'); + loginBloc.launchURL('https://example.com/privacy'); }, ), ], @@ -297,15 +273,12 @@ class LoginMobilePage extends StatelessWidget { : ColorsManager.grayColor, child: const Text('Sign in'), onPressed: () { - if (loginBloc.loginFormKey.currentState! - .validate()) { + if (loginBloc.loginFormKey.currentState!.validate()) { loginBloc.add( LoginButtonPressed( regionUuid: '', - username: - loginBloc.loginEmailController.text, - password: loginBloc - .loginPasswordController.text, + username: loginBloc.loginEmailController.text, + password: loginBloc.loginPasswordController.text, ), ); } @@ -320,8 +293,7 @@ class LoginMobilePage extends StatelessWidget { Flexible( child: Text( "Don't you have an account? ", - style: TextStyle( - color: Colors.white, fontSize: 13), + style: TextStyle(color: Colors.white, fontSize: 13), )), Text( "Sign up", diff --git a/lib/pages/auth/view/login_web_page.dart b/lib/pages/auth/view/login_web_page.dart index 7e9123ee..09191fb1 100644 --- a/lib/pages/auth/view/login_web_page.dart +++ b/lib/pages/auth/view/login_web_page.dart @@ -10,6 +10,7 @@ import 'package:syncrow_web/pages/auth/model/region_model.dart'; import 'package:syncrow_web/pages/auth/view/forget_password_page.dart'; import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/pages/common/first_layer.dart'; +import 'package:syncrow_web/pages/home/view/home_page.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/routes_const.dart'; @@ -31,7 +32,7 @@ class _LoginWebPageState extends State { child: BlocConsumer( listener: (context, state) { if (state is LoginSuccess) { - context.go(RoutesConst.home); + context.replace(RoutesConst.home); } else if (state is LoginFailure) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( @@ -201,7 +202,6 @@ class _LoginWebPageState extends State { child: TextFormField( onChanged: (value) { loginBloc.add(CheckEnableEvent()); - // print(loginBloc.checkEnable()); }, validator: loginBloc.loginValidateEmail, controller: loginBloc.loginEmailController, diff --git a/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart b/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart index fbe1f198..14ac7c5a 100644 --- a/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart +++ b/lib/pages/device_managment/all_devices/helper/route_controls_based_code.dart @@ -5,7 +5,7 @@ import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_mo import 'package:syncrow_web/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart'; import 'package:syncrow_web/pages/device_managment/door_lock/view/door_lock_status_view.dart'; import 'package:syncrow_web/pages/device_managment/gateway/view/gateway_view.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/view/living_room_device_control.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/view/living_room_device_control.dart'; import 'package:syncrow_web/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart'; mixin RouteControlsBasedCode { diff --git a/lib/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart b/lib/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart similarity index 82% rename from lib/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart rename to lib/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart index 8adc11cb..de06248b 100644 --- a/lib/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart +++ b/lib/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart @@ -4,7 +4,7 @@ import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/models/living_room_model.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/models/living_room_model.dart'; import 'package:syncrow_web/services/devices_mang_api.dart'; part 'living_room_event.dart'; @@ -24,18 +24,15 @@ class LivingRoomBloc extends Bloc { LivingRoomFetchDeviceStatus event, Emitter emit) async { emit(LivingRoomDeviceStatusLoading()); try { - final status = - await DevicesManagementApi().getDeviceStatus(event.deviceId); - deviceStatus = - LivingRoomStatusModel.fromJson(event.deviceId, status.status); + final status = await DevicesManagementApi().getDeviceStatus(event.deviceId); + deviceStatus = LivingRoomStatusModel.fromJson(event.deviceId, status.status); emit(LivingRoomDeviceStatusLoaded(deviceStatus)); } catch (e) { emit(LivingRoomDeviceManagementError(e.toString())); } } - FutureOr _livingRoomControl( - LivingRoomControl event, Emitter emit) async { + FutureOr _livingRoomControl(LivingRoomControl event, Emitter emit) async { final oldValue = _getValueByCode(event.code); _updateLocalValue(event.code, event.value); @@ -63,8 +60,8 @@ class LivingRoomBloc extends Bloc { } _timer = Timer(const Duration(seconds: 1), () async { try { - final response = await DevicesManagementApi() - .deviceControl(deviceId, Status(code: code, value: value)); + final response = + await DevicesManagementApi().deviceControl(deviceId, Status(code: code, value: value)); if (!response) { _revertValueAndEmit(deviceId, code, oldValue, emit); } @@ -74,8 +71,8 @@ class LivingRoomBloc extends Bloc { }); } - void _revertValueAndEmit(String deviceId, String code, dynamic oldValue, - Emitter emit) { + void _revertValueAndEmit( + String deviceId, String code, dynamic oldValue, Emitter emit) { _updateLocalValue(code, oldValue); emit(LivingRoomDeviceStatusLoaded(deviceStatus)); emit(const LivingRoomControlError('Failed to control the device.')); diff --git a/lib/pages/device_managment/living_room_switch/bloc/living_room_event.dart b/lib/pages/device_managment/three_gang_switch/bloc/living_room_event.dart similarity index 100% rename from lib/pages/device_managment/living_room_switch/bloc/living_room_event.dart rename to lib/pages/device_managment/three_gang_switch/bloc/living_room_event.dart diff --git a/lib/pages/device_managment/living_room_switch/bloc/living_room_state.dart b/lib/pages/device_managment/three_gang_switch/bloc/living_room_state.dart similarity index 100% rename from lib/pages/device_managment/living_room_switch/bloc/living_room_state.dart rename to lib/pages/device_managment/three_gang_switch/bloc/living_room_state.dart diff --git a/lib/pages/device_managment/living_room_switch/helper/living_room_helper.dart b/lib/pages/device_managment/three_gang_switch/helper/living_room_helper.dart similarity index 65% rename from lib/pages/device_managment/living_room_switch/helper/living_room_helper.dart rename to lib/pages/device_managment/three_gang_switch/helper/living_room_helper.dart index 8e3f4985..255204b2 100644 --- a/lib/pages/device_managment/living_room_switch/helper/living_room_helper.dart +++ b/lib/pages/device_managment/three_gang_switch/helper/living_room_helper.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/widgets/cieling_light.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/widgets/spot_light.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/widgets/wall_light.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/widgets/cieling_light.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/widgets/spot_light.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/widgets/wall_light.dart'; mixin LivingRoomHelper { Widget livingRoomControlWidgets( @@ -18,4 +18,3 @@ mixin LivingRoomHelper { } } } - diff --git a/lib/pages/device_managment/living_room_switch/models/living_room_model.dart b/lib/pages/device_managment/three_gang_switch/models/living_room_model.dart similarity index 100% rename from lib/pages/device_managment/living_room_switch/models/living_room_model.dart rename to lib/pages/device_managment/three_gang_switch/models/living_room_model.dart diff --git a/lib/pages/device_managment/living_room_switch/view/living_room_device_control.dart b/lib/pages/device_managment/three_gang_switch/view/living_room_device_control.dart similarity index 76% rename from lib/pages/device_managment/living_room_switch/view/living_room_device_control.dart rename to lib/pages/device_managment/three_gang_switch/view/living_room_device_control.dart index 1c9d05ca..e3a42a7a 100644 --- a/lib/pages/device_managment/living_room_switch/view/living_room_device_control.dart +++ b/lib/pages/device_managment/three_gang_switch/view/living_room_device_control.dart @@ -1,12 +1,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/models/living_room_model.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/widgets/living_toggle_widget.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/models/living_room_model.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/widgets/living_toggle_widget.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; -class LivingRoomDeviceControl extends StatelessWidget - with HelperResponsiveLayout { +class LivingRoomDeviceControl extends StatelessWidget with HelperResponsiveLayout { final String deviceId; const LivingRoomDeviceControl({super.key, required this.deviceId}); @@ -14,16 +13,15 @@ class LivingRoomDeviceControl extends StatelessWidget @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => LivingRoomBloc(deviceId: deviceId) - ..add(LivingRoomFetchDeviceStatus(deviceId)), + create: (context) => + LivingRoomBloc(deviceId: deviceId)..add(LivingRoomFetchDeviceStatus(deviceId)), child: BlocBuilder( builder: (context, state) { if (state is LivingRoomDeviceStatusLoading) { return const Center(child: CircularProgressIndicator()); } else if (state is LivingRoomDeviceStatusLoaded) { return _buildStatusControls(context, state.status); - } else if (state is LivingRoomDeviceManagementError || - state is LivingRoomControlError) { + } else if (state is LivingRoomDeviceManagementError || state is LivingRoomControlError) { return const Center(child: Text('Error fetching status')); } else { return const Center(child: CircularProgressIndicator()); @@ -33,8 +31,7 @@ class LivingRoomDeviceControl extends StatelessWidget ); } - Widget _buildStatusControls( - BuildContext context, LivingRoomStatusModel status) { + Widget _buildStatusControls(BuildContext context, LivingRoomStatusModel status) { final isExtraLarge = isExtraLargeScreenSize(context); final isLarge = isLargeScreenSize(context); final isMedium = isMediumScreenSize(context); diff --git a/lib/pages/device_managment/living_room_switch/widgets/cieling_light.dart b/lib/pages/device_managment/three_gang_switch/widgets/cieling_light.dart similarity index 89% rename from lib/pages/device_managment/living_room_switch/widgets/cieling_light.dart rename to lib/pages/device_managment/three_gang_switch/widgets/cieling_light.dart index b529e6e6..629c131b 100644 --- a/lib/pages/device_managment/living_room_switch/widgets/cieling_light.dart +++ b/lib/pages/device_managment/three_gang_switch/widgets/cieling_light.dart @@ -2,16 +2,12 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; class CeilingLight extends StatelessWidget { - const CeilingLight( - {super.key, - required this.value, - required this.code, - required this.deviceId}); + const CeilingLight({super.key, required this.value, required this.code, required this.deviceId}); final bool value; final String code; diff --git a/lib/pages/device_managment/living_room_switch/widgets/living_toggle_widget.dart b/lib/pages/device_managment/three_gang_switch/widgets/living_toggle_widget.dart similarity index 95% rename from lib/pages/device_managment/living_room_switch/widgets/living_toggle_widget.dart rename to lib/pages/device_managment/three_gang_switch/widgets/living_toggle_widget.dart index 701d412b..abc75e66 100644 --- a/lib/pages/device_managment/living_room_switch/widgets/living_toggle_widget.dart +++ b/lib/pages/device_managment/three_gang_switch/widgets/living_toggle_widget.dart @@ -2,7 +2,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; diff --git a/lib/pages/device_managment/living_room_switch/widgets/spot_light.dart b/lib/pages/device_managment/three_gang_switch/widgets/spot_light.dart similarity index 89% rename from lib/pages/device_managment/living_room_switch/widgets/spot_light.dart rename to lib/pages/device_managment/three_gang_switch/widgets/spot_light.dart index 14c4fe5e..6ac71a38 100644 --- a/lib/pages/device_managment/living_room_switch/widgets/spot_light.dart +++ b/lib/pages/device_managment/three_gang_switch/widgets/spot_light.dart @@ -2,16 +2,12 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; class SpotLight extends StatelessWidget { - const SpotLight( - {super.key, - required this.value, - required this.code, - required this.deviceId}); + const SpotLight({super.key, required this.value, required this.code, required this.deviceId}); final bool value; final String code; diff --git a/lib/pages/device_managment/living_room_switch/widgets/wall_light.dart b/lib/pages/device_managment/three_gang_switch/widgets/wall_light.dart similarity index 89% rename from lib/pages/device_managment/living_room_switch/widgets/wall_light.dart rename to lib/pages/device_managment/three_gang_switch/widgets/wall_light.dart index 8e168ec0..12c814ac 100644 --- a/lib/pages/device_managment/living_room_switch/widgets/wall_light.dart +++ b/lib/pages/device_managment/three_gang_switch/widgets/wall_light.dart @@ -2,16 +2,12 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; -import 'package:syncrow_web/pages/device_managment/living_room_switch/bloc/living_room_bloc.dart'; +import 'package:syncrow_web/pages/device_managment/three_gang_switch/bloc/living_room_bloc.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; class WallLight extends StatelessWidget { - const WallLight( - {super.key, - required this.value, - required this.code, - required this.deviceId}); + const WallLight({super.key, required this.value, required this.code, required this.deviceId}); final bool value; final String code; diff --git a/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart b/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart index 068cb27d..75772cad 100644 --- a/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart +++ b/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart @@ -21,19 +21,17 @@ class WallSensorControls extends StatelessWidget with HelperResponsiveLayout { @override Widget build(BuildContext context) { + final isExtraLarge = isExtraLargeScreenSize(context); final isLarge = isLargeScreenSize(context); final isMedium = isMediumScreenSize(context); return BlocProvider( - create: (context) => - WallSensorBloc(deviceId: device.uuid!)..add(WallSensorInitialEvent()), + create: (context) => WallSensorBloc(deviceId: device.uuid!)..add(WallSensorInitialEvent()), child: BlocBuilder( builder: (context, state) { - if (state is WallSensorLoadingInitialState || - state is DeviceReportsLoadingState) { + if (state is WallSensorLoadingInitialState || state is DeviceReportsLoadingState) { return const Center(child: CircularProgressIndicator()); } else if (state is WallSensorUpdateState) { - return _buildGridView( - context, state.wallSensorModel, isLarge, isMedium); + return _buildGridView(context, state.wallSensorModel, isExtraLarge, isLarge, isMedium); } else if (state is DeviceReportsState) { return ReportsTable( report: state.deviceReport, @@ -51,7 +49,7 @@ class WallSensorControls extends StatelessWidget with HelperResponsiveLayout { ); } else if (state is DeviceReportsFailedState) { final model = context.read().deviceStatus; - return _buildGridView(context, model, isLarge, isMedium); + return _buildGridView(context, model, isExtraLarge, isLarge, isMedium); } return const Center(child: Text('Error fetching status')); }, @@ -59,14 +57,14 @@ class WallSensorControls extends StatelessWidget with HelperResponsiveLayout { ); } - Widget _buildGridView(BuildContext context, WallSensorModel model, - bool isLarge, bool isMedium) { + Widget _buildGridView( + BuildContext context, WallSensorModel model, bool isExtraLarge, bool isLarge, bool isMedium) { return GridView( padding: const EdgeInsets.symmetric(horizontal: 50), shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: isLarge + crossAxisCount: isLarge || isExtraLarge ? 3 : isMedium ? 2 @@ -129,11 +127,10 @@ class WallSensorControls extends StatelessWidget with HelperResponsiveLayout { maxValue: 10000, steps: 1, description: 'hr', - action: (int value) => - context.read().add(WallSensorChangeValueEvent( - code: 'no_one_time', - value: value, - ))), + action: (int value) => context.read().add(WallSensorChangeValueEvent( + code: 'no_one_time', + value: value, + ))), PresenceUpdateData( value: model.farDetection.toDouble(), title: 'Far Detection:', @@ -150,8 +147,9 @@ class WallSensorControls extends StatelessWidget with HelperResponsiveLayout { ), GestureDetector( onTap: () { - context.read().add(GetDeviceReportsEvent( - code: 'illuminance_value', deviceUuid: device.uuid!)); + context + .read() + .add(GetDeviceReportsEvent(code: 'illuminance_value', deviceUuid: device.uuid!)); }, child: const PresenceStaticWidget( icon: Assets.illuminanceRecordIcon, @@ -160,8 +158,9 @@ class WallSensorControls extends StatelessWidget with HelperResponsiveLayout { ), GestureDetector( onTap: () { - context.read().add(GetDeviceReportsEvent( - code: 'presence_state', deviceUuid: device.uuid!)); + context + .read() + .add(GetDeviceReportsEvent(code: 'presence_state', deviceUuid: device.uuid!)); }, child: const PresenceStaticWidget( icon: Assets.presenceRecordIcon, diff --git a/lib/pages/home/bloc/home_bloc.dart b/lib/pages/home/bloc/home_bloc.dart index 42a63592..79579efc 100644 --- a/lib/pages/home/bloc/home_bloc.dart +++ b/lib/pages/home/bloc/home_bloc.dart @@ -39,11 +39,10 @@ class HomeBloc extends Bloc { emit(HomeUpdateTree(graph: graph, builder: builder)); } - Future fetchUserInfo() async { + static Future fetchUserInfo() async { try { var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey); user = await HomeApi().fetchUserInfo(uuid); - emit(HomeUserInfoLoaded(user!)); // Emit state after fetching user info } catch (e) { return; } diff --git a/lib/pages/home/bloc/home_state.dart b/lib/pages/home/bloc/home_state.dart index dda3fa50..10c50486 100644 --- a/lib/pages/home/bloc/home_state.dart +++ b/lib/pages/home/bloc/home_state.dart @@ -1,6 +1,5 @@ import 'package:equatable/equatable.dart'; import 'package:graphview/GraphView.dart'; -import 'package:syncrow_web/pages/auth/model/user_model.dart'; abstract class HomeState extends Equatable { const HomeState(); @@ -25,9 +24,3 @@ class HomeUpdateTree extends HomeState { @override List get props => [graph, builder]; } - -class HomeUserInfoLoaded extends HomeState { - final UserModel user; - - HomeUserInfoLoaded(this.user); -} diff --git a/lib/pages/home/view/home_page.dart b/lib/pages/home/view/home_page.dart index c1e36729..6217122b 100644 --- a/lib/pages/home/view/home_page.dart +++ b/lib/pages/home/view/home_page.dart @@ -8,6 +8,6 @@ class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { - return ResponsiveLayout(desktopBody: HomeWebPage(), mobileBody: HomeMobilePage()); + return ResponsiveLayout(desktopBody: const HomeWebPage(), mobileBody: HomeMobilePage()); } } diff --git a/lib/pages/home/view/home_page_mobile.dart b/lib/pages/home/view/home_page_mobile.dart index dcf35a41..ccf506e1 100644 --- a/lib/pages/home/view/home_page_mobile.dart +++ b/lib/pages/home/view/home_page_mobile.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; import 'package:syncrow_web/pages/home/bloc/home_bloc.dart'; +import 'package:syncrow_web/pages/home/bloc/home_state.dart'; import 'package:syncrow_web/pages/home/view/home_card.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; @@ -22,51 +23,51 @@ class HomeMobilePage extends StatelessWidget { ), ], ), - scaffoldBody: BlocProvider( - create: (context) => HomeBloc(), - child: SizedBox( - height: size.height, - width: size.width, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SizedBox(height: size.height * 0.05), - const Text( - 'ACCESS YOUR APPS', - style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700), - ), - const SizedBox(height: 30), - Expanded( - flex: 4, - child: SizedBox( - height: size.height * 0.6, - width: size.width * 0.68, - child: GridView.builder( - itemCount: 8, - gridDelegate: - const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 20.0, - mainAxisSpacing: 20.0, - childAspectRatio: 1.5, - ), - itemBuilder: (context, index) { - return HomeCard( - index: index, - active: homeItems[index]['active'], - name: homeItems[index]['title'], - img: homeItems[index]['icon'], - onTap: () {}, - ); - }, + scaffoldBody: BlocConsumer( + listener: (context, state) {}, + builder: (context, state) { + return SizedBox( + height: size.height, + width: size.width, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox(height: size.height * 0.05), + const Text( + 'ACCESS YOUR APPS', + style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700), ), - ), + const SizedBox(height: 30), + Expanded( + flex: 4, + child: SizedBox( + height: size.height * 0.6, + width: size.width * 0.68, + child: GridView.builder( + itemCount: 8, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 20.0, + mainAxisSpacing: 20.0, + childAspectRatio: 1.5, + ), + itemBuilder: (context, index) { + return HomeCard( + index: index, + active: homeItems[index]['active'], + name: homeItems[index]['title'], + img: homeItems[index]['icon'], + onTap: () {}, + ); + }, + ), + ), + ), + ], ), - ], - ), - ), - ), + ); + }), ); } diff --git a/lib/pages/home/view/home_page_web.dart b/lib/pages/home/view/home_page_web.dart index 2a578fc9..af59d70e 100644 --- a/lib/pages/home/view/home_page_web.dart +++ b/lib/pages/home/view/home_page_web.dart @@ -8,78 +8,72 @@ import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/web_layout/web_scaffold.dart'; class HomeWebPage extends StatelessWidget { - HomeWebPage({super.key}); + const HomeWebPage({super.key}); @override Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; return PopScope( canPop: false, onPopInvoked: (didPop) => false, - child: - WebScaffold( - enableMenuSideba: false, - appBarTitle: Row( - children: [ - SvgPicture.asset( - Assets.loginLogo, - width: 150, + child: WebScaffold( + enableMenuSideba: false, + appBarTitle: Row( + children: [ + SvgPicture.asset( + Assets.loginLogo, + width: 150, + ), + ], ), - ], - ), - scaffoldBody: BlocProvider( - create: (context) => HomeBloc(), - child: BlocConsumer( - listener: (BuildContext context, state) {}, - builder: (context, state) { - final homeBloc = BlocProvider.of(context); - return SizedBox( - height: size.height, - width: size.width, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SizedBox(height: size.height * 0.1), - Text( - 'ACCESS YOUR APPS', - style: Theme.of(context) - .textTheme - .headlineLarge! - .copyWith(color: Colors.black, fontSize: 40), - ), - const SizedBox(height: 30), - Expanded( - flex: 4, - child: SizedBox( - height: size.height * 0.6, - width: size.width * 0.68, - child: GridView.builder( - itemCount: 8, - gridDelegate: - const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 4, - crossAxisSpacing: 20.0, - mainAxisSpacing: 20.0, - childAspectRatio: 1.5, + scaffoldBody: BlocConsumer( + listener: (BuildContext context, state) {}, + builder: (context, state) { + final homeBloc = BlocProvider.of(context); + return SizedBox( + height: size.height, + width: size.width, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox(height: size.height * 0.1), + Text( + 'ACCESS YOUR APPS', + style: Theme.of(context) + .textTheme + .headlineLarge! + .copyWith(color: Colors.black, fontSize: 40), + ), + const SizedBox(height: 30), + Expanded( + flex: 4, + child: SizedBox( + height: size.height * 0.6, + width: size.width * 0.68, + child: GridView.builder( + itemCount: 8, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + crossAxisSpacing: 20.0, + mainAxisSpacing: 20.0, + childAspectRatio: 1.5, + ), + itemBuilder: (context, index) { + return HomeCard( + index: index, + active: homeBloc.homeItems[index].active!, + name: homeBloc.homeItems[index].title!, + img: homeBloc.homeItems[index].icon!, + onTap: () => homeBloc.homeItems[index].onPress(context), + ); + }, ), - itemBuilder: (context, index) { - return HomeCard( - index: index, - active: homeBloc.homeItems[index].active!, - name: homeBloc.homeItems[index].title!, - img: homeBloc.homeItems[index].icon!, - onTap: () => - homeBloc.homeItems[index].onPress(context), - ); - }, ), ), - ), - ], - ), - ); - }, - ), - ))); + ], + ), + ); + }, + ))); } } diff --git a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart index 2b64d606..f1dbe47c 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart @@ -205,7 +205,6 @@ class VisitorPasswordBloc extends Bloc mapEventToState(VisitorPasswordEvent event) async* { if (event is FetchDevice) { } else if (event is UpdateFilteredDevicesEvent) { @@ -417,7 +412,6 @@ class VisitorPasswordBloc extends Bloc? devicesUuid}) async { - print(jsonEncode({ - "email": email, - "devicesUuid": devicesUuid, - "passwordName": passwordName, - "effectiveTime": effectiveTime, - "invalidTime": invalidTime, - })); final response = await HTTPService().post( path: ApiEndpoints.sendOffLineMultipleTime, body: jsonEncode({ diff --git a/lib/utils/constants/routes_const.dart b/lib/utils/constants/routes_const.dart index 093a61dc..9f3b2d2b 100644 --- a/lib/utils/constants/routes_const.dart +++ b/lib/utils/constants/routes_const.dart @@ -1,5 +1,5 @@ class RoutesConst { - static const String auth = '/'; + static const String auth = '/auth'; static const String home = '/home'; static const String visitorPassword = '/visitor-password'; static const String accessManagementPage = '/access-management-page'; From dbe65bffff0d6ad719b61e9e07be347a9d968efa Mon Sep 17 00:00:00 2001 From: ashrafzarkanisala Date: Sat, 31 Aug 2024 15:35:17 +0300 Subject: [PATCH 005/158] access management design revamp, responsiveness and buttons --- lib/main.dart | 90 +--- .../view/access_management.dart | 394 +++++++++--------- lib/pages/auth/bloc/auth_bloc.dart | 6 +- lib/pages/auth/view/login_web_page.dart | 319 +++++++++----- .../common/buttons/search_reset_buttons.dart | 19 +- lib/pages/common/date_time_widget.dart | 32 +- .../common/text_field/custom_text_field.dart | 6 +- .../text_field/custom_web_textfield.dart | 10 +- .../view/device_managment_page.dart | 4 +- .../widgets/device_managment_body.dart | 3 +- lib/utils/theme/theme.dart | 53 +++ lib/web_layout/web_app_bar.dart | 150 +++++-- lib/web_layout/web_scaffold.dart | 20 +- 13 files changed, 642 insertions(+), 464 deletions(-) create mode 100644 lib/utils/theme/theme.dart diff --git a/lib/main.dart b/lib/main.dart index a94c79c3..b4fcb72d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,30 +7,35 @@ import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.da import 'package:go_router/go_router.dart'; import 'package:syncrow_web/services/locator.dart'; import 'package:syncrow_web/utils/app_routes.dart'; -import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/routes_const.dart'; +import 'package:syncrow_web/utils/theme/theme.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); initialSetup(); - String checkToken = await AuthBloc.getTokenAndValidate(); - GoRouter router = GoRouter( - initialLocation: - checkToken == 'Success' ? RoutesConst.home : RoutesConst.auth, - routes: AppRoutes.getRoutes(), - ); - runApp(MyApp( - router: router, - )); + runApp(MyApp()); } class MyApp extends StatelessWidget { - final GoRouter router; - const MyApp({ + MyApp({ super.key, - required this.router, }); + final GoRouter _router = GoRouter( + initialLocation: RoutesConst.auth, + routes: AppRoutes.getRoutes(), + redirect: (context, state) async { + String checkToken = await AuthBloc.getTokenAndValidate(); + final loggedIn = checkToken == 'Success'; + final goingToLogin = state.uri.toString() == RoutesConst.auth; + + if (!loggedIn && !goingToLogin) return RoutesConst.auth; + if (loggedIn && goingToLogin) return RoutesConst.home; + + return null; + }, + ); + @override Widget build(BuildContext context) { return MultiBlocProvider( @@ -41,7 +46,7 @@ class MyApp extends StatelessWidget { ) ], child: MaterialApp.router( - debugShowCheckedModeBanner: false, // Hide debug banner + debugShowCheckedModeBanner: false, scrollBehavior: const MaterialScrollBehavior().copyWith( dragDevices: { PointerDeviceKind.mouse, @@ -50,61 +55,8 @@ class MyApp extends StatelessWidget { PointerDeviceKind.unknown, }, ), - - theme: ThemeData( - fontFamily: 'Aftika', - textTheme: const TextTheme( - bodySmall: TextStyle( - fontSize: 13, - color: ColorsManager.whiteColors, - fontWeight: FontWeight.bold), - bodyMedium: TextStyle(color: Colors.black87, fontSize: 14), - bodyLarge: TextStyle(fontSize: 16, color: Colors.white), - headlineSmall: TextStyle(color: Colors.black87, fontSize: 18), - headlineMedium: TextStyle(color: Colors.black87, fontSize: 20), - headlineLarge: TextStyle( - color: Colors.white, - fontSize: 24, - fontWeight: FontWeight.bold, - ), - ), - colorScheme: ColorScheme.fromSeed( - seedColor: ColorsManager.blueColor, - primary: ColorsManager.blueColor, - onSurface: Colors.grey.shade400, - ), - switchTheme: SwitchThemeData( - thumbColor: WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.selected)) { - return ColorsManager.blueColor; - } - return ColorsManager.whiteColors; - }), - trackColor: WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.selected)) { - return ColorsManager.blueColor.withOpacity(0.5); - } - return ColorsManager.whiteColors; - }), - ), - checkboxTheme: CheckboxThemeData( - fillColor: WidgetStateProperty.resolveWith((states) { - if (states.contains(WidgetState.selected)) { - return ColorsManager.blueColor; - } - return Colors.grey.shade200; - }), - checkColor: WidgetStateProperty.all(Colors.white), - side: const BorderSide(color: ColorsManager.whiteColors), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(4), - ), - ), - ), - - routeInformationProvider: router.routeInformationProvider, - routerDelegate: router.routerDelegate, - routeInformationParser: router.routeInformationParser, + theme: myTheme, + routerConfig: _router, )); } } diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index 76c2d26e..2f5deb6d 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -4,237 +4,86 @@ import 'package:syncrow_web/pages/access_management/bloc/access_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/common/buttons/default_button.dart'; +import 'package:syncrow_web/pages/common/buttons/search_reset_buttons.dart'; import 'package:syncrow_web/pages/common/custom_table.dart'; import 'package:syncrow_web/pages/common/date_time_widget.dart'; +import 'package:syncrow_web/pages/common/filter/filter_widget.dart'; import 'package:syncrow_web/pages/common/text_field/custom_web_textfield.dart'; import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart'; import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart'; import 'package:syncrow_web/utils/color_manager.dart'; -import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/app_enum.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/style.dart'; +import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; import 'package:syncrow_web/web_layout/web_scaffold.dart'; -class AccessManagementPage extends StatelessWidget { +class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { const AccessManagementPage({super.key}); + @override Widget build(BuildContext context) { - Size size = MediaQuery.of(context).size; + final isLargeScreen = isLargeScreenSize(context); + final isSmallScreen = isSmallScreenSize(context); + final padding = + isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15); + return WebScaffold( enableMenuSideba: false, - appBarTitle: Row( - children: [ - Text( - 'Access Management', - style: Theme.of(context).textTheme.headlineLarge, - ) - ], - ), - appBarBody: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - 'Physical Access', - style: Theme.of(context).textTheme.headlineMedium!.copyWith(color: Colors.white), - ), - const NavigateHomeGridView(), - ], + appBarTitle: FittedBox( + child: Text( + 'Access Management', + style: Theme.of(context).textTheme.headlineLarge, ), - ], + ), + centerBody: Text( + 'Physical Access', + style: Theme.of(context) + .textTheme + .headlineMedium! + .copyWith(color: Colors.white), + ), + rightBody: const NavigateHomeGridView(), scaffoldBody: BlocProvider( - create: (BuildContext context) => AccessBloc()..add(FetchTableData()), + create: (BuildContext context) => + AccessBloc()..add(FetchTableData()), child: BlocConsumer( listener: (context, state) {}, builder: (context, state) { final accessBloc = BlocProvider.of(context); final filteredData = accessBloc.filteredData; + return state is AccessLoaded ? const Center(child: CircularProgressIndicator()) : Container( - padding: const EdgeInsets.all(30), - height: size.height, - width: size.width, + padding: padding, + height: MediaQuery.of(context).size.height, + width: MediaQuery.of(context).size.width, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Container( - decoration: containerDecoration, - height: size.height * 0.05, - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: BlocProvider.of(context).tabs.length, - shrinkWrap: true, - itemBuilder: (context, index) { - final isSelected = - index == BlocProvider.of(context).selectedIndex; - return InkWell( - onTap: () { - BlocProvider.of(context) - .add(TabChangedEvent(index)); - }, - child: Container( - decoration: BoxDecoration( - color: ColorsManager.boxColor, - border: Border.all( - color: isSelected ? Colors.blue : Colors.transparent, - width: 2.0, - ), - borderRadius: index == 0 - ? const BorderRadius.only( - topLeft: Radius.circular(10), - bottomLeft: Radius.circular(10)) - : index == 3 - ? const BorderRadius.only( - topRight: Radius.circular(10), - bottomRight: Radius.circular(10)) - : null, - ), - padding: const EdgeInsets.only(left: 10, right: 10), - child: Center( - child: Text( - BlocProvider.of(context).tabs[index], - style: TextStyle( - color: isSelected ? Colors.blue : Colors.black, - ), - ), - ), - ), - ); - }, - ), - ), - const SizedBox( - height: 20, - ), - Row( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.end, - textBaseline: TextBaseline.ideographic, - children: [ - Container( - width: size.width * 0.15, - child: CustomWebTextField( - controller: accessBloc.passwordName, - isRequired: true, - textFieldName: 'Name', - description: '', - ), - ), - const SizedBox( - width: 15, - ), - DateTimeWebWidget( - icon: Assets.calendarIcon, - isRequired: false, - title: 'Access Time', - size: size, - endTime: () { - accessBloc.add(SelectTime(context: context, isStart: false)); - }, - startTime: () { - accessBloc.add(SelectTime(context: context, isStart: true)); - }, - firstString: BlocProvider.of(context).startTime, - secondString: BlocProvider.of(context).endTime, - ), - const SizedBox( - width: 15, - ), - SizedBox( - width: size.width * 0.06, - child: Container( - decoration: containerDecoration, - child: DefaultButton( - onPressed: () { - accessBloc.add(FilterDataEvent( - selectedTabIndex: BlocProvider.of( - context) - .selectedIndex, // Pass the selected tab index - passwordName: - accessBloc.passwordName.text.toLowerCase(), - startTime: accessBloc.effectiveTimeTimeStamp, - endTime: accessBloc.expirationTimeTimeStamp)); - }, - borderRadius: 9, - child: const Text('Search'))), - ), - const SizedBox( - width: 10, - ), - SizedBox( - width: size.width * 0.06, - child: Container( - decoration: containerDecoration, - child: DefaultButton( - onPressed: () { - accessBloc.add(ResetSearch()); - }, - backgroundColor: ColorsManager.whiteColors, - borderRadius: 9, - child: Text( - 'Reset', - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith(color: Colors.black), - ), - ), - ), - ), - ], - ), - const SizedBox( - height: 20, - ), - Wrap( - children: [ - Container( - width: size.width * 0.15, - decoration: containerDecoration, - child: DefaultButton( - onPressed: () { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return const VisitorPasswordDialog(); - }, - ).then((v) { - if (v != null) { - accessBloc.add(FetchTableData()); - } - }); - }, - borderRadius: 8, - child: const Text('+ Create Visitor Password ')), - ), - const SizedBox( - width: 10, - ), - Container( - width: size.width * 0.12, - decoration: containerDecoration, - child: DefaultButton( - borderRadius: 8, - backgroundColor: ColorsManager.whiteColors, - child: Text( - 'Admin Password', - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith(color: Colors.black), - ))) - ], - ), - const SizedBox( - height: 20, + FilterWidget( + size: MediaQuery.of(context).size, + tabs: accessBloc.tabs, + selectedIndex: accessBloc.selectedIndex, + onTabChanged: (index) { + accessBloc.add(TabChangedEvent(index)); + }, ), + const SizedBox(height: 20), + if (isSmallScreen) + _buildSmallSearchFilters(context, accessBloc) + else + _buildNormalSearchWidgets(context, accessBloc), + const SizedBox(height: 20), + _buildVisitorAdminPasswords(context, accessBloc), + const SizedBox(height: 20), Expanded( child: DynamicTable( isEmpty: filteredData.isEmpty, withCheckBox: false, - size: size, + size: MediaQuery.of(context).size, cellDecoration: containerDecoration, headers: const [ 'Name', @@ -256,12 +105,155 @@ class AccessManagementPage extends StatelessWidget { item.passwordStatus.value, ]; }).toList(), - ) - // : const Center(child: CircularProgressIndicator()), - ) + )), ], ), ); }))); } + + Wrap _buildVisitorAdminPasswords( + BuildContext context, AccessBloc accessBloc) { + return Wrap( + spacing: 10, + runSpacing: 10, + children: [ + Container( + width: 205, + height: 35, + decoration: containerDecoration, + child: DefaultButton( + onPressed: () { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return const VisitorPasswordDialog(); + }, + ).then((v) { + if (v != null) { + accessBloc.add(FetchTableData()); + } + }); + }, + borderRadius: 8, + child: Text( + '+ Create Visitor Password ', + style: context.textTheme.titleSmall! + .copyWith(color: Colors.white, fontSize: 12), + )), + ), + Container( + width: 133, + height: 35, + decoration: containerDecoration, + child: DefaultButton( + borderRadius: 8, + backgroundColor: ColorsManager.whiteColors, + child: Text( + 'Admin Password', + style: context.textTheme.titleSmall! + .copyWith(color: Colors.black, fontSize: 12), + )), + ), + ], + ); + } + + Row _buildNormalSearchWidgets(BuildContext context, AccessBloc accessBloc) { + return Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + textBaseline: TextBaseline.ideographic, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.15, + child: CustomWebTextField( + controller: accessBloc.passwordName, + height: 36, + isRequired: true, + textFieldName: 'Name', + description: '', + ), + ), + const SizedBox(width: 15), + SizedBox( + child: DateTimeWebWidget( + icon: Assets.calendarIcon, + isRequired: false, + title: 'Access Time', + size: MediaQuery.of(context).size, + endTime: () { + accessBloc.add(SelectTime(context: context, isStart: false)); + }, + startTime: () { + accessBloc.add(SelectTime(context: context, isStart: true)); + }, + firstString: BlocProvider.of(context).startTime, + secondString: BlocProvider.of(context).endTime, + ), + ), + const SizedBox(width: 15), + SearchResetButtons( + onSearch: () { + accessBloc.add(FilterDataEvent( + selectedTabIndex: + BlocProvider.of(context).selectedIndex, + passwordName: accessBloc.passwordName.text.toLowerCase(), + startTime: accessBloc.effectiveTimeTimeStamp, + endTime: accessBloc.expirationTimeTimeStamp)); + }, + onReset: () { + accessBloc.add(ResetSearch()); + }, + ), + ], + ); + } + + Widget _buildSmallSearchFilters(BuildContext context, AccessBloc accessBloc) { + return Wrap( + spacing: 20, + runSpacing: 10, + children: [ + SizedBox( + width: MediaQuery.of(context).size.width * 0.15, + child: CustomWebTextField( + controller: accessBloc.passwordName, + isRequired: true, + height: 36, + textFieldName: 'Name', + description: '', + ), + ), + DateTimeWebWidget( + icon: Assets.calendarIcon, + isRequired: false, + title: 'Access Time', + size: MediaQuery.of(context).size, + endTime: () { + accessBloc.add(SelectTime(context: context, isStart: false)); + }, + startTime: () { + accessBloc.add(SelectTime(context: context, isStart: true)); + }, + firstString: BlocProvider.of(context).startTime, + secondString: BlocProvider.of(context).endTime, + ), + SearchResetButtons( + onSearch: () { + accessBloc.add(FilterDataEvent( + selectedTabIndex: + BlocProvider.of(context).selectedIndex, + passwordName: accessBloc.passwordName.text.toLowerCase(), + startTime: accessBloc.effectiveTimeTimeStamp, + endTime: accessBloc.expirationTimeTimeStamp)); + }, + onReset: () { + accessBloc.add(ResetSearch()); + }, + ), + ], + ); + } } diff --git a/lib/pages/auth/bloc/auth_bloc.dart b/lib/pages/auth/bloc/auth_bloc.dart index ea53fdd3..a08cd0d3 100644 --- a/lib/pages/auth/bloc/auth_bloc.dart +++ b/lib/pages/auth/bloc/auth_bloc.dart @@ -135,6 +135,7 @@ class AuthBloc extends Bloc { emit(const LoginFailure(error: 'Something went wrong')); return; } + token = await AuthenticationAPI.loginWithEmail( model: LoginWithEmailModel( email: event.username, @@ -143,10 +144,10 @@ class AuthBloc extends Bloc { ); } catch (failure) { validate = 'Invalid Credentials!'; - emit(AuthInitialState()); - // emit(const LoginFailure(error: 'Something went wrong')); + emit(const LoginFailure(error: 'Invalid Credentials!')); return; } + if (token.accessTokenIsNotEmpty) { FlutterSecureStorage storage = const FlutterSecureStorage(); await storage.write( @@ -155,7 +156,6 @@ class AuthBloc extends Bloc { key: UserModel.userUuidKey, value: Token.decodeToken(token.accessToken)['uuid'].toString()); user = UserModel.fromToken(token); - debugPrint(token.accessToken); loginEmailController.clear(); loginPasswordController.clear(); emit(LoginSuccess()); diff --git a/lib/pages/auth/view/login_web_page.dart b/lib/pages/auth/view/login_web_page.dart index 09191fb1..a88aac07 100644 --- a/lib/pages/auth/view/login_web_page.dart +++ b/lib/pages/auth/view/login_web_page.dart @@ -10,7 +10,6 @@ import 'package:syncrow_web/pages/auth/model/region_model.dart'; import 'package:syncrow_web/pages/auth/view/forget_password_page.dart'; import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/pages/common/first_layer.dart'; -import 'package:syncrow_web/pages/home/view/home_page.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/routes_const.dart'; @@ -32,7 +31,7 @@ class _LoginWebPageState extends State { child: BlocConsumer( listener: (context, state) { if (state is LoginSuccess) { - context.replace(RoutesConst.home); + GoRouter.of(context).go(RoutesConst.home); } else if (state is LoginFailure) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( @@ -55,7 +54,8 @@ class _LoginWebPageState extends State { late ScrollController _scrollController; _scrollController = ScrollController(); void _scrollToCenter() { - final double middlePosition = _scrollController.position.maxScrollExtent / 2; + final double middlePosition = + _scrollController.position.maxScrollExtent / 2; _scrollController.animateTo( middlePosition, duration: const Duration(seconds: 1), @@ -99,9 +99,11 @@ class _LoginWebPageState extends State { child: Container( decoration: BoxDecoration( color: Colors.white.withOpacity(0.1), - borderRadius: const BorderRadius.all(Radius.circular(30)), + borderRadius: const BorderRadius.all( + Radius.circular(30)), border: Border.all( - color: ColorsManager.graysColor.withOpacity(0.2))), + color: ColorsManager.graysColor + .withOpacity(0.2))), child: Form( key: loginBloc.loginFormKey, child: Padding( @@ -109,16 +111,22 @@ class _LoginWebPageState extends State { horizontal: size.width * 0.02, vertical: size.width * 0.003), child: Column( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + crossAxisAlignment: + CrossAxisAlignment.start, children: [ const SizedBox(height: 40), Text('Login', - style: Theme.of(context).textTheme.headlineLarge), + style: Theme.of(context) + .textTheme + .headlineLarge), SizedBox(height: size.height * 0.03), Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisAlignment: + MainAxisAlignment.start, children: [ Text( "Country/Region", @@ -126,57 +134,81 @@ class _LoginWebPageState extends State { .textTheme .bodySmall! .copyWith( - fontSize: 14, fontWeight: FontWeight.w400), + fontSize: 14, + fontWeight: + FontWeight.w400), ), const SizedBox( height: 10, ), SizedBox( - child: DropdownButtonFormField( + child: DropdownButtonFormField< + String>( padding: EdgeInsets.zero, - value: loginBloc.regionList!.any((region) => - region.id == loginBloc.regionUuid) + value: loginBloc.regionList! + .any((region) => + region.id == + loginBloc + .regionUuid) ? loginBloc.regionUuid : null, - validator: loginBloc.validateRegion, + validator: + loginBloc.validateRegion, icon: const Icon( - Icons.keyboard_arrow_down_outlined, + Icons + .keyboard_arrow_down_outlined, ), - decoration: textBoxDecoration()!.copyWith( - errorStyle: const TextStyle(height: 0), + decoration: textBoxDecoration()! + .copyWith( + errorStyle: const TextStyle( + height: 0), hintText: null, ), hint: SizedBox( width: size.width * 0.12, child: Align( - alignment: Alignment.centerLeft, + alignment: + Alignment.centerLeft, child: Text( 'Select your region/country', - textAlign: TextAlign.center, + textAlign: + TextAlign.center, style: Theme.of(context) .textTheme .bodySmall! .copyWith( - color: ColorsManager.grayColor, - fontWeight: FontWeight.w400), - overflow: TextOverflow.ellipsis, + color: + ColorsManager + .grayColor, + fontWeight: + FontWeight + .w400), + overflow: + TextOverflow.ellipsis, ), ), ), isDense: true, - style: const TextStyle(color: Colors.black), - items: - loginBloc.regionList!.map((RegionModel region) { - return DropdownMenuItem( + style: const TextStyle( + color: Colors.black), + items: loginBloc.regionList! + .map((RegionModel region) { + return DropdownMenuItem< + String>( value: region.id, child: SizedBox( - width: size.width * 0.08, - child: Text(region.name)), + width: + size.width * 0.08, + child: + Text(region.name)), ); }).toList(), onChanged: (String? value) { - loginBloc.add(CheckEnableEvent()); - loginBloc.add(SelectRegionEvent(val: value!)); + loginBloc + .add(CheckEnableEvent()); + loginBloc.add( + SelectRegionEvent( + val: value!)); }, ), ) @@ -184,8 +216,10 @@ class _LoginWebPageState extends State { ), const SizedBox(height: 20.0), Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisAlignment: + MainAxisAlignment.start, children: [ Text( "Email", @@ -193,7 +227,9 @@ class _LoginWebPageState extends State { .textTheme .bodySmall! .copyWith( - fontSize: 14, fontWeight: FontWeight.w400), + fontSize: 14, + fontWeight: + FontWeight.w400), ), const SizedBox( height: 10, @@ -201,29 +237,42 @@ class _LoginWebPageState extends State { SizedBox( child: TextFormField( onChanged: (value) { - loginBloc.add(CheckEnableEvent()); + loginBloc + .add(CheckEnableEvent()); }, - validator: loginBloc.loginValidateEmail, - controller: loginBloc.loginEmailController, - decoration: textBoxDecoration()!.copyWith( - errorStyle: const TextStyle( - height: 0), // Hide the error text space - hintText: 'Enter your email address', - hintStyle: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - color: ColorsManager.grayColor, - fontWeight: FontWeight.w400)), - style: const TextStyle(color: Colors.black), + validator: loginBloc + .loginValidateEmail, + controller: loginBloc + .loginEmailController, + decoration: textBoxDecoration()! + .copyWith( + errorStyle: const TextStyle( + height: + 0), // Hide the error text space + hintText: + 'Enter your email address', + hintStyle: Theme.of( + context) + .textTheme + .bodySmall! + .copyWith( + color: ColorsManager + .grayColor, + fontWeight: + FontWeight + .w400)), + style: const TextStyle( + color: Colors.black), ), ), ], ), const SizedBox(height: 20.0), Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: + CrossAxisAlignment.start, + mainAxisAlignment: + MainAxisAlignment.start, children: [ Text( "Password", @@ -231,7 +280,9 @@ class _LoginWebPageState extends State { .textTheme .bodySmall! .copyWith( - fontSize: 14, fontWeight: FontWeight.w400), + fontSize: 14, + fontWeight: + FontWeight.w400), ), const SizedBox( height: 10, @@ -239,39 +290,54 @@ class _LoginWebPageState extends State { SizedBox( child: TextFormField( onChanged: (value) { - loginBloc.add(CheckEnableEvent()); + loginBloc + .add(CheckEnableEvent()); }, - validator: loginBloc.validatePassword, - obscureText: loginBloc.obscureText, - keyboardType: TextInputType.visiblePassword, - controller: loginBloc.loginPasswordController, - decoration: textBoxDecoration()!.copyWith( - hintText: 'At least 8 characters', + validator: + loginBloc.validatePassword, + obscureText: + loginBloc.obscureText, + keyboardType: TextInputType + .visiblePassword, + controller: loginBloc + .loginPasswordController, + decoration: textBoxDecoration()! + .copyWith( + hintText: + 'At least 8 characters', hintStyle: Theme.of(context) .textTheme .bodySmall! .copyWith( - color: ColorsManager.grayColor, - fontWeight: FontWeight.w400), + color: ColorsManager + .grayColor, + fontWeight: + FontWeight.w400), suffixIcon: IconButton( onPressed: () { - loginBloc.add(PasswordVisibleEvent( - newValue: loginBloc.obscureText)); + loginBloc.add( + PasswordVisibleEvent( + newValue: loginBloc + .obscureText)); }, icon: SizedBox( child: SvgPicture.asset( loginBloc.obscureText - ? Assets.visiblePassword - : Assets.invisiblePassword, + ? Assets + .visiblePassword + : Assets + .invisiblePassword, height: 15, width: 15, ), ), ), errorStyle: const TextStyle( - height: 0), // Hide the error text space + height: + 0), // Hide the error text space ), - style: const TextStyle(color: Colors.black), + style: const TextStyle( + color: Colors.black), ), ), ], @@ -281,11 +347,13 @@ class _LoginWebPageState extends State { ), SizedBox( child: Row( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: + MainAxisAlignment.end, children: [ InkWell( onTap: () { - Navigator.of(context).push(MaterialPageRoute( + Navigator.of(context) + .push(MaterialPageRoute( builder: (context) => const ForgetPasswordPage(), )); @@ -298,7 +366,8 @@ class _LoginWebPageState extends State { .copyWith( color: Colors.black, fontSize: 14, - fontWeight: FontWeight.w400), + fontWeight: + FontWeight.w400), ), ), ], @@ -310,16 +379,18 @@ class _LoginWebPageState extends State { Row( children: [ Transform.scale( - scale: 1.2, // Adjust the scale as needed + scale: + 1.2, // Adjust the scale as needed child: Checkbox( - fillColor: - MaterialStateProperty.all(Colors.white), + fillColor: MaterialStateProperty + .all(Colors.white), activeColor: Colors.white, value: loginBloc.isChecked, checkColor: Colors.black, shape: const CircleBorder(), onChanged: (bool? newValue) { - loginBloc.add(CheckBoxEvent(newValue: newValue)); + loginBloc.add(CheckBoxEvent( + newValue: newValue)); }, ), ), @@ -328,36 +399,45 @@ class _LoginWebPageState extends State { child: RichText( text: TextSpan( text: 'Agree to ', - style: const TextStyle(color: Colors.white), + style: const TextStyle( + color: Colors.white), children: [ TextSpan( - text: '(Terms of Service)', + text: + '(Terms of Service)', style: const TextStyle( color: Colors.black, ), - recognizer: TapGestureRecognizer() - ..onTap = () { - loginBloc.launchURL( - 'https://example.com/terms'); - }, + recognizer: + TapGestureRecognizer() + ..onTap = () { + loginBloc.launchURL( + 'https://example.com/terms'); + }, ), TextSpan( - text: ' (Legal Statement)', - style: const TextStyle(color: Colors.black), - recognizer: TapGestureRecognizer() - ..onTap = () { - loginBloc.launchURL( - 'https://example.com/legal'); - }, + text: + ' (Legal Statement)', + style: const TextStyle( + color: Colors.black), + recognizer: + TapGestureRecognizer() + ..onTap = () { + loginBloc.launchURL( + 'https://example.com/legal'); + }, ), TextSpan( - text: ' (Privacy Statement)', - style: const TextStyle(color: Colors.black), - recognizer: TapGestureRecognizer() - ..onTap = () { - loginBloc.launchURL( - 'https://example.com/privacy'); - }, + text: + ' (Privacy Statement)', + style: const TextStyle( + color: Colors.black), + recognizer: + TapGestureRecognizer() + ..onTap = () { + loginBloc.launchURL( + 'https://example.com/privacy'); + }, ), ], ), @@ -367,35 +447,49 @@ class _LoginWebPageState extends State { ), const SizedBox(height: 20.0), Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.center, children: [ SizedBox( width: size.width * 0.2, child: DefaultButton( - enabled: loginBloc.checkValidate, + enabled: + loginBloc.checkValidate, child: Text('Sign in', style: Theme.of(context) .textTheme .labelLarge! .copyWith( fontSize: 14, - color: loginBloc.checkValidate - ? ColorsManager.whiteColors - : ColorsManager.whiteColors - .withOpacity(0.2), + color: loginBloc + .checkValidate + ? ColorsManager + .whiteColors + : ColorsManager + .whiteColors + .withOpacity( + 0.2), )), onPressed: () { - if (loginBloc.loginFormKey.currentState! + if (loginBloc.loginFormKey + .currentState! .validate()) { - loginBloc.add(LoginButtonPressed( - regionUuid: loginBloc.regionUuid, - username: loginBloc.loginEmailController.text, - password: - loginBloc.loginPasswordController.text, + loginBloc + .add(LoginButtonPressed( + regionUuid: + loginBloc.regionUuid, + username: loginBloc + .loginEmailController + .text, + password: loginBloc + .loginPasswordController + .text, )); } else { - loginBloc.add(ChangeValidateEvent()); + loginBloc.add( + ChangeValidateEvent()); } }, ), @@ -404,8 +498,10 @@ class _LoginWebPageState extends State { ), const SizedBox(height: 15.0), Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, + mainAxisAlignment: + MainAxisAlignment.center, children: [ SizedBox( child: Text( @@ -430,7 +526,8 @@ class _LoginWebPageState extends State { ), ), ), - if (state is AuthLoading) const Center(child: CircularProgressIndicator()) + if (state is AuthLoading) + const Center(child: CircularProgressIndicator()) ], ); } diff --git a/lib/pages/common/buttons/search_reset_buttons.dart b/lib/pages/common/buttons/search_reset_buttons.dart index a03b889a..cdb09c21 100644 --- a/lib/pages/common/buttons/search_reset_buttons.dart +++ b/lib/pages/common/buttons/search_reset_buttons.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:syncrow_web/pages/common/buttons/default_button.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/style.dart'; import 'package:syncrow_web/utils/color_manager.dart'; @@ -23,14 +24,18 @@ class SearchResetButtons extends StatelessWidget { const SizedBox(height: 25), Center( child: Container( - height: 43, + height: 35, width: 100, decoration: containerDecoration, child: Center( child: DefaultButton( onPressed: onSearch, borderRadius: 9, - child: const Text('Search'), + child: Text( + 'Search', + style: context.textTheme.titleSmall! + .copyWith(color: Colors.white, fontSize: 12), + ), ), ), ), @@ -44,21 +49,19 @@ class SearchResetButtons extends StatelessWidget { const SizedBox(height: 25), Center( child: Container( - height: 43, + height: 35, width: 100, decoration: containerDecoration, child: Center( child: DefaultButton( backgroundColor: ColorsManager.whiteColors, borderRadius: 9, + onPressed: onReset, child: Text( 'Reset', - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith(color: Colors.black), + style: context.textTheme.titleSmall! + .copyWith(color: Colors.black, fontSize: 12), ), - onPressed: onReset, ), ), ), diff --git a/lib/pages/common/date_time_widget.dart b/lib/pages/common/date_time_widget.dart index 0b8fa0da..824ab382 100644 --- a/lib/pages/common/date_time_widget.dart +++ b/lib/pages/common/date_time_widget.dart @@ -36,7 +36,10 @@ class DateTimeWebWidget extends StatelessWidget { if (isRequired) Text( '* ', - style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: Colors.red), + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(color: Colors.red), ), Text( title, @@ -51,8 +54,9 @@ class DateTimeWebWidget extends StatelessWidget { height: 8, ), Container( - height: size.height * 0.055, - padding: const EdgeInsets.only(top: 10, bottom: 10, right: 30, left: 10), + height: size.height * 0.056, + padding: + const EdgeInsets.only(top: 10, bottom: 10, right: 30, left: 10), decoration: containerDecoration, child: FittedBox( child: Column( @@ -65,10 +69,13 @@ class DateTimeWebWidget extends StatelessWidget { child: FittedBox( child: Text( firstString, - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: ColorsManager.grayColor, - fontSize: 12, - fontWeight: FontWeight.w400), + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( + color: ColorsManager.grayColor, + fontSize: 12, + fontWeight: FontWeight.w400), ), )), const SizedBox( @@ -83,10 +90,13 @@ class DateTimeWebWidget extends StatelessWidget { child: FittedBox( child: Text( secondString, - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: ColorsManager.grayColor, - fontSize: 12, - fontWeight: FontWeight.w400), + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( + color: ColorsManager.grayColor, + fontSize: 12, + fontWeight: FontWeight.w400), ), )), const SizedBox( diff --git a/lib/pages/common/text_field/custom_text_field.dart b/lib/pages/common/text_field/custom_text_field.dart index 2a379982..2c29762c 100644 --- a/lib/pages/common/text_field/custom_text_field.dart +++ b/lib/pages/common/text_field/custom_text_field.dart @@ -8,7 +8,7 @@ class StatefulTextField extends StatefulWidget { this.hintText = 'Please enter', required this.width, this.elevation = 0, - required this.controller, // Add the controller + required this.controller, }); final String title; @@ -59,7 +59,8 @@ class CustomTextField extends StatelessWidget { Text( title, style: context.textTheme.bodyMedium!.copyWith( - fontWeight: FontWeight.w600, + fontSize: 13, + fontWeight: FontWeight.w400, color: const Color(0xff000000), ), ), @@ -79,6 +80,7 @@ class CustomTextField extends StatelessWidget { style: const TextStyle(color: Colors.black), decoration: InputDecoration( hintText: hintText, + hintStyle: const TextStyle(fontSize: 12), contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), border: InputBorder.none, diff --git a/lib/pages/common/text_field/custom_web_textfield.dart b/lib/pages/common/text_field/custom_web_textfield.dart index 6fe0dc49..926a20f5 100644 --- a/lib/pages/common/text_field/custom_web_textfield.dart +++ b/lib/pages/common/text_field/custom_web_textfield.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/utils/style.dart'; class CustomWebTextField extends StatelessWidget { @@ -11,6 +12,7 @@ class CustomWebTextField extends StatelessWidget { this.description, this.validator, this.hintText, + this.height, }); final bool isRequired; @@ -19,6 +21,7 @@ class CustomWebTextField extends StatelessWidget { final TextEditingController? controller; final String? Function(String?)? validator; final String? hintText; + final double? height; @override Widget build(BuildContext context) { @@ -66,6 +69,7 @@ class CustomWebTextField extends StatelessWidget { height: 7, ), Container( + height: height ?? 35, decoration: containerDecoration .copyWith(color: const Color(0xFFF5F6F7), boxShadow: [ BoxShadow( @@ -80,9 +84,9 @@ class CustomWebTextField extends StatelessWidget { controller: controller, style: const TextStyle(color: Colors.black), decoration: textBoxDecoration()!.copyWith( - errorStyle: - const TextStyle(height: 0), // Hide the error text space - + errorStyle: const TextStyle(height: 0), + hintStyle: context.textTheme.titleSmall! + .copyWith(color: Colors.grey, fontSize: 12), hintText: hintText ?? 'Please enter'), ), ), 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 04315651..93480ae5 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 @@ -20,9 +20,7 @@ class DeviceManagementPage extends StatelessWidget with HelperResponsiveLayout { style: Theme.of(context).textTheme.headlineLarge, ), ), - appBarBody: const [ - NavigateHomeGridView(), - ], + rightBody: const NavigateHomeGridView(), enableMenuSideba: isLargeScreenSize(context), scaffoldBody: BlocBuilder( builder: (context, state) { diff --git a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart index 9b5fcc8d..d1ee0fed 100644 --- a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart +++ b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart @@ -75,7 +75,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { const DeviceSearchFilters(), const SizedBox(height: 12), Container( - height: 43, + height: 35, width: 100, decoration: containerDecoration, child: Center( @@ -97,6 +97,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { child: Text( 'Control', style: TextStyle( + fontSize: 12, color: isControlButtonEnabled ? Colors.white : Colors.grey, diff --git a/lib/utils/theme/theme.dart b/lib/utils/theme/theme.dart new file mode 100644 index 00000000..ee868c8d --- /dev/null +++ b/lib/utils/theme/theme.dart @@ -0,0 +1,53 @@ +import 'package:flutter/material.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; + +final myTheme = ThemeData( + fontFamily: 'Aftika', + textTheme: const TextTheme( + bodySmall: TextStyle( + fontSize: 13, + color: ColorsManager.whiteColors, + fontWeight: FontWeight.bold), + bodyMedium: TextStyle(color: Colors.black87, fontSize: 14), + bodyLarge: TextStyle(fontSize: 16, color: Colors.white), + headlineSmall: TextStyle(color: Colors.black87, fontSize: 18), + headlineMedium: TextStyle(color: Colors.black87, fontSize: 20), + headlineLarge: TextStyle( + color: Colors.white, + fontSize: 24, + fontWeight: FontWeight.bold, + ), + ), + colorScheme: ColorScheme.fromSeed( + seedColor: ColorsManager.blueColor, + primary: ColorsManager.blueColor, + onSurface: Colors.grey.shade400, + ), + switchTheme: SwitchThemeData( + thumbColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.selected)) { + return ColorsManager.blueColor; + } + return ColorsManager.whiteColors; + }), + trackColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.selected)) { + return ColorsManager.blueColor.withOpacity(0.5); + } + return ColorsManager.whiteColors; + }), + ), + checkboxTheme: CheckboxThemeData( + fillColor: WidgetStateProperty.resolveWith((states) { + if (states.contains(WidgetState.selected)) { + return ColorsManager.blueColor; + } + return Colors.grey.shade200; + }), + checkColor: WidgetStateProperty.all(Colors.white), + side: const BorderSide(color: ColorsManager.whiteColors), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(4), + ), + ), +); diff --git a/lib/web_layout/web_app_bar.dart b/lib/web_layout/web_app_bar.dart index 6ad54d0b..46b9c614 100644 --- a/lib/web_layout/web_app_bar.dart +++ b/lib/web_layout/web_app_bar.dart @@ -3,63 +3,125 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_web/pages/home/bloc/home_bloc.dart'; import 'package:syncrow_web/pages/home/bloc/home_state.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; -class WebAppBar extends StatelessWidget { +class WebAppBar extends StatelessWidget with HelperResponsiveLayout { final Widget? title; - final List? body; - const WebAppBar({super.key, this.title, this.body}); + final Widget? centerBody; + final Widget? rightBody; + + const WebAppBar({super.key, this.title, this.centerBody, this.rightBody}); @override Widget build(BuildContext context) { + bool isSmallScreen = isSmallScreenSize(context); + return BlocBuilder(builder: (context, state) { return Container( - height: 100, + height: isSmallScreen ? 130 : 100, decoration: const BoxDecoration(color: ColorsManager.secondaryColor), padding: const EdgeInsets.all(10), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: title!, - ), - if (body != null) - Expanded( - flex: 2, - child: Wrap( - spacing: 15, // Adjust the spacing as needed - children: body!, - ), - ), - Row( - children: [ - const SizedBox( - width: 10, - ), - const SizedBox.square( - dimension: 40, - child: CircleAvatar( - backgroundColor: Colors.white, - child: SizedBox.square( - dimension: 35, - child: CircleAvatar( - backgroundColor: Colors.grey, - child: FlutterLogo(), + child: isSmallScreen + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (title != null) + Align( + alignment: Alignment.centerLeft, + child: title!, + ), + if (centerBody != null) + Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.only(top: 8.0), + child: centerBody, ), ), + if (rightBody != null || HomeBloc.user != null) + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (rightBody != null) rightBody!, + Row( + children: [ + const SizedBox.square( + dimension: 40, + child: CircleAvatar( + backgroundColor: Colors.white, + child: SizedBox.square( + dimension: 35, + child: CircleAvatar( + backgroundColor: Colors.grey, + child: FlutterLogo(), + ), + ), + ), + ), + const SizedBox( + width: 10, + ), + if (HomeBloc.user != null) + Text( + '${HomeBloc.user!.firstName} ${HomeBloc.user!.lastName}', + style: Theme.of(context).textTheme.bodyLarge, + ), + ], + ), + ], + ), + ], + ) + : Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Align( + alignment: Alignment.centerLeft, + child: title!, ), - ), - const SizedBox( - width: 10, - ), - if (HomeBloc.user != null) - Text( - '${HomeBloc.user!.firstName.toString()} ${HomeBloc.user!.lastName.toString()} ', - style: Theme.of(context).textTheme.bodyLarge, + if (centerBody != null) + Expanded( + child: Center( + child: centerBody, + ), + ), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (rightBody != null) + Align( + alignment: Alignment.centerRight, + child: rightBody, + ), + const SizedBox( + width: 10, + ), + const SizedBox.square( + dimension: 40, + child: CircleAvatar( + backgroundColor: Colors.white, + child: SizedBox.square( + dimension: 35, + child: CircleAvatar( + backgroundColor: Colors.grey, + child: FlutterLogo(), + ), + ), + ), + ), + const SizedBox( + width: 10, + ), + if (HomeBloc.user != null) + Text( + '${HomeBloc.user!.firstName} ${HomeBloc.user!.lastName}', + style: Theme.of(context).textTheme.bodyLarge, + ), + ], ), - ], - ) - ], - ), + ], + ), ); }); } diff --git a/lib/web_layout/web_scaffold.dart b/lib/web_layout/web_scaffold.dart index 72bcb777..b4edd764 100644 --- a/lib/web_layout/web_scaffold.dart +++ b/lib/web_layout/web_scaffold.dart @@ -8,14 +8,17 @@ import 'menu_sidebar.dart'; class WebScaffold extends StatelessWidget with HelperResponsiveLayout { final bool enableMenuSideba; final Widget? appBarTitle; - final List? appBarBody; + final Widget? centerBody; + final Widget? rightBody; final Widget? scaffoldBody; - const WebScaffold( - {super.key, - this.appBarTitle, - this.appBarBody, - this.scaffoldBody, - this.enableMenuSideba = true}); + const WebScaffold({ + super.key, + this.appBarTitle, + this.centerBody, + this.rightBody, + this.scaffoldBody, + this.enableMenuSideba = true, + }); @override Widget build(BuildContext context) { final isSmall = isSmallScreenSize(context); @@ -40,7 +43,8 @@ class WebScaffold extends StatelessWidget with HelperResponsiveLayout { opacity: 0.7, child: WebAppBar( title: appBarTitle, - body: appBarBody, + centerBody: centerBody, + rightBody: rightBody, )), Expanded( child: Row( From 36c2412234fb49484b52f191ffaef59d0f896b3a Mon Sep 17 00:00:00 2001 From: ashrafzarkanisala Date: Sat, 31 Aug 2024 17:24:43 +0300 Subject: [PATCH 006/158] handle login, home page responsiveness --- .../view/access_management.dart | 16 +- lib/pages/auth/view/login_web_page.dart | 823 ++++++++---------- .../common/buttons/search_reset_buttons.dart | 4 +- lib/pages/common/date_time_widget.dart | 2 +- lib/pages/common/filter/filter_widget.dart | 2 +- .../common/text_field/custom_text_field.dart | 2 +- .../widgets/device_managment_body.dart | 2 +- lib/pages/home/view/home_page.dart | 10 +- lib/pages/home/view/home_page_mobile.dart | 112 +-- .../responsive_layout_helper.dart | 5 + 10 files changed, 471 insertions(+), 507 deletions(-) diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index 2f5deb6d..26a1dcc2 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -26,6 +26,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { Widget build(BuildContext context) { final isLargeScreen = isLargeScreenSize(context); final isSmallScreen = isSmallScreenSize(context); + final isHalfMediumScreen = isHafMediumScreenSize(context); final padding = isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15); @@ -72,7 +73,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { }, ), const SizedBox(height: 20), - if (isSmallScreen) + if (isSmallScreen || isHalfMediumScreen) _buildSmallSearchFilters(context, accessBloc) else _buildNormalSearchWidgets(context, accessBloc), @@ -120,7 +121,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { children: [ Container( width: 205, - height: 35, + height: 42, decoration: containerDecoration, child: DefaultButton( onPressed: () { @@ -145,7 +146,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { ), Container( width: 133, - height: 35, + height: 42, decoration: containerDecoration, child: DefaultButton( borderRadius: 8, @@ -167,10 +168,10 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { textBaseline: TextBaseline.ideographic, children: [ SizedBox( - width: MediaQuery.of(context).size.width * 0.15, + width: 250, child: CustomWebTextField( controller: accessBloc.passwordName, - height: 36, + height: 38, isRequired: true, textFieldName: 'Name', description: '', @@ -178,6 +179,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { ), const SizedBox(width: 15), SizedBox( + height: 70, child: DateTimeWebWidget( icon: Assets.calendarIcon, isRequired: false, @@ -217,11 +219,11 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { runSpacing: 10, children: [ SizedBox( - width: MediaQuery.of(context).size.width * 0.15, + width: 300, child: CustomWebTextField( controller: accessBloc.passwordName, isRequired: true, - height: 36, + height: 40, textFieldName: 'Name', description: '', ), diff --git a/lib/pages/auth/view/login_web_page.dart b/lib/pages/auth/view/login_web_page.dart index a88aac07..bce74d56 100644 --- a/lib/pages/auth/view/login_web_page.dart +++ b/lib/pages/auth/view/login_web_page.dart @@ -13,6 +13,7 @@ import 'package:syncrow_web/pages/common/first_layer.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/routes_const.dart'; +import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; import 'package:syncrow_web/utils/style.dart'; class LoginWebPage extends StatefulWidget { @@ -22,7 +23,8 @@ class LoginWebPage extends StatefulWidget { State createState() => _LoginWebPageState(); } -class _LoginWebPageState extends State { +class _LoginWebPageState extends State + with HelperResponsiveLayout { @override Widget build(BuildContext context) { return Scaffold( @@ -50,9 +52,12 @@ class _LoginWebPageState extends State { Widget _buildLoginForm(BuildContext context, AuthState state) { final loginBloc = BlocProvider.of(context); + final isSmallScreen = isSmallScreenSize(context); + final isMediumScreen = isMediumScreenSize(context); Size size = MediaQuery.of(context).size; late ScrollController _scrollController; _scrollController = ScrollController(); + void _scrollToCenter() { final double middlePosition = _scrollController.position.maxScrollExtent / 2; @@ -66,6 +71,7 @@ class _LoginWebPageState extends State { WidgetsBinding.instance.addPostFrameCallback((_) { _scrollToCenter(); }); + return Stack( children: [ FirstLayer( @@ -75,451 +81,53 @@ class _LoginWebPageState extends State { shrinkWrap: true, children: [ Container( + width: 400, padding: EdgeInsets.all(size.width * 0.02), - margin: EdgeInsets.all(size.width * 0.09), + margin: EdgeInsets.all(size.width * 0.05), decoration: BoxDecoration( color: Colors.black.withOpacity(0.3), borderRadius: const BorderRadius.all(Radius.circular(20)), ), child: Center( - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Spacer(), - Expanded( - flex: 3, - child: SvgPicture.asset( - Assets.loginLogo, - ), - ), - const Spacer(), - Expanded( - flex: 3, - child: Container( - decoration: BoxDecoration( - color: Colors.white.withOpacity(0.1), - borderRadius: const BorderRadius.all( - Radius.circular(30)), - border: Border.all( - color: ColorsManager.graysColor - .withOpacity(0.2))), - child: Form( - key: loginBloc.loginFormKey, - child: Padding( - padding: EdgeInsets.symmetric( - horizontal: size.width * 0.02, - vertical: size.width * 0.003), - child: Column( - mainAxisAlignment: - MainAxisAlignment.spaceEvenly, - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - const SizedBox(height: 40), - Text('Login', - style: Theme.of(context) - .textTheme - .headlineLarge), - SizedBox(height: size.height * 0.03), - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisAlignment: - MainAxisAlignment.start, - children: [ - Text( - "Country/Region", - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - fontSize: 14, - fontWeight: - FontWeight.w400), - ), - const SizedBox( - height: 10, - ), - SizedBox( - child: DropdownButtonFormField< - String>( - padding: EdgeInsets.zero, - value: loginBloc.regionList! - .any((region) => - region.id == - loginBloc - .regionUuid) - ? loginBloc.regionUuid - : null, - validator: - loginBloc.validateRegion, - icon: const Icon( - Icons - .keyboard_arrow_down_outlined, - ), - decoration: textBoxDecoration()! - .copyWith( - errorStyle: const TextStyle( - height: 0), - hintText: null, - ), - hint: SizedBox( - width: size.width * 0.12, - child: Align( - alignment: - Alignment.centerLeft, - child: Text( - 'Select your region/country', - textAlign: - TextAlign.center, - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - color: - ColorsManager - .grayColor, - fontWeight: - FontWeight - .w400), - overflow: - TextOverflow.ellipsis, - ), - ), - ), - isDense: true, - style: const TextStyle( - color: Colors.black), - items: loginBloc.regionList! - .map((RegionModel region) { - return DropdownMenuItem< - String>( - value: region.id, - child: SizedBox( - width: - size.width * 0.08, - child: - Text(region.name)), - ); - }).toList(), - onChanged: (String? value) { - loginBloc - .add(CheckEnableEvent()); - loginBloc.add( - SelectRegionEvent( - val: value!)); - }, - ), - ) - ], - ), - const SizedBox(height: 20.0), - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisAlignment: - MainAxisAlignment.start, - children: [ - Text( - "Email", - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - fontSize: 14, - fontWeight: - FontWeight.w400), - ), - const SizedBox( - height: 10, - ), - SizedBox( - child: TextFormField( - onChanged: (value) { - loginBloc - .add(CheckEnableEvent()); - }, - validator: loginBloc - .loginValidateEmail, - controller: loginBloc - .loginEmailController, - decoration: textBoxDecoration()! - .copyWith( - errorStyle: const TextStyle( - height: - 0), // Hide the error text space - hintText: - 'Enter your email address', - hintStyle: Theme.of( - context) - .textTheme - .bodySmall! - .copyWith( - color: ColorsManager - .grayColor, - fontWeight: - FontWeight - .w400)), - style: const TextStyle( - color: Colors.black), - ), - ), - ], - ), - const SizedBox(height: 20.0), - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - mainAxisAlignment: - MainAxisAlignment.start, - children: [ - Text( - "Password", - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - fontSize: 14, - fontWeight: - FontWeight.w400), - ), - const SizedBox( - height: 10, - ), - SizedBox( - child: TextFormField( - onChanged: (value) { - loginBloc - .add(CheckEnableEvent()); - }, - validator: - loginBloc.validatePassword, - obscureText: - loginBloc.obscureText, - keyboardType: TextInputType - .visiblePassword, - controller: loginBloc - .loginPasswordController, - decoration: textBoxDecoration()! - .copyWith( - hintText: - 'At least 8 characters', - hintStyle: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - color: ColorsManager - .grayColor, - fontWeight: - FontWeight.w400), - suffixIcon: IconButton( - onPressed: () { - loginBloc.add( - PasswordVisibleEvent( - newValue: loginBloc - .obscureText)); - }, - icon: SizedBox( - child: SvgPicture.asset( - loginBloc.obscureText - ? Assets - .visiblePassword - : Assets - .invisiblePassword, - height: 15, - width: 15, - ), - ), - ), - errorStyle: const TextStyle( - height: - 0), // Hide the error text space - ), - style: const TextStyle( - color: Colors.black), - ), - ), - ], - ), - const SizedBox( - height: 20, - ), - SizedBox( - child: Row( - mainAxisAlignment: - MainAxisAlignment.end, - children: [ - InkWell( - onTap: () { - Navigator.of(context) - .push(MaterialPageRoute( - builder: (context) => - const ForgetPasswordPage(), - )); - }, - child: Text( - "Forgot Password?", - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - color: Colors.black, - fontSize: 14, - fontWeight: - FontWeight.w400), - ), - ), - ], - ), - ), - const SizedBox( - height: 20, - ), - Row( - children: [ - Transform.scale( - scale: - 1.2, // Adjust the scale as needed - child: Checkbox( - fillColor: MaterialStateProperty - .all(Colors.white), - activeColor: Colors.white, - value: loginBloc.isChecked, - checkColor: Colors.black, - shape: const CircleBorder(), - onChanged: (bool? newValue) { - loginBloc.add(CheckBoxEvent( - newValue: newValue)); - }, - ), - ), - SizedBox( - width: size.width * 0.14, - child: RichText( - text: TextSpan( - text: 'Agree to ', - style: const TextStyle( - color: Colors.white), - children: [ - TextSpan( - text: - '(Terms of Service)', - style: const TextStyle( - color: Colors.black, - ), - recognizer: - TapGestureRecognizer() - ..onTap = () { - loginBloc.launchURL( - 'https://example.com/terms'); - }, - ), - TextSpan( - text: - ' (Legal Statement)', - style: const TextStyle( - color: Colors.black), - recognizer: - TapGestureRecognizer() - ..onTap = () { - loginBloc.launchURL( - 'https://example.com/legal'); - }, - ), - TextSpan( - text: - ' (Privacy Statement)', - style: const TextStyle( - color: Colors.black), - recognizer: - TapGestureRecognizer() - ..onTap = () { - loginBloc.launchURL( - 'https://example.com/privacy'); - }, - ), - ], - ), - ), - ), - ], - ), - const SizedBox(height: 20.0), - Row( - crossAxisAlignment: - CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - SizedBox( - width: size.width * 0.2, - child: DefaultButton( - enabled: - loginBloc.checkValidate, - child: Text('Sign in', - style: Theme.of(context) - .textTheme - .labelLarge! - .copyWith( - fontSize: 14, - color: loginBloc - .checkValidate - ? ColorsManager - .whiteColors - : ColorsManager - .whiteColors - .withOpacity( - 0.2), - )), - onPressed: () { - if (loginBloc.loginFormKey - .currentState! - .validate()) { - loginBloc - .add(LoginButtonPressed( - regionUuid: - loginBloc.regionUuid, - username: loginBloc - .loginEmailController - .text, - password: loginBloc - .loginPasswordController - .text, - )); - } else { - loginBloc.add( - ChangeValidateEvent()); - } - }, - ), - ), - ], - ), - const SizedBox(height: 15.0), - Row( - crossAxisAlignment: - CrossAxisAlignment.center, - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - SizedBox( - child: Text( - loginBloc.validate, - style: const TextStyle( - fontWeight: FontWeight.w700, - color: ColorsManager.red), - ), - ) - ], - ) - ], - ), + child: isSmallScreen || isMediumScreen + ? SizedBox( + width: 400, + child: Column( + // For small screens + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + width: 300, + child: SvgPicture.asset( + Assets.loginLogo, ), - ))), - const Spacer(), - ], - ), + ), + const SizedBox(height: 20), + _buildLoginFormFields(context, loginBloc, size), + ], + ), + ) + : Row( + // For larger screens + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Spacer(), + Expanded( + flex: 1, + child: SvgPicture.asset( + Assets.loginLogo, + ), + ), + const Spacer(), + Expanded( + flex: 3, + child: _buildLoginFormFields( + context, loginBloc, size), + ), + const Spacer(), + ], + ), ), ), ], @@ -531,4 +139,341 @@ class _LoginWebPageState extends State { ], ); } + + Widget _buildLoginFormFields( + BuildContext context, AuthBloc loginBloc, Size size) { + return Container( + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.1), + borderRadius: const BorderRadius.all(Radius.circular(30)), + border: Border.all(color: ColorsManager.graysColor.withOpacity(0.2)), + ), + child: Form( + key: loginBloc.loginFormKey, + child: Padding( + padding: EdgeInsets.symmetric( + horizontal: size.width * 0.02, vertical: size.width * 0.003), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 40), + Text('Login', style: Theme.of(context).textTheme.headlineLarge), + SizedBox(height: size.height * 0.03), + _buildDropdownField(context, loginBloc, size), + const SizedBox(height: 20.0), + _buildEmailField(context, loginBloc), + const SizedBox(height: 20.0), + _buildPasswordField(context, loginBloc), + const SizedBox(height: 20), + _buildForgotPassword(context), + const SizedBox(height: 20), + _buildCheckbox(context, loginBloc, size), + const SizedBox(height: 20.0), + _buildSignInButton(context, loginBloc, size), + const SizedBox(height: 15.0), + _buildValidationMessage(loginBloc), + ], + ), + ), + ), + ); + } + + Widget _buildDropdownField( + BuildContext context, AuthBloc loginBloc, Size size) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "Country/Region", + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith(fontSize: 14, fontWeight: FontWeight.w400), + ), + const SizedBox(height: 10), + SizedBox( + width: size.width * 0.8, + child: LayoutBuilder( + builder: (context, constraints) { + return DropdownButtonFormField( + value: loginBloc.regionList! + .any((region) => region.id == loginBloc.regionUuid) + ? loginBloc.regionUuid + : null, + validator: loginBloc.validateRegion, + icon: const Icon( + Icons.keyboard_arrow_down_outlined, + size: 20, + ), + decoration: textBoxDecoration()!.copyWith( + errorStyle: const TextStyle(height: 0), + contentPadding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 10, + ), + ), + hint: Text( + 'Select your region/country', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor, + fontWeight: FontWeight.w400), + overflow: TextOverflow.ellipsis, + ), + isDense: true, + style: const TextStyle(color: Colors.black), + items: loginBloc.regionList!.map((RegionModel region) { + return DropdownMenuItem( + value: region.id, + child: Container( + constraints: + BoxConstraints(maxWidth: constraints.maxWidth - 40), + child: Text( + region.name, + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + ), + ); + }).toList(), + onChanged: (String? value) { + loginBloc.add(CheckEnableEvent()); + loginBloc.add(SelectRegionEvent(val: value!)); + }, + dropdownColor: Colors.white, + menuMaxHeight: size.height * 0.45, + selectedItemBuilder: (context) { + return loginBloc.regionList!.map((region) { + return Container( + constraints: + BoxConstraints(maxWidth: constraints.maxWidth - 40), + child: Text( + region.name, + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + ); + }).toList(); + }, + ); + }, + ), + ), + ], + ); + } + + Widget _buildEmailField(BuildContext context, AuthBloc loginBloc) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "Email", + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith(fontSize: 14, fontWeight: FontWeight.w400), + ), + const SizedBox(height: 10), + SizedBox( + child: TextFormField( + onChanged: (value) { + loginBloc.add(CheckEnableEvent()); + }, + validator: loginBloc.loginValidateEmail, + controller: loginBloc.loginEmailController, + decoration: textBoxDecoration()!.copyWith( + errorStyle: const TextStyle(height: 0), + hintText: 'Enter your email address', + hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor, + fontWeight: FontWeight.w400)), + style: const TextStyle(color: Colors.black), + ), + ), + ], + ); + } + + Widget _buildPasswordField(BuildContext context, AuthBloc loginBloc) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "Password", + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith(fontSize: 14, fontWeight: FontWeight.w400), + ), + const SizedBox(height: 10), + SizedBox( + child: TextFormField( + onChanged: (value) { + loginBloc.add(CheckEnableEvent()); + }, + validator: loginBloc.validatePassword, + obscureText: loginBloc.obscureText, + keyboardType: TextInputType.visiblePassword, + controller: loginBloc.loginPasswordController, + decoration: textBoxDecoration()!.copyWith( + hintText: 'At least 8 characters', + hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor, fontWeight: FontWeight.w400), + suffixIcon: IconButton( + onPressed: () { + loginBloc.add( + PasswordVisibleEvent(newValue: loginBloc.obscureText)); + }, + icon: SizedBox( + child: SvgPicture.asset( + loginBloc.obscureText + ? Assets.visiblePassword + : Assets.invisiblePassword, + height: 15, + width: 15, + ), + ), + ), + errorStyle: const TextStyle(height: 0), + ), + style: const TextStyle(color: Colors.black), + ), + ), + ], + ); + } + + Widget _buildForgotPassword(BuildContext context) { + return SizedBox( + child: Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + InkWell( + onTap: () { + Navigator.of(context).push(MaterialPageRoute( + builder: (context) => const ForgetPasswordPage(), + )); + }, + child: Text( + "Forgot Password?", + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Colors.black, + fontSize: 14, + fontWeight: FontWeight.w400), + ), + ), + ], + ), + ); + } + + Widget _buildCheckbox(BuildContext context, AuthBloc loginBloc, Size size) { + return Row( + children: [ + Transform.scale( + scale: 1.2, + child: Checkbox( + fillColor: MaterialStateProperty.all(Colors.white), + activeColor: Colors.white, + value: loginBloc.isChecked, + checkColor: Colors.black, + shape: const CircleBorder(), + onChanged: (bool? newValue) { + loginBloc.add(CheckBoxEvent(newValue: newValue)); + }, + ), + ), + SizedBox( + width: 220, + child: RichText( + text: TextSpan( + text: 'Agree to ', + style: const TextStyle(color: Colors.white), + children: [ + TextSpan( + text: '(Terms of Service)', + style: const TextStyle(color: Colors.black), + recognizer: TapGestureRecognizer() + ..onTap = () { + loginBloc.launchURL('https://example.com/terms'); + }, + ), + TextSpan( + text: ' (Legal Statement)', + style: const TextStyle(color: Colors.black), + recognizer: TapGestureRecognizer() + ..onTap = () { + loginBloc.launchURL('https://example.com/legal'); + }, + ), + TextSpan( + text: ' (Privacy Statement)', + style: const TextStyle(color: Colors.black), + recognizer: TapGestureRecognizer() + ..onTap = () { + loginBloc.launchURL('https://example.com/privacy'); + }, + ), + ], + ), + ), + ), + ], + ); + } + + Widget _buildSignInButton( + BuildContext context, AuthBloc loginBloc, Size size) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + width: size.width * 0.2, + child: DefaultButton( + enabled: loginBloc.checkValidate, + child: Text('Sign in', + style: Theme.of(context).textTheme.labelLarge!.copyWith( + fontSize: 14, + color: loginBloc.checkValidate + ? ColorsManager.whiteColors + : ColorsManager.whiteColors.withOpacity(0.2), + )), + onPressed: () { + if (loginBloc.loginFormKey.currentState!.validate()) { + loginBloc.add(LoginButtonPressed( + regionUuid: loginBloc.regionUuid, + username: loginBloc.loginEmailController.text, + password: loginBloc.loginPasswordController.text, + )); + } else { + loginBloc.add(ChangeValidateEvent()); + } + }, + ), + ), + ], + ); + } + + Widget _buildValidationMessage(AuthBloc loginBloc) { + return Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + child: Text( + loginBloc.validate, + style: const TextStyle( + fontWeight: FontWeight.w700, color: ColorsManager.red), + ), + ) + ], + ); + } } diff --git a/lib/pages/common/buttons/search_reset_buttons.dart b/lib/pages/common/buttons/search_reset_buttons.dart index cdb09c21..7b63a485 100644 --- a/lib/pages/common/buttons/search_reset_buttons.dart +++ b/lib/pages/common/buttons/search_reset_buttons.dart @@ -24,7 +24,7 @@ class SearchResetButtons extends StatelessWidget { const SizedBox(height: 25), Center( child: Container( - height: 35, + height: 42, width: 100, decoration: containerDecoration, child: Center( @@ -49,7 +49,7 @@ class SearchResetButtons extends StatelessWidget { const SizedBox(height: 25), Center( child: Container( - height: 35, + height: 42, width: 100, decoration: containerDecoration, child: Center( diff --git a/lib/pages/common/date_time_widget.dart b/lib/pages/common/date_time_widget.dart index 824ab382..0965377e 100644 --- a/lib/pages/common/date_time_widget.dart +++ b/lib/pages/common/date_time_widget.dart @@ -54,7 +54,7 @@ class DateTimeWebWidget extends StatelessWidget { height: 8, ), Container( - height: size.height * 0.056, + // height: size.height * 0.056, padding: const EdgeInsets.only(top: 10, bottom: 10, right: 30, left: 10), decoration: containerDecoration, diff --git a/lib/pages/common/filter/filter_widget.dart b/lib/pages/common/filter/filter_widget.dart index d6cfcc7e..1af23045 100644 --- a/lib/pages/common/filter/filter_widget.dart +++ b/lib/pages/common/filter/filter_widget.dart @@ -20,7 +20,7 @@ class FilterWidget extends StatelessWidget { Widget build(BuildContext context) { return Container( decoration: containerDecoration, - height: size.height * 0.05, + height: 40, child: ListView.builder( scrollDirection: Axis.horizontal, itemCount: tabs.length, diff --git a/lib/pages/common/text_field/custom_text_field.dart b/lib/pages/common/text_field/custom_text_field.dart index 2c29762c..f54d3991 100644 --- a/lib/pages/common/text_field/custom_text_field.dart +++ b/lib/pages/common/text_field/custom_text_field.dart @@ -60,7 +60,7 @@ class CustomTextField extends StatelessWidget { title, style: context.textTheme.bodyMedium!.copyWith( fontSize: 13, - fontWeight: FontWeight.w400, + fontWeight: FontWeight.w600, color: const Color(0xff000000), ), ), diff --git a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart index d1ee0fed..2e9d916a 100644 --- a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart +++ b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart @@ -75,7 +75,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { const DeviceSearchFilters(), const SizedBox(height: 12), Container( - height: 35, + height: 45, width: 100, decoration: containerDecoration, child: Center( diff --git a/lib/pages/home/view/home_page.dart b/lib/pages/home/view/home_page.dart index 6217122b..9159011f 100644 --- a/lib/pages/home/view/home_page.dart +++ b/lib/pages/home/view/home_page.dart @@ -1,13 +1,17 @@ import 'package:flutter/cupertino.dart'; import 'package:syncrow_web/pages/home/view/home_page_mobile.dart'; import 'package:syncrow_web/pages/home/view/home_page_web.dart'; -import 'package:syncrow_web/utils/responsive_layout.dart'; +import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; -class HomePage extends StatelessWidget { +class HomePage extends StatelessWidget with HelperResponsiveLayout { const HomePage({super.key}); @override Widget build(BuildContext context) { - return ResponsiveLayout(desktopBody: const HomeWebPage(), mobileBody: HomeMobilePage()); + final isSmallScreen = isSmallScreenSize(context); + final isMediumScreen = isMediumScreenSize(context); + return isSmallScreen || isMediumScreen + ? HomeMobilePage() + : const HomeWebPage(); } } diff --git a/lib/pages/home/view/home_page_mobile.dart b/lib/pages/home/view/home_page_mobile.dart index ccf506e1..c0abdfe3 100644 --- a/lib/pages/home/view/home_page_mobile.dart +++ b/lib/pages/home/view/home_page_mobile.dart @@ -13,61 +13,69 @@ class HomeMobilePage extends StatelessWidget { @override Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; - return WebScaffold( - enableMenuSideba: false, - appBarTitle: Row( - children: [ - SvgPicture.asset( - Assets.loginLogo, - width: 150, - ), - ], - ), - scaffoldBody: BlocConsumer( - listener: (context, state) {}, - builder: (context, state) { - return SizedBox( - height: size.height, - width: size.width, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SizedBox(height: size.height * 0.05), - const Text( - 'ACCESS YOUR APPS', - style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700), - ), - const SizedBox(height: 30), - Expanded( - flex: 4, - child: SizedBox( - height: size.height * 0.6, - width: size.width * 0.68, - child: GridView.builder( - itemCount: 8, - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - crossAxisSpacing: 20.0, - mainAxisSpacing: 20.0, - childAspectRatio: 1.5, + return PopScope( + canPop: false, + onPopInvoked: (didPop) => false, + child: WebScaffold( + enableMenuSideba: false, + appBarTitle: Row( + children: [ + SvgPicture.asset( + Assets.loginLogo, + width: 150, + ), + ], + ), + scaffoldBody: BlocConsumer( + listener: (context, state) {}, + builder: (context, state) { + final homeBloc = BlocProvider.of(context); + return SizedBox( + height: size.height, + width: size.width, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox(height: size.height * 0.05), + const Text( + 'ACCESS YOUR APPS', + style: + TextStyle(fontSize: 20, fontWeight: FontWeight.w700), + ), + const SizedBox(height: 30), + Expanded( + flex: 4, + child: SizedBox( + height: size.height * 0.6, + width: size.width * 0.68, + child: GridView.builder( + itemCount: 8, + gridDelegate: + const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + crossAxisSpacing: 20.0, + mainAxisSpacing: 20.0, + childAspectRatio: 1.5, + ), + itemBuilder: (context, index) { + return HomeCard( + index: index, + active: homeItems[index]['active'], + name: homeItems[index]['title'], + img: homeItems[index]['icon'], + onTap: () => + homeBloc.homeItems[index].onPress(context), + ); + }, ), - itemBuilder: (context, index) { - return HomeCard( - index: index, - active: homeItems[index]['active'], - name: homeItems[index]['title'], - img: homeItems[index]['icon'], - onTap: () {}, - ); - }, ), ), - ), - ], - ), - ); - }), + ], + ), + ); + }), + ), ); } diff --git a/lib/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart b/lib/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart index ba11583c..0d793aa6 100644 --- a/lib/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart +++ b/lib/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart @@ -10,6 +10,11 @@ mixin HelperResponsiveLayout { MediaQuery.of(context).size.width < 1024; } + bool isHafMediumScreenSize(BuildContext context) { + return MediaQuery.of(context).size.width >= 600 / 1.3 && + MediaQuery.of(context).size.width < 1024 / 1.3; + } + bool isLargeScreenSize(BuildContext context) { return MediaQuery.of(context).size.width >= 1024 && MediaQuery.of(context).size.width < 1440; From 3287e43a5f97f29f865f9ab2b0a40ac68bc37ab3 Mon Sep 17 00:00:00 2001 From: Abdullah Alassaf Date: Sun, 1 Sep 2024 09:49:24 +0300 Subject: [PATCH 007/158] Fixed login design --- lib/pages/auth/view/login_web_page.dart | 76 +++++++--------- lib/pages/home/view/home_page_web.dart | 115 ++++++++++++------------ 2 files changed, 91 insertions(+), 100 deletions(-) diff --git a/lib/pages/auth/view/login_web_page.dart b/lib/pages/auth/view/login_web_page.dart index bce74d56..1c638287 100644 --- a/lib/pages/auth/view/login_web_page.dart +++ b/lib/pages/auth/view/login_web_page.dart @@ -23,8 +23,7 @@ class LoginWebPage extends StatefulWidget { State createState() => _LoginWebPageState(); } -class _LoginWebPageState extends State - with HelperResponsiveLayout { +class _LoginWebPageState extends State with HelperResponsiveLayout { @override Widget build(BuildContext context) { return Scaffold( @@ -59,8 +58,7 @@ class _LoginWebPageState extends State _scrollController = ScrollController(); void _scrollToCenter() { - final double middlePosition = - _scrollController.position.maxScrollExtent / 2; + final double middlePosition = _scrollController.position.maxScrollExtent / 2; _scrollController.animateTo( middlePosition, duration: const Duration(seconds: 1), @@ -114,16 +112,15 @@ class _LoginWebPageState extends State children: [ const Spacer(), Expanded( - flex: 1, + flex: 2, child: SvgPicture.asset( Assets.loginLogo, ), ), const Spacer(), Expanded( - flex: 3, - child: _buildLoginFormFields( - context, loginBloc, size), + flex: 2, + child: _buildLoginFormFields(context, loginBloc, size), ), const Spacer(), ], @@ -134,14 +131,12 @@ class _LoginWebPageState extends State ), ), ), - if (state is AuthLoading) - const Center(child: CircularProgressIndicator()) + if (state is AuthLoading) const Center(child: CircularProgressIndicator()) ], ); } - Widget _buildLoginFormFields( - BuildContext context, AuthBloc loginBloc, Size size) { + Widget _buildLoginFormFields(BuildContext context, AuthBloc loginBloc, Size size) { return Container( decoration: BoxDecoration( color: Colors.white.withOpacity(0.1), @@ -151,8 +146,8 @@ class _LoginWebPageState extends State child: Form( key: loginBloc.loginFormKey, child: Padding( - padding: EdgeInsets.symmetric( - horizontal: size.width * 0.02, vertical: size.width * 0.003), + padding: + EdgeInsets.symmetric(horizontal: size.width * 0.02, vertical: size.width * 0.003), child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.start, @@ -180,8 +175,7 @@ class _LoginWebPageState extends State ); } - Widget _buildDropdownField( - BuildContext context, AuthBloc loginBloc, Size size) { + Widget _buildDropdownField(BuildContext context, AuthBloc loginBloc, Size size) { return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, @@ -199,8 +193,7 @@ class _LoginWebPageState extends State child: LayoutBuilder( builder: (context, constraints) { return DropdownButtonFormField( - value: loginBloc.regionList! - .any((region) => region.id == loginBloc.regionUuid) + value: loginBloc.regionList!.any((region) => region.id == loginBloc.regionUuid) ? loginBloc.regionUuid : null, validator: loginBloc.validateRegion, @@ -217,9 +210,10 @@ class _LoginWebPageState extends State ), hint: Text( 'Select your region/country', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: ColorsManager.grayColor, - fontWeight: FontWeight.w400), + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith(color: ColorsManager.grayColor, fontWeight: FontWeight.w400), overflow: TextOverflow.ellipsis, ), isDense: true, @@ -228,8 +222,7 @@ class _LoginWebPageState extends State return DropdownMenuItem( value: region.id, child: Container( - constraints: - BoxConstraints(maxWidth: constraints.maxWidth - 40), + constraints: BoxConstraints(maxWidth: constraints.maxWidth - 40), child: Text( region.name, overflow: TextOverflow.ellipsis, @@ -247,8 +240,7 @@ class _LoginWebPageState extends State selectedItemBuilder: (context) { return loginBloc.regionList!.map((region) { return Container( - constraints: - BoxConstraints(maxWidth: constraints.maxWidth - 40), + constraints: BoxConstraints(maxWidth: constraints.maxWidth - 40), child: Text( region.name, overflow: TextOverflow.ellipsis, @@ -288,9 +280,10 @@ class _LoginWebPageState extends State decoration: textBoxDecoration()!.copyWith( errorStyle: const TextStyle(height: 0), hintText: 'Enter your email address', - 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)), style: const TextStyle(color: Colors.black), ), ), @@ -322,18 +315,17 @@ class _LoginWebPageState extends State controller: loginBloc.loginPasswordController, decoration: textBoxDecoration()!.copyWith( hintText: 'At least 8 characters', - 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: IconButton( onPressed: () { - loginBloc.add( - PasswordVisibleEvent(newValue: loginBloc.obscureText)); + loginBloc.add(PasswordVisibleEvent(newValue: loginBloc.obscureText)); }, icon: SizedBox( child: SvgPicture.asset( - loginBloc.obscureText - ? Assets.visiblePassword - : Assets.invisiblePassword, + loginBloc.obscureText ? Assets.visiblePassword : Assets.invisiblePassword, height: 15, width: 15, ), @@ -361,10 +353,10 @@ class _LoginWebPageState extends State }, child: Text( "Forgot Password?", - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: Colors.black, - fontSize: 14, - fontWeight: FontWeight.w400), + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith(color: Colors.black, fontSize: 14, fontWeight: FontWeight.w400), ), ), ], @@ -427,8 +419,7 @@ class _LoginWebPageState extends State ); } - Widget _buildSignInButton( - BuildContext context, AuthBloc loginBloc, Size size) { + Widget _buildSignInButton(BuildContext context, AuthBloc loginBloc, Size size) { return Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, @@ -469,8 +460,7 @@ class _LoginWebPageState extends State SizedBox( child: Text( loginBloc.validate, - style: const TextStyle( - fontWeight: FontWeight.w700, color: ColorsManager.red), + style: const TextStyle(fontWeight: FontWeight.w700, color: ColorsManager.red), ), ) ], diff --git a/lib/pages/home/view/home_page_web.dart b/lib/pages/home/view/home_page_web.dart index af59d70e..c1fc54f9 100644 --- a/lib/pages/home/view/home_page_web.dart +++ b/lib/pages/home/view/home_page_web.dart @@ -15,65 +15,66 @@ class HomeWebPage extends StatelessWidget { return PopScope( canPop: false, onPopInvoked: (didPop) => false, - child: WebScaffold( - enableMenuSideba: false, - appBarTitle: Row( - children: [ - SvgPicture.asset( - Assets.loginLogo, - width: 150, - ), - ], - ), - scaffoldBody: BlocConsumer( - listener: (BuildContext context, state) {}, - builder: (context, state) { - final homeBloc = BlocProvider.of(context); - return SizedBox( - height: size.height, - width: size.width, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - SizedBox(height: size.height * 0.1), - Text( - 'ACCESS YOUR APPS', - style: Theme.of(context) - .textTheme - .headlineLarge! - .copyWith(color: Colors.black, fontSize: 40), - ), - const SizedBox(height: 30), - Expanded( - flex: 4, - child: SizedBox( - height: size.height * 0.6, - width: size.width * 0.68, - child: GridView.builder( - itemCount: 8, - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 4, - crossAxisSpacing: 20.0, - mainAxisSpacing: 20.0, - childAspectRatio: 1.5, - ), - itemBuilder: (context, index) { - return HomeCard( - index: index, - active: homeBloc.homeItems[index].active!, - name: homeBloc.homeItems[index].title!, - img: homeBloc.homeItems[index].icon!, - onTap: () => homeBloc.homeItems[index].onPress(context), - ); - }, + child: BlocConsumer( + listener: (BuildContext context, state) {}, + builder: (context, state) { + final homeBloc = BlocProvider.of(context); + return WebScaffold( + enableMenuSideba: false, + appBarTitle: Row( + children: [ + SvgPicture.asset( + Assets.loginLogo, + width: 150, + ), + ], + ), + scaffoldBody: SizedBox( + height: size.height, + width: size.width, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox(height: size.height * 0.1), + Text( + 'ACCESS YOUR APPS', + style: Theme.of(context) + .textTheme + .headlineLarge! + .copyWith(color: Colors.black, fontSize: 40), + ), + const SizedBox(height: 30), + Expanded( + flex: 4, + child: SizedBox( + height: size.height * 0.6, + width: size.width * 0.68, + child: GridView.builder( + itemCount: 8, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + crossAxisSpacing: 20.0, + mainAxisSpacing: 20.0, + childAspectRatio: 1.5, ), + itemBuilder: (context, index) { + return HomeCard( + index: index, + active: homeBloc.homeItems[index].active!, + name: homeBloc.homeItems[index].title!, + img: homeBloc.homeItems[index].icon!, + onTap: () => homeBloc.homeItems[index].onPress(context), + ); + }, ), ), - ], - ), - ); - }, - ))); + ), + ], + ), + ), + ); + }, + )); } } From ddcdd4891a2590c76431bbbafe3d2262a36e5cfd Mon Sep 17 00:00:00 2001 From: mohammad Date: Mon, 2 Sep 2024 10:16:28 +0300 Subject: [PATCH 008/158] forget password changes & bugs number 10 & 15-18 --- lib/main.dart | 4 +- .../view/access_management.dart | 31 ++++-- lib/pages/auth/bloc/auth_bloc.dart | 45 ++++---- .../auth/view/forget_password_web_page.dart | 17 +-- lib/pages/common/custom_table.dart | 16 ++- .../text_field/custom_web_textfield.dart | 20 ++-- .../widgets/device_managment_body.dart | 105 +++++++++--------- lib/pages/home/bloc/home_bloc.dart | 1 + .../view/add_device_dialog.dart | 78 ++++++------- .../view/visitor_password_dialog.dart | 5 +- lib/services/auth_api.dart | 17 +-- lib/services/home_api.dart | 1 + 12 files changed, 180 insertions(+), 160 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index b4fcb72d..6e2531a7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -38,6 +38,7 @@ class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { + HomeBloc.fetchUserInfo(); return MultiBlocProvider( providers: [ BlocProvider(create: (context) => HomeBloc()), @@ -57,6 +58,7 @@ class MyApp extends StatelessWidget { ), theme: myTheme, routerConfig: _router, - )); + ) + ); } } diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index 26a1dcc2..19c29643 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -38,12 +38,22 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { style: Theme.of(context).textTheme.headlineLarge, ), ), - centerBody: Text( - 'Physical Access', - style: Theme.of(context) - .textTheme - .headlineMedium! - .copyWith(color: Colors.white), + centerBody: Wrap( + children: [ + Padding( + padding: EdgeInsets.only(left: MediaQuery.of(context).size.width*0.09), + child: Align( + alignment: Alignment.bottomLeft, + child: Text( + 'Physical Access', + style: Theme.of(context) + .textTheme + .headlineMedium! + .copyWith(color: Colors.white), + ), + ), + ), + ], ), rightBody: const NavigateHomeGridView(), scaffoldBody: BlocProvider( @@ -82,6 +92,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { const SizedBox(height: 20), Expanded( child: DynamicTable( + withSelectAll: false, isEmpty: filteredData.isEmpty, withCheckBox: false, size: MediaQuery.of(context).size, @@ -113,8 +124,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { }))); } - Wrap _buildVisitorAdminPasswords( - BuildContext context, AccessBloc accessBloc) { + Wrap _buildVisitorAdminPasswords(BuildContext context, AccessBloc accessBloc) { return Wrap( spacing: 10, runSpacing: 10, @@ -171,15 +181,14 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { width: 250, child: CustomWebTextField( controller: accessBloc.passwordName, - height: 38, - isRequired: true, + height: 43, + isRequired: false, textFieldName: 'Name', description: '', ), ), const SizedBox(width: 15), SizedBox( - height: 70, child: DateTimeWebWidget( icon: Assets.calendarIcon, isRequired: false, diff --git a/lib/pages/auth/bloc/auth_bloc.dart b/lib/pages/auth/bloc/auth_bloc.dart index a08cd0d3..455fc324 100644 --- a/lib/pages/auth/bloc/auth_bloc.dart +++ b/lib/pages/auth/bloc/auth_bloc.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; @@ -81,21 +82,25 @@ class AuthBloc extends Bloc { _timer?.cancel(); emit(const TimerState(isButtonEnabled: true, remainingTime: 0)); emit(SuccessForgetState()); - } else if (response == "You entered wrong otp") { - forgetValidate = 'Wrong one time password.'; - emit(AuthInitialState()); - } else if (response == "OTP expired") { - forgetValidate = 'One time password has been expired.'; - emit(AuthInitialState()); } - } catch (failure) { - // forgetValidate='Invalid Credentials!'; - emit(AuthInitialState()); - // emit(FailureForgetState(error: failure.toString())); } + on DioException catch (e) { + final errorData = e.response!.data; + String errorMessage = errorData['message']; + if(errorMessage=='this email is not registered'){ + validate='Invalid Credentials!'; + emit(AuthInitialState()); + }else if (errorMessage == "You entered wrong otp") { + forgetValidate = 'Wrong one time password.'; + emit(AuthInitialState()); + } else if (errorMessage == "OTP expired") { + forgetValidate = 'One time password has been expired.'; + emit(AuthInitialState()); + } + + } } -//925207 String? validateCode(String? value) { if (value == null || value.isEmpty) { return 'Code is required'; @@ -177,15 +182,15 @@ class AuthBloc extends Bloc { emit(LoginInitial()); } - checkOtpCode( - ChangePasswordEvent event, - Emitter emit, - ) async { - emit(LoadingForgetState()); - await AuthenticationAPI.verifyOtp( - email: forgetEmailController.text, otpCode: forgetOtp.text); - emit(SuccessForgetState()); - } + // checkOtpCode( + // ChangePasswordEvent event, + // Emitter emit, + // ) async { + // emit(LoadingForgetState()); + // await AuthenticationAPI.verifyOtp( + // email: forgetEmailController.text, otpCode: forgetOtp.text); + // emit(SuccessForgetState()); + // } void _passwordVisible(PasswordVisibleEvent event, Emitter emit) { emit(AuthLoading()); diff --git a/lib/pages/auth/view/forget_password_web_page.dart b/lib/pages/auth/view/forget_password_web_page.dart index 907569ee..dd930779 100644 --- a/lib/pages/auth/view/forget_password_web_page.dart +++ b/lib/pages/auth/view/forget_password_web_page.dart @@ -346,8 +346,7 @@ class ForgetPasswordWebPage extends StatelessWidget { if (forgetBloc .forgetFormKey.currentState! .validate()) { - forgetBloc - .add(ChangePasswordEvent()); + forgetBloc.add(ChangePasswordEvent()); } }, ), @@ -355,12 +354,14 @@ class ForgetPasswordWebPage extends StatelessWidget { ], ), const SizedBox(height: 10.0), - SizedBox( - child: Text( - forgetBloc.validate, - style: const TextStyle( - fontWeight: FontWeight.w700, - color: ColorsManager.red), + Center( + child: SizedBox( + child: Text( + forgetBloc.validate, + style: const TextStyle( + fontWeight: FontWeight.w700, + color: ColorsManager.red), + ), ), ), SizedBox( diff --git a/lib/pages/common/custom_table.dart b/lib/pages/common/custom_table.dart index 5308e450..281a3bbb 100644 --- a/lib/pages/common/custom_table.dart +++ b/lib/pages/common/custom_table.dart @@ -10,6 +10,7 @@ class DynamicTable extends StatefulWidget { final BoxDecoration? cellDecoration; final Size size; final bool withCheckBox; + final bool withSelectAll; final bool isEmpty; final void Function(bool?)? selectAll; final void Function(int, bool, dynamic)? onRowSelected; @@ -21,6 +22,7 @@ class DynamicTable extends StatefulWidget { required this.size, required this.isEmpty, required this.withCheckBox, + required this.withSelectAll, this.headerDecoration, this.cellDecoration, this.selectAll, @@ -34,6 +36,7 @@ class DynamicTable extends StatefulWidget { class _DynamicTableState extends State { late List _selected; + bool _selectAll = false; @override void initState() { @@ -54,6 +57,17 @@ class _DynamicTableState extends State { }); } + + void _toggleSelectAll(bool? value) { + setState(() { + _selectAll = value ?? false; + _selected = List.filled(widget.data.length, _selectAll); + if (widget.selectAll != null) { + widget.selectAll!(_selectAll); + } + }); + } + @override Widget build(BuildContext context) { return Container( @@ -148,7 +162,7 @@ class _DynamicTableState extends State { ), child: Checkbox( value: _selected.every((element) => element == true), - onChanged: null, + onChanged:widget.withSelectAll?_toggleSelectAll:null, ), ); } diff --git a/lib/pages/common/text_field/custom_web_textfield.dart b/lib/pages/common/text_field/custom_web_textfield.dart index 926a20f5..756463e2 100644 --- a/lib/pages/common/text_field/custom_web_textfield.dart +++ b/lib/pages/common/text_field/custom_web_textfield.dart @@ -32,21 +32,19 @@ class CustomWebTextField extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - if (isRequired) + Row( children: [ - Text( - '* ', + if (isRequired) + Text('* ', style: Theme.of(context) - .textTheme - .bodyMedium! + .textTheme.bodyMedium! .copyWith(color: Colors.red), ), Text( textFieldName, style: Theme.of(context) - .textTheme - .bodySmall! + .textTheme.bodySmall! .copyWith(color: Colors.black, fontSize: 13), ), ], @@ -70,15 +68,17 @@ class CustomWebTextField extends StatelessWidget { ), Container( height: height ?? 35, - decoration: containerDecoration - .copyWith(color: const Color(0xFFF5F6F7), boxShadow: [ + decoration: containerDecoration.copyWith( + color: const Color(0xFFF5F6F7), + boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.3), spreadRadius: 2, blurRadius: 3, offset: const Offset(1, 1), // changes position of shadow ), - ]), + ] + ), child: TextFormField( validator: validator, controller: controller, diff --git a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart index 2e9d916a..e4eb7966 100644 --- a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart +++ b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart @@ -51,71 +51,68 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { 'Low Battery ($lowBatteryCount)', ]; - return CustomScrollView( - slivers: [ - SliverToBoxAdapter( - child: Container( - padding: isLargeScreenSize(context) - ? const EdgeInsets.all(30) - : const EdgeInsets.all(15), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - FilterWidget( - size: MediaQuery.of(context).size, - tabs: tabs, - selectedIndex: selectedIndex, - onTabChanged: (index) { - context - .read() - .add(SelectedFilterChanged(index)); - }, - ), - const SizedBox(height: 20), - const DeviceSearchFilters(), - const SizedBox(height: 12), - Container( - height: 45, - width: 100, - decoration: containerDecoration, - child: Center( - child: DefaultButton( - onPressed: isControlButtonEnabled - ? () { - final selectedDevice = context - .read() - .selectedDevices - .first; - showDialog( - context: context, - builder: (context) => DeviceControlDialog( - device: selectedDevice), - ); - } - : null, - borderRadius: 9, - child: Text( - 'Control', - style: TextStyle( - fontSize: 12, - color: isControlButtonEnabled - ? Colors.white - : Colors.grey, - ), + return Column( + children: [ + Container( + padding: isLargeScreenSize(context) + ? const EdgeInsets.all(30) + : const EdgeInsets.all(15), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + FilterWidget( + size: MediaQuery.of(context).size, + tabs: tabs, + selectedIndex: selectedIndex, + onTabChanged: (index) { + context.read() + .add(SelectedFilterChanged(index)); + }, + ), + const SizedBox(height: 20), + const DeviceSearchFilters(), + const SizedBox(height: 12), + Container( + height: 45, + width: 100, + decoration: containerDecoration, + child: Center( + child: DefaultButton( + onPressed: isControlButtonEnabled + ? () { + final selectedDevice = context + .read() + .selectedDevices.first; + showDialog( + context: context, + builder: (context) => DeviceControlDialog( + device: selectedDevice), + ); + } + : null, + borderRadius: 9, + child: Text( + 'Control', + style: TextStyle( + fontSize: 12, + color: isControlButtonEnabled + ? Colors.white + : Colors.grey, ), ), ), ), - ], - ), + ), + ], ), ), - SliverFillRemaining( + Expanded( child: Padding( padding: isLargeScreenSize(context) ? const EdgeInsets.all(30) : const EdgeInsets.all(15), child: DynamicTable( + withSelectAll: false, cellDecoration: containerDecoration, onRowSelected: (index, isSelected, row) { final selectedDevice = devicesToShow[index]; diff --git a/lib/pages/home/bloc/home_bloc.dart b/lib/pages/home/bloc/home_bloc.dart index 79579efc..1de54eff 100644 --- a/lib/pages/home/bloc/home_bloc.dart +++ b/lib/pages/home/bloc/home_bloc.dart @@ -43,6 +43,7 @@ class HomeBloc extends Bloc { try { var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey); user = await HomeApi().fetchUserInfo(uuid); + } catch (e) { return; } diff --git a/lib/pages/visitor_password/view/add_device_dialog.dart b/lib/pages/visitor_password/view/add_device_dialog.dart index 85262ff1..3bedbd2f 100644 --- a/lib/pages/visitor_password/view/add_device_dialog.dart +++ b/lib/pages/visitor_password/view/add_device_dialog.dart @@ -40,7 +40,7 @@ class AddDeviceDialog extends StatelessWidget { fontSize: 24, color: Colors.black), ), - content: Container( + content: SizedBox( height: MediaQuery.of(context).size.height / 1.7, width: MediaQuery.of(context).size.width / 2, child: Padding( @@ -78,7 +78,7 @@ class AddDeviceDialog extends StatelessWidget { ), ], )), - SizedBox( + const SizedBox( height: 20, ), const SizedBox( @@ -93,7 +93,7 @@ class AddDeviceDialog extends StatelessWidget { flex: 4, child: CustomWebTextField( controller: visitorBloc.deviceNameController, - isRequired: true, + isRequired: false, textFieldName: 'Device Name', description: '', ), @@ -103,7 +103,7 @@ class AddDeviceDialog extends StatelessWidget { flex: 4, child: CustomWebTextField( controller: visitorBloc.deviceIdController, - isRequired: true, + isRequired: false, textFieldName: 'Device ID', description: '', ), @@ -113,7 +113,7 @@ class AddDeviceDialog extends StatelessWidget { flex: 4, child: CustomWebTextField( controller: visitorBloc.unitNameController, - isRequired: true, + isRequired: false, textFieldName: 'Unit Name', description: '', ), @@ -168,40 +168,40 @@ class AddDeviceDialog extends StatelessWidget { flex: 3, child: state is TableLoaded ? DynamicTable( - initialSelectedIds: selectedDeviceIds, - cellDecoration: containerDecoration, - isEmpty: visitorBloc.data.isEmpty, - selectAll: (p0) { - visitorBloc.selectedDeviceIds.clear(); - for (var item in state.data) { - visitorBloc - .add(SelectDeviceEvent(item.uuid)); - } - }, - onRowSelected: (index, isSelected, row) { - final deviceId = state.data[index].uuid; - visitorBloc.add(SelectDeviceEvent(deviceId)); - }, - withCheckBox: true, - size: size * 0.5, - headers: const [ - 'Device Name', - 'Device ID', - 'Access Type', - 'Unit Name', - 'Status' - ], - data: state.data.map((item) { - return [ - item.name.toString(), - item.uuid.toString(), - item.productType.toString(), - '', - item.online.value.toString(), - ]; - }).toList(), - ) - : const Center(child: CircularProgressIndicator())) + withSelectAll: true, + + initialSelectedIds: selectedDeviceIds, + cellDecoration: containerDecoration, + isEmpty: visitorBloc.data.isEmpty, + selectAll: (p0) { + visitorBloc.selectedDeviceIds.clear(); + for (var item in state.data) { + visitorBloc.add(SelectDeviceEvent(item.uuid)); + } + }, + onRowSelected: (index, isSelected, row) { + final deviceId = state.data[index].uuid; + visitorBloc.add(SelectDeviceEvent(deviceId)); + }, + withCheckBox: true, + size: size * 0.5, + headers: const [ + 'Device Name', + 'Device ID', + 'Access Type', + 'Unit Name', + 'Status' + ], + data: state.data.map((item) { + return [ + item.name.toString(), + item.uuid.toString(), + item.productType.toString(), + '', + item.online.value.toString(), + ]; + }).toList(), + ) : const Center(child: CircularProgressIndicator())) ], ), ), diff --git a/lib/pages/visitor_password/view/visitor_password_dialog.dart b/lib/pages/visitor_password/view/visitor_password_dialog.dart index 591b6ff6..420fd3de 100644 --- a/lib/pages/visitor_password/view/visitor_password_dialog.dart +++ b/lib/pages/visitor_password/view/visitor_password_dialog.dart @@ -323,8 +323,7 @@ class VisitorPasswordDialog extends StatelessWidget { : visitorBloc.usageFrequencySelected, onChanged: (String? value) { if (value != null) { - context - .read() + context.read() .add(SelectUsageFrequency(value)); } }, @@ -344,7 +343,7 @@ class VisitorPasswordDialog extends StatelessWidget { if (visitorBloc.usageFrequencySelected == 'One-Time' && visitorBloc.accessTypeSelected == 'Offline Password') Text( - 'Within the validity period, there is no limit to the number of times each device can be unlocked.', + 'Within the validity period, each device can be unlocked only once, and the maximum validity period is 6 hours', style: Theme.of(context).textTheme.bodySmall!.copyWith( color: ColorsManager.grayColor, fontSize: 9), ), diff --git a/lib/services/auth_api.dart b/lib/services/auth_api.dart index 6573f3ad..844689df 100644 --- a/lib/services/auth_api.dart +++ b/lib/services/auth_api.dart @@ -25,7 +25,9 @@ class AuthenticationAPI { path: ApiEndpoints.forgetPassword, body: {"email": email, "password": password}, showServerMessage: true, - expectedResponseModel: (json) {}); + expectedResponseModel: (json) { + print('json=$json'); + }); return response; } @@ -66,7 +68,6 @@ class AuthenticationAPI { } static Future verifyOtp({required String email, required String otpCode}) async { - try { final response = await HTTPService().post( path: ApiEndpoints.verifyOtp, body: {"email": email, "type": "PASSWORD", "otpCode": otpCode}, @@ -79,17 +80,7 @@ class AuthenticationAPI { } }); return response; - } on DioException catch (e) { - if (e.response != null) { - if (e.response!.statusCode == 400) { - final errorData = e.response!.data; - String errorMessage = errorData['message']; - return errorMessage; - } - } else { - debugPrint('Error: ${e.message}'); - } - } + } static Future> fetchRegion() async { diff --git a/lib/services/home_api.dart b/lib/services/home_api.dart index dfbaf4bf..000d4ff2 100644 --- a/lib/services/home_api.dart +++ b/lib/services/home_api.dart @@ -8,6 +8,7 @@ class HomeApi { path: ApiEndpoints.getUser.replaceAll('{userUuid}', userId!), showServerMessage: true, expectedResponseModel: (json) { + print('fetchUserInfo$json'); return UserModel.fromJson(json); }); return response; From 00bce2d0ab707a2c872eb0d45c1265e3e4e70bf1 Mon Sep 17 00:00:00 2001 From: mohammad Date: Mon, 2 Sep 2024 14:52:06 +0300 Subject: [PATCH 009/158] fix pugs --- .../access_management/bloc/access_bloc.dart | 34 +++++++++++-------- .../model/password_model.dart | 2 +- .../view/access_management.dart | 3 +- lib/pages/auth/bloc/auth_event.dart | 8 +++-- lib/pages/common/custom_table.dart | 5 ++- .../bloc/visitor_password_bloc.dart | 5 +-- .../view/visitor_password_dialog.dart | 22 ++++++------ lib/services/access_mang_api.dart | 7 ++++ 8 files changed, 54 insertions(+), 32 deletions(-) diff --git a/lib/pages/access_management/bloc/access_bloc.dart b/lib/pages/access_management/bloc/access_bloc.dart index fb66408a..94b0992f 100644 --- a/lib/pages/access_management/bloc/access_bloc.dart +++ b/lib/pages/access_management/bloc/access_bloc.dart @@ -107,26 +107,28 @@ class AccessBloc extends Bloc { Future _filterData(FilterDataEvent event, Emitter emit) async { emit(AccessLoaded()); try { + // Convert search text to lower case for case-insensitive search + final searchText = event.passwordName?.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) - .toUtc() - .toLocal(); + DateTime.fromMillisecondsSinceEpoch(int.parse(item.effectiveTime.toString()) * 1000) + .toUtc() + .toLocal(); DateTime invalidDate = - DateTime.fromMillisecondsSinceEpoch(int.parse(item.invalidTime.toString()) * 1000) - .toUtc() - .toLocal(); + DateTime.fromMillisecondsSinceEpoch(int.parse(item.invalidTime.toString()) * 1000) + .toUtc() + .toLocal(); DateTime effectiveDateOnly = - DateTime(effectiveDate.year, effectiveDate.month, effectiveDate.day); + DateTime(effectiveDate.year, effectiveDate.month, effectiveDate.day); DateTime invalidDateOnly = DateTime(invalidDate.year, invalidDate.month, invalidDate.day); - // Filter by password name - if (event.passwordName != null && event.passwordName!.isNotEmpty) { - final bool matchesName = - item.passwordName != null && item.passwordName.contains(event.passwordName); + // Filter by password name, making the search case-insensitive + if (searchText.isNotEmpty) { + final bool matchesName = item.passwordName.toString().toLowerCase().contains(searchText); if (!matchesName) { matchesCriteria = false; } @@ -135,7 +137,7 @@ class AccessBloc extends Bloc { // Filter by start date only if (event.startTime != null && event.endTime == null) { DateTime startDateOnly = - DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal(); + DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal(); startDateOnly = DateTime(startDateOnly.year, startDateOnly.month, startDateOnly.day); if (effectiveDateOnly.isBefore(startDateOnly)) { matchesCriteria = false; @@ -145,7 +147,7 @@ class AccessBloc extends Bloc { // Filter by end date only if (event.endTime != null && event.startTime == null) { DateTime endDateOnly = - DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal(); + DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal(); endDateOnly = DateTime(endDateOnly.year, endDateOnly.month, endDateOnly.day); if (invalidDateOnly.isAfter(endDateOnly)) { matchesCriteria = false; @@ -155,9 +157,9 @@ class AccessBloc extends Bloc { // Filter by both start date and end date if (event.startTime != null && event.endTime != null) { DateTime startDateOnly = - DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal(); + DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal(); DateTime endDateOnly = - DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal(); + 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)) { @@ -183,6 +185,8 @@ class AccessBloc extends Bloc { } } + + resetSearch(ResetSearch event, Emitter emit) async { emit(AccessLoaded()); startTime = 'Start Time'; diff --git a/lib/pages/access_management/model/password_model.dart b/lib/pages/access_management/model/password_model.dart index 8436ef56..50c03090 100644 --- a/lib/pages/access_management/model/password_model.dart +++ b/lib/pages/access_management/model/password_model.dart @@ -30,7 +30,7 @@ class PasswordModel { effectiveTime: json['effectiveTime'], passwordCreated: json['passwordCreated'], createdTime: json['createdTime'], - passwordName: json['passwordName'] ?? 'No name', // New field + passwordName: json['passwordName']??'No Name', passwordStatus: AccessStatusExtension.fromString(json['passwordStatus']), passwordType: AccessTypeExtension.fromString(json['passwordType']), deviceUuid: json['deviceUuid'], diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index 19c29643..48811d32 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -92,6 +92,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { const SizedBox(height: 20), Expanded( child: DynamicTable( + tableName:'AccessManagement', withSelectAll: false, isEmpty: filteredData.isEmpty, withCheckBox: false, @@ -108,7 +109,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { ], data: filteredData.map((item) { return [ - item.passwordName.toString(), + item.passwordName, item.passwordType.value, ('${accessBloc.timestampToDate(item.effectiveTime)} - ${accessBloc.timestampToDate(item.invalidTime)}'), item.deviceUuid.toString(), diff --git a/lib/pages/auth/bloc/auth_event.dart b/lib/pages/auth/bloc/auth_event.dart index 0026554c..fa7e86b3 100644 --- a/lib/pages/auth/bloc/auth_event.dart +++ b/lib/pages/auth/bloc/auth_event.dart @@ -49,9 +49,13 @@ class UpdateTimerEvent extends AuthEvent { const UpdateTimerEvent({required this.remainingTime, required this.isButtonEnabled}); } -class ChangePasswordEvent extends AuthEvent {} +class ChangePasswordEvent extends AuthEvent { -class SendOtpEvent extends AuthEvent {} +} + +class SendOtpEvent extends AuthEvent { + +} class PasswordVisibleEvent extends AuthEvent { final bool? newValue; diff --git a/lib/pages/common/custom_table.dart b/lib/pages/common/custom_table.dart index 281a3bbb..82228da6 100644 --- a/lib/pages/common/custom_table.dart +++ b/lib/pages/common/custom_table.dart @@ -5,6 +5,7 @@ import 'package:syncrow_web/utils/constants/assets.dart'; class DynamicTable extends StatefulWidget { final List headers; + final String? tableName; final List> data; final BoxDecoration? headerDecoration; final BoxDecoration? cellDecoration; @@ -20,6 +21,7 @@ class DynamicTable extends StatefulWidget { required this.headers, required this.data, required this.size, + this.tableName, required this.isEmpty, required this.withCheckBox, required this.withSelectAll, @@ -106,7 +108,8 @@ class _DynamicTableState extends State { height: 15, ), Text( - 'No Devices', + // no password + widget.tableName=='AccessManagement'? 'No Password ' : 'No Devices', style: Theme.of(context) .textTheme .bodySmall! diff --git a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart index f1dbe47c..02f5ef0a 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart @@ -219,8 +219,8 @@ class VisitorPasswordBloc extends Bloc[ TextButton( onPressed: () { + Navigator.of(context).pop(true); }, child: const Text('OK'), diff --git a/lib/pages/visitor_password/view/visitor_password_dialog.dart b/lib/pages/visitor_password/view/visitor_password_dialog.dart index 420fd3de..5fc82dbf 100644 --- a/lib/pages/visitor_password/view/visitor_password_dialog.dart +++ b/lib/pages/visitor_password/view/visitor_password_dialog.dart @@ -87,7 +87,8 @@ class VisitorPasswordDialog extends StatelessWidget { ], )) .then((v) { - Navigator.of(context).pop(); + Navigator.of(context).pop(true); + }); } else if (state is FailedState) { visitorBloc.stateDialog( @@ -379,11 +380,9 @@ class VisitorPasswordDialog extends StatelessWidget { endTime: () { if (visitorBloc.usageFrequencySelected == 'Periodic' && visitorBloc.accessTypeSelected == 'Offline Password') { - visitorBloc.add( - SelectTimeEvent(context: context, isEffective: false)); + visitorBloc.add(SelectTimeEvent(context: context, isEffective: false)); } else { - visitorBloc.add(SelectTimeVisitorPassword( - context: context, isStart: false, isRepeat: false)); + visitorBloc.add(SelectTimeVisitorPassword(context: context, isStart: false, isRepeat: false)); } }, startTime: () { @@ -397,13 +396,11 @@ class VisitorPasswordDialog extends StatelessWidget { } }, firstString: (visitorBloc.usageFrequencySelected == - 'Periodic' && - visitorBloc.accessTypeSelected == 'Offline Password') + 'Periodic' && visitorBloc.accessTypeSelected == 'Offline Password') ? visitorBloc.effectiveTime : visitorBloc.startTimeAccess.toString(), secondString: (visitorBloc.usageFrequencySelected == - 'Periodic' && - visitorBloc.accessTypeSelected == 'Offline Password') + 'Periodic' && visitorBloc.accessTypeSelected == 'Offline Password') ? visitorBloc.expirationTime : visitorBloc.endTimeAccess.toString(), icon: Assets.calendarIcon), @@ -529,7 +526,7 @@ class VisitorPasswordDialog extends StatelessWidget { setPasswordFunction(context, size, visitorBloc); } else if (visitorBloc.accessTypeSelected == 'Dynamic Password') { setPasswordFunction(context, size, visitorBloc); - } else { + } else if(visitorBloc.endTimeAccess.toString()!='End Time'&&visitorBloc.startTimeAccess.toString()!='Start Time') { if (visitorBloc.effectiveTimeTimeStamp != null && visitorBloc.expirationTimeTimeStamp != null) { if (isRepeat == true) { @@ -553,6 +550,11 @@ class VisitorPasswordDialog extends StatelessWidget { message: 'Please select Access Period to continue', title: 'Access Period'); } + }else{ + visitorBloc.stateDialog( + context: context, + message: 'Please select Access Period to continue', + title: 'Access Period'); } } else { visitorBloc.stateDialog( diff --git a/lib/services/access_mang_api.dart b/lib/services/access_mang_api.dart index 3309e253..68ea4f8d 100644 --- a/lib/services/access_mang_api.dart +++ b/lib/services/access_mang_api.dart @@ -123,6 +123,13 @@ class AccessMangApi { String? effectiveTime, String? invalidTime, List? devicesUuid}) async { + print('object=== ${ jsonEncode({ + "email": email, + "devicesUuid": devicesUuid, + "passwordName": passwordName, + "effectiveTime": effectiveTime, + "invalidTime": invalidTime, + })}'); final response = await HTTPService().post( path: ApiEndpoints.sendOffLineMultipleTime, body: jsonEncode({ From 418f5d5406d727e0017edc6ae97c8510877c9a37 Mon Sep 17 00:00:00 2001 From: mohammad Date: Mon, 2 Sep 2024 16:59:25 +0300 Subject: [PATCH 010/158] login Enhancements --- lib/pages/auth/view/login_web_page.dart | 290 +++++++++++++++++------- pubspec.lock | 16 ++ pubspec.yaml | 2 + 3 files changed, 221 insertions(+), 87 deletions(-) diff --git a/lib/pages/auth/view/login_web_page.dart b/lib/pages/auth/view/login_web_page.dart index 1c638287..13492c45 100644 --- a/lib/pages/auth/view/login_web_page.dart +++ b/lib/pages/auth/view/login_web_page.dart @@ -1,3 +1,4 @@ +import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -23,7 +24,8 @@ class LoginWebPage extends StatefulWidget { State createState() => _LoginWebPageState(); } -class _LoginWebPageState extends State with HelperResponsiveLayout { +class _LoginWebPageState extends State + with HelperResponsiveLayout { @override Widget build(BuildContext context) { return Scaffold( @@ -58,7 +60,8 @@ class _LoginWebPageState extends State with HelperResponsiveLayout _scrollController = ScrollController(); void _scrollToCenter() { - final double middlePosition = _scrollController.position.maxScrollExtent / 2; + final double middlePosition = + _scrollController.position.maxScrollExtent / 2; _scrollController.animateTo( middlePosition, duration: const Duration(seconds: 1), @@ -120,7 +123,8 @@ class _LoginWebPageState extends State with HelperResponsiveLayout const Spacer(), Expanded( flex: 2, - child: _buildLoginFormFields(context, loginBloc, size), + child: _buildLoginFormFields( + context, loginBloc, size), ), const Spacer(), ], @@ -131,12 +135,14 @@ class _LoginWebPageState extends State with HelperResponsiveLayout ), ), ), - if (state is AuthLoading) const Center(child: CircularProgressIndicator()) + if (state is AuthLoading) + const Center(child: CircularProgressIndicator()) ], ); } - Widget _buildLoginFormFields(BuildContext context, AuthBloc loginBloc, Size size) { + Widget _buildLoginFormFields( + BuildContext context, AuthBloc loginBloc, Size size) { return Container( decoration: BoxDecoration( color: Colors.white.withOpacity(0.1), @@ -146,8 +152,8 @@ class _LoginWebPageState extends State with HelperResponsiveLayout child: Form( key: loginBloc.loginFormKey, child: Padding( - padding: - EdgeInsets.symmetric(horizontal: size.width * 0.02, vertical: size.width * 0.003), + padding: EdgeInsets.symmetric( + horizontal: size.width * 0.02, vertical: size.width * 0.003), child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.start, @@ -175,82 +181,190 @@ class _LoginWebPageState extends State with HelperResponsiveLayout ); } - Widget _buildDropdownField(BuildContext context, AuthBloc loginBloc, Size size) { + // Widget _buildDropdownField(BuildContext context, AuthBloc loginBloc, Size size) { + // return Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisAlignment: MainAxisAlignment.start, + // children: [ + // Text( + // "Country/Region", + // style: Theme.of(context) + // .textTheme + // .bodySmall! + // .copyWith(fontSize: 14, fontWeight: FontWeight.w400), + // ), + // const SizedBox(height: 10), + // SizedBox( + // width: size.width * 0.8, + // child: LayoutBuilder( + // builder: (context, constraints) { + // return DropdownButtonFormField( + // value: loginBloc.regionList!.any((region) => region.id == loginBloc.regionUuid) + // ? loginBloc.regionUuid + // : null, + // validator: loginBloc.validateRegion, + // icon: const Icon( + // Icons.keyboard_arrow_down_outlined, + // size: 20, + // ), + // decoration: textBoxDecoration()!.copyWith( + // errorStyle: const TextStyle(height: 0), + // contentPadding: const EdgeInsets.symmetric( + // vertical: 12, + // horizontal: 10, + // ), + // ), + // hint: Text( + // 'Select your region/country', + // style: Theme.of(context) + // .textTheme + // .bodySmall! + // .copyWith(color: ColorsManager.grayColor, fontWeight: FontWeight.w400), + // overflow: TextOverflow.ellipsis, + // ), + // isDense: true, + // style: const TextStyle(color: Colors.black), + // items: loginBloc.regionList!.map((RegionModel region) { + // return DropdownMenuItem( + // value: region.id, + // child: Container( + // constraints: BoxConstraints(maxWidth: constraints.maxWidth - 40), + // child: Text( + // region.name, + // overflow: TextOverflow.ellipsis, + // maxLines: 1, + // ), + // ), + // ); + // }).toList(), + // onChanged: (String? value) { + // loginBloc.add(CheckEnableEvent()); + // loginBloc.add(SelectRegionEvent(val: value!)); + // }, + // dropdownColor: Colors.white, + // menuMaxHeight: size.height * 0.45, + // selectedItemBuilder: (context) { + // return loginBloc.regionList!.map((region) { + // return Container( + // constraints: BoxConstraints(maxWidth: constraints.maxWidth - 40), + // child: Text( + // region.name, + // overflow: TextOverflow.ellipsis, + // maxLines: 1, + // ), + // ); + // }).toList(); + // }, + // ); + // }, + // ), + // ), + // ], + // ); + // } + + Widget _buildDropdownField( + BuildContext context, AuthBloc loginBloc, Size size) { + final TextEditingController textEditingController = TextEditingController(); return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ Text( "Country/Region", - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith(fontSize: 14, fontWeight: FontWeight.w400), + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontSize: 14, + fontWeight: FontWeight.w400, + ), ), const SizedBox(height: 10), - SizedBox( - width: size.width * 0.8, - child: LayoutBuilder( - builder: (context, constraints) { - return DropdownButtonFormField( - value: loginBloc.regionList!.any((region) => region.id == loginBloc.regionUuid) - ? loginBloc.regionUuid - : null, - validator: loginBloc.validateRegion, - icon: const Icon( - Icons.keyboard_arrow_down_outlined, - size: 20, - ), - decoration: textBoxDecoration()!.copyWith( - errorStyle: const TextStyle(height: 0), - contentPadding: const EdgeInsets.symmetric( - vertical: 12, - horizontal: 10, + Container( + height: size.height * 0.05, + decoration:const BoxDecoration( + color: ColorsManager.boxColor, + borderRadius: BorderRadius.all(Radius.circular(8))), + width: size.width * 0.9, + child: DropdownButtonHideUnderline( + child: DropdownButton2( + isExpanded: true, + hint: Text( + 'Select your region/country', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor, + fontWeight: FontWeight.w400, + ), + overflow: TextOverflow.ellipsis, + ), + items: loginBloc.regionList!.map((RegionModel region) { + return DropdownMenuItem( + value: region.id, + child: Text( + region.name, + overflow: TextOverflow.ellipsis, + maxLines: 1, ), - ), - hint: Text( - 'Select your region/country', - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith(color: ColorsManager.grayColor, fontWeight: FontWeight.w400), - overflow: TextOverflow.ellipsis, - ), - isDense: true, - style: const TextStyle(color: Colors.black), - items: loginBloc.regionList!.map((RegionModel region) { - return DropdownMenuItem( - value: region.id, - child: Container( - constraints: BoxConstraints(maxWidth: constraints.maxWidth - 40), - child: Text( - region.name, - overflow: TextOverflow.ellipsis, - maxLines: 1, + ); + }).toList(), + value: loginBloc.regionList!.any( + (region) => region.id == loginBloc.regionUuid, + ) + ? loginBloc.regionUuid + : null, + onChanged: (String? value) { + if (value != null) { + loginBloc.add(CheckEnableEvent()); + loginBloc.add(SelectRegionEvent(val: value)); + } + }, + buttonStyleData: const ButtonStyleData( + padding: EdgeInsets.symmetric(horizontal: 16), + height: 40, + width: double.infinity, + ), + dropdownStyleData: DropdownStyleData( + maxHeight: size.height * 0.45, + ), + menuItemStyleData: const MenuItemStyleData( + height: 40, + ), + dropdownSearchData: DropdownSearchData( + searchController: textEditingController, + searchInnerWidgetHeight: 50, + searchInnerWidget: Container( + height: 50, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + child: TextFormField( + style: TextStyle(color: Colors.black), + controller: textEditingController, + decoration: textBoxDecoration()!.copyWith( + errorStyle: const TextStyle(height: 0), + contentPadding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 10, ), ), - ); - }).toList(), - onChanged: (String? value) { - loginBloc.add(CheckEnableEvent()); - loginBloc.add(SelectRegionEvent(val: value!)); + ), + ), + + searchMatchFn: (item, searchValue) { + // Ensure both item value and search value are compared in lowercase for a case-insensitive match. + final itemValue = item.value?.toLowerCase() ?? ''; + final search = searchValue.toLowerCase().trim(); + + // Debugging print statement to ensure values are captured correctly. + print('searchValue == $search'); + + // Return true if the item value contains the search term. + return itemValue.contains(search); }, - dropdownColor: Colors.white, - menuMaxHeight: size.height * 0.45, - selectedItemBuilder: (context) { - return loginBloc.regionList!.map((region) { - return Container( - constraints: BoxConstraints(maxWidth: constraints.maxWidth - 40), - child: Text( - region.name, - overflow: TextOverflow.ellipsis, - maxLines: 1, - ), - ); - }).toList(); - }, - ); - }, + + ), + onMenuStateChange: (isOpen) { + if (!isOpen) { + textEditingController.clear(); + } + }, + ), ), ), ], @@ -280,10 +394,9 @@ class _LoginWebPageState extends State with HelperResponsiveLayout decoration: textBoxDecoration()!.copyWith( errorStyle: const TextStyle(height: 0), hintText: 'Enter your email address', - 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)), style: const TextStyle(color: Colors.black), ), ), @@ -315,17 +428,18 @@ class _LoginWebPageState extends State with HelperResponsiveLayout controller: loginBloc.loginPasswordController, decoration: textBoxDecoration()!.copyWith( hintText: 'At least 8 characters', - 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: IconButton( onPressed: () { - loginBloc.add(PasswordVisibleEvent(newValue: loginBloc.obscureText)); + loginBloc.add( + PasswordVisibleEvent(newValue: loginBloc.obscureText)); }, icon: SizedBox( child: SvgPicture.asset( - loginBloc.obscureText ? Assets.visiblePassword : Assets.invisiblePassword, + loginBloc.obscureText + ? Assets.visiblePassword + : Assets.invisiblePassword, height: 15, width: 15, ), @@ -353,10 +467,10 @@ class _LoginWebPageState extends State with HelperResponsiveLayout }, child: Text( "Forgot Password?", - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith(color: Colors.black, fontSize: 14, fontWeight: FontWeight.w400), + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Colors.black, + fontSize: 14, + fontWeight: FontWeight.w400), ), ), ], @@ -419,7 +533,8 @@ class _LoginWebPageState extends State with HelperResponsiveLayout ); } - Widget _buildSignInButton(BuildContext context, AuthBloc loginBloc, Size size) { + Widget _buildSignInButton( + BuildContext context, AuthBloc loginBloc, Size size) { return Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, @@ -460,7 +575,8 @@ class _LoginWebPageState extends State with HelperResponsiveLayout SizedBox( child: Text( loginBloc.validate, - style: const TextStyle(fontWeight: FontWeight.w700, color: ColorsManager.red), + style: const TextStyle( + fontWeight: FontWeight.w700, color: ColorsManager.red), ), ) ], diff --git a/pubspec.lock b/pubspec.lock index 9a9cd6a8..3da608f2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -89,6 +89,22 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + dropdown_button2: + dependency: "direct main" + description: + name: dropdown_button2 + sha256: b0fe8d49a030315e9eef6c7ac84ca964250155a6224d491c1365061bc974a9e1 + url: "https://pub.dev" + source: hosted + version: "2.3.9" + dropdown_search: + dependency: "direct main" + description: + name: dropdown_search + sha256: "55106e8290acaa97ed15bea1fdad82c3cf0c248dd410e651f5a8ac6870f783ab" + url: "https://pub.dev" + source: hosted + version: "5.0.6" equatable: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index a8e96a9b..ea0138ea 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -43,9 +43,11 @@ dependencies: get_it: ^7.6.7 flutter_secure_storage: ^9.2.2 shared_preferences: ^2.3.0 + dropdown_button2: ^2.3.9 data_table_2: ^2.5.15 go_router: intl: ^0.19.0 + dropdown_search: ^5.0.6 dev_dependencies: flutter_test: From 4cf9d4c2f26bb80cd4fc12aec4e7d10c4577c051 Mon Sep 17 00:00:00 2001 From: ashrafzarkanisala Date: Mon, 2 Sep 2024 17:37:40 +0300 Subject: [PATCH 011/158] push --- .../all_devices/bloc/device_managment_bloc.dart | 1 + lib/utils/constants/assets.dart | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart b/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart index 6ac40419..d5ad921f 100644 --- a/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart +++ b/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart @@ -36,6 +36,7 @@ class DeviceManagementBloc onlineCount: _onlineCount, offlineCount: _offlineCount, lowBatteryCount: _lowBatteryCount, + selectedDevice: null, )); } catch (e) { emit(DeviceManagementInitial()); diff --git a/lib/utils/constants/assets.dart b/lib/utils/constants/assets.dart index 49cefd2d..85a06ea3 100644 --- a/lib/utils/constants/assets.dart +++ b/lib/utils/constants/assets.dart @@ -14,7 +14,7 @@ class Assets { static const String google = "assets/images/google.svg"; static const String facebook = "assets/images/facebook.svg"; static const String invisiblePassword = "assets/images/Password_invisible.svg"; - static const String visiblePassword = "assets/images/Password_visible.svg"; + static const String visiblePassword = "assets/images/password_visible.svg"; static const String accessIcon = "assets/images/access_icon.svg"; static const String spaseManagementIcon = "assets/images/spase_management_icon.svg"; static const String devicesIcon = "assets/images/devices_icon.svg"; From 7bbae2d3326552512a146f02cfbaf39d7ae99975 Mon Sep 17 00:00:00 2001 From: ashrafzarkanisala Date: Mon, 2 Sep 2024 19:26:52 +0300 Subject: [PATCH 012/158] fix selection from dynamic table --- .../view/access_management.dart | 1 + lib/pages/common/custom_table.dart | 30 +++++++++---- .../bloc/device_managment_bloc.dart | 15 +++++-- .../widgets/device_managment_body.dart | 12 +++++- lib/pages/home/bloc/home_bloc.dart | 10 +++-- lib/pages/home/bloc/home_event.dart | 4 ++ lib/pages/home/view/home_page.dart | 16 ++++++- lib/pages/home/view/home_page_mobile.dart | 3 +- .../view/add_device_dialog.dart | 1 + lib/web_layout/web_app_bar.dart | 43 ++++++++++--------- 10 files changed, 96 insertions(+), 39 deletions(-) diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index 26a1dcc2..cebf2eae 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -82,6 +82,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { const SizedBox(height: 20), Expanded( child: DynamicTable( + uuidIndex: 0, isEmpty: filteredData.isEmpty, withCheckBox: false, size: MediaQuery.of(context).size, diff --git a/lib/pages/common/custom_table.dart b/lib/pages/common/custom_table.dart index 5308e450..a1532b68 100644 --- a/lib/pages/common/custom_table.dart +++ b/lib/pages/common/custom_table.dart @@ -14,6 +14,7 @@ class DynamicTable extends StatefulWidget { final void Function(bool?)? selectAll; final void Function(int, bool, dynamic)? onRowSelected; final List? initialSelectedIds; + final int uuidIndex; const DynamicTable({ super.key, required this.headers, @@ -26,6 +27,7 @@ class DynamicTable extends StatefulWidget { this.selectAll, this.onRowSelected, this.initialSelectedIds, + required this.uuidIndex, }); @override @@ -38,9 +40,24 @@ class _DynamicTableState extends State { @override void initState() { super.initState(); + _initializeSelection(); + } + + @override + void didUpdateWidget(DynamicTable oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.data != widget.data) { + _initializeSelection(); + } + } + + void _initializeSelection() { _selected = List.generate(widget.data.length, (index) { + // Check if the initialSelectedIds contains the deviceUuid + // uuidIndex is the index of the column containing the deviceUuid + final deviceUuid = widget.data[index][widget.uuidIndex]; return widget.initialSelectedIds != null && - widget.initialSelectedIds!.contains(widget.data[index][1]); + widget.initialSelectedIds!.contains(deviceUuid); }); } @@ -71,8 +88,7 @@ class _DynamicTableState extends State { children: [ if (widget.withCheckBox) _buildSelectAllCheckbox(), ...widget.headers - .map((header) => _buildTableHeaderCell(header)) - .toList(), + .map((header) => _buildTableHeaderCell(header)), ], ), ), @@ -119,11 +135,9 @@ class _DynamicTableState extends State { if (widget.withCheckBox) _buildRowCheckbox( index, widget.size.height * 0.10), - ...row - .map((cell) => _buildTableCell( - cell.toString(), - widget.size.height * 0.10)) - .toList(), + ...row.map((cell) => _buildTableCell( + cell.toString(), + widget.size.height * 0.10)), ], ); }, diff --git a/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart b/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart index d5ad921f..d64599f1 100644 --- a/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart +++ b/lib/pages/device_managment/all_devices/bloc/device_managment_bloc.dart @@ -28,11 +28,12 @@ class DeviceManagementBloc emit(DeviceManagementLoading()); try { final devices = await DevicesManagementApi().fetchDevices(); + _selectedDevices.clear(); _devices = devices; _calculateDeviceCounts(); emit(DeviceManagementLoaded( devices: devices, - selectedIndex: _selectedIndex, + selectedIndex: 0, onlineCount: _onlineCount, offlineCount: _offlineCount, lowBatteryCount: _lowBatteryCount, @@ -64,6 +65,8 @@ class DeviceManagementBloc onlineCount: _onlineCount, offlineCount: _offlineCount, lowBatteryCount: _lowBatteryCount, + selectedDevice: + _selectedDevices.isNotEmpty ? _selectedDevices.first : null, )); } } @@ -76,8 +79,10 @@ class DeviceManagementBloc void _onSelectDevice( SelectDevice event, Emitter emit) { - if (_selectedDevices.contains(event.selectedDevice)) { - _selectedDevices.remove(event.selectedDevice); + final selectedUuid = event.selectedDevice.uuid; + + if (_selectedDevices.any((device) => device.uuid == selectedUuid)) { + _selectedDevices.removeWhere((device) => device.uuid == selectedUuid); } else { _selectedDevices.add(event.selectedDevice); } @@ -130,6 +135,9 @@ class DeviceManagementBloc void _onSearchDevices( SearchDevices event, Emitter emit) { if (_devices.isNotEmpty) { + _selectedDevices.clear(); + _selectedIndex = 0; + final filteredDevices = _devices.where((device) { final matchesCommunity = event.community == null || event.community!.isEmpty || @@ -151,7 +159,6 @@ class DeviceManagementBloc false); return matchesCommunity && matchesUnit && matchesProductName; }).toList(); - _selectedDevices = []; emit(DeviceManagementFiltered( filteredDevices: filteredDevices, selectedIndex: 0, diff --git a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart index 2e9d916a..7f40bf37 100644 --- a/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart +++ b/lib/pages/device_managment/all_devices/widgets/device_managment_body.dart @@ -42,6 +42,10 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { offlineCount = state.offlineCount; lowBatteryCount = state.lowBatteryCount; isControlButtonEnabled = state.selectedDevice != null; + } else if (state is DeviceManagementInitial) { + devicesToShow = []; + selectedIndex = 0; + isControlButtonEnabled = false; } final tabs = [ @@ -125,6 +129,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { }, withCheckBox: true, size: context.screenSize, + uuidIndex: 2, headers: const [ 'Device Name', 'Product Name', @@ -153,10 +158,15 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { (device.updateTime ?? 0) * 1000)), ]; }).toList(), + initialSelectedIds: context + .read() + .selectedDevices + .map((device) => device.uuid!) + .toList(), isEmpty: devicesToShow.isEmpty, ), ), - ), + ) ], ); }, diff --git a/lib/pages/home/bloc/home_bloc.dart b/lib/pages/home/bloc/home_bloc.dart index 79579efc..cc40b8fe 100644 --- a/lib/pages/home/bloc/home_bloc.dart +++ b/lib/pages/home/bloc/home_bloc.dart @@ -16,11 +16,11 @@ class HomeBloc extends Bloc { final BuchheimWalkerConfiguration builder = BuchheimWalkerConfiguration(); List sourcesList = []; List destinationsList = []; - static UserModel? user; + UserModel? user; HomeBloc() : super((HomeInitial())) { on(_createNode); - fetchUserInfo(); + on(_fetchUserInfo); } void _createNode(CreateNewNode event, Emitter emit) async { @@ -39,10 +39,12 @@ class HomeBloc extends Bloc { emit(HomeUpdateTree(graph: graph, builder: builder)); } - static Future fetchUserInfo() async { + Future _fetchUserInfo(FetchUserInfo event, Emitter emit) async { try { - var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey); + var uuid = + await const FlutterSecureStorage().read(key: UserModel.userUuidKey); user = await HomeApi().fetchUserInfo(uuid); + emit(HomeInitial()); } catch (e) { return; } diff --git a/lib/pages/home/bloc/home_event.dart b/lib/pages/home/bloc/home_event.dart index da517943..963202b9 100644 --- a/lib/pages/home/bloc/home_event.dart +++ b/lib/pages/home/bloc/home_event.dart @@ -17,3 +17,7 @@ class CreateNewNode extends HomeEvent { @override List get props => [sourceNode, destinationNode]; } + +class FetchUserInfo extends HomeEvent { + const FetchUserInfo(); +} \ No newline at end of file diff --git a/lib/pages/home/view/home_page.dart b/lib/pages/home/view/home_page.dart index 9159011f..75107e84 100644 --- a/lib/pages/home/view/home_page.dart +++ b/lib/pages/home/view/home_page.dart @@ -1,11 +1,25 @@ import 'package:flutter/cupertino.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/home/bloc/home_bloc.dart'; +import 'package:syncrow_web/pages/home/bloc/home_event.dart'; import 'package:syncrow_web/pages/home/view/home_page_mobile.dart'; import 'package:syncrow_web/pages/home/view/home_page_web.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; -class HomePage extends StatelessWidget with HelperResponsiveLayout { +class HomePage extends StatefulWidget { const HomePage({super.key}); + @override + State createState() => _HomePageState(); +} + +class _HomePageState extends State with HelperResponsiveLayout { + @override + void initState() { + super.initState(); + context.read().add(const FetchUserInfo()); + } + @override Widget build(BuildContext context) { final isSmallScreen = isSmallScreenSize(context); diff --git a/lib/pages/home/view/home_page_mobile.dart b/lib/pages/home/view/home_page_mobile.dart index c0abdfe3..e8371cf2 100644 --- a/lib/pages/home/view/home_page_mobile.dart +++ b/lib/pages/home/view/home_page_mobile.dart @@ -10,6 +10,7 @@ import 'package:syncrow_web/web_layout/web_scaffold.dart'; class HomeMobilePage extends StatelessWidget { HomeMobilePage({super.key}); + @override Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; @@ -79,7 +80,7 @@ class HomeMobilePage extends StatelessWidget { ); } - dynamic homeItems = [ + final dynamic homeItems = [ { 'title': 'Access', 'icon': Assets.accessIcon, diff --git a/lib/pages/visitor_password/view/add_device_dialog.dart b/lib/pages/visitor_password/view/add_device_dialog.dart index 85262ff1..38b08f6c 100644 --- a/lib/pages/visitor_password/view/add_device_dialog.dart +++ b/lib/pages/visitor_password/view/add_device_dialog.dart @@ -184,6 +184,7 @@ class AddDeviceDialog extends StatelessWidget { }, withCheckBox: true, size: size * 0.5, + uuidIndex: 1, headers: const [ 'Device Name', 'Device ID', diff --git a/lib/web_layout/web_app_bar.dart b/lib/web_layout/web_app_bar.dart index 46b9c614..e63a329a 100644 --- a/lib/web_layout/web_app_bar.dart +++ b/lib/web_layout/web_app_bar.dart @@ -15,13 +15,14 @@ class WebAppBar extends StatelessWidget with HelperResponsiveLayout { @override Widget build(BuildContext context) { bool isSmallScreen = isSmallScreenSize(context); - + bool isHalfMediumScreen = isHafMediumScreenSize(context); return BlocBuilder(builder: (context, state) { + final user = context.read().user; return Container( - height: isSmallScreen ? 130 : 100, + height: (isSmallScreen || isHalfMediumScreen) ? 130 : 100, decoration: const BoxDecoration(color: ColorsManager.secondaryColor), padding: const EdgeInsets.all(10), - child: isSmallScreen + child: isSmallScreen || isHalfMediumScreen ? Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -31,14 +32,11 @@ class WebAppBar extends StatelessWidget with HelperResponsiveLayout { child: title!, ), if (centerBody != null) - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.only(top: 8.0), - child: centerBody, - ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: centerBody, ), - if (rightBody != null || HomeBloc.user != null) + if (rightBody != null || user != null) Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -61,9 +59,9 @@ class WebAppBar extends StatelessWidget with HelperResponsiveLayout { const SizedBox( width: 10, ), - if (HomeBloc.user != null) + if (user != null) Text( - '${HomeBloc.user!.firstName} ${HomeBloc.user!.lastName}', + '${user.firstName} ${user.lastName}', style: Theme.of(context).textTheme.bodyLarge, ), ], @@ -78,14 +76,19 @@ class WebAppBar extends StatelessWidget with HelperResponsiveLayout { children: [ Align( alignment: Alignment.centerLeft, - child: title!, - ), - if (centerBody != null) - Expanded( - child: Center( - child: centerBody, + child: Expanded( + child: Row( + children: [ + title!, + if (centerBody != null) + Padding( + padding: const EdgeInsets.only(left: 80), + child: centerBody!, + ), + ], ), ), + ), Row( mainAxisSize: MainAxisSize.min, children: [ @@ -113,9 +116,9 @@ class WebAppBar extends StatelessWidget with HelperResponsiveLayout { const SizedBox( width: 10, ), - if (HomeBloc.user != null) + if (user != null) Text( - '${HomeBloc.user!.firstName} ${HomeBloc.user!.lastName}', + '${user.firstName} ${user.lastName}', style: Theme.of(context).textTheme.bodyLarge, ), ], From 3017a5d1f685c738c1fbbd04f21fcd2b11993c1b Mon Sep 17 00:00:00 2001 From: ashrafzarkanisala Date: Mon, 2 Sep 2024 21:23:31 +0300 Subject: [PATCH 013/158] fixed report table --- .../view/access_management.dart | 2 +- .../shared/table/report_table.dart | 51 ++++++++++--------- .../view/wall_sensor_conrtols.dart | 37 ++++++++------ lib/web_layout/web_app_bar.dart | 23 ++++----- 4 files changed, 60 insertions(+), 53 deletions(-) diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index cebf2eae..5652e2cd 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -82,7 +82,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout { const SizedBox(height: 20), Expanded( child: DynamicTable( - uuidIndex: 0, + uuidIndex: 1, isEmpty: filteredData.isEmpty, withCheckBox: false, size: MediaQuery.of(context).size, diff --git a/lib/pages/device_managment/shared/table/report_table.dart b/lib/pages/device_managment/shared/table/report_table.dart index 619df168..ef189f3a 100644 --- a/lib/pages/device_managment/shared/table/report_table.dart +++ b/lib/pages/device_managment/shared/table/report_table.dart @@ -6,6 +6,8 @@ import 'package:syncrow_web/pages/device_managment/shared/table/table_header.dar class ReportsTable extends StatelessWidget { final DeviceReport report; + final String? thirdColumnTitle; + final String? thirdColumnDescription; final Function(int index) onRowTap; final VoidCallback onClose; @@ -14,6 +16,8 @@ class ReportsTable extends StatelessWidget { required this.report, required this.onRowTap, required this.onClose, + this.thirdColumnTitle, + this.thirdColumnDescription, }); @override @@ -32,33 +36,34 @@ class ReportsTable extends StatelessWidget { children: [ TableRow( decoration: BoxDecoration(color: Colors.grey.shade200), - children: const [ - TableHeader(title: 'Date'), - TableHeader(title: 'Time'), - TableHeader(title: 'Status'), + children: [ + const TableHeader(title: 'Date'), + const TableHeader(title: 'Time'), + TableHeader(title: thirdColumnTitle ?? 'Status'), ], ), - ...report.data!.asMap().entries.map((entry) { - int index = entry.key; - DeviceEvent data = entry.value; + if (report.data != null) + ...report.data!.asMap().entries.map((entry) { + int index = entry.key; + DeviceEvent data = entry.value; - // Parse eventTime into Date and Time - DateTime eventDateTime = - DateTime.fromMillisecondsSinceEpoch(data.eventTime!); - String date = DateFormat('dd/MM/yyyy').format(eventDateTime); - String time = DateFormat('HH:mm').format(eventDateTime); + // Parse eventTime into Date and Time + DateTime eventDateTime = + DateTime.fromMillisecondsSinceEpoch(data.eventTime!); + String date = DateFormat('dd/MM/yyyy').format(eventDateTime); + String time = DateFormat('HH:mm').format(eventDateTime); - return TableRow( - children: [ - TableCellWidget(value: date), - TableCellWidget(value: time), - TableCellWidget( - value: data.value!, - onTap: () => onRowTap(index), - ), - ], - ); - }).toList(), + return TableRow( + children: [ + TableCellWidget(value: date), + TableCellWidget(value: time), + TableCellWidget( + value: '${data.value!} $thirdColumnDescription', + onTap: () => onRowTap(index), + ), + ], + ); + }), ], ), ), diff --git a/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart b/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart index 75772cad..8448ef67 100644 --- a/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart +++ b/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart @@ -25,16 +25,21 @@ class WallSensorControls extends StatelessWidget with HelperResponsiveLayout { final isLarge = isLargeScreenSize(context); final isMedium = isMediumScreenSize(context); return BlocProvider( - create: (context) => WallSensorBloc(deviceId: device.uuid!)..add(WallSensorInitialEvent()), + create: (context) => + WallSensorBloc(deviceId: device.uuid!)..add(WallSensorInitialEvent()), child: BlocBuilder( builder: (context, state) { - if (state is WallSensorLoadingInitialState || state is DeviceReportsLoadingState) { + if (state is WallSensorLoadingInitialState || + state is DeviceReportsLoadingState) { return const Center(child: CircularProgressIndicator()); } else if (state is WallSensorUpdateState) { - return _buildGridView(context, state.wallSensorModel, isExtraLarge, isLarge, isMedium); + return _buildGridView(context, state.wallSensorModel, isExtraLarge, + isLarge, isMedium); } else if (state is DeviceReportsState) { return ReportsTable( report: state.deviceReport, + thirdColumnTitle: "Value", + thirdColumnDescription: "Lux", onRowTap: (index) {}, onClose: () { context.read().add(BackToGridViewEvent()); @@ -49,7 +54,8 @@ class WallSensorControls extends StatelessWidget with HelperResponsiveLayout { ); } else if (state is DeviceReportsFailedState) { final model = context.read().deviceStatus; - return _buildGridView(context, model, isExtraLarge, isLarge, isMedium); + return _buildGridView( + context, model, isExtraLarge, isLarge, isMedium); } return const Center(child: Text('Error fetching status')); }, @@ -57,8 +63,8 @@ class WallSensorControls extends StatelessWidget with HelperResponsiveLayout { ); } - Widget _buildGridView( - BuildContext context, WallSensorModel model, bool isExtraLarge, bool isLarge, bool isMedium) { + Widget _buildGridView(BuildContext context, WallSensorModel model, + bool isExtraLarge, bool isLarge, bool isMedium) { return GridView( padding: const EdgeInsets.symmetric(horizontal: 50), shrinkWrap: true, @@ -127,10 +133,11 @@ class WallSensorControls extends StatelessWidget with HelperResponsiveLayout { maxValue: 10000, steps: 1, description: 'hr', - action: (int value) => context.read().add(WallSensorChangeValueEvent( - code: 'no_one_time', - value: value, - ))), + action: (int value) => + context.read().add(WallSensorChangeValueEvent( + code: 'no_one_time', + value: value, + ))), PresenceUpdateData( value: model.farDetection.toDouble(), title: 'Far Detection:', @@ -147,9 +154,8 @@ class WallSensorControls extends StatelessWidget with HelperResponsiveLayout { ), GestureDetector( onTap: () { - context - .read() - .add(GetDeviceReportsEvent(code: 'illuminance_value', deviceUuid: device.uuid!)); + context.read().add(GetDeviceReportsEvent( + code: 'illuminance_value', deviceUuid: device.uuid!)); }, child: const PresenceStaticWidget( icon: Assets.illuminanceRecordIcon, @@ -158,9 +164,8 @@ class WallSensorControls extends StatelessWidget with HelperResponsiveLayout { ), GestureDetector( onTap: () { - context - .read() - .add(GetDeviceReportsEvent(code: 'presence_state', deviceUuid: device.uuid!)); + context.read().add(GetDeviceReportsEvent( + code: 'presence_state', deviceUuid: device.uuid!)); }, child: const PresenceStaticWidget( icon: Assets.presenceRecordIcon, diff --git a/lib/web_layout/web_app_bar.dart b/lib/web_layout/web_app_bar.dart index e63a329a..69f88f09 100644 --- a/lib/web_layout/web_app_bar.dart +++ b/lib/web_layout/web_app_bar.dart @@ -74,19 +74,16 @@ class WebAppBar extends StatelessWidget with HelperResponsiveLayout { mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Align( - alignment: Alignment.centerLeft, - child: Expanded( - child: Row( - children: [ - title!, - if (centerBody != null) - Padding( - padding: const EdgeInsets.only(left: 80), - child: centerBody!, - ), - ], - ), + Expanded( + child: Row( + children: [ + title!, + if (centerBody != null) + Padding( + padding: const EdgeInsets.only(left: 80), + child: centerBody!, + ), + ], ), ), Row( From 2339417c8c760f88cd6740752b79c9c3e61f28a6 Mon Sep 17 00:00:00 2001 From: ashrafzarkanisala Date: Mon, 2 Sep 2024 22:36:11 +0300 Subject: [PATCH 014/158] space type connection --- lib/pages/auth/bloc/auth_bloc.dart | 1 + .../ceiling_sensor/bloc/bloc.dart | 10 +++- .../model/ceiling_sensor_model.dart | 30 +++++++++-- .../view/ceiling_sensor_controls.dart | 13 +++-- .../sensors_widgets/presence_space_type.dart | 54 ++++++++++++------- 5 files changed, 77 insertions(+), 31 deletions(-) diff --git a/lib/pages/auth/bloc/auth_bloc.dart b/lib/pages/auth/bloc/auth_bloc.dart index a08cd0d3..ef433028 100644 --- a/lib/pages/auth/bloc/auth_bloc.dart +++ b/lib/pages/auth/bloc/auth_bloc.dart @@ -158,6 +158,7 @@ class AuthBloc extends Bloc { user = UserModel.fromToken(token); loginEmailController.clear(); loginPasswordController.clear(); + debugPrint("token " + token.accessToken); emit(LoginSuccess()); } else { emit(const LoginFailure(error: 'Something went wrong')); diff --git a/lib/pages/device_managment/ceiling_sensor/bloc/bloc.dart b/lib/pages/device_managment/ceiling_sensor/bloc/bloc.dart index fe928c94..570c1e9c 100644 --- a/lib/pages/device_managment/ceiling_sensor/bloc/bloc.dart +++ b/lib/pages/device_managment/ceiling_sensor/bloc/bloc.dart @@ -62,16 +62,19 @@ class CeilingSensorBloc extends Bloc { deviceStatus.noBodyTime = event.value; } else if (event.code == 'moving_max_dis') { deviceStatus.maxDistance = event.value; + } else if (event.code == 'scene') { + deviceStatus.spaceType = getSpaceType(event.value); } emit(CeilingUpdateState(ceilingSensorModel: deviceStatus)); await _runDeBouncer( - deviceId: deviceId, code: event.code, value: event.value); + deviceId: deviceId, code: event.code, value: event.value, emit: emit); } _runDeBouncer({ required String deviceId, required String code, required dynamic value, + required Emitter emit, }) { if (_timer != null) { _timer!.cancel(); @@ -84,6 +87,11 @@ class CeilingSensorBloc extends Bloc { if (!response) { add(CeilingInitialEvent()); } + if (response == true && code == 'scene') { + emit(CeilingLoadingInitialState()); + await Future.delayed(const Duration(seconds: 1)); + add(CeilingInitialEvent()); + } } catch (_) { await Future.delayed(const Duration(milliseconds: 500)); add(CeilingInitialEvent()); diff --git a/lib/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart b/lib/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart index 528de1e6..a79cbc19 100644 --- a/lib/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart +++ b/lib/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart @@ -10,7 +10,7 @@ class CeilingSensorModel { String bodyMovement; String noBodyTime; int maxDistance; - String spaceType; + SpaceTypes spaceType; CeilingSensorModel({ required this.presenceState, @@ -33,7 +33,7 @@ class CeilingSensorModel { String _bodyMovement = 'none'; String _noBodyTime = 'none'; int _maxDis = 0; - String _spaceType = 'none'; + SpaceTypes _spaceType = SpaceTypes.none; try { for (var status in jsonList) { @@ -42,7 +42,7 @@ class CeilingSensorModel { _presenceState = status.value ?? 'none'; break; case 'scene': - _spaceType = status.value ?? 'none'; + _spaceType = getSpaceType(status.value ?? 'none'); break; case 'sensitivity': _sensitivity = status.value is int @@ -92,3 +92,27 @@ class CeilingSensorModel { ); } } + +enum SpaceTypes { + none, + parlour, + area, + toilet, + bedroom, +} + +SpaceTypes getSpaceType(String value) { + switch (value) { + case 'parlour': + return SpaceTypes.parlour; + case 'area': + return SpaceTypes.area; + case 'toilet': + return SpaceTypes.toilet; + case 'bedroom': + return SpaceTypes.bedroom; + case 'none': + default: + return SpaceTypes.none; + } +} diff --git a/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart b/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart index 4c00dd69..bf24ae0f 100644 --- a/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart +++ b/lib/pages/device_managment/ceiling_sensor/view/ceiling_sensor_controls.dart @@ -99,15 +99,14 @@ class CeilingSensorControls extends StatelessWidget description: 'Detection Range', ), PresenceSpaceType( - listOfIcons: const [ - Assets.office, - Assets.parlour, - Assets.dyi, - Assets.bathroom, - Assets.bedroom, - ], description: 'Space Type', value: model.spaceType, + action: (String value) => context.read().add( + CeilingChangeValueEvent( + code: 'scene', + value: value, + ), + ), ), PresenceUpdateData( value: model.sensitivity.toDouble(), diff --git a/lib/pages/device_managment/shared/sensors_widgets/presence_space_type.dart b/lib/pages/device_managment/shared/sensors_widgets/presence_space_type.dart index 5b14452a..2f593abe 100644 --- a/lib/pages/device_managment/shared/sensors_widgets/presence_space_type.dart +++ b/lib/pages/device_managment/shared/sensors_widgets/presence_space_type.dart @@ -1,24 +1,33 @@ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/extension/build_context_x.dart'; import 'package:syncrow_web/pages/device_managment/shared/device_controls_container.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/pages/device_managment/ceiling_sensor/model/ceiling_sensor_model.dart'; class PresenceSpaceType extends StatelessWidget { const PresenceSpaceType({ super.key, - required this.listOfIcons, required this.description, required this.value, + required this.action, }); - final List listOfIcons; final String description; - final String value; + final SpaceTypes value; + final void Function(String value) action; @override Widget build(BuildContext context) { + final Map spaceTypeIcons = { + SpaceTypes.none: Assets.office, + SpaceTypes.parlour: Assets.parlour, + SpaceTypes.area: Assets.dyi, + SpaceTypes.toilet: Assets.bathroom, + SpaceTypes.bedroom: Assets.bedroom, + }; + return DeviceControlsContainer( child: Column( mainAxisSize: MainAxisSize.min, @@ -38,23 +47,28 @@ class PresenceSpaceType extends StatelessWidget { Wrap( runSpacing: 8, spacing: 16, - children: [ - ...listOfIcons.map((icon) => Container( - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(100), - border: Border.all( - color: icon.contains(value) - ? ColorsManager.blueColor - : Colors.transparent, - ), + children: spaceTypeIcons.entries.map((entry) { + final icon = entry.value; + final spaceType = entry.key; + return GestureDetector( + onTap: () => action(spaceType.name), + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(100), + border: Border.all( + color: value == spaceType + ? ColorsManager.blueColor + : Colors.transparent, ), - child: SvgPicture.asset( - icon, - width: 40, - height: 40, - ), - )), - ], + ), + child: SvgPicture.asset( + icon, + width: 40, + height: 40, + ), + ), + ); + }).toList(), ), ], ), From 8130acc392a7e5483656e74f58fdc1b1c2ae52ae Mon Sep 17 00:00:00 2001 From: mohammad Date: Tue, 3 Sep 2024 08:58:48 +0300 Subject: [PATCH 015/158] login Enhancements and add search to forget password --- .../auth/view/forget_password_web_page.dart | 145 +++++++++++++----- lib/pages/auth/view/login_web_page.dart | 126 +++------------ 2 files changed, 128 insertions(+), 143 deletions(-) diff --git a/lib/pages/auth/view/forget_password_web_page.dart b/lib/pages/auth/view/forget_password_web_page.dart index dd930779..5208a6b3 100644 --- a/lib/pages/auth/view/forget_password_web_page.dart +++ b/lib/pages/auth/view/forget_password_web_page.dart @@ -1,3 +1,4 @@ +import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; @@ -148,44 +149,7 @@ class ForgetPasswordWebPage extends StatelessWidget { ), const SizedBox(height: 10), SizedBox( - child: DropdownButtonFormField( - validator: forgetBloc.validateRegion, - icon: const Icon( - Icons.keyboard_arrow_down_outlined, - ), - decoration: - textBoxDecoration()!.copyWith( - hintText: null, - ), - hint: SizedBox( - width: size.width * 0.12, - child: const Align( - alignment: Alignment.centerLeft, - child: Text( - 'Select your region/country', - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - ), - ), - ), - isDense: true, - style: const TextStyle( - color: Colors.black), - items: forgetBloc.regionList! - .map((RegionModel region) { - return DropdownMenuItem( - value: region.id, - child: SizedBox( - width: size.width * 0.06, - child: Text(region.name)), - ); - }).toList(), - onChanged: (String? value) { - forgetBloc.add(SelectRegionEvent( - val: value!, - )); - }, - ), + child: _buildDropdownField(context, forgetBloc, size) ) ], ), @@ -411,4 +375,109 @@ class ForgetPasswordWebPage extends StatelessWidget { ), )); } + Widget _buildDropdownField( + BuildContext context, AuthBloc loginBloc, Size size) { + final TextEditingController textEditingController = TextEditingController(); + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text( + "Country/Region", + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontSize: 14, + fontWeight: FontWeight.w400, + ), + ), + const SizedBox(height: 10), + Container( + height: 50, + decoration: const BoxDecoration( + color: ColorsManager.boxColor, + borderRadius: BorderRadius.all(Radius.circular(8)), + ), + width: size.width * 0.9, + child: DropdownButtonHideUnderline( + child: DropdownButton2( + style: TextStyle(color: Colors.black), + isExpanded: true, + hint: Text( + 'Select your region/country', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor, + fontWeight: FontWeight.w400, + ), + overflow: TextOverflow.ellipsis, + ), + items: loginBloc.regionList!.map((RegionModel region) { + return DropdownMenuItem( + value: region.id, // Use region.id as the value + child: Text( + region.name, + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + ); + }).toList(), + value: loginBloc.regionList!.any( + (region) => region.id == loginBloc.regionUuid,) + ? loginBloc.regionUuid + : null, + onChanged: (String? value) { + if (value != null) { + + loginBloc.add(SelectRegionEvent( + val: value, + )); + } + }, + buttonStyleData: const ButtonStyleData( + padding: EdgeInsets.symmetric(horizontal: 16), + height: 40, + width: double.infinity, + ), + dropdownStyleData: DropdownStyleData( + maxHeight: size.height * 0.70, + ), + menuItemStyleData: const MenuItemStyleData( + height: 40, + ), + dropdownSearchData: DropdownSearchData( + searchController: textEditingController, + searchInnerWidgetHeight: 50, + searchInnerWidget: Container( + height: 50, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + child: TextFormField( + style: const TextStyle(color: Colors.black), + controller: textEditingController, + decoration: textBoxDecoration()!.copyWith( + errorStyle: const TextStyle(height: 0), + contentPadding: const EdgeInsets.symmetric( + vertical: 12, + horizontal: 10, + ), + ), + ), + ), + searchMatchFn: (item, searchValue) { + // Use the item's child text (region name) for searching. + final regionName = (item.child as Text).data?.toLowerCase() ?? ''; + final search = searchValue.toLowerCase().trim(); + // Debugging print statement to ensure values are captured correctly. + // Return true if the region name contains the search term. + return regionName.contains(search); + }, + ), + onMenuStateChange: (isOpen) { + if (!isOpen) { + textEditingController.clear(); + } + }, + ), + ), + ), + ], + ); + } } diff --git a/lib/pages/auth/view/login_web_page.dart b/lib/pages/auth/view/login_web_page.dart index 13492c45..af211308 100644 --- a/lib/pages/auth/view/login_web_page.dart +++ b/lib/pages/auth/view/login_web_page.dart @@ -181,87 +181,6 @@ class _LoginWebPageState extends State ); } - // Widget _buildDropdownField(BuildContext context, AuthBloc loginBloc, Size size) { - // return Column( - // crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisAlignment: MainAxisAlignment.start, - // children: [ - // Text( - // "Country/Region", - // style: Theme.of(context) - // .textTheme - // .bodySmall! - // .copyWith(fontSize: 14, fontWeight: FontWeight.w400), - // ), - // const SizedBox(height: 10), - // SizedBox( - // width: size.width * 0.8, - // child: LayoutBuilder( - // builder: (context, constraints) { - // return DropdownButtonFormField( - // value: loginBloc.regionList!.any((region) => region.id == loginBloc.regionUuid) - // ? loginBloc.regionUuid - // : null, - // validator: loginBloc.validateRegion, - // icon: const Icon( - // Icons.keyboard_arrow_down_outlined, - // size: 20, - // ), - // decoration: textBoxDecoration()!.copyWith( - // errorStyle: const TextStyle(height: 0), - // contentPadding: const EdgeInsets.symmetric( - // vertical: 12, - // horizontal: 10, - // ), - // ), - // hint: Text( - // 'Select your region/country', - // style: Theme.of(context) - // .textTheme - // .bodySmall! - // .copyWith(color: ColorsManager.grayColor, fontWeight: FontWeight.w400), - // overflow: TextOverflow.ellipsis, - // ), - // isDense: true, - // style: const TextStyle(color: Colors.black), - // items: loginBloc.regionList!.map((RegionModel region) { - // return DropdownMenuItem( - // value: region.id, - // child: Container( - // constraints: BoxConstraints(maxWidth: constraints.maxWidth - 40), - // child: Text( - // region.name, - // overflow: TextOverflow.ellipsis, - // maxLines: 1, - // ), - // ), - // ); - // }).toList(), - // onChanged: (String? value) { - // loginBloc.add(CheckEnableEvent()); - // loginBloc.add(SelectRegionEvent(val: value!)); - // }, - // dropdownColor: Colors.white, - // menuMaxHeight: size.height * 0.45, - // selectedItemBuilder: (context) { - // return loginBloc.regionList!.map((region) { - // return Container( - // constraints: BoxConstraints(maxWidth: constraints.maxWidth - 40), - // child: Text( - // region.name, - // overflow: TextOverflow.ellipsis, - // maxLines: 1, - // ), - // ); - // }).toList(); - // }, - // ); - // }, - // ), - // ), - // ], - // ); - // } Widget _buildDropdownField( BuildContext context, AuthBloc loginBloc, Size size) { @@ -273,31 +192,33 @@ class _LoginWebPageState extends State Text( "Country/Region", style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontSize: 14, - fontWeight: FontWeight.w400, - ), + fontSize: 14, + fontWeight: FontWeight.w400, + ), ), const SizedBox(height: 10), Container( - height: size.height * 0.05, - decoration:const BoxDecoration( - color: ColorsManager.boxColor, - borderRadius: BorderRadius.all(Radius.circular(8))), + height: 50, + decoration: const BoxDecoration( + color: ColorsManager.boxColor, + borderRadius: BorderRadius.all(Radius.circular(8)), + ), width: size.width * 0.9, child: DropdownButtonHideUnderline( child: DropdownButton2( + style: TextStyle(color: Colors.black), isExpanded: true, hint: Text( 'Select your region/country', style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: ColorsManager.grayColor, - fontWeight: FontWeight.w400, - ), + color: ColorsManager.grayColor, + fontWeight: FontWeight.w400, + ), overflow: TextOverflow.ellipsis, ), items: loginBloc.regionList!.map((RegionModel region) { return DropdownMenuItem( - value: region.id, + value: region.id, // Use region.id as the value child: Text( region.name, overflow: TextOverflow.ellipsis, @@ -306,8 +227,7 @@ class _LoginWebPageState extends State ); }).toList(), value: loginBloc.regionList!.any( - (region) => region.id == loginBloc.regionUuid, - ) + (region) => region.id == loginBloc.regionUuid,) ? loginBloc.regionUuid : null, onChanged: (String? value) { @@ -322,7 +242,7 @@ class _LoginWebPageState extends State width: double.infinity, ), dropdownStyleData: DropdownStyleData( - maxHeight: size.height * 0.45, + maxHeight: size.height * 0.70, ), menuItemStyleData: const MenuItemStyleData( height: 40, @@ -334,7 +254,7 @@ class _LoginWebPageState extends State height: 50, padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), child: TextFormField( - style: TextStyle(color: Colors.black), + style: const TextStyle(color: Colors.black), controller: textEditingController, decoration: textBoxDecoration()!.copyWith( errorStyle: const TextStyle(height: 0), @@ -345,19 +265,14 @@ class _LoginWebPageState extends State ), ), ), - searchMatchFn: (item, searchValue) { - // Ensure both item value and search value are compared in lowercase for a case-insensitive match. - final itemValue = item.value?.toLowerCase() ?? ''; + // Use the item's child text (region name) for searching. + final regionName = (item.child as Text).data?.toLowerCase() ?? ''; final search = searchValue.toLowerCase().trim(); - // Debugging print statement to ensure values are captured correctly. - print('searchValue == $search'); - - // Return true if the item value contains the search term. - return itemValue.contains(search); + // Return true if the region name contains the search term. + return regionName.contains(search); }, - ), onMenuStateChange: (isOpen) { if (!isOpen) { @@ -371,6 +286,7 @@ class _LoginWebPageState extends State ); } + Widget _buildEmailField(BuildContext context, AuthBloc loginBloc) { return Column( crossAxisAlignment: CrossAxisAlignment.start, From 6ba0a70289c47121a367e9dba9a8321ffde6a087 Mon Sep 17 00:00:00 2001 From: mohammad Date: Tue, 3 Sep 2024 09:03:01 +0300 Subject: [PATCH 016/158] login Enhancements and add search to forget password --- .../auth/view/forget_password_web_page.dart | 40 +++++++++---------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/lib/pages/auth/view/forget_password_web_page.dart b/lib/pages/auth/view/forget_password_web_page.dart index 5208a6b3..efc580b3 100644 --- a/lib/pages/auth/view/forget_password_web_page.dart +++ b/lib/pages/auth/view/forget_password_web_page.dart @@ -172,11 +172,12 @@ class ForgetPasswordWebPage extends StatelessWidget { SizedBox( child: TextFormField( validator: forgetBloc.validateEmail, - controller: - forgetBloc.forgetEmailController, decoration: textBoxDecoration()! .copyWith( - hintText: 'Enter your email'), + hintText: 'Enter your email', + hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor, + fontWeight: FontWeight.w400)), style: const TextStyle( color: Colors.black), ), @@ -208,13 +209,15 @@ class ForgetPasswordWebPage extends StatelessWidget { decoration: textBoxDecoration()!.copyWith( hintText: 'Enter Code', + 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.isButtonEnabled && state.remainingTime != 1 ? null @@ -225,10 +228,8 @@ class ForgetPasswordWebPage extends StatelessWidget { child: Text( 'Get Code ${state is TimerState && !state.isButtonEnabled && state.remainingTime != 1 ? "(${forgetBloc.formattedTime(state.remainingTime)}) " : ""}', style: TextStyle( - color: state - is TimerState && - !state - .isButtonEnabled + color: state is TimerState && + !state.isButtonEnabled ? Colors.grey : ColorsManager .btnColor, @@ -242,8 +243,7 @@ class ForgetPasswordWebPage extends StatelessWidget { color: Colors.black), ), ), - if (forgetBloc.forgetValidate != - '') // Check if there is a validation message + if (forgetBloc.forgetValidate != '') // Check if there is a validation message Padding( padding: const EdgeInsets.only(top: 8.0), @@ -275,18 +275,16 @@ class ForgetPasswordWebPage extends StatelessWidget { const SizedBox(height: 10), SizedBox( child: TextFormField( - validator: - forgetBloc.passwordValidator, - keyboardType: - TextInputType.visiblePassword, - controller: forgetBloc - .forgetPasswordController, - decoration: - textBoxDecoration()!.copyWith( + validator: forgetBloc.passwordValidator, + keyboardType: TextInputType.visiblePassword, + controller: forgetBloc.forgetPasswordController, + decoration: textBoxDecoration()!.copyWith( hintText: 'At least 8 characters', + hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor, + fontWeight: FontWeight.w400), ), - style: const TextStyle( - color: Colors.black), + style: const TextStyle(color: Colors.black), ), ), ], From a100b5c40ed4af12ecb64ad0a6da41b619cf7179 Mon Sep 17 00:00:00 2001 From: mohammad Date: Tue, 3 Sep 2024 09:12:01 +0300 Subject: [PATCH 017/158] login Enhancements and add search to forget password --- lib/pages/home/bloc/home_bloc.dart | 1 - lib/services/access_mang_api.dart | 9 --------- lib/services/auth_api.dart | 4 ---- lib/services/home_api.dart | 1 - 4 files changed, 15 deletions(-) diff --git a/lib/pages/home/bloc/home_bloc.dart b/lib/pages/home/bloc/home_bloc.dart index 1de54eff..79579efc 100644 --- a/lib/pages/home/bloc/home_bloc.dart +++ b/lib/pages/home/bloc/home_bloc.dart @@ -43,7 +43,6 @@ class HomeBloc extends Bloc { try { var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey); user = await HomeApi().fetchUserInfo(uuid); - } catch (e) { return; } diff --git a/lib/services/access_mang_api.dart b/lib/services/access_mang_api.dart index 68ea4f8d..b99b75a9 100644 --- a/lib/services/access_mang_api.dart +++ b/lib/services/access_mang_api.dart @@ -22,7 +22,6 @@ class AccessMangApi { ); return response; } catch (e) { - debugPrint('Error fetching visitor passwords: $e'); return []; } } @@ -42,7 +41,6 @@ class AccessMangApi { ); return response; } catch (e) { - debugPrint('Error fetching $e'); return []; } } @@ -123,13 +121,6 @@ class AccessMangApi { String? effectiveTime, String? invalidTime, List? devicesUuid}) async { - print('object=== ${ jsonEncode({ - "email": email, - "devicesUuid": devicesUuid, - "passwordName": passwordName, - "effectiveTime": effectiveTime, - "invalidTime": invalidTime, - })}'); final response = await HTTPService().post( path: ApiEndpoints.sendOffLineMultipleTime, body: jsonEncode({ diff --git a/lib/services/auth_api.dart b/lib/services/auth_api.dart index 844689df..a09fa7ba 100644 --- a/lib/services/auth_api.dart +++ b/lib/services/auth_api.dart @@ -26,7 +26,6 @@ class AuthenticationAPI { body: {"email": email, "password": password}, showServerMessage: true, expectedResponseModel: (json) { - print('json=$json'); }); return response; } @@ -54,15 +53,12 @@ class AuthenticationAPI { return cooldown; } } else { - debugPrint('Error: ${e.response!.statusCode} - ${e.response!.statusMessage}'); return 1; } } else { - debugPrint('Error: ${e.message}'); return 1; } } catch (e) { - debugPrint('Unexpected Error: $e'); return 1; } } diff --git a/lib/services/home_api.dart b/lib/services/home_api.dart index 000d4ff2..dfbaf4bf 100644 --- a/lib/services/home_api.dart +++ b/lib/services/home_api.dart @@ -8,7 +8,6 @@ class HomeApi { path: ApiEndpoints.getUser.replaceAll('{userUuid}', userId!), showServerMessage: true, expectedResponseModel: (json) { - print('fetchUserInfo$json'); return UserModel.fromJson(json); }); return response; From 439ce85117231c0d1c8ffcda992ddb08ec60d39c Mon Sep 17 00:00:00 2001 From: mohammad Date: Tue, 3 Sep 2024 09:50:36 +0300 Subject: [PATCH 018/158] delete dynamic password --- .../view/visitor_password_dialog.dart | 151 ++++++++++-------- 1 file changed, 81 insertions(+), 70 deletions(-) diff --git a/lib/pages/visitor_password/view/visitor_password_dialog.dart b/lib/pages/visitor_password/view/visitor_password_dialog.dart index 5fc82dbf..cb93cb40 100644 --- a/lib/pages/visitor_password/view/visitor_password_dialog.dart +++ b/lib/pages/visitor_password/view/visitor_password_dialog.dart @@ -212,28 +212,28 @@ class VisitorPasswordDialog extends StatelessWidget { }, ), ), - SizedBox( - width: size.width * 0.12, - child: RadioListTile( - contentPadding: EdgeInsets.zero, - title: Text( - 'Dynamic Password', - style: text, - ), - value: 'Dynamic Password', - groupValue: (state is PasswordTypeSelected) - ? state.selectedType - : visitorBloc.accessTypeSelected, - onChanged: (String? value) { - if (value != null) { - context - .read() - .add(SelectPasswordType(value)); - visitorBloc.usageFrequencySelected = ''; - } - }, - ), - ), + // SizedBox( + // width: size.width * 0.12, + // child: RadioListTile( + // contentPadding: EdgeInsets.zero, + // title: Text( + // 'Dynamic Password', + // style: text, + // ), + // value: 'Dynamic Password', + // groupValue: (state is PasswordTypeSelected) + // ? state.selectedType + // : visitorBloc.accessTypeSelected, + // onChanged: (String? value) { + // if (value != null) { + // context + // .read() + // .add(SelectPasswordType(value)); + // visitorBloc.usageFrequencySelected = ''; + // } + // }, + // ), + // ), ], )), const Spacer( @@ -257,14 +257,14 @@ class VisitorPasswordDialog extends StatelessWidget { color: ColorsManager.grayColor, fontSize: 9), ), - if (visitorBloc.accessTypeSelected == 'Dynamic Password') - Text( - 'Quick and short-acting password, only valid within 5 minutes after creation, the system randomly generates a digital password.', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.w400, - color: ColorsManager.grayColor, - fontSize: 9), - ), + // if (visitorBloc.accessTypeSelected == 'Dynamic Password') + // Text( + // 'Quick and short-acting password, only valid within 5 minutes after creation, the system randomly generates a digital password.', + // style: Theme.of(context).textTheme.bodySmall!.copyWith( + // fontWeight: FontWeight.w400, + // color: ColorsManager.grayColor, + // fontSize: 9), + // ), const SizedBox( height: 20, ) @@ -524,9 +524,20 @@ class VisitorPasswordDialog extends StatelessWidget { if (visitorBloc.usageFrequencySelected == 'One-Time' && visitorBloc.accessTypeSelected == 'Offline Password') { setPasswordFunction(context, size, visitorBloc); - } else if (visitorBloc.accessTypeSelected == 'Dynamic Password') { - setPasswordFunction(context, size, visitorBloc); - } else if(visitorBloc.endTimeAccess.toString()!='End Time'&&visitorBloc.startTimeAccess.toString()!='Start Time') { + } else if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Offline Password') { + if (visitorBloc.expirationTime != 'End Time' && + visitorBloc.effectiveTime != 'Start Time' ) { + setPasswordFunction(context, size, visitorBloc); + }else{ + visitorBloc.stateDialog( + context: context, + message: 'Please select Access Period to continue', + title: 'Access Period'); + } + } else if( + visitorBloc.endTimeAccess.toString()!='End Time' + &&visitorBloc.startTimeAccess.toString()!='Start Time') { if (visitorBloc.effectiveTimeTimeStamp != null && visitorBloc.expirationTimeTimeStamp != null) { if (isRepeat == true) { @@ -551,10 +562,10 @@ class VisitorPasswordDialog extends StatelessWidget { title: 'Access Period'); } }else{ - visitorBloc.stateDialog( - context: context, - message: 'Please select Access Period to continue', - title: 'Access Period'); + visitorBloc.stateDialog( + context: context, + message: 'Please select Access Period to continue', + title: 'Access Period'); } } else { visitorBloc.stateDialog( @@ -724,39 +735,39 @@ class VisitorPasswordDialog extends StatelessWidget { borderRadius: 8, onPressed: () { Navigator.pop(context); - if (visitorBloc.accessTypeSelected == 'Dynamic Password') { - } else { - if (visitorBloc.usageFrequencySelected == 'One-Time' && - visitorBloc.accessTypeSelected == 'Online Password') { - visitorBloc.add(OnlineOneTimePasswordEvent( - context: context, - passwordName: visitorBloc.userNameController.text, - email: visitorBloc.emailController.text, - )); - } else if (visitorBloc.usageFrequencySelected == 'Periodic' && - visitorBloc.accessTypeSelected == 'Online Password') { - visitorBloc.add(OnlineMultipleTimePasswordEvent( - passwordName: visitorBloc.userNameController.text, - email: visitorBloc.emailController.text, - effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(), - invalidTime: visitorBloc.expirationTimeTimeStamp.toString(), - )); - } else if (visitorBloc.usageFrequencySelected == 'One-Time' && - visitorBloc.accessTypeSelected == 'Offline Password') { - visitorBloc.add(OfflineOneTimePasswordEvent( - context: context, - passwordName: visitorBloc.userNameController.text, - email: visitorBloc.emailController.text, - )); - } else if (visitorBloc.usageFrequencySelected == 'Periodic' && - visitorBloc.accessTypeSelected == 'Offline Password') { - visitorBloc.add(OfflineMultipleTimePasswordEvent( - passwordName: visitorBloc.userNameController.text, - email: visitorBloc.emailController.text, - effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(), - invalidTime: visitorBloc.expirationTimeTimeStamp.toString(), - )); - } + if (visitorBloc.usageFrequencySelected == 'One-Time' && + visitorBloc.accessTypeSelected == 'Online Password') { + visitorBloc.add(OnlineOneTimePasswordEvent( + context: context, + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text, + )); + } + else if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Online Password') { + visitorBloc.add(OnlineMultipleTimePasswordEvent( + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text, + effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(), + invalidTime: visitorBloc.expirationTimeTimeStamp.toString(), + )); + } + else if (visitorBloc.usageFrequencySelected == 'One-Time' && + visitorBloc.accessTypeSelected == 'Offline Password') { + visitorBloc.add(OfflineOneTimePasswordEvent( + context: context, + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text, + )); + } + else if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Offline Password') { + visitorBloc.add(OfflineMultipleTimePasswordEvent( + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text, + effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(), + invalidTime: visitorBloc.expirationTimeTimeStamp.toString(), + )); } }, child: Text( From 3a254bce4d46f840fb89a035fec512d9b9871d00 Mon Sep 17 00:00:00 2001 From: mohammad Date: Tue, 3 Sep 2024 09:51:55 +0300 Subject: [PATCH 019/158] delete dynamic password --- .../view/visitor_password_dialog.dart | 51 ------------------- 1 file changed, 51 deletions(-) diff --git a/lib/pages/visitor_password/view/visitor_password_dialog.dart b/lib/pages/visitor_password/view/visitor_password_dialog.dart index cb93cb40..ad11b30f 100644 --- a/lib/pages/visitor_password/view/visitor_password_dialog.dart +++ b/lib/pages/visitor_password/view/visitor_password_dialog.dart @@ -575,57 +575,6 @@ class VisitorPasswordDialog extends StatelessWidget { } } }, - - // onPressed: () { - // if (visitorBloc.forgetFormKey.currentState!.validate()) { - // if (visitorBloc.selectedDevices.isNotEmpty) { - // switch (visitorBloc.usageFrequencySelected) { - // case 'One-Time': - // if (visitorBloc.accessTypeSelected == 'Offline Password') { - // setPasswordFunction(context, size, visitorBloc); - // } else { - // visitorBloc.stateDialog( - // context: context, - // message: 'Invalid combination of Access Type and Usage Frequency.', - // title: 'Error', - // ); - // } - // break; - // default: - // if (visitorBloc.effectiveTimeTimeStamp != null && visitorBloc.expirationTimeTimeStamp != null) { - // if (isRepeat) { - // if (visitorBloc.expirationTime != 'End Time' && - // visitorBloc.effectiveTime != 'Start Time' && - // visitorBloc.selectedDays.isNotEmpty) { - // setPasswordFunction(context, size, visitorBloc); - // } else { - // visitorBloc.stateDialog( - // context: context, - // message: 'Please select days and fill start time and end time to continue', - // title: 'Access Period', - // ); - // } - // } else { - // setPasswordFunction(context, size, visitorBloc); - // } - // } else { - // visitorBloc.stateDialog( - // context: context, - // message: 'Please select Access Period to continue', - // title: 'Access Period', - // ); - // } - // break; - // } - // } else { - // visitorBloc.stateDialog( - // context: context, - // message: 'Please select devices to continue', - // title: 'Select Devices', - // ); - // } - // } - // }, borderRadius: 8, child: Text( 'Ok', From ea256c4f51303449e650a68c21804f587bbb1fe4 Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:55:30 +0300 Subject: [PATCH 020/158] ci: add Azure Static Web Apps workflow file on-behalf-of: @Azure opensource@microsoft.com --- ...atic-web-apps-agreeable-wave-096d61a10.yml | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml diff --git a/.github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml b/.github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml new file mode 100644 index 00000000..a1fe5d8e --- /dev/null +++ b/.github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml @@ -0,0 +1,46 @@ +name: Azure Static Web Apps CI/CD + +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened, closed] + branches: + - main + +jobs: + build_and_deploy_job: + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') + runs-on: ubuntu-latest + name: Build and Deploy Job + steps: + - uses: actions/checkout@v3 + with: + submodules: true + lfs: false + - name: Build And Deploy + id: builddeploy + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AGREEABLE_WAVE_096D61A10 }} + repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) + action: "upload" + ###### Repository/Build Configurations - These values can be configured to match your app requirements. ###### + # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig + app_location: "/web" # App source code path + api_location: "" # Api source code path - optional + output_location: "/web" # Built app content directory - optional + ###### End of Repository/Build Configurations ###### + + close_pull_request_job: + if: github.event_name == 'pull_request' && github.event.action == 'closed' + runs-on: ubuntu-latest + name: Close Pull Request Job + steps: + - name: Close Pull Request + id: closepullrequest + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AGREEABLE_WAVE_096D61A10 }} + action: "close" From 7a32ad78787b211aa2cdd8c796ca4b1be2a8057b Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:00:09 +0300 Subject: [PATCH 021/158] staging deployed --- ...atic-web-apps-agreeable-wave-096d61a10.yml | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/.github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml b/.github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml index a1fe5d8e..86bf0c5d 100644 --- a/.github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml +++ b/.github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml @@ -15,22 +15,36 @@ jobs: runs-on: ubuntu-latest name: Build and Deploy Job steps: - - uses: actions/checkout@v3 + + - name: Checkout Code + uses: actions/checkout@v3 with: submodules: true lfs: false + + - name: Set up Flutter + uses: subosito/flutter-action@v2 + with: + flutter-version: '3.22.2' # Specify the Flutter version you want to use + + - name: Install dependencies + run: flutter pub get + + - name: Build Flutter Web App + run: flutter build web + - name: Build And Deploy id: builddeploy uses: Azure/static-web-apps-deploy@v1 with: - azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AGREEABLE_WAVE_096D61A10 }} + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ZEALOUS_MUSHROOM_0D31A3303 }} repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) action: "upload" ###### Repository/Build Configurations - These values can be configured to match your app requirements. ###### # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig - app_location: "/web" # App source code path + app_location: "/build/web" # App source code path api_location: "" # Api source code path - optional - output_location: "/web" # Built app content directory - optional + output_location: "/build/web" # Built app content directory - optional ###### End of Repository/Build Configurations ###### close_pull_request_job: @@ -42,5 +56,5 @@ jobs: id: closepullrequest uses: Azure/static-web-apps-deploy@v1 with: - azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_AGREEABLE_WAVE_096D61A10 }} + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_ZEALOUS_MUSHROOM_0D31A3303 }} action: "close" From 040e678b1e7561824761b6785538df7298274651 Mon Sep 17 00:00:00 2001 From: ashrafzarkanisala Date: Tue, 3 Sep 2024 13:37:33 +0300 Subject: [PATCH 022/158] handle Lux description for illumnance sensor --- lib/pages/device_managment/shared/table/report_table.dart | 2 +- lib/pages/device_managment/wall_sensor/bloc/bloc.dart | 2 +- lib/pages/device_managment/wall_sensor/bloc/state.dart | 3 ++- .../wall_sensor/view/wall_sensor_conrtols.dart | 6 ++++-- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/pages/device_managment/shared/table/report_table.dart b/lib/pages/device_managment/shared/table/report_table.dart index ef189f3a..d655964b 100644 --- a/lib/pages/device_managment/shared/table/report_table.dart +++ b/lib/pages/device_managment/shared/table/report_table.dart @@ -58,7 +58,7 @@ class ReportsTable extends StatelessWidget { TableCellWidget(value: date), TableCellWidget(value: time), TableCellWidget( - value: '${data.value!} $thirdColumnDescription', + value: '${data.value!} ${thirdColumnDescription ?? ''}', onTap: () => onRowTap(index), ), ], diff --git a/lib/pages/device_managment/wall_sensor/bloc/bloc.dart b/lib/pages/device_managment/wall_sensor/bloc/bloc.dart index a2697cd3..bda4d968 100644 --- a/lib/pages/device_managment/wall_sensor/bloc/bloc.dart +++ b/lib/pages/device_managment/wall_sensor/bloc/bloc.dart @@ -99,7 +99,7 @@ class WallSensorBloc extends Bloc { try { await DevicesManagementApi.getDeviceReports(deviceId, event.code) .then((value) { - emit(DeviceReportsState(deviceReport: value)); + emit(DeviceReportsState(deviceReport: value, code:event.code)); }); } catch (e) { emit(DeviceReportsFailedState(error: e.toString())); diff --git a/lib/pages/device_managment/wall_sensor/bloc/state.dart b/lib/pages/device_managment/wall_sensor/bloc/state.dart index 67ce0d19..19a154a9 100644 --- a/lib/pages/device_managment/wall_sensor/bloc/state.dart +++ b/lib/pages/device_managment/wall_sensor/bloc/state.dart @@ -42,7 +42,8 @@ class DeviceReportsLoadingState extends WallSensorState {} class DeviceReportsState extends WallSensorState { final DeviceReport deviceReport; - const DeviceReportsState({required this.deviceReport}); + final String code; + const DeviceReportsState({required this.deviceReport, required this.code}); } class DeviceReportsFailedState extends WallSensorState { diff --git a/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart b/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart index 8448ef67..fce90593 100644 --- a/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart +++ b/lib/pages/device_managment/wall_sensor/view/wall_sensor_conrtols.dart @@ -38,8 +38,10 @@ class WallSensorControls extends StatelessWidget with HelperResponsiveLayout { } else if (state is DeviceReportsState) { return ReportsTable( report: state.deviceReport, - thirdColumnTitle: "Value", - thirdColumnDescription: "Lux", + thirdColumnTitle: + state.code == 'illuminance_value' ? "Value" : 'Status', + thirdColumnDescription: + state.code == 'illuminance_value' ? "Lux" : null, onRowTap: (index) {}, onClose: () { context.read().add(BackToGridViewEvent()); From 25b94570438b6f7d55ef296e5296cfc1a39c09f7 Mon Sep 17 00:00:00 2001 From: Abdullah Alassaf Date: Tue, 3 Sep 2024 13:41:07 +0300 Subject: [PATCH 023/158] Added env files and dotenv package --- .env.development | 2 + .env.production | 2 + .env.staging | 2 + .vscode/launch.json | 61 +++++++++++++++++++ lib/main.dart | 9 ++- .../space_management/spaseManagementIcon.dart | 16 ----- lib/utils/constants/api_const.dart | 48 +++++++-------- pubspec.lock | 8 +++ pubspec.yaml | 5 ++ 9 files changed, 108 insertions(+), 45 deletions(-) create mode 100644 .env.development create mode 100644 .env.production create mode 100644 .env.staging create mode 100644 .vscode/launch.json delete mode 100644 lib/pages/space_management/spaseManagementIcon.dart diff --git a/.env.development b/.env.development new file mode 100644 index 00000000..e77609dc --- /dev/null +++ b/.env.development @@ -0,0 +1,2 @@ +ENV_NAME=development +BASE_URL=https://syncrow-dev.azurewebsites.net \ No newline at end of file diff --git a/.env.production b/.env.production new file mode 100644 index 00000000..4e9dcb81 --- /dev/null +++ b/.env.production @@ -0,0 +1,2 @@ +ENV_NAME=production +BASE_URL=https://syncrow-staging.azurewebsites.net \ No newline at end of file diff --git a/.env.staging b/.env.staging new file mode 100644 index 00000000..9565b426 --- /dev/null +++ b/.env.staging @@ -0,0 +1,2 @@ +ENV_NAME=staging +BASE_URL=https://syncrow-staging.azurewebsites.net \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..b6f83bdc --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,61 @@ +{ + "configurations": [ + + { + + "name": "DEVELOPMENT", + + "request": "launch", + + "type": "dart", + + "args": [ + + "--dart-define", + + "FLAVOR=development" + + ], + + "flutterMode": "debug" + + },{ + + "name": "STAGING", + + "request": "launch", + + "type": "dart", + + "args": [ + + "--dart-define", + + "FLAVOR=staging" + + ], + + "flutterMode": "debug" + + },{ + + "name": "PRODUCTION", + + "request": "launch", + + "type": "dart", + + "args": [ + + "--dart-define", + + "FLAVOR=production" + + ], + + "flutterMode": "debug" + + }, + + ] +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index b4fcb72d..eeaa4685 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart'; import 'package:syncrow_web/pages/home/bloc/home_bloc.dart'; import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart'; @@ -11,8 +12,12 @@ import 'package:syncrow_web/utils/constants/routes_const.dart'; import 'package:syncrow_web/utils/theme/theme.dart'; Future main() async { - WidgetsFlutterBinding.ensureInitialized(); - initialSetup(); + try { + const environment = String.fromEnvironment('FLAVOR', defaultValue: 'production'); + await dotenv.load(fileName: '.env.$environment'); + WidgetsFlutterBinding.ensureInitialized(); + initialSetup(); + } catch (_) {} runApp(MyApp()); } diff --git a/lib/pages/space_management/spaseManagementIcon.dart b/lib/pages/space_management/spaseManagementIcon.dart deleted file mode 100644 index 510b90b9..00000000 --- a/lib/pages/space_management/spaseManagementIcon.dart +++ /dev/null @@ -1,16 +0,0 @@ - - - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; - -class SpaseManagementicon extends StatelessWidget { - const SpaseManagementicon({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Container(), - ); - } -} diff --git a/lib/utils/constants/api_const.dart b/lib/utils/constants/api_const.dart index 2d85a7f5..5d24b501 100644 --- a/lib/utils/constants/api_const.dart +++ b/lib/utils/constants/api_const.dart @@ -1,41 +1,35 @@ -abstract class ApiEndpoints { - static const String baseUrl = 'https://syncrow-dev.azurewebsites.net'; - // static const String baseUrl = 'http://100.107.182.63:4001'; //Localhost -//https://syncrow-staging.azurewebsites.net -////////////////////////////////////// Authentication /////////////////////////////// - static const String signUp = '$baseUrl/authentication/user/signup'; - static const String login = '$baseUrl/authentication/user/login'; - static const String forgetPassword = - '$baseUrl/authentication/user/forget-password'; - static const String sendOtp = '$baseUrl/authentication/user/send-otp'; - static const String verifyOtp = '$baseUrl/authentication/user/verify-otp'; - static const String getRegion = '$baseUrl/region'; - static const String visitorPassword = '$baseUrl/visitor-password'; - static const String getDevices = '$baseUrl/visitor-password/devices'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; - static const String sendOnlineOneTime = - '$baseUrl/visitor-password/temporary-password/online/one-time'; +abstract class ApiEndpoints { + static String baseUrl = dotenv.env['BASE_URL'] ?? ''; + static const String signUp = '/authentication/user/signup'; + static const String login = '/authentication/user/login'; + static const String forgetPassword = '/authentication/user/forget-password'; + static const String sendOtp = '/authentication/user/send-otp'; + static const String verifyOtp = '/authentication/user/verify-otp'; + static const String getRegion = '/region'; + static const String visitorPassword = '/visitor-password'; + static const String getDevices = '/visitor-password/devices'; + + static const String sendOnlineOneTime = '/visitor-password/temporary-password/online/one-time'; static const String sendOnlineMultipleTime = - '$baseUrl/visitor-password/temporary-password/online/multiple-time'; + '/visitor-password/temporary-password/online/multiple-time'; //offline Password - static const String sendOffLineOneTime = - '$baseUrl/visitor-password/temporary-password/offline/one-time'; + static const String sendOffLineOneTime = '/visitor-password/temporary-password/offline/one-time'; static const String sendOffLineMultipleTime = - '$baseUrl/visitor-password/temporary-password/offline/multiple-time'; + '/visitor-password/temporary-password/offline/multiple-time'; - static const String getUser = '$baseUrl/user/{userUuid}'; + static const String getUser = '/user/{userUuid}'; ////// Devices Management //////////////// - static const String getAllDevices = '$baseUrl/device'; - static const String getDeviceStatus = - '$baseUrl/device/{uuid}/functions/status'; + static const String getAllDevices = '/device'; + static const String getDeviceStatus = '/device/{uuid}/functions/status'; - static const String deviceControl = '$baseUrl/device/{uuid}/control'; + static const String deviceControl = '/device/{uuid}/control'; static const String gatewayApi = '/device/gateway/{gatewayUuid}/devices'; static const String openDoorLock = '/door-lock/open/{doorLockUuid}'; - static const String getDeviceLogs = - '$baseUrl/device/report-logs/{uuid}?code={code}'; + static const String getDeviceLogs = '/device/report-logs/{uuid}?code={code}'; } diff --git a/pubspec.lock b/pubspec.lock index 3da608f2..8b9df6d6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -150,6 +150,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.1.5" + flutter_dotenv: + dependency: "direct main" + description: + name: flutter_dotenv + sha256: "9357883bdd153ab78cbf9ffa07656e336b8bbb2b5a3ca596b0b27e119f7c7d77" + url: "https://pub.dev" + source: hosted + version: "5.1.0" flutter_lints: dependency: "direct dev" description: diff --git a/pubspec.yaml b/pubspec.yaml index ea0138ea..d187cf1a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -48,6 +48,8 @@ dependencies: go_router: intl: ^0.19.0 dropdown_search: ^5.0.6 + flutter_dotenv: ^5.1.0 + dev_dependencies: flutter_test: @@ -77,6 +79,9 @@ flutter: - assets/icons/ - assets/images/ - assets/ + - .env.development + - .env.staging + - .env.production # An image asset can refer to one or more resolution-specific "variants", see From 5a291ce9f8dd13ce05f68566baca5ab118c1cd98 Mon Sep 17 00:00:00 2001 From: Abdullah Alassaf Date: Tue, 3 Sep 2024 13:42:10 +0300 Subject: [PATCH 024/158] Changed the default env. file --- lib/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/main.dart b/lib/main.dart index eeaa4685..721a472b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -13,7 +13,7 @@ import 'package:syncrow_web/utils/theme/theme.dart'; Future main() async { try { - const environment = String.fromEnvironment('FLAVOR', defaultValue: 'production'); + const environment = String.fromEnvironment('FLAVOR', defaultValue: 'development'); await dotenv.load(fileName: '.env.$environment'); WidgetsFlutterBinding.ensureInitialized(); initialSetup(); From 4c102de9be2c71626f238ebab391dbfbdb32e869 Mon Sep 17 00:00:00 2001 From: Abdullah Alassaf Date: Tue, 3 Sep 2024 13:50:16 +0300 Subject: [PATCH 025/158] Updated the default env. file --- lib/main.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/main.dart b/lib/main.dart index 721a472b..eeaa4685 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -13,7 +13,7 @@ import 'package:syncrow_web/utils/theme/theme.dart'; Future main() async { try { - const environment = String.fromEnvironment('FLAVOR', defaultValue: 'development'); + const environment = String.fromEnvironment('FLAVOR', defaultValue: 'production'); await dotenv.load(fileName: '.env.$environment'); WidgetsFlutterBinding.ensureInitialized(); initialSetup(); From 9d7216295fba9143d95201009c0cefbfbeb704d3 Mon Sep 17 00:00:00 2001 From: Abdullah Alassaf Date: Tue, 3 Sep 2024 14:25:42 +0300 Subject: [PATCH 026/158] Updated the github workflow --- .../azure-static-web-apps-zealous-mushroom-0d31a3303.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/azure-static-web-apps-zealous-mushroom-0d31a3303.yml b/.github/workflows/azure-static-web-apps-zealous-mushroom-0d31a3303.yml index b8d576b9..a154206e 100644 --- a/.github/workflows/azure-static-web-apps-zealous-mushroom-0d31a3303.yml +++ b/.github/workflows/azure-static-web-apps-zealous-mushroom-0d31a3303.yml @@ -31,7 +31,7 @@ jobs: run: flutter pub get - name: Build Flutter Web App - run: flutter build web + run: flutter build web --release --dart-define=FLAVOR=development - name: Build And Deploy id: builddeploy From 54fe899d0a9ac4649a66aba28b6cc67b7031aa2d Mon Sep 17 00:00:00 2001 From: Abdullah Alassaf Date: Tue, 3 Sep 2024 14:34:24 +0300 Subject: [PATCH 027/158] Updated the githib workflow --- .../azure-static-web-apps-agreeable-wave-096d61a10.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml b/.github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml index 86bf0c5d..9a1c1713 100644 --- a/.github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml +++ b/.github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml @@ -31,7 +31,7 @@ jobs: run: flutter pub get - name: Build Flutter Web App - run: flutter build web + run: flutter build web --release --dart-define=FLAVOR=production - name: Build And Deploy id: builddeploy From 1bd953a902f7e299ccf7ed0065202a364923f7d2 Mon Sep 17 00:00:00 2001 From: Abdullah Alassaf Date: Tue, 3 Sep 2024 15:14:47 +0300 Subject: [PATCH 028/158] Updated main github workflow --- .../azure-static-web-apps-agreeable-wave-096d61a10.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml b/.github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml index 86bf0c5d..9a1c1713 100644 --- a/.github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml +++ b/.github/workflows/azure-static-web-apps-agreeable-wave-096d61a10.yml @@ -31,7 +31,7 @@ jobs: run: flutter pub get - name: Build Flutter Web App - run: flutter build web + run: flutter build web --release --dart-define=FLAVOR=production - name: Build And Deploy id: builddeploy From f15ce71d09289f59676725783cb3b380f4830420 Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:19:48 +0300 Subject: [PATCH 029/158] ci: add Azure Static Web Apps workflow file on-behalf-of: @Azure opensource@microsoft.com --- ...static-web-apps-salmon-ocean-0c2902310.yml | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .github/workflows/azure-static-web-apps-salmon-ocean-0c2902310.yml diff --git a/.github/workflows/azure-static-web-apps-salmon-ocean-0c2902310.yml b/.github/workflows/azure-static-web-apps-salmon-ocean-0c2902310.yml new file mode 100644 index 00000000..347f357a --- /dev/null +++ b/.github/workflows/azure-static-web-apps-salmon-ocean-0c2902310.yml @@ -0,0 +1,46 @@ +name: Azure Static Web Apps CI/CD + +on: + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened, closed] + branches: + - main + +jobs: + build_and_deploy_job: + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') + runs-on: ubuntu-latest + name: Build and Deploy Job + steps: + - uses: actions/checkout@v3 + with: + submodules: true + lfs: false + - name: Build And Deploy + id: builddeploy + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_SALMON_OCEAN_0C2902310 }} + repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) + action: "upload" + ###### Repository/Build Configurations - These values can be configured to match your app requirements. ###### + # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig + app_location: "/web" # App source code path + api_location: "" # Api source code path - optional + output_location: "/web" # Built app content directory - optional + ###### End of Repository/Build Configurations ###### + + close_pull_request_job: + if: github.event_name == 'pull_request' && github.event.action == 'closed' + runs-on: ubuntu-latest + name: Close Pull Request Job + steps: + - name: Close Pull Request + id: closepullrequest + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_SALMON_OCEAN_0C2902310 }} + action: "close" From 20d98b9121a886b03ac0045dae85fd07d1170f46 Mon Sep 17 00:00:00 2001 From: faris Aljohari <83524184+farisaljohari@users.noreply.github.com> Date: Tue, 3 Sep 2024 15:21:34 +0300 Subject: [PATCH 030/158] test deploy --- web/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/web/index.html b/web/index.html index b3fc8dfc..007a83d3 100644 --- a/web/index.html +++ b/web/index.html @@ -40,6 +40,7 @@ +

test

-

test