Compare commits

..

1 Commits

Author SHA1 Message Date
818bdee745 change calibration completed dialog color 2025-07-01 15:04:50 +03:00
64 changed files with 699 additions and 1335 deletions

View File

@ -1,8 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 583 B

View File

@ -1,5 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 520 B

View File

@ -1,7 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,99 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 6.1 KiB

View File

@ -1,7 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -39,12 +39,8 @@ 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 && json['lat'] != '' latitude: json['lat'] != null ? double.parse(json['lat'] as String? ?? '0.0') : null,
? double.tryParse(json['lat']?.toString() ?? '0.0') longitude: json['lon'] != null ? double.parse(json['lon'] as String? ?? '0.0') : null,
: null,
longitude: json['lon'] != null && json['lon'] != ''
? double.tryParse(json['lon']?.toString() ?? '0.0')
: null,
); );
} }
} }

View File

@ -46,11 +46,11 @@ class AirQualityDistributionBloc
} }
} }
void _onClearAirQualityDistribution( Future<void> _onClearAirQualityDistribution(
ClearAirQualityDistribution event, ClearAirQualityDistribution event,
Emitter<AirQualityDistributionState> emit, Emitter<AirQualityDistributionState> emit,
) { ) async {
emit(AirQualityDistributionState(selectedAqiType: state.selectedAqiType)); emit(const AirQualityDistributionState());
} }
void _onUpdateAqiTypeEvent( void _onUpdateAqiTypeEvent(

View File

@ -75,6 +75,6 @@ class RangeOfAqiBloc extends Bloc<RangeOfAqiEvent, RangeOfAqiState> {
ClearRangeOfAqiEvent event, ClearRangeOfAqiEvent event,
Emitter<RangeOfAqiState> emit, Emitter<RangeOfAqiState> emit,
) { ) {
emit(RangeOfAqiState(selectedAqiType: state.selectedAqiType)); emit(const RangeOfAqiState());
} }
} }

View File

@ -20,7 +20,6 @@ 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,
), ),

View File

@ -3,9 +3,7 @@ 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 {
@ -34,20 +32,8 @@ class AqiDistributionChartBox extends StatelessWidget {
const SizedBox(height: 10), const SizedBox(height: 10),
const Divider(), const Divider(),
const SizedBox(height: 20), const SizedBox(height: 20),
Visibility( Expanded(
visible: state.chartData.isNotEmpty, child: AqiDistributionChart(chartData: state.chartData),
replacement: AnalyticsChartEmptyStateWidget(
isLoading: state.status == AirQualityDistributionStatus.loading,
isError: state.status == AirQualityDistributionStatus.failure,
isInitial: state.status == AirQualityDistributionStatus.initial,
errorMessage: state.errorMessage,
iconPath: Assets.emptyBarredChart,
),
child: Expanded(
child: AqiDistributionChart(
chartData: state.chartData,
),
),
), ),
], ],
), ),

View File

@ -34,7 +34,6 @@ 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>();

View File

@ -18,20 +18,19 @@ enum AqiType {
} }
class AqiTypeDropdown extends StatefulWidget { class AqiTypeDropdown extends StatefulWidget {
const AqiTypeDropdown({ const AqiTypeDropdown({super.key, required this.onChanged});
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(
@ -42,8 +41,8 @@ class _AqiTypeDropdownState extends State<AqiTypeDropdown> {
width: 1, width: 1,
), ),
), ),
child: DropdownButton<AqiType>( child: DropdownButton<AqiType?>(
value: widget.selectedAqiType, value: _selectedItem,
isDense: true, isDense: true,
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
dropdownColor: ColorsManager.whiteColors, dropdownColor: ColorsManager.whiteColors,
@ -60,7 +59,10 @@ 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: widget.onChanged, onChanged: (value) {
_updateSelectedItem(value);
widget.onChanged(value);
},
), ),
); );
} }

View File

@ -3,9 +3,7 @@ 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 {
@ -34,20 +32,10 @@ class RangeOfAqiChartBox extends StatelessWidget {
const SizedBox(height: 10), const SizedBox(height: 10),
const Divider(), const Divider(),
const SizedBox(height: 20), const SizedBox(height: 20),
Visibility( Expanded(
visible: state.filteredRangeOfAqi.isNotEmpty, child: RangeOfAqiChart(
replacement: AnalyticsChartEmptyStateWidget( chartData: state.filteredRangeOfAqi,
isLoading: state.status == RangeOfAqiStatus.loading, selectedAqiType: state.selectedAqiType,
isError: state.status == RangeOfAqiStatus.failure,
isInitial: state.status == RangeOfAqiStatus.initial,
errorMessage: state.errorMessage,
iconPath: Assets.emptyRangeOfAqi,
),
child: Expanded(
child: RangeOfAqiChart(
chartData: state.filteredRangeOfAqi,
selectedAqiType: state.selectedAqiType,
),
), ),
), ),
], ],

View File

@ -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;
}, },
), ),
), ),

View File

@ -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.05, height: MediaQuery.sizeOf(context).height * 1,
child: const Column( child: const Column(
children: [ children: [
Expanded( Expanded(

View File

@ -5,10 +5,8 @@ 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 {
@ -56,24 +54,8 @@ 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),
Visibility( Expanded(
visible: state.chartData.isNotEmpty && child: EnergyConsumptionPerDeviceChart(chartData: state.chartData),
state.chartData
.every((e) => e.energy.every((e) => e.value != 0)),
replacement: AnalyticsChartEmptyStateWidget(
isLoading:
state.status == EnergyConsumptionPerDeviceStatus.loading,
isError: state.status == EnergyConsumptionPerDeviceStatus.failure,
isInitial:
state.status == EnergyConsumptionPerDeviceStatus.initial,
errorMessage: state.errorMessage,
iconPath: Assets.emptyEnergyManagementPerDevice,
),
child: Expanded(
child: EnergyConsumptionPerDeviceChart(
chartData: state.chartData,
),
),
), ),
], ],
), ),

View File

@ -3,10 +3,8 @@ 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 {
@ -43,18 +41,7 @@ class TotalEnergyConsumptionChartBox extends StatelessWidget {
const SizedBox(height: 20), const SizedBox(height: 20),
const Divider(), const Divider(),
const SizedBox(height: 20), const SizedBox(height: 20),
Visibility( TotalEnergyConsumptionChart(chartData: state.chartData),
visible: state.chartData.isNotEmpty &&
state.chartData.every((e) => e.value != 0),
replacement: AnalyticsChartEmptyStateWidget(
isLoading: state.status == TotalEnergyConsumptionStatus.loading,
isError: state.status == TotalEnergyConsumptionStatus.failure,
isInitial: state.status == TotalEnergyConsumptionStatus.initial,
errorMessage: state.errorMessage,
iconPath: Assets.emptyEnergyManagementChart,
),
child: TotalEnergyConsumptionChart(chartData: state.chartData),
),
], ],
), ),
), ),

View File

@ -18,7 +18,6 @@ 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,

View File

@ -6,10 +6,8 @@ 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 {
@ -69,24 +67,7 @@ class OccupancyChartBox extends StatelessWidget {
const SizedBox(height: 20), const SizedBox(height: 20),
const Divider(), const Divider(),
const SizedBox(height: 20), const SizedBox(height: 20),
Visibility( Expanded(child: OccupancyChart(chartData: state.chartData)),
visible: state.chartData.isNotEmpty &&
state.chartData.every(
(e) => e.occupancy.isNotEmpty,
),
replacement: AnalyticsChartEmptyStateWidget(
isLoading: state.status == OccupancyStatus.loading,
isError: state.status == OccupancyStatus.failure,
isInitial: state.status == OccupancyStatus.initial,
errorMessage: state.errorMessage,
iconPath: Assets.emptyBarredChart,
),
child: Expanded(
child: OccupancyChart(
chartData: state.chartData,
),
),
),
], ],
), ),
); );

View File

@ -6,10 +6,8 @@ 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 {
@ -70,29 +68,16 @@ class OccupancyHeatMapBox extends StatelessWidget {
const SizedBox(height: 20), const SizedBox(height: 20),
const Divider(), const Divider(),
const SizedBox(height: 20), const SizedBox(height: 20),
Visibility( Expanded(
visible: state.heatMapData.isNotEmpty && child: OccupancyHeatMap(
state.heatMapData.every( selectedDate:
(e) => e.countTotalPresenceDetected != 0, context.watch<AnalyticsDatePickerBloc>().state.yearlyDate,
), heatMapData: state.heatMapData.asMap().map(
replacement: AnalyticsChartEmptyStateWidget( (_, value) => MapEntry(
isLoading: state.status == OccupancyHeatMapStatus.loading, value.eventDate,
isError: state.status == OccupancyHeatMapStatus.failure, value.countTotalPresenceDetected,
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,
),
), ),
), ),
), ),
), ),
], ],

View File

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

View File

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

View File

@ -16,12 +16,11 @@ class DeviceManagementBloc
int _onlineCount = 0; int _onlineCount = 0;
int _offlineCount = 0; int _offlineCount = 0;
int _lowBatteryCount = 0; int _lowBatteryCount = 0;
final List<AllDevicesModel> _selectedDevices = []; 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);
@ -32,29 +31,24 @@ 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 {
var devices = <AllDevicesModel>[]; List<AllDevicesModel> devices = [];
_devices.clear(); _devices.clear();
final spaceBloc = event.context.read<SpaceTreeBloc>(); var 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 (final community in spaceBloc.state.selectedCommunities) { for (var community in spaceBloc.state.selectedCommunities) {
final spacesList = List<String> spacesList =
spaceBloc.state.selectedCommunityAndSpaces[community] ?? []; spaceBloc.state.selectedCommunityAndSpaces[community] ?? [];
for (final space in spacesList) { devices.addAll(await DevicesManagementApi()
devices.addAll(await DevicesManagementApi() .fetchDevices(projectUuid, spacesId: spacesList));
.fetchDevices(community, space, projectUuid));
}
} }
} }
@ -76,7 +70,7 @@ class DeviceManagementBloc
} }
} }
Future<void> _onFilterDevices( 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) {
@ -158,7 +152,8 @@ class DeviceManagementBloc
add(FilterDevices(_getFilterFromIndex(_selectedIndex))); add(FilterDevices(_getFilterFromIndex(_selectedIndex)));
} }
void _onSelectDevice(SelectDevice event, Emitter<DeviceManagementState> emit) { void _onSelectDevice(
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)) {
@ -167,9 +162,9 @@ class DeviceManagementBloc
_selectedDevices.add(event.selectedDevice); _selectedDevices.add(event.selectedDevice);
} }
final clonedSelectedDevices = List<AllDevicesModel>.from(_selectedDevices); List<AllDevicesModel> clonedSelectedDevices = List.from(_selectedDevices);
final isControlButtonEnabled = bool isControlButtonEnabled =
_checkIfControlButtonEnabled(clonedSelectedDevices); _checkIfControlButtonEnabled(clonedSelectedDevices);
if (state is DeviceManagementLoaded) { if (state is DeviceManagementLoaded) {
@ -199,8 +194,8 @@ class DeviceManagementBloc
void _onUpdateSelection( void _onUpdateSelection(
UpdateSelection event, Emitter<DeviceManagementState> emit) { UpdateSelection event, Emitter<DeviceManagementState> emit) {
final selectedDevices = <AllDevicesModel>[]; List<AllDevicesModel> selectedDevices = [];
var devicesToSelectFrom = <AllDevicesModel>[]; List<AllDevicesModel> devicesToSelectFrom = [];
if (state is DeviceManagementLoaded) { if (state is DeviceManagementLoaded) {
devicesToSelectFrom = (state as DeviceManagementLoaded).devices; devicesToSelectFrom = (state as DeviceManagementLoaded).devices;
@ -208,7 +203,7 @@ class DeviceManagementBloc
devicesToSelectFrom = (state as DeviceManagementFiltered).filteredDevices; devicesToSelectFrom = (state as DeviceManagementFiltered).filteredDevices;
} }
for (var i = 0; i < event.selectedRows.length; i++) { for (int i = 0; i < event.selectedRows.length; i++) {
if (event.selectedRows[i]) { if (event.selectedRows[i]) {
selectedDevices.add(devicesToSelectFrom[i]); selectedDevices.add(devicesToSelectFrom[i]);
} }
@ -254,7 +249,8 @@ 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) => device.batteryLevel != null && device.batteryLevel! < 20) .where((device) =>
device.batteryLevel != null && device.batteryLevel! < 20)
.length; .length;
} }
@ -271,7 +267,8 @@ class DeviceManagementBloc
} }
} }
void _onSearchDevices(SearchDevices event, Emitter<DeviceManagementState> emit) { void _onSearchDevices(
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 ||
@ -300,7 +297,7 @@ class DeviceManagementBloc
currentCommunity = event.community; currentCommunity = event.community;
currentUnitName = event.unitName; currentUnitName = event.unitName;
final devicesToSearch = _devices; List<AllDevicesModel> devicesToSearch = _devices;
if (devicesToSearch.isNotEmpty) { if (devicesToSearch.isNotEmpty) {
final searchText = event.deviceNameOrProductName?.toLowerCase() ?? ''; final searchText = event.deviceNameOrProductName?.toLowerCase() ?? '';
@ -343,134 +340,5 @@ 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;
} }

View File

@ -70,21 +70,3 @@ 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});
}

View File

@ -60,13 +60,4 @@ 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,
);
}
} }

View File

@ -44,20 +44,4 @@ 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,
);
}
} }

View File

@ -588,72 +588,4 @@ 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,
);
}
} }

View File

@ -23,7 +23,6 @@ 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;
@ -32,6 +31,7 @@ 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;
@ -111,8 +111,6 @@ 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(
@ -192,7 +190,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',
@ -244,7 +242,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) async { onSettingsPressed: (rowIndex) {
final device = devicesToShow[rowIndex]; final device = devicesToShow[rowIndex];
showDeviceSettingsSidebar(context, device); showDeviceSettingsSidebar(context, device);
}, },
@ -266,7 +264,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: (_, anim1, anim2) { pageBuilder: (context, anim1, anim2) {
return Align( return Align(
alignment: Alignment.centerRight, alignment: Alignment.centerRight,
child: Material( child: Material(
@ -276,7 +274,6 @@ 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>(),
), ),
), ),
), ),

View File

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

View File

@ -17,6 +17,7 @@ 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,

View File

@ -19,14 +19,11 @@ 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) {
@ -90,11 +87,6 @@ class DeviceManagementContent extends StatelessWidget {
), ),
); );
}); });
deviceManagementBloc.add(UpdateSubSpaceName(
subspaceId: selectedSubSpace.id!,
deviceId: device.uuid!,
newSubSpaceName: selectedSubSpace.name ?? ''));
} }
}, },
child: infoRow( child: infoRow(

View File

@ -1,15 +1,13 @@
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';
@ -19,13 +17,7 @@ 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;
final DeviceManagementBloc deviceManagementBloc; const DeviceSettingsPanel({super.key, this.onClose, required this.device});
const DeviceSettingsPanel({
super.key,
this.onClose,
required this.device,
required this.deviceManagementBloc,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -79,10 +71,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),
), ),
], ],
), ),
@ -142,14 +134,8 @@ 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:const InputDecoration( decoration: InputDecoration(
isDense: true, isDense: true,
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
border: InputBorder.none, border: InputBorder.none,
@ -171,7 +157,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
@ -204,7 +190,6 @@ 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),

View File

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

View File

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

View File

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

View File

@ -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: event.countdownCode, code: 'countdown_1',
value: 0, value: 0,
), ),
); );
@ -80,18 +80,15 @@ 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,
countdownHours: currentState.countdownHours, countdownRemaining: Duration.zero,
countdownMinutes: currentState.countdownMinutes, countdownHours: 0,
inchingHours: currentState.inchingHours, countdownMinutes: 0,
inchingMinutes: currentState.inchingMinutes, inchingHours: 0,
inchingMinutes: 0,
isCountdownActive: false,
isInchingActive: false, isInchingActive: false,
isCountdownActive: currentState.countdownRemaining > Duration.zero,
)); ));
} }
} }
@ -224,6 +221,7 @@ 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(
@ -232,6 +230,7 @@ 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(
@ -286,22 +285,12 @@ 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, function: Status(code: event.category, value: event.functionOn),
days: event.selectedDays, days: event.selectedDays,
); );
final success = await DevicesManagementApi().editScheduleRecord( final success = await DevicesManagementApi().editScheduleRecord(
@ -407,7 +396,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
? event.countDownCode ? 'countdown_1'
: 'switch_inching'; : 'switch_inching';
final currentState = state as ScheduleLoaded; final currentState = state as ScheduleLoaded;
final duration = Duration(seconds: totalSeconds); final duration = Duration(seconds: totalSeconds);
@ -434,7 +423,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
); );
if (success) { if (success) {
if (code == event.countDownCode) { if (code == 'countdown_1') {
final countdownDuration = Duration(seconds: totalSeconds); final countdownDuration = Duration(seconds: totalSeconds);
emit( emit(
@ -448,7 +437,7 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
); );
if (countdownDuration.inSeconds > 0) { if (countdownDuration.inSeconds > 0) {
_startCountdownTimer(emit, countdownDuration, event.countDownCode); _startCountdownTimer(emit, countdownDuration);
} else { } else {
_countdownTimer?.cancel(); _countdownTimer?.cancel();
emit( emit(
@ -478,7 +467,9 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
} }
void _startCountdownTimer( void _startCountdownTimer(
Emitter<ScheduleState> emit, Duration duration, String countdownCode) { Emitter<ScheduleState> emit,
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) {
@ -488,7 +479,6 @@ 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,
@ -525,75 +515,70 @@ class ScheduleBloc extends Bloc<ScheduleEvent, ScheduleState> {
try { try {
final status = final status =
await DevicesManagementApi().getDeviceStatus(event.deviceId); await DevicesManagementApi().getDeviceStatus(event.deviceId);
int totalSeconds = 0; print(status.status);
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 newState = state is ScheduleLoaded final scheduleMode =
? (state as ScheduleLoaded).copyWith( deviceStatus.countdownHours > 0 || deviceStatus.countdownMinutes > 0
scheduleMode: ScheduleModes.schedule, ? ScheduleModes.countdown
countdownHours: countdownHours, : deviceStatus.inchingHours > 0 || deviceStatus.inchingMinutes > 0
countdownMinutes: countdownMinutes, ? ScheduleModes.inching
countdownSeconds: countdownSeconds, : ScheduleModes.schedule;
inchingHours: deviceStatus.inchingHours, final isCountdown = scheduleMode == ScheduleModes.countdown;
inchingMinutes: deviceStatus.inchingMinutes, final isInching = scheduleMode == ScheduleModes.inching;
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);
if (isCountdownActive) { Duration? countdownRemaining;
_countdownTimer?.cancel(); var isCountdownActive = false;
_currentCountdown = Duration(seconds: totalSeconds); var isInchingActive = false;
countdownRemaining = _currentCountdown!;
if (totalSeconds > 0) { if (isCountdown) {
_startCountdownTimer( countdownRemaining = Duration(
emit, Duration(seconds: totalSeconds), event.countdownCode); hours: deviceStatus.countdownHours,
} else { minutes: deviceStatus.countdownMinutes,
add(StopScheduleEvent( );
countdownCode: event.countdownCode, isCountdownActive = countdownRemaining > Duration.zero;
mode: ScheduleModes.countdown, } else if (isInching) {
deviceId: event.deviceId, isInchingActive = Duration(
)); hours: deviceStatus.inchingHours,
} minutes: deviceStatus.inchingMinutes,
} else { ) >
_countdownTimer?.cancel(); 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 {
emit(ScheduleLoaded(
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'));
} }

View File

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

View File

@ -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 = Duration.zero, this.countdownRemaining,
}); });
ScheduleLoaded copyWith({ ScheduleLoaded copyWith({

View File

@ -11,7 +11,6 @@ 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,
@ -19,7 +18,6 @@ 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
@ -45,7 +43,6 @@ class CountdownModeButtons extends StatelessWidget {
StopScheduleEvent( StopScheduleEvent(
mode: ScheduleModes.countdown, mode: ScheduleModes.countdown,
deviceId: deviceId, deviceId: deviceId,
countdownCode: countDownCode,
), ),
); );
}, },
@ -57,10 +54,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,

View File

@ -75,33 +75,23 @@ 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);
final displayHours = _updateControllers(displayHours, displayMinutes, displaySeconds!);
isActive && state.countdownRemaining != Duration.zero
? state.countdownRemaining.inHours
: (isCountDown ? state.countdownHours : state.inchingHours);
final displayMinutes = if (displayHours == 0 && displayMinutes == 0 && displaySeconds == 0) {
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: '',
), ),
); );
} }

View File

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

View File

@ -18,15 +18,11 @@ 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) {
@ -35,8 +31,7 @@ class BuildScheduleView extends StatelessWidget {
deviceId: deviceUuid, deviceId: deviceUuid,
) )
..add(ScheduleGetEvent(category: category)) ..add(ScheduleGetEvent(category: category))
..add(ScheduleFetchStatusEvent( ..add(ScheduleFetchStatusEvent(deviceUuid)),
deviceId: deviceUuid, countdownCode: countdownCode ?? '')),
child: Dialog( child: Dialog(
backgroundColor: Colors.white, backgroundColor: Colors.white,
insetPadding: const EdgeInsets.all(20), insetPadding: const EdgeInsets.all(20),
@ -57,32 +52,28 @@ class BuildScheduleView extends StatelessWidget {
children: [ children: [
const ScheduleHeader(), const ScheduleHeader(),
const SizedBox(height: 20), const SizedBox(height: 20),
if (deviceType == 'CUR_2') ScheduleModeSelector(
const SizedBox() currentMode: state.scheduleMode,
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(context, .showAddScheduleDialog(
schedule: ScheduleEntry( context,
category: category, schedule: ScheduleEntry(
time: '', category: category,
function: Status( time: '',
code: code.toString(), value: null), function: Status(
days: [], code: code.toString(), value: null),
), days: [],
isEdit: false, ),
code: code, isEdit: false,
deviceType: deviceType); code: code,
);
if (entry != null) { if (entry != null) {
context.read<ScheduleBloc>().add( context.read<ScheduleBloc>().add(
ScheduleAddEvent( ScheduleAddEvent(
@ -96,16 +87,14 @@ class BuildScheduleView extends StatelessWidget {
} }
}, },
), ),
if (deviceType != 'CUR_2') if (state.scheduleMode == ScheduleModes.countdown ||
if (state.scheduleMode == ScheduleModes.countdown || state.scheduleMode == ScheduleModes.inching)
state.scheduleMode == ScheduleModes.inching) CountdownInchingView(
CountdownInchingView( deviceId: deviceUuid,
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,

View File

@ -5,16 +5,14 @@ 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',
}); });
@ -46,11 +44,7 @@ class ScheduleManagementUI extends StatelessWidget {
), ),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
ScheduleTableWidget( ScheduleTableWidget(deviceUuid: deviceUuid, category: category),
deviceUuid: deviceUuid,
category: category,
deviceType: deviceType,
),
], ],
); );
} }

View File

@ -7,12 +7,10 @@ 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
@ -73,8 +71,7 @@ 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( UpdateScheduleModeEvent(scheduleMode: value),
scheduleMode: value, countdownCode: countdownCode),
); );
if (value == ScheduleModes.schedule) { if (value == ScheduleModes.schedule) {
context.read<ScheduleBloc>().add( context.read<ScheduleBloc>().add(

View File

@ -12,13 +12,11 @@ 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
@ -27,14 +25,13 @@ class ScheduleTableWidget extends StatelessWidget {
create: (_) => ScheduleBloc( create: (_) => ScheduleBloc(
deviceId: deviceUuid, deviceId: deviceUuid,
)..add(ScheduleGetEvent(category: category)), )..add(ScheduleGetEvent(category: category)),
child: _ScheduleTableView(deviceType), child: _ScheduleTableView(),
); );
} }
} }
class _ScheduleTableView extends StatelessWidget { class _ScheduleTableView extends StatelessWidget {
final String deviceType; const _ScheduleTableView();
const _ScheduleTableView(this.deviceType);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -84,7 +81,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, deviceType)); child: _buildTableBody(state.schedules, context));
} }
if (state is ScheduleError) { if (state is ScheduleError) {
return Center(child: Text(state.error)); return Center(child: Text(state.error));
@ -126,8 +123,7 @@ class _ScheduleTableView extends StatelessWidget {
); );
} }
Widget _buildTableBody( Widget _buildTableBody(List<ScheduleModel> schedules, BuildContext context) {
List<ScheduleModel> schedules, BuildContext context, String deviceType) {
return SizedBox( return SizedBox(
height: 200, height: 200,
child: SingleChildScrollView( child: SingleChildScrollView(
@ -136,8 +132,7 @@ 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),
], ],
), ),
), ),
@ -160,19 +155,25 @@ 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: schedule.function.value, functionOn: temp,
// schedule.function.value,
enable: !schedule.enable, enable: !schedule.enable,
), ),
); );
@ -194,11 +195,10 @@ 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))),
if (deviceType == 'CUR_2') schedule.category == 'CUR_2'
Center( ? Center(
child: Text(schedule.function.value == true ? 'open' : 'close')) child: Text(schedule.function.value == true ? 'open' : 'close'))
else : Center(child: Text(schedule.function.value ? 'On' : 'Off')),
Center(child: Text(schedule.function.value ? 'On' : 'Off')),
Center( Center(
child: Wrap( child: Wrap(
runAlignment: WrapAlignment.center, runAlignment: WrapAlignment.center,
@ -206,27 +206,18 @@ class _ScheduleTableView extends StatelessWidget {
TextButton( TextButton(
style: TextButton.styleFrom(padding: EdgeInsets.zero), style: TextButton.styleFrom(padding: EdgeInsets.zero),
onPressed: () { onPressed: () {
ScheduleDialogHelper.showAddScheduleDialog(context, ScheduleDialogHelper.showAddScheduleDialog(
schedule: ScheduleEntry.fromScheduleModel(schedule), context,
isEdit: true, schedule: ScheduleEntry.fromScheduleModel(schedule),
deviceType: deviceType) isEdit: true,
.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: temp, functionOn: updatedSchedule.function.value,
selectedDays: updatedSchedule.days), selectedDays: updatedSchedule.days),
); );
} }

View File

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

View File

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

View File

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

View File

@ -1,177 +1,173 @@
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()));
} }
}
Future<void> _onFetchDeviceStatus( void _listenToChanges(String deviceId) {
TwoGangGlassSwitchFetchDeviceEvent event, try {
Emitter<TwoGangGlassSwitchState> emit, final ref = FirebaseDatabase.instance.ref(
) async { 'device-status/$deviceId',
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()));
}
}
StreamSubscription<DatabaseEvent>? _deviceStatusSubscription; ref.onValue.listen((event) {
final eventsMap = event.snapshot.value as Map<dynamic, dynamic>;
void _listenToChanges(String deviceId) { List<Status> statusList = [];
try { eventsMap['status'].forEach((element) {
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId'); statusList.add(Status(code: element['code'], value: element['value']));
_deviceStatusSubscription = ref.onValue.listen((DatabaseEvent event) async {
if (event.snapshot.value == null) return;
final usersMap = event.snapshot.value! as Map<dynamic, dynamic>;
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 (_) {}
deviceStatus = TwoGangGlassStatusModel.fromJson(deviceId, statusList);
add(StatusUpdated(deviceStatus));
});
} catch (_) {
log(
'Error listening to changes',
name: 'TwoGangGlassSwitchBloc._listenToChanges',
);
} }
}
Future<void> _onControl( Future<void> _onControl(
TwoGangGlassSwitchControl event, TwoGangGlassSwitchControl event,
Emitter<TwoGangGlassSwitchState> emit, Emitter<TwoGangGlassSwitchState> emit,
) async { ) async {
emit(TwoGangGlassSwitchLoading()); emit(TwoGangGlassSwitchLoading());
_updateLocalValue(event.code, event.value); _updateLocalValue(event.code, event.value);
emit(TwoGangGlassSwitchStatusLoaded(deviceStatus)); emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
try { try {
await controlDeviceService.controlDevice( await controlDeviceService.controlDevice(
deviceUuid: event.deviceId, deviceUuid: event.deviceId,
status: Status(code: event.code, value: event.value), status: Status(code: event.code, value: event.value),
); );
} catch (e) { } catch (e) {
_updateLocalValue(event.code, !event.value); _updateLocalValue(event.code, !event.value);
emit(TwoGangGlassSwitchError(e.toString())); emit(TwoGangGlassSwitchError(e.toString()));
}
} }
}
Future<void> _onBatchControl( Future<void> _onBatchControl(
TwoGangGlassSwitchBatchControl event, TwoGangGlassSwitchBatchControl event,
Emitter<TwoGangGlassSwitchState> emit, Emitter<TwoGangGlassSwitchState> emit,
) async { ) async {
emit(TwoGangGlassSwitchLoading()); emit(TwoGangGlassSwitchLoading());
_updateLocalValue(event.code, event.value); _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)); emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus));
} catch (e) {
emit(TwoGangGlassSwitchError(e.toString()));
}
}
try { Future<void> _onFactoryReset(
await batchControlDevicesService.batchControlDevices( TwoGangGlassFactoryReset event,
uuids: event.deviceIds, Emitter<TwoGangGlassSwitchState> emit,
code: event.code, ) async {
value: event.value, emit(TwoGangGlassSwitchLoading());
); try {
} catch (e) { final response = await DevicesManagementApi().factoryReset(
_updateLocalValue(event.code, !event.value); event.factoryReset,
emit(TwoGangGlassSwitchError(e.toString())); event.deviceId,
);
if (!response) {
emit(TwoGangGlassSwitchError('Failed to reset device'));
} else {
add(TwoGangGlassSwitchFetchDeviceEvent(event.deviceId));
} }
} catch (e) {
emit(TwoGangGlassSwitchError(e.toString()));
} }
}
Future<void> _onFetchBatchStatus( void _onStatusUpdated(
TwoGangGlassSwitchFetchBatchStatusEvent event, StatusUpdated event,
Emitter<TwoGangGlassSwitchState> emit, Emitter<TwoGangGlassSwitchState> emit,
) async { ) {
emit(TwoGangGlassSwitchLoading()); deviceStatus = event.deviceStatus;
try { emit(TwoGangGlassSwitchStatusLoaded(deviceStatus));
final status = await DevicesManagementApi().getBatchStatus(event.deviceIds); }
deviceStatus = TwoGangGlassStatusModel.fromJson(
event.deviceIds.first, void _updateLocalValue(String code, bool value) {
status.status, switch (code) {
); case 'switch_1':
emit(TwoGangGlassSwitchBatchStatusLoaded(deviceStatus)); deviceStatus = deviceStatus.copyWith(switch1: value);
} catch (e) { break;
emit(TwoGangGlassSwitchError(e.toString())); case 'switch_2':
} deviceStatus = deviceStatus.copyWith(switch2: value);
break;
} }
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();
} }
} }

View File

@ -102,8 +102,6 @@ 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',
), ),
@ -120,8 +118,6 @@ 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',
), ),

View File

@ -97,8 +97,6 @@ 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',
), ),
)); ));
}, },
@ -116,8 +114,6 @@ 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',
), ),
)); ));
}, },
@ -125,7 +121,10 @@ 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(

View File

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

View File

@ -18,21 +18,14 @@ 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 = temp; bool? functionOn = schedule?.function.value ?? true;
TimeOfDay selectedTime = initialTime; TimeOfDay selectedTime = initialTime;
List<bool> selectedDays = List.of(initialDays); List<bool> selectedDays = List.of(initialDays);
@ -104,7 +97,8 @@ class ScheduleDialogHelper {
setState(() => selectedDays[i] = v); setState(() => selectedDays[i] = v);
}), }),
const SizedBox(height: 16), const SizedBox(height: 16),
_buildFunctionSwitch(deviceType, ctx, functionOn!, (v) { _buildFunctionSwitch(schedule!.category, ctx, functionOn!,
(v) {
setState(() => functionOn = v); setState(() => functionOn = v);
}), }),
], ],
@ -120,29 +114,32 @@ class ScheduleDialogHelper {
), ),
), ),
SizedBox( SizedBox(
width: 100, width: 100,
child: ElevatedButton( child: ElevatedButton(
onPressed: () { onPressed: () {
dynamic temp; dynamic temp;
if (deviceType == 'CUR_2') { if (schedule?.category == 'CUR_2') {
temp = functionOn! ? 'open' : 'close'; temp = functionOn! ? 'open' : 'close';
} else { } else {
temp = functionOn; temp = functionOn;
} }
final entry = ScheduleEntry( print(temp);
category: schedule?.category ?? 'switch_1', final entry = ScheduleEntry(
time: _formatTimeOfDayToISO(selectedTime), category: schedule?.category ?? 'switch_1',
function: Status( time: _formatTimeOfDayToISO(selectedTime),
code: code ?? 'switch_1', function: Status(
value: temp, code: code ?? 'switch_1',
), value: temp,
days: _convertSelectedDaysToStrings(selectedDays), // functionOn,
scheduleId: schedule.scheduleId, ),
); days: _convertSelectedDaysToStrings(selectedDays),
Navigator.pop(ctx, entry); scheduleId: schedule?.scheduleId,
}, );
child: const Text('Save'), Navigator.pop(ctx, entry);
)), },
child: const Text('Save'),
),
),
], ],
); );
}, },

View File

@ -84,8 +84,6 @@ 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',
), ),
)); ));
}, },

View File

@ -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!;

View File

@ -34,8 +34,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
return Dialog( return Dialog(
child: Container( child: Container(
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: Colors.white, color: Colors.white, borderRadius: BorderRadius.all(Radius.circular(20))),
borderRadius: BorderRadius.all(Radius.circular(20))),
width: 900, width: 900,
child: Column( child: Column(
children: [ children: [
@ -64,8 +63,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
children: [ children: [
_buildStep1Indicator(1, "Basics", _blocRole), _buildStep1Indicator(1, "Basics", _blocRole),
_buildStep2Indicator(2, "Spaces", _blocRole), _buildStep2Indicator(2, "Spaces", _blocRole),
_buildStep3Indicator( _buildStep3Indicator(3, "Role & Permissions", _blocRole),
3, "Role & Permissions", _blocRole),
], ],
), ),
), ),
@ -107,32 +105,18 @@ 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( _blocRole.add(const CheckStepStatus(isEditUser: false));
isEditUser: false));
} else if (currentStep == 3) { } else if (currentStep == 3) {
_blocRole _blocRole.add(const CheckSpacesStepStatus());
.add(const CheckSpacesStepStatus());
} }
} else { } else {
_blocRole _blocRole.add(SendInviteUsers(context: context));
.add(SendInviteUsers(context: context));
} }
}); });
}, },
@ -140,11 +124,8 @@ 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 == _blocRole.isCompleteBasics == false ||
false || _blocRole.isCompleteRolePermissions == false) &&
_blocRole
.isCompleteRolePermissions ==
false) &&
currentStep == 3 currentStep == 3
? ColorsManager.grayColor ? ColorsManager.grayColor
: ColorsManager.secondaryColor), : ColorsManager.secondaryColor),
@ -162,7 +143,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
Widget _getFormContent() { Widget _getFormContent() {
switch (currentStep) { switch (currentStep) {
case 1: case 1:
return BasicsView( return const BasicsView(
userId: '', userId: '',
); );
case 2: case 2:
@ -215,12 +196,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
label, label,
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
color: currentStep == step color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
? ColorsManager.blackColor fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
: ColorsManager.greyColor,
fontWeight: currentStep == step
? FontWeight.bold
: FontWeight.normal,
), ),
), ),
], ],
@ -283,12 +260,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
label, label,
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
color: currentStep == step color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
? ColorsManager.blackColor fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
: ColorsManager.greyColor,
fontWeight: currentStep == step
? FontWeight.bold
: FontWeight.normal,
), ),
), ),
], ],
@ -345,12 +318,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
label, label,
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
color: currentStep == step color: currentStep == step ? ColorsManager.blackColor : ColorsManager.greyColor,
? ColorsManager.blackColor fontWeight: currentStep == step ? FontWeight.bold : FontWeight.normal,
: ColorsManager.greyColor,
fontWeight: currentStep == step
? FontWeight.bold
: FontWeight.normal,
), ),
), ),
], ],

View File

@ -1,12 +1,9 @@
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';
@ -14,9 +11,7 @@ import 'package:syncrow_web/utils/style.dart';
class BasicsView extends StatelessWidget { class BasicsView extends StatelessWidget {
final String? userId; final String? userId;
Timer? _debounce; const BasicsView({super.key, this.userId = ''});
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) {
@ -26,7 +21,6 @@ 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: [
@ -214,14 +208,6 @@ 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';

View File

@ -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 {
scenes.addAll(await SceneApi.getScenes(
createRoutineBloc.selectedSpaceId,
createRoutineBloc.selectedCommunityId,
projectUuid));
}
emit(state.copyWith( emit(state.copyWith(
scenes: scenes, scenes: scenes,
isLoading: false,
));
} catch (e) {
emit(state.copyWith(
isLoading: false, isLoading: false,
loadScenesErrorMessage: 'Failed to load scenes', ));
errorMessage: '', } catch (e) {
loadAutomationErrorMessage: '', emit(state.copyWith(
scenes: scenes)); 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,16 +936,12 @@ Future<void> _onLoadScenes(
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) { devices.addAll(await DevicesManagementApi()
devices.addAll(await DevicesManagementApi() .fetchDevices(projectUuid, spacesId: spacesList));
.fetchDevices(communityId, spaceId, projectUuid));
}
} }
} else { } else {
devices.addAll(await DevicesManagementApi().fetchDevices( devices.addAll(await DevicesManagementApi().fetchDevices(projectUuid,
createRoutineBloc.selectedCommunityId, spacesId: [createRoutineBloc.selectedSpaceId]));
createRoutineBloc.selectedSpaceId,
projectUuid));
} }
emit(state.copyWith(isLoading: false, devices: devices)); emit(state.copyWith(isLoading: false, devices: devices));

View File

@ -58,9 +58,7 @@ class CurtainHelper {
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
DialogHeader(dialogType == 'THEN' const DialogHeader('AC Functions'),
? 'Curtain Functions'
: 'Curtain Conditions'),
Expanded( Expanded(
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,

View File

@ -58,14 +58,11 @@ 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,

View File

@ -2,8 +2,10 @@ 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';
@ -21,8 +23,8 @@ class VisitorPasswordDialog extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final size = MediaQuery.of(context).size; Size size = MediaQuery.of(context).size;
final text = Theme.of(context) var text = Theme.of(context)
.textTheme .textTheme
.bodySmall! .bodySmall!
.copyWith(color: Colors.black, fontSize: 13); .copyWith(color: Colors.black, fontSize: 13);
@ -39,7 +41,8 @@ class VisitorPasswordDialog extends StatelessWidget {
title: 'Sent Successfully', title: 'Sent Successfully',
widgeta: Column( widgeta: Column(
children: [ children: [
if (visitorBloc.passwordStatus!.failedOperations.isNotEmpty) if (visitorBloc
.passwordStatus!.failedOperations.isNotEmpty)
Column( Column(
children: [ children: [
const Text('Failed Devices'), const Text('Failed Devices'),
@ -53,19 +56,22 @@ class VisitorPasswordDialog extends StatelessWidget {
.passwordStatus!.failedOperations.length, .passwordStatus!.failedOperations.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return Container( return Container(
margin: const EdgeInsets.all(5), margin: EdgeInsets.all(5),
decoration: containerDecoration, decoration: containerDecoration,
height: 45, height: 45,
child: Center( child: Center(
child: Text(visitorBloc.passwordStatus! child: Text(visitorBloc
.failedOperations[index].deviceName)), .passwordStatus!
.failedOperations[index]
.deviceName)),
); );
}, },
), ),
), ),
], ],
), ),
if (visitorBloc.passwordStatus!.successOperations.isNotEmpty) if (visitorBloc
.passwordStatus!.successOperations.isNotEmpty)
Column( Column(
children: [ children: [
const Text('Success Devices'), const Text('Success Devices'),
@ -79,12 +85,14 @@ class VisitorPasswordDialog extends StatelessWidget {
.passwordStatus!.successOperations.length, .passwordStatus!.successOperations.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
return Container( return Container(
margin: const EdgeInsets.all(5), margin: EdgeInsets.all(5),
decoration: containerDecoration, decoration: containerDecoration,
height: 45, height: 45,
child: Center( child: Center(
child: Text(visitorBloc.passwordStatus! child: Text(visitorBloc
.successOperations[index].deviceName)), .passwordStatus!
.successOperations[index]
.deviceName)),
); );
}, },
), ),
@ -107,14 +115,16 @@ 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);
final isRepeat = bool 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, fontSize: 24, color: Colors.black), fontWeight: FontWeight.w400,
fontSize: 24,
color: Colors.black),
), ),
content: state is LoadingInitialState content: state is LoadingInitialState
? const Center(child: CircularProgressIndicator()) ? const Center(child: CircularProgressIndicator())
@ -300,12 +310,14 @@ class VisitorPasswordDialog extends StatelessWidget {
visitorBloc.accessTypeSelected == visitorBloc.accessTypeSelected ==
'Offline Password') { 'Offline Password') {
visitorBloc.add(SelectTimeEvent( visitorBloc.add(SelectTimeEvent(
context: context, isEffective: false));
} else {
visitorBloc.add(SelectTimeVisitorPassword(
context: context, context: context,
isStart: false, isEffective: false));
isRepeat: false)); } else {
visitorBloc.add(
SelectTimeVisitorPassword(
context: context,
isStart: false,
isRepeat: false));
} }
}, },
startTime: () { startTime: () {
@ -314,28 +326,31 @@ class VisitorPasswordDialog extends StatelessWidget {
visitorBloc.accessTypeSelected == visitorBloc.accessTypeSelected ==
'Offline Password') { 'Offline Password') {
visitorBloc.add(SelectTimeEvent( visitorBloc.add(SelectTimeEvent(
context: context, isEffective: true));
} else {
visitorBloc.add(SelectTimeVisitorPassword(
context: context, context: context,
isStart: true, isEffective: true));
isRepeat: false)); } else {
visitorBloc.add(
SelectTimeVisitorPassword(
context: context,
isStart: true,
isRepeat: false));
} }
}, },
firstString: firstString: (visitorBloc
(visitorBloc.usageFrequencySelected == .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, : visitorBloc.endTimeAccess.toString(),
icon: Assets.calendarIcon), icon: Assets.calendarIcon),
const SizedBox( const SizedBox(
height: 10, height: 10,
@ -395,7 +410,8 @@ class VisitorPasswordDialog extends StatelessWidget {
child: CupertinoSwitch( child: CupertinoSwitch(
value: visitorBloc.repeat, value: visitorBloc.repeat,
onChanged: (value) { onChanged: (value) {
visitorBloc.add(ToggleRepeatEvent()); visitorBloc
.add(ToggleRepeatEvent());
}, },
applyTheme: true, applyTheme: true,
), ),
@ -426,7 +442,8 @@ class VisitorPasswordDialog extends StatelessWidget {
}, },
).then((listDevice) { ).then((listDevice) {
if (listDevice != null) { if (listDevice != null) {
visitorBloc.selectedDevices = listDevice; visitorBloc.selectedDevices =
listDevice;
} }
}); });
}, },
@ -438,7 +455,8 @@ class VisitorPasswordDialog extends StatelessWidget {
.bodySmall! .bodySmall!
.copyWith( .copyWith(
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: ColorsManager.whiteColors, color:
ColorsManager.whiteColors,
fontSize: 12), fontSize: 12),
), ),
), ),
@ -477,30 +495,37 @@ 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 == 'One-Time' && if (visitorBloc.usageFrequencySelected ==
visitorBloc.accessTypeSelected == 'Offline Password') { 'One-Time' &&
visitorBloc.accessTypeSelected ==
'Offline Password') {
setPasswordFunction(context, size, visitorBloc); setPasswordFunction(context, size, visitorBloc);
} else if (visitorBloc.usageFrequencySelected == } else if (visitorBloc.usageFrequencySelected ==
'Periodic' && 'Periodic' &&
visitorBloc.accessTypeSelected == 'Offline Password') { visitorBloc.accessTypeSelected ==
'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: 'Please select Access Period to continue', message:
'Please select Access Period to continue',
title: 'Access Period'); title: 'Access Period');
} }
} else if (visitorBloc.endTimeAccess != 'End Time' && } else if (visitorBloc.endTimeAccess.toString() !=
visitorBloc.startTimeAccess != 'Start Time') { 'End 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(context, size, visitorBloc); setPasswordFunction(
context, size, visitorBloc);
} else { } else {
visitorBloc.stateDialog( visitorBloc.stateDialog(
context: context, context: context,
@ -514,13 +539,15 @@ class VisitorPasswordDialog extends StatelessWidget {
} else { } else {
visitorBloc.stateDialog( visitorBloc.stateDialog(
context: context, context: context,
message: 'Please select Access Period to continue', message:
'Please select Access Period to continue',
title: 'Access Period'); title: 'Access Period');
} }
} else { } else {
visitorBloc.stateDialog( visitorBloc.stateDialog(
context: context, context: context,
message: 'Please select Access Period to continue', message:
'Please select Access Period to continue',
title: 'Access Period'); title: 'Access Period');
} }
} else { } else {
@ -566,17 +593,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: const Center( child: Center(
child: CircularProgressIndicator(), // Display a loading spinner child:
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.13, height: size.height * 0.25,
child: Column( child: Column(
children: [ children: [
Column( Column(
@ -590,16 +617,13 @@ 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: 24, fontSize: 30,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: Colors.black, color: Colors.black,
), ),
@ -607,6 +631,15 @@ 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,
),
),
], ],
), ),
), ),
@ -635,12 +668,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 == 'Online Password') { visitorBloc.accessTypeSelected ==
'Online Password') {
visitorBloc.add(OnlineOneTimePasswordEvent( visitorBloc.add(OnlineOneTimePasswordEvent(
context: context, context: context,
passwordName: visitorBloc.userNameController.text, passwordName: visitorBloc.userNameController.text,
@ -648,7 +681,8 @@ class VisitorPasswordDialog extends StatelessWidget {
)); ));
} else if (visitorBloc.usageFrequencySelected == } else if (visitorBloc.usageFrequencySelected ==
'Periodic' && 'Periodic' &&
visitorBloc.accessTypeSelected == 'Online Password') { visitorBloc.accessTypeSelected ==
'Online Password') {
visitorBloc.add(OnlineMultipleTimePasswordEvent( visitorBloc.add(OnlineMultipleTimePasswordEvent(
passwordName: visitorBloc.userNameController.text, passwordName: visitorBloc.userNameController.text,
email: visitorBloc.emailController.text, email: visitorBloc.emailController.text,
@ -659,7 +693,8 @@ class VisitorPasswordDialog extends StatelessWidget {
)); ));
} else if (visitorBloc.usageFrequencySelected == } else if (visitorBloc.usageFrequencySelected ==
'One-Time' && 'One-Time' &&
visitorBloc.accessTypeSelected == 'Offline Password') { visitorBloc.accessTypeSelected ==
'Offline Password') {
visitorBloc.add(OfflineOneTimePasswordEvent( visitorBloc.add(OfflineOneTimePasswordEvent(
context: context, context: context,
passwordName: visitorBloc.userNameController.text, passwordName: visitorBloc.userNameController.text,
@ -667,7 +702,8 @@ class VisitorPasswordDialog extends StatelessWidget {
)); ));
} else if (visitorBloc.usageFrequencySelected == } else if (visitorBloc.usageFrequencySelected ==
'Periodic' && 'Periodic' &&
visitorBloc.accessTypeSelected == 'Offline Password') { visitorBloc.accessTypeSelected ==
'Offline Password') {
visitorBloc.add(OfflineMultipleTimePasswordEvent( visitorBloc.add(OfflineMultipleTimePasswordEvent(
passwordName: visitorBloc.userNameController.text, passwordName: visitorBloc.userNameController.text,
email: visitorBloc.emailController.text, email: visitorBloc.emailController.text,
@ -679,7 +715,7 @@ class VisitorPasswordDialog extends StatelessWidget {
} }
}, },
child: Text( child: Text(
'Confirm', 'Ok',
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,

View File

@ -13,15 +13,13 @@ import 'package:syncrow_web/utils/constants/api_const.dart';
class DevicesManagementApi { class DevicesManagementApi {
Future<List<AllDevicesModel>> fetchDevices( Future<List<AllDevicesModel>> fetchDevices(
String communityId, String spaceId, String projectId) async { String projectId, {
List<String>? spacesId,
}) async {
try { try {
final response = await HTTPService().get( final response = await HTTPService().get(
path: communityId.isNotEmpty && spaceId.isNotEmpty queryParameters: {if (spacesId != null) 'spaces': spacesId},
? ApiEndpoints.getSpaceDevices path: ApiEndpoints.getAllDevices.replaceAll('{projectId}', projectId),
.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'];
@ -416,5 +414,4 @@ class DevicesManagementApi {
); );
return response; return response;
} }
} }

View File

@ -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}/communities/{communityUuid}/spaces/{spaceUuid}/devices'; '/projects/{projectId}/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';

View File

@ -14,7 +14,8 @@ 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 = 'assets/images/Password_invisible.svg'; static const String invisiblePassword =
'assets/images/Password_invisible.svg';
static const String visiblePassword = 'assets/images/password_visible.svg'; static const String 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 =
@ -33,7 +34,8 @@ 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 = 'assets/icons/motionless_detection.svg'; static const String motionlessDetection =
'assets/icons/motionless_detection.svg';
static const String acHeating = 'assets/icons/ac_heating.svg'; static const String 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';
@ -70,19 +72,22 @@ 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 = 'assets/icons/automation_functions/doorbell.svg'; static const String doorbell =
'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 = 'assets/icons/automation_functions/lock_alarm.svg'; static const String lockAlarm =
'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 = 'assets/icons/automation_functions/presence.svg'; static const String presence =
'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 =
@ -99,12 +104,15 @@ 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 = 'assets/icons/sensor_presence_ic.svg'; static const String sensorPresenceIcon =
'assets/icons/sensor_presence_ic.svg';
static const String sensorVacantIcon = 'assets/icons/sensor_vacant_ic.svg'; static const String 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 = 'assets/icons/presence_record_ic.svg'; static const String presenceRecordIcon =
static const String helpDescriptionIcon = 'assets/icons/help_description_ic.svg'; 'assets/icons/presence_record_ic.svg';
static const String helpDescriptionIcon =
'assets/icons/help_description_ic.svg';
static const String lightPulp = 'assets/icons/light_pulb.svg'; static const String lightPulp = 'assets/icons/light_pulb.svg';
static const String acDevice = 'assets/icons/ac_device.svg'; static const String acDevice = 'assets/icons/ac_device.svg';
@ -158,10 +166,12 @@ 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 = 'assets/icons/textfield_search_icon.svg'; static const String textFieldSearch =
'assets/icons/textfield_search_icon.svg';
static const String roundedAddIcon = 'assets/icons/rounded_add_icon.svg'; static const String 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 = 'assets/icons/smart_thermostat_icon.svg'; static const String smartThermostatIcon =
'assets/icons/smart_thermostat_icon.svg';
static const String smartLightIcon = 'assets/icons/smart_light_icon.svg'; static const String 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';
@ -209,7 +219,8 @@ 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 = 'assets/icons/water_leak_detected.svg'; static const String waterLeakDetected =
'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';
@ -280,13 +291,16 @@ 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 = 'assets/icons/functions_icons/ac_power.svg'; static const String assetsAcPower =
'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 = 'assets/icons/functions_icons/freezing.svg'; static const String assetsFreezing =
static const String assetsFanSpeed = 'assets/icons/functions_icons/fan_speed.svg'; 'assets/icons/functions_icons/freezing.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 =
@ -295,7 +309,8 @@ 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 = 'assets/icons/functions_icons/ac_fan_low.svg'; static const String assetsAcFanLow =
'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 =
@ -314,7 +329,8 @@ 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 = 'assets/icons/functions_icons/indicator.svg'; static const String assetsIndicator =
'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 =
@ -327,7 +343,8 @@ 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 = 'assets/icons/functions_icons/reset_off.svg'; static const String assetsResetOff =
'assets/icons/functions_icons/reset_off.svg';
// Assets for automation_functions // Assets for automation_functions
static const String assetsCardUnlock = static const String assetsCardUnlock =
@ -371,13 +388,15 @@ 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 = 'assets/icons/rectangle_check_box.png'; static const String rectangleCheckBox =
'assets/icons/rectangle_check_box.png';
static const String CheckBoxChecked = 'assets/icons/box_checked.png'; static const String 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 = 'assets/icons/current_process_icon.svg'; static const String currentProcessIcon =
'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';
@ -398,9 +417,11 @@ 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 = 'assets/icons/scenesPlayIconCheck.png'; static const String scenesPlayIconCheck =
'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 = 'assets/icons/current_distance_icon.svg'; static const String currentDistanceIcon =
'assets/icons/current_distance_icon.svg';
static const String farDetectionIcon = 'assets/icons/far_detection_icon.svg'; static const String farDetectionIcon = 'assets/icons/far_detection_icon.svg';
static const String motionDetectionSensitivityIcon = static const String motionDetectionSensitivityIcon =
@ -423,29 +444,44 @@ 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 = 'assets/icons/communication_fault.svg'; static const String communicationFault =
'assets/icons/communication_fault.svg';
static const String radarFault = 'assets/icons/radar_fault.svg'; static const String radarFault = 'assets/icons/radar_fault.svg';
static const String selfTestingSuccess = 'assets/icons/self_testing_success.svg'; static const String selfTestingSuccess =
static const String selfTestingFailure = 'assets/icons/self_testing_failure.svg'; 'assets/icons/self_testing_success.svg';
static const String selfTestingTimeout = 'assets/icons/self_testing_timeout.svg'; static const String selfTestingFailure =
'assets/icons/self_testing_failure.svg';
static const String selfTestingTimeout =
'assets/icons/self_testing_timeout.svg';
static const String movingSpeed = 'assets/icons/moving_speed.svg'; static const String 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 = 'assets/icons/spatial_static_value.svg'; static const String spatialStaticValue =
static const String spatialMotionValue = 'assets/icons/spatial_motion_value.svg'; 'assets/icons/spatial_static_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 = 'assets/icons/sensitivity_feature_1.svg'; static const String sensitivityFeature1 =
static const String sensitivityFeature2 = 'assets/icons/sensitivity_feature_2.svg'; 'assets/icons/sensitivity_feature_1.svg';
static const String sensitivityFeature3 = 'assets/icons/sensitivity_feature_3.svg'; static const String sensitivityFeature2 =
static const String sensitivityFeature4 = 'assets/icons/sensitivity_feature_4.svg'; 'assets/icons/sensitivity_feature_2.svg';
static const String sensitivityFeature5 = 'assets/icons/sensitivity_feature_5.svg'; static const String sensitivityFeature3 =
static const String sensitivityFeature6 = 'assets/icons/sensitivity_feature_6.svg'; 'assets/icons/sensitivity_feature_3.svg';
static const String sensitivityFeature7 = 'assets/icons/sensitivity_feature_7.svg'; static const String sensitivityFeature4 =
static const String sensitivityFeature8 = 'assets/icons/sensitivity_feature_8.svg'; 'assets/icons/sensitivity_feature_4.svg';
static const String sensitivityFeature9 = 'assets/icons/sensitivity_feature_9.svg'; static const String sensitivityFeature5 =
'assets/icons/sensitivity_feature_5.svg';
static const String sensitivityFeature6 =
'assets/icons/sensitivity_feature_6.svg';
static const String sensitivityFeature7 =
'assets/icons/sensitivity_feature_7.svg';
static const String sensitivityFeature8 =
'assets/icons/sensitivity_feature_8.svg';
static const String sensitivityFeature9 =
'assets/icons/sensitivity_feature_9.svg';
static const String deviceTagIcon = 'assets/icons/device_tag_ic.svg'; static const String 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';
@ -453,10 +489,13 @@ 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 = 'assets/icons/refresh_status_icon.svg'; static const String refreshStatusIcon =
static const String energyConsumedIcon = 'assets/icons/energy_consumed_icon.svg'; 'assets/icons/refresh_status_icon.svg';
static const String energyConsumedIcon =
'assets/icons/energy_consumed_icon.svg';
static const String closeSettingsIcon = 'assets/icons/close_settings_icon.svg'; static const String closeSettingsIcon =
'assets/icons/close_settings_icon.svg';
static const String editNameIconSettings = static const String editNameIconSettings =
'assets/icons/edit_name_icon_settings.svg'; 'assets/icons/edit_name_icon_settings.svg';
@ -469,11 +508,4 @@ 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';
} }