mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 07:07:19 +00:00
Merge branch 'SP-1703-fe-build-device-overview-page_curtain_module' of https://github.com/SyncrowIOT/web into SP-1703-fe-build-device-overview-page_curtain_module
This commit is contained in:
@ -21,11 +21,11 @@ class OccupancyHeatMapModel extends Equatable {
|
|||||||
|
|
||||||
return OccupancyHeatMapModel(
|
return OccupancyHeatMapModel(
|
||||||
uuid: json['uuid'] as String? ?? '',
|
uuid: json['uuid'] as String? ?? '',
|
||||||
eventDate: DateTime(
|
eventDate: DateTime.utc(
|
||||||
int.parse(year ?? '2025'),
|
int.parse(year ?? '2025'),
|
||||||
int.parse(month ?? '1'),
|
int.parse(month ?? '1'),
|
||||||
int.parse(day ?? '1'),
|
int.parse(day ?? '1'),
|
||||||
).toUtc(),
|
),
|
||||||
countTotalPresenceDetected: num.parse(
|
countTotalPresenceDetected: num.parse(
|
||||||
json['count_total_presence_detected']?.toString() ?? '0',
|
json['count_total_presence_detected']?.toString() ?? '0',
|
||||||
).toInt(),
|
).toInt(),
|
||||||
|
@ -14,14 +14,17 @@ class TotalEnergyConsumptionChart extends StatelessWidget {
|
|||||||
return Expanded(
|
return Expanded(
|
||||||
child: LineChart(
|
child: LineChart(
|
||||||
LineChartData(
|
LineChartData(
|
||||||
|
maxY: chartData.isEmpty
|
||||||
|
? null
|
||||||
|
: chartData.map((e) => e.value).reduce((a, b) => a > b ? a : b) + 250,
|
||||||
clipData: const FlClipData.vertical(),
|
clipData: const FlClipData.vertical(),
|
||||||
titlesData: EnergyManagementChartsHelper.titlesData(
|
titlesData: EnergyManagementChartsHelper.titlesData(
|
||||||
context,
|
context,
|
||||||
leftTitlesInterval: 250,
|
leftTitlesInterval: 500,
|
||||||
),
|
),
|
||||||
gridData: EnergyManagementChartsHelper.gridData().copyWith(
|
gridData: EnergyManagementChartsHelper.gridData().copyWith(
|
||||||
checkToShowHorizontalLine: (value) => true,
|
checkToShowHorizontalLine: (value) => true,
|
||||||
horizontalInterval: 250,
|
horizontalInterval: 500,
|
||||||
),
|
),
|
||||||
borderData: EnergyManagementChartsHelper.borderData(),
|
borderData: EnergyManagementChartsHelper.borderData(),
|
||||||
lineTouchData: EnergyManagementChartsHelper.lineTouchData(),
|
lineTouchData: EnergyManagementChartsHelper.lineTouchData(),
|
||||||
@ -29,7 +32,6 @@ class TotalEnergyConsumptionChart extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
duration: Duration.zero,
|
duration: Duration.zero,
|
||||||
curve: Curves.easeIn,
|
curve: Curves.easeIn,
|
||||||
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -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,14 +25,14 @@ class OccupancyHeatMap extends StatelessWidget {
|
|||||||
: 0;
|
: 0;
|
||||||
|
|
||||||
DateTime _getStartingDate() {
|
DateTime _getStartingDate() {
|
||||||
final jan1 = DateTime(DateTime.now().year, 1, 1).toUtc();
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<OccupancyPaintItem> _generatePaintItems(DateTime startDate) {
|
List<OccupancyPaintItem> _generatePaintItems(DateTime startDate) {
|
||||||
return List.generate(_totalWeeks * 7, (index) {
|
return List.generate(_totalWeeks * 7, (index) {
|
||||||
final date = startDate.toUtc().add(Duration(days: index));
|
final date = startDate.add(Duration(days: index));
|
||||||
final value = heatMapData[date] ?? 0;
|
final value = heatMapData[date] ?? 0;
|
||||||
return OccupancyPaintItem(index: index, value: value, date: date);
|
return OccupancyPaintItem(index: index, value: value, date: date);
|
||||||
});
|
});
|
||||||
|
@ -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,
|
||||||
|
@ -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,25 @@ 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);
|
||||||
|
|
||||||
|
deviceStatus = AcStatusModel.fromJson(usersMap['productUuid'], statusList);
|
||||||
|
print('Device status updated: ${deviceStatus.acSwitch}');
|
||||||
|
|
||||||
|
|
||||||
if (!isClosed) {
|
if (!isClosed) {
|
||||||
add(AcStatusUpdated(deviceStatus));
|
add(AcStatusUpdated(deviceStatus));
|
||||||
}
|
}
|
||||||
@ -109,21 +111,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(
|
||||||
@ -132,10 +127,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()));
|
||||||
@ -146,23 +139,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(
|
||||||
@ -195,8 +181,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) {
|
||||||
@ -218,7 +204,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;
|
||||||
@ -291,7 +277,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) {
|
||||||
|
Reference in New Issue
Block a user