diff --git a/lib/pages/analytics/modules/analytics/widgets/analytics_communities_sidebar.dart b/lib/pages/analytics/modules/analytics/widgets/analytics_communities_sidebar.dart index d8a3cbd7..aba54d08 100644 --- a/lib/pages/analytics/modules/analytics/widgets/analytics_communities_sidebar.dart +++ b/lib/pages/analytics/modules/analytics/widgets/analytics_communities_sidebar.dart @@ -1,7 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; -import 'package:syncrow_web/pages/space_tree/bloc/space_tree_event.dart'; +import 'package:syncrow_web/pages/analytics/modules/energy_management/helpers/fetch_energy_management_data_helper.dart'; import 'package:syncrow_web/pages/space_tree/view/space_tree_view.dart'; class AnalyticsCommunitiesSidebar extends StatelessWidget { @@ -9,15 +7,28 @@ class AnalyticsCommunitiesSidebar extends StatelessWidget { @override Widget build(BuildContext context) { - return Expanded( - child: SpaceTreeView( - title: const Text('Communities'), - shouldDisableDeselectingChildrenOfSelectedParent: true, - onSelect: () { - context.read().add(const SpaceTreeClearSelectionEvent()); - }, - isSide: false, - ), + return Builder( + builder: (context) { + return Expanded( + child: SpaceTreeView( + title: const Text('Communities'), + shouldDisableDeselectingChildrenOfSelectedParent: true, + onSelect: () { + /// Necessary to wait for the state to update before fethcing the data. + Future.delayed( + const Duration(milliseconds: 100), + () { + if (context.mounted) { + FetchEnergyManagementDataHelper.fetchEnergyManagementData( + context); + } + }, + ); + }, + isSide: false, + ), + ); + }, ); } } diff --git a/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_by_phases/energy_consumption_by_phases_bloc.dart b/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_by_phases/energy_consumption_by_phases_bloc.dart index 2711e304..012f435a 100644 --- a/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_by_phases/energy_consumption_by_phases_bloc.dart +++ b/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_by_phases/energy_consumption_by_phases_bloc.dart @@ -13,6 +13,7 @@ class EnergyConsumptionByPhasesBloc this._energyConsumptionByPhasesService, ) : super(const EnergyConsumptionByPhasesState()) { on(_onLoadEnergyConsumptionByPhasesEvent); + on(_onClearEnergyConsumptionByPhasesEvent); } final EnergyConsumptionByPhasesService _energyConsumptionByPhasesService; @@ -39,4 +40,11 @@ class EnergyConsumptionByPhasesBloc ); } } + + void _onClearEnergyConsumptionByPhasesEvent( + ClearEnergyConsumptionByPhasesEvent event, + Emitter emit, + ) async { + emit(const EnergyConsumptionByPhasesState()); + } } diff --git a/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_by_phases/energy_consumption_by_phases_event.dart b/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_by_phases/energy_consumption_by_phases_event.dart index 1886e422..87bcf447 100644 --- a/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_by_phases/energy_consumption_by_phases_event.dart +++ b/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_by_phases/energy_consumption_by_phases_event.dart @@ -17,3 +17,7 @@ class LoadEnergyConsumptionByPhasesEvent extends EnergyConsumptionByPhasesEvent @override List get props => [param]; } + +final class ClearEnergyConsumptionByPhasesEvent extends EnergyConsumptionByPhasesEvent { + const ClearEnergyConsumptionByPhasesEvent(); +} diff --git a/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_per_device/energy_consumption_per_device_bloc.dart b/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_per_device/energy_consumption_per_device_bloc.dart index b1e021d9..75dd9c6c 100644 --- a/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_per_device/energy_consumption_per_device_bloc.dart +++ b/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_per_device/energy_consumption_per_device_bloc.dart @@ -13,6 +13,7 @@ class EnergyConsumptionPerDeviceBloc this._energyConsumptionPerDeviceService, ) : super(const EnergyConsumptionPerDeviceState()) { on(_onLoadEnergyConsumptionPerDeviceEvent); + on(_onClearEnergyConsumptionPerDeviceEvent); } final EnergyConsumptionPerDeviceService _energyConsumptionPerDeviceService; @@ -39,4 +40,11 @@ class EnergyConsumptionPerDeviceBloc ); } } + + void _onClearEnergyConsumptionPerDeviceEvent( + ClearEnergyConsumptionPerDeviceEvent event, + Emitter emit, + ) async { + emit(const EnergyConsumptionPerDeviceState()); + } } diff --git a/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_per_device/energy_consumption_per_device_event.dart b/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_per_device/energy_consumption_per_device_event.dart index a17cdab3..2e59da8e 100644 --- a/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_per_device/energy_consumption_per_device_event.dart +++ b/lib/pages/analytics/modules/energy_management/blocs/energy_consumption_per_device/energy_consumption_per_device_event.dart @@ -16,3 +16,8 @@ final class LoadEnergyConsumptionPerDeviceEvent @override List get props => [param]; } + +final class ClearEnergyConsumptionPerDeviceEvent + extends EnergyConsumptionPerDeviceEvent { + const ClearEnergyConsumptionPerDeviceEvent(); +} diff --git a/lib/pages/analytics/modules/energy_management/blocs/power_clamp_info/power_clamp_info_bloc.dart b/lib/pages/analytics/modules/energy_management/blocs/power_clamp_info/power_clamp_info_bloc.dart index 4febe1b4..d0e7aab6 100644 --- a/lib/pages/analytics/modules/energy_management/blocs/power_clamp_info/power_clamp_info_bloc.dart +++ b/lib/pages/analytics/modules/energy_management/blocs/power_clamp_info/power_clamp_info_bloc.dart @@ -13,6 +13,7 @@ class PowerClampInfoBloc extends Bloc ) : super(const PowerClampInfoState()) { on(_onLoadPowerClampInfoEvent); on(_onUpdatePowerClampStatusEvent); + on(_onClearPowerClampInfoEvent); } final PowerClampInfoService _powerClampInfoService; @@ -52,4 +53,11 @@ class PowerClampInfoBloc extends Bloc emit(state.copyWith(powerClampModel: updatedModel)); } + + void _onClearPowerClampInfoEvent( + ClearPowerClampInfoEvent event, + Emitter emit, + ) { + emit(const PowerClampInfoState()); + } } diff --git a/lib/pages/analytics/modules/energy_management/blocs/power_clamp_info/power_clamp_info_event.dart b/lib/pages/analytics/modules/energy_management/blocs/power_clamp_info/power_clamp_info_event.dart index acf5e967..b69a2556 100644 --- a/lib/pages/analytics/modules/energy_management/blocs/power_clamp_info/power_clamp_info_event.dart +++ b/lib/pages/analytics/modules/energy_management/blocs/power_clamp_info/power_clamp_info_event.dart @@ -24,4 +24,8 @@ final class UpdatePowerClampStatusEvent extends PowerClampInfoEvent { @override List get props => [statusList]; +} + +final class ClearPowerClampInfoEvent extends PowerClampInfoEvent { + const ClearPowerClampInfoEvent(); } \ No newline at end of file diff --git a/lib/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_bloc.dart b/lib/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_bloc.dart index b052e560..a73f38b0 100644 --- a/lib/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_bloc.dart +++ b/lib/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_bloc.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:syncrow_web/pages/analytics/services/realtime_device_service/realtime_device_service.dart'; @@ -12,35 +14,66 @@ class RealtimeDeviceChangesBloc this._realtimeDeviceService, ) : super(const RealtimeDeviceChangesState()) { on(_onRealtimeDeviceChangesStarted); + on(_onRealtimeDeviceChangesClosed); + on<_RealtimeDeviceChangesUpdated>(_onRealtimeDeviceChangesUpdated); } final RealtimeDeviceService _realtimeDeviceService; + StreamSubscription>? _subscription; Future _onRealtimeDeviceChangesStarted( RealtimeDeviceChangesStarted event, Emitter emit, ) async { - await emit.onEach( - _realtimeDeviceService.subscribe(event.deviceId), - onData: (data) { - final currentState = state; + await _subscription?.cancel(); + _subscription = _realtimeDeviceService.subscribe(event.deviceId).listen( + (data) { + add(_RealtimeDeviceChangesUpdated(data)); + }, + onError: (error) { emit( state.copyWith( - status: RealtimeDeviceChangesStatus.loaded, - deviceStatusList: [ - ...currentState.deviceStatusList.where((device) => - !data.any((newDevice) => newDevice.code == device.code)), - ...data, - ], + status: RealtimeDeviceChangesStatus.failure, + errorMessage: '$error', ), ); }, - onError: (error, _) => emit( - state.copyWith( - status: RealtimeDeviceChangesStatus.failure, - errorMessage: '$error', - ), + ); + } + + void _onRealtimeDeviceChangesClosed( + RealtimeDeviceChangesClosed event, + Emitter emit, + ) async { + await _subscription?.cancel(); + _subscription = null; + emit(state.copyWith(status: RealtimeDeviceChangesStatus.closed)); + } + + void _onRealtimeDeviceChangesUpdated( + _RealtimeDeviceChangesUpdated event, + Emitter emit, + ) { + final currentState = state; + final updatedList = [ + ...currentState.deviceStatusList.where( + (device) => !event.deviceStatusList + .any((newDevice) => newDevice.code == device.code), + ), + ...event.deviceStatusList, + ]; + + emit( + state.copyWith( + status: RealtimeDeviceChangesStatus.loaded, + deviceStatusList: updatedList, ), ); } + + @override + Future close() { + _subscription?.cancel(); + return super.close(); + } } diff --git a/lib/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_event.dart b/lib/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_event.dart index b1d5c793..1eba8f7e 100644 --- a/lib/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_event.dart +++ b/lib/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_event.dart @@ -15,3 +15,13 @@ final class RealtimeDeviceChangesStarted extends RealtimeDeviceChangesEvent { @override List get props => [deviceId]; } + +final class RealtimeDeviceChangesClosed extends RealtimeDeviceChangesEvent { + const RealtimeDeviceChangesClosed(); +} + +class _RealtimeDeviceChangesUpdated extends RealtimeDeviceChangesEvent { + final List deviceStatusList; + + const _RealtimeDeviceChangesUpdated(this.deviceStatusList); +} \ No newline at end of file diff --git a/lib/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_state.dart b/lib/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_state.dart index 5ba47feb..78475084 100644 --- a/lib/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_state.dart +++ b/lib/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_state.dart @@ -1,6 +1,6 @@ part of 'realtime_device_changes_bloc.dart'; -enum RealtimeDeviceChangesStatus { initial, loaded, failure } +enum RealtimeDeviceChangesStatus { initial, loaded, failure, closed } final class RealtimeDeviceChangesState extends Equatable { const RealtimeDeviceChangesState({ diff --git a/lib/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_bloc.dart b/lib/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_bloc.dart index 7382edd1..443f60b7 100644 --- a/lib/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_bloc.dart +++ b/lib/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_bloc.dart @@ -13,6 +13,7 @@ class TotalEnergyConsumptionBloc this._totalEnergyConsumptionService, ) : super(const TotalEnergyConsumptionState()) { on(_onTotalEnergyConsumptionLoadEvent); + on(_onClearTotalEnergyConsumptionEvent); } final TotalEnergyConsumptionService _totalEnergyConsumptionService; @@ -39,4 +40,11 @@ class TotalEnergyConsumptionBloc ); } } + + void _onClearTotalEnergyConsumptionEvent( + ClearTotalEnergyConsumptionEvent event, + Emitter emit, + ) async { + emit(const TotalEnergyConsumptionState()); + } } diff --git a/lib/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_event.dart b/lib/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_event.dart index 8cc9f7df..f9510737 100644 --- a/lib/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_event.dart +++ b/lib/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_event.dart @@ -10,8 +10,12 @@ sealed class TotalEnergyConsumptionEvent extends Equatable { final class TotalEnergyConsumptionLoadEvent extends TotalEnergyConsumptionEvent { const TotalEnergyConsumptionLoadEvent({required this.param}); - final GetTotalEnergyConsumptionParam param ; + final GetTotalEnergyConsumptionParam param; @override List get props => [param]; } + +final class ClearTotalEnergyConsumptionEvent extends TotalEnergyConsumptionEvent { + const ClearTotalEnergyConsumptionEvent(); +} diff --git a/lib/pages/analytics/modules/energy_management/helpers/fetch_energy_management_data_helper.dart b/lib/pages/analytics/modules/energy_management/helpers/fetch_energy_management_data_helper.dart new file mode 100644 index 00000000..f2df3181 --- /dev/null +++ b/lib/pages/analytics/modules/energy_management/helpers/fetch_energy_management_data_helper.dart @@ -0,0 +1,100 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/energy_consumption_by_phases/energy_consumption_by_phases_bloc.dart'; +import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/energy_consumption_per_device/energy_consumption_per_device_bloc.dart'; +import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/power_clamp_info/power_clamp_info_bloc.dart'; +import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_bloc.dart'; +import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_bloc.dart'; +import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_by_phases_param.dart'; +import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_per_device_param.dart'; +import 'package:syncrow_web/pages/analytics/params/get_total_energy_consumption_param.dart'; +import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart'; + +abstract final class FetchEnergyManagementDataHelper { + const FetchEnergyManagementDataHelper._(); + + static void fetchEnergyManagementData(BuildContext context) { + final (selectedCommunities, selectedSpaces) = + _getSelectedCommunitiesAndSpaces(context); + + if (selectedCommunities.isEmpty && selectedSpaces.isEmpty) { + clearAllData(context); + return; + } + + loadTotalEnergyConsumption(context); + loadEnergyConsumptionByPhases(context); + loadPowerClampInfo(context); + loadEnergyConsumptionPerDevice(context); + loadRealtimeDeviceChanges(context); + return; + } + + static (List selectedCommunities, List selectedSpaces) + _getSelectedCommunitiesAndSpaces(BuildContext context) { + final spaceTreeState = context.read().state; + final selectedCommunities = spaceTreeState.selectedCommunities; + final selectedSpaces = spaceTreeState.selectedSpaces; + + return (selectedCommunities, selectedSpaces); + } + + static void loadEnergyConsumptionByPhases(BuildContext context) { + const param = GetEnergyConsumptionByPhasesParam(); + context.read().add( + const LoadEnergyConsumptionByPhasesEvent(param: param), + ); + } + + static void loadTotalEnergyConsumption(BuildContext context) { + final (selectedCommunities, selectedSpaces) = + _getSelectedCommunitiesAndSpaces(context); + + final param = GetTotalEnergyConsumptionParam( + spaceId: selectedCommunities.firstOrNull, + ); + context.read().add( + TotalEnergyConsumptionLoadEvent(param: param), + ); + } + + static void loadEnergyConsumptionPerDevice(BuildContext context) { + const param = GetEnergyConsumptionPerDeviceParam(); + context.read().add( + const LoadEnergyConsumptionPerDeviceEvent(param), + ); + } + + static void loadPowerClampInfo(BuildContext context) { + context.read().add( + const LoadPowerClampInfoEvent('cb71d6ad-6e29-4eaa-ae3e-1a0d1c5f60fa'), + ); + } + + static void loadRealtimeDeviceChanges(BuildContext context) { + context.read().add( + const RealtimeDeviceChangesStarted('cb71d6ad-6e29-4eaa-ae3e-1a0d1c5f60fa'), + ); + } + + static void clearAllData(BuildContext context) { + context.read().add( + const RealtimeDeviceChangesClosed(), + ); + + context.read().add( + const ClearPowerClampInfoEvent(), + ); + context.read().add( + const ClearEnergyConsumptionPerDeviceEvent(), + ); + + context.read().add( + const ClearTotalEnergyConsumptionEvent(), + ); + + context.read().add( + const ClearEnergyConsumptionByPhasesEvent(), + ); + } +} diff --git a/lib/pages/analytics/modules/energy_management/views/analytics_energy_management_view.dart b/lib/pages/analytics/modules/energy_management/views/analytics_energy_management_view.dart index 9fb32422..cba5eea5 100644 --- a/lib/pages/analytics/modules/energy_management/views/analytics_energy_management_view.dart +++ b/lib/pages/analytics/modules/energy_management/views/analytics_energy_management_view.dart @@ -1,70 +1,11 @@ import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/energy_consumption_by_phases/energy_consumption_by_phases_bloc.dart'; -import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/energy_consumption_per_device/energy_consumption_per_device_bloc.dart'; -import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/power_clamp_info/power_clamp_info_bloc.dart'; -import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_bloc.dart'; -import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/total_energy_consumption/total_energy_consumption_bloc.dart'; import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart_box.dart'; import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/power_clamp_energy_data_widget.dart'; import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/total_energy_consumption_chart_box.dart'; -import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_by_phases_param.dart'; -import 'package:syncrow_web/pages/analytics/params/get_energy_consumption_per_device_param.dart'; -import 'package:syncrow_web/pages/analytics/params/get_total_energy_consumption_param.dart'; -import 'package:syncrow_web/utils/style.dart'; -class AnalyticsEnergyManagementView extends StatefulWidget { +class AnalyticsEnergyManagementView extends StatelessWidget { const AnalyticsEnergyManagementView({super.key}); - @override - State createState() => - _AnalyticsEnergyManagementViewState(); -} - -class _AnalyticsEnergyManagementViewState - extends State { - @override - void initState() { - _loadEnergyConsumptionByPhases(); - _loadTotalEnergyConsumption(); - _loadEnergyConsumptionPerDevice(); - _loadPowerClampInfo(); - - context.read().add( - const RealtimeDeviceChangesStarted( - 'cb71d6ad-6e29-4eaa-ae3e-1a0d1c5f60fa', - ), - ); - super.initState(); - } - - void _loadEnergyConsumptionByPhases() { - const param = GetEnergyConsumptionByPhasesParam(); - context.read().add( - const LoadEnergyConsumptionByPhasesEvent(param: param), - ); - } - - void _loadTotalEnergyConsumption() { - const param = GetTotalEnergyConsumptionParam(); - context.read().add( - const TotalEnergyConsumptionLoadEvent(param: param), - ); - } - - void _loadEnergyConsumptionPerDevice() { - const param = GetEnergyConsumptionPerDeviceParam(); - context.read().add( - const LoadEnergyConsumptionPerDeviceEvent(param), - ); - } - - void _loadPowerClampInfo() { - context.read().add( - const LoadPowerClampInfoEvent('deviceId'), - ); - } - static const _padding = EdgeInsetsDirectional.all(32); @override @@ -80,13 +21,7 @@ class _AnalyticsEnergyManagementViewState children: [ SizedBox( height: MediaQuery.sizeOf(context).height * 1.2, - child: Container( - decoration: subSectionContainerDecoration.copyWith( - borderRadius: BorderRadius.circular(30), - ), - padding: const EdgeInsetsDirectional.all(32), - child: const PowerClampEnergyDataWidget(), - ), + child: const PowerClampEnergyDataWidget(), ), SizedBox( height: MediaQuery.sizeOf(context).height * 0.5,