From 1200a809c2719f9da1f4c6d6e86b51d468981d45 Mon Sep 17 00:00:00 2001 From: raf-dev1 Date: Mon, 23 Jun 2025 14:33:56 +0300 Subject: [PATCH 01/14] now cant use offline device to controll --- .../widgets/device_managment_body.dart | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) 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 f4baad0c..c484b1b1 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 @@ -103,8 +103,30 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { decoration: containerDecoration, child: Center( child: DefaultButton( + backgroundColor: selectedDevices.any( + (element) => !element.online!, + ) + ? ColorsManager.primaryColor + .withValues(alpha: 0.1) + : null, onPressed: isControlButtonEnabled ? () { + if (selectedDevices.any( + (element) => !element.online!, + )) { + ScaffoldMessenger.of(context) + .showSnackBar( + const SnackBar( + content: Text( + 'This Device is Offline', + ), + duration: + Duration(seconds: 2), + ), + ); + return; + } + if (selectedDevices.length == 1) { showDialog( context: context, From 71cf0a636e15c2009bd9f134ef158e685f07a9c0 Mon Sep 17 00:00:00 2001 From: raf-dev1 Date: Mon, 23 Jun 2025 15:22:24 +0300 Subject: [PATCH 02/14] send all user instead of only uuid --- .../users_table/view/users_page.dart | 53 ++++++++++--------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/lib/pages/roles_and_permission/users_page/users_table/view/users_page.dart b/lib/pages/roles_and_permission/users_page/users_table/view/users_page.dart index 767fd9a6..88f89e30 100644 --- a/lib/pages/roles_and_permission/users_page/users_table/view/users_page.dart +++ b/lib/pages/roles_and_permission/users_page/users_table/view/users_page.dart @@ -19,6 +19,7 @@ import 'package:syncrow_web/utils/color_manager.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'; + class UsersPage extends StatelessWidget { UsersPage({super.key}); @@ -451,33 +452,33 @@ class UsersPage extends StatelessWidget { ), Row( children: [ - user.isEnabled != false - ? actionButton( - isActive: true, - title: "Edit", - onTap: () { - context - .read() - .add(ClearCachedData()); - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return EditUserDialog( - userId: user.uuid); - }, - ).then((v) { - if (v != null) { - if (v != null) { - _blocRole.add(const GetUsers()); - } - } - }); + if (user.isEnabled != false) + actionButton( + isActive: true, + title: "Edit", + onTap: () { + context + .read() + .add(ClearCachedData()); + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return EditUserDialog(user: user); }, - ) - : actionButton( - title: "Edit", - ), + ).then((v) { + if (v != null) { + if (v != null) { + _blocRole.add(const GetUsers()); + } + } + }); + }, + ) + else + actionButton( + title: "Edit", + ), actionButton( title: "Delete", onTap: () { From e6957d566da8ec3e4a24dc9e23ffe7d47eebb290 Mon Sep 17 00:00:00 2001 From: raf-dev1 Date: Mon, 23 Jun 2025 15:29:35 +0300 Subject: [PATCH 03/14] use RoleUserModel instead of only id and all is good --- .../view/edit_user_dialog.dart | 62 +++++++++++++------ 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/lib/pages/roles_and_permission/users_page/add_user_dialog/view/edit_user_dialog.dart b/lib/pages/roles_and_permission/users_page/add_user_dialog/view/edit_user_dialog.dart index 071de067..c84a6baf 100644 --- a/lib/pages/roles_and_permission/users_page/add_user_dialog/view/edit_user_dialog.dart +++ b/lib/pages/roles_and_permission/users_page/add_user_dialog/view/edit_user_dialog.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/flutter_svg.dart'; +import 'package:syncrow_web/pages/auth/model/user_model.dart'; import 'package:syncrow_web/pages/common/bloc/project_manager.dart'; +import 'package:syncrow_web/pages/roles_and_permission/model/roles_user_model.dart'; import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart'; import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart'; import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart'; @@ -12,8 +14,11 @@ import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; class EditUserDialog extends StatefulWidget { - final String? userId; - const EditUserDialog({super.key, this.userId}); + final RolesUserModel? user; + const EditUserDialog({ + super.key, + this.user, + }); @override _EditUserDialogState createState() => _EditUserDialogState(); @@ -28,10 +33,11 @@ class _EditUserDialogState extends State { create: (BuildContext context) => UsersBloc() // ..add(const LoadCommunityAndSpacesEvent()) ..add(const RoleEvent()) - ..add(GetUserByIdEvent(uuid: widget.userId)), + ..add(GetUserByIdEvent(uuid: widget.user!.uuid)), child: BlocConsumer(listener: (context, state) { if (state is SpacesLoadedState) { - BlocProvider.of(context).add(GetUserByIdEvent(uuid: widget.userId)); + BlocProvider.of(context) + .add(GetUserByIdEvent(uuid: widget.user!.uuid)); } }, builder: (context, state) { final _blocRole = BlocProvider.of(context); @@ -39,7 +45,8 @@ class _EditUserDialogState extends State { return Dialog( child: Container( decoration: const BoxDecoration( - color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))), + color: Colors.white, + borderRadius: BorderRadius.all(Radius.circular(20))), width: 900, child: Column( children: [ @@ -68,7 +75,8 @@ class _EditUserDialogState extends State { children: [ _buildStep1Indicator(1, "Basics", _blocRole), _buildStep2Indicator(2, "Spaces", _blocRole), - _buildStep3Indicator(3, "Role & Permissions", _blocRole), + _buildStep3Indicator( + 3, "Role & Permissions", _blocRole), ], ), ), @@ -86,7 +94,7 @@ class _EditUserDialogState extends State { children: [ const SizedBox(height: 10), Expanded( - child: _getFormContent(widget.userId), + child: _getFormContent(widget.user!), ), const SizedBox(height: 20), ], @@ -116,13 +124,14 @@ class _EditUserDialogState extends State { if (currentStep < 3) { currentStep++; if (currentStep == 2) { - _blocRole.add(CheckStepStatus(isEditUser: true)); + _blocRole + .add(CheckStepStatus(isEditUser: true)); } else if (currentStep == 3) { _blocRole.add(const CheckSpacesStepStatus()); } } else { - _blocRole - .add(EditInviteUsers(context: context, userId: widget.userId!)); + _blocRole.add(EditInviteUsers( + context: context, userId: widget.user!.uuid)); } }); }, @@ -131,7 +140,8 @@ class _EditUserDialogState extends State { style: TextStyle( color: (_blocRole.isCompleteSpaces == false || _blocRole.isCompleteBasics == false || - _blocRole.isCompleteRolePermissions == false) && + _blocRole.isCompleteRolePermissions == + false) && currentStep == 3 ? ColorsManager.grayColor : ColorsManager.secondaryColor), @@ -146,15 +156,15 @@ class _EditUserDialogState extends State { })); } - Widget _getFormContent(userid) { + Widget _getFormContent(RolesUserModel user) { switch (currentStep) { case 1: return BasicsView( - userId: userid, + userId: user.uuid, ); case 2: return SpacesAccessView( - userId: userid, + userId: user.uuid, ); case 3: return const RolesAndPermission(); @@ -204,8 +214,12 @@ class _EditUserDialogState extends State { label, style: TextStyle( fontSize: 16, - color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor, - fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal, + color: currentStep == step + ? ColorsManager.blackColor + : ColorsManager.greyColor, + fontWeight: currentStep == step + ? FontWeight.bold + : FontWeight.normal, ), ), ], @@ -263,8 +277,12 @@ class _EditUserDialogState extends State { label, style: TextStyle( fontSize: 16, - color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor, - fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal, + color: currentStep == step + ? ColorsManager.blackColor + : ColorsManager.greyColor, + fontWeight: currentStep == step + ? FontWeight.bold + : FontWeight.normal, ), ), ], @@ -321,8 +339,12 @@ class _EditUserDialogState extends State { label, style: TextStyle( fontSize: 16, - color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor, - fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal, + color: currentStep == step + ? ColorsManager.blackColor + : ColorsManager.greyColor, + fontWeight: currentStep == step + ? FontWeight.bold + : FontWeight.normal, ), ), ], From 5276f4186c46022f5bf42cc6e9aa23fba8cf8ddb Mon Sep 17 00:00:00 2001 From: raf-dev1 Date: Mon, 23 Jun 2025 15:55:56 +0300 Subject: [PATCH 04/14] emit error state when catch error and send the real API exception --- lib/pages/auth/bloc/auth_bloc.dart | 34 ++++++++++++++++++------------ 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/lib/pages/auth/bloc/auth_bloc.dart b/lib/pages/auth/bloc/auth_bloc.dart index 58950089..bfe0b3eb 100644 --- a/lib/pages/auth/bloc/auth_bloc.dart +++ b/lib/pages/auth/bloc/auth_bloc.dart @@ -36,7 +36,8 @@ class AuthBloc extends Bloc { ////////////////////////////// forget password ////////////////////////////////// final TextEditingController forgetEmailController = TextEditingController(); - final TextEditingController forgetPasswordController = TextEditingController(); + final TextEditingController forgetPasswordController = + TextEditingController(); final TextEditingController forgetOtp = TextEditingController(); final forgetFormKey = GlobalKey(); final forgetEmailKey = GlobalKey(); @@ -53,7 +54,8 @@ class AuthBloc extends Bloc { return; } _remainingTime = 1; - add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false)); + add(UpdateTimerEvent( + remainingTime: _remainingTime, isButtonEnabled: false)); try { forgetEmailValidate = ''; _remainingTime = (await AuthenticationAPI.sendOtp( @@ -90,7 +92,8 @@ class AuthBloc extends Bloc { _timer?.cancel(); add(const UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true)); } else { - add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false)); + add(UpdateTimerEvent( + remainingTime: _remainingTime, isButtonEnabled: false)); } }); } @@ -100,7 +103,7 @@ class AuthBloc extends Bloc { emit(const TimerState(isButtonEnabled: true, remainingTime: 0)); } -Future changePassword( + Future changePassword( ChangePasswordEvent event, Emitter emit) async { emit(LoadingForgetState()); try { @@ -122,7 +125,6 @@ Future changePassword( } } - String? validateCode(String? value) { if (value == null || value.isEmpty) { return 'Code is required'; @@ -131,7 +133,9 @@ Future changePassword( } void _onUpdateTimer(UpdateTimerEvent event, Emitter emit) { - emit(TimerState(isButtonEnabled: event.isButtonEnabled, remainingTime: event.remainingTime)); + emit(TimerState( + isButtonEnabled: event.isButtonEnabled, + remainingTime: event.remainingTime)); } ///////////////////////////////////// login ///////////////////////////////////// @@ -151,7 +155,6 @@ Future changePassword( static UserModel? user; bool showValidationMessage = false; - void _login(LoginButtonPressed event, Emitter emit) async { emit(AuthLoading()); if (isChecked) { @@ -170,11 +173,11 @@ Future changePassword( ); } on APIException catch (e) { validate = e.message; - emit(LoginInitial()); + emit(LoginFailure(error: validate)); return; } catch (e) { validate = 'Something went wrong'; - emit(LoginInitial()); + emit(LoginFailure(error: validate)); return; } @@ -197,7 +200,6 @@ Future changePassword( } } - checkBoxToggle( CheckBoxEvent event, Emitter emit, @@ -339,12 +341,14 @@ Future changePassword( static Future getTokenAndValidate() async { try { const storage = FlutterSecureStorage(); - final firstLaunch = - await SharedPreferencesHelper.readBoolFromSP(StringsManager.firstLaunch) ?? true; + final firstLaunch = await SharedPreferencesHelper.readBoolFromSP( + StringsManager.firstLaunch) ?? + true; if (firstLaunch) { storage.deleteAll(); } - await SharedPreferencesHelper.saveBoolToSP(StringsManager.firstLaunch, false); + await SharedPreferencesHelper.saveBoolToSP( + StringsManager.firstLaunch, false); final value = await storage.read(key: Token.loginAccessTokenKey) ?? ''; if (value.isEmpty) { return 'Token not found'; @@ -397,7 +401,9 @@ Future changePassword( final String formattedTime = [ if (days > 0) '${days}d', // Append 'd' for days if (days > 0 || hours > 0) - hours.toString().padLeft(2, '0'), // Show hours if there are days or hours + hours + .toString() + .padLeft(2, '0'), // Show hours if there are days or hours minutes.toString().padLeft(2, '0'), seconds.toString().padLeft(2, '0'), ].join(':'); From ad00cf35ba65e6a935b4203289dfe6bbe0f8ac29 Mon Sep 17 00:00:00 2001 From: raf-dev1 Date: Mon, 23 Jun 2025 16:05:16 +0300 Subject: [PATCH 05/14] added the PR notes --- .../all_devices/widgets/device_managment_body.dart | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) 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 c484b1b1..c865a5dc 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 @@ -62,7 +62,8 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { final buttonLabel = (selectedDevices.length > 1) ? 'Batch Control' : 'Control'; - + final isAnyDeviceOffline = + selectedDevices.any((element) => !(element.online ?? false)); return Row( children: [ Expanded(child: SpaceTreeView( @@ -103,17 +104,13 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout { decoration: containerDecoration, child: Center( child: DefaultButton( - backgroundColor: selectedDevices.any( - (element) => !element.online!, - ) + backgroundColor: isAnyDeviceOffline ? ColorsManager.primaryColor .withValues(alpha: 0.1) : null, onPressed: isControlButtonEnabled ? () { - if (selectedDevices.any( - (element) => !element.online!, - )) { + if (isAnyDeviceOffline) { ScaffoldMessenger.of(context) .showSnackBar( const SnackBar( From 379ecec789e2339fa3e4e4b07419155384991c41 Mon Sep 17 00:00:00 2001 From: raf-dev1 Date: Mon, 23 Jun 2025 16:15:05 +0300 Subject: [PATCH 06/14] use isCurrentStep instead of checking with multi variables everyTime --- .../view/edit_user_dialog.dart | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/pages/roles_and_permission/users_page/add_user_dialog/view/edit_user_dialog.dart b/lib/pages/roles_and_permission/users_page/add_user_dialog/view/edit_user_dialog.dart index c84a6baf..00c566c6 100644 --- a/lib/pages/roles_and_permission/users_page/add_user_dialog/view/edit_user_dialog.dart +++ b/lib/pages/roles_and_permission/users_page/add_user_dialog/view/edit_user_dialog.dart @@ -176,6 +176,7 @@ class _EditUserDialogState extends State { int step3 = 0; Widget _buildStep1Indicator(int step, String label, UsersBloc bloc) { + final isCurrentStep = currentStep == step; return GestureDetector( onTap: () { setState(() { @@ -199,7 +200,7 @@ class _EditUserDialogState extends State { child: Row( children: [ SvgPicture.asset( - currentStep == step + isCurrentStep ? Assets.currentProcessIcon : bloc.isCompleteBasics == false ? Assets.wrongProcessIcon @@ -214,12 +215,11 @@ class _EditUserDialogState extends State { label, style: TextStyle( fontSize: 16, - color: currentStep == step + color: isCurrentStep ? ColorsManager.blackColor : ColorsManager.greyColor, - fontWeight: currentStep == step - ? FontWeight.bold - : FontWeight.normal, + fontWeight: + isCurrentStep ? FontWeight.bold : FontWeight.normal, ), ), ], @@ -243,6 +243,7 @@ class _EditUserDialogState extends State { } Widget _buildStep2Indicator(int step, String label, UsersBloc bloc) { + final isCurrentStep = currentStep == step; return GestureDetector( onTap: () { setState(() { @@ -262,7 +263,7 @@ class _EditUserDialogState extends State { child: Row( children: [ SvgPicture.asset( - currentStep == step + isCurrentStep ? Assets.currentProcessIcon : bloc.isCompleteSpaces == false ? Assets.wrongProcessIcon @@ -277,12 +278,11 @@ class _EditUserDialogState extends State { label, style: TextStyle( fontSize: 16, - color: currentStep == step + color: isCurrentStep ? ColorsManager.blackColor : ColorsManager.greyColor, - fontWeight: currentStep == step - ? FontWeight.bold - : FontWeight.normal, + fontWeight: + isCurrentStep ? FontWeight.bold : FontWeight.normal, ), ), ], @@ -306,6 +306,7 @@ class _EditUserDialogState extends State { } Widget _buildStep3Indicator(int step, String label, UsersBloc bloc) { + final isCurrentStep = currentStep == step; return GestureDetector( onTap: () { setState(() { @@ -324,7 +325,7 @@ class _EditUserDialogState extends State { child: Row( children: [ SvgPicture.asset( - currentStep == step + isCurrentStep ? Assets.currentProcessIcon : bloc.isCompleteRolePermissions == false ? Assets.wrongProcessIcon @@ -339,12 +340,11 @@ class _EditUserDialogState extends State { label, style: TextStyle( fontSize: 16, - color: currentStep == step + color: isCurrentStep ? ColorsManager.blackColor : ColorsManager.greyColor, - fontWeight: currentStep == step - ? FontWeight.bold - : FontWeight.normal, + fontWeight: + isCurrentStep ? FontWeight.bold : FontWeight.normal, ), ), ], From d14cc785a8f23dda61d274cf8b22d4f08bbb4c90 Mon Sep 17 00:00:00 2001 From: raf-dev1 Date: Mon, 23 Jun 2025 16:16:34 +0300 Subject: [PATCH 07/14] no need for two condtions inside themselves --- .../users_page/users_table/view/users_page.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/pages/roles_and_permission/users_page/users_table/view/users_page.dart b/lib/pages/roles_and_permission/users_page/users_table/view/users_page.dart index 88f89e30..da159d94 100644 --- a/lib/pages/roles_and_permission/users_page/users_table/view/users_page.dart +++ b/lib/pages/roles_and_permission/users_page/users_table/view/users_page.dart @@ -468,9 +468,7 @@ class UsersPage extends StatelessWidget { }, ).then((v) { if (v != null) { - if (v != null) { - _blocRole.add(const GetUsers()); - } + _blocRole.add(const GetUsers()); } }); }, From 7397486e7ac3c948cc5e3de1e40b9267c3e25509 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Wed, 25 Jun 2025 13:11:49 +0300 Subject: [PATCH 08/14] SP-368-Clarification-on-Default-Value-for-Start-Date-in-Door-Lock-Online-Tile-Limited-Password-repeat-section --- .../bloc/visitor_password_bloc.dart | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart index 438b1abf..6dc20cfd 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart @@ -68,7 +68,7 @@ class VisitorPasswordBloc DateTime? startTime = DateTime.now(); DateTime? endTime; - String startTimeAccess = 'Start Time'; + String startTimeAccess = DateTime.now().toString().split('.').first; String endTimeAccess = 'End Time'; PasswordStatus? passwordStatus; selectAccessType( @@ -136,6 +136,27 @@ class VisitorPasswordBloc ); return; } + if(selectedTimestamp < DateTime.now().millisecondsSinceEpoch ~/ 1000) { + if(selectedTimestamp < DateTime.now().millisecondsSinceEpoch ~/ 1000) { + await showDialog( + context: event.context, + builder: (context) => AlertDialog( + title: const Text('Effective Time cannot be earlier than current time.'), + actionsAlignment: MainAxisAlignment.center, + content: + FilledButton( + onPressed: () { + Navigator.of(event.context).pop(); + add(SelectTimeVisitorPassword(context: event.context, isStart: true, isRepeat: false)); + }, + child: const Text('OK'), + ), + + ), + ); + } + return; + } effectiveTimeTimeStamp = selectedTimestamp; startTimeAccess = selectedDateTime.toString().split('.').first; } else { From 11e285340376b90f0d169b8eb31e66219a8ddb64 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Fri, 27 Jun 2025 11:56:43 +0300 Subject: [PATCH 09/14] Enhance AnalyticsDeviceDropdown to show loading indicator during loading state. --- .../widgets/analytics_device_dropdown.dart | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/pages/analytics/modules/energy_management/widgets/analytics_device_dropdown.dart b/lib/pages/analytics/modules/energy_management/widgets/analytics_device_dropdown.dart index f7b33309..055e9675 100644 --- a/lib/pages/analytics/modules/energy_management/widgets/analytics_device_dropdown.dart +++ b/lib/pages/analytics/modules/energy_management/widgets/analytics_device_dropdown.dart @@ -28,15 +28,29 @@ class AnalyticsDeviceDropdown extends StatelessWidget { ), ), child: Visibility( - visible: state.devices.isNotEmpty, - replacement: _buildNoDevicesFound(context), - child: _buildDevicesDropdown(context, state), + visible: state.status != AnalyticsDevicesStatus.loading, + replacement: _buildLoadingIndicator(), + child: Visibility( + visible: state.devices.isNotEmpty, + replacement: _buildNoDevicesFound(context), + child: _buildDevicesDropdown(context, state), + ), ), ); }, ); } + Widget _buildLoadingIndicator() { + return const Center( + child: SizedBox( + width: 24, + height: 24, + child: CircularProgressIndicator(strokeWidth: 3), + ), + ); + } + static const _defaultPadding = EdgeInsetsDirectional.symmetric( horizontal: 20, vertical: 2, From 7fda564ee43256336723fec9b0e1fc2bf059a08c Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Fri, 27 Jun 2025 14:07:24 +0300 Subject: [PATCH 10/14] hotfixes. --- lib/pages/analytics/models/occupancy_heat_map_model.dart | 4 +++- .../modules/air_quality/widgets/aqi_type_dropdown.dart | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/pages/analytics/models/occupancy_heat_map_model.dart b/lib/pages/analytics/models/occupancy_heat_map_model.dart index 73e7d5d7..cd332745 100644 --- a/lib/pages/analytics/models/occupancy_heat_map_model.dart +++ b/lib/pages/analytics/models/occupancy_heat_map_model.dart @@ -19,7 +19,9 @@ class OccupancyHeatMapModel extends Equatable { eventDate: DateTime.parse( json['event_date'] as String? ?? '${DateTime.now()}', ), - countTotalPresenceDetected: json['count_total_presence_detected'] as int? ?? 0, + countTotalPresenceDetected: num.parse( + json['count_total_presence_detected']?.toString() ?? '900', + ).toInt(), ); } diff --git a/lib/pages/analytics/modules/air_quality/widgets/aqi_type_dropdown.dart b/lib/pages/analytics/modules/air_quality/widgets/aqi_type_dropdown.dart index 457bf610..6640c717 100644 --- a/lib/pages/analytics/modules/air_quality/widgets/aqi_type_dropdown.dart +++ b/lib/pages/analytics/modules/air_quality/widgets/aqi_type_dropdown.dart @@ -6,7 +6,7 @@ enum AqiType { aqi('AQI', '', 'aqi'), pm25('PM2.5', 'µg/m³', 'pm25'), pm10('PM10', 'µg/m³', 'pm10'), - hcho('HCHO', 'mg/m³', 'cho2'), + hcho('HCHO', 'mg/m³', 'ch2o'), tvoc('TVOC', 'mg/m³', 'voc'), co2('CO2', 'ppm', 'co2'); From 475462301f8ff72b2b666d8ddadbcf25700cbab9 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Fri, 27 Jun 2025 15:29:11 +0300 Subject: [PATCH 11/14] manually parse event date for heatmap date object. --- .../analytics/models/occupancy_heat_map_model.dart | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/lib/pages/analytics/models/occupancy_heat_map_model.dart b/lib/pages/analytics/models/occupancy_heat_map_model.dart index cd332745..60d1a453 100644 --- a/lib/pages/analytics/models/occupancy_heat_map_model.dart +++ b/lib/pages/analytics/models/occupancy_heat_map_model.dart @@ -14,13 +14,16 @@ class OccupancyHeatMapModel extends Equatable { }); factory OccupancyHeatMapModel.fromJson(Map json) { + final eventDate = json['event_date'] as String? ?? '${DateTime.now()}'; + final year = eventDate.split('-')[0]; + final month = eventDate.split('-')[1]; + final day = eventDate.split('-')[2]; + return OccupancyHeatMapModel( uuid: json['uuid'] as String? ?? '', - eventDate: DateTime.parse( - json['event_date'] as String? ?? '${DateTime.now()}', - ), + eventDate: DateTime(int.parse(year), int.parse(month), int.parse(day)), countTotalPresenceDetected: num.parse( - json['count_total_presence_detected']?.toString() ?? '900', + json['count_total_presence_detected']?.toString() ?? '0', ).toInt(), ); } From ca41aa622479d28c10478620546e8447bfcbac9f Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Fri, 27 Jun 2025 16:37:09 +0300 Subject: [PATCH 12/14] all dates in heatmap are utc. --- .../analytics/models/occupancy_heat_map_model.dart | 14 +++++++++----- .../occupancy/widgets/interactive_heat_map.dart | 2 +- .../occupancy/widgets/occupancy_heat_map.dart | 4 ++-- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/lib/pages/analytics/models/occupancy_heat_map_model.dart b/lib/pages/analytics/models/occupancy_heat_map_model.dart index 60d1a453..e4b7d730 100644 --- a/lib/pages/analytics/models/occupancy_heat_map_model.dart +++ b/lib/pages/analytics/models/occupancy_heat_map_model.dart @@ -14,14 +14,18 @@ class OccupancyHeatMapModel extends Equatable { }); factory OccupancyHeatMapModel.fromJson(Map json) { - final eventDate = json['event_date'] as String? ?? '${DateTime.now()}'; - final year = eventDate.split('-')[0]; - final month = eventDate.split('-')[1]; - final day = eventDate.split('-')[2]; + final eventDate = json['event_date'] as String?; + final year = eventDate?.split('-')[0]; + final month = eventDate?.split('-')[1]; + final day = eventDate?.split('-')[2]; return OccupancyHeatMapModel( uuid: json['uuid'] as String? ?? '', - eventDate: DateTime(int.parse(year), int.parse(month), int.parse(day)), + eventDate: DateTime( + int.parse(year ?? '2025'), + int.parse(month ?? '1'), + int.parse(day ?? '1'), + ).toUtc(), countTotalPresenceDetected: num.parse( json['count_total_presence_detected']?.toString() ?? '0', ).toInt(), diff --git a/lib/pages/analytics/modules/occupancy/widgets/interactive_heat_map.dart b/lib/pages/analytics/modules/occupancy/widgets/interactive_heat_map.dart index a652ae73..514ebb65 100644 --- a/lib/pages/analytics/modules/occupancy/widgets/interactive_heat_map.dart +++ b/lib/pages/analytics/modules/occupancy/widgets/interactive_heat_map.dart @@ -52,7 +52,7 @@ class _InteractiveHeatMapState extends State { color: Colors.transparent, child: Transform.translate( offset: Offset(-(widget.cellSize * 2.5), -50), - child: HeatMapTooltip(date: item.date, value: item.value), + child: HeatMapTooltip(date: item.date.toUtc(), value: item.value), ), ), ), diff --git a/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map.dart b/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map.dart index 05415421..0809a990 100644 --- a/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map.dart +++ b/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map.dart @@ -20,14 +20,14 @@ class OccupancyHeatMap extends StatelessWidget { : 0; DateTime _getStartingDate() { - final jan1 = DateTime(DateTime.now().year, 1, 1); + final jan1 = DateTime(DateTime.now().year, 1, 1).toUtc(); final startOfWeek = jan1.subtract(Duration(days: jan1.weekday - 1)); return startOfWeek; } List _generatePaintItems(DateTime startDate) { return List.generate(_totalWeeks * 7, (index) { - final date = startDate.add(Duration(days: index)); + final date = startDate.toUtc().add(Duration(days: index)); final value = heatMapData[date] ?? 0; return OccupancyPaintItem(index: index, value: value, date: date); }); From 4744009cb65c887a80346a898733c032813877d7 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Fri, 27 Jun 2025 17:11:17 +0300 Subject: [PATCH 13/14] Update TotalEnergyConsumptionChart to adjust Y-axis limits and intervals for better data representation --- .../widgets/total_energy_consumption_chart.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/pages/analytics/modules/energy_management/widgets/total_energy_consumption_chart.dart b/lib/pages/analytics/modules/energy_management/widgets/total_energy_consumption_chart.dart index 85b95c29..bba1fa14 100644 --- a/lib/pages/analytics/modules/energy_management/widgets/total_energy_consumption_chart.dart +++ b/lib/pages/analytics/modules/energy_management/widgets/total_energy_consumption_chart.dart @@ -14,14 +14,17 @@ class TotalEnergyConsumptionChart extends StatelessWidget { return Expanded( child: LineChart( LineChartData( + maxY: chartData.isEmpty + ? null + : chartData.map((e) => e.value).reduce((a, b) => a > b ? a : b) + 250, clipData: const FlClipData.vertical(), titlesData: EnergyManagementChartsHelper.titlesData( context, - leftTitlesInterval: 250, + leftTitlesInterval: 500, ), gridData: EnergyManagementChartsHelper.gridData().copyWith( checkToShowHorizontalLine: (value) => true, - horizontalInterval: 250, + horizontalInterval: 500, ), borderData: EnergyManagementChartsHelper.borderData(), lineTouchData: EnergyManagementChartsHelper.lineTouchData(), @@ -29,7 +32,6 @@ class TotalEnergyConsumptionChart extends StatelessWidget { ), duration: Duration.zero, curve: Curves.easeIn, - ), ); } From 13e9a808ab70e0fe745d25ac9eadfb72cfcf5845 Mon Sep 17 00:00:00 2001 From: Faris Armoush Date: Fri, 27 Jun 2025 22:09:00 +0300 Subject: [PATCH 14/14] uses UTC dates as an attempt to fix heatmap's rendering bug. --- lib/pages/analytics/models/occupancy_heat_map_model.dart | 4 ++-- .../modules/occupancy/widgets/occupancy_heat_map.dart | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pages/analytics/models/occupancy_heat_map_model.dart b/lib/pages/analytics/models/occupancy_heat_map_model.dart index e4b7d730..4c7a37d4 100644 --- a/lib/pages/analytics/models/occupancy_heat_map_model.dart +++ b/lib/pages/analytics/models/occupancy_heat_map_model.dart @@ -21,11 +21,11 @@ class OccupancyHeatMapModel extends Equatable { return OccupancyHeatMapModel( uuid: json['uuid'] as String? ?? '', - eventDate: DateTime( + eventDate: DateTime.utc( int.parse(year ?? '2025'), int.parse(month ?? '1'), int.parse(day ?? '1'), - ).toUtc(), + ), countTotalPresenceDetected: num.parse( json['count_total_presence_detected']?.toString() ?? '0', ).toInt(), diff --git a/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map.dart b/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map.dart index 0809a990..05c5bb71 100644 --- a/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map.dart +++ b/lib/pages/analytics/modules/occupancy/widgets/occupancy_heat_map.dart @@ -20,14 +20,14 @@ class OccupancyHeatMap extends StatelessWidget { : 0; DateTime _getStartingDate() { - final jan1 = DateTime(DateTime.now().year, 1, 1).toUtc(); + final jan1 = DateTime.utc(DateTime.now().year, 1, 1); final startOfWeek = jan1.subtract(Duration(days: jan1.weekday - 1)); return startOfWeek; } List _generatePaintItems(DateTime startDate) { return List.generate(_totalWeeks * 7, (index) { - final date = startDate.toUtc().add(Duration(days: index)); + final date = startDate.add(Duration(days: index)); final value = heatMapData[date] ?? 0; return OccupancyPaintItem(index: index, value: value, date: date); });