Compare commits

..

5 Commits

38 changed files with 745 additions and 555 deletions

View File

@ -0,0 +1,8 @@
<svg width="175" height="134" viewBox="0 0 175 134" fill="none" xmlns="http://www.w3.org/2000/svg">
<line x1="0.5" y1="2.18557e-08" x2="0.499994" y2="132.759" stroke="#B9C0C5"/>
<line x1="175" y1="133.259" x2="-4.37114e-08" y2="133.259" stroke="#B9C0C5"/>
<rect x="16.0922" y="66.3794" width="28.1609" height="66.3793" fill="#C7CDD1"/>
<rect x="54.3105" y="24.1379" width="28.1609" height="108.621" fill="#ABB4BA"/>
<rect x="92.5288" y="78.4484" width="28.1609" height="54.3103" fill="#C7CDD1"/>
<rect x="130.747" y="48.2759" width="28.1609" height="84.4828" fill="#ABB4BA"/>
</svg>

After

Width:  |  Height:  |  Size: 583 B

View File

@ -0,0 +1,5 @@
<svg width="175" height="134" viewBox="0 0 175 134" fill="none" xmlns="http://www.w3.org/2000/svg">
<line x1="0.5" y1="3.05394e-05" x2="0.499994" y2="132.759" stroke="#B9C0C5"/>
<line x1="175" y1="133.259" x2="-4.37114e-08" y2="133.259" stroke="#B9C0C5"/>
<path d="M1.5 132.5C13 132.5 6.58852 66.5 29.5 66.5C46.5 66.5 46.1214 24.9349 68.5 24.5C94.2816 23.999 80.7136 78.5065 106.5 78.5C125.715 78.4952 131.5 48.5 145.5 48.5C159.5 48.5 156.5 96 171.5 96" stroke="#ABB4BA" stroke-width="2" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 520 B

View File

@ -0,0 +1,7 @@
<svg width="175" height="134" viewBox="0 0 175 134" fill="none" xmlns="http://www.w3.org/2000/svg">
<line x1="0.5" y1="2.18557e-08" x2="0.499994" y2="132.759" stroke="#B9C0C5"/>
<line x1="175" y1="133.259" x2="-4.37114e-08" y2="133.259" stroke="#B9C0C5"/>
<path d="M1.5 132.5C13 132.5 6.58852 66.5 29.5 66.5C46.5 66.5 46.1214 24.9348 68.5 24.5C94.2816 23.999 80.7136 78.5064 106.5 78.5C125.715 78.4951 131.5 48.5 145.5 48.5C159.5 48.5 156.5 95.9999 171.5 95.9999" stroke="#ABB4BA" stroke-width="1.5" stroke-linecap="round" stroke-dasharray="4 4"/>
<path d="M1.5 132.5C13 132.5 6.58852 78.4999 29.5 78.4999C46.5 78.4999 45.6214 44.9349 68 44.5C93.7816 43.999 80.7136 27.0065 106.5 27C125.715 26.9952 131.5 63.5 145.5 63.5C159.5 63.5 156.5 113.5 171.5 113.5" stroke="#C7CDD1" stroke-width="1.5" stroke-linecap="round" stroke-dasharray="4 4"/>
<path d="M1.5 132.5C13 132.5 6.58852 85.9999 29.5 85.9999C46.5 85.9999 45.6214 11.9348 68 11.4999C93.7816 10.9989 80.7136 43.5064 106.5 43.4999C125.715 43.4951 131.5 35.4999 145.5 35.4999C159.5 35.4999 156.5 105.5 171.5 105.5" stroke="#D5D5D5" stroke-width="1.5" stroke-linecap="round" stroke-dasharray="4 4"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,99 @@
<svg width="181" height="121" viewBox="0 0 181 121" fill="none" xmlns="http://www.w3.org/2000/svg">
<line x1="15.5" y1="-2.52181e-08" x2="15.5" y2="120" stroke="#B9B9B9"/>
<line x1="45.5" y1="-2.52181e-08" x2="45.5" y2="120" stroke="#B9B9B9"/>
<line x1="75.5" y1="-2.52181e-08" x2="75.5" y2="120" stroke="#B9B9B9"/>
<line x1="105.5" y1="-2.52181e-08" x2="105.5" y2="120" stroke="#B9B9B9"/>
<line x1="135.5" y1="-2.52181e-08" x2="135.5" y2="120" stroke="#B9B9B9"/>
<line x1="165.5" y1="-2.52181e-08" x2="165.5" y2="120" stroke="#B9B9B9"/>
<line x1="30.5" y1="-2.52181e-08" x2="30.5" y2="120" stroke="#B9B9B9"/>
<line x1="60.5" y1="-2.52181e-08" x2="60.5" y2="120" stroke="#B9B9B9"/>
<line x1="90.5" y1="-2.52181e-08" x2="90.5" y2="120" stroke="#B9B9B9"/>
<line x1="120.5" y1="-2.52181e-08" x2="120.5" y2="120" stroke="#B9B9B9"/>
<line x1="150.5" y1="-2.52181e-08" x2="150.5" y2="120" stroke="#B9B9B9"/>
<line x1="180.5" y1="-2.52181e-08" x2="180.5" y2="120" stroke="#B9B9B9"/>
<line x1="181" y1="120.5" x2="-4.52101e-08" y2="120.5" stroke="#B9B9B9"/>
<line x1="181" y1="60.5" x2="-4.52101e-08" y2="60.5" stroke="#B9B9B9"/>
<line x1="181" y1="90.5" x2="-4.52101e-08" y2="90.5" stroke="#B9B9B9"/>
<line x1="181" y1="30.5" x2="-4.52101e-08" y2="30.5" stroke="#B9B9B9"/>
<line x1="181" y1="105.5" x2="-4.52101e-08" y2="105.5" stroke="#B9B9B9"/>
<line x1="181" y1="45.5" x2="-4.52101e-08" y2="45.5" stroke="#B9B9B9"/>
<line x1="181" y1="75.5" x2="-4.52101e-08" y2="75.5" stroke="#B9B9B9"/>
<line x1="181" y1="15.5" x2="-4.52101e-08" y2="15.5" stroke="#B9B9B9"/>
<rect x="16" y="16" width="14" height="14" fill="#F2F2F2"/>
<rect x="31" y="16" width="14" height="14" fill="#F2F2F2"/>
<rect x="46" y="16" width="14" height="14" fill="#F2F2F2"/>
<rect x="61" y="16" width="14" height="14" fill="#F2F2F2"/>
<rect x="76" y="16" width="14" height="14" fill="#F2F2F2"/>
<rect x="91" y="16" width="14" height="14" fill="#F2F2F2"/>
<rect x="106" y="16" width="14" height="14" fill="#F2F2F2"/>
<rect x="121" y="16" width="14" height="14" fill="#F2F2F2"/>
<rect x="136" y="16" width="14" height="14" fill="#F2F2F2"/>
<rect x="151" y="16" width="14" height="14" fill="#F2F2F2"/>
<rect x="166" y="16" width="14" height="14" fill="#F2F2F2"/>
<rect x="16" y="31" width="14" height="14" fill="#F2F2F2"/>
<rect x="31" y="31" width="14" height="14" fill="#D5D5D5"/>
<rect x="46" y="31" width="14" height="14" fill="#D5D5D5"/>
<rect x="61" y="31" width="14" height="14" fill="#D5D5D5"/>
<rect x="76" y="31" width="14" height="14" fill="#D5D5D5"/>
<rect x="91" y="31" width="14" height="14" fill="#D5D5D5"/>
<rect x="106" y="31" width="14" height="14" fill="#D5D5D5"/>
<rect x="121" y="31" width="14" height="14" fill="#D5D5D5"/>
<rect x="136" y="31" width="14" height="14" fill="#D5D5D5"/>
<rect x="151" y="31" width="14" height="14" fill="#D5D5D5"/>
<rect x="166" y="31" width="14" height="14" fill="#F2F2F2"/>
<rect x="16" y="46" width="14" height="14" fill="#F2F2F2"/>
<rect x="31" y="46" width="14" height="14" fill="#D5D5D5"/>
<rect x="46" y="46" width="14" height="14" fill="#D5D5D5"/>
<rect x="61" y="46" width="14" height="14" fill="#D5D5D5"/>
<rect x="76" y="46" width="14" height="14" fill="#D5D5D5"/>
<rect x="91" y="46" width="14" height="14" fill="#D5D5D5"/>
<rect x="106" y="46" width="14" height="14" fill="#D5D5D5"/>
<rect x="121" y="46" width="14" height="14" fill="#D5D5D5"/>
<rect x="136" y="46" width="14" height="14" fill="#D5D5D5"/>
<rect x="151" y="46" width="14" height="14" fill="#D5D5D5"/>
<rect x="166" y="46" width="14" height="14" fill="#F2F2F2"/>
<rect x="16" y="61" width="14" height="14" fill="#F2F2F2"/>
<rect x="31" y="61" width="14" height="14" fill="#D5D5D5"/>
<rect x="46" y="61" width="14" height="14" fill="#D5D5D5"/>
<rect x="61" y="61" width="14" height="14" fill="#B1B1B1"/>
<rect x="76" y="61" width="14" height="14" fill="#B1B1B1"/>
<rect x="91" y="61" width="14" height="14" fill="#B1B1B1"/>
<rect x="106" y="61" width="14" height="14" fill="#B1B1B1"/>
<rect x="121" y="61" width="14" height="14" fill="#B1B1B1"/>
<rect x="136" y="61" width="14" height="14" fill="#D5D5D5"/>
<rect x="151" y="61" width="14" height="14" fill="#D5D5D5"/>
<rect x="166" y="61" width="14" height="14" fill="#F2F2F2"/>
<rect x="16" y="76" width="14" height="14" fill="#F2F2F2"/>
<rect x="31" y="76" width="14" height="14" fill="#D5D5D5"/>
<rect x="46" y="76" width="14" height="14" fill="#D5D5D5"/>
<rect x="61" y="76" width="14" height="14" fill="#D5D5D5"/>
<rect x="76" y="76" width="14" height="14" fill="#D5D5D5"/>
<rect x="91" y="76" width="14" height="14" fill="#D5D5D5"/>
<rect x="106" y="76" width="14" height="14" fill="#D5D5D5"/>
<rect x="121" y="76" width="14" height="14" fill="#D5D5D5"/>
<rect x="136" y="76" width="14" height="14" fill="#D5D5D5"/>
<rect x="151" y="76" width="14" height="14" fill="#D5D5D5"/>
<rect x="166" y="76" width="14" height="14" fill="#F2F2F2"/>
<rect x="16" y="91" width="14" height="14" fill="#F2F2F2"/>
<rect x="31" y="91" width="14" height="14" fill="#D5D5D5"/>
<rect x="46" y="91" width="14" height="14" fill="#D5D5D5"/>
<rect x="61" y="91" width="14" height="14" fill="#D5D5D5"/>
<rect x="76" y="91" width="14" height="14" fill="#D5D5D5"/>
<rect x="91" y="91" width="14" height="14" fill="#D5D5D5"/>
<rect x="106" y="91" width="14" height="14" fill="#D5D5D5"/>
<rect x="121" y="91" width="14" height="14" fill="#D5D5D5"/>
<rect x="136" y="91" width="14" height="14" fill="#D5D5D5"/>
<rect x="151" y="91" width="14" height="14" fill="#D5D5D5"/>
<rect x="166" y="91" width="14" height="14" fill="#F2F2F2"/>
<rect x="16" y="106" width="14" height="14" fill="#F2F2F2"/>
<rect x="31" y="106" width="14" height="14" fill="#F2F2F2"/>
<rect x="46" y="106" width="14" height="14" fill="#F2F2F2"/>
<rect x="61" y="106" width="14" height="14" fill="#F2F2F2"/>
<rect x="76" y="106" width="14" height="14" fill="#F2F2F2"/>
<rect x="91" y="106" width="14" height="14" fill="#F2F2F2"/>
<rect x="106" y="106" width="14" height="14" fill="#F2F2F2"/>
<rect x="121" y="106" width="14" height="14" fill="#F2F2F2"/>
<rect x="136" y="106" width="14" height="14" fill="#F2F2F2"/>
<rect x="151" y="106" width="14" height="14" fill="#F2F2F2"/>
<rect x="166" y="106" width="14" height="14" fill="#F2F2F2"/>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -0,0 +1,7 @@
<svg width="175" height="134" viewBox="0 0 175 134" fill="none" xmlns="http://www.w3.org/2000/svg">
<line x1="0.5" y1="2.18557e-08" x2="0.499994" y2="132.759" stroke="#B9C0C5"/>
<line x1="175" y1="133.259" x2="-4.37114e-08" y2="133.259" stroke="#B9C0C5"/>
<path d="M1.5 95.9999C13 95.9999 6.58853 66.4999 29.5 66.4999C46.5 66.4999 46.1214 34.9348 68.5 34.4999C94.2816 33.9989 80.7136 65.0065 106.5 65C125.715 64.9952 131.5 50.5 145.5 50.5C159.5 50.5 156.5 70.5 171.5 70.5" stroke="#C7CDD1" stroke-width="2" stroke-linecap="round"/>
<path d="M1.5 106C13 106 6.58853 76.4999 29.5 76.4999C46.5 76.4999 46.1214 44.9348 68.5 44.4999C94.2816 43.9989 80.7136 75.0065 106.5 75C125.715 74.9952 131.5 60.5 145.5 60.5C159.5 60.5 156.5 80.5 171.5 80.5" stroke="#F2F2F2" stroke-width="2" stroke-linecap="round"/>
<path d="M1.5 116C13 116 6.58853 86.4999 29.5 86.4999C46.5 86.4999 46.1214 54.9348 68.5 54.4999C94.2816 53.9989 80.7136 85.0065 106.5 85C125.715 84.9952 131.5 70.5 145.5 70.5C159.5 70.5 156.5 90.5 171.5 90.5" stroke="#ABB4BA" stroke-width="2" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -3,7 +3,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/blocs/air_quality_distribution/air_quality_distribution_bloc.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart_title.dart';
import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart';
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/style.dart';
class AqiDistributionChartBox extends StatelessWidget {
@ -32,8 +34,20 @@ class AqiDistributionChartBox extends StatelessWidget {
const SizedBox(height: 10),
const Divider(),
const SizedBox(height: 20),
Expanded(
child: AqiDistributionChart(chartData: state.chartData),
Visibility(
visible: state.chartData.isNotEmpty,
replacement: AnalyticsChartEmptyStateWidget(
isLoading: state.status == AirQualityDistributionStatus.loading,
isError: state.status == AirQualityDistributionStatus.failure,
isInitial: state.status == AirQualityDistributionStatus.initial,
errorMessage: state.errorMessage,
iconPath: Assets.emptyBarredChart,
),
child: Expanded(
child: AqiDistributionChart(
chartData: state.chartData,
),
),
),
],
),

View File

@ -3,7 +3,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/blocs/range_of_aqi/range_of_aqi_bloc.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/range_of_aqi_chart.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/range_of_aqi_chart_title.dart';
import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart';
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/style.dart';
class RangeOfAqiChartBox extends StatelessWidget {
@ -32,12 +34,22 @@ class RangeOfAqiChartBox extends StatelessWidget {
const SizedBox(height: 10),
const Divider(),
const SizedBox(height: 20),
Expanded(
Visibility(
visible: state.filteredRangeOfAqi.isNotEmpty,
replacement: AnalyticsChartEmptyStateWidget(
isLoading: state.status == RangeOfAqiStatus.loading,
isError: state.status == RangeOfAqiStatus.failure,
isInitial: state.status == RangeOfAqiStatus.initial,
errorMessage: state.errorMessage,
iconPath: Assets.emptyRangeOfAqi,
),
child: Expanded(
child: RangeOfAqiChart(
chartData: state.filteredRangeOfAqi,
selectedAqiType: state.selectedAqiType,
),
),
),
],
),
);

View File

@ -5,8 +5,10 @@ import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/ener
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/chart_title.dart';
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_chart.dart';
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/energy_consumption_per_device_devices_list.dart';
import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart';
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
import 'package:syncrow_web/pages/analytics/widgets/charts_loading_widget.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/style.dart';
class EnergyConsumptionPerDeviceChartBox extends StatelessWidget {
@ -54,8 +56,24 @@ class EnergyConsumptionPerDeviceChartBox extends StatelessWidget {
const SizedBox(height: 20),
const Divider(height: 0),
const SizedBox(height: 20),
Expanded(
child: EnergyConsumptionPerDeviceChart(chartData: state.chartData),
Visibility(
visible: state.chartData.isNotEmpty &&
state.chartData
.every((e) => e.energy.every((e) => e.value != 0)),
replacement: AnalyticsChartEmptyStateWidget(
isLoading:
state.status == EnergyConsumptionPerDeviceStatus.loading,
isError: state.status == EnergyConsumptionPerDeviceStatus.failure,
isInitial:
state.status == EnergyConsumptionPerDeviceStatus.initial,
errorMessage: state.errorMessage,
iconPath: Assets.emptyEnergyManagementPerDevice,
),
child: Expanded(
child: EnergyConsumptionPerDeviceChart(
chartData: state.chartData,
),
),
),
],
),

View File

@ -3,8 +3,10 @@ import 'package:flutter_bloc/flutter_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/chart_title.dart';
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/total_energy_consumption_chart.dart';
import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart';
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
import 'package:syncrow_web/pages/analytics/widgets/charts_loading_widget.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/style.dart';
class TotalEnergyConsumptionChartBox extends StatelessWidget {
@ -41,7 +43,18 @@ class TotalEnergyConsumptionChartBox extends StatelessWidget {
const SizedBox(height: 20),
const Divider(),
const SizedBox(height: 20),
TotalEnergyConsumptionChart(chartData: state.chartData),
Visibility(
visible: state.chartData.isNotEmpty &&
state.chartData.every((e) => e.value != 0),
replacement: AnalyticsChartEmptyStateWidget(
isLoading: state.status == TotalEnergyConsumptionStatus.loading,
isError: state.status == TotalEnergyConsumptionStatus.failure,
isInitial: state.status == TotalEnergyConsumptionStatus.initial,
errorMessage: state.errorMessage,
iconPath: Assets.emptyEnergyManagementChart,
),
child: TotalEnergyConsumptionChart(chartData: state.chartData),
),
],
),
),

View File

@ -6,8 +6,10 @@ import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/ch
import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy/occupancy_bloc.dart';
import 'package:syncrow_web/pages/analytics/modules/occupancy/helpers/fetch_occupancy_data_helper.dart';
import 'package:syncrow_web/pages/analytics/modules/occupancy/widgets/occupancy_chart.dart';
import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart';
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/style.dart';
class OccupancyChartBox extends StatelessWidget {
@ -67,7 +69,24 @@ class OccupancyChartBox extends StatelessWidget {
const SizedBox(height: 20),
const Divider(),
const SizedBox(height: 20),
Expanded(child: OccupancyChart(chartData: state.chartData)),
Visibility(
visible: state.chartData.isNotEmpty &&
state.chartData.every(
(e) => e.occupancy.isNotEmpty,
),
replacement: AnalyticsChartEmptyStateWidget(
isLoading: state.status == OccupancyStatus.loading,
isError: state.status == OccupancyStatus.failure,
isInitial: state.status == OccupancyStatus.initial,
errorMessage: state.errorMessage,
iconPath: Assets.emptyBarredChart,
),
child: Expanded(
child: OccupancyChart(
chartData: state.chartData,
),
),
),
],
),
);

View File

@ -6,8 +6,10 @@ import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/ch
import 'package:syncrow_web/pages/analytics/modules/occupancy/blocs/occupancy_heat_map/occupancy_heat_map_bloc.dart';
import 'package:syncrow_web/pages/analytics/modules/occupancy/helpers/fetch_occupancy_data_helper.dart';
import 'package:syncrow_web/pages/analytics/modules/occupancy/widgets/occupancy_heat_map.dart';
import 'package:syncrow_web/pages/analytics/widgets/analytics_chart_empty_state_widget.dart';
import 'package:syncrow_web/pages/analytics/widgets/analytics_error_widget.dart';
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/style.dart';
class OccupancyHeatMapBox extends StatelessWidget {
@ -68,7 +70,19 @@ class OccupancyHeatMapBox extends StatelessWidget {
const SizedBox(height: 20),
const Divider(),
const SizedBox(height: 20),
Expanded(
Visibility(
visible: state.heatMapData.isNotEmpty &&
state.heatMapData.every(
(e) => e.countTotalPresenceDetected != 0,
),
replacement: AnalyticsChartEmptyStateWidget(
isLoading: state.status == OccupancyHeatMapStatus.loading,
isError: state.status == OccupancyHeatMapStatus.failure,
isInitial: state.status == OccupancyHeatMapStatus.initial,
errorMessage: state.errorMessage,
iconPath: Assets.emptyHeatmap,
),
child: Expanded(
child: OccupancyHeatMap(
selectedDate:
context.watch<AnalyticsDatePickerBloc>().state.yearlyDate,
@ -80,6 +94,7 @@ class OccupancyHeatMapBox extends StatelessWidget {
),
),
),
),
],
),
);

View File

@ -17,8 +17,8 @@ class DeviceLocationDetailsServiceDecorator implements DeviceLocationService {
'reverse',
queryParameters: {
'format': 'json',
'lat': 25.1880567,
'lon': 55.266608,
'lat': param.latitude,
'lon': param.longitude,
},
);

View File

@ -0,0 +1,68 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:syncrow_web/common/widgets/app_loading_indicator.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
class AnalyticsChartEmptyStateWidget extends StatelessWidget {
const AnalyticsChartEmptyStateWidget({
required this.iconPath,
this.isLoading = false,
this.isError = false,
this.isInitial = false,
this.errorMessage,
this.noDataMessage = 'No data to display',
this.initialMessage = 'Please select a space to see data',
super.key,
});
final bool isLoading;
final bool isError;
final bool isInitial;
final String? errorMessage;
final String noDataMessage;
final String initialMessage;
final String iconPath;
@override
Widget build(BuildContext context) {
return Expanded(
child: _buildWidgetBasedOnState(context),
);
}
Widget _buildWidgetBasedOnState(BuildContext context) {
final widgetsMap = {
isLoading: const AppLoadingIndicator(),
isInitial: _buildState(context, initialMessage),
isError: _buildState(context, errorMessage ?? 'Something went wrong'),
};
return widgetsMap[true] ?? _buildState(context, noDataMessage);
}
Widget _buildState(BuildContext context, String message) {
return Center(
child: Column(
spacing: 16,
mainAxisAlignment: MainAxisAlignment.center,
children: [
const SizedBox(height: 16),
Expanded(child: SvgPicture.asset(iconPath, fit: BoxFit.contain)),
SelectableText(
message,
style: isError
? context.textTheme.bodyMedium?.copyWith(
color: ColorsManager.red,
fontSize: 16,
fontWeight: FontWeight.w700,
)
: null,
textAlign: TextAlign.center,
),
const SizedBox(height: 16),
],
),
);
}
}

View File

@ -57,9 +57,6 @@ class Status {
};
}
factory Status.fromJson(String source) => Status.fromMap(json.decode(source));
String toJson() => json.encode(toMap());
Status copyWith({
String? code,
dynamic value,
@ -69,4 +66,8 @@ class Status {
value: value ?? this.value,
);
}
factory Status.fromJson(String source) => Status.fromMap(json.decode(source));
String toJson() => json.encode(toMap());
}

View File

@ -62,10 +62,9 @@ class CurtainModuleItems extends StatelessWidget with HelperResponsiveLayout {
BlocProvider.of<CurtainModuleBloc>(context),
child: BuildScheduleView(
deviceUuid: deviceId,
category: 'timer',
category: 'CUR_2',
code: 'control',
countdownCode: 'timer',
deviceType: 'CUR_2',
),
));
},

View File

@ -40,7 +40,7 @@ class OneGangGlassSwitchBloc
emit(OneGangGlassSwitchLoading());
try {
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
_listenToChanges(event.deviceId);
_listenToChanges(event.deviceId, emit);
deviceStatus = OneGangGlassStatusModel.fromJson(event.deviceId, status.status);
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
} catch (e) {
@ -48,28 +48,42 @@ class OneGangGlassSwitchBloc
}
}
StreamSubscription<DatabaseEvent>? _deviceStatusSubscription;
void _listenToChanges(String deviceId) {
void _listenToChanges(
String deviceId,
Emitter<OneGangGlassSwitchState> emit,
) {
try {
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
_deviceStatusSubscription = ref.onValue.listen((DatabaseEvent event) async {
if (event.snapshot.value == null) return;
final stream = ref.onValue;
final usersMap = event.snapshot.value! as Map<dynamic, dynamic>;
stream.listen((DatabaseEvent event) {
final data = event.snapshot.value as Map<dynamic, dynamic>?;
if (data == null) return;
final statusList = <Status>[];
usersMap['status'].forEach((element) {
statusList.add(Status(code: element['code'], value: element['value']));
});
deviceStatus =
OneGangGlassStatusModel.fromJson(usersMap['productUuid'], statusList);
if (data['status'] != null) {
for (var element in data['status']) {
statusList.add(
Status(
code: element['code'].toString(),
value: element['value'].toString(),
),
);
}
}
if (statusList.isNotEmpty) {
final newStatus = OneGangGlassStatusModel.fromJson(deviceId, statusList);
if (newStatus != deviceStatus) {
deviceStatus = newStatus;
if (!isClosed) {
add(StatusUpdated(deviceStatus));
}
}
}
});
} catch (_) {}
} catch (e) {
emit(OneGangGlassSwitchError('Failed to listen to changes: $e'));
}
}
void _onStatusUpdated(
@ -160,10 +174,4 @@ class OneGangGlassSwitchBloc
deviceStatus = deviceStatus.copyWith(switch1: value);
}
}
@override
Future<void> close() {
_deviceStatusSubscription?.cancel();
return super.close();
}
}

View File

@ -90,8 +90,6 @@ class OneGangGlassSwitchControlView extends StatelessWidget
child: BuildScheduleView(
category: 'switch_1',
deviceUuid: deviceId,
countdownCode: 'countdown_1',
deviceType: '1GT',
),
));
},

View File

@ -80,8 +80,6 @@ class WallLightDeviceControl extends StatelessWidget
child: BuildScheduleView(
category: 'switch_1',
deviceUuid: deviceId,
countdownCode: 'countdown_1',
deviceType: '1G',
),
));
},

View File

@ -47,7 +47,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
final success = await RemoteControlDeviceService().controlDevice(
deviceUuid: deviceId,
status: Status(
code: event.countdownCode,
code: 'countdown_1',
value: 0,
),
);
@ -80,18 +80,15 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
) {
if (state is ScheduleLoaded) {
final currentState = state as ScheduleLoaded;
emit(currentState.copyWith(
countdownSeconds: currentState.countdownSeconds,
selectedTime: currentState.selectedTime,
deviceId: deviceId,
scheduleMode: event.scheduleMode,
countdownHours: currentState.countdownHours,
countdownMinutes: currentState.countdownMinutes,
inchingHours: currentState.inchingHours,
inchingMinutes: currentState.inchingMinutes,
countdownRemaining: Duration.zero,
countdownHours: 0,
countdownMinutes: 0,
inchingHours: 0,
inchingMinutes: 0,
isCountdownActive: false,
isInchingActive: false,
isCountdownActive: currentState.countdownRemaining > Duration.zero,
));
}
}
@ -224,6 +221,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
deviceId,
event.category,
);
if (state is ScheduleLoaded) {
final currentState = state as ScheduleLoaded;
emit(currentState.copyWith(
@ -287,8 +285,9 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
) async {
try {
if (state is ScheduleLoaded) {
final dateTime = DateTime.parse(event.time);
Status status = Status(code: '', value: '');
if (event.deviceType == 'CUR_2') {
if (event.category == 'CUR_2') {
status = status.copyWith(
code: 'control',
value: event.functionOn == true ? 'open' : 'close');
@ -296,8 +295,6 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
status =
status.copyWith(code: event.category, value: event.functionOn);
}
final dateTime = DateTime.parse(event.time);
final updatedSchedule = ScheduleEntry(
scheduleId: event.scheduleId,
category: event.category,
@ -408,7 +405,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
final totalSeconds =
Duration(hours: event.hours, minutes: event.minutes).inSeconds;
final code = event.mode == ScheduleModes.countdown
? event.countDownCode
? 'countdown_1'
: 'switch_inching';
final currentState = state as ScheduleLoaded;
final duration = Duration(seconds: totalSeconds);
@ -435,7 +432,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
);
if (success) {
if (code == event.countDownCode) {
if (code == 'countdown_1') {
final countdownDuration = Duration(seconds: totalSeconds);
emit(
@ -449,7 +446,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
);
if (countdownDuration.inSeconds > 0) {
_startCountdownTimer(emit, countdownDuration, event.countDownCode);
_startCountdownTimer(emit, countdownDuration);
} else {
_countdownTimer?.cancel();
emit(
@ -479,7 +476,9 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
}
void _startCountdownTimer(
Emitter<ScheduleState> emit, Duration duration, String countdownCode) {
Emitter<ScheduleState> emit,
Duration duration,
) {
_countdownTimer?.cancel();
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (_currentCountdown != null && _currentCountdown! > Duration.zero) {
@ -489,7 +488,6 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
} else {
timer.cancel();
add(StopScheduleEvent(
countdownCode: countdownCode,
mode: _currentCountdown == null
? ScheduleModes.countdown
: ScheduleModes.inching,
@ -526,75 +524,70 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
try {
final status =
await DevicesManagementApi().getDeviceStatus(event.deviceId);
int totalSeconds = 0;
final countdownItem = status.status.firstWhere(
(item) => item.code == event.countdownCode,
orElse: () => Status(code: '', value: 0),
);
totalSeconds = (countdownItem.value as int?) ?? 0;
final countdownHours = totalSeconds ~/ 3600;
final countdownMinutes = (totalSeconds % 3600) ~/ 60;
final countdownSeconds = totalSeconds % 60;
print(status.status);
final deviceStatus =
WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
final isCountdownActive = totalSeconds > 0;
final isInchingActive = !isCountdownActive &&
(deviceStatus.inchingHours > 0 || deviceStatus.inchingMinutes > 0);
final newState = state is ScheduleLoaded
? (state as ScheduleLoaded).copyWith(
scheduleMode: ScheduleModes.schedule,
countdownHours: countdownHours,
countdownMinutes: countdownMinutes,
countdownSeconds: countdownSeconds,
final scheduleMode =
deviceStatus.countdownHours > 0 || deviceStatus.countdownMinutes > 0
? ScheduleModes.countdown
: deviceStatus.inchingHours > 0 || deviceStatus.inchingMinutes > 0
? ScheduleModes.inching
: ScheduleModes.schedule;
final isCountdown = scheduleMode == ScheduleModes.countdown;
final isInching = scheduleMode == ScheduleModes.inching;
Duration? countdownRemaining;
var isCountdownActive = false;
var isInchingActive = false;
if (isCountdown) {
countdownRemaining = Duration(
hours: deviceStatus.countdownHours,
minutes: deviceStatus.countdownMinutes,
);
isCountdownActive = countdownRemaining > Duration.zero;
} else if (isInching) {
isInchingActive = Duration(
hours: deviceStatus.inchingHours,
minutes: deviceStatus.inchingMinutes,
) >
Duration.zero;
}
if (state is ScheduleLoaded) {
final currentState = state as ScheduleLoaded;
emit(currentState.copyWith(
scheduleMode: scheduleMode,
countdownHours: deviceStatus.countdownHours,
countdownMinutes: deviceStatus.countdownMinutes,
inchingHours: deviceStatus.inchingHours,
inchingMinutes: deviceStatus.inchingMinutes,
isCountdownActive: isCountdownActive,
isInchingActive: isInchingActive,
countdownRemaining: isCountdownActive
? Duration(seconds: totalSeconds)
: Duration.zero,
)
: ScheduleLoaded(
scheduleMode: ScheduleModes.schedule,
countdownRemaining: countdownRemaining ?? Duration.zero,
));
} else {
emit(ScheduleLoaded(
schedules: const [],
selectedTime: null,
selectedDays: List.filled(7, false),
functionOn: false,
isEditing: false,
deviceId: event.deviceId,
countdownHours: countdownHours,
countdownMinutes: countdownMinutes,
countdownSeconds: countdownSeconds,
deviceId: deviceId,
scheduleMode: scheduleMode,
countdownHours: deviceStatus.countdownHours,
countdownMinutes: deviceStatus.countdownMinutes,
inchingHours: deviceStatus.inchingHours,
inchingMinutes: deviceStatus.inchingMinutes,
isCountdownActive: isCountdownActive,
isInchingActive: isInchingActive,
countdownRemaining: isCountdownActive
? Duration(seconds: totalSeconds)
: Duration.zero,
);
emit(newState);
if (isCountdownActive) {
_countdownTimer?.cancel();
_currentCountdown = Duration(seconds: totalSeconds);
countdownRemaining = _currentCountdown!;
if (totalSeconds > 0) {
_startCountdownTimer(
emit, Duration(seconds: totalSeconds), event.countdownCode);
} else {
add(StopScheduleEvent(
countdownCode: event.countdownCode,
mode: ScheduleModes.countdown,
deviceId: event.deviceId,
countdownRemaining: countdownRemaining ?? Duration.zero,
));
}
} else {
_countdownTimer?.cancel();
}
// if (isCountdownActive && countdownRemaining != null) {
// _startCountdownTimer(emit, countdownRemaining);
// }
} catch (e) {
emit(ScheduleError('Failed to fetch device status: $e'));
}

View File

@ -91,7 +91,6 @@ class ScheduleEditEvent extends ScheduleEvent {
final String time;
final List<String> selectedDays;
final bool functionOn;
final String deviceType;
const ScheduleEditEvent({
required this.scheduleId,
@ -99,7 +98,6 @@ class ScheduleEditEvent extends ScheduleEvent {
required this.time,
required this.selectedDays,
required this.functionOn,
required this.deviceType,
});
@override
@ -109,7 +107,6 @@ class ScheduleEditEvent extends ScheduleEvent {
time,
selectedDays,
functionOn,
deviceType,
];
}
@ -141,13 +138,11 @@ class ScheduleUpdateEntryEvent extends ScheduleEvent {
class UpdateScheduleModeEvent extends ScheduleEvent {
final ScheduleModes scheduleMode;
final String countdownCode;
const UpdateScheduleModeEvent(
{required this.scheduleMode, required this.countdownCode});
const UpdateScheduleModeEvent({required this.scheduleMode});
@override
List<Object> get props => [scheduleMode, countdownCode!];
List<Object> get props => [scheduleMode];
}
class UpdateCountdownTimeEvent extends ScheduleEvent {
@ -182,32 +177,28 @@ class StartScheduleEvent extends ScheduleEvent {
final ScheduleModes mode;
final int hours;
final int minutes;
final String countDownCode;
const StartScheduleEvent({
required this.mode,
required this.hours,
required this.minutes,
required this.countDownCode,
});
@override
List<Object?> get props => [mode, hours, minutes, countDownCode];
List<Object?> get props => [mode, hours, minutes];
}
class StopScheduleEvent extends ScheduleEvent {
final ScheduleModes mode;
final String deviceId;
final String countdownCode;
const StopScheduleEvent({
required this.mode,
required this.deviceId,
required this.countdownCode,
});
@override
List<Object?> get props => [mode, deviceId, countdownCode];
List<Object?> get props => [mode, deviceId];
}
class ScheduleDecrementCountdownEvent extends ScheduleEvent {
@ -219,13 +210,11 @@ class ScheduleDecrementCountdownEvent extends ScheduleEvent {
class ScheduleFetchStatusEvent extends ScheduleEvent {
final String deviceId;
final String countdownCode;
const ScheduleFetchStatusEvent(
{required this.deviceId, required this.countdownCode});
const ScheduleFetchStatusEvent(this.deviceId);
@override
List<Object> get props => [deviceId, countdownCode];
List<Object> get props => [deviceId];
}
class DeleteScheduleEvent extends ScheduleEvent {

View File

@ -29,7 +29,7 @@ class ScheduleLoaded extends ScheduleState {
final int inchingSeconds;
final bool isInchingActive;
final ScheduleModes scheduleMode;
final Duration countdownRemaining;
final Duration? countdownRemaining;
final int? countdownSeconds;
const ScheduleLoaded({
@ -48,7 +48,7 @@ class ScheduleLoaded extends ScheduleState {
this.inchingMinutes = 0,
this.isInchingActive = false,
this.scheduleMode = ScheduleModes.countdown,
this.countdownRemaining = Duration.zero,
this.countdownRemaining,
});
ScheduleLoaded copyWith({

View File

@ -11,7 +11,6 @@ class CountdownModeButtons extends StatelessWidget {
final String deviceId;
final int hours;
final int minutes;
final String countDownCode;
const CountdownModeButtons({
super.key,
@ -19,7 +18,6 @@ class CountdownModeButtons extends StatelessWidget {
required this.deviceId,
required this.hours,
required this.minutes,
required this.countDownCode,
});
@override
@ -45,7 +43,6 @@ class CountdownModeButtons extends StatelessWidget {
StopScheduleEvent(
mode: ScheduleModes.countdown,
deviceId: deviceId,
countdownCode: countDownCode,
),
);
},
@ -60,7 +57,7 @@ class CountdownModeButtons extends StatelessWidget {
mode: ScheduleModes.countdown,
hours: hours,
minutes: minutes,
countDownCode: countDownCode),
),
);
},
backgroundColor: ColorsManager.primaryColor,

View File

@ -75,33 +75,23 @@ class _CountdownInchingViewState extends State<CountdownInchingView> {
final isCountDown = state.scheduleMode == ScheduleModes.countdown;
final isActive =
isCountDown ? state.isCountdownActive : state.isInchingActive;
final displayHours =
isActive && state.countdownRemaining != Duration.zero
? state.countdownRemaining.inHours
final displayHours = isActive && state.countdownRemaining != null
? state.countdownRemaining!.inHours
: (isCountDown ? state.countdownHours : state.inchingHours);
final displayMinutes =
isActive && state.countdownRemaining != Duration.zero
? state.countdownRemaining.inMinutes.remainder(60)
final displayMinutes = isActive && state.countdownRemaining != null
? state.countdownRemaining!.inMinutes.remainder(60)
: (isCountDown ? state.countdownMinutes : state.inchingMinutes);
final displaySeconds = isActive && state.countdownRemaining != null
? state.countdownRemaining!.inSeconds.remainder(60)
: (isCountDown ? state.countdownSeconds : state.inchingSeconds);
final displaySeconds =
isActive && state.countdownRemaining != Duration.zero
? state.countdownRemaining.inSeconds.remainder(60)
: (isCountDown ? (state.countdownSeconds ?? 0) : 0);
_updateControllers(displayHours, displayMinutes, displaySeconds!);
_updateControllers(displayHours, displayMinutes, displaySeconds);
if (isActive &&
displayHours == 0 &&
displayMinutes == 0 &&
displaySeconds == 0) {
if (displayHours == 0 && displayMinutes == 0 && displaySeconds == 0) {
context.read<ScheduleBloc>().add(
StopScheduleEvent(
mode: ScheduleModes.countdown,
deviceId: widget.deviceId,
countdownCode: '',
),
);
}

View File

@ -43,9 +43,7 @@ class InchingModeButtons extends StatelessWidget {
onPressed: () {
context.read<ScheduleBloc>().add(
StopScheduleEvent(
deviceId: deviceId,
mode: ScheduleModes.inching,
countdownCode: ''),
deviceId: deviceId, mode: ScheduleModes.inching),
);
},
backgroundColor: Colors.red,

View File

@ -18,15 +18,11 @@ class BuildScheduleView extends StatelessWidget {
super.key,
required this.deviceUuid,
required this.category,
required this.countdownCode,
this.code,
required this.deviceType,
});
final String deviceUuid;
final String category;
final String? code;
final String? countdownCode;
final String deviceType;
@override
Widget build(BuildContext context) {
@ -35,8 +31,7 @@ class BuildScheduleView extends StatelessWidget {
deviceId: deviceUuid,
)
..add(ScheduleGetEvent(category: category))
..add(ScheduleFetchStatusEvent(
deviceId: deviceUuid, countdownCode: countdownCode ?? '')),
..add(ScheduleFetchStatusEvent(deviceUuid)),
child: Dialog(
backgroundColor: Colors.white,
insetPadding: const EdgeInsets.all(20),
@ -57,22 +52,21 @@ class BuildScheduleView extends StatelessWidget {
children: [
const ScheduleHeader(),
const SizedBox(height: 20),
if (deviceType == 'CUR_2')
if (category == 'CUR_2')
const SizedBox()
else
ScheduleModeSelector(
countdownCode: countdownCode ?? '',
currentMode: state.scheduleMode,
),
const SizedBox(height: 20),
if (state.scheduleMode == ScheduleModes.schedule)
ScheduleManagementUI(
deviceType: deviceType,
category: category,
deviceUuid: deviceUuid,
onAddSchedule: () async {
final entry = await ScheduleDialogHelper
.showAddScheduleDialog(context,
.showAddScheduleDialog(
context,
schedule: ScheduleEntry(
category: category,
time: '',
@ -82,7 +76,7 @@ class BuildScheduleView extends StatelessWidget {
),
isEdit: false,
code: code,
deviceType: deviceType);
);
if (entry != null) {
context.read<ScheduleBloc>().add(
ScheduleAddEvent(
@ -96,7 +90,6 @@ class BuildScheduleView extends StatelessWidget {
}
},
),
if (deviceType != 'CUR_2')
if (state.scheduleMode == ScheduleModes.countdown ||
state.scheduleMode == ScheduleModes.inching)
CountdownInchingView(
@ -105,7 +98,6 @@ class BuildScheduleView extends StatelessWidget {
const SizedBox(height: 20),
if (state.scheduleMode == ScheduleModes.countdown)
CountdownModeButtons(
countDownCode: countdownCode ?? '',
isActive: state.isCountdownActive,
deviceId: deviceUuid,
hours: state.countdownHours,

View File

@ -8,13 +8,11 @@ class ScheduleManagementUI extends StatelessWidget {
final String deviceUuid;
final VoidCallback onAddSchedule;
final String category;
final String deviceType;
const ScheduleManagementUI({
super.key,
required this.deviceUuid,
required this.onAddSchedule,
required this.deviceType,
this.category = 'switch_1',
});
@ -46,11 +44,7 @@ class ScheduleManagementUI extends StatelessWidget {
),
),
const SizedBox(height: 20),
ScheduleTableWidget(
deviceUuid: deviceUuid,
category: category,
deviceType: deviceType,
),
ScheduleTableWidget(deviceUuid: deviceUuid, category: category),
],
);
}

View File

@ -7,12 +7,10 @@ import 'package:syncrow_web/utils/extension/build_context_x.dart';
class ScheduleModeSelector extends StatelessWidget {
final ScheduleModes currentMode;
final String countdownCode;
const ScheduleModeSelector({
super.key,
required this.currentMode,
required this.countdownCode,
});
@override
@ -73,8 +71,7 @@ class ScheduleModeSelector extends StatelessWidget {
onChanged: (ScheduleModes? value) {
if (value != null) {
context.read<ScheduleBloc>().add(
UpdateScheduleModeEvent(
scheduleMode: value, countdownCode: countdownCode),
UpdateScheduleModeEvent(scheduleMode: value),
);
if (value == ScheduleModes.schedule) {
context.read<ScheduleBloc>().add(

View File

@ -12,13 +12,11 @@ import 'package:syncrow_web/utils/format_date_time.dart';
class ScheduleTableWidget extends StatelessWidget {
final String deviceUuid;
final String category;
final String deviceType;
const ScheduleTableWidget({
super.key,
required this.deviceUuid,
this.category = 'switch_1',
required this.deviceType,
});
@override
@ -27,14 +25,13 @@ class ScheduleTableWidget extends StatelessWidget {
create: (_) => ScheduleBloc(
deviceId: deviceUuid,
)..add(ScheduleGetEvent(category: category)),
child: _ScheduleTableView(deviceType),
child: _ScheduleTableView(),
);
}
}
class _ScheduleTableView extends StatelessWidget {
final String deviceType;
const _ScheduleTableView(this.deviceType);
const _ScheduleTableView();
@override
Widget build(BuildContext context) {
@ -84,7 +81,7 @@ class _ScheduleTableView extends StatelessWidget {
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20)),
),
child: _buildTableBody(state.schedules, context, deviceType));
child: _buildTableBody(state.schedules, context));
}
if (state is ScheduleError) {
return Center(child: Text(state.error));
@ -126,8 +123,7 @@ class _ScheduleTableView extends StatelessWidget {
);
}
Widget _buildTableBody(
List<ScheduleModel> schedules, BuildContext context, String deviceType) {
Widget _buildTableBody(List<ScheduleModel> schedules, BuildContext context) {
return SizedBox(
height: 200,
child: SingleChildScrollView(
@ -136,8 +132,7 @@ class _ScheduleTableView extends StatelessWidget {
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: [
for (int i = 0; i < schedules.length; i++)
_buildScheduleRow(schedules[i], i, context,
deviceType: deviceType),
_buildScheduleRow(schedules[i], i, context),
],
),
),
@ -160,19 +155,25 @@ class _ScheduleTableView extends StatelessWidget {
}
TableRow _buildScheduleRow(
ScheduleModel schedule, int index, BuildContext context,
{required String deviceType}) {
ScheduleModel schedule, int index, BuildContext context) {
return TableRow(
children: [
Center(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
bool temp;
if (schedule.category == 'CUR_2') {
temp = schedule.function.value == 'open' ? true : false;
} else {
temp = schedule.function.value as bool;
}
context.read<ScheduleBloc>().add(
ScheduleUpdateEntryEvent(
category: schedule.category,
scheduleId: schedule.scheduleId,
functionOn: schedule.function.value,
functionOn: temp,
// schedule.function.value,
enable: !schedule.enable,
),
);
@ -194,9 +195,8 @@ class _ScheduleTableView extends StatelessWidget {
child: Text(_getSelectedDays(
ScheduleModel.parseSelectedDays(schedule.days)))),
Center(child: Text(formatIsoStringToTime(schedule.time, context))),
if (deviceType == 'CUR_2')
Center(
child: Text(schedule.function.value == true ? 'open' : 'close'))
if (schedule.category == 'CUR_2')
Center(child: Text(schedule.function.value))
else
Center(child: Text(schedule.function.value ? 'On' : 'Off')),
Center(
@ -206,14 +206,14 @@ class _ScheduleTableView extends StatelessWidget {
TextButton(
style: TextButton.styleFrom(padding: EdgeInsets.zero),
onPressed: () {
ScheduleDialogHelper.showAddScheduleDialog(context,
ScheduleDialogHelper.showAddScheduleDialog(
context,
schedule: ScheduleEntry.fromScheduleModel(schedule),
isEdit: true,
deviceType: deviceType)
.then((updatedSchedule) {
).then((updatedSchedule) {
if (updatedSchedule != null) {
bool temp;
if (deviceType == 'CUR_2') {
if (schedule.category == 'CUR_2') {
updatedSchedule.function.value == 'open'
? temp = true
: temp = false;
@ -222,7 +222,6 @@ class _ScheduleTableView extends StatelessWidget {
}
context.read<ScheduleBloc>().add(
ScheduleEditEvent(
deviceType: deviceType,
scheduleId: schedule.scheduleId,
category: schedule.category,
time: updatedSchedule.time,

View File

@ -41,7 +41,7 @@ class ThreeGangGlassSwitchBloc
emit(ThreeGangGlassSwitchLoading());
try {
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
_listenToChanges(event.deviceId);
_listenToChanges(event.deviceId, emit);
deviceStatus =
ThreeGangGlassStatusModel.fromJson(event.deviceId, status.status);
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
@ -50,28 +50,42 @@ class ThreeGangGlassSwitchBloc
}
}
StreamSubscription<DatabaseEvent>? _deviceStatusSubscription;
void _listenToChanges(String deviceId) {
void _listenToChanges(
String deviceId,
Emitter<ThreeGangGlassSwitchState> emit,
) {
try {
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
_deviceStatusSubscription = ref.onValue.listen((DatabaseEvent event) async {
if (event.snapshot.value == null) return;
final stream = ref.onValue;
final usersMap = event.snapshot.value! as Map<dynamic, dynamic>;
stream.listen((DatabaseEvent event) {
final data = event.snapshot.value as Map<dynamic, dynamic>?;
if (data == null) return;
final statusList = <Status>[];
usersMap['status'].forEach((element) {
statusList.add(Status(code: element['code'], value: element['value']));
});
deviceStatus =
ThreeGangGlassStatusModel.fromJson(usersMap['productUuid'], statusList);
if (data['status'] != null) {
for (var element in data['status']) {
statusList.add(
Status(
code: element['code'].toString(),
value: element['value'].toString(),
),
);
}
}
if (statusList.isNotEmpty) {
final newStatus = ThreeGangGlassStatusModel.fromJson(deviceId, statusList);
if (newStatus != deviceStatus) {
deviceStatus = newStatus;
if (!isClosed) {
add(StatusUpdated(deviceStatus));
}
}
}
});
} catch (_) {}
} catch (e) {
emit(ThreeGangGlassSwitchError('Failed to listen to changes: $e'));
}
}
void _onStatusUpdated(
@ -170,10 +184,4 @@ class ThreeGangGlassSwitchBloc
break;
}
}
@override
Future<void> close() {
_deviceStatusSubscription?.cancel();
return super.close();
}
}

View File

@ -111,8 +111,6 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget
child: BuildScheduleView(
category: 'switch_1',
deviceUuid: deviceId,
countdownCode: 'countdown_1',
deviceType: '3GT',
),
));
},
@ -129,8 +127,6 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget
child: BuildScheduleView(
category: 'switch_2',
deviceUuid: deviceId,
countdownCode: 'countdown_2',
deviceType: '3GT',
),
));
},
@ -147,8 +143,6 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget
child: BuildScheduleView(
category: 'switch_3',
deviceUuid: deviceId,
countdownCode: 'countdown_3',
deviceType: '3GT',
),
));
},

View File

@ -102,8 +102,6 @@ class LivingRoomDeviceControlsView extends StatelessWidget
child: BuildScheduleView(
deviceUuid: deviceId,
category: 'switch_1',
countdownCode: 'countdown_1',
deviceType: '3G',
),
));
},
@ -120,8 +118,6 @@ class LivingRoomDeviceControlsView extends StatelessWidget
child: BuildScheduleView(
deviceUuid: deviceId,
category: 'switch_2',
countdownCode: 'countdown_2',
deviceType: '3G',
),
));
},
@ -138,8 +134,6 @@ class LivingRoomDeviceControlsView extends StatelessWidget
child: BuildScheduleView(
deviceUuid: deviceId,
category: 'switch_3',
countdownCode: 'countdown_3',
deviceType: '3G',
),
));
},

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:developer';
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
@ -50,28 +51,29 @@
}
}
StreamSubscription<DatabaseEvent>? _deviceStatusSubscription;
void _listenToChanges(String deviceId) {
try {
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
_deviceStatusSubscription = ref.onValue.listen((DatabaseEvent event) async {
if (event.snapshot.value == null) return;
final ref = FirebaseDatabase.instance.ref(
'device-status/$deviceId',
);
final usersMap = event.snapshot.value! as Map<dynamic, dynamic>;
ref.onValue.listen((event) {
final eventsMap = event.snapshot.value as Map<dynamic, dynamic>;
final statusList = <Status>[];
usersMap['status'].forEach((element) {
List<Status> statusList = [];
eventsMap['status'].forEach((element) {
statusList.add(Status(code: element['code'], value: element['value']));
});
deviceStatus =
TwoGangGlassStatusModel.fromJson(usersMap['productUuid'], statusList);
deviceStatus = TwoGangGlassStatusModel.fromJson(deviceId, statusList);
add(StatusUpdated(deviceStatus));
});
} catch (_) {}
} catch (_) {
log(
'Error listening to changes',
name: 'TwoGangGlassSwitchBloc._listenToChanges',
);
}
}
Future<void> _onControl(
@ -168,10 +170,4 @@
break;
}
}
@override
Future<void> close() {
_deviceStatusSubscription?.cancel();
return super.close();
}
}

View File

@ -102,8 +102,6 @@ class TwoGangGlassSwitchControlView extends StatelessWidget
builder: (ctx) => BlocProvider.value(
value: BlocProvider.of<TwoGangGlassSwitchBloc>(context),
child: BuildScheduleView(
deviceType: '2GT',
countdownCode: 'countdown_1',
deviceUuid: deviceId,
category: 'switch_1',
),
@ -120,8 +118,6 @@ class TwoGangGlassSwitchControlView extends StatelessWidget
builder: (ctx) => BlocProvider.value(
value: BlocProvider.of<TwoGangGlassSwitchBloc>(context),
child: BuildScheduleView(
deviceType: '2GT',
countdownCode: 'countdown_2',
deviceUuid: deviceId,
category: 'switch_2',
),

View File

@ -97,8 +97,6 @@ class TwoGangBatchControlView extends StatelessWidget
child: BuildScheduleView(
category: 'switch_1',
deviceUuid: deviceIds.first,
countdownCode: 'countdown_1',
deviceType: '2G',
),
));
},
@ -116,8 +114,6 @@ class TwoGangBatchControlView extends StatelessWidget
child: BuildScheduleView(
category: 'switch_2',
deviceUuid: deviceIds.first,
countdownCode: 'countdown_2',
deviceType: '2G',
),
));
},
@ -125,7 +121,10 @@ class TwoGangBatchControlView extends StatelessWidget
subtitle: 'Scheduling',
iconPath: Assets.scheduling,
),
// FirmwareUpdateWidget(
// deviceId: deviceIds.first,
// version: 12,
// ),
FactoryResetWidget(callFactoryReset: () {
context.read<TwoGangSwitchBloc>().add(
TwoGangFactoryReset(

View File

@ -103,8 +103,6 @@ class TwoGangDeviceControlView extends StatelessWidget
child: BuildScheduleView(
deviceUuid: deviceId,
category: 'switch_1',
countdownCode: 'countdown_1',
deviceType: '2G',
),
));
},
@ -127,8 +125,6 @@ class TwoGangDeviceControlView extends StatelessWidget
child: BuildScheduleView(
deviceUuid: deviceId,
category: 'switch_2',
countdownCode: 'countdown_2',
deviceType: '2G',
),
));
},

View File

@ -18,10 +18,9 @@ class ScheduleDialogHelper {
ScheduleEntry? schedule,
bool isEdit = false,
String? code,
required String deviceType,
}) {
bool temp;
if (deviceType == 'CUR_2') {
if (schedule?.category == 'CUR_2') {
temp = schedule!.function.value == 'open' ? true : false;
} else {
temp = schedule!.function.value;
@ -104,7 +103,8 @@ class ScheduleDialogHelper {
setState(() => selectedDays[i] = v);
}),
const SizedBox(height: 16),
_buildFunctionSwitch(deviceType, ctx, functionOn!, (v) {
_buildFunctionSwitch(schedule!.category, ctx, functionOn!,
(v) {
setState(() => functionOn = v);
}),
],
@ -124,25 +124,28 @@ class ScheduleDialogHelper {
child: ElevatedButton(
onPressed: () {
dynamic temp;
if (deviceType == 'CUR_2') {
if (schedule?.category == 'CUR_2') {
temp = functionOn! ? 'open' : 'close';
} else {
temp = functionOn;
}
print(temp);
final entry = ScheduleEntry(
category: schedule?.category ?? 'switch_1',
time: _formatTimeOfDayToISO(selectedTime),
function: Status(
code: code ?? 'switch_1',
value: temp,
// functionOn,
),
days: _convertSelectedDaysToStrings(selectedDays),
scheduleId: schedule.scheduleId,
scheduleId: schedule?.scheduleId,
);
Navigator.pop(ctx, entry);
},
child: const Text('Save'),
)),
),
),
],
);
},

View File

@ -84,8 +84,6 @@ class WaterHeaterDeviceControlView extends StatelessWidget
child: BuildScheduleView(
deviceUuid: device.uuid ?? '',
category: 'switch_1',
countdownCode: 'countdown_1',
deviceType: 'WH',
),
));
},

View File

@ -14,8 +14,7 @@ class Assets {
static const String rightLine = 'assets/images/right_line.png';
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 invisiblePassword = 'assets/images/Password_invisible.svg';
static const String visiblePassword = 'assets/images/password_visible.svg';
static const String accessIcon = 'assets/images/access_icon.svg';
static const String spaseManagementIcon =
@ -34,8 +33,7 @@ class Assets {
static const String emptyTable = 'assets/images/empty_table.svg';
// General assets
static const String motionlessDetection =
'assets/icons/motionless_detection.svg';
static const String motionlessDetection = 'assets/icons/motionless_detection.svg';
static const String acHeating = 'assets/icons/ac_heating.svg';
static const String acPowerOff = 'assets/icons/ac_power_off.svg';
static const String acFanMiddle = 'assets/icons/ac_fan_middle.svg';
@ -72,22 +70,19 @@ class Assets {
'assets/icons/automation_functions/temp_password_unlock.svg';
static const String doorlockNormalOpen =
'assets/icons/automation_functions/doorlock_normal_open.svg';
static const String doorbell =
'assets/icons/automation_functions/doorbell.svg';
static const String doorbell = 'assets/icons/automation_functions/doorbell.svg';
static const String remoteUnlockViaApp =
'assets/icons/automation_functions/remote_unlock_via_app.svg';
static const String doubleLock =
'assets/icons/automation_functions/double_lock.svg';
static const String selfTestResult =
'assets/icons/automation_functions/self_test_result.svg';
static const String lockAlarm =
'assets/icons/automation_functions/lock_alarm.svg';
static const String lockAlarm = 'assets/icons/automation_functions/lock_alarm.svg';
static const String presenceState =
'assets/icons/automation_functions/presence_state.svg';
static const String currentTemp =
'assets/icons/automation_functions/current_temp.svg';
static const String presence =
'assets/icons/automation_functions/presence.svg';
static const String presence = 'assets/icons/automation_functions/presence.svg';
static const String residualElectricity =
'assets/icons/automation_functions/residual_electricity.svg';
static const String hijackAlarm =
@ -104,15 +99,12 @@ class Assets {
// Presence Sensor Assets
static const String sensorMotionIcon = 'assets/icons/sensor_motion_ic.svg';
static const String sensorPresenceIcon =
'assets/icons/sensor_presence_ic.svg';
static const String sensorPresenceIcon = 'assets/icons/sensor_presence_ic.svg';
static const String sensorVacantIcon = 'assets/icons/sensor_vacant_ic.svg';
static const String illuminanceRecordIcon =
'assets/icons/illuminance_record_ic.svg';
static const String presenceRecordIcon =
'assets/icons/presence_record_ic.svg';
static const String helpDescriptionIcon =
'assets/icons/help_description_ic.svg';
static const String presenceRecordIcon = 'assets/icons/presence_record_ic.svg';
static const String helpDescriptionIcon = 'assets/icons/help_description_ic.svg';
static const String lightPulp = 'assets/icons/light_pulb.svg';
static const String acDevice = 'assets/icons/ac_device.svg';
@ -166,12 +158,10 @@ class Assets {
static const String unit = 'assets/icons/unit_icon.svg';
static const String villa = 'assets/icons/villa_icon.svg';
static const String iconEdit = 'assets/icons/icon_edit_icon.svg';
static const String textFieldSearch =
'assets/icons/textfield_search_icon.svg';
static const String textFieldSearch = 'assets/icons/textfield_search_icon.svg';
static const String roundedAddIcon = 'assets/icons/rounded_add_icon.svg';
static const String addIcon = 'assets/icons/add_icon.svg';
static const String smartThermostatIcon =
'assets/icons/smart_thermostat_icon.svg';
static const String smartThermostatIcon = 'assets/icons/smart_thermostat_icon.svg';
static const String smartLightIcon = 'assets/icons/smart_light_icon.svg';
static const String presenceSensor = 'assets/icons/presence_sensor.svg';
static const String Gang3SwitchIcon = 'assets/icons/3_Gang_switch_icon.svg';
@ -219,8 +209,7 @@ class Assets {
//assets/icons/water_leak_normal.svg
static const String waterLeakNormal = 'assets/icons/water_leak_normal.svg';
//assets/icons/water_leak_detected.svg
static const String waterLeakDetected =
'assets/icons/water_leak_detected.svg';
static const String waterLeakDetected = 'assets/icons/water_leak_detected.svg';
//assets/icons/automation_records.svg
static const String automationRecords = 'assets/icons/automation_records.svg';
@ -291,16 +280,13 @@ class Assets {
'assets/icons/functions_icons/sensitivity.svg';
static const String assetsSensitivityOperationIcon =
'assets/icons/functions_icons/sesitivity_operation_icon.svg';
static const String assetsAcPower =
'assets/icons/functions_icons/ac_power.svg';
static const String assetsAcPower = 'assets/icons/functions_icons/ac_power.svg';
static const String assetsAcPowerOFF =
'assets/icons/functions_icons/ac_power_off.svg';
static const String assetsChildLock =
'assets/icons/functions_icons/child_lock.svg';
static const String assetsFreezing =
'assets/icons/functions_icons/freezing.svg';
static const String assetsFanSpeed =
'assets/icons/functions_icons/fan_speed.svg';
static const String assetsFreezing = 'assets/icons/functions_icons/freezing.svg';
static const String assetsFanSpeed = 'assets/icons/functions_icons/fan_speed.svg';
static const String assetsAcCooling =
'assets/icons/functions_icons/ac_cooling.svg';
static const String assetsAcHeating =
@ -309,8 +295,7 @@ class Assets {
'assets/icons/functions_icons/celsius_degrees.svg';
static const String assetsTempreture =
'assets/icons/functions_icons/tempreture.svg';
static const String assetsAcFanLow =
'assets/icons/functions_icons/ac_fan_low.svg';
static const String assetsAcFanLow = 'assets/icons/functions_icons/ac_fan_low.svg';
static const String assetsAcFanMiddle =
'assets/icons/functions_icons/ac_fan_middle.svg';
static const String assetsAcFanHigh =
@ -329,8 +314,7 @@ class Assets {
'assets/icons/functions_icons/far_detection.svg';
static const String assetsFarDetectionFunction =
'assets/icons/functions_icons/far_detection_function.svg';
static const String assetsIndicator =
'assets/icons/functions_icons/indicator.svg';
static const String assetsIndicator = 'assets/icons/functions_icons/indicator.svg';
static const String assetsMotionDetection =
'assets/icons/functions_icons/motion_detection.svg';
static const String assetsMotionlessDetection =
@ -343,8 +327,7 @@ class Assets {
'assets/icons/functions_icons/master_state.svg';
static const String assetsSwitchAlarmSound =
'assets/icons/functions_icons/switch_alarm_sound.svg';
static const String assetsResetOff =
'assets/icons/functions_icons/reset_off.svg';
static const String assetsResetOff = 'assets/icons/functions_icons/reset_off.svg';
// Assets for automation_functions
static const String assetsCardUnlock =
@ -388,15 +371,13 @@ class Assets {
static const String activeUser = 'assets/icons/active_user.svg';
static const String deActiveUser = 'assets/icons/deactive_user.svg';
static const String invitedIcon = 'assets/icons/invited_icon.svg';
static const String rectangleCheckBox =
'assets/icons/rectangle_check_box.png';
static const String rectangleCheckBox = 'assets/icons/rectangle_check_box.png';
static const String CheckBoxChecked = 'assets/icons/box_checked.png';
static const String emptyBox = 'assets/icons/empty_box.png';
static const String completeProcessIcon =
'assets/icons/compleate_process_icon.svg';
static const String completedDoneIcon = 'assets/images/completed_done.svg';
static const String currentProcessIcon =
'assets/icons/current_process_icon.svg';
static const String currentProcessIcon = 'assets/icons/current_process_icon.svg';
static const String uncomplete_ProcessIcon =
'assets/icons/uncompleate_process_icon.svg';
static const String wrongProcessIcon = 'assets/icons/wrong_process_icon.svg';
@ -417,11 +398,9 @@ class Assets {
static const String successIcon = 'assets/icons/success_icon.svg';
static const String spaceLocationIcon = 'assets/icons/spaseLocationIcon.svg';
static const String scenesPlayIcon = 'assets/icons/scenesPlayIcon.png';
static const String scenesPlayIconCheck =
'assets/icons/scenesPlayIconCheck.png';
static const String scenesPlayIconCheck = 'assets/icons/scenesPlayIconCheck.png';
static const String presenceStateIcon = 'assets/icons/presence_state.svg';
static const String currentDistanceIcon =
'assets/icons/current_distance_icon.svg';
static const String currentDistanceIcon = 'assets/icons/current_distance_icon.svg';
static const String farDetectionIcon = 'assets/icons/far_detection_icon.svg';
static const String motionDetectionSensitivityIcon =
@ -444,44 +423,29 @@ class Assets {
static const String cpsMode4 = 'assets/icons/cps_mode4.svg';
static const String closeToMotion = 'assets/icons/close_to_motion.svg';
static const String farAwayMotion = 'assets/icons/far_away_motion.svg';
static const String communicationFault =
'assets/icons/communication_fault.svg';
static const String communicationFault = 'assets/icons/communication_fault.svg';
static const String radarFault = 'assets/icons/radar_fault.svg';
static const String selfTestingSuccess =
'assets/icons/self_testing_success.svg';
static const String selfTestingFailure =
'assets/icons/self_testing_failure.svg';
static const String selfTestingTimeout =
'assets/icons/self_testing_timeout.svg';
static const String selfTestingSuccess = 'assets/icons/self_testing_success.svg';
static const String selfTestingFailure = 'assets/icons/self_testing_failure.svg';
static const String selfTestingTimeout = 'assets/icons/self_testing_timeout.svg';
static const String movingSpeed = 'assets/icons/moving_speed.svg';
static const String boundary = 'assets/icons/boundary.svg';
static const String motionMeter = 'assets/icons/motion_meter.svg';
static const String spatialStaticValue =
'assets/icons/spatial_static_value.svg';
static const String spatialMotionValue =
'assets/icons/spatial_motion_value.svg';
static const String spatialStaticValue = 'assets/icons/spatial_static_value.svg';
static const String spatialMotionValue = 'assets/icons/spatial_motion_value.svg';
static const String presenceJudgementThrshold =
'assets/icons/presence_judgement_threshold.svg';
static const String spaceType = 'assets/icons/space_type.svg';
static const String sportsPara = 'assets/icons/sports_para.svg';
static const String sensitivityFeature1 =
'assets/icons/sensitivity_feature_1.svg';
static const String sensitivityFeature2 =
'assets/icons/sensitivity_feature_2.svg';
static const String sensitivityFeature3 =
'assets/icons/sensitivity_feature_3.svg';
static const String sensitivityFeature4 =
'assets/icons/sensitivity_feature_4.svg';
static const String sensitivityFeature5 =
'assets/icons/sensitivity_feature_5.svg';
static const String sensitivityFeature6 =
'assets/icons/sensitivity_feature_6.svg';
static const String sensitivityFeature7 =
'assets/icons/sensitivity_feature_7.svg';
static const String sensitivityFeature8 =
'assets/icons/sensitivity_feature_8.svg';
static const String sensitivityFeature9 =
'assets/icons/sensitivity_feature_9.svg';
static const String sensitivityFeature1 = 'assets/icons/sensitivity_feature_1.svg';
static const String sensitivityFeature2 = 'assets/icons/sensitivity_feature_2.svg';
static const String sensitivityFeature3 = 'assets/icons/sensitivity_feature_3.svg';
static const String sensitivityFeature4 = 'assets/icons/sensitivity_feature_4.svg';
static const String sensitivityFeature5 = 'assets/icons/sensitivity_feature_5.svg';
static const String sensitivityFeature6 = 'assets/icons/sensitivity_feature_6.svg';
static const String sensitivityFeature7 = 'assets/icons/sensitivity_feature_7.svg';
static const String sensitivityFeature8 = 'assets/icons/sensitivity_feature_8.svg';
static const String sensitivityFeature9 = 'assets/icons/sensitivity_feature_9.svg';
static const String deviceTagIcon = 'assets/icons/device_tag_ic.svg';
static const String targetConfirmTimeIcon =
'assets/icons/target_confirm_time_icon.svg';
@ -489,13 +453,10 @@ class Assets {
static const String indentLevelIcon = 'assets/icons/indent_level_icon.svg';
static const String triggerLevelIcon = 'assets/icons/trigger_level_icon.svg';
static const String blankCalendar = 'assets/icons/blank_calendar.svg';
static const String refreshStatusIcon =
'assets/icons/refresh_status_icon.svg';
static const String energyConsumedIcon =
'assets/icons/energy_consumed_icon.svg';
static const String refreshStatusIcon = 'assets/icons/refresh_status_icon.svg';
static const String energyConsumedIcon = 'assets/icons/energy_consumed_icon.svg';
static const String closeSettingsIcon =
'assets/icons/close_settings_icon.svg';
static const String closeSettingsIcon = 'assets/icons/close_settings_icon.svg';
static const String editNameIconSettings =
'assets/icons/edit_name_icon_settings.svg';
@ -508,4 +469,11 @@ class Assets {
static const String humidityAqiSidebar = 'assets/icons/humidity.svg';
static const String autocadOccupancyImage =
'assets/images/autocad_occupancy_image.png';
static const String emptyBarredChart = 'assets/icons/empty_barred_chart.svg';
static const String emptyEnergyManagementChart =
'assets/icons/empty_energy_management_chart.svg';
static const String emptyEnergyManagementPerDevice =
'assets/icons/empty_energy_management_per_device.svg';
static const String emptyHeatmap = 'assets/icons/empty_heatmap.svg';
static const String emptyRangeOfAqi = 'assets/icons/empty_range_of_aqi.svg';
}