Compare commits

..

4 Commits

Author SHA1 Message Date
b97183fb61 SP-1801 2025-06-28 15:47:42 +04:00
07dfe6b206 Merge branch 'dev' of https://github.com/SyncrowIOT/web into dev 2025-06-28 13:16:16 +03:00
c4fd90b3bc testing heatmap fixes. 2025-06-28 13:16:06 +03:00
bbcb947313 uses UTC dates as an attempt to fix heat-map's rendering bug. (#304)
<!--
  Thanks for contributing!

Provide a description of your changes below and a general summary in the
title

Please look at the following checklist to ensure that your PR can be
accepted quickly:
-->

## Description

Uses UTC dates as an attempt to fix heatmap's rendering bug 

## Type of Change

<!--- Put an `x` in all the boxes that apply: -->

- [ ]  New feature (non-breaking change which adds functionality)
- [x] 🛠️ Bug fix (non-breaking change which fixes an issue)
- [ ]  Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] 🧹 Code refactor
- [ ]  Build configuration change
- [ ] 📝 Documentation
- [ ] 🗑️ Chore
2025-06-27 22:15:05 +03:00
3 changed files with 27 additions and 41 deletions

View File

@ -9,8 +9,13 @@ import 'package:syncrow_web/pages/analytics/modules/occupancy/widgets/occupancy_
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
class OccupancyHeatMap extends StatelessWidget { class OccupancyHeatMap extends StatelessWidget {
const OccupancyHeatMap({required this.heatMapData, super.key}); const OccupancyHeatMap({
required this.heatMapData,
required this.selectedDate,
super.key,
});
final Map<DateTime, int> heatMapData; final Map<DateTime, int> heatMapData;
final DateTime selectedDate;
static const _cellSize = 16.0; static const _cellSize = 16.0;
static const _totalWeeks = 53; static const _totalWeeks = 53;
@ -20,7 +25,7 @@ class OccupancyHeatMap extends StatelessWidget {
: 0; : 0;
DateTime _getStartingDate() { DateTime _getStartingDate() {
final jan1 = DateTime.utc(DateTime.now().year, 1, 1); final jan1 = DateTime.utc(selectedDate.year, 1, 1);
final startOfWeek = jan1.subtract(Duration(days: jan1.weekday - 1)); final startOfWeek = jan1.subtract(Duration(days: jan1.weekday - 1));
return startOfWeek; return startOfWeek;
} }

View File

@ -70,6 +70,8 @@ class OccupancyHeatMapBox extends StatelessWidget {
const SizedBox(height: 20), const SizedBox(height: 20),
Expanded( Expanded(
child: OccupancyHeatMap( child: OccupancyHeatMap(
selectedDate:
context.watch<AnalyticsDatePickerBloc>().state.yearlyDate,
heatMapData: state.heatMapData.asMap().map( heatMapData: state.heatMapData.asMap().map(
(_, value) => MapEntry( (_, value) => MapEntry(
value.eventDate, value.eventDate,

View File

@ -45,8 +45,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
) async { ) async {
emit(AcsLoadingState()); emit(AcsLoadingState());
try { try {
final status = final status = await DevicesManagementApi().getDeviceStatus(event.deviceId);
await DevicesManagementApi().getDeviceStatus(event.deviceId);
deviceStatus = AcStatusModel.fromJson(event.deviceId, status.status); deviceStatus = AcStatusModel.fromJson(event.deviceId, status.status);
if (deviceStatus.countdown1 != 0) { if (deviceStatus.countdown1 != 0) {
final totalMinutes = deviceStatus.countdown1 * 6; final totalMinutes = deviceStatus.countdown1 * 6;
@ -74,22 +73,18 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
void _listenToChanges(String deviceId) { void _listenToChanges(String deviceId) {
try { try {
final ref = FirebaseDatabase.instance.ref('device-status/$deviceId'); final ref = FirebaseDatabase.instance.ref('device-status/$deviceId');
_deviceStatusSubscription = _deviceStatusSubscription = ref.onValue.listen((DatabaseEvent event) async {
ref.onValue.listen((DatabaseEvent event) async {
if (event.snapshot.value == null) return; if (event.snapshot.value == null) return;
Map<dynamic, dynamic> usersMap = final usersMap = event.snapshot.value! as Map<dynamic, dynamic>;
event.snapshot.value as Map<dynamic, dynamic>;
List<Status> statusList = []; final statusList = <Status>[];
usersMap['status'].forEach((element) { usersMap['status'].forEach((element) {
statusList statusList.add(Status(code: element['code'], value: element['value']));
.add(Status(code: element['code'], value: element['value']));
}); });
deviceStatus = deviceStatus = AcStatusModel.fromJson(usersMap['productUuid'], statusList);
AcStatusModel.fromJson(usersMap['productUuid'], statusList);
print('Device status updated: ${deviceStatus.acSwitch}'); print('Device status updated: ${deviceStatus.acSwitch}');
if (!isClosed) { if (!isClosed) {
@ -111,21 +106,14 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
AcControlEvent event, AcControlEvent event,
Emitter<AcsState> emit, Emitter<AcsState> emit,
) async { ) async {
emit(AcsLoadingState());
try { try {
final success = await controlDeviceService.controlDevice( _updateDeviceFunctionFromCode(event.code, event.value);
emit(ACStatusLoaded(status: deviceStatus));
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),
); );
_updateDeviceFunctionFromCode(event.code, event.value); } catch (e) {}
emit(ACStatusLoaded(status: deviceStatus));
if (!success) {
emit(const AcsFailedState(error: 'Failed to control device'));
}
} catch (e) {
emit(AcsFailedState(error: e.toString()));
}
} }
FutureOr<void> _onFetchAcBatchStatus( FutureOr<void> _onFetchAcBatchStatus(
@ -134,10 +122,8 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
) async { ) async {
emit(AcsLoadingState()); emit(AcsLoadingState());
try { try {
final status = final status = await DevicesManagementApi().getBatchStatus(event.devicesIds);
await DevicesManagementApi().getBatchStatus(event.devicesIds); deviceStatus = AcStatusModel.fromJson(event.devicesIds.first, status.status);
deviceStatus =
AcStatusModel.fromJson(event.devicesIds.first, status.status);
emit(ACStatusLoaded(status: deviceStatus)); emit(ACStatusLoaded(status: deviceStatus));
} catch (e) { } catch (e) {
emit(AcsFailedState(error: e.toString())); emit(AcsFailedState(error: e.toString()));
@ -148,23 +134,16 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
AcBatchControlEvent event, AcBatchControlEvent event,
Emitter<AcsState> emit, Emitter<AcsState> emit,
) async { ) async {
emit(AcsLoadingState());
_updateDeviceFunctionFromCode(event.code, event.value); _updateDeviceFunctionFromCode(event.code, event.value);
emit(ACStatusLoaded(status: deviceStatus)); emit(ACStatusLoaded(status: deviceStatus));
try { try {
final success = await batchControlDevicesService.batchControlDevices( await batchControlDevicesService.batchControlDevices(
uuids: event.devicesIds, uuids: event.devicesIds,
code: event.code, code: event.code,
value: event.value, value: event.value,
); );
} catch (e) {}
if (!success) {
emit(const AcsFailedState(error: 'Failed to control devices'));
}
} catch (e) {
emit(AcsFailedState(error: e.toString()));
}
} }
Future<void> _onFactoryReset( Future<void> _onFactoryReset(
@ -197,8 +176,8 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
void _handleIncreaseTime(IncreaseTimeEvent event, Emitter<AcsState> emit) { void _handleIncreaseTime(IncreaseTimeEvent event, Emitter<AcsState> emit) {
if (state is! ACStatusLoaded) return; if (state is! ACStatusLoaded) return;
final currentState = state as ACStatusLoaded; final currentState = state as ACStatusLoaded;
int newHours = scheduledHours; var newHours = scheduledHours;
int newMinutes = scheduledMinutes + 30; var newMinutes = scheduledMinutes + 30;
newHours += newMinutes ~/ 60; newHours += newMinutes ~/ 60;
newMinutes = newMinutes % 60; newMinutes = newMinutes % 60;
if (newHours > 23) { if (newHours > 23) {
@ -220,7 +199,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
) { ) {
if (state is! ACStatusLoaded) return; if (state is! ACStatusLoaded) return;
final currentState = state as ACStatusLoaded; final currentState = state as ACStatusLoaded;
int totalMinutes = (scheduledHours * 60) + scheduledMinutes; var totalMinutes = (scheduledHours * 60) + scheduledMinutes;
totalMinutes = (totalMinutes - 30).clamp(0, 1440); totalMinutes = (totalMinutes - 30).clamp(0, 1440);
scheduledHours = totalMinutes ~/ 60; scheduledHours = totalMinutes ~/ 60;
scheduledMinutes = totalMinutes % 60; scheduledMinutes = totalMinutes % 60;
@ -293,7 +272,7 @@ class AcBloc extends Bloc<AcsEvent, AcsState> {
void _startCountdownTimer(Emitter<AcsState> emit) { void _startCountdownTimer(Emitter<AcsState> emit) {
_countdownTimer?.cancel(); _countdownTimer?.cancel();
int totalSeconds = (scheduledHours * 3600) + (scheduledMinutes * 60); var totalSeconds = (scheduledHours * 3600) + (scheduledMinutes * 60);
_countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) { _countdownTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
if (totalSeconds > 0) { if (totalSeconds > 0) {