mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-15 01:35:25 +00:00
Compare commits
59 Commits
SP-1707-fe
...
hot-fix-th
Author | SHA1 | Date | |
---|---|---|---|
b06e4bd2ba | |||
0a022d8a8d | |||
8f0eb88567 | |||
19739c6e4d | |||
9f86b8d638 | |||
95907661d2 | |||
9c9b7d99dc | |||
037895844a | |||
c07bae5cbc | |||
e6fe9f35b0 | |||
8cb6c13cd5 | |||
949c27938a | |||
4c582b865d | |||
d7467adeda | |||
5486f0832d | |||
fd239a3907 | |||
e2d6f5eea8 | |||
289922071a | |||
8594168548 | |||
bd9a74b380 | |||
15ee79688d | |||
e5e88385e9 | |||
62d5bbce7e | |||
05d784ec11 | |||
9ebf474a60 | |||
af48bbead5 | |||
3c80724c1e | |||
db05331e9a | |||
cdc76c2c8e | |||
44c88fb1c4 | |||
dfb120e7cf | |||
4d51321675 | |||
b5e7776ccb | |||
32938404dd | |||
0cfd58d820 | |||
d4625a8f04 | |||
9f24606613 | |||
e87dffd76b | |||
0c220a1f34 | |||
a526fcbeee | |||
172e1d208a | |||
2c254c1a91 | |||
480e183b91 | |||
d8bb234537 | |||
8916efcebb | |||
175d1e662b | |||
57bd4b8527 | |||
df308fd12a | |||
e0cfe541dd | |||
814cbf787f | |||
df8eff895e | |||
9514200892 | |||
cf4bfc41f6 | |||
01f55c14de | |||
19cdd371f8 | |||
388391eec4 | |||
23cfee1490 | |||
2f5ad03431 | |||
df34ded153 |
8
assets/icons/empty_barred_chart.svg
Normal file
8
assets/icons/empty_barred_chart.svg
Normal 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 |
5
assets/icons/empty_energy_management_chart.svg
Normal file
5
assets/icons/empty_energy_management_chart.svg
Normal 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 |
7
assets/icons/empty_energy_management_per_device.svg
Normal file
7
assets/icons/empty_energy_management_per_device.svg
Normal 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 |
99
assets/icons/empty_heatmap.svg
Normal file
99
assets/icons/empty_heatmap.svg
Normal 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 |
7
assets/icons/empty_range_of_aqi.svg
Normal file
7
assets/icons/empty_range_of_aqi.svg
Normal 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 |
@ -39,8 +39,12 @@ class AnalyticsDevice {
|
|||||||
? ProductDevice.fromJson(json['productDevice'] as Map<String, dynamic>)
|
? ProductDevice.fromJson(json['productDevice'] as Map<String, dynamic>)
|
||||||
: null,
|
: null,
|
||||||
spaceUuid: json['spaceUuid'] as String?,
|
spaceUuid: json['spaceUuid'] as String?,
|
||||||
latitude: json['lat'] != null ? double.parse(json['lat'] as String? ?? '0.0') : null,
|
latitude: json['lat'] != null && json['lat'] != ''
|
||||||
longitude: json['lon'] != null ? double.parse(json['lon'] as String? ?? '0.0') : null,
|
? double.tryParse(json['lat']?.toString() ?? '0.0')
|
||||||
|
: null,
|
||||||
|
longitude: json['lon'] != null && json['lon'] != ''
|
||||||
|
? double.tryParse(json['lon']?.toString() ?? '0.0')
|
||||||
|
: null,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,11 +46,11 @@ class AirQualityDistributionBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onClearAirQualityDistribution(
|
void _onClearAirQualityDistribution(
|
||||||
ClearAirQualityDistribution event,
|
ClearAirQualityDistribution event,
|
||||||
Emitter<AirQualityDistributionState> emit,
|
Emitter<AirQualityDistributionState> emit,
|
||||||
) async {
|
) {
|
||||||
emit(const AirQualityDistributionState());
|
emit(AirQualityDistributionState(selectedAqiType: state.selectedAqiType));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onUpdateAqiTypeEvent(
|
void _onUpdateAqiTypeEvent(
|
||||||
|
@ -75,6 +75,6 @@ class RangeOfAqiBloc extends Bloc<RangeOfAqiEvent, RangeOfAqiState> {
|
|||||||
ClearRangeOfAqiEvent event,
|
ClearRangeOfAqiEvent event,
|
||||||
Emitter<RangeOfAqiState> emit,
|
Emitter<RangeOfAqiState> emit,
|
||||||
) {
|
) {
|
||||||
emit(const RangeOfAqiState());
|
emit(RangeOfAqiState(selectedAqiType: state.selectedAqiType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ class AqiDistributionChart extends StatelessWidget {
|
|||||||
return BarChart(
|
return BarChart(
|
||||||
BarChartData(
|
BarChartData(
|
||||||
maxY: 100.1,
|
maxY: 100.1,
|
||||||
|
alignment: BarChartAlignment.start,
|
||||||
gridData: EnergyManagementChartsHelper.gridData(
|
gridData: EnergyManagementChartsHelper.gridData(
|
||||||
horizontalInterval: 20,
|
horizontalInterval: 20,
|
||||||
),
|
),
|
||||||
|
@ -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/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.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/aqi_distribution_chart_title.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/pages/analytics/widgets/analytics_error_widget.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class AqiDistributionChartBox extends StatelessWidget {
|
class AqiDistributionChartBox extends StatelessWidget {
|
||||||
@ -32,8 +34,20 @@ class AqiDistributionChartBox extends StatelessWidget {
|
|||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Expanded(
|
Visibility(
|
||||||
child: AqiDistributionChart(chartData: state.chartData),
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -34,6 +34,7 @@ class AqiDistributionChartTitle extends StatelessWidget {
|
|||||||
alignment: AlignmentDirectional.centerEnd,
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
fit: BoxFit.scaleDown,
|
fit: BoxFit.scaleDown,
|
||||||
child: AqiTypeDropdown(
|
child: AqiTypeDropdown(
|
||||||
|
selectedAqiType: context.watch<AirQualityDistributionBloc>().state.selectedAqiType,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
final bloc = context.read<AirQualityDistributionBloc>();
|
final bloc = context.read<AirQualityDistributionBloc>();
|
||||||
|
@ -18,19 +18,20 @@ enum AqiType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class AqiTypeDropdown extends StatefulWidget {
|
class AqiTypeDropdown extends StatefulWidget {
|
||||||
const AqiTypeDropdown({super.key, required this.onChanged});
|
const AqiTypeDropdown({
|
||||||
|
required this.onChanged,
|
||||||
|
this.selectedAqiType,
|
||||||
|
super.key,
|
||||||
|
});
|
||||||
|
|
||||||
final ValueChanged<AqiType?> onChanged;
|
final ValueChanged<AqiType?> onChanged;
|
||||||
|
final AqiType? selectedAqiType;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AqiTypeDropdown> createState() => _AqiTypeDropdownState();
|
State<AqiTypeDropdown> createState() => _AqiTypeDropdownState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AqiTypeDropdownState extends State<AqiTypeDropdown> {
|
class _AqiTypeDropdownState extends State<AqiTypeDropdown> {
|
||||||
AqiType? _selectedItem = AqiType.aqi;
|
|
||||||
|
|
||||||
void _updateSelectedItem(AqiType? item) => setState(() => _selectedItem = item);
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
@ -41,8 +42,8 @@ class _AqiTypeDropdownState extends State<AqiTypeDropdown> {
|
|||||||
width: 1,
|
width: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: DropdownButton<AqiType?>(
|
child: DropdownButton<AqiType>(
|
||||||
value: _selectedItem,
|
value: widget.selectedAqiType,
|
||||||
isDense: true,
|
isDense: true,
|
||||||
borderRadius: BorderRadius.circular(16),
|
borderRadius: BorderRadius.circular(16),
|
||||||
dropdownColor: ColorsManager.whiteColors,
|
dropdownColor: ColorsManager.whiteColors,
|
||||||
@ -59,10 +60,7 @@ class _AqiTypeDropdownState extends State<AqiTypeDropdown> {
|
|||||||
items: AqiType.values
|
items: AqiType.values
|
||||||
.map((e) => DropdownMenuItem(value: e, child: Text(e.value)))
|
.map((e) => DropdownMenuItem(value: e, child: Text(e.value)))
|
||||||
.toList(),
|
.toList(),
|
||||||
onChanged: (value) {
|
onChanged: widget.onChanged,
|
||||||
_updateSelectedItem(value);
|
|
||||||
widget.onChanged(value);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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/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.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/air_quality/widgets/range_of_aqi_chart_title.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/pages/analytics/widgets/analytics_error_widget.dart';
|
||||||
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
import 'package:syncrow_web/utils/style.dart';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class RangeOfAqiChartBox extends StatelessWidget {
|
class RangeOfAqiChartBox extends StatelessWidget {
|
||||||
@ -32,10 +34,20 @@ class RangeOfAqiChartBox extends StatelessWidget {
|
|||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Expanded(
|
Visibility(
|
||||||
child: RangeOfAqiChart(
|
visible: state.filteredRangeOfAqi.isNotEmpty,
|
||||||
chartData: state.filteredRangeOfAqi,
|
replacement: AnalyticsChartEmptyStateWidget(
|
||||||
selectedAqiType: state.selectedAqiType,
|
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,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -63,15 +63,15 @@ class RangeOfAqiChartTitle extends StatelessWidget {
|
|||||||
fit: BoxFit.scaleDown,
|
fit: BoxFit.scaleDown,
|
||||||
alignment: AlignmentDirectional.centerEnd,
|
alignment: AlignmentDirectional.centerEnd,
|
||||||
child: AqiTypeDropdown(
|
child: AqiTypeDropdown(
|
||||||
|
selectedAqiType: context.watch<RangeOfAqiBloc>().state.selectedAqiType,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
final spaceTreeState = context.read<SpaceTreeBloc>().state;
|
final spaceTreeState = context.read<SpaceTreeBloc>().state;
|
||||||
final spaceUuid = spaceTreeState.selectedSpaces.firstOrNull;
|
final spaceUuid = spaceTreeState.selectedSpaces.firstOrNull;
|
||||||
|
|
||||||
if (spaceUuid == null) return;
|
|
||||||
|
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
context.read<RangeOfAqiBloc>().add(UpdateAqiTypeEvent(value));
|
context.read<RangeOfAqiBloc>().add(UpdateAqiTypeEvent(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (spaceUuid == null) return;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -38,7 +38,7 @@ class AnalyticsEnergyManagementView extends StatelessWidget {
|
|||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: _padding,
|
padding: _padding,
|
||||||
height: MediaQuery.sizeOf(context).height * 1,
|
height: MediaQuery.sizeOf(context).height * 1.05,
|
||||||
child: const Column(
|
child: const Column(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
|
@ -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/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_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/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/analytics_error_widget.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/charts_loading_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';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class EnergyConsumptionPerDeviceChartBox extends StatelessWidget {
|
class EnergyConsumptionPerDeviceChartBox extends StatelessWidget {
|
||||||
@ -54,8 +56,24 @@ class EnergyConsumptionPerDeviceChartBox extends StatelessWidget {
|
|||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
const Divider(height: 0),
|
const Divider(height: 0),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Expanded(
|
Visibility(
|
||||||
child: EnergyConsumptionPerDeviceChart(chartData: state.chartData),
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -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/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/chart_title.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/energy_management/widgets/total_energy_consumption_chart.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/analytics_error_widget.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/widgets/charts_loading_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';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class TotalEnergyConsumptionChartBox extends StatelessWidget {
|
class TotalEnergyConsumptionChartBox extends StatelessWidget {
|
||||||
@ -41,7 +43,18 @@ class TotalEnergyConsumptionChartBox extends StatelessWidget {
|
|||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
const SizedBox(height: 20),
|
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),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -18,6 +18,7 @@ class OccupancyChart extends StatelessWidget {
|
|||||||
return BarChart(
|
return BarChart(
|
||||||
BarChartData(
|
BarChartData(
|
||||||
maxY: 100.001,
|
maxY: 100.001,
|
||||||
|
alignment: BarChartAlignment.start,
|
||||||
gridData: EnergyManagementChartsHelper.gridData().copyWith(
|
gridData: EnergyManagementChartsHelper.gridData().copyWith(
|
||||||
checkToShowHorizontalLine: (value) => true,
|
checkToShowHorizontalLine: (value) => true,
|
||||||
horizontalInterval: 20,
|
horizontalInterval: 20,
|
||||||
|
@ -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/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/helpers/fetch_occupancy_data_helper.dart';
|
||||||
import 'package:syncrow_web/pages/analytics/modules/occupancy/widgets/occupancy_chart.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/analytics/widgets/analytics_error_widget.dart';
|
||||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.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';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class OccupancyChartBox extends StatelessWidget {
|
class OccupancyChartBox extends StatelessWidget {
|
||||||
@ -67,7 +69,24 @@ class OccupancyChartBox extends StatelessWidget {
|
|||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
const SizedBox(height: 20),
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -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/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/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/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/analytics/widgets/analytics_error_widget.dart';
|
||||||
import 'package:syncrow_web/pages/space_tree/bloc/space_tree_bloc.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';
|
import 'package:syncrow_web/utils/style.dart';
|
||||||
|
|
||||||
class OccupancyHeatMapBox extends StatelessWidget {
|
class OccupancyHeatMapBox extends StatelessWidget {
|
||||||
@ -68,16 +70,29 @@ class OccupancyHeatMapBox extends StatelessWidget {
|
|||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
Expanded(
|
Visibility(
|
||||||
child: OccupancyHeatMap(
|
visible: state.heatMapData.isNotEmpty &&
|
||||||
selectedDate:
|
state.heatMapData.every(
|
||||||
context.watch<AnalyticsDatePickerBloc>().state.yearlyDate,
|
(e) => e.countTotalPresenceDetected != 0,
|
||||||
heatMapData: state.heatMapData.asMap().map(
|
),
|
||||||
(_, value) => MapEntry(
|
replacement: AnalyticsChartEmptyStateWidget(
|
||||||
value.eventDate,
|
isLoading: state.status == OccupancyHeatMapStatus.loading,
|
||||||
value.countTotalPresenceDetected,
|
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,
|
||||||
|
heatMapData: state.heatMapData.asMap().map(
|
||||||
|
(_, value) => MapEntry(
|
||||||
|
value.eventDate,
|
||||||
|
value.countTotalPresenceDetected,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -17,8 +17,8 @@ class DeviceLocationDetailsServiceDecorator implements DeviceLocationService {
|
|||||||
'reverse',
|
'reverse',
|
||||||
queryParameters: {
|
queryParameters: {
|
||||||
'format': 'json',
|
'format': 'json',
|
||||||
'lat': param.latitude,
|
'lat': 25.1880567,
|
||||||
'lon': param.longitude,
|
'lon': 55.266608,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -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),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -15,7 +15,8 @@ import 'package:syncrow_web/utils/constants/assets.dart';
|
|||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart';
|
||||||
|
|
||||||
class AcDeviceBatchControlView extends StatelessWidget with HelperResponsiveLayout {
|
class AcDeviceBatchControlView extends StatelessWidget
|
||||||
|
with HelperResponsiveLayout {
|
||||||
const AcDeviceBatchControlView({super.key, required this.devicesIds});
|
const AcDeviceBatchControlView({super.key, required this.devicesIds});
|
||||||
|
|
||||||
final List<String> devicesIds;
|
final List<String> devicesIds;
|
||||||
@ -51,7 +52,7 @@ class AcDeviceBatchControlView extends StatelessWidget with HelperResponsiveLayo
|
|||||||
deviceId: devicesIds.first,
|
deviceId: devicesIds.first,
|
||||||
code: 'switch',
|
code: 'switch',
|
||||||
value: state.status.acSwitch,
|
value: state.status.acSwitch,
|
||||||
label: 'ThermoState',
|
label: 'Thermostat',
|
||||||
icon: Assets.ac,
|
icon: Assets.ac,
|
||||||
onChange: (value) {
|
onChange: (value) {
|
||||||
context.read<AcBloc>().add(AcBatchControlEvent(
|
context.read<AcBloc>().add(AcBatchControlEvent(
|
||||||
@ -100,8 +101,8 @@ class AcDeviceBatchControlView extends StatelessWidget with HelperResponsiveLayo
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'h',
|
'h',
|
||||||
style:
|
style: context.textTheme.bodySmall!
|
||||||
context.textTheme.bodySmall!.copyWith(color: ColorsManager.blackColor),
|
.copyWith(color: ColorsManager.blackColor),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'30',
|
'30',
|
||||||
@ -148,7 +149,8 @@ class AcDeviceBatchControlView extends StatelessWidget with HelperResponsiveLayo
|
|||||||
callFactoryReset: () {
|
callFactoryReset: () {
|
||||||
context.read<AcBloc>().add(AcFactoryResetEvent(
|
context.read<AcBloc>().add(AcFactoryResetEvent(
|
||||||
deviceId: state.status.uuid,
|
deviceId: state.status.uuid,
|
||||||
factoryResetModel: FactoryResetModel(devicesUuid: devicesIds),
|
factoryResetModel:
|
||||||
|
FactoryResetModel(devicesUuid: devicesIds),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
@ -16,11 +16,12 @@ class DeviceManagementBloc
|
|||||||
int _onlineCount = 0;
|
int _onlineCount = 0;
|
||||||
int _offlineCount = 0;
|
int _offlineCount = 0;
|
||||||
int _lowBatteryCount = 0;
|
int _lowBatteryCount = 0;
|
||||||
List<AllDevicesModel> _selectedDevices = [];
|
final List<AllDevicesModel> _selectedDevices = [];
|
||||||
List<AllDevicesModel> _filteredDevices = [];
|
List<AllDevicesModel> _filteredDevices = [];
|
||||||
String currentProductName = '';
|
String currentProductName = '';
|
||||||
String? currentCommunity;
|
String? currentCommunity;
|
||||||
String? currentUnitName;
|
String? currentUnitName;
|
||||||
|
String subSpaceName = '';
|
||||||
|
|
||||||
DeviceManagementBloc() : super(DeviceManagementInitial()) {
|
DeviceManagementBloc() : super(DeviceManagementInitial()) {
|
||||||
on<FetchDevices>(_onFetchDevices);
|
on<FetchDevices>(_onFetchDevices);
|
||||||
@ -31,24 +32,29 @@ class DeviceManagementBloc
|
|||||||
on<ResetFilters>(_onResetFilters);
|
on<ResetFilters>(_onResetFilters);
|
||||||
on<ResetSelectedDevices>(_onResetSelectedDevices);
|
on<ResetSelectedDevices>(_onResetSelectedDevices);
|
||||||
on<UpdateSelection>(_onUpdateSelection);
|
on<UpdateSelection>(_onUpdateSelection);
|
||||||
|
on<UpdateDeviceName>(_onUpdateDeviceName);
|
||||||
|
on<UpdateSubSpaceName>(_onUpdateSubSpaceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onFetchDevices(
|
Future<void> _onFetchDevices(
|
||||||
FetchDevices event, Emitter<DeviceManagementState> emit) async {
|
FetchDevices event, Emitter<DeviceManagementState> emit) async {
|
||||||
emit(DeviceManagementLoading());
|
emit(DeviceManagementLoading());
|
||||||
try {
|
try {
|
||||||
List<AllDevicesModel> devices = [];
|
var devices = <AllDevicesModel>[];
|
||||||
_devices.clear();
|
_devices.clear();
|
||||||
var spaceBloc = event.context.read<SpaceTreeBloc>();
|
final spaceBloc = event.context.read<SpaceTreeBloc>();
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
|
|
||||||
if (spaceBloc.state.selectedCommunities.isEmpty) {
|
if (spaceBloc.state.selectedCommunities.isEmpty) {
|
||||||
devices = await DevicesManagementApi().fetchDevices(projectUuid);
|
devices = await DevicesManagementApi().fetchDevices('', '', projectUuid);
|
||||||
} else {
|
} else {
|
||||||
for (var community in spaceBloc.state.selectedCommunities) {
|
for (final community in spaceBloc.state.selectedCommunities) {
|
||||||
List<String> spacesList =
|
final spacesList =
|
||||||
spaceBloc.state.selectedCommunityAndSpaces[community] ?? [];
|
spaceBloc.state.selectedCommunityAndSpaces[community] ?? [];
|
||||||
devices.addAll(await DevicesManagementApi()
|
for (final space in spacesList) {
|
||||||
.fetchDevices(projectUuid, spacesId: spacesList));
|
devices.addAll(await DevicesManagementApi()
|
||||||
|
.fetchDevices(community, space, projectUuid));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +76,7 @@ class DeviceManagementBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onFilterDevices(
|
Future<void> _onFilterDevices(
|
||||||
FilterDevices event, Emitter<DeviceManagementState> emit) async {
|
FilterDevices event, Emitter<DeviceManagementState> emit) async {
|
||||||
if (_devices.isNotEmpty) {
|
if (_devices.isNotEmpty) {
|
||||||
_filteredDevices = List.from(_devices.where((device) {
|
_filteredDevices = List.from(_devices.where((device) {
|
||||||
@ -152,8 +158,7 @@ class DeviceManagementBloc
|
|||||||
add(FilterDevices(_getFilterFromIndex(_selectedIndex)));
|
add(FilterDevices(_getFilterFromIndex(_selectedIndex)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onSelectDevice(
|
void _onSelectDevice(SelectDevice event, Emitter<DeviceManagementState> emit) {
|
||||||
SelectDevice event, Emitter<DeviceManagementState> emit) {
|
|
||||||
final selectedUuid = event.selectedDevice.uuid;
|
final selectedUuid = event.selectedDevice.uuid;
|
||||||
|
|
||||||
if (_selectedDevices.any((device) => device.uuid == selectedUuid)) {
|
if (_selectedDevices.any((device) => device.uuid == selectedUuid)) {
|
||||||
@ -162,9 +167,9 @@ class DeviceManagementBloc
|
|||||||
_selectedDevices.add(event.selectedDevice);
|
_selectedDevices.add(event.selectedDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AllDevicesModel> clonedSelectedDevices = List.from(_selectedDevices);
|
final clonedSelectedDevices = List<AllDevicesModel>.from(_selectedDevices);
|
||||||
|
|
||||||
bool isControlButtonEnabled =
|
final isControlButtonEnabled =
|
||||||
_checkIfControlButtonEnabled(clonedSelectedDevices);
|
_checkIfControlButtonEnabled(clonedSelectedDevices);
|
||||||
|
|
||||||
if (state is DeviceManagementLoaded) {
|
if (state is DeviceManagementLoaded) {
|
||||||
@ -194,8 +199,8 @@ class DeviceManagementBloc
|
|||||||
|
|
||||||
void _onUpdateSelection(
|
void _onUpdateSelection(
|
||||||
UpdateSelection event, Emitter<DeviceManagementState> emit) {
|
UpdateSelection event, Emitter<DeviceManagementState> emit) {
|
||||||
List<AllDevicesModel> selectedDevices = [];
|
final selectedDevices = <AllDevicesModel>[];
|
||||||
List<AllDevicesModel> devicesToSelectFrom = [];
|
var devicesToSelectFrom = <AllDevicesModel>[];
|
||||||
|
|
||||||
if (state is DeviceManagementLoaded) {
|
if (state is DeviceManagementLoaded) {
|
||||||
devicesToSelectFrom = (state as DeviceManagementLoaded).devices;
|
devicesToSelectFrom = (state as DeviceManagementLoaded).devices;
|
||||||
@ -203,7 +208,7 @@ class DeviceManagementBloc
|
|||||||
devicesToSelectFrom = (state as DeviceManagementFiltered).filteredDevices;
|
devicesToSelectFrom = (state as DeviceManagementFiltered).filteredDevices;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < event.selectedRows.length; i++) {
|
for (var i = 0; i < event.selectedRows.length; i++) {
|
||||||
if (event.selectedRows[i]) {
|
if (event.selectedRows[i]) {
|
||||||
selectedDevices.add(devicesToSelectFrom[i]);
|
selectedDevices.add(devicesToSelectFrom[i]);
|
||||||
}
|
}
|
||||||
@ -249,8 +254,7 @@ class DeviceManagementBloc
|
|||||||
_onlineCount = _devices.where((device) => device.online == true).length;
|
_onlineCount = _devices.where((device) => device.online == true).length;
|
||||||
_offlineCount = _devices.where((device) => device.online == false).length;
|
_offlineCount = _devices.where((device) => device.online == false).length;
|
||||||
_lowBatteryCount = _devices
|
_lowBatteryCount = _devices
|
||||||
.where((device) =>
|
.where((device) => device.batteryLevel != null && device.batteryLevel! < 20)
|
||||||
device.batteryLevel != null && device.batteryLevel! < 20)
|
|
||||||
.length;
|
.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,8 +271,7 @@ class DeviceManagementBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onSearchDevices(
|
void _onSearchDevices(SearchDevices event, Emitter<DeviceManagementState> emit) {
|
||||||
SearchDevices event, Emitter<DeviceManagementState> emit) {
|
|
||||||
if ((event.community == null || event.community!.isEmpty) &&
|
if ((event.community == null || event.community!.isEmpty) &&
|
||||||
(event.unitName == null || event.unitName!.isEmpty) &&
|
(event.unitName == null || event.unitName!.isEmpty) &&
|
||||||
(event.deviceNameOrProductName == null ||
|
(event.deviceNameOrProductName == null ||
|
||||||
@ -297,7 +300,7 @@ class DeviceManagementBloc
|
|||||||
currentCommunity = event.community;
|
currentCommunity = event.community;
|
||||||
currentUnitName = event.unitName;
|
currentUnitName = event.unitName;
|
||||||
|
|
||||||
List<AllDevicesModel> devicesToSearch = _devices;
|
final devicesToSearch = _devices;
|
||||||
|
|
||||||
if (devicesToSearch.isNotEmpty) {
|
if (devicesToSearch.isNotEmpty) {
|
||||||
final searchText = event.deviceNameOrProductName?.toLowerCase() ?? '';
|
final searchText = event.deviceNameOrProductName?.toLowerCase() ?? '';
|
||||||
@ -340,5 +343,134 @@ class DeviceManagementBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _onUpdateDeviceName(
|
||||||
|
UpdateDeviceName event, Emitter<DeviceManagementState> emit) {
|
||||||
|
final devices = _devices.map((device) {
|
||||||
|
if (device.uuid == event.deviceId) {
|
||||||
|
final modifiedDevice = device.copyWith(name: event.newName);
|
||||||
|
_selectedDevices.removeWhere((device) => device.uuid == event.deviceId);
|
||||||
|
_selectedDevices.add(modifiedDevice);
|
||||||
|
return modifiedDevice;
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
final filteredDevices = _filteredDevices.map((device) {
|
||||||
|
if (device.uuid == event.deviceId) {
|
||||||
|
final modifiedDevice = device.copyWith(name: event.newName);
|
||||||
|
_selectedDevices.removeWhere((device) => device.uuid == event.deviceId);
|
||||||
|
_selectedDevices.add(modifiedDevice);
|
||||||
|
return modifiedDevice;
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
_devices = devices;
|
||||||
|
_filteredDevices = filteredDevices;
|
||||||
|
|
||||||
|
if (state is DeviceManagementLoaded) {
|
||||||
|
final loaded = state as DeviceManagementLoaded;
|
||||||
|
final selectedDevices01 = _selectedDevices.map((device) {
|
||||||
|
if (device.uuid == event.deviceId) {
|
||||||
|
final modifiedDevice = device.copyWith(name: event.newName);
|
||||||
|
return modifiedDevice;
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}).toList();
|
||||||
|
emit(DeviceManagementLoaded(
|
||||||
|
devices: devices,
|
||||||
|
selectedIndex: loaded.selectedIndex,
|
||||||
|
onlineCount: loaded.onlineCount,
|
||||||
|
offlineCount: loaded.offlineCount,
|
||||||
|
lowBatteryCount: loaded.lowBatteryCount,
|
||||||
|
selectedDevice: selectedDevices01,
|
||||||
|
isControlButtonEnabled: loaded.isControlButtonEnabled,
|
||||||
|
));
|
||||||
|
} else if (state is DeviceManagementFiltered) {
|
||||||
|
final filtered = state as DeviceManagementFiltered;
|
||||||
|
final selectedDevices01 = filtered.selectedDevice?.map((device) {
|
||||||
|
if (device.uuid == event.deviceId) {
|
||||||
|
final modifiedDevice = device.copyWith(name: event.newName);
|
||||||
|
return modifiedDevice;
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}).toList();
|
||||||
|
emit(DeviceManagementFiltered(
|
||||||
|
filteredDevices: filteredDevices,
|
||||||
|
selectedIndex: filtered.selectedIndex,
|
||||||
|
onlineCount: filtered.onlineCount,
|
||||||
|
offlineCount: filtered.offlineCount,
|
||||||
|
lowBatteryCount: filtered.lowBatteryCount,
|
||||||
|
selectedDevice: selectedDevices01,
|
||||||
|
isControlButtonEnabled: filtered.isControlButtonEnabled,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onUpdateSubSpaceName(
|
||||||
|
UpdateSubSpaceName event, Emitter<DeviceManagementState> emit) {
|
||||||
|
final devices = _devices.map((device) {
|
||||||
|
if (device.uuid == event.deviceId) {
|
||||||
|
return device.copyWith(
|
||||||
|
subspace:
|
||||||
|
device.subspace?.copyWith(subspaceName: event.newSubSpaceName));
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
final filteredDevices = _filteredDevices.map((device) {
|
||||||
|
if (device.uuid == event.deviceId) {
|
||||||
|
return device.copyWith(
|
||||||
|
subspace:
|
||||||
|
device.subspace?.copyWith(subspaceName: event.newSubSpaceName));
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
_devices = devices;
|
||||||
|
_filteredDevices = filteredDevices;
|
||||||
|
|
||||||
|
if (state is DeviceManagementLoaded) {
|
||||||
|
final loaded = state as DeviceManagementLoaded;
|
||||||
|
final selectedDevices = loaded.selectedDevice?.map((device) {
|
||||||
|
if (device.uuid == event.deviceId) {
|
||||||
|
return device.copyWith(
|
||||||
|
subspace:
|
||||||
|
device.subspace?.copyWith(subspaceName: event.newSubSpaceName));
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}).toList();
|
||||||
|
emit(DeviceManagementLoaded(
|
||||||
|
devices: _devices,
|
||||||
|
selectedIndex: loaded.selectedIndex,
|
||||||
|
onlineCount: loaded.onlineCount,
|
||||||
|
offlineCount: loaded.offlineCount,
|
||||||
|
lowBatteryCount: loaded.lowBatteryCount,
|
||||||
|
selectedDevice: selectedDevices,
|
||||||
|
isControlButtonEnabled: loaded.isControlButtonEnabled,
|
||||||
|
));
|
||||||
|
} else if (state is DeviceManagementFiltered) {
|
||||||
|
// final filtered = state as DeviceManagementFiltered;
|
||||||
|
// emit(DeviceManagementFiltered(
|
||||||
|
// filteredDevices: _filteredDevices,
|
||||||
|
// selectedIndex: filtered.selectedIndex,
|
||||||
|
// onlineCount: filtered.onlineCount,
|
||||||
|
// offlineCount: filtered.offlineCount,
|
||||||
|
// lowBatteryCount: filtered.lowBatteryCount,
|
||||||
|
// selectedDevice: filtered.selectedDevice,
|
||||||
|
// isControlButtonEnabled: filtered.isControlButtonEnabled,
|
||||||
|
// ));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void changeSubspaceName(
|
||||||
|
String deviceId, String newSubSpaceName, String subspaceId) {
|
||||||
|
add(UpdateSubSpaceName(
|
||||||
|
deviceId: deviceId,
|
||||||
|
newSubSpaceName: newSubSpaceName,
|
||||||
|
subspaceId: subspaceId,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
List<AllDevicesModel> get selectedDevices => _selectedDevices;
|
List<AllDevicesModel> get selectedDevices => _selectedDevices;
|
||||||
}
|
}
|
||||||
|
@ -70,3 +70,21 @@ class UpdateSelection extends DeviceManagementEvent {
|
|||||||
|
|
||||||
const UpdateSelection(this.selectedRows);
|
const UpdateSelection(this.selectedRows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class UpdateDeviceName extends DeviceManagementEvent {
|
||||||
|
final String deviceId;
|
||||||
|
final String newName;
|
||||||
|
|
||||||
|
const UpdateDeviceName({required this.deviceId, required this.newName});
|
||||||
|
}
|
||||||
|
|
||||||
|
class UpdateSubSpaceName extends DeviceManagementEvent {
|
||||||
|
final String deviceId;
|
||||||
|
final String newSubSpaceName;
|
||||||
|
final String subspaceId;
|
||||||
|
|
||||||
|
const UpdateSubSpaceName(
|
||||||
|
{required this.deviceId,
|
||||||
|
required this.newSubSpaceName,
|
||||||
|
required this.subspaceId});
|
||||||
|
}
|
||||||
|
@ -60,4 +60,13 @@ class Status {
|
|||||||
factory Status.fromJson(String source) => Status.fromMap(json.decode(source));
|
factory Status.fromJson(String source) => Status.fromMap(json.decode(source));
|
||||||
|
|
||||||
String toJson() => json.encode(toMap());
|
String toJson() => json.encode(toMap());
|
||||||
|
Status copyWith({
|
||||||
|
String? code,
|
||||||
|
dynamic value,
|
||||||
|
}) {
|
||||||
|
return Status(
|
||||||
|
code: code ?? this.code,
|
||||||
|
value: value ?? this.value,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,4 +44,20 @@ class DeviceSubspace {
|
|||||||
static List<Map<String, dynamic>> listToJson(List<DeviceSubspace> subspaces) {
|
static List<Map<String, dynamic>> listToJson(List<DeviceSubspace> subspaces) {
|
||||||
return subspaces.map((subspace) => subspace.toJson()).toList();
|
return subspaces.map((subspace) => subspace.toJson()).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DeviceSubspace copyWith({
|
||||||
|
String? uuid,
|
||||||
|
DateTime? createdAt,
|
||||||
|
DateTime? updatedAt,
|
||||||
|
String? subspaceName,
|
||||||
|
bool? disabled,
|
||||||
|
}) {
|
||||||
|
return DeviceSubspace(
|
||||||
|
uuid: uuid ?? this.uuid,
|
||||||
|
createdAt: createdAt ?? this.createdAt,
|
||||||
|
updatedAt: updatedAt ?? this.updatedAt,
|
||||||
|
subspaceName: subspaceName ?? this.subspaceName,
|
||||||
|
disabled: disabled ?? this.disabled,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -588,4 +588,72 @@ SOS
|
|||||||
"NCPS": DeviceType.NCPS,
|
"NCPS": DeviceType.NCPS,
|
||||||
"PC": DeviceType.PC,
|
"PC": DeviceType.PC,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AllDevicesModel copyWith({
|
||||||
|
DevicesModelRoom? room,
|
||||||
|
DeviceSubspace? subspace,
|
||||||
|
DevicesModelUnit? unit,
|
||||||
|
DeviceCommunityModel? community,
|
||||||
|
String? productUuid,
|
||||||
|
String? productType,
|
||||||
|
String? permissionType,
|
||||||
|
int? activeTime,
|
||||||
|
String? category,
|
||||||
|
String? categoryName,
|
||||||
|
int? createTime,
|
||||||
|
String? gatewayId,
|
||||||
|
String? icon,
|
||||||
|
String? ip,
|
||||||
|
String? lat,
|
||||||
|
String? localKey,
|
||||||
|
String? lon,
|
||||||
|
String? model,
|
||||||
|
String? name,
|
||||||
|
String? nodeId,
|
||||||
|
bool? online,
|
||||||
|
String? ownerId,
|
||||||
|
bool? sub,
|
||||||
|
String? timeZone,
|
||||||
|
int? updateTime,
|
||||||
|
String? uuid,
|
||||||
|
int? batteryLevel,
|
||||||
|
String? productName,
|
||||||
|
List<DeviceSpaceModel>? spaces,
|
||||||
|
List<DeviceTagModel>? deviceTags,
|
||||||
|
DeviceSubSpace? deviceSubSpace,
|
||||||
|
}) {
|
||||||
|
return AllDevicesModel(
|
||||||
|
room: room ?? this.room,
|
||||||
|
subspace: subspace ?? this.subspace,
|
||||||
|
unit: unit ?? this.unit,
|
||||||
|
community: community ?? this.community,
|
||||||
|
productUuid: productUuid ?? this.productUuid,
|
||||||
|
productType: productType ?? this.productType,
|
||||||
|
permissionType: permissionType ?? this.permissionType,
|
||||||
|
activeTime: activeTime ?? this.activeTime,
|
||||||
|
category: category ?? this.category,
|
||||||
|
categoryName: categoryName ?? this.categoryName,
|
||||||
|
createTime: createTime ?? this.createTime,
|
||||||
|
gatewayId: gatewayId ?? this.gatewayId,
|
||||||
|
icon: icon ?? this.icon,
|
||||||
|
ip: ip ?? this.ip,
|
||||||
|
lat: lat ?? this.lat,
|
||||||
|
localKey: localKey ?? this.localKey,
|
||||||
|
lon: lon ?? this.lon,
|
||||||
|
model: model ?? this.model,
|
||||||
|
name: name ?? this.name,
|
||||||
|
nodeId: nodeId ?? this.nodeId,
|
||||||
|
online: online ?? this.online,
|
||||||
|
ownerId: ownerId ?? this.ownerId,
|
||||||
|
sub: sub ?? this.sub,
|
||||||
|
timeZone: timeZone ?? this.timeZone,
|
||||||
|
updateTime: updateTime ?? this.updateTime,
|
||||||
|
uuid: uuid ?? this.uuid,
|
||||||
|
batteryLevel: batteryLevel ?? this.batteryLevel,
|
||||||
|
productName: productName ?? this.productName,
|
||||||
|
spaces: spaces ?? this.spaces,
|
||||||
|
deviceTags: deviceTags ?? this.deviceTags,
|
||||||
|
deviceSubSpace: deviceSubSpace ?? this.deviceSubSpace,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
return BlocBuilder<DeviceManagementBloc, DeviceManagementState>(
|
||||||
|
buildWhen: (previous, current) => previous != current,
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
List<AllDevicesModel> devicesToShow = [];
|
List<AllDevicesModel> devicesToShow = [];
|
||||||
int selectedIndex = 0;
|
int selectedIndex = 0;
|
||||||
@ -31,7 +32,6 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
int lowBatteryCount = 0;
|
int lowBatteryCount = 0;
|
||||||
bool isControlButtonEnabled = false;
|
bool isControlButtonEnabled = false;
|
||||||
List<AllDevicesModel> selectedDevices = [];
|
List<AllDevicesModel> selectedDevices = [];
|
||||||
|
|
||||||
if (state is DeviceManagementLoaded) {
|
if (state is DeviceManagementLoaded) {
|
||||||
devicesToShow = state.devices;
|
devicesToShow = state.devices;
|
||||||
selectedIndex = state.selectedIndex;
|
selectedIndex = state.selectedIndex;
|
||||||
@ -68,6 +68,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(child: SpaceTreeView(
|
Expanded(child: SpaceTreeView(
|
||||||
onSelect: () {
|
onSelect: () {
|
||||||
|
context.read<DeviceManagementBloc>().add(ResetFilters());
|
||||||
context.read<DeviceManagementBloc>().add(FetchDevices(context));
|
context.read<DeviceManagementBloc>().add(FetchDevices(context));
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
@ -111,6 +112,8 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
onPressed: isControlButtonEnabled
|
onPressed: isControlButtonEnabled
|
||||||
? () {
|
? () {
|
||||||
if (isAnyDeviceOffline) {
|
if (isAnyDeviceOffline) {
|
||||||
|
ScaffoldMessenger.of(context)
|
||||||
|
.clearSnackBars();
|
||||||
ScaffoldMessenger.of(context)
|
ScaffoldMessenger.of(context)
|
||||||
.showSnackBar(
|
.showSnackBar(
|
||||||
const SnackBar(
|
const SnackBar(
|
||||||
@ -190,7 +193,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
'Product Name',
|
'Product Name',
|
||||||
'Device ID',
|
'Device ID',
|
||||||
'Space Name',
|
'Space Name',
|
||||||
'location',
|
'Location',
|
||||||
'Battery Level',
|
'Battery Level',
|
||||||
'Installation Date and Time',
|
'Installation Date and Time',
|
||||||
'Status',
|
'Status',
|
||||||
@ -242,7 +245,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
.map((device) => device.uuid!)
|
.map((device) => device.uuid!)
|
||||||
.toList(),
|
.toList(),
|
||||||
isEmpty: devicesToShow.isEmpty,
|
isEmpty: devicesToShow.isEmpty,
|
||||||
onSettingsPressed: (rowIndex) {
|
onSettingsPressed: (rowIndex) async {
|
||||||
final device = devicesToShow[rowIndex];
|
final device = devicesToShow[rowIndex];
|
||||||
showDeviceSettingsSidebar(context, device);
|
showDeviceSettingsSidebar(context, device);
|
||||||
},
|
},
|
||||||
@ -264,7 +267,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
barrierLabel: "Device Settings",
|
barrierLabel: "Device Settings",
|
||||||
transitionDuration: const Duration(milliseconds: 300),
|
transitionDuration: const Duration(milliseconds: 300),
|
||||||
pageBuilder: (context, anim1, anim2) {
|
pageBuilder: (_, anim1, anim2) {
|
||||||
return Align(
|
return Align(
|
||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
child: Material(
|
child: Material(
|
||||||
@ -274,6 +277,7 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
child: DeviceSettingsPanel(
|
child: DeviceSettingsPanel(
|
||||||
device: device,
|
device: device,
|
||||||
onClose: () => Navigator.of(context).pop(),
|
onClose: () => Navigator.of(context).pop(),
|
||||||
|
deviceManagementBloc: context.read<DeviceManagementBloc>(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -62,9 +62,10 @@ class CurtainModuleItems extends StatelessWidget with HelperResponsiveLayout {
|
|||||||
BlocProvider.of<CurtainModuleBloc>(context),
|
BlocProvider.of<CurtainModuleBloc>(context),
|
||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'CUR_2',
|
category: 'Timer',
|
||||||
code: 'control',
|
code: 'control',
|
||||||
|
countdownCode: 'Timer',
|
||||||
|
deviceType: 'CUR_2',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -17,7 +17,6 @@ class CalibrateCompletedDialog extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(_) {
|
Widget build(_) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
backgroundColor: ColorsManager.whiteColors,
|
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
height: 250,
|
height: 250,
|
||||||
|
@ -19,11 +19,14 @@ class DeviceManagementContent extends StatelessWidget {
|
|||||||
required this.device,
|
required this.device,
|
||||||
required this.subSpaces,
|
required this.subSpaces,
|
||||||
required this.deviceInfo,
|
required this.deviceInfo,
|
||||||
|
required this.deviceManagementBloc,
|
||||||
});
|
});
|
||||||
|
|
||||||
final AllDevicesModel device;
|
final AllDevicesModel device;
|
||||||
final List<SubSpaceModel> subSpaces;
|
final List<SubSpaceModel> subSpaces;
|
||||||
final DeviceInfoModel deviceInfo;
|
final DeviceInfoModel deviceInfo;
|
||||||
|
final DeviceManagementBloc deviceManagementBloc;
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -87,6 +90,11 @@ class DeviceManagementContent extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
deviceManagementBloc.add(UpdateSubSpaceName(
|
||||||
|
subspaceId: selectedSubSpace.id!,
|
||||||
|
deviceId: device.uuid!,
|
||||||
|
newSubSpaceName: selectedSubSpace.name ?? ''));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: infoRow(
|
child: infoRow(
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/rendering.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/all_devices/bloc/device_mgmt_bloc/device_managment_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/devices_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/device_setting/bloc/setting_bloc_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/device_managment/device_setting/bloc/setting_bloc_state.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/device_setting/device_icon_type_helper.dart';
|
import 'package:syncrow_web/pages/device_managment/device_setting/device_icon_type_helper.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/device_setting/device_management_content.dart';
|
import 'package:syncrow_web/pages/device_managment/device_setting/device_management_content.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/device_setting/remove_device_widget.dart';
|
import 'package:syncrow_web/pages/device_managment/device_setting/remove_device_widget.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/device_info_model.dart';
|
import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/device_info_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/device_setting/bloc/setting_bloc_bloc.dart';
|
|
||||||
import 'package:syncrow_web/pages/device_managment/device_setting/bloc/setting_bloc_state.dart';
|
|
||||||
import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/sub_space_model.dart';
|
import 'package:syncrow_web/pages/device_managment/device_setting/settings_model/sub_space_model.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||||
@ -17,7 +19,13 @@ import 'package:syncrow_web/web_layout/default_container.dart';
|
|||||||
class DeviceSettingsPanel extends StatelessWidget {
|
class DeviceSettingsPanel extends StatelessWidget {
|
||||||
final VoidCallback? onClose;
|
final VoidCallback? onClose;
|
||||||
final AllDevicesModel device;
|
final AllDevicesModel device;
|
||||||
const DeviceSettingsPanel({super.key, this.onClose, required this.device});
|
final DeviceManagementBloc deviceManagementBloc;
|
||||||
|
const DeviceSettingsPanel({
|
||||||
|
super.key,
|
||||||
|
this.onClose,
|
||||||
|
required this.device,
|
||||||
|
required this.deviceManagementBloc,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -71,10 +79,10 @@ class DeviceSettingsPanel extends StatelessWidget {
|
|||||||
'Device Settings',
|
'Device Settings',
|
||||||
style: context.theme.textTheme.titleLarge!
|
style: context.theme.textTheme.titleLarge!
|
||||||
.copyWith(
|
.copyWith(
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
color: ColorsManager.vividBlue
|
color: ColorsManager.vividBlue
|
||||||
.withOpacity(0.7),
|
.withOpacity(0.7),
|
||||||
fontSize: 24),
|
fontSize: 24),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -134,8 +142,14 @@ class DeviceSettingsPanel extends StatelessWidget {
|
|||||||
onFieldSubmitted: (value) {
|
onFieldSubmitted: (value) {
|
||||||
_bloc.add(const ChangeNameEvent(
|
_bloc.add(const ChangeNameEvent(
|
||||||
value: false));
|
value: false));
|
||||||
|
deviceManagementBloc
|
||||||
|
..add(UpdateDeviceName(
|
||||||
|
deviceId: device.uuid!,
|
||||||
|
newName: _bloc
|
||||||
|
.nameController
|
||||||
|
.text))..add(ResetSelectedDevices());
|
||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
decoration:const InputDecoration(
|
||||||
isDense: true,
|
isDense: true,
|
||||||
contentPadding: EdgeInsets.zero,
|
contentPadding: EdgeInsets.zero,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
@ -157,7 +171,7 @@ class DeviceSettingsPanel extends StatelessWidget {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
_bloc.add(
|
_bloc.add(
|
||||||
const ChangeNameEvent(
|
const ChangeNameEvent(
|
||||||
value: true));
|
value: true));
|
||||||
},
|
},
|
||||||
child: SvgPicture.asset(
|
child: SvgPicture.asset(
|
||||||
Assets
|
Assets
|
||||||
@ -190,6 +204,7 @@ class DeviceSettingsPanel extends StatelessWidget {
|
|||||||
device: device,
|
device: device,
|
||||||
subSpaces: subSpaces.cast<SubSpaceModel>(),
|
subSpaces: subSpaces.cast<SubSpaceModel>(),
|
||||||
deviceInfo: deviceInfo,
|
deviceInfo: deviceInfo,
|
||||||
|
deviceManagementBloc: deviceManagementBloc,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
RemoveDeviceWidget(bloc: _bloc),
|
RemoveDeviceWidget(bloc: _bloc),
|
||||||
|
@ -40,7 +40,7 @@ class OneGangGlassSwitchBloc
|
|||||||
emit(OneGangGlassSwitchLoading());
|
emit(OneGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
_listenToChanges(event.deviceId, emit);
|
_listenToChanges(event.deviceId);
|
||||||
deviceStatus = OneGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
deviceStatus = OneGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||||
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(OneGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -48,42 +48,28 @@ class OneGangGlassSwitchBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _listenToChanges(
|
StreamSubscription<DatabaseEvent>? _deviceStatusSubscription;
|
||||||
String deviceId,
|
|
||||||
Emitter<OneGangGlassSwitchState> emit,
|
void _listenToChanges(String deviceId) {
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
final stream = ref.onValue;
|
_deviceStatusSubscription = ref.onValue.listen((DatabaseEvent event) async {
|
||||||
|
if (event.snapshot.value == null) return;
|
||||||
|
|
||||||
stream.listen((DatabaseEvent event) {
|
final usersMap = event.snapshot.value! as Map<dynamic, dynamic>;
|
||||||
final data = event.snapshot.value as Map<dynamic, dynamic>?;
|
|
||||||
if (data == null) return;
|
|
||||||
|
|
||||||
final statusList = <Status>[];
|
final statusList = <Status>[];
|
||||||
if (data['status'] != null) {
|
|
||||||
for (var element in data['status']) {
|
usersMap['status'].forEach((element) {
|
||||||
statusList.add(
|
statusList.add(Status(code: element['code'], value: element['value']));
|
||||||
Status(
|
});
|
||||||
code: element['code'].toString(),
|
|
||||||
value: element['value'].toString(),
|
deviceStatus =
|
||||||
),
|
OneGangGlassStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||||
);
|
|
||||||
}
|
add(StatusUpdated(deviceStatus));
|
||||||
}
|
|
||||||
if (statusList.isNotEmpty) {
|
|
||||||
final newStatus = OneGangGlassStatusModel.fromJson(deviceId, statusList);
|
|
||||||
if (newStatus != deviceStatus) {
|
|
||||||
deviceStatus = newStatus;
|
|
||||||
if (!isClosed) {
|
|
||||||
add(StatusUpdated(deviceStatus));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (_) {}
|
||||||
emit(OneGangGlassSwitchError('Failed to listen to changes: $e'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onStatusUpdated(
|
void _onStatusUpdated(
|
||||||
@ -174,4 +160,10 @@ class OneGangGlassSwitchBloc
|
|||||||
deviceStatus = deviceStatus.copyWith(switch1: value);
|
deviceStatus = deviceStatus.copyWith(switch1: value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() {
|
||||||
|
_deviceStatusSubscription?.cancel();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,6 +90,8 @@ class OneGangGlassSwitchControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
|
countdownCode: 'countdown_1',
|
||||||
|
deviceType: '1GT',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -80,6 +80,8 @@ class WallLightDeviceControl extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
|
countdownCode: 'countdown_1',
|
||||||
|
deviceType: '1G',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -277,6 +277,32 @@ class SmartPowerDeviceControl extends StatelessWidget
|
|||||||
totalConsumption: 10000,
|
totalConsumption: 10000,
|
||||||
date: blocProvider.formattedDate,
|
date: blocProvider.formattedDate,
|
||||||
),
|
),
|
||||||
|
EnergyConsumptionPage(
|
||||||
|
formattedDate:
|
||||||
|
'${blocProvider.dateTime!.day}/${blocProvider.dateTime!.month}/${blocProvider.dateTime!.year} ${blocProvider.endChartDate}',
|
||||||
|
onTap: () {
|
||||||
|
blocProvider.add(SelectDateEvent(context: context));
|
||||||
|
},
|
||||||
|
widget: blocProvider.dateSwitcher(),
|
||||||
|
chartData: blocProvider.energyDataList.isNotEmpty
|
||||||
|
? blocProvider.energyDataList
|
||||||
|
: [
|
||||||
|
EnergyData('12:00 AM', 4.0),
|
||||||
|
EnergyData('01:00 AM', 6.5),
|
||||||
|
EnergyData('02:00 AM', 3.8),
|
||||||
|
EnergyData('03:00 AM', 3.2),
|
||||||
|
EnergyData('04:00 AM', 6.0),
|
||||||
|
EnergyData('05:00 AM', 3.4),
|
||||||
|
EnergyData('06:00 AM', 5.2),
|
||||||
|
EnergyData('07:00 AM', 3.5),
|
||||||
|
EnergyData('08:00 AM', 6.8),
|
||||||
|
EnergyData('09:00 AM', 5.6),
|
||||||
|
EnergyData('10:00 AM', 3.9),
|
||||||
|
EnergyData('11:00 AM', 4.0),
|
||||||
|
],
|
||||||
|
totalConsumption: 10000,
|
||||||
|
date: blocProvider.formattedDate,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -47,7 +47,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
final success = await RemoteControlDeviceService().controlDevice(
|
final success = await RemoteControlDeviceService().controlDevice(
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
status: Status(
|
status: Status(
|
||||||
code: 'countdown_1',
|
code: event.countdownCode,
|
||||||
value: 0,
|
value: 0,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -80,15 +80,18 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
) {
|
) {
|
||||||
if (state is ScheduleLoaded) {
|
if (state is ScheduleLoaded) {
|
||||||
final currentState = state as ScheduleLoaded;
|
final currentState = state as ScheduleLoaded;
|
||||||
|
|
||||||
emit(currentState.copyWith(
|
emit(currentState.copyWith(
|
||||||
|
countdownSeconds: currentState.countdownSeconds,
|
||||||
|
selectedTime: currentState.selectedTime,
|
||||||
|
deviceId: deviceId,
|
||||||
scheduleMode: event.scheduleMode,
|
scheduleMode: event.scheduleMode,
|
||||||
countdownRemaining: Duration.zero,
|
countdownHours: currentState.countdownHours,
|
||||||
countdownHours: 0,
|
countdownMinutes: currentState.countdownMinutes,
|
||||||
countdownMinutes: 0,
|
inchingHours: currentState.inchingHours,
|
||||||
inchingHours: 0,
|
inchingMinutes: currentState.inchingMinutes,
|
||||||
inchingMinutes: 0,
|
|
||||||
isCountdownActive: false,
|
|
||||||
isInchingActive: false,
|
isInchingActive: false,
|
||||||
|
isCountdownActive: currentState.countdownRemaining > Duration.zero,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,7 +224,6 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
deviceId,
|
deviceId,
|
||||||
event.category,
|
event.category,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (state is ScheduleLoaded) {
|
if (state is ScheduleLoaded) {
|
||||||
final currentState = state as ScheduleLoaded;
|
final currentState = state as ScheduleLoaded;
|
||||||
emit(currentState.copyWith(
|
emit(currentState.copyWith(
|
||||||
@ -230,7 +232,6 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
selectedDays: List.filled(7, false),
|
selectedDays: List.filled(7, false),
|
||||||
functionOn: false,
|
functionOn: false,
|
||||||
isEditing: false,
|
isEditing: false,
|
||||||
countdownRemaining: Duration.zero,
|
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
emit(ScheduleLoaded(
|
emit(ScheduleLoaded(
|
||||||
@ -285,12 +286,22 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
if (state is ScheduleLoaded) {
|
if (state is ScheduleLoaded) {
|
||||||
|
Status status = Status(code: '', value: '');
|
||||||
|
if (event.deviceType == 'CUR_2') {
|
||||||
|
status = status.copyWith(
|
||||||
|
code: 'control',
|
||||||
|
value: event.functionOn == true ? 'open' : 'close');
|
||||||
|
} else {
|
||||||
|
status =
|
||||||
|
status.copyWith(code: event.category, value: event.functionOn);
|
||||||
|
}
|
||||||
|
|
||||||
final dateTime = DateTime.parse(event.time);
|
final dateTime = DateTime.parse(event.time);
|
||||||
final updatedSchedule = ScheduleEntry(
|
final updatedSchedule = ScheduleEntry(
|
||||||
scheduleId: event.scheduleId,
|
scheduleId: event.scheduleId,
|
||||||
category: event.category,
|
category: event.category,
|
||||||
time: getTimeStampWithoutSeconds(dateTime).toString(),
|
time: getTimeStampWithoutSeconds(dateTime).toString(),
|
||||||
function: Status(code: event.category, value: event.functionOn),
|
function: status,
|
||||||
days: event.selectedDays,
|
days: event.selectedDays,
|
||||||
);
|
);
|
||||||
final success = await DevicesManagementApi().editScheduleRecord(
|
final success = await DevicesManagementApi().editScheduleRecord(
|
||||||
@ -396,7 +407,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
final totalSeconds =
|
final totalSeconds =
|
||||||
Duration(hours: event.hours, minutes: event.minutes).inSeconds;
|
Duration(hours: event.hours, minutes: event.minutes).inSeconds;
|
||||||
final code = event.mode == ScheduleModes.countdown
|
final code = event.mode == ScheduleModes.countdown
|
||||||
? 'countdown_1'
|
? event.countDownCode
|
||||||
: 'switch_inching';
|
: 'switch_inching';
|
||||||
final currentState = state as ScheduleLoaded;
|
final currentState = state as ScheduleLoaded;
|
||||||
final duration = Duration(seconds: totalSeconds);
|
final duration = Duration(seconds: totalSeconds);
|
||||||
@ -423,7 +434,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
if (code == 'countdown_1') {
|
if (code == event.countDownCode) {
|
||||||
final countdownDuration = Duration(seconds: totalSeconds);
|
final countdownDuration = Duration(seconds: totalSeconds);
|
||||||
|
|
||||||
emit(
|
emit(
|
||||||
@ -437,7 +448,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (countdownDuration.inSeconds > 0) {
|
if (countdownDuration.inSeconds > 0) {
|
||||||
_startCountdownTimer(emit, countdownDuration);
|
_startCountdownTimer(emit, countdownDuration, event.countDownCode);
|
||||||
} else {
|
} else {
|
||||||
_countdownTimer?.cancel();
|
_countdownTimer?.cancel();
|
||||||
emit(
|
emit(
|
||||||
@ -467,9 +478,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _startCountdownTimer(
|
void _startCountdownTimer(
|
||||||
Emitter<ScheduleState> emit,
|
Emitter<ScheduleState> emit, Duration duration, String countdownCode) {
|
||||||
Duration duration,
|
|
||||||
) {
|
|
||||||
_countdownTimer?.cancel();
|
_countdownTimer?.cancel();
|
||||||
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
|
||||||
if (_currentCountdown != null && _currentCountdown! > Duration.zero) {
|
if (_currentCountdown != null && _currentCountdown! > Duration.zero) {
|
||||||
@ -479,6 +488,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
} else {
|
} else {
|
||||||
timer.cancel();
|
timer.cancel();
|
||||||
add(StopScheduleEvent(
|
add(StopScheduleEvent(
|
||||||
|
countdownCode: countdownCode,
|
||||||
mode: _currentCountdown == null
|
mode: _currentCountdown == null
|
||||||
? ScheduleModes.countdown
|
? ScheduleModes.countdown
|
||||||
: ScheduleModes.inching,
|
: ScheduleModes.inching,
|
||||||
@ -515,70 +525,75 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
|
|||||||
try {
|
try {
|
||||||
final status =
|
final status =
|
||||||
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
print(status.status);
|
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;
|
||||||
|
|
||||||
final deviceStatus =
|
final deviceStatus =
|
||||||
WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
|
WaterHeaterStatusModel.fromJson(event.deviceId, status.status);
|
||||||
|
final isCountdownActive = totalSeconds > 0;
|
||||||
|
final isInchingActive = !isCountdownActive &&
|
||||||
|
(deviceStatus.inchingHours > 0 || deviceStatus.inchingMinutes > 0);
|
||||||
|
|
||||||
final scheduleMode =
|
final newState = state is ScheduleLoaded
|
||||||
deviceStatus.countdownHours > 0 || deviceStatus.countdownMinutes > 0
|
? (state as ScheduleLoaded).copyWith(
|
||||||
? ScheduleModes.countdown
|
scheduleMode: ScheduleModes.schedule,
|
||||||
: deviceStatus.inchingHours > 0 || deviceStatus.inchingMinutes > 0
|
countdownHours: countdownHours,
|
||||||
? ScheduleModes.inching
|
countdownMinutes: countdownMinutes,
|
||||||
: ScheduleModes.schedule;
|
countdownSeconds: countdownSeconds,
|
||||||
final isCountdown = scheduleMode == ScheduleModes.countdown;
|
inchingHours: deviceStatus.inchingHours,
|
||||||
final isInching = scheduleMode == ScheduleModes.inching;
|
inchingMinutes: deviceStatus.inchingMinutes,
|
||||||
|
isCountdownActive: isCountdownActive,
|
||||||
|
isInchingActive: isInchingActive,
|
||||||
|
countdownRemaining: isCountdownActive
|
||||||
|
? Duration(seconds: totalSeconds)
|
||||||
|
: Duration.zero,
|
||||||
|
)
|
||||||
|
: ScheduleLoaded(
|
||||||
|
scheduleMode: ScheduleModes.schedule,
|
||||||
|
schedules: const [],
|
||||||
|
selectedTime: null,
|
||||||
|
selectedDays: List.filled(7, false),
|
||||||
|
functionOn: false,
|
||||||
|
isEditing: false,
|
||||||
|
deviceId: event.deviceId,
|
||||||
|
countdownHours: countdownHours,
|
||||||
|
countdownMinutes: countdownMinutes,
|
||||||
|
countdownSeconds: countdownSeconds,
|
||||||
|
inchingHours: deviceStatus.inchingHours,
|
||||||
|
inchingMinutes: deviceStatus.inchingMinutes,
|
||||||
|
isCountdownActive: isCountdownActive,
|
||||||
|
isInchingActive: isInchingActive,
|
||||||
|
countdownRemaining: isCountdownActive
|
||||||
|
? Duration(seconds: totalSeconds)
|
||||||
|
: Duration.zero,
|
||||||
|
);
|
||||||
|
emit(newState);
|
||||||
|
|
||||||
Duration? countdownRemaining;
|
if (isCountdownActive) {
|
||||||
var isCountdownActive = false;
|
_countdownTimer?.cancel();
|
||||||
var isInchingActive = false;
|
_currentCountdown = Duration(seconds: totalSeconds);
|
||||||
|
countdownRemaining = _currentCountdown!;
|
||||||
|
|
||||||
if (isCountdown) {
|
if (totalSeconds > 0) {
|
||||||
countdownRemaining = Duration(
|
_startCountdownTimer(
|
||||||
hours: deviceStatus.countdownHours,
|
emit, Duration(seconds: totalSeconds), event.countdownCode);
|
||||||
minutes: deviceStatus.countdownMinutes,
|
} else {
|
||||||
);
|
add(StopScheduleEvent(
|
||||||
isCountdownActive = countdownRemaining > Duration.zero;
|
countdownCode: event.countdownCode,
|
||||||
} else if (isInching) {
|
mode: ScheduleModes.countdown,
|
||||||
isInchingActive = Duration(
|
deviceId: event.deviceId,
|
||||||
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: countdownRemaining ?? Duration.zero,
|
|
||||||
));
|
|
||||||
} else {
|
} else {
|
||||||
emit(ScheduleLoaded(
|
_countdownTimer?.cancel();
|
||||||
schedules: const [],
|
|
||||||
selectedTime: null,
|
|
||||||
selectedDays: List.filled(7, false),
|
|
||||||
functionOn: false,
|
|
||||||
isEditing: false,
|
|
||||||
deviceId: deviceId,
|
|
||||||
scheduleMode: scheduleMode,
|
|
||||||
countdownHours: deviceStatus.countdownHours,
|
|
||||||
countdownMinutes: deviceStatus.countdownMinutes,
|
|
||||||
inchingHours: deviceStatus.inchingHours,
|
|
||||||
inchingMinutes: deviceStatus.inchingMinutes,
|
|
||||||
isCountdownActive: isCountdownActive,
|
|
||||||
isInchingActive: isInchingActive,
|
|
||||||
countdownRemaining: countdownRemaining ?? Duration.zero,
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (isCountdownActive && countdownRemaining != null) {
|
|
||||||
// _startCountdownTimer(emit, countdownRemaining);
|
|
||||||
// }
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
emit(ScheduleError('Failed to fetch device status: $e'));
|
emit(ScheduleError('Failed to fetch device status: $e'));
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,7 @@ class ScheduleEditEvent extends ScheduleEvent {
|
|||||||
final String time;
|
final String time;
|
||||||
final List<String> selectedDays;
|
final List<String> selectedDays;
|
||||||
final bool functionOn;
|
final bool functionOn;
|
||||||
|
final String deviceType;
|
||||||
|
|
||||||
const ScheduleEditEvent({
|
const ScheduleEditEvent({
|
||||||
required this.scheduleId,
|
required this.scheduleId,
|
||||||
@ -98,6 +99,7 @@ class ScheduleEditEvent extends ScheduleEvent {
|
|||||||
required this.time,
|
required this.time,
|
||||||
required this.selectedDays,
|
required this.selectedDays,
|
||||||
required this.functionOn,
|
required this.functionOn,
|
||||||
|
required this.deviceType,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -107,6 +109,7 @@ class ScheduleEditEvent extends ScheduleEvent {
|
|||||||
time,
|
time,
|
||||||
selectedDays,
|
selectedDays,
|
||||||
functionOn,
|
functionOn,
|
||||||
|
deviceType,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,11 +141,13 @@ class ScheduleUpdateEntryEvent extends ScheduleEvent {
|
|||||||
|
|
||||||
class UpdateScheduleModeEvent extends ScheduleEvent {
|
class UpdateScheduleModeEvent extends ScheduleEvent {
|
||||||
final ScheduleModes scheduleMode;
|
final ScheduleModes scheduleMode;
|
||||||
|
final String countdownCode;
|
||||||
|
|
||||||
const UpdateScheduleModeEvent({required this.scheduleMode});
|
const UpdateScheduleModeEvent(
|
||||||
|
{required this.scheduleMode, required this.countdownCode});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [scheduleMode];
|
List<Object> get props => [scheduleMode, countdownCode!];
|
||||||
}
|
}
|
||||||
|
|
||||||
class UpdateCountdownTimeEvent extends ScheduleEvent {
|
class UpdateCountdownTimeEvent extends ScheduleEvent {
|
||||||
@ -177,28 +182,32 @@ class StartScheduleEvent extends ScheduleEvent {
|
|||||||
final ScheduleModes mode;
|
final ScheduleModes mode;
|
||||||
final int hours;
|
final int hours;
|
||||||
final int minutes;
|
final int minutes;
|
||||||
|
final String countDownCode;
|
||||||
|
|
||||||
const StartScheduleEvent({
|
const StartScheduleEvent({
|
||||||
required this.mode,
|
required this.mode,
|
||||||
required this.hours,
|
required this.hours,
|
||||||
required this.minutes,
|
required this.minutes,
|
||||||
|
required this.countDownCode,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [mode, hours, minutes];
|
List<Object?> get props => [mode, hours, minutes, countDownCode];
|
||||||
}
|
}
|
||||||
|
|
||||||
class StopScheduleEvent extends ScheduleEvent {
|
class StopScheduleEvent extends ScheduleEvent {
|
||||||
final ScheduleModes mode;
|
final ScheduleModes mode;
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
|
final String countdownCode;
|
||||||
|
|
||||||
const StopScheduleEvent({
|
const StopScheduleEvent({
|
||||||
required this.mode,
|
required this.mode,
|
||||||
required this.deviceId,
|
required this.deviceId,
|
||||||
|
required this.countdownCode,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [mode, deviceId];
|
List<Object?> get props => [mode, deviceId, countdownCode];
|
||||||
}
|
}
|
||||||
|
|
||||||
class ScheduleDecrementCountdownEvent extends ScheduleEvent {
|
class ScheduleDecrementCountdownEvent extends ScheduleEvent {
|
||||||
@ -210,11 +219,13 @@ class ScheduleDecrementCountdownEvent extends ScheduleEvent {
|
|||||||
|
|
||||||
class ScheduleFetchStatusEvent extends ScheduleEvent {
|
class ScheduleFetchStatusEvent extends ScheduleEvent {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
|
final String countdownCode;
|
||||||
|
|
||||||
const ScheduleFetchStatusEvent(this.deviceId);
|
const ScheduleFetchStatusEvent(
|
||||||
|
{required this.deviceId, required this.countdownCode});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object> get props => [deviceId];
|
List<Object> get props => [deviceId, countdownCode];
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeleteScheduleEvent extends ScheduleEvent {
|
class DeleteScheduleEvent extends ScheduleEvent {
|
||||||
|
@ -29,7 +29,7 @@ class ScheduleLoaded extends ScheduleState {
|
|||||||
final int inchingSeconds;
|
final int inchingSeconds;
|
||||||
final bool isInchingActive;
|
final bool isInchingActive;
|
||||||
final ScheduleModes scheduleMode;
|
final ScheduleModes scheduleMode;
|
||||||
final Duration? countdownRemaining;
|
final Duration countdownRemaining;
|
||||||
final int? countdownSeconds;
|
final int? countdownSeconds;
|
||||||
|
|
||||||
const ScheduleLoaded({
|
const ScheduleLoaded({
|
||||||
@ -48,7 +48,7 @@ class ScheduleLoaded extends ScheduleState {
|
|||||||
this.inchingMinutes = 0,
|
this.inchingMinutes = 0,
|
||||||
this.isInchingActive = false,
|
this.isInchingActive = false,
|
||||||
this.scheduleMode = ScheduleModes.countdown,
|
this.scheduleMode = ScheduleModes.countdown,
|
||||||
this.countdownRemaining,
|
this.countdownRemaining = Duration.zero,
|
||||||
});
|
});
|
||||||
|
|
||||||
ScheduleLoaded copyWith({
|
ScheduleLoaded copyWith({
|
||||||
|
@ -11,6 +11,7 @@ class CountdownModeButtons extends StatelessWidget {
|
|||||||
final String deviceId;
|
final String deviceId;
|
||||||
final int hours;
|
final int hours;
|
||||||
final int minutes;
|
final int minutes;
|
||||||
|
final String countDownCode;
|
||||||
|
|
||||||
const CountdownModeButtons({
|
const CountdownModeButtons({
|
||||||
super.key,
|
super.key,
|
||||||
@ -18,6 +19,7 @@ class CountdownModeButtons extends StatelessWidget {
|
|||||||
required this.deviceId,
|
required this.deviceId,
|
||||||
required this.hours,
|
required this.hours,
|
||||||
required this.minutes,
|
required this.minutes,
|
||||||
|
required this.countDownCode,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -43,6 +45,7 @@ class CountdownModeButtons extends StatelessWidget {
|
|||||||
StopScheduleEvent(
|
StopScheduleEvent(
|
||||||
mode: ScheduleModes.countdown,
|
mode: ScheduleModes.countdown,
|
||||||
deviceId: deviceId,
|
deviceId: deviceId,
|
||||||
|
countdownCode: countDownCode,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -54,10 +57,10 @@ class CountdownModeButtons extends StatelessWidget {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<ScheduleBloc>().add(
|
context.read<ScheduleBloc>().add(
|
||||||
StartScheduleEvent(
|
StartScheduleEvent(
|
||||||
mode: ScheduleModes.countdown,
|
mode: ScheduleModes.countdown,
|
||||||
hours: hours,
|
hours: hours,
|
||||||
minutes: minutes,
|
minutes: minutes,
|
||||||
),
|
countDownCode: countDownCode),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
backgroundColor: ColorsManager.primaryColor,
|
backgroundColor: ColorsManager.primaryColor,
|
||||||
|
@ -75,23 +75,33 @@ class _CountdownInchingViewState extends State<CountdownInchingView> {
|
|||||||
final isCountDown = state.scheduleMode == ScheduleModes.countdown;
|
final isCountDown = state.scheduleMode == ScheduleModes.countdown;
|
||||||
final isActive =
|
final isActive =
|
||||||
isCountDown ? state.isCountdownActive : state.isInchingActive;
|
isCountDown ? state.isCountdownActive : state.isInchingActive;
|
||||||
final displayHours = isActive && state.countdownRemaining != null
|
|
||||||
? state.countdownRemaining!.inHours
|
|
||||||
: (isCountDown ? state.countdownHours : state.inchingHours);
|
|
||||||
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);
|
|
||||||
|
|
||||||
_updateControllers(displayHours, displayMinutes, displaySeconds!);
|
final displayHours =
|
||||||
|
isActive && state.countdownRemaining != Duration.zero
|
||||||
|
? state.countdownRemaining.inHours
|
||||||
|
: (isCountDown ? state.countdownHours : state.inchingHours);
|
||||||
|
|
||||||
if (displayHours == 0 && displayMinutes == 0 && displaySeconds == 0) {
|
final displayMinutes =
|
||||||
|
isActive && state.countdownRemaining != Duration.zero
|
||||||
|
? state.countdownRemaining.inMinutes.remainder(60)
|
||||||
|
: (isCountDown ? state.countdownMinutes : state.inchingMinutes);
|
||||||
|
|
||||||
|
final displaySeconds =
|
||||||
|
isActive && state.countdownRemaining != Duration.zero
|
||||||
|
? state.countdownRemaining.inSeconds.remainder(60)
|
||||||
|
: (isCountDown ? (state.countdownSeconds ?? 0) : 0);
|
||||||
|
|
||||||
|
_updateControllers(displayHours, displayMinutes, displaySeconds);
|
||||||
|
|
||||||
|
if (isActive &&
|
||||||
|
displayHours == 0 &&
|
||||||
|
displayMinutes == 0 &&
|
||||||
|
displaySeconds == 0) {
|
||||||
context.read<ScheduleBloc>().add(
|
context.read<ScheduleBloc>().add(
|
||||||
StopScheduleEvent(
|
StopScheduleEvent(
|
||||||
mode: ScheduleModes.countdown,
|
mode: ScheduleModes.countdown,
|
||||||
deviceId: widget.deviceId,
|
deviceId: widget.deviceId,
|
||||||
|
countdownCode: '',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,9 @@ class InchingModeButtons extends StatelessWidget {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.read<ScheduleBloc>().add(
|
context.read<ScheduleBloc>().add(
|
||||||
StopScheduleEvent(
|
StopScheduleEvent(
|
||||||
deviceId: deviceId, mode: ScheduleModes.inching),
|
deviceId: deviceId,
|
||||||
|
mode: ScheduleModes.inching,
|
||||||
|
countdownCode: ''),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: Colors.red,
|
||||||
|
@ -18,11 +18,15 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.deviceUuid,
|
required this.deviceUuid,
|
||||||
required this.category,
|
required this.category,
|
||||||
|
required this.countdownCode,
|
||||||
this.code,
|
this.code,
|
||||||
|
required this.deviceType,
|
||||||
});
|
});
|
||||||
final String deviceUuid;
|
final String deviceUuid;
|
||||||
final String category;
|
final String category;
|
||||||
final String? code;
|
final String? code;
|
||||||
|
final String? countdownCode;
|
||||||
|
final String deviceType;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -31,7 +35,8 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
deviceId: deviceUuid,
|
deviceId: deviceUuid,
|
||||||
)
|
)
|
||||||
..add(ScheduleGetEvent(category: category))
|
..add(ScheduleGetEvent(category: category))
|
||||||
..add(ScheduleFetchStatusEvent(deviceUuid)),
|
..add(ScheduleFetchStatusEvent(
|
||||||
|
deviceId: deviceUuid, countdownCode: countdownCode ?? '')),
|
||||||
child: Dialog(
|
child: Dialog(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
insetPadding: const EdgeInsets.all(20),
|
insetPadding: const EdgeInsets.all(20),
|
||||||
@ -52,28 +57,32 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
const ScheduleHeader(),
|
const ScheduleHeader(),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
ScheduleModeSelector(
|
if (deviceType == 'CUR_2')
|
||||||
currentMode: state.scheduleMode,
|
const SizedBox()
|
||||||
),
|
else
|
||||||
|
ScheduleModeSelector(
|
||||||
|
countdownCode: countdownCode ?? '',
|
||||||
|
currentMode: state.scheduleMode,
|
||||||
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
if (state.scheduleMode == ScheduleModes.schedule)
|
if (state.scheduleMode == ScheduleModes.schedule)
|
||||||
ScheduleManagementUI(
|
ScheduleManagementUI(
|
||||||
|
deviceType: deviceType,
|
||||||
category: category,
|
category: category,
|
||||||
deviceUuid: deviceUuid,
|
deviceUuid: deviceUuid,
|
||||||
onAddSchedule: () async {
|
onAddSchedule: () async {
|
||||||
final entry = await ScheduleDialogHelper
|
final entry = await ScheduleDialogHelper
|
||||||
.showAddScheduleDialog(
|
.showAddScheduleDialog(context,
|
||||||
context,
|
schedule: ScheduleEntry(
|
||||||
schedule: ScheduleEntry(
|
category: category,
|
||||||
category: category,
|
time: '',
|
||||||
time: '',
|
function: Status(
|
||||||
function: Status(
|
code: code.toString(), value: null),
|
||||||
code: code.toString(), value: null),
|
days: [],
|
||||||
days: [],
|
),
|
||||||
),
|
isEdit: false,
|
||||||
isEdit: false,
|
code: code,
|
||||||
code: code,
|
deviceType: deviceType);
|
||||||
);
|
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
context.read<ScheduleBloc>().add(
|
context.read<ScheduleBloc>().add(
|
||||||
ScheduleAddEvent(
|
ScheduleAddEvent(
|
||||||
@ -87,14 +96,16 @@ class BuildScheduleView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
if (state.scheduleMode == ScheduleModes.countdown ||
|
if (deviceType != 'CUR_2')
|
||||||
state.scheduleMode == ScheduleModes.inching)
|
if (state.scheduleMode == ScheduleModes.countdown ||
|
||||||
CountdownInchingView(
|
state.scheduleMode == ScheduleModes.inching)
|
||||||
deviceId: deviceUuid,
|
CountdownInchingView(
|
||||||
),
|
deviceId: deviceUuid,
|
||||||
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
if (state.scheduleMode == ScheduleModes.countdown)
|
if (state.scheduleMode == ScheduleModes.countdown)
|
||||||
CountdownModeButtons(
|
CountdownModeButtons(
|
||||||
|
countDownCode: countdownCode ?? '',
|
||||||
isActive: state.isCountdownActive,
|
isActive: state.isCountdownActive,
|
||||||
deviceId: deviceUuid,
|
deviceId: deviceUuid,
|
||||||
hours: state.countdownHours,
|
hours: state.countdownHours,
|
||||||
|
@ -5,14 +5,16 @@ import 'package:syncrow_web/utils/color_manager.dart';
|
|||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
|
|
||||||
class ScheduleManagementUI extends StatelessWidget {
|
class ScheduleManagementUI extends StatelessWidget {
|
||||||
final String deviceUuid;
|
final String deviceUuid;
|
||||||
final VoidCallback onAddSchedule;
|
final VoidCallback onAddSchedule;
|
||||||
final String category;
|
final String category;
|
||||||
|
final String deviceType;
|
||||||
|
|
||||||
const ScheduleManagementUI({
|
const ScheduleManagementUI({
|
||||||
super.key,
|
super.key,
|
||||||
required this.deviceUuid,
|
required this.deviceUuid,
|
||||||
required this.onAddSchedule,
|
required this.onAddSchedule,
|
||||||
|
required this.deviceType,
|
||||||
this.category = 'switch_1',
|
this.category = 'switch_1',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -44,7 +46,11 @@ class ScheduleManagementUI extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
ScheduleTableWidget(deviceUuid: deviceUuid, category: category),
|
ScheduleTableWidget(
|
||||||
|
deviceUuid: deviceUuid,
|
||||||
|
category: category,
|
||||||
|
deviceType: deviceType,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -7,10 +7,12 @@ import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
|||||||
|
|
||||||
class ScheduleModeSelector extends StatelessWidget {
|
class ScheduleModeSelector extends StatelessWidget {
|
||||||
final ScheduleModes currentMode;
|
final ScheduleModes currentMode;
|
||||||
|
final String countdownCode;
|
||||||
|
|
||||||
const ScheduleModeSelector({
|
const ScheduleModeSelector({
|
||||||
super.key,
|
super.key,
|
||||||
required this.currentMode,
|
required this.currentMode,
|
||||||
|
required this.countdownCode,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -71,7 +73,8 @@ class ScheduleModeSelector extends StatelessWidget {
|
|||||||
onChanged: (ScheduleModes? value) {
|
onChanged: (ScheduleModes? value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
context.read<ScheduleBloc>().add(
|
context.read<ScheduleBloc>().add(
|
||||||
UpdateScheduleModeEvent(scheduleMode: value),
|
UpdateScheduleModeEvent(
|
||||||
|
scheduleMode: value, countdownCode: countdownCode),
|
||||||
);
|
);
|
||||||
if (value == ScheduleModes.schedule) {
|
if (value == ScheduleModes.schedule) {
|
||||||
context.read<ScheduleBloc>().add(
|
context.read<ScheduleBloc>().add(
|
||||||
|
@ -12,11 +12,13 @@ import 'package:syncrow_web/utils/format_date_time.dart';
|
|||||||
class ScheduleTableWidget extends StatelessWidget {
|
class ScheduleTableWidget extends StatelessWidget {
|
||||||
final String deviceUuid;
|
final String deviceUuid;
|
||||||
final String category;
|
final String category;
|
||||||
|
final String deviceType;
|
||||||
|
|
||||||
const ScheduleTableWidget({
|
const ScheduleTableWidget({
|
||||||
super.key,
|
super.key,
|
||||||
required this.deviceUuid,
|
required this.deviceUuid,
|
||||||
this.category = 'switch_1',
|
this.category = 'switch_1',
|
||||||
|
required this.deviceType,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -25,13 +27,14 @@ class ScheduleTableWidget extends StatelessWidget {
|
|||||||
create: (_) => ScheduleBloc(
|
create: (_) => ScheduleBloc(
|
||||||
deviceId: deviceUuid,
|
deviceId: deviceUuid,
|
||||||
)..add(ScheduleGetEvent(category: category)),
|
)..add(ScheduleGetEvent(category: category)),
|
||||||
child: _ScheduleTableView(),
|
child: _ScheduleTableView(deviceType),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ScheduleTableView extends StatelessWidget {
|
class _ScheduleTableView extends StatelessWidget {
|
||||||
const _ScheduleTableView();
|
final String deviceType;
|
||||||
|
const _ScheduleTableView(this.deviceType);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -81,7 +84,7 @@ class _ScheduleTableView extends StatelessWidget {
|
|||||||
bottomLeft: Radius.circular(20),
|
bottomLeft: Radius.circular(20),
|
||||||
bottomRight: Radius.circular(20)),
|
bottomRight: Radius.circular(20)),
|
||||||
),
|
),
|
||||||
child: _buildTableBody(state.schedules, context));
|
child: _buildTableBody(state.schedules, context, deviceType));
|
||||||
}
|
}
|
||||||
if (state is ScheduleError) {
|
if (state is ScheduleError) {
|
||||||
return Center(child: Text(state.error));
|
return Center(child: Text(state.error));
|
||||||
@ -123,7 +126,8 @@ class _ScheduleTableView extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildTableBody(List<ScheduleModel> schedules, BuildContext context) {
|
Widget _buildTableBody(
|
||||||
|
List<ScheduleModel> schedules, BuildContext context, String deviceType) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: 200,
|
height: 200,
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
@ -132,7 +136,8 @@ class _ScheduleTableView extends StatelessWidget {
|
|||||||
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
|
||||||
children: [
|
children: [
|
||||||
for (int i = 0; i < schedules.length; i++)
|
for (int i = 0; i < schedules.length; i++)
|
||||||
_buildScheduleRow(schedules[i], i, context),
|
_buildScheduleRow(schedules[i], i, context,
|
||||||
|
deviceType: deviceType),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -155,25 +160,19 @@ class _ScheduleTableView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TableRow _buildScheduleRow(
|
TableRow _buildScheduleRow(
|
||||||
ScheduleModel schedule, int index, BuildContext context) {
|
ScheduleModel schedule, int index, BuildContext context,
|
||||||
|
{required String deviceType}) {
|
||||||
return TableRow(
|
return TableRow(
|
||||||
children: [
|
children: [
|
||||||
Center(
|
Center(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
onTap: () {
|
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(
|
context.read<ScheduleBloc>().add(
|
||||||
ScheduleUpdateEntryEvent(
|
ScheduleUpdateEntryEvent(
|
||||||
category: schedule.category,
|
category: schedule.category,
|
||||||
scheduleId: schedule.scheduleId,
|
scheduleId: schedule.scheduleId,
|
||||||
functionOn: temp,
|
functionOn: schedule.function.value,
|
||||||
// schedule.function.value,
|
|
||||||
enable: !schedule.enable,
|
enable: !schedule.enable,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -195,10 +194,11 @@ class _ScheduleTableView extends StatelessWidget {
|
|||||||
child: Text(_getSelectedDays(
|
child: Text(_getSelectedDays(
|
||||||
ScheduleModel.parseSelectedDays(schedule.days)))),
|
ScheduleModel.parseSelectedDays(schedule.days)))),
|
||||||
Center(child: Text(formatIsoStringToTime(schedule.time, context))),
|
Center(child: Text(formatIsoStringToTime(schedule.time, context))),
|
||||||
schedule.category == 'CUR_2'
|
if (deviceType == 'CUR_2')
|
||||||
? Center(
|
Center(
|
||||||
child: Text(schedule.function.value == true ? 'open' : 'close'))
|
child: Text(schedule.function.value == true ? 'open' : 'close'))
|
||||||
: Center(child: Text(schedule.function.value ? 'On' : 'Off')),
|
else
|
||||||
|
Center(child: Text(schedule.function.value ? 'On' : 'Off')),
|
||||||
Center(
|
Center(
|
||||||
child: Wrap(
|
child: Wrap(
|
||||||
runAlignment: WrapAlignment.center,
|
runAlignment: WrapAlignment.center,
|
||||||
@ -206,18 +206,27 @@ class _ScheduleTableView extends StatelessWidget {
|
|||||||
TextButton(
|
TextButton(
|
||||||
style: TextButton.styleFrom(padding: EdgeInsets.zero),
|
style: TextButton.styleFrom(padding: EdgeInsets.zero),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ScheduleDialogHelper.showAddScheduleDialog(
|
ScheduleDialogHelper.showAddScheduleDialog(context,
|
||||||
context,
|
schedule: ScheduleEntry.fromScheduleModel(schedule),
|
||||||
schedule: ScheduleEntry.fromScheduleModel(schedule),
|
isEdit: true,
|
||||||
isEdit: true,
|
deviceType: deviceType)
|
||||||
).then((updatedSchedule) {
|
.then((updatedSchedule) {
|
||||||
if (updatedSchedule != null) {
|
if (updatedSchedule != null) {
|
||||||
|
bool temp;
|
||||||
|
if (deviceType == 'CUR_2') {
|
||||||
|
updatedSchedule.function.value == 'open'
|
||||||
|
? temp = true
|
||||||
|
: temp = false;
|
||||||
|
} else {
|
||||||
|
temp = updatedSchedule.function.value;
|
||||||
|
}
|
||||||
context.read<ScheduleBloc>().add(
|
context.read<ScheduleBloc>().add(
|
||||||
ScheduleEditEvent(
|
ScheduleEditEvent(
|
||||||
|
deviceType: deviceType,
|
||||||
scheduleId: schedule.scheduleId,
|
scheduleId: schedule.scheduleId,
|
||||||
category: schedule.category,
|
category: schedule.category,
|
||||||
time: updatedSchedule.time,
|
time: updatedSchedule.time,
|
||||||
functionOn: updatedSchedule.function.value,
|
functionOn: temp,
|
||||||
selectedDays: updatedSchedule.days),
|
selectedDays: updatedSchedule.days),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ class ThreeGangGlassSwitchBloc
|
|||||||
emit(ThreeGangGlassSwitchLoading());
|
emit(ThreeGangGlassSwitchLoading());
|
||||||
try {
|
try {
|
||||||
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
_listenToChanges(event.deviceId, emit);
|
_listenToChanges(event.deviceId);
|
||||||
deviceStatus =
|
deviceStatus =
|
||||||
ThreeGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
ThreeGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||||
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
emit(ThreeGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
@ -50,42 +50,28 @@ class ThreeGangGlassSwitchBloc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _listenToChanges(
|
StreamSubscription<DatabaseEvent>? _deviceStatusSubscription;
|
||||||
String deviceId,
|
|
||||||
Emitter<ThreeGangGlassSwitchState> emit,
|
void _listenToChanges(String deviceId) {
|
||||||
) {
|
|
||||||
try {
|
try {
|
||||||
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
final stream = ref.onValue;
|
_deviceStatusSubscription = ref.onValue.listen((DatabaseEvent event) async {
|
||||||
|
if (event.snapshot.value == null) return;
|
||||||
|
|
||||||
stream.listen((DatabaseEvent event) {
|
final usersMap = event.snapshot.value! as Map<dynamic, dynamic>;
|
||||||
final data = event.snapshot.value as Map<dynamic, dynamic>?;
|
|
||||||
if (data == null) return;
|
|
||||||
|
|
||||||
final statusList = <Status>[];
|
final statusList = <Status>[];
|
||||||
if (data['status'] != null) {
|
|
||||||
for (var element in data['status']) {
|
usersMap['status'].forEach((element) {
|
||||||
statusList.add(
|
statusList.add(Status(code: element['code'], value: element['value']));
|
||||||
Status(
|
});
|
||||||
code: element['code'].toString(),
|
|
||||||
value: element['value'].toString(),
|
deviceStatus =
|
||||||
),
|
ThreeGangGlassStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||||
);
|
|
||||||
}
|
add(StatusUpdated(deviceStatus));
|
||||||
}
|
|
||||||
if (statusList.isNotEmpty) {
|
|
||||||
final newStatus = ThreeGangGlassStatusModel.fromJson(deviceId, statusList);
|
|
||||||
if (newStatus != deviceStatus) {
|
|
||||||
deviceStatus = newStatus;
|
|
||||||
if (!isClosed) {
|
|
||||||
add(StatusUpdated(deviceStatus));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (_) {}
|
||||||
emit(ThreeGangGlassSwitchError('Failed to listen to changes: $e'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onStatusUpdated(
|
void _onStatusUpdated(
|
||||||
@ -184,4 +170,10 @@ class ThreeGangGlassSwitchBloc
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() {
|
||||||
|
_deviceStatusSubscription?.cancel();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,8 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
|
countdownCode: 'countdown_1',
|
||||||
|
deviceType: '3GT',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
@ -127,6 +129,8 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
category: 'switch_2',
|
category: 'switch_2',
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
|
countdownCode: 'countdown_2',
|
||||||
|
deviceType: '3GT',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
@ -143,6 +147,8 @@ class ThreeGangGlassSwitchControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
category: 'switch_3',
|
category: 'switch_3',
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
|
countdownCode: 'countdown_3',
|
||||||
|
deviceType: '3GT',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -102,6 +102,8 @@ class LivingRoomDeviceControlsView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
|
countdownCode: 'countdown_1',
|
||||||
|
deviceType: '3G',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
@ -118,6 +120,8 @@ class LivingRoomDeviceControlsView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'switch_2',
|
category: 'switch_2',
|
||||||
|
countdownCode: 'countdown_2',
|
||||||
|
deviceType: '3G',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
@ -134,6 +138,8 @@ class LivingRoomDeviceControlsView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'switch_3',
|
category: 'switch_3',
|
||||||
|
countdownCode: 'countdown_3',
|
||||||
|
deviceType: '3G',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -1,173 +1,177 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:firebase_database/firebase_database.dart';
|
import 'package:firebase_database/firebase_database.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/device_status.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
import 'package:syncrow_web/pages/device_managment/all_devices/models/factory_reset_model.dart';
|
||||||
import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/models/two_gang_glass_status_model.dart';
|
import 'package:syncrow_web/pages/device_managment/two_g_glass_switch/models/two_gang_glass_status_model.dart';
|
||||||
import 'package:syncrow_web/services/batch_control_devices_service.dart';
|
import 'package:syncrow_web/services/batch_control_devices_service.dart';
|
||||||
import 'package:syncrow_web/services/control_device_service.dart';
|
import 'package:syncrow_web/services/control_device_service.dart';
|
||||||
import 'package:syncrow_web/services/devices_mang_api.dart';
|
import 'package:syncrow_web/services/devices_mang_api.dart';
|
||||||
|
|
||||||
part 'two_gang_glass_switch_event.dart';
|
part 'two_gang_glass_switch_event.dart';
|
||||||
part 'two_gang_glass_switch_state.dart';
|
part 'two_gang_glass_switch_state.dart';
|
||||||
|
|
||||||
class TwoGangGlassSwitchBloc
|
class TwoGangGlassSwitchBloc
|
||||||
extends Bloc<TwoGangGlassSwitchEvent, TwoGangGlassSwitchState> {
|
extends Bloc<TwoGangGlassSwitchEvent, TwoGangGlassSwitchState> {
|
||||||
final String deviceId;
|
final String deviceId;
|
||||||
final ControlDeviceService controlDeviceService;
|
final ControlDeviceService controlDeviceService;
|
||||||
final BatchControlDevicesService batchControlDevicesService;
|
final BatchControlDevicesService batchControlDevicesService;
|
||||||
|
|
||||||
late TwoGangGlassStatusModel deviceStatus;
|
late TwoGangGlassStatusModel deviceStatus;
|
||||||
|
|
||||||
TwoGangGlassSwitchBloc({
|
TwoGangGlassSwitchBloc({
|
||||||
required this.deviceId,
|
required this.deviceId,
|
||||||
required this.controlDeviceService,
|
required this.controlDeviceService,
|
||||||
required this.batchControlDevicesService,
|
required this.batchControlDevicesService,
|
||||||
}) : super(TwoGangGlassSwitchInitial()) {
|
}) : super(TwoGangGlassSwitchInitial()) {
|
||||||
on<TwoGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
on<TwoGangGlassSwitchFetchDeviceEvent>(_onFetchDeviceStatus);
|
||||||
on<TwoGangGlassSwitchControl>(_onControl);
|
on<TwoGangGlassSwitchControl>(_onControl);
|
||||||
on<TwoGangGlassSwitchBatchControl>(_onBatchControl);
|
on<TwoGangGlassSwitchBatchControl>(_onBatchControl);
|
||||||
on<TwoGangGlassSwitchFetchBatchStatusEvent>(_onFetchBatchStatus);
|
on<TwoGangGlassSwitchFetchBatchStatusEvent>(_onFetchBatchStatus);
|
||||||
on<TwoGangGlassFactoryReset>(_onFactoryReset);
|
on<TwoGangGlassFactoryReset>(_onFactoryReset);
|
||||||
on<StatusUpdated>(_onStatusUpdated);
|
on<StatusUpdated>(_onStatusUpdated);
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onFetchDeviceStatus(
|
|
||||||
TwoGangGlassSwitchFetchDeviceEvent event,
|
|
||||||
Emitter<TwoGangGlassSwitchState> emit,
|
|
||||||
) async {
|
|
||||||
emit(TwoGangGlassSwitchLoading());
|
|
||||||
try {
|
|
||||||
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
|
||||||
deviceStatus = TwoGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
|
||||||
_listenToChanges(event.deviceId);
|
|
||||||
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
|
||||||
} catch (e) {
|
|
||||||
emit(TwoGangGlassSwitchError(e.toString()));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void _listenToChanges(String deviceId) {
|
Future<void> _onFetchDeviceStatus(
|
||||||
try {
|
TwoGangGlassSwitchFetchDeviceEvent event,
|
||||||
final ref = FirebaseDatabase.instance.ref(
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
'device-status/$deviceId',
|
) async {
|
||||||
);
|
emit(TwoGangGlassSwitchLoading());
|
||||||
|
try {
|
||||||
ref.onValue.listen((event) {
|
final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
|
||||||
final eventsMap = event.snapshot.value as Map<dynamic, dynamic>;
|
deviceStatus = TwoGangGlassStatusModel.fromJson(event.deviceId, status.status);
|
||||||
|
_listenToChanges(event.deviceId);
|
||||||
List<Status> statusList = [];
|
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
eventsMap['status'].forEach((element) {
|
} catch (e) {
|
||||||
statusList.add(Status(code: element['code'], value: element['value']));
|
emit(TwoGangGlassSwitchError(e.toString()));
|
||||||
});
|
|
||||||
|
|
||||||
deviceStatus = TwoGangGlassStatusModel.fromJson(deviceId, statusList);
|
|
||||||
add(StatusUpdated(deviceStatus));
|
|
||||||
});
|
|
||||||
} catch (_) {
|
|
||||||
log(
|
|
||||||
'Error listening to changes',
|
|
||||||
name: 'TwoGangGlassSwitchBloc._listenToChanges',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onControl(
|
|
||||||
TwoGangGlassSwitchControl event,
|
|
||||||
Emitter<TwoGangGlassSwitchState> emit,
|
|
||||||
) async {
|
|
||||||
emit(TwoGangGlassSwitchLoading());
|
|
||||||
_updateLocalValue(event.code, event.value);
|
|
||||||
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
|
||||||
|
|
||||||
try {
|
|
||||||
await controlDeviceService.controlDevice(
|
|
||||||
deviceUuid: event.deviceId,
|
|
||||||
status: Status(code: event.code, value: event.value),
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
_updateLocalValue(event.code, !event.value);
|
|
||||||
emit(TwoGangGlassSwitchError(e.toString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onBatchControl(
|
|
||||||
TwoGangGlassSwitchBatchControl event,
|
|
||||||
Emitter<TwoGangGlassSwitchState> emit,
|
|
||||||
) async {
|
|
||||||
emit(TwoGangGlassSwitchLoading());
|
|
||||||
_updateLocalValue(event.code, event.value);
|
|
||||||
emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
|
||||||
|
|
||||||
try {
|
|
||||||
await batchControlDevicesService.batchControlDevices(
|
|
||||||
uuids: event.deviceIds,
|
|
||||||
code: event.code,
|
|
||||||
value: event.value,
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
_updateLocalValue(event.code, !event.value);
|
|
||||||
emit(TwoGangGlassSwitchError(e.toString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onFetchBatchStatus(
|
|
||||||
TwoGangGlassSwitchFetchBatchStatusEvent event,
|
|
||||||
Emitter<TwoGangGlassSwitchState> emit,
|
|
||||||
) async {
|
|
||||||
emit(TwoGangGlassSwitchLoading());
|
|
||||||
try {
|
|
||||||
final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
|
||||||
deviceStatus = TwoGangGlassStatusModel.fromJson(
|
|
||||||
event.deviceIds.first,
|
|
||||||
status.status,
|
|
||||||
);
|
|
||||||
emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
|
||||||
} catch (e) {
|
|
||||||
emit(TwoGangGlassSwitchError(e.toString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _onFactoryReset(
|
|
||||||
TwoGangGlassFactoryReset event,
|
|
||||||
Emitter<TwoGangGlassSwitchState> emit,
|
|
||||||
) async {
|
|
||||||
emit(TwoGangGlassSwitchLoading());
|
|
||||||
try {
|
|
||||||
final response = await DevicesManagementApi().factoryReset(
|
|
||||||
event.factoryReset,
|
|
||||||
event.deviceId,
|
|
||||||
);
|
|
||||||
if (!response) {
|
|
||||||
emit(TwoGangGlassSwitchError('Failed to reset device'));
|
|
||||||
} else {
|
|
||||||
add(TwoGangGlassSwitchFetchDeviceEvent(event.deviceId));
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
emit(TwoGangGlassSwitchError(e.toString()));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void _onStatusUpdated(
|
StreamSubscription<DatabaseEvent>? _deviceStatusSubscription;
|
||||||
StatusUpdated event,
|
|
||||||
Emitter<TwoGangGlassSwitchState> emit,
|
|
||||||
) {
|
|
||||||
deviceStatus = event.deviceStatus;
|
|
||||||
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
|
||||||
}
|
|
||||||
|
|
||||||
void _updateLocalValue(String code, bool value) {
|
void _listenToChanges(String deviceId) {
|
||||||
switch (code) {
|
try {
|
||||||
case 'switch_1':
|
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
|
||||||
deviceStatus = deviceStatus.copyWith(switch1: value);
|
_deviceStatusSubscription = ref.onValue.listen((DatabaseEvent event) async {
|
||||||
break;
|
if (event.snapshot.value == null) return;
|
||||||
case 'switch_2':
|
|
||||||
deviceStatus = deviceStatus.copyWith(switch2: value);
|
final usersMap = event.snapshot.value! as Map<dynamic, dynamic>;
|
||||||
break;
|
|
||||||
|
final statusList = <Status>[];
|
||||||
|
|
||||||
|
usersMap['status'].forEach((element) {
|
||||||
|
statusList.add(Status(code: element['code'], value: element['value']));
|
||||||
|
});
|
||||||
|
|
||||||
|
deviceStatus =
|
||||||
|
TwoGangGlassStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||||
|
|
||||||
|
add(StatusUpdated(deviceStatus));
|
||||||
|
});
|
||||||
|
} catch (_) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _onControl(
|
||||||
|
TwoGangGlassSwitchControl event,
|
||||||
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
|
emit(TwoGangGlassSwitchLoading());
|
||||||
|
_updateLocalValue(event.code, event.value);
|
||||||
|
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await controlDeviceService.controlDevice(
|
||||||
|
deviceUuid: event.deviceId,
|
||||||
|
status: Status(code: event.code, value: event.value),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
_updateLocalValue(event.code, !event.value);
|
||||||
|
emit(TwoGangGlassSwitchError(e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onBatchControl(
|
||||||
|
TwoGangGlassSwitchBatchControl event,
|
||||||
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
|
emit(TwoGangGlassSwitchLoading());
|
||||||
|
_updateLocalValue(event.code, event.value);
|
||||||
|
emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
||||||
|
|
||||||
|
try {
|
||||||
|
await batchControlDevicesService.batchControlDevices(
|
||||||
|
uuids: event.deviceIds,
|
||||||
|
code: event.code,
|
||||||
|
value: event.value,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
_updateLocalValue(event.code, !event.value);
|
||||||
|
emit(TwoGangGlassSwitchError(e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onFetchBatchStatus(
|
||||||
|
TwoGangGlassSwitchFetchBatchStatusEvent event,
|
||||||
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
|
emit(TwoGangGlassSwitchLoading());
|
||||||
|
try {
|
||||||
|
final status = await DevicesManagementApi().getBatchStatus(event.deviceIds);
|
||||||
|
deviceStatus = TwoGangGlassStatusModel.fromJson(
|
||||||
|
event.deviceIds.first,
|
||||||
|
status.status,
|
||||||
|
);
|
||||||
|
emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus));
|
||||||
|
} catch (e) {
|
||||||
|
emit(TwoGangGlassSwitchError(e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _onFactoryReset(
|
||||||
|
TwoGangGlassFactoryReset event,
|
||||||
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
|
) async {
|
||||||
|
emit(TwoGangGlassSwitchLoading());
|
||||||
|
try {
|
||||||
|
final response = await DevicesManagementApi().factoryReset(
|
||||||
|
event.factoryReset,
|
||||||
|
event.deviceId,
|
||||||
|
);
|
||||||
|
if (!response) {
|
||||||
|
emit(TwoGangGlassSwitchError('Failed to reset device'));
|
||||||
|
} else {
|
||||||
|
add(TwoGangGlassSwitchFetchDeviceEvent(event.deviceId));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
emit(TwoGangGlassSwitchError(e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onStatusUpdated(
|
||||||
|
StatusUpdated event,
|
||||||
|
Emitter<TwoGangGlassSwitchState> emit,
|
||||||
|
) {
|
||||||
|
deviceStatus = event.deviceStatus;
|
||||||
|
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateLocalValue(String code, bool value) {
|
||||||
|
switch (code) {
|
||||||
|
case 'switch_1':
|
||||||
|
deviceStatus = deviceStatus.copyWith(switch1: value);
|
||||||
|
break;
|
||||||
|
case 'switch_2':
|
||||||
|
deviceStatus = deviceStatus.copyWith(switch2: value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() {
|
||||||
|
_deviceStatusSubscription?.cancel();
|
||||||
|
return super.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,6 +102,8 @@ class TwoGangGlassSwitchControlView extends StatelessWidget
|
|||||||
builder: (ctx) => BlocProvider.value(
|
builder: (ctx) => BlocProvider.value(
|
||||||
value: BlocProvider.of<TwoGangGlassSwitchBloc>(context),
|
value: BlocProvider.of<TwoGangGlassSwitchBloc>(context),
|
||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
|
deviceType: '2GT',
|
||||||
|
countdownCode: 'countdown_1',
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
),
|
),
|
||||||
@ -118,6 +120,8 @@ class TwoGangGlassSwitchControlView extends StatelessWidget
|
|||||||
builder: (ctx) => BlocProvider.value(
|
builder: (ctx) => BlocProvider.value(
|
||||||
value: BlocProvider.of<TwoGangGlassSwitchBloc>(context),
|
value: BlocProvider.of<TwoGangGlassSwitchBloc>(context),
|
||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
|
deviceType: '2GT',
|
||||||
|
countdownCode: 'countdown_2',
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'switch_2',
|
category: 'switch_2',
|
||||||
),
|
),
|
||||||
|
@ -97,6 +97,8 @@ class TwoGangBatchControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
deviceUuid: deviceIds.first,
|
deviceUuid: deviceIds.first,
|
||||||
|
countdownCode: 'countdown_1',
|
||||||
|
deviceType: '2G',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
@ -114,6 +116,8 @@ class TwoGangBatchControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
category: 'switch_2',
|
category: 'switch_2',
|
||||||
deviceUuid: deviceIds.first,
|
deviceUuid: deviceIds.first,
|
||||||
|
countdownCode: 'countdown_2',
|
||||||
|
deviceType: '2G',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
@ -121,10 +125,7 @@ class TwoGangBatchControlView extends StatelessWidget
|
|||||||
subtitle: 'Scheduling',
|
subtitle: 'Scheduling',
|
||||||
iconPath: Assets.scheduling,
|
iconPath: Assets.scheduling,
|
||||||
),
|
),
|
||||||
// FirmwareUpdateWidget(
|
|
||||||
// deviceId: deviceIds.first,
|
|
||||||
// version: 12,
|
|
||||||
// ),
|
|
||||||
FactoryResetWidget(callFactoryReset: () {
|
FactoryResetWidget(callFactoryReset: () {
|
||||||
context.read<TwoGangSwitchBloc>().add(
|
context.read<TwoGangSwitchBloc>().add(
|
||||||
TwoGangFactoryReset(
|
TwoGangFactoryReset(
|
||||||
|
@ -103,6 +103,8 @@ class TwoGangDeviceControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
|
countdownCode: 'countdown_1',
|
||||||
|
deviceType: '2G',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
@ -125,6 +127,8 @@ class TwoGangDeviceControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceUuid: deviceId,
|
deviceUuid: deviceId,
|
||||||
category: 'switch_2',
|
category: 'switch_2',
|
||||||
|
countdownCode: 'countdown_2',
|
||||||
|
deviceType: '2G',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -18,14 +18,21 @@ class ScheduleDialogHelper {
|
|||||||
ScheduleEntry? schedule,
|
ScheduleEntry? schedule,
|
||||||
bool isEdit = false,
|
bool isEdit = false,
|
||||||
String? code,
|
String? code,
|
||||||
|
required String deviceType,
|
||||||
}) {
|
}) {
|
||||||
|
bool temp;
|
||||||
|
if (deviceType == 'CUR_2') {
|
||||||
|
temp = schedule!.function.value == 'open' ? true : false;
|
||||||
|
} else {
|
||||||
|
temp = schedule!.function.value;
|
||||||
|
}
|
||||||
final initialTime = schedule != null
|
final initialTime = schedule != null
|
||||||
? _convertStringToTimeOfDay(schedule.time)
|
? _convertStringToTimeOfDay(schedule.time)
|
||||||
: TimeOfDay.now();
|
: TimeOfDay.now();
|
||||||
final initialDays = schedule != null
|
final initialDays = schedule != null
|
||||||
? _convertDaysStringToBooleans(schedule.days)
|
? _convertDaysStringToBooleans(schedule.days)
|
||||||
: List.filled(7, false);
|
: List.filled(7, false);
|
||||||
bool? functionOn = schedule?.function.value ?? true;
|
bool? functionOn = temp;
|
||||||
TimeOfDay selectedTime = initialTime;
|
TimeOfDay selectedTime = initialTime;
|
||||||
List<bool> selectedDays = List.of(initialDays);
|
List<bool> selectedDays = List.of(initialDays);
|
||||||
|
|
||||||
@ -97,8 +104,7 @@ class ScheduleDialogHelper {
|
|||||||
setState(() => selectedDays[i] = v);
|
setState(() => selectedDays[i] = v);
|
||||||
}),
|
}),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_buildFunctionSwitch(schedule!.category, ctx, functionOn!,
|
_buildFunctionSwitch(deviceType, ctx, functionOn!, (v) {
|
||||||
(v) {
|
|
||||||
setState(() => functionOn = v);
|
setState(() => functionOn = v);
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@ -114,32 +120,29 @@ class ScheduleDialogHelper {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 100,
|
width: 100,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
dynamic temp;
|
dynamic temp;
|
||||||
if (schedule?.category == 'CUR_2') {
|
if (deviceType == 'CUR_2') {
|
||||||
temp = functionOn! ? 'open' : 'close';
|
temp = functionOn! ? 'open' : 'close';
|
||||||
} else {
|
} else {
|
||||||
temp = functionOn;
|
temp = functionOn;
|
||||||
}
|
}
|
||||||
print(temp);
|
final entry = ScheduleEntry(
|
||||||
final entry = ScheduleEntry(
|
category: schedule?.category ?? 'switch_1',
|
||||||
category: schedule?.category ?? 'switch_1',
|
time: _formatTimeOfDayToISO(selectedTime),
|
||||||
time: _formatTimeOfDayToISO(selectedTime),
|
function: Status(
|
||||||
function: Status(
|
code: code ?? 'switch_1',
|
||||||
code: code ?? 'switch_1',
|
value: temp,
|
||||||
value: temp,
|
),
|
||||||
// functionOn,
|
days: _convertSelectedDaysToStrings(selectedDays),
|
||||||
),
|
scheduleId: schedule.scheduleId,
|
||||||
days: _convertSelectedDaysToStrings(selectedDays),
|
);
|
||||||
scheduleId: schedule?.scheduleId,
|
Navigator.pop(ctx, entry);
|
||||||
);
|
},
|
||||||
Navigator.pop(ctx, entry);
|
child: const Text('Save'),
|
||||||
},
|
)),
|
||||||
child: const Text('Save'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -84,6 +84,8 @@ class WaterHeaterDeviceControlView extends StatelessWidget
|
|||||||
child: BuildScheduleView(
|
child: BuildScheduleView(
|
||||||
deviceUuid: device.uuid ?? '',
|
deviceUuid: device.uuid ?? '',
|
||||||
category: 'switch_1',
|
category: 'switch_1',
|
||||||
|
countdownCode: 'countdown_1',
|
||||||
|
deviceType: 'WH',
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
@ -455,7 +455,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
Future<void> checkEmail(
|
Future<void> checkEmail(
|
||||||
CheckEmailEvent event, Emitter<UsersState> emit) async {
|
CheckEmailEvent event, Emitter<UsersState> emit) async {
|
||||||
emit(UsersLoadingState());
|
emit(UsersLoadingState());
|
||||||
String? res = await UserPermissionApi().checkEmail(
|
String? res = await UserPermissionApi().checkEmail(
|
||||||
emailController.text,
|
emailController.text,
|
||||||
);
|
);
|
||||||
checkEmailValid = res!;
|
checkEmailValid = res!;
|
||||||
|
@ -34,7 +34,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
return Dialog(
|
return Dialog(
|
||||||
child: Container(
|
child: Container(
|
||||||
decoration: const BoxDecoration(
|
decoration: const BoxDecoration(
|
||||||
color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(20))),
|
||||||
width: 900,
|
width: 900,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@ -63,7 +64,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
children: [
|
children: [
|
||||||
_buildStep1Indicator(1, "Basics", _blocRole),
|
_buildStep1Indicator(1, "Basics", _blocRole),
|
||||||
_buildStep2Indicator(2, "Spaces", _blocRole),
|
_buildStep2Indicator(2, "Spaces", _blocRole),
|
||||||
_buildStep3Indicator(3, "Role & Permissions", _blocRole),
|
_buildStep3Indicator(
|
||||||
|
3, "Role & Permissions", _blocRole),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -105,18 +107,32 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
),
|
),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
final isBasicsStep = currentStep == 1;
|
||||||
|
|
||||||
|
if (isBasicsStep) {
|
||||||
|
// Validate the form first
|
||||||
|
final isValid = _blocRole.formKey.currentState
|
||||||
|
?.validate() ??
|
||||||
|
false;
|
||||||
|
|
||||||
|
if (!isValid)
|
||||||
|
return; // Stop if form is not valid
|
||||||
|
}
|
||||||
_blocRole.add(const CheckEmailEvent());
|
_blocRole.add(const CheckEmailEvent());
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
if (currentStep < 3) {
|
if (currentStep < 3) {
|
||||||
currentStep++;
|
currentStep++;
|
||||||
if (currentStep == 2) {
|
if (currentStep == 2) {
|
||||||
_blocRole.add(const CheckStepStatus(isEditUser: false));
|
_blocRole.add(const CheckStepStatus(
|
||||||
|
isEditUser: false));
|
||||||
} else if (currentStep == 3) {
|
} else if (currentStep == 3) {
|
||||||
_blocRole.add(const CheckSpacesStepStatus());
|
_blocRole
|
||||||
|
.add(const CheckSpacesStepStatus());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_blocRole.add(SendInviteUsers(context: context));
|
_blocRole
|
||||||
|
.add(SendInviteUsers(context: context));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -124,8 +140,11 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
currentStep < 3 ? "Next" : "Save",
|
currentStep < 3 ? "Next" : "Save",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: (_blocRole.isCompleteSpaces == false ||
|
color: (_blocRole.isCompleteSpaces == false ||
|
||||||
_blocRole.isCompleteBasics == false ||
|
_blocRole.isCompleteBasics ==
|
||||||
_blocRole.isCompleteRolePermissions == false) &&
|
false ||
|
||||||
|
_blocRole
|
||||||
|
.isCompleteRolePermissions ==
|
||||||
|
false) &&
|
||||||
currentStep == 3
|
currentStep == 3
|
||||||
? ColorsManager.grayColor
|
? ColorsManager.grayColor
|
||||||
: ColorsManager.secondaryColor),
|
: ColorsManager.secondaryColor),
|
||||||
@ -143,7 +162,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
Widget _getFormContent() {
|
Widget _getFormContent() {
|
||||||
switch (currentStep) {
|
switch (currentStep) {
|
||||||
case 1:
|
case 1:
|
||||||
return const BasicsView(
|
return BasicsView(
|
||||||
userId: '',
|
userId: '',
|
||||||
);
|
);
|
||||||
case 2:
|
case 2:
|
||||||
@ -196,8 +215,12 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
color: currentStep == step
|
||||||
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
? ColorsManager.blackColor
|
||||||
|
: ColorsManager.greyColor,
|
||||||
|
fontWeight: currentStep == step
|
||||||
|
? FontWeight.bold
|
||||||
|
: FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -260,8 +283,12 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
color: currentStep == step
|
||||||
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
? ColorsManager.blackColor
|
||||||
|
: ColorsManager.greyColor,
|
||||||
|
fontWeight: currentStep == step
|
||||||
|
? FontWeight.bold
|
||||||
|
: FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -318,8 +345,12 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
label,
|
label,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
|
color: currentStep == step
|
||||||
fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
|
? ColorsManager.blackColor
|
||||||
|
: ColorsManager.greyColor,
|
||||||
|
fontWeight: currentStep == step
|
||||||
|
? FontWeight.bold
|
||||||
|
: FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:intl_phone_field/countries.dart';
|
import 'package:intl_phone_field/countries.dart';
|
||||||
import 'package:intl_phone_field/country_picker_dialog.dart';
|
import 'package:intl_phone_field/country_picker_dialog.dart';
|
||||||
import 'package:intl_phone_field/intl_phone_field.dart';
|
import 'package:intl_phone_field/intl_phone_field.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||||
import 'package:syncrow_web/utils/color_manager.dart';
|
import 'package:syncrow_web/utils/color_manager.dart';
|
||||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
@ -11,7 +14,9 @@ import 'package:syncrow_web/utils/style.dart';
|
|||||||
|
|
||||||
class BasicsView extends StatelessWidget {
|
class BasicsView extends StatelessWidget {
|
||||||
final String? userId;
|
final String? userId;
|
||||||
const BasicsView({super.key, this.userId = ''});
|
Timer? _debounce;
|
||||||
|
|
||||||
|
BasicsView({super.key, this.userId = ''});
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocBuilder<UsersBloc, UsersState>(builder: (context, state) {
|
return BlocBuilder<UsersBloc, UsersState>(builder: (context, state) {
|
||||||
@ -21,6 +26,7 @@ class BasicsView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
return Form(
|
return Form(
|
||||||
key: _blocRole.formKey,
|
key: _blocRole.formKey,
|
||||||
|
autovalidateMode: AutovalidateMode.onUserInteraction,
|
||||||
child: ListView(
|
child: ListView(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
children: [
|
children: [
|
||||||
@ -208,6 +214,14 @@ class BasicsView extends StatelessWidget {
|
|||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: ColorsManager.textGray),
|
color: ColorsManager.textGray),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
onChanged: (value) {
|
||||||
|
if (_debounce?.isActive ?? false) _debounce!.cancel();
|
||||||
|
_debounce = Timer(const Duration(milliseconds: 800), () {
|
||||||
|
_blocRole.add(const CheckEmailEvent());
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
return 'Enter Email Address';
|
return 'Enter Email Address';
|
||||||
|
@ -170,45 +170,45 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onLoadScenes(
|
Future<void> _onLoadScenes(
|
||||||
LoadScenes event, Emitter<RoutineState> emit) async {
|
LoadScenes event, Emitter<RoutineState> emit) async {
|
||||||
emit(state.copyWith(isLoading: true, errorMessage: null));
|
emit(state.copyWith(isLoading: true, errorMessage: null));
|
||||||
List<ScenesModel> scenes = [];
|
List<ScenesModel> scenes = [];
|
||||||
try {
|
try {
|
||||||
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
BuildContext context = NavigationService.navigatorKey.currentContext!;
|
||||||
var createRoutineBloc = context.read<CreateRoutineBloc>();
|
var createRoutineBloc = context.read<CreateRoutineBloc>();
|
||||||
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
final projectUuid = await ProjectManager.getProjectUUID() ?? '';
|
||||||
if (createRoutineBloc.selectedSpaceId == '' &&
|
if (createRoutineBloc.selectedSpaceId == '' &&
|
||||||
createRoutineBloc.selectedCommunityId == '') {
|
createRoutineBloc.selectedCommunityId == '') {
|
||||||
var spaceBloc = context.read<SpaceTreeBloc>();
|
var spaceBloc = context.read<SpaceTreeBloc>();
|
||||||
for (var communityId in spaceBloc.state.selectedCommunities) {
|
for (var communityId in spaceBloc.state.selectedCommunities) {
|
||||||
List<String> spacesList =
|
List<String> spacesList =
|
||||||
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||||
for (var spaceId in spacesList) {
|
for (var spaceId in spacesList) {
|
||||||
scenes.addAll(
|
scenes.addAll(
|
||||||
await SceneApi.getScenes(spaceId, communityId, projectUuid));
|
await SceneApi.getScenes(spaceId, communityId, projectUuid));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
scenes.addAll(await SceneApi.getScenes(
|
|
||||||
createRoutineBloc.selectedSpaceId,
|
|
||||||
createRoutineBloc.selectedCommunityId,
|
|
||||||
projectUuid));
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
emit(state.copyWith(
|
scenes.addAll(await SceneApi.getScenes(
|
||||||
scenes: scenes,
|
createRoutineBloc.selectedSpaceId,
|
||||||
isLoading: false,
|
createRoutineBloc.selectedCommunityId,
|
||||||
));
|
projectUuid));
|
||||||
} catch (e) {
|
|
||||||
emit(state.copyWith(
|
|
||||||
isLoading: false,
|
|
||||||
loadScenesErrorMessage: 'Failed to load scenes',
|
|
||||||
errorMessage: '',
|
|
||||||
loadAutomationErrorMessage: '',
|
|
||||||
scenes: scenes));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit(state.copyWith(
|
||||||
|
scenes: scenes,
|
||||||
|
isLoading: false,
|
||||||
|
));
|
||||||
|
} catch (e) {
|
||||||
|
emit(state.copyWith(
|
||||||
|
isLoading: false,
|
||||||
|
loadScenesErrorMessage: 'Failed to load scenes',
|
||||||
|
errorMessage: '',
|
||||||
|
loadAutomationErrorMessage: '',
|
||||||
|
scenes: scenes));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _onLoadAutomation(
|
Future<void> _onLoadAutomation(
|
||||||
LoadAutomation event, Emitter<RoutineState> emit) async {
|
LoadAutomation event, Emitter<RoutineState> emit) async {
|
||||||
@ -936,12 +936,16 @@ class RoutineBloc extends Bloc<RoutineEvent, RoutineState> {
|
|||||||
for (var communityId in spaceBloc.state.selectedCommunities) {
|
for (var communityId in spaceBloc.state.selectedCommunities) {
|
||||||
List<String> spacesList =
|
List<String> spacesList =
|
||||||
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
spaceBloc.state.selectedCommunityAndSpaces[communityId] ?? [];
|
||||||
devices.addAll(await DevicesManagementApi()
|
for (var spaceId in spacesList) {
|
||||||
.fetchDevices(projectUuid, spacesId: spacesList));
|
devices.addAll(await DevicesManagementApi()
|
||||||
|
.fetchDevices(communityId, spaceId, projectUuid));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
devices.addAll(await DevicesManagementApi().fetchDevices(projectUuid,
|
devices.addAll(await DevicesManagementApi().fetchDevices(
|
||||||
spacesId: [createRoutineBloc.selectedSpaceId]));
|
createRoutineBloc.selectedCommunityId,
|
||||||
|
createRoutineBloc.selectedSpaceId,
|
||||||
|
projectUuid));
|
||||||
}
|
}
|
||||||
|
|
||||||
emit(state.copyWith(isLoading: false, devices: devices));
|
emit(state.copyWith(isLoading: false, devices: devices));
|
||||||
|
@ -58,7 +58,9 @@ class CurtainHelper {
|
|||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
const DialogHeader('AC Functions'),
|
DialogHeader(dialogType == 'THEN'
|
||||||
|
? 'Curtain Functions'
|
||||||
|
: 'Curtain Conditions'),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
@ -58,11 +58,14 @@ class ProductModel {
|
|||||||
'3G': Assets.Gang3SwitchIcon,
|
'3G': Assets.Gang3SwitchIcon,
|
||||||
'3GT': Assets.threeTouchSwitch,
|
'3GT': Assets.threeTouchSwitch,
|
||||||
'CUR': Assets.curtain,
|
'CUR': Assets.curtain,
|
||||||
|
'CUR_2': Assets.curtain,
|
||||||
'GD': Assets.garageDoor,
|
'GD': Assets.garageDoor,
|
||||||
'GW': Assets.SmartGatewayIcon,
|
'GW': Assets.SmartGatewayIcon,
|
||||||
'DL': Assets.DoorLockIcon,
|
'DL': Assets.DoorLockIcon,
|
||||||
'WL': Assets.waterLeakSensor,
|
'WL': Assets.waterLeakSensor,
|
||||||
'WH': Assets.waterHeater,
|
'WH': Assets.waterHeater,
|
||||||
|
'WM': Assets.waterLeakSensor,
|
||||||
|
'SOS': Assets.sos,
|
||||||
'AC': Assets.ac,
|
'AC': Assets.ac,
|
||||||
'CPS': Assets.presenceSensor,
|
'CPS': Assets.presenceSensor,
|
||||||
'PC': Assets.powerClamp,
|
'PC': Assets.powerClamp,
|
||||||
|
@ -2,10 +2,8 @@ import 'package:flutter/cupertino.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:syncrow_web/pages/common/bloc/project_manager.dart';
|
|
||||||
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
import 'package:syncrow_web/pages/common/buttons/default_button.dart';
|
||||||
import 'package:syncrow_web/pages/common/date_time_widget.dart';
|
import 'package:syncrow_web/pages/common/date_time_widget.dart';
|
||||||
import 'package:syncrow_web/pages/common/text_field/custom_web_textfield.dart';
|
|
||||||
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
|
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
|
||||||
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_event.dart';
|
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_event.dart';
|
||||||
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_state.dart';
|
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_state.dart';
|
||||||
@ -23,8 +21,8 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Size size = MediaQuery.of(context).size;
|
final size = MediaQuery.of(context).size;
|
||||||
var text = Theme.of(context)
|
final text = Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodySmall!
|
.bodySmall!
|
||||||
.copyWith(color: Colors.black, fontSize: 13);
|
.copyWith(color: Colors.black, fontSize: 13);
|
||||||
@ -41,8 +39,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
title: 'Sent Successfully',
|
title: 'Sent Successfully',
|
||||||
widgeta: Column(
|
widgeta: Column(
|
||||||
children: [
|
children: [
|
||||||
if (visitorBloc
|
if (visitorBloc.passwordStatus!.failedOperations.isNotEmpty)
|
||||||
.passwordStatus!.failedOperations.isNotEmpty)
|
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
const Text('Failed Devices'),
|
const Text('Failed Devices'),
|
||||||
@ -56,22 +53,19 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
.passwordStatus!.failedOperations.length,
|
.passwordStatus!.failedOperations.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.all(5),
|
margin: const EdgeInsets.all(5),
|
||||||
decoration: containerDecoration,
|
decoration: containerDecoration,
|
||||||
height: 45,
|
height: 45,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(visitorBloc
|
child: Text(visitorBloc.passwordStatus!
|
||||||
.passwordStatus!
|
.failedOperations[index].deviceName)),
|
||||||
.failedOperations[index]
|
|
||||||
.deviceName)),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (visitorBloc
|
if (visitorBloc.passwordStatus!.successOperations.isNotEmpty)
|
||||||
.passwordStatus!.successOperations.isNotEmpty)
|
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
const Text('Success Devices'),
|
const Text('Success Devices'),
|
||||||
@ -85,14 +79,12 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
.passwordStatus!.successOperations.length,
|
.passwordStatus!.successOperations.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.all(5),
|
margin: const EdgeInsets.all(5),
|
||||||
decoration: containerDecoration,
|
decoration: containerDecoration,
|
||||||
height: 45,
|
height: 45,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text(visitorBloc
|
child: Text(visitorBloc.passwordStatus!
|
||||||
.passwordStatus!
|
.successOperations[index].deviceName)),
|
||||||
.successOperations[index]
|
|
||||||
.deviceName)),
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -115,16 +107,14 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
child: BlocBuilder<VisitorPasswordBloc, VisitorPasswordState>(
|
child: BlocBuilder<VisitorPasswordBloc, VisitorPasswordState>(
|
||||||
builder: (BuildContext context, VisitorPasswordState state) {
|
builder: (BuildContext context, VisitorPasswordState state) {
|
||||||
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
|
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
|
||||||
bool isRepeat =
|
final isRepeat =
|
||||||
state is IsRepeatState ? state.repeat : visitorBloc.repeat;
|
state is IsRepeatState ? state.repeat : visitorBloc.repeat;
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
title: Text(
|
title: Text(
|
||||||
'Create visitor password',
|
'Create visitor password',
|
||||||
style: Theme.of(context).textTheme.headlineLarge!.copyWith(
|
style: Theme.of(context).textTheme.headlineLarge!.copyWith(
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400, fontSize: 24, color: Colors.black),
|
||||||
fontSize: 24,
|
|
||||||
color: Colors.black),
|
|
||||||
),
|
),
|
||||||
content: state is LoadingInitialState
|
content: state is LoadingInitialState
|
||||||
? const Center(child: CircularProgressIndicator())
|
? const Center(child: CircularProgressIndicator())
|
||||||
@ -310,14 +300,12 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
visitorBloc.accessTypeSelected ==
|
visitorBloc.accessTypeSelected ==
|
||||||
'Offline Password') {
|
'Offline Password') {
|
||||||
visitorBloc.add(SelectTimeEvent(
|
visitorBloc.add(SelectTimeEvent(
|
||||||
context: context,
|
context: context, isEffective: false));
|
||||||
isEffective: false));
|
|
||||||
} else {
|
} else {
|
||||||
visitorBloc.add(
|
visitorBloc.add(SelectTimeVisitorPassword(
|
||||||
SelectTimeVisitorPassword(
|
context: context,
|
||||||
context: context,
|
isStart: false,
|
||||||
isStart: false,
|
isRepeat: false));
|
||||||
isRepeat: false));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
startTime: () {
|
startTime: () {
|
||||||
@ -326,31 +314,28 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
visitorBloc.accessTypeSelected ==
|
visitorBloc.accessTypeSelected ==
|
||||||
'Offline Password') {
|
'Offline Password') {
|
||||||
visitorBloc.add(SelectTimeEvent(
|
visitorBloc.add(SelectTimeEvent(
|
||||||
context: context,
|
context: context, isEffective: true));
|
||||||
isEffective: true));
|
|
||||||
} else {
|
} else {
|
||||||
visitorBloc.add(
|
visitorBloc.add(SelectTimeVisitorPassword(
|
||||||
SelectTimeVisitorPassword(
|
context: context,
|
||||||
context: context,
|
isStart: true,
|
||||||
isStart: true,
|
isRepeat: false));
|
||||||
isRepeat: false));
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
firstString: (visitorBloc
|
firstString:
|
||||||
.usageFrequencySelected ==
|
(visitorBloc.usageFrequencySelected ==
|
||||||
'Periodic' &&
|
'Periodic' &&
|
||||||
visitorBloc.accessTypeSelected ==
|
visitorBloc.accessTypeSelected ==
|
||||||
'Offline Password')
|
'Offline Password')
|
||||||
? visitorBloc.effectiveTime
|
? visitorBloc.effectiveTime
|
||||||
: visitorBloc.startTimeAccess
|
: visitorBloc.startTimeAccess,
|
||||||
.toString(),
|
|
||||||
secondString: (visitorBloc
|
secondString: (visitorBloc
|
||||||
.usageFrequencySelected ==
|
.usageFrequencySelected ==
|
||||||
'Periodic' &&
|
'Periodic' &&
|
||||||
visitorBloc.accessTypeSelected ==
|
visitorBloc.accessTypeSelected ==
|
||||||
'Offline Password')
|
'Offline Password')
|
||||||
? visitorBloc.expirationTime
|
? visitorBloc.expirationTime
|
||||||
: visitorBloc.endTimeAccess.toString(),
|
: visitorBloc.endTimeAccess,
|
||||||
icon: Assets.calendarIcon),
|
icon: Assets.calendarIcon),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 10,
|
height: 10,
|
||||||
@ -410,8 +395,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
child: CupertinoSwitch(
|
child: CupertinoSwitch(
|
||||||
value: visitorBloc.repeat,
|
value: visitorBloc.repeat,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
visitorBloc
|
visitorBloc.add(ToggleRepeatEvent());
|
||||||
.add(ToggleRepeatEvent());
|
|
||||||
},
|
},
|
||||||
applyTheme: true,
|
applyTheme: true,
|
||||||
),
|
),
|
||||||
@ -442,8 +426,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
).then((listDevice) {
|
).then((listDevice) {
|
||||||
if (listDevice != null) {
|
if (listDevice != null) {
|
||||||
visitorBloc.selectedDevices =
|
visitorBloc.selectedDevices = listDevice;
|
||||||
listDevice;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -455,8 +438,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
.bodySmall!
|
.bodySmall!
|
||||||
.copyWith(
|
.copyWith(
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
color:
|
color: ColorsManager.whiteColors,
|
||||||
ColorsManager.whiteColors,
|
|
||||||
fontSize: 12),
|
fontSize: 12),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -495,37 +477,30 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (visitorBloc.forgetFormKey.currentState!.validate()) {
|
if (visitorBloc.forgetFormKey.currentState!.validate()) {
|
||||||
if (visitorBloc.selectedDevices.isNotEmpty) {
|
if (visitorBloc.selectedDevices.isNotEmpty) {
|
||||||
if (visitorBloc.usageFrequencySelected ==
|
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
|
||||||
'One-Time' &&
|
visitorBloc.accessTypeSelected == 'Offline Password') {
|
||||||
visitorBloc.accessTypeSelected ==
|
|
||||||
'Offline Password') {
|
|
||||||
setPasswordFunction(context, size, visitorBloc);
|
setPasswordFunction(context, size, visitorBloc);
|
||||||
} else if (visitorBloc.usageFrequencySelected ==
|
} else if (visitorBloc.usageFrequencySelected ==
|
||||||
'Periodic' &&
|
'Periodic' &&
|
||||||
visitorBloc.accessTypeSelected ==
|
visitorBloc.accessTypeSelected == 'Offline Password') {
|
||||||
'Offline Password') {
|
|
||||||
if (visitorBloc.expirationTime != 'End Time' &&
|
if (visitorBloc.expirationTime != 'End Time' &&
|
||||||
visitorBloc.effectiveTime != 'Start Time') {
|
visitorBloc.effectiveTime != 'Start Time') {
|
||||||
setPasswordFunction(context, size, visitorBloc);
|
setPasswordFunction(context, size, visitorBloc);
|
||||||
} else {
|
} else {
|
||||||
visitorBloc.stateDialog(
|
visitorBloc.stateDialog(
|
||||||
context: context,
|
context: context,
|
||||||
message:
|
message: 'Please select Access Period to continue',
|
||||||
'Please select Access Period to continue',
|
|
||||||
title: 'Access Period');
|
title: 'Access Period');
|
||||||
}
|
}
|
||||||
} else if (visitorBloc.endTimeAccess.toString() !=
|
} else if (visitorBloc.endTimeAccess != 'End Time' &&
|
||||||
'End Time' &&
|
visitorBloc.startTimeAccess != 'Start Time') {
|
||||||
visitorBloc.startTimeAccess.toString() !=
|
|
||||||
'Start Time') {
|
|
||||||
if (visitorBloc.effectiveTimeTimeStamp != null &&
|
if (visitorBloc.effectiveTimeTimeStamp != null &&
|
||||||
visitorBloc.expirationTimeTimeStamp != null) {
|
visitorBloc.expirationTimeTimeStamp != null) {
|
||||||
if (isRepeat == true) {
|
if (isRepeat == true) {
|
||||||
if (visitorBloc.expirationTime != 'End Time' &&
|
if (visitorBloc.expirationTime != 'End Time' &&
|
||||||
visitorBloc.effectiveTime != 'Start Time' &&
|
visitorBloc.effectiveTime != 'Start Time' &&
|
||||||
visitorBloc.selectedDays.isNotEmpty) {
|
visitorBloc.selectedDays.isNotEmpty) {
|
||||||
setPasswordFunction(
|
setPasswordFunction(context, size, visitorBloc);
|
||||||
context, size, visitorBloc);
|
|
||||||
} else {
|
} else {
|
||||||
visitorBloc.stateDialog(
|
visitorBloc.stateDialog(
|
||||||
context: context,
|
context: context,
|
||||||
@ -539,15 +514,13 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
} else {
|
} else {
|
||||||
visitorBloc.stateDialog(
|
visitorBloc.stateDialog(
|
||||||
context: context,
|
context: context,
|
||||||
message:
|
message: 'Please select Access Period to continue',
|
||||||
'Please select Access Period to continue',
|
|
||||||
title: 'Access Period');
|
title: 'Access Period');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
visitorBloc.stateDialog(
|
visitorBloc.stateDialog(
|
||||||
context: context,
|
context: context,
|
||||||
message:
|
message: 'Please select Access Period to continue',
|
||||||
'Please select Access Period to continue',
|
|
||||||
title: 'Access Period');
|
title: 'Access Period');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -593,17 +566,17 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
height: size.height * 0.25,
|
height: size.height * 0.25,
|
||||||
child: Center(
|
child: const Center(
|
||||||
child:
|
child: CircularProgressIndicator(), // Display a loading spinner
|
||||||
CircularProgressIndicator(), // Display a loading spinner
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
|
backgroundColor: Colors.white,
|
||||||
content: SizedBox(
|
content: SizedBox(
|
||||||
height: size.height * 0.25,
|
height: size.height * 0.13,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Column(
|
Column(
|
||||||
@ -617,13 +590,16 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
width: 35,
|
width: 35,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(
|
||||||
|
height: 20,
|
||||||
|
),
|
||||||
Text(
|
Text(
|
||||||
'Set Password',
|
'Set Password',
|
||||||
style: Theme.of(context)
|
style: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.headlineLarge!
|
.headlineLarge!
|
||||||
.copyWith(
|
.copyWith(
|
||||||
fontSize: 30,
|
fontSize: 24,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
),
|
),
|
||||||
@ -631,15 +607,6 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(width: 15),
|
const SizedBox(width: 15),
|
||||||
Text(
|
|
||||||
'This action will update all of the selected\n door locks passwords in the property.\n\nAre you sure you want to continue?',
|
|
||||||
textAlign: TextAlign.center,
|
|
||||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
|
||||||
color: ColorsManager.grayColor,
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
fontSize: 18,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -668,12 +635,12 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
decoration: containerDecoration,
|
decoration: containerDecoration,
|
||||||
width: size.width * 0.1,
|
width: size.width * 0.1,
|
||||||
child: DefaultButton(
|
child: DefaultButton(
|
||||||
|
backgroundColor: Color(0xff023DFE),
|
||||||
borderRadius: 8,
|
borderRadius: 8,
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
|
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
|
||||||
visitorBloc.accessTypeSelected ==
|
visitorBloc.accessTypeSelected == 'Online Password') {
|
||||||
'Online Password') {
|
|
||||||
visitorBloc.add(OnlineOneTimePasswordEvent(
|
visitorBloc.add(OnlineOneTimePasswordEvent(
|
||||||
context: context,
|
context: context,
|
||||||
passwordName: visitorBloc.userNameController.text,
|
passwordName: visitorBloc.userNameController.text,
|
||||||
@ -681,8 +648,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
));
|
));
|
||||||
} else if (visitorBloc.usageFrequencySelected ==
|
} else if (visitorBloc.usageFrequencySelected ==
|
||||||
'Periodic' &&
|
'Periodic' &&
|
||||||
visitorBloc.accessTypeSelected ==
|
visitorBloc.accessTypeSelected == 'Online Password') {
|
||||||
'Online Password') {
|
|
||||||
visitorBloc.add(OnlineMultipleTimePasswordEvent(
|
visitorBloc.add(OnlineMultipleTimePasswordEvent(
|
||||||
passwordName: visitorBloc.userNameController.text,
|
passwordName: visitorBloc.userNameController.text,
|
||||||
email: visitorBloc.emailController.text,
|
email: visitorBloc.emailController.text,
|
||||||
@ -693,8 +659,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
));
|
));
|
||||||
} else if (visitorBloc.usageFrequencySelected ==
|
} else if (visitorBloc.usageFrequencySelected ==
|
||||||
'One-Time' &&
|
'One-Time' &&
|
||||||
visitorBloc.accessTypeSelected ==
|
visitorBloc.accessTypeSelected == 'Offline Password') {
|
||||||
'Offline Password') {
|
|
||||||
visitorBloc.add(OfflineOneTimePasswordEvent(
|
visitorBloc.add(OfflineOneTimePasswordEvent(
|
||||||
context: context,
|
context: context,
|
||||||
passwordName: visitorBloc.userNameController.text,
|
passwordName: visitorBloc.userNameController.text,
|
||||||
@ -702,8 +667,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
));
|
));
|
||||||
} else if (visitorBloc.usageFrequencySelected ==
|
} else if (visitorBloc.usageFrequencySelected ==
|
||||||
'Periodic' &&
|
'Periodic' &&
|
||||||
visitorBloc.accessTypeSelected ==
|
visitorBloc.accessTypeSelected == 'Offline Password') {
|
||||||
'Offline Password') {
|
|
||||||
visitorBloc.add(OfflineMultipleTimePasswordEvent(
|
visitorBloc.add(OfflineMultipleTimePasswordEvent(
|
||||||
passwordName: visitorBloc.userNameController.text,
|
passwordName: visitorBloc.userNameController.text,
|
||||||
email: visitorBloc.emailController.text,
|
email: visitorBloc.emailController.text,
|
||||||
@ -715,7 +679,7 @@ class VisitorPasswordDialog extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
'Ok',
|
'Confirm',
|
||||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
color: ColorsManager.whiteColors,
|
color: ColorsManager.whiteColors,
|
||||||
|
@ -13,13 +13,15 @@ import 'package:syncrow_web/utils/constants/api_const.dart';
|
|||||||
|
|
||||||
class DevicesManagementApi {
|
class DevicesManagementApi {
|
||||||
Future<List<AllDevicesModel>> fetchDevices(
|
Future<List<AllDevicesModel>> fetchDevices(
|
||||||
String projectId, {
|
String communityId, String spaceId, String projectId) async {
|
||||||
List<String>? spacesId,
|
|
||||||
}) async {
|
|
||||||
try {
|
try {
|
||||||
final response = await HTTPService().get(
|
final response = await HTTPService().get(
|
||||||
queryParameters: {if (spacesId != null) 'spaces': spacesId},
|
path: communityId.isNotEmpty && spaceId.isNotEmpty
|
||||||
path: ApiEndpoints.getAllDevices.replaceAll('{projectId}', projectId),
|
? ApiEndpoints.getSpaceDevices
|
||||||
|
.replaceAll('{spaceUuid}', spaceId)
|
||||||
|
.replaceAll('{communityUuid}', communityId)
|
||||||
|
.replaceAll('{projectId}', projectId)
|
||||||
|
: ApiEndpoints.getAllDevices.replaceAll('{projectId}', projectId),
|
||||||
showServerMessage: true,
|
showServerMessage: true,
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
List<dynamic> jsonData = json['data'];
|
List<dynamic> jsonData = json['data'];
|
||||||
@ -414,4 +416,5 @@ class DevicesManagementApi {
|
|||||||
);
|
);
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ abstract class ApiEndpoints {
|
|||||||
|
|
||||||
static const String getAllDevices = '/projects/{projectId}/devices';
|
static const String getAllDevices = '/projects/{projectId}/devices';
|
||||||
static const String getSpaceDevices =
|
static const String getSpaceDevices =
|
||||||
'/projects/{projectId}/devices';
|
'/projects/{projectId}/communities/{communityUuid}/spaces/{spaceUuid}/devices';
|
||||||
static const String getDeviceStatus = '/devices/{uuid}/functions/status';
|
static const String getDeviceStatus = '/devices/{uuid}/functions/status';
|
||||||
static const String getBatchStatus = '/devices/batch';
|
static const String getBatchStatus = '/devices/batch';
|
||||||
|
|
||||||
|
@ -14,8 +14,7 @@ class Assets {
|
|||||||
static const String rightLine = 'assets/images/right_line.png';
|
static const String rightLine = 'assets/images/right_line.png';
|
||||||
static const String google = 'assets/images/google.svg';
|
static const String google = 'assets/images/google.svg';
|
||||||
static const String facebook = 'assets/images/facebook.svg';
|
static const String facebook = 'assets/images/facebook.svg';
|
||||||
static const String invisiblePassword =
|
static const String invisiblePassword = 'assets/images/Password_invisible.svg';
|
||||||
'assets/images/Password_invisible.svg';
|
|
||||||
static const String visiblePassword = 'assets/images/password_visible.svg';
|
static const String visiblePassword = 'assets/images/password_visible.svg';
|
||||||
static const String accessIcon = 'assets/images/access_icon.svg';
|
static const String accessIcon = 'assets/images/access_icon.svg';
|
||||||
static const String spaseManagementIcon =
|
static const String spaseManagementIcon =
|
||||||
@ -34,8 +33,7 @@ class Assets {
|
|||||||
static const String emptyTable = 'assets/images/empty_table.svg';
|
static const String emptyTable = 'assets/images/empty_table.svg';
|
||||||
|
|
||||||
// General assets
|
// General assets
|
||||||
static const String motionlessDetection =
|
static const String motionlessDetection = 'assets/icons/motionless_detection.svg';
|
||||||
'assets/icons/motionless_detection.svg';
|
|
||||||
static const String acHeating = 'assets/icons/ac_heating.svg';
|
static const String acHeating = 'assets/icons/ac_heating.svg';
|
||||||
static const String acPowerOff = 'assets/icons/ac_power_off.svg';
|
static const String acPowerOff = 'assets/icons/ac_power_off.svg';
|
||||||
static const String acFanMiddle = 'assets/icons/ac_fan_middle.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';
|
'assets/icons/automation_functions/temp_password_unlock.svg';
|
||||||
static const String doorlockNormalOpen =
|
static const String doorlockNormalOpen =
|
||||||
'assets/icons/automation_functions/doorlock_normal_open.svg';
|
'assets/icons/automation_functions/doorlock_normal_open.svg';
|
||||||
static const String doorbell =
|
static const String doorbell = 'assets/icons/automation_functions/doorbell.svg';
|
||||||
'assets/icons/automation_functions/doorbell.svg';
|
|
||||||
static const String remoteUnlockViaApp =
|
static const String remoteUnlockViaApp =
|
||||||
'assets/icons/automation_functions/remote_unlock_via_app.svg';
|
'assets/icons/automation_functions/remote_unlock_via_app.svg';
|
||||||
static const String doubleLock =
|
static const String doubleLock =
|
||||||
'assets/icons/automation_functions/double_lock.svg';
|
'assets/icons/automation_functions/double_lock.svg';
|
||||||
static const String selfTestResult =
|
static const String selfTestResult =
|
||||||
'assets/icons/automation_functions/self_test_result.svg';
|
'assets/icons/automation_functions/self_test_result.svg';
|
||||||
static const String lockAlarm =
|
static const String lockAlarm = 'assets/icons/automation_functions/lock_alarm.svg';
|
||||||
'assets/icons/automation_functions/lock_alarm.svg';
|
|
||||||
static const String presenceState =
|
static const String presenceState =
|
||||||
'assets/icons/automation_functions/presence_state.svg';
|
'assets/icons/automation_functions/presence_state.svg';
|
||||||
static const String currentTemp =
|
static const String currentTemp =
|
||||||
'assets/icons/automation_functions/current_temp.svg';
|
'assets/icons/automation_functions/current_temp.svg';
|
||||||
static const String presence =
|
static const String presence = 'assets/icons/automation_functions/presence.svg';
|
||||||
'assets/icons/automation_functions/presence.svg';
|
|
||||||
static const String residualElectricity =
|
static const String residualElectricity =
|
||||||
'assets/icons/automation_functions/residual_electricity.svg';
|
'assets/icons/automation_functions/residual_electricity.svg';
|
||||||
static const String hijackAlarm =
|
static const String hijackAlarm =
|
||||||
@ -104,15 +99,12 @@ class Assets {
|
|||||||
|
|
||||||
// Presence Sensor Assets
|
// Presence Sensor Assets
|
||||||
static const String sensorMotionIcon = 'assets/icons/sensor_motion_ic.svg';
|
static const String sensorMotionIcon = 'assets/icons/sensor_motion_ic.svg';
|
||||||
static const String sensorPresenceIcon =
|
static const String sensorPresenceIcon = 'assets/icons/sensor_presence_ic.svg';
|
||||||
'assets/icons/sensor_presence_ic.svg';
|
|
||||||
static const String sensorVacantIcon = 'assets/icons/sensor_vacant_ic.svg';
|
static const String sensorVacantIcon = 'assets/icons/sensor_vacant_ic.svg';
|
||||||
static const String illuminanceRecordIcon =
|
static const String illuminanceRecordIcon =
|
||||||
'assets/icons/illuminance_record_ic.svg';
|
'assets/icons/illuminance_record_ic.svg';
|
||||||
static const String presenceRecordIcon =
|
static const String presenceRecordIcon = 'assets/icons/presence_record_ic.svg';
|
||||||
'assets/icons/presence_record_ic.svg';
|
static const String helpDescriptionIcon = 'assets/icons/help_description_ic.svg';
|
||||||
static const String helpDescriptionIcon =
|
|
||||||
'assets/icons/help_description_ic.svg';
|
|
||||||
|
|
||||||
static const String lightPulp = 'assets/icons/light_pulb.svg';
|
static const String lightPulp = 'assets/icons/light_pulb.svg';
|
||||||
static const String acDevice = 'assets/icons/ac_device.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 unit = 'assets/icons/unit_icon.svg';
|
||||||
static const String villa = 'assets/icons/villa_icon.svg';
|
static const String villa = 'assets/icons/villa_icon.svg';
|
||||||
static const String iconEdit = 'assets/icons/icon_edit_icon.svg';
|
static const String iconEdit = 'assets/icons/icon_edit_icon.svg';
|
||||||
static const String textFieldSearch =
|
static const String textFieldSearch = 'assets/icons/textfield_search_icon.svg';
|
||||||
'assets/icons/textfield_search_icon.svg';
|
|
||||||
static const String roundedAddIcon = 'assets/icons/rounded_add_icon.svg';
|
static const String roundedAddIcon = 'assets/icons/rounded_add_icon.svg';
|
||||||
static const String addIcon = 'assets/icons/add_icon.svg';
|
static const String addIcon = 'assets/icons/add_icon.svg';
|
||||||
static const String smartThermostatIcon =
|
static const String smartThermostatIcon = 'assets/icons/smart_thermostat_icon.svg';
|
||||||
'assets/icons/smart_thermostat_icon.svg';
|
|
||||||
static const String smartLightIcon = 'assets/icons/smart_light_icon.svg';
|
static const String smartLightIcon = 'assets/icons/smart_light_icon.svg';
|
||||||
static const String presenceSensor = 'assets/icons/presence_sensor.svg';
|
static const String presenceSensor = 'assets/icons/presence_sensor.svg';
|
||||||
static const String Gang3SwitchIcon = 'assets/icons/3_Gang_switch_icon.svg';
|
static const String Gang3SwitchIcon = 'assets/icons/3_Gang_switch_icon.svg';
|
||||||
@ -219,8 +209,7 @@ class Assets {
|
|||||||
//assets/icons/water_leak_normal.svg
|
//assets/icons/water_leak_normal.svg
|
||||||
static const String waterLeakNormal = 'assets/icons/water_leak_normal.svg';
|
static const String waterLeakNormal = 'assets/icons/water_leak_normal.svg';
|
||||||
//assets/icons/water_leak_detected.svg
|
//assets/icons/water_leak_detected.svg
|
||||||
static const String waterLeakDetected =
|
static const String waterLeakDetected = 'assets/icons/water_leak_detected.svg';
|
||||||
'assets/icons/water_leak_detected.svg';
|
|
||||||
|
|
||||||
//assets/icons/automation_records.svg
|
//assets/icons/automation_records.svg
|
||||||
static const String automationRecords = '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';
|
'assets/icons/functions_icons/sensitivity.svg';
|
||||||
static const String assetsSensitivityOperationIcon =
|
static const String assetsSensitivityOperationIcon =
|
||||||
'assets/icons/functions_icons/sesitivity_operation_icon.svg';
|
'assets/icons/functions_icons/sesitivity_operation_icon.svg';
|
||||||
static const String assetsAcPower =
|
static const String assetsAcPower = 'assets/icons/functions_icons/ac_power.svg';
|
||||||
'assets/icons/functions_icons/ac_power.svg';
|
|
||||||
static const String assetsAcPowerOFF =
|
static const String assetsAcPowerOFF =
|
||||||
'assets/icons/functions_icons/ac_power_off.svg';
|
'assets/icons/functions_icons/ac_power_off.svg';
|
||||||
static const String assetsChildLock =
|
static const String assetsChildLock =
|
||||||
'assets/icons/functions_icons/child_lock.svg';
|
'assets/icons/functions_icons/child_lock.svg';
|
||||||
static const String assetsFreezing =
|
static const String assetsFreezing = 'assets/icons/functions_icons/freezing.svg';
|
||||||
'assets/icons/functions_icons/freezing.svg';
|
static const String assetsFanSpeed = 'assets/icons/functions_icons/fan_speed.svg';
|
||||||
static const String assetsFanSpeed =
|
|
||||||
'assets/icons/functions_icons/fan_speed.svg';
|
|
||||||
static const String assetsAcCooling =
|
static const String assetsAcCooling =
|
||||||
'assets/icons/functions_icons/ac_cooling.svg';
|
'assets/icons/functions_icons/ac_cooling.svg';
|
||||||
static const String assetsAcHeating =
|
static const String assetsAcHeating =
|
||||||
@ -309,8 +295,7 @@ class Assets {
|
|||||||
'assets/icons/functions_icons/celsius_degrees.svg';
|
'assets/icons/functions_icons/celsius_degrees.svg';
|
||||||
static const String assetsTempreture =
|
static const String assetsTempreture =
|
||||||
'assets/icons/functions_icons/tempreture.svg';
|
'assets/icons/functions_icons/tempreture.svg';
|
||||||
static const String assetsAcFanLow =
|
static const String assetsAcFanLow = 'assets/icons/functions_icons/ac_fan_low.svg';
|
||||||
'assets/icons/functions_icons/ac_fan_low.svg';
|
|
||||||
static const String assetsAcFanMiddle =
|
static const String assetsAcFanMiddle =
|
||||||
'assets/icons/functions_icons/ac_fan_middle.svg';
|
'assets/icons/functions_icons/ac_fan_middle.svg';
|
||||||
static const String assetsAcFanHigh =
|
static const String assetsAcFanHigh =
|
||||||
@ -329,8 +314,7 @@ class Assets {
|
|||||||
'assets/icons/functions_icons/far_detection.svg';
|
'assets/icons/functions_icons/far_detection.svg';
|
||||||
static const String assetsFarDetectionFunction =
|
static const String assetsFarDetectionFunction =
|
||||||
'assets/icons/functions_icons/far_detection_function.svg';
|
'assets/icons/functions_icons/far_detection_function.svg';
|
||||||
static const String assetsIndicator =
|
static const String assetsIndicator = 'assets/icons/functions_icons/indicator.svg';
|
||||||
'assets/icons/functions_icons/indicator.svg';
|
|
||||||
static const String assetsMotionDetection =
|
static const String assetsMotionDetection =
|
||||||
'assets/icons/functions_icons/motion_detection.svg';
|
'assets/icons/functions_icons/motion_detection.svg';
|
||||||
static const String assetsMotionlessDetection =
|
static const String assetsMotionlessDetection =
|
||||||
@ -343,8 +327,7 @@ class Assets {
|
|||||||
'assets/icons/functions_icons/master_state.svg';
|
'assets/icons/functions_icons/master_state.svg';
|
||||||
static const String assetsSwitchAlarmSound =
|
static const String assetsSwitchAlarmSound =
|
||||||
'assets/icons/functions_icons/switch_alarm_sound.svg';
|
'assets/icons/functions_icons/switch_alarm_sound.svg';
|
||||||
static const String assetsResetOff =
|
static const String assetsResetOff = 'assets/icons/functions_icons/reset_off.svg';
|
||||||
'assets/icons/functions_icons/reset_off.svg';
|
|
||||||
|
|
||||||
// Assets for automation_functions
|
// Assets for automation_functions
|
||||||
static const String assetsCardUnlock =
|
static const String assetsCardUnlock =
|
||||||
@ -388,15 +371,13 @@ class Assets {
|
|||||||
static const String activeUser = 'assets/icons/active_user.svg';
|
static const String activeUser = 'assets/icons/active_user.svg';
|
||||||
static const String deActiveUser = 'assets/icons/deactive_user.svg';
|
static const String deActiveUser = 'assets/icons/deactive_user.svg';
|
||||||
static const String invitedIcon = 'assets/icons/invited_icon.svg';
|
static const String invitedIcon = 'assets/icons/invited_icon.svg';
|
||||||
static const String rectangleCheckBox =
|
static const String rectangleCheckBox = 'assets/icons/rectangle_check_box.png';
|
||||||
'assets/icons/rectangle_check_box.png';
|
|
||||||
static const String CheckBoxChecked = 'assets/icons/box_checked.png';
|
static const String CheckBoxChecked = 'assets/icons/box_checked.png';
|
||||||
static const String emptyBox = 'assets/icons/empty_box.png';
|
static const String emptyBox = 'assets/icons/empty_box.png';
|
||||||
static const String completeProcessIcon =
|
static const String completeProcessIcon =
|
||||||
'assets/icons/compleate_process_icon.svg';
|
'assets/icons/compleate_process_icon.svg';
|
||||||
static const String completedDoneIcon = 'assets/images/completed_done.svg';
|
static const String completedDoneIcon = 'assets/images/completed_done.svg';
|
||||||
static const String currentProcessIcon =
|
static const String currentProcessIcon = 'assets/icons/current_process_icon.svg';
|
||||||
'assets/icons/current_process_icon.svg';
|
|
||||||
static const String uncomplete_ProcessIcon =
|
static const String uncomplete_ProcessIcon =
|
||||||
'assets/icons/uncompleate_process_icon.svg';
|
'assets/icons/uncompleate_process_icon.svg';
|
||||||
static const String wrongProcessIcon = 'assets/icons/wrong_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 successIcon = 'assets/icons/success_icon.svg';
|
||||||
static const String spaceLocationIcon = 'assets/icons/spaseLocationIcon.svg';
|
static const String spaceLocationIcon = 'assets/icons/spaseLocationIcon.svg';
|
||||||
static const String scenesPlayIcon = 'assets/icons/scenesPlayIcon.png';
|
static const String scenesPlayIcon = 'assets/icons/scenesPlayIcon.png';
|
||||||
static const String scenesPlayIconCheck =
|
static const String scenesPlayIconCheck = 'assets/icons/scenesPlayIconCheck.png';
|
||||||
'assets/icons/scenesPlayIconCheck.png';
|
|
||||||
static const String presenceStateIcon = 'assets/icons/presence_state.svg';
|
static const String presenceStateIcon = 'assets/icons/presence_state.svg';
|
||||||
static const String currentDistanceIcon =
|
static const String currentDistanceIcon = 'assets/icons/current_distance_icon.svg';
|
||||||
'assets/icons/current_distance_icon.svg';
|
|
||||||
|
|
||||||
static const String farDetectionIcon = 'assets/icons/far_detection_icon.svg';
|
static const String farDetectionIcon = 'assets/icons/far_detection_icon.svg';
|
||||||
static const String motionDetectionSensitivityIcon =
|
static const String motionDetectionSensitivityIcon =
|
||||||
@ -444,44 +423,29 @@ class Assets {
|
|||||||
static const String cpsMode4 = 'assets/icons/cps_mode4.svg';
|
static const String cpsMode4 = 'assets/icons/cps_mode4.svg';
|
||||||
static const String closeToMotion = 'assets/icons/close_to_motion.svg';
|
static const String closeToMotion = 'assets/icons/close_to_motion.svg';
|
||||||
static const String farAwayMotion = 'assets/icons/far_away_motion.svg';
|
static const String farAwayMotion = 'assets/icons/far_away_motion.svg';
|
||||||
static const String communicationFault =
|
static const String communicationFault = 'assets/icons/communication_fault.svg';
|
||||||
'assets/icons/communication_fault.svg';
|
|
||||||
static const String radarFault = 'assets/icons/radar_fault.svg';
|
static const String radarFault = 'assets/icons/radar_fault.svg';
|
||||||
static const String selfTestingSuccess =
|
static const String selfTestingSuccess = 'assets/icons/self_testing_success.svg';
|
||||||
'assets/icons/self_testing_success.svg';
|
static const String selfTestingFailure = 'assets/icons/self_testing_failure.svg';
|
||||||
static const String selfTestingFailure =
|
static const String selfTestingTimeout = 'assets/icons/self_testing_timeout.svg';
|
||||||
'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 movingSpeed = 'assets/icons/moving_speed.svg';
|
||||||
static const String boundary = 'assets/icons/boundary.svg';
|
static const String boundary = 'assets/icons/boundary.svg';
|
||||||
static const String motionMeter = 'assets/icons/motion_meter.svg';
|
static const String motionMeter = 'assets/icons/motion_meter.svg';
|
||||||
static const String spatialStaticValue =
|
static const String spatialStaticValue = 'assets/icons/spatial_static_value.svg';
|
||||||
'assets/icons/spatial_static_value.svg';
|
static const String spatialMotionValue = 'assets/icons/spatial_motion_value.svg';
|
||||||
static const String spatialMotionValue =
|
|
||||||
'assets/icons/spatial_motion_value.svg';
|
|
||||||
static const String presenceJudgementThrshold =
|
static const String presenceJudgementThrshold =
|
||||||
'assets/icons/presence_judgement_threshold.svg';
|
'assets/icons/presence_judgement_threshold.svg';
|
||||||
static const String spaceType = 'assets/icons/space_type.svg';
|
static const String spaceType = 'assets/icons/space_type.svg';
|
||||||
static const String sportsPara = 'assets/icons/sports_para.svg';
|
static const String sportsPara = 'assets/icons/sports_para.svg';
|
||||||
static const String sensitivityFeature1 =
|
static const String sensitivityFeature1 = 'assets/icons/sensitivity_feature_1.svg';
|
||||||
'assets/icons/sensitivity_feature_1.svg';
|
static const String sensitivityFeature2 = 'assets/icons/sensitivity_feature_2.svg';
|
||||||
static const String sensitivityFeature2 =
|
static const String sensitivityFeature3 = 'assets/icons/sensitivity_feature_3.svg';
|
||||||
'assets/icons/sensitivity_feature_2.svg';
|
static const String sensitivityFeature4 = 'assets/icons/sensitivity_feature_4.svg';
|
||||||
static const String sensitivityFeature3 =
|
static const String sensitivityFeature5 = 'assets/icons/sensitivity_feature_5.svg';
|
||||||
'assets/icons/sensitivity_feature_3.svg';
|
static const String sensitivityFeature6 = 'assets/icons/sensitivity_feature_6.svg';
|
||||||
static const String sensitivityFeature4 =
|
static const String sensitivityFeature7 = 'assets/icons/sensitivity_feature_7.svg';
|
||||||
'assets/icons/sensitivity_feature_4.svg';
|
static const String sensitivityFeature8 = 'assets/icons/sensitivity_feature_8.svg';
|
||||||
static const String sensitivityFeature5 =
|
static const String sensitivityFeature9 = 'assets/icons/sensitivity_feature_9.svg';
|
||||||
'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 deviceTagIcon = 'assets/icons/device_tag_ic.svg';
|
||||||
static const String targetConfirmTimeIcon =
|
static const String targetConfirmTimeIcon =
|
||||||
'assets/icons/target_confirm_time_icon.svg';
|
'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 indentLevelIcon = 'assets/icons/indent_level_icon.svg';
|
||||||
static const String triggerLevelIcon = 'assets/icons/trigger_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 blankCalendar = 'assets/icons/blank_calendar.svg';
|
||||||
static const String refreshStatusIcon =
|
static const String refreshStatusIcon = 'assets/icons/refresh_status_icon.svg';
|
||||||
'assets/icons/refresh_status_icon.svg';
|
static const String energyConsumedIcon = 'assets/icons/energy_consumed_icon.svg';
|
||||||
static const String energyConsumedIcon =
|
|
||||||
'assets/icons/energy_consumed_icon.svg';
|
|
||||||
|
|
||||||
static const String closeSettingsIcon =
|
static const String closeSettingsIcon = 'assets/icons/close_settings_icon.svg';
|
||||||
'assets/icons/close_settings_icon.svg';
|
|
||||||
|
|
||||||
static const String editNameIconSettings =
|
static const String editNameIconSettings =
|
||||||
'assets/icons/edit_name_icon_settings.svg';
|
'assets/icons/edit_name_icon_settings.svg';
|
||||||
@ -508,4 +469,11 @@ class Assets {
|
|||||||
static const String humidityAqiSidebar = 'assets/icons/humidity.svg';
|
static const String humidityAqiSidebar = 'assets/icons/humidity.svg';
|
||||||
static const String autocadOccupancyImage =
|
static const String autocadOccupancyImage =
|
||||||
'assets/images/autocad_occupancy_image.png';
|
'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';
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user