Extracted big widgets into smaller ones, and integrated aqi device info with RealtimeChangesBloc.

This commit is contained in:
Faris Armoush
2025-05-29 11:25:27 +03:00
parent 3d133581ff
commit 94b4aa7c46
6 changed files with 200 additions and 112 deletions

View File

@ -5,7 +5,14 @@ import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
class AirQualityEndSideGaugeAndInfo extends StatelessWidget {
const AirQualityEndSideGaugeAndInfo({super.key});
const AirQualityEndSideGaugeAndInfo({
super.key,
required this.temperature,
required this.humidity,
});
final int temperature;
final int humidity;
@override
Widget build(BuildContext context) {
@ -54,7 +61,10 @@ class AirQualityEndSideGaugeAndInfo extends StatelessWidget {
),
),
const Spacer(),
const AqiHumidityAndTemperature(),
AqiHumidityAndTemperature(
temperature: temperature,
humidity: humidity,
),
],
),
),

View File

@ -1,12 +1,7 @@
import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/air_quality_end_side_gauge_and_info.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/air_quality_end_side_live_indicator.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_location.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_location_info_cell.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_sub_value_widget.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_type_dropdown.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_device_info.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_location_info.dart';
import 'package:syncrow_web/pages/analytics/widgets/analytics_sidebar_header.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/style.dart';
class AirQualityEndSideWidget extends StatelessWidget {
@ -19,98 +14,13 @@ class AirQualityEndSideWidget extends StatelessWidget {
borderRadius: BorderRadius.circular(30),
),
padding: const EdgeInsetsDirectional.all(32),
child: Column(
child: const Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const AnalyticsSidebarHeader(title: 'AQI Sensor'),
Expanded(
flex: 15,
child: Container(
decoration: secondarySection.copyWith(boxShadow: const []),
padding: const EdgeInsetsDirectional.all(20),
child: Expanded(
child: Column(
spacing: 6,
children: [
const AirQualityEndSideLiveIndicator(),
const AirQualityEndSideGaugeAndInfo(),
const SizedBox(height: 20),
AqiSubValueWidget(
label: AqiType.pm25.value,
value: 19,
unit: AqiType.pm25.unit,
),
AqiSubValueWidget(
label: AqiType.pm10.value,
value: 42,
unit: AqiType.pm10.unit,
),
AqiSubValueWidget(
label: AqiType.co2.value,
value: 610,
unit: AqiType.co2.unit,
),
AqiSubValueWidget(
label: AqiType.hcho.value,
value: 1,
unit: AqiType.hcho.unit,
),
AqiSubValueWidget(
label: AqiType.tvoc.value,
value: 55,
unit: AqiType.tvoc.unit,
),
AqiSubValueWidget(
label: AqiType.co2.value,
value: 18,
unit: AqiType.co2.unit,
),
AqiSubValueWidget(
label: AqiType.c6h6.value,
value: 18,
unit: AqiType.c6h6.unit,
),
],
),
),
),
),
const SizedBox(height: 20),
Expanded(
flex: 6,
child: Container(
decoration: secondarySection.copyWith(boxShadow: const []),
padding: const EdgeInsetsDirectional.all(20),
child: const Column(
spacing: 8,
children: [
AqiLocation(),
Expanded(
child: Row(
spacing: 8,
children: [
AqiLocationInfoCell(
label: 'Temperature',
value: ' 25°',
svgPath: Assets.aqiTemperature,
),
AqiLocationInfoCell(
label: 'Humidity',
value: '25%',
svgPath: Assets.aqiHumidity,
),
AqiLocationInfoCell(
label: 'Air Quality',
value: ' 120',
svgPath: Assets.aqiAirQuality,
),
],
),
),
],
),
),
),
AnalyticsSidebarHeader(title: 'AQI Sensor'),
Expanded(flex: 15, child: AqiDeviceInfo()),
SizedBox(height: 20),
Expanded(flex: 6, child: AqiLocationInfo()),
],
),
);

View File

@ -0,0 +1,100 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/air_quality_end_side_gauge_and_info.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/air_quality_end_side_live_indicator.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_sub_value_widget.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_type_dropdown.dart';
import 'package:syncrow_web/pages/analytics/modules/energy_management/blocs/realtime_device_changes/realtime_device_changes_bloc.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
import 'package:syncrow_web/utils/style.dart';
class AqiDeviceInfo extends StatelessWidget {
const AqiDeviceInfo({super.key});
double _getValueForStatus(
List<Status> deviceStatusList,
String code, {
double defaultValue = 0,
}) {
try {
final foundStatus = deviceStatusList.firstWhere((e) => e.code == code);
return double.parse(foundStatus.value.toString());
} catch (_) {
return defaultValue;
}
}
@override
Widget build(BuildContext context) {
return BlocBuilder<RealtimeDeviceChangesBloc, RealtimeDeviceChangesState>(
builder: (context, state) {
final status = state.deviceStatusList;
final humidityValue = _getValueForStatus(status, 'humidity_value');
final tempValue = _getValueForStatus(status, 'temp_current');
final pm25Value = _getValueForStatus(status, 'pm25_value');
final pm10Value = _getValueForStatus(status, 'pm10');
final co2Value = _getValueForStatus(status, 'co2_value');
final ch2oValue = _getValueForStatus(status, 'ch2o_value');
final tvocValue = _getValueForStatus(status, 'tvoc_value');
return Container(
decoration: secondarySection.copyWith(boxShadow: const []),
padding: const EdgeInsetsDirectional.all(20),
child: Expanded(
child: Column(
spacing: 6,
children: [
const AirQualityEndSideLiveIndicator(),
AirQualityEndSideGaugeAndInfo(
temperature: humidityValue.toInt(),
humidity: tempValue.toInt(),
),
const SizedBox(height: 20),
AqiSubValueWidget(
range: (0, 999),
label: AqiType.pm25.value,
value: pm25Value < 100
? double.parse(pm25Value.toStringAsFixed(1).padLeft(4, '0'))
: pm25Value,
unit: AqiType.pm25.unit,
),
AqiSubValueWidget(
range: (0, 999),
label: AqiType.pm10.value,
value: pm10Value < 100
? double.parse(pm10Value.toStringAsFixed(1).padLeft(4, '0'))
: pm10Value,
unit: AqiType.pm10.unit,
),
AqiSubValueWidget(
range: (0, 5),
label: AqiType.hcho.value,
value: double.parse(ch2oValue.toStringAsFixed(2)),
unit: AqiType.hcho.unit,
),
AqiSubValueWidget(
range: (0, 9.99),
label: AqiType.tvoc.value,
value: tvocValue,
unit: AqiType.tvoc.unit,
),
AqiSubValueWidget(
range: (0, 5000),
label: AqiType.co2.value,
value: co2Value,
unit: AqiType.co2.unit,
),
AqiSubValueWidget(
range: (0, 100),
label: AqiType.c6h6.value,
value: 18,
unit: AqiType.c6h6.unit,
),
],
),
),
);
},
);
}
}

View File

@ -5,7 +5,13 @@ import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/extension/build_context_x.dart';
class AqiHumidityAndTemperature extends StatelessWidget {
const AqiHumidityAndTemperature({super.key});
const AqiHumidityAndTemperature({
super.key,
required this.temperature,
required this.humidity,
});
final int temperature;
final int humidity;
static const iconSize = 12.0;
static const colorFilter = ColorFilter.mode(
@ -13,6 +19,7 @@ class AqiHumidityAndTemperature extends StatelessWidget {
BlendMode.srcIn,
);
@override
Widget build(BuildContext context) {
return FittedBox(
@ -33,7 +40,7 @@ class AqiHumidityAndTemperature extends StatelessWidget {
colorFilter: colorFilter,
),
const SizedBox(width: 4),
const Text('30°C'),
Text('$temperature°C'),
const SizedBox(width: 10),
SvgPicture.asset(
Assets.humidityAqiSidebar,
@ -42,7 +49,7 @@ class AqiHumidityAndTemperature extends StatelessWidget {
colorFilter: colorFilter,
),
const SizedBox(width: 4),
const Text('30°C'),
Text('$humidity%'),
],
),
),

View File

@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_location.dart';
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_location_info_cell.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/style.dart';
class AqiLocationInfo extends StatelessWidget {
const AqiLocationInfo({super.key});
@override
Widget build(BuildContext context) {
return Container(
decoration: secondarySection.copyWith(boxShadow: const []),
padding: const EdgeInsetsDirectional.all(20),
child: const Column(
spacing: 8,
children: [
AqiLocation(),
Expanded(
child: Row(
spacing: 8,
children: [
AqiLocationInfoCell(
label: 'Temperature',
value: ' 25°',
svgPath: Assets.aqiTemperature,
),
AqiLocationInfoCell(
label: 'Humidity',
value: '25%',
svgPath: Assets.aqiHumidity,
),
AqiLocationInfoCell(
label: 'Air Quality',
value: ' 120',
svgPath: Assets.aqiAirQuality,
),
],
),
),
],
),
);
}
}

View File

@ -5,7 +5,7 @@ import 'package:syncrow_web/utils/extension/build_context_x.dart';
final class _AqiRange {
const _AqiRange({required this.max, required this.color});
final int max;
final double max;
final Color color;
}
@ -14,12 +14,35 @@ class AqiSubValueWidget extends StatelessWidget {
required this.label,
required this.value,
required this.unit,
required this.range,
super.key,
});
static List<_AqiRange> _getRangesForValue((double min, double max) range) {
final (double min, double max) = range;
final rangeSize = (max - min) / 6;
return [
_AqiRange(max: range.$1 + rangeSize, color: ColorsManager.goodGreen),
_AqiRange(max: range.$1 + (rangeSize * 2), color: ColorsManager.poorOrange),
_AqiRange(max: range.$1 + (rangeSize * 3), color: ColorsManager.poorOrange),
_AqiRange(max: range.$1 + (rangeSize * 4), color: ColorsManager.unhealthyRed),
_AqiRange(max: range.$1 + (rangeSize * 5), color: ColorsManager.severePink),
_AqiRange(max: range.$2, color: ColorsManager.hazardousPurple),
];
}
int _getActiveSegmentByRange(double value, (double min, double max) range) {
final ranges = _getRangesForValue(range);
for (int i = 0; i < ranges.length; i++) {
if (value <= ranges[i].max) return i;
}
return ranges.length - 1;
}
final String label;
final int value;
final double value;
final String unit;
final (double min, double max) range;
static const List<_AqiRange> _ranges = [
_AqiRange(max: 12, color: ColorsManager.goodGreen),
@ -30,16 +53,9 @@ class AqiSubValueWidget extends StatelessWidget {
_AqiRange(max: 500, color: ColorsManager.hazardousPurple),
];
int _getActiveSegment(int value) {
for (int i = 0; i < _ranges.length; i++) {
if (value <= _ranges[i].max) return i;
}
return _ranges.length - 1;
}
@override
Widget build(BuildContext context) {
final activeSegment = _getActiveSegment(value);
final activeSegment = _getActiveSegmentByRange(value, range);
return Expanded(
child: Container(
padding: const EdgeInsetsDirectional.all(10),